Skip to content

Commit e90d647

Browse files
committed
[WIP] Support const blocks in const_continue
1 parent 3da83c6 commit e90d647

File tree

7 files changed

+77
-54
lines changed

7 files changed

+77
-54
lines changed

compiler/rustc_mir_build/src/builder/matches/mod.rs

+57-37
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@ use std::mem;
1111
use std::sync::Arc;
1212

1313
use rustc_abi::VariantIdx;
14-
use rustc_ast::LitKind;
1514
use rustc_data_structures::fx::FxIndexMap;
1615
use rustc_data_structures::stack::ensure_sufficient_stack;
1716
use rustc_hir::{BindingMode, ByRef};
18-
use rustc_middle::bug;
1917
use rustc_middle::middle::region;
2018
use rustc_middle::mir::{self, *};
2119
use rustc_middle::thir::{self, *};
22-
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
20+
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TypeVisitableExt, ValTreeKind};
21+
use rustc_middle::{bug, span_bug};
2322
use rustc_pattern_analysis::rustc::{DeconstructedPat, RustcPatCtxt};
2423
use rustc_span::{BytePos, Pos, Span, Symbol};
2524
use tracing::{debug, instrument};
@@ -2836,7 +2835,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
28362835
pub(crate) fn static_pattern_match(
28372836
&self,
28382837
cx: &RustcPatCtxt<'_, 'tcx>,
2839-
value: ExprId,
2838+
constant: ConstOperand<'tcx>,
28402839
arms: &[ArmId],
28412840
built_match_tree: &BuiltMatchTree<'tcx>,
28422841
) -> Option<BasicBlock> {
@@ -2854,57 +2853,78 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
28542853
.or_else(|| branch.sub_branches.last())
28552854
.unwrap();
28562855

2857-
match self.static_pattern_match_help(value, &pat.pat) {
2856+
match self.static_pattern_match_help(constant, &pat.pat) {
28582857
true => return Some(sub_branch.success_block),
28592858
false => continue,
28602859
}
28612860
}
2862-
} else if self.static_pattern_match_help(value, &pat) {
2861+
} else if self.static_pattern_match_help(constant, &pat) {
28632862
return Some(branch.sub_branches[0].success_block);
28642863
}
28652864
}
28662865

28672866
None
28682867
}
28692868

2870-
fn static_pattern_match_help(&self, value: ExprId, pat: &DeconstructedPat<'_, 'tcx>) -> bool {
2871-
use rustc_middle::thir::ExprKind;
2869+
fn static_pattern_match_help(
2870+
&self,
2871+
constant: ConstOperand<'tcx>,
2872+
pat: &DeconstructedPat<'_, 'tcx>,
2873+
) -> bool {
28722874
use rustc_pattern_analysis::constructor::{IntRange, MaybeInfiniteInt};
28732875
use rustc_pattern_analysis::rustc::Constructor;
28742876

2877+
// Based on eval_unevaluated_mir_constant_to_valtree
2878+
let (valtree, ty) = 'a: {
2879+
assert!(!constant.const_.ty().has_param());
2880+
let (uv, ty) = match constant.const_ {
2881+
mir::Const::Unevaluated(uv, ty) => (uv.shrink(), ty),
2882+
mir::Const::Ty(_, c) => match c.kind() {
2883+
// A constant that came from a const generic but was then used as an argument to
2884+
// old-style simd_shuffle (passing as argument instead of as a generic param).
2885+
ty::ConstKind::Value(cv) => break 'a (cv.valtree, cv.ty),
2886+
other => span_bug!(constant.span, "{other:#?}"),
2887+
},
2888+
// We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate
2889+
// a constant and write that value back into `Operand`s. This could happen, but is
2890+
// unlikely. Also: all users of `simd_shuffle` are on unstable and already need to take
2891+
// a lot of care around intrinsics. For an issue to happen here, it would require a
2892+
// macro expanding to a `simd_shuffle` call without wrapping the constant argument in a
2893+
// `const {}` block, but the user pass through arbitrary expressions.
2894+
// FIXME(oli-obk): replace the magic const generic argument of `simd_shuffle` with a
2895+
// real const generic, and get rid of this entire function.
2896+
other => span_bug!(constant.span, "{other:#?}"),
2897+
};
2898+
(
2899+
self.tcx
2900+
.const_eval_resolve_for_typeck(self.typing_env(), uv, constant.span)
2901+
.unwrap()
2902+
.unwrap(),
2903+
ty,
2904+
)
2905+
};
2906+
assert!(!ty.has_param());
2907+
28752908
match pat.ctor() {
2876-
Constructor::Variant(variant_index) => match &self.thir[value].kind {
2877-
ExprKind::Adt(value_adt) => {
2878-
return *variant_index == value_adt.variant_index;
2909+
Constructor::Variant(variant_index) => match *valtree {
2910+
ValTreeKind::Branch(box [actual_variant_idx]) => {
2911+
*variant_index
2912+
== VariantIdx::from_u32(actual_variant_idx.unwrap_leaf().to_u32())
28792913
}
28802914
other => todo!("{other:?}"),
28812915
},
2882-
Constructor::IntRange(int_range) => match &self.thir[value].kind {
2883-
ExprKind::Literal { lit, neg } => match &lit.node {
2884-
LitKind::Int(n, _) => {
2885-
let n = if pat.ty().is_signed() {
2886-
let bits = pat.ty().primitive_size(self.tcx).bits();
2887-
MaybeInfiniteInt::new_finite_int(
2888-
if *neg {
2889-
(n.get() as i128).overflowing_neg().0 as u128
2890-
& ((1u128 << bits) - 1)
2891-
} else {
2892-
n.get()
2893-
},
2894-
bits,
2895-
)
2896-
} else {
2897-
MaybeInfiniteInt::new_finite_uint(n.get())
2898-
};
2899-
2900-
return IntRange::from_singleton(n).is_subrange(int_range);
2901-
}
2902-
2903-
other => todo!("{other:?}"),
2904-
},
2905-
other => todo!("{other:?}"),
2906-
},
2907-
Constructor::Wildcard => return true,
2916+
Constructor::IntRange(int_range) => {
2917+
let size = pat.ty().primitive_size(self.tcx);
2918+
let actual_int = valtree.unwrap_leaf().to_bits(size);
2919+
let actual_int = if pat.ty().is_signed() {
2920+
MaybeInfiniteInt::new_finite_int(actual_int, size.bits())
2921+
} else {
2922+
MaybeInfiniteInt::new_finite_uint(actual_int)
2923+
};
2924+
IntRange::from_singleton(actual_int).is_subrange(int_range)
2925+
}
2926+
Constructor::Wildcard => true,
2927+
// FIXME error out before static_pattern_match gets run and replace this with bug!()
29082928
_ => false,
29092929
}
29102930
}

compiler/rustc_mir_build/src/builder/scope.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
761761
span_bug!(span, "break value must be a scope")
762762
};
763763

764+
// FIXME accept bare MyEnum::Foo as constant
765+
let constant = self.as_constant(&self.thir[value]);
766+
764767
let break_index = self
765768
.scopes
766769
.const_continuable_scopes
@@ -809,7 +812,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
809812
};
810813

