diff --git a/compiler/rustc_error_codes/src/error_codes/E0435.md b/compiler/rustc_error_codes/src/error_codes/E0435.md index 424e5ce1e2e..798a20d48b6 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0435.md +++ b/compiler/rustc_error_codes/src/error_codes/E0435.md @@ -7,6 +7,12 @@ let foo = 42; let a: [u8; foo]; // error: attempt to use a non-constant value in a constant ``` +'constant' means 'a compile-time value'. + +More details can be found in the [Variables and Mutability] section of the book. + +[Variables and Mutability]: https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants + To fix this error, please replace the value with a constant. Example: ``` diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 809de9beff6..6a181dbab5a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -398,13 +398,19 @@ impl<'a> Resolver<'a> { err.help("use the `|| { ... }` closure form instead"); err } - ResolutionError::AttemptToUseNonConstantValueInConstant => { + ResolutionError::AttemptToUseNonConstantValueInConstant(ident, sugg) => { let mut err = struct_span_err!( self.session, span, E0435, "attempt to use a non-constant value in a constant" ); + err.span_suggestion( + ident.span, + &sugg, + "".to_string(), + Applicability::MaybeIncorrect, + ); err.span_label(span, "non-constant value"); err } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2e738ce8dac..4d956e7f0d2 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -92,6 +92,12 @@ crate enum HasGenericParams { No, } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +crate enum ConstantItemKind { + Const, + Static, +} + /// The rib kind restricts certain accesses, /// e.g. to a `Res::Local` of an outer item. #[derive(Copy, Clone, Debug)] @@ -119,7 +125,7 @@ crate enum RibKind<'a> { /// /// The `bool` indicates if this constant may reference generic parameters /// and is used to only allow generic parameters to be used in trivial constant expressions. - ConstantItemRibKind(bool), + ConstantItemRibKind(bool, Option<(Ident, ConstantItemKind)>), /// We passed through a module. ModuleRibKind(Module<'a>), @@ -145,7 +151,7 @@ impl RibKind<'_> { NormalRibKind | ClosureOrAsyncRibKind | FnItemRibKind - | ConstantItemRibKind(_) + | ConstantItemRibKind(..) | ModuleRibKind(_) | MacroDefinition(_) | ConstParamTyRibKind => false, @@ -634,7 +640,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // Note that we might not be inside of an repeat expression here, // but considering that `IsRepeatExpr` is only relevant for // non-trivial constants this is doesn't matter. - self.with_constant_rib(IsRepeatExpr::No, true, |this| { + self.with_constant_rib(IsRepeatExpr::No, true, None, |this| { this.smart_resolve_path( ty.id, qself.as_ref(), @@ -843,7 +849,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { | ClosureOrAsyncRibKind | FnItemRibKind | ItemRibKind(..) - | ConstantItemRibKind(_) + | ConstantItemRibKind(..) | ModuleRibKind(..) | ForwardTyParamBanRibKind | ConstParamTyRibKind => { @@ -970,6 +976,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.with_constant_rib( IsRepeatExpr::No, true, + None, |this| this.visit_expr(expr), ); } @@ -1012,11 +1019,19 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_item_rib(HasGenericParams::No, |this| { this.visit_ty(ty); if let Some(expr) = expr { + let constant_item_kind = match item.kind { + ItemKind::Const(..) => ConstantItemKind::Const, + ItemKind::Static(..) => ConstantItemKind::Static, + _ => unreachable!(), + }; // We already forbid generic params because of the above item rib, // so it doesn't matter whether this is a trivial constant. - this.with_constant_rib(IsRepeatExpr::No, true, |this| { - this.visit_expr(expr) - }); + this.with_constant_rib( + IsRepeatExpr::No, + true, + Some((item.ident, constant_item_kind)), + |this| this.visit_expr(expr), + ); } }); } @@ -1118,15 +1133,16 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &mut self, is_repeat: IsRepeatExpr, is_trivial: bool, + item: Option<(Ident, ConstantItemKind)>, f: impl FnOnce(&mut Self), ) { debug!("with_constant_rib: is_repeat={:?} is_trivial={}", is_repeat, is_trivial); - self.with_rib(ValueNS, ConstantItemRibKind(is_trivial), |this| { + self.with_rib(ValueNS, ConstantItemRibKind(is_trivial, item), |this| { this.with_rib( TypeNS, - ConstantItemRibKind(is_repeat == IsRepeatExpr::Yes || is_trivial), + ConstantItemRibKind(is_repeat == IsRepeatExpr::Yes || is_trivial, item), |this| { - this.with_label_rib(ConstantItemRibKind(is_trivial), f); + this.with_label_rib(ConstantItemRibKind(is_trivial, item), f); }, ) }); @@ -1266,6 +1282,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.with_constant_rib( IsRepeatExpr::No, true, + None, |this| { visit::walk_assoc_item( this, @@ -2200,6 +2217,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_constant_rib( is_repeat, constant.value.is_potential_trivial_const_param(), + None, |this| { visit::walk_anon_const(this, constant); }, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index dba30f66640..a6d0240b6fd 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -64,7 +64,7 @@ use tracing::debug; use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_next_binding}; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use imports::{Import, ImportKind, ImportResolver, NameResolution}; -use late::{HasGenericParams, PathSource, Rib, RibKind::*}; +use late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind::*}; use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; type Res = def::Res; @@ -210,7 +210,7 @@ enum ResolutionError<'a> { /// Error E0434: can't capture dynamic environment in a fn item. CannotCaptureDynamicEnvironmentInFnItem, /// Error E0435: attempt to use a non-constant value in a constant. - AttemptToUseNonConstantValueInConstant, + AttemptToUseNonConstantValueInConstant(Ident, String), /// Error E0530: `X` bindings cannot shadow `Y`s. BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>), /// Error E0128: type parameters with a default cannot use forward-declared identifiers. @@ -1837,14 +1837,16 @@ impl<'a> Resolver<'a> { // Use the rib kind to determine whether we are resolving parameters // (macro 2.0 hygiene) or local variables (`macro_rules` hygiene). let rib_ident = if ribs[i].kind.contains_params() { normalized_ident } else { ident }; - if let Some(res) = ribs[i].bindings.get(&rib_ident).cloned() { + if let Some((original_rib_ident_def, res)) = ribs[i].bindings.get_key_value(&rib_ident) + { // The ident resolves to a type parameter or local variable. return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs( i, rib_ident, - res, + *res, record_used, path_span, + *original_rib_ident_def, ribs, ))); } @@ -2556,6 +2558,7 @@ impl<'a> Resolver<'a> { mut res: Res, record_used: bool, span: Span, + original_rib_ident_def: Ident, all_ribs: &[Rib<'a>], ) -> Res { const CG_BUG_STR: &str = "min_const_generics resolve check didn't stop compilation"; @@ -2602,10 +2605,31 @@ impl<'a> Resolver<'a> { res_err = Some(CannotCaptureDynamicEnvironmentInFnItem); } } - ConstantItemRibKind(_) => { + ConstantItemRibKind(_, item) => { // Still doesn't deal with upvars if record_used { - self.report_error(span, AttemptToUseNonConstantValueInConstant); + let (span, resolution_error) = + if let Some((ident, constant_item_kind)) = item { + let kind_str = match constant_item_kind { + ConstantItemKind::Const => "const", + ConstantItemKind::Static => "static", + }; + let sugg = format!( + "consider using `let` instead of `{}`", + kind_str + ); + (span, AttemptToUseNonConstantValueInConstant(ident, sugg)) + } else { + let sugg = "consider using `const` instead of `let`"; + ( + rib_ident.span, + AttemptToUseNonConstantValueInConstant( + original_rib_ident_def, + sugg.to_string(), + ), + ) + }; + self.report_error(span, resolution_error); } return Res::Err; } @@ -2641,7 +2665,7 @@ impl<'a> Resolver<'a> { in_ty_param_default = true; continue; } - ConstantItemRibKind(trivial) => { + ConstantItemRibKind(trivial, _) => { let features = self.session.features_untracked(); // HACK(min_const_generics): We currently only allow `N` or `{ N }`. if !(trivial @@ -2734,7 +2758,7 @@ impl<'a> Resolver<'a> { in_ty_param_default = true; continue; } - ConstantItemRibKind(trivial) => { + ConstantItemRibKind(trivial, _) => { let features = self.session.features_untracked(); // HACK(min_const_generics): We currently only allow `N` or `{ N }`. if !(trivial diff --git a/src/test/ui/error-codes/E0435.stderr b/src/test/ui/error-codes/E0435.stderr index 349aa0d07c5..21827d1fd87 100644 --- a/src/test/ui/error-codes/E0435.stderr +++ b/src/test/ui/error-codes/E0435.stderr @@ -1,6 +1,8 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/E0435.rs:3:17 | +LL | let foo = 42u32; + | --- help: consider using `const` instead of `let` LL | let _: [u8; foo]; | ^^^ non-constant value diff --git a/src/test/ui/impl-trait/bindings.stderr b/src/test/ui/impl-trait/bindings.stderr index e983fdecdba..ad5f13d0672 100644 --- a/src/test/ui/impl-trait/bindings.stderr +++ b/src/test/ui/impl-trait/bindings.stderr @@ -2,25 +2,33 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/bindings.rs:5:29 | LL | const foo: impl Clone = x; - | ^ non-constant value + | --- ^ non-constant value + | | + | help: consider using `let` instead of `const` error[E0435]: attempt to use a non-constant value in a constant --> $DIR/bindings.rs:11:33 | LL | const foo: impl Clone = x; - | ^ non-constant value + | --- ^ non-constant value + | | + | help: consider using `let` instead of `const` error[E0435]: attempt to use a non-constant value in a constant --> $DIR/bindings.rs:18:33 | LL | const foo: impl Clone = x; - | ^ non-constant value + | --- ^ non-constant value + | | + | help: consider using `let` instead of `const` error[E0435]: attempt to use a non-constant value in a constant --> $DIR/bindings.rs:25:33 | LL | const foo: impl Clone = x; - | ^ non-constant value + | --- ^ non-constant value + | | + | help: consider using `let` instead of `const` warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/bindings.rs:1:12 diff --git a/src/test/ui/issues/issue-27433.stderr b/src/test/ui/issues/issue-27433.stderr index e232d17e6d7..201b7e8549c 100644 --- a/src/test/ui/issues/issue-27433.stderr +++ b/src/test/ui/issues/issue-27433.stderr @@ -2,7 +2,9 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-27433.rs:3:23 | LL | const FOO : u32 = foo; - | ^^^ non-constant value + | --- ^^^ non-constant value + | | + | help: consider using `let` instead of `const` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3521-2.stderr b/src/test/ui/issues/issue-3521-2.stderr index d54bbbcdc33..ba29d1becb8 100644 --- a/src/test/ui/issues/issue-3521-2.stderr +++ b/src/test/ui/issues/issue-3521-2.stderr @@ -2,7 +2,9 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3521-2.rs:4:23 | LL | static y: isize = foo + 1; - | ^^^ non-constant value + | - ^^^ non-constant value + | | + | help: consider using `let` instead of `static` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3521.stderr b/src/test/ui/issues/issue-3521.stderr index ae199875269..8473526006c 100644 --- a/src/test/ui/issues/issue-3521.stderr +++ b/src/test/ui/issues/issue-3521.stderr @@ -1,6 +1,9 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3521.rs:6:15 | +LL | let foo = 100; + | --- help: consider using `const` instead of `let` +... LL | Bar = foo | ^^^ non-constant value diff --git a/src/test/ui/issues/issue-3668-2.stderr b/src/test/ui/issues/issue-3668-2.stderr index d6a6e837960..7cee497b0bc 100644 --- a/src/test/ui/issues/issue-3668-2.stderr +++ b/src/test/ui/issues/issue-3668-2.stderr @@ -2,7 +2,9 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3668-2.rs:2:27 | LL | static child: isize = x + 1; - | ^ non-constant value + | ----- ^ non-constant value + | | + | help: consider using `let` instead of `static` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3668.stderr b/src/test/ui/issues/issue-3668.stderr index 98cd3631a53..e45472929ab 100644 --- a/src/test/ui/issues/issue-3668.stderr +++ b/src/test/ui/issues/issue-3668.stderr @@ -2,7 +2,9 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3668.rs:8:34 | LL | static childVal: Box

= self.child.get(); - | ^^^^ non-constant value + | -------- ^^^^ non-constant value + | | + | help: consider using `let` instead of `static` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-42060.stderr b/src/test/ui/issues/issue-42060.stderr index 72408c79194..dc089b856bb 100644 --- a/src/test/ui/issues/issue-42060.stderr +++ b/src/test/ui/issues/issue-42060.stderr @@ -1,12 +1,16 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-42060.rs:3:23 | +LL | let thing = (); + | ----- help: consider using `const` instead of `let` LL | let other: typeof(thing) = thing; | ^^^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-42060.rs:9:13 | +LL | let q = 1; + | - help: consider using `const` instead of `let` LL | ::N | ^ non-constant value diff --git a/src/test/ui/issues/issue-44239.stderr b/src/test/ui/issues/issue-44239.stderr index bc5a6a03f03..bbd3d116c96 100644 --- a/src/test/ui/issues/issue-44239.stderr +++ b/src/test/ui/issues/issue-44239.stderr @@ -1,6 +1,9 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-44239.rs:6:26 | +LL | let n = 0; + | - help: consider using `const` instead of `let` +... LL | const N: usize = n; | ^ non-constant value diff --git a/src/test/ui/non-constant-expr-for-arr-len.stderr b/src/test/ui/non-constant-expr-for-arr-len.stderr index b947cb7e19c..01da6bcf49a 100644 --- a/src/test/ui/non-constant-expr-for-arr-len.stderr +++ b/src/test/ui/non-constant-expr-for-arr-len.stderr @@ -1,6 +1,8 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/non-constant-expr-for-arr-len.rs:5:22 | +LL | fn bar(n: usize) { + | - help: consider using `const` instead of `let` LL | let _x = [0; n]; | ^ non-constant value diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat_count.stderr index 5fcda348ab3..aa1b2e60d51 100644 --- a/src/test/ui/repeat_count.stderr +++ b/src/test/ui/repeat_count.stderr @@ -1,6 +1,8 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/repeat_count.rs:5:17 | +LL | let n = 1; + | - help: consider using `const` instead of `let` LL | let a = [0; n]; | ^ non-constant value diff --git a/src/test/ui/type/type-dependent-def-issue-49241.stderr b/src/test/ui/type/type-dependent-def-issue-49241.stderr index c5dcfa7a431..df791435e88 100644 --- a/src/test/ui/type/type-dependent-def-issue-49241.stderr +++ b/src/test/ui/type/type-dependent-def-issue-49241.stderr @@ -2,7 +2,9 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-dependent-def-issue-49241.rs:3:22 | LL | const l: usize = v.count(); - | ^ non-constant value + | - ^ non-constant value + | | + | help: consider using `let` instead of `const` error: aborting due to previous error