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 fbe99a31150..fbaec149d54 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -92,6 +92,12 @@ enum PatBoundCtx { 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 @@ enum PatBoundCtx { /// /// 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 @@ fn visit_generic_arg(&mut self, arg: &'ast GenericArg) { // 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 @@ fn is_label_valid_from_rib(&self, rib_index: usize) -> bool { | ClosureOrAsyncRibKind | FnItemRibKind | ItemRibKind(..) - | ConstantItemRibKind(_) + | ConstantItemRibKind(..) | ModuleRibKind(..) | ForwardTyParamBanRibKind | ConstParamTyRibKind => { @@ -970,6 +976,7 @@ fn resolve_item(&mut self, item: &'ast Item) { this.with_constant_rib( IsRepeatExpr::No, true, + None, |this| this.visit_expr(expr), ); } @@ -1012,11 +1019,19 @@ fn resolve_item(&mut self, item: &'ast Item) { 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 @@ fn with_constant_rib( &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 @@ fn resolve_implementation( this.with_constant_rib( IsRepeatExpr::No, true, + None, |this| { visit::walk_assoc_item( this, @@ -2200,6 +2217,7 @@ fn resolve_anon_const(&mut self, constant: &'ast AnonConst, is_repeat: IsRepeatE 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 0de732b2cf9..ebfe5301b69 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -64,7 +64,7 @@ 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. @@ -1821,14 +1821,16 @@ fn resolve_ident_in_lexical_scope( // 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, ))); } @@ -2540,6 +2542,7 @@ fn validate_res_from_ribs( 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"; @@ -2586,10 +2589,31 @@ fn validate_res_from_ribs( 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; } @@ -2625,7 +2649,7 @@ fn validate_res_from_ribs( 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 @@ -2718,7 +2742,7 @@ fn validate_res_from_ribs( 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