811814
let Some(real_target) =
812-
self.static_pattern_match(&cx, value, &*scope.arms, &scope.built_match_tree)
815+
self.static_pattern_match(&cx, constant, &*scope.arms, &scope.built_match_tree)
813816
else {
814817
self.tcx.dcx().emit_fatal(ConstContinueUnknownJumpTarget { span })
815818
};

tests/ui/feature-gates/feature-gate-loop-match.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ fn main() {
1313
State::A => {
1414
#[const_continue]
1515
//~^ ERROR the `#[const_continue]` attribute is an experimental feature
16-
break 'blk State::B;
16+
break 'blk const { State::B };
1717
}
1818
State::B => {
1919
#[const_continue]
2020
//~^ ERROR the `#[const_continue]` attribute is an experimental feature
21-
break 'blk State::C;
21+
break 'blk const { State::C };
2222
}
2323
State::C => break 'a,
2424
}

tests/ui/loop-match/integer-patterns.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ fn main() {
1313
match state {
1414
-1 => {
1515
#[const_continue]
16-
break 'blk 2;
16+
break 'blk const { 2 };
1717
}
1818
0 => {
1919
#[const_continue]
20-
break 'blk -1;
20+
break 'blk const { -1 };
2121
}
2222
2 => break 'a,
2323
_ => unreachable!("weird value {:?}", state),

tests/ui/loop-match/loop-match.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn main() {
1919
match state {
2020
State::A => {
2121
#[const_continue]
22-
break 'blk State::B;
22+
break 'blk const { State::B };
2323
}
2424
State::B => {
2525
// without special logic, the compiler believes this is a re-assignment to
@@ -29,10 +29,10 @@ fn main() {
2929

3030
if true {
3131
#[const_continue]
32-
break 'blk State::C;
32+
break 'blk const { State::C };
3333
} else {
3434
#[const_continue]
35-
break 'blk State::A;
35+
break 'blk const { State::A };
3636
}
3737
}
3838
State::C => break 'a,

tests/ui/loop-match/nested.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn run() -> String {
3737
State1::A => {
3838
accum.push('a');
3939
#[const_continue]
40-
break 'blk1 State1::B;
40+
break 'blk1 const { State1::B };
4141
}
4242
State1::B => {
4343
accum.push('b');
@@ -48,22 +48,22 @@ fn run() -> String {
4848
State2::X => {
4949
accum.push('x');
5050
#[const_continue]
51-
break 'blk2 State2::Y;
51+
break 'blk2 const { State2::Y };
5252
}
5353
State2::Y => {
5454
accum.push('y');
5555
#[const_continue]
56-
break 'blk2 State2::Z;
56+
break 'blk2 const { State2::Z };
5757
}
5858
State2::Z => {
5959
accum.push('z');
6060
if first {
6161
first = false;
6262
#[const_continue]
63-
break 'blk2 State2::X;
63+
break 'blk2 const { State2::X };
6464
} else {
6565
#[const_continue]
66-
break 'blk1 State1::C;
66+
break 'blk1 const { State1::C };
6767
}
6868
}
6969
}

tests/ui/loop-match/or-patterns.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,21 @@ fn main() {
2525
states.push(state);
2626
if first {
2727
#[const_continue]
28-
break 'blk State::B;
28+
break 'blk const { State::B };
2929
} else {
3030
#[const_continue]
31-
break 'blk State::D;
31+
break 'blk const { State::D };
3232
}
3333
}
3434
State::B | State::D => {
3535
states.push(state);
3636
if first {
3737
first = false;
3838
#[const_continue]
39-
break 'blk State::A;
39+
break 'blk const { State::A };
4040
} else {
4141
#[const_continue]
42-
break 'blk State::C;
42+
break 'blk const { State::C };
4343
}
4444
}
4545
State::C => {

0 commit comments

Comments
 (0)