diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index bf260d823b76..a92ed9cd3ae8 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -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, diff --git a/tests/ui/consts/non-const-value-in-const-irrefutable-pat-binding.rs b/tests/ui/consts/non-const-value-in-const-irrefutable-pat-binding.rs new file mode 100644 index 000000000000..de5a57335408 --- /dev/null +++ b/tests/ui/consts/non-const-value-in-const-irrefutable-pat-binding.rs @@ -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() {} diff --git a/tests/ui/consts/non-const-value-in-const-irrefutable-pat-binding.stderr b/tests/ui/consts/non-const-value-in-const-irrefutable-pat-binding.stderr new file mode 100644 index 000000000000..1a2fa226e633 --- /dev/null +++ b/tests/ui/consts/non-const-value-in-const-irrefutable-pat-binding.stderr @@ -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`. diff --git a/tests/ui/consts/non-const-value-in-const-pat-binding.rs b/tests/ui/consts/non-const-value-in-const-pat-binding.rs new file mode 100644 index 000000000000..8c6edfdf363c --- /dev/null +++ b/tests/ui/consts/non-const-value-in-const-pat-binding.rs @@ -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() {} diff --git a/tests/ui/consts/non-const-value-in-const-pat-binding.stderr b/tests/ui/consts/non-const-value-in-const-pat-binding.stderr new file mode 100644 index 000000000000..d303189eb305 --- /dev/null +++ b/tests/ui/consts/non-const-value-in-const-pat-binding.stderr @@ -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`.