Skip to content

Commit 38091b2

Browse files
committed
loop_match: suggest wrapping in a const block
if the expression cannot be evaluated in a straightforward way
1 parent c720f49 commit 38091b2

File tree

4 files changed

+75
-20
lines changed

4 files changed

+75
-20
lines changed

compiler/rustc_mir_build/messages.ftl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,13 @@ mir_build_confused = missing patterns are not covered because `{$variable}` is i
8686
8787
mir_build_const_continue_bad_const = could not determine the target branch for this `#[const_continue]`
8888
.label = this value is too generic
89-
.note = the value must be a literal or a monomorphic const
9089
9190
mir_build_const_continue_missing_value = a `#[const_continue]` must break to a label with a value
9291
92+
mir_build_const_continue_not_const = could not determine the target branch for this `#[const_continue]`
93+
.label = the value must be a literal or a monomorphic const
94+
.suggestion = try wrapping the expression in a `const` block
95+
9396
mir_build_const_continue_unknown_jump_target = the target of this `#[const_continue]` is not statically known
9497
.label = this value must be a literal or a monomorphic const
9598

compiler/rustc_mir_build/src/builder/expr/as_constant.rs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,31 @@ use crate::builder::{Builder, parse_float_into_constval};
1818
impl<'a, 'tcx> Builder<'a, 'tcx> {
1919
/// Compile `expr`, yielding a compile-time constant. Assumes that
2020
/// `expr` is a valid compile-time constant!
21-
pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> ConstOperand<'tcx> {
22-
let this = self;
23-
let tcx = this.tcx;
24-
let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
25-
match kind {
26-
ExprKind::Scope { region_scope: _, lint_level: _, value } => {
27-
this.as_constant(&this.thir[*value])
28-
}
29-
_ => as_constant_inner(
21+
pub(crate) fn as_constant(&mut self, expr: &'a Expr<'tcx>) -> ConstOperand<'tcx> {
22+
match self.try_as_constant(expr) {
23+
Ok(const_operand) => const_operand,
24+
Err(expr) => span_bug!(expr.span, "expression is not a valid constant {:?}", expr.kind),
25+
}
26+
}
27+
28+
pub(crate) fn try_as_constant(
29+
&mut self,
30+
expr: &'a Expr<'tcx>,
31+
) -> Result<ConstOperand<'tcx>, &'a Expr<'tcx>> {
32+
if let ExprKind::Scope { region_scope: _, lint_level: _, value } = expr.kind {
33+
self.try_as_constant(&self.thir[value])
34+
} else {
35+
try_as_constant_inner(
3036
expr,
3137
|user_ty| {
32-
Some(this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
33-
span,
38+
Some(self.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
39+
span: expr.span,
3440
user_ty: user_ty.clone(),
35-
inferred_ty: ty,
41+
inferred_ty: expr.ty,
3642
}))
3743
},
38-
tcx,
39-
),
44+
self.tcx,
45+
)
4046
}
4147
}
4248
}
@@ -46,8 +52,19 @@ pub(crate) fn as_constant_inner<'tcx>(
4652
push_cuta: impl FnMut(&Box<CanonicalUserType<'tcx>>) -> Option<UserTypeAnnotationIndex>,
4753
tcx: TyCtxt<'tcx>,
4854
) -> ConstOperand<'tcx> {
55+
match try_as_constant_inner(expr, push_cuta, tcx) {
56+
Ok(const_operand) => const_operand,
57+
Err(expr) => span_bug!(expr.span, "expression is not a valid constant {:?}", expr.kind),
58+
}
59+
}
60+
61+
fn try_as_constant_inner<'a, 'tcx>(
62+
expr: &'a Expr<'tcx>,
63+
push_cuta: impl FnMut(&Box<CanonicalUserType<'tcx>>) -> Option<UserTypeAnnotationIndex>,
64+
tcx: TyCtxt<'tcx>,
65+
) -> Result<ConstOperand<'tcx>, &'a Expr<'tcx>> {
4966
let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
50-
match *kind {
67+
Ok(match *kind {
5168
ExprKind::Literal { lit, neg } => {
5269
let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty, neg });
5370

@@ -93,8 +110,8 @@ pub(crate) fn as_constant_inner<'tcx>(
93110

94111
ConstOperand { span, user_ty: None, const_ }
95112
}
96-
_ => span_bug!(span, "expression is not a valid constant {:?}", kind),
97-
}
113+
_ => return Err(expr),
114+
})
98115
}
99116

100117
#[instrument(skip(tcx, lit_input))]

compiler/rustc_mir_build/src/builder/scope.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,10 @@ use tracing::{debug, instrument};
100100

101101
use super::matches::BuiltMatchTree;
102102
use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
103-
use crate::errors::{ConstContinueBadConst, ConstContinueUnknownJumpTarget};
103+
use crate::errors::{
104+
ConstContinueBadConst, ConstContinueNotConst, ConstContinueNotConstSuggestConstBlock,
105+
ConstContinueUnknownJumpTarget,
106+
};
104107

105108
#[derive(Debug)]
106109
pub(crate) struct Scopes<'tcx> {
@@ -887,7 +890,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
887890
),
888891
}
889892
}
890-
_ => self.as_constant(&self.thir[value]),
893+
_ => match self.try_as_constant(&self.thir[value]) {
894+
Ok(const_operand) => const_operand,
895+
Err(expr) => {
896+
self.tcx.dcx().emit_err(ConstContinueNotConst {
897+
span: expr.span,
898+
sub: ConstContinueNotConstSuggestConstBlock {
899+
left: expr.span.shrink_to_lo(),
900+
right: expr.span.shrink_to_hi(),
901+
},
902+
});
903+
return block.unit();
904+
}
905+
},
891906
};
892907

893908
let break_index = self

compiler/rustc_mir_build/src/errors.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,26 @@ pub(crate) struct LoopMatchArmWithGuard {
12131213
pub span: Span,
12141214
}
12151215

1216+
#[derive(Diagnostic)]
1217+
#[diag(mir_build_const_continue_not_const)]
1218+
pub(crate) struct ConstContinueNotConst {
1219+
#[primary_span]
1220+
#[label]
1221+
pub span: Span,
1222+
1223+
#[subdiagnostic]
1224+
pub(crate) sub: ConstContinueNotConstSuggestConstBlock,
1225+
}
1226+
1227+
#[derive(Subdiagnostic)]
1228+
#[multipart_suggestion(mir_build_suggestion, applicability = "maybe-incorrect")]
1229+
pub(crate) struct ConstContinueNotConstSuggestConstBlock {
1230+
#[suggestion_part(code = "const {{ ")]
1231+
pub(crate) left: Span,
1232+
#[suggestion_part(code = " }}")]
1233+
pub(crate) right: Span,
1234+
}
1235+
12161236
#[derive(Diagnostic)]
12171237
#[diag(mir_build_const_continue_bad_const)]
12181238
pub(crate) struct ConstContinueBadConst {

0 commit comments

Comments
 (0)