Skip to content

Commit afa0fb6

Browse files
committed
[WIP] Support const blocks in const_continue
1 parent 0a9679e commit afa0fb6

File tree

7 files changed

+77
-53
lines changed

7 files changed

+77
-53
lines changed

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

Lines changed: 57 additions & 36 deletions
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, LetStmt, LocalSource, Node};
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, sym};
2524
use tracing::{debug, instrument};
@@ -2870,7 +2869,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
28702869
pub(crate) fn static_pattern_match(
28712870
&self,
28722871
cx: &RustcPatCtxt<'_, 'tcx>,
2873-
value: ExprId,
2872+
constant: ConstOperand<'tcx>,
28742873
arms: &[ArmId],
28752874
built_match_tree: &BuiltMatchTree<'tcx>,
28762875
) -> Option<BasicBlock> {
@@ -2888,56 +2887,78 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
28882887
.or_else(|| branch.sub_branches.last())
28892888
.unwrap();
28902889

2891-
match self.static_pattern_match_help(value, &pat.pat) {
2890+
match self.static_pattern_match_help(constant, &pat.pat) {
28922891
true => return Some(sub_branch.success_block),
28932892
false => continue,
28942893
}
28952894
}
2896-
} else if self.static_pattern_match_help(value, &pat) {
2895+
} else if self.static_pattern_match_help(constant, &pat) {
28972896
return Some(branch.sub_branches[0].success_block);
28982897
}
28992898
}
29002899

29012900
None
29022901
}
29032902

2904-
fn static_pattern_match_help(&self, value: ExprId, pat: &DeconstructedPat<'_, 'tcx>) -> bool {
2905-
use rustc_middle::thir::ExprKind;
2903+
fn static_pattern_match_help(
2904+
&self,
2905+
constant: ConstOperand<'tcx>,
2906+
pat: &DeconstructedPat<'_, 'tcx>,
2907+
) -> bool {
29062908
use rustc_pattern_analysis::constructor::{IntRange, MaybeInfiniteInt};
29072909
use rustc_pattern_analysis::rustc::Constructor;
29082910

2911+
// Based on eval_unevaluated_mir_constant_to_valtree
2912+
let (valtree, ty) = 'a: {
2913+
assert!(!constant.const_.ty().has_param());
2914+
let (uv, ty) = match constant.const_ {
2915+
mir::Const::Unevaluated(uv, ty) => (uv.shrink(), ty),
2916+
mir::Const::Ty(_, c) => match c.kind() {
2917+
// A constant that came from a const generic but was then used as an argument to
2918+
// old-style simd_shuffle (passing as argument instead of as a generic param).
2919+
ty::ConstKind::Value(cv) => break 'a (cv.valtree, cv.ty),
2920+
other => span_bug!(constant.span, "{other:#?}"),
2921+
},
2922+
// We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate
2923+
// a constant and write that value back into `Operand`s. This could happen, but is
2924+
// unlikely. Also: all users of `simd_shuffle` are on unstable and already need to take
2925+
// a lot of care around intrinsics. For an issue to happen here, it would require a
2926+
// macro expanding to a `simd_shuffle` call without wrapping the constant argument in a
2927+
// `const {}` block, but the user pass through arbitrary expressions.
2928+
// FIXME(oli-obk): replace the magic const generic argument of `simd_shuffle` with a
2929+
// real const generic, and get rid of this entire function.
2930+
other => span_bug!(constant.span, "{other:#?}"),
2931+
};
2932+
(
2933+
self.tcx
2934+
.const_eval_resolve_for_typeck(self.typing_env(), uv, constant.span)
2935+
.unwrap()
2936+
.unwrap(),
2937+
ty,
2938+
)
2939+
};
2940+
assert!(!ty.has_param());
2941+
29092942
match pat.ctor() {
2910-
Constructor::Variant(variant_index) => match &self.thir[value].kind {
2911-
ExprKind::Adt(value_adt) => {
2912-
return *variant_index == value_adt.variant_index;
2943+
Constructor::Variant(variant_index) => match *valtree {
2944+
ValTreeKind::Branch(box [actual_variant_idx]) => {
2945+
*variant_index
2946+
== VariantIdx::from_u32(actual_variant_idx.unwrap_leaf().to_u32())
29132947
}
29142948
other => todo!("{other:?}"),
29152949
},
2916-
Constructor::IntRange(int_range) => match &self.thir[value].kind {
2917-
ExprKind::Literal { lit, neg } => match &lit.node {
2918-
LitKind::Int(n, _) => {
2919-
let n = if pat.ty().is_signed() {
2920-
let size = pat.ty().primitive_size(self.tcx);
2921-
MaybeInfiniteInt::new_finite_int(
2922-
if *neg {
2923-
size.truncate((n.get() as i128).overflowing_neg().0 as u128)
2924-
} else {
2925-
n.get()
2926-
},
2927-
size.bits(),
2928-
)
2929-
} else {
2930-
MaybeInfiniteInt::new_finite_uint(n.get())
2931-
};
2932-
2933-
return IntRange::from_singleton(n).is_subrange(int_range);
2934-
}
2935-
2936-
other => todo!("{other:?}"),
2937-
},
2938-
other => todo!("{other:?}"),
2939-
},
2940-
Constructor::Wildcard => return true,
2950+
Constructor::IntRange(int_range) => {
2951+
let size = pat.ty().primitive_size(self.tcx);
2952+
let actual_int = valtree.unwrap_leaf().to_bits(size);
2953+
let actual_int = if pat.ty().is_signed() {
2954+
MaybeInfiniteInt::new_finite_int(actual_int, size.bits())
2955+
} else {
2956+
MaybeInfiniteInt::new_finite_uint(actual_int)
2957+
};
2958+
IntRange::from_singleton(actual_int).is_subrange(int_range)
2959+
}
2960+
Constructor::Wildcard => true,
2961+
// FIXME error out before static_pattern_match gets run and replace this with bug!()
29412962
_ => false,
29422963
}
29432964
}

compiler/rustc_mir_build/src/builder/scope.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
824824
span_bug!(span, "break value must be a scope")
825825
};
826826

827+
// FIXME accept bare MyEnum::Foo as constant
828+
let constant = self.as_constant(&self.thir[value]);
829+
827830
let break_index = self
828831
.scopes
829832
.const_continuable_scopes
@@ -865,7 +868,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
865868
};
866869

867870
let Some(real_target) =
868-
self.static_pattern_match(&cx, value, &*scope.arms, &scope.built_match_tree)
871+
self.static_pattern_match(&cx, constant, &*scope.arms, &scope.built_match_tree)
869872
else {
870873
self.tcx.dcx().emit_fatal(ConstContinueUnknownJumpTarget { span })
871874
};

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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 5 additions & 5 deletions
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

Lines changed: 4 additions & 4 deletions
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)