Rollup merge of #152834 - lapla-cogito:issue_152831, r=jackh726

Fix incorrect `let` to `const` suggestion for pattern bindings

When a variable from a pattern binding was referenced inside a `const {}` block, the compiler incorrectly suggested replacing `let` with `const`. This was reported in rust-lang/rust#152831 for `if let`, but also applies to `while let` and `let ... else`.
This commit is contained in:
Jonathan Brouwer
2026-04-21 20:42:51 +02:00
committed by GitHub
5 changed files with 108 additions and 11 deletions
+35 -11
View File
@@ -979,23 +979,47 @@ pub(crate) fn into_struct_error(
.source_map()
.span_extend_to_prev_str(ident.span, current, true, false);
let ((with, with_label), without) = match sp {
let (with, with_label, without) = match sp {
Some(sp) if !self.tcx.sess.source_map().is_multiline(sp) => {
let sp = sp
.with_lo(BytePos(sp.lo().0 - (current.len() as u32)))
.until(ident.span);
(
(Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion {
span: sp,
suggestion,
current,
type_span,
}), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})),
None,
)
// Only suggest replacing the binding keyword if this is a simple
// binding.
//
// Note: this approach still incorrectly suggests for irrefutable
// patterns like `if let x = 1 { const { x } }`, since the text
// between `let` and the identifier is just whitespace.
// See tests/ui/consts/non-const-value-in-const-irrefutable-pat-binding.rs
let is_simple_binding =
self.tcx.sess.source_map().span_to_snippet(sp).is_ok_and(|snippet| {
let after_keyword = snippet[current.len()..].trim();
after_keyword.is_empty() || after_keyword == "mut"
});
if is_simple_binding {
(
Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion {
span: sp,
suggestion,
current,
type_span,
}),
Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion { span }),
None,
)
} else {
(
None,
Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion { span }),
None,
)
}
}
_ => (
(None, None),
None,
None,
Some(errs::AttemptToUseNonConstantValueInConstantWithoutSuggestion {
ident_span: ident.span,
suggestion,
@@ -0,0 +1,13 @@
// Irrefutable `if let` pattern bindings still produce an incorrect suggestion
// to replace `let` with `const`.
// See https://github.com/rust-lang/rust/pull/152834#discussion_r3068766148
//@ known-bug: #152831
fn irrefutable_if_let_binding() {
if let x = 1 {
const { x }
}
}
fn main() {}
@@ -0,0 +1,15 @@
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/non-const-value-in-const-irrefutable-pat-binding.rs:9:17
|
LL | const { x }
| ^ non-constant value
|
help: consider using `const` instead of `let`
|
LL - if let x = 1 {
LL + if const x: /* Type */ = 1 {
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0435`.
@@ -0,0 +1,24 @@
// Regression test for https://github.com/rust-lang/rust/issues/152831
fn if_let_binding() {
if let Some(v) = Some(1) {
const { v }
//~^ ERROR: attempt to use a non-constant value in a constant
}
}
fn while_let_binding() {
while let Some(v) = Some(1) {
const { v }
//~^ ERROR: attempt to use a non-constant value in a constant
break;
}
}
fn let_else_binding() {
let Some(v) = Some(1) else { return };
const { v }
//~^ ERROR: attempt to use a non-constant value in a constant
}
fn main() {}
@@ -0,0 +1,21 @@
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/non-const-value-in-const-pat-binding.rs:5:17
|
LL | const { v }
| ^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/non-const-value-in-const-pat-binding.rs:12:17
|
LL | const { v }
| ^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/non-const-value-in-const-pat-binding.rs:20:13
|
LL | const { v }
| ^ non-constant value
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0435`.