diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b5dba0713bf..fa1155f135d 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -120,6 +120,12 @@ impl Path { pub fn is_global(&self) -> bool { !self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot } + + /// If this path is a single identifier with no arguments, does not ensure + /// that the path resolves to a const param, the caller should check this. + pub fn is_potential_trivial_const_arg(&self) -> bool { + self.segments.len() == 1 && self.segments[0].args.is_none() + } } /// A segment of a path: an identifier, an optional lifetime, and a set of types. @@ -1154,7 +1160,9 @@ impl Expr { /// /// If this is not the case, name resolution does not resolve `N` when using /// `min_const_generics` as more complex expressions are not supported. - pub fn is_potential_trivial_const_param(&self) -> bool { + /// + /// Does not ensure that the path resolves to a const param, the caller should check this. + pub fn is_potential_trivial_const_arg(&self) -> bool { let this = if let ExprKind::Block(block, None) = &self.kind && block.stmts.len() == 1 && let StmtKind::Expr(expr) = &block.stmts[0].kind @@ -1165,8 +1173,7 @@ impl Expr { }; if let ExprKind::Path(None, path) = &this.kind - && path.segments.len() == 1 - && path.segments[0].args.is_none() + && path.is_potential_trivial_const_arg() { true } else { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 1526ffa0b03..275692ad5dd 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -188,6 +188,9 @@ pub trait Visitor<'ast>: Sized { fn visit_variant(&mut self, v: &'ast Variant) { walk_variant(self, v) } + fn visit_variant_discr(&mut self, discr: &'ast AnonConst) { + self.visit_anon_const(discr); + } fn visit_label(&mut self, label: &'ast Label) { walk_label(self, label) } @@ -380,7 +383,7 @@ where visitor.visit_ident(variant.ident); visitor.visit_vis(&variant.vis); visitor.visit_variant_data(&variant.data); - walk_list!(visitor, visit_anon_const, &variant.disr_expr); + walk_list!(visitor, visit_variant_discr, &variant.disr_expr); walk_list!(visitor, visit_attribute, &variant.attrs); } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 4100efb6eb3..ce3b0acdab3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1190,13 +1190,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // parsing. We try to resolve that ambiguity by attempting resolution in both the // type and value namespaces. If we resolved the path in the value namespace, we // transform it into a generic const argument. - TyKind::Path(qself, path) => { + TyKind::Path(None, path) => { if let Some(res) = self .resolver .get_partial_res(ty.id) .and_then(|partial_res| partial_res.full_res()) { - if !res.matches_ns(Namespace::TypeNS) { + if !res.matches_ns(Namespace::TypeNS) + && path.is_potential_trivial_const_arg() + { debug!( "lower_generic_arg: Lowering type argument as const argument: {:?}", ty, @@ -1218,7 +1220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let path_expr = Expr { id: ty.id, - kind: ExprKind::Path(qself.clone(), path.clone()), + kind: ExprKind::Path(None, path.clone()), span, attrs: AttrVec::new(), tokens: None, diff --git a/compiler/rustc_error_codes/src/error_codes/E0771.md b/compiler/rustc_error_codes/src/error_codes/E0771.md index a2a1a20f230..4f36590025b 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0771.md +++ b/compiler/rustc_error_codes/src/error_codes/E0771.md @@ -1,9 +1,11 @@ +#### Note: this error code is no longer emitted by the compiler + A non-`'static` lifetime was used in a const generic. This is currently not allowed. Erroneous code example: -```compile_fail,E0771 +```compile_fail,E0770 #![feature(adt_const_params)] fn function_with_str<'a, const STRING: &'a str>() {} // error! diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 119933697a1..ab2932bf969 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -51,7 +51,15 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // of a const parameter type, e.g. `struct Foo` is not allowed. None } else if tcx.lazy_normalization() { - if let Some(param_id) = tcx.hir().opt_const_param_default_param_def_id(hir_id) { + let parent_node = tcx.hir().get_parent(hir_id); + if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node + && constant.hir_id == hir_id + { + // enum variant discriminants are not allowed to use any kind of generics + None + } else if let Some(param_id) = + tcx.hir().opt_const_param_default_param_def_id(hir_id) + { // If the def_id we are calling generics_of on is an anon ct default i.e: // // struct Foo; @@ -94,15 +102,15 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { has_self: generics.has_self, has_late_bound_regions: generics.has_late_bound_regions, }; + } else { + // HACK(eddyb) this provides the correct generics when + // `feature(generic_const_expressions)` is enabled, so that const expressions + // used with const generics, e.g. `Foo<{N+1}>`, can work at all. + // + // Note that we do not supply the parent generics when using + // `min_const_generics`. + Some(parent_def_id.to_def_id()) } - - // HACK(eddyb) this provides the correct generics when - // `feature(generic_const_expressions)` is enabled, so that const expressions - // used with const generics, e.g. `Foo<{N+1}>`, can work at all. - // - // Note that we do not supply the parent generics when using - // `min_const_generics`. - Some(parent_def_id.to_def_id()) } else { let parent_node = tcx.hir().get_parent(hir_id); match parent_node { @@ -115,11 +123,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { { Some(parent_def_id.to_def_id()) } - Node::Variant(Variant { disr_expr: Some(constant), .. }) - if constant.hir_id == hir_id => - { - Some(parent_def_id.to_def_id()) - } Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => { Some(tcx.typeck_root_def_id(def_id.to_def_id())) } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 2db1d83d4fd..4e1d49c12a7 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1188,11 +1188,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } RibKind::ConstantItem(trivial, _) => { - let features = self.tcx.sess.features_untracked(); - // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !(trivial == ConstantHasGenerics::Yes - || features.generic_const_exprs) - { + if let ConstantHasGenerics::No(cause) = trivial { // HACK(min_const_generics): If we encounter `Self` in an anonymous // constant we can't easily tell if it's generic at this stage, so // we instead remember this and then enforce the self type to be @@ -1264,11 +1260,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { | RibKind::ForwardGenericParamBan => continue, RibKind::ConstantItem(trivial, _) => { - let features = self.tcx.sess.features_untracked(); - // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !(trivial == ConstantHasGenerics::Yes - || features.generic_const_exprs) - { + if let ConstantHasGenerics::No(cause) = trivial { if let Some(span) = finalize { self.report_error( span, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6f5d54bcf87..c6b193710e0 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -66,6 +66,15 @@ enum IsRepeatExpr { Yes, } +/// Describes whether an `AnonConst` is a type level const arg or +/// some other form of anon const (i.e. inline consts or enum discriminants) +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum AnonConstKind { + EnumDiscriminant, + InlineConst, + ConstArg(IsRepeatExpr), +} + impl PatternSource { fn descr(self) -> &'static str { match self { @@ -105,7 +114,7 @@ pub(crate) enum HasGenericParams { #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub(crate) enum ConstantHasGenerics { Yes, - No, + No(NoConstantGenericsReason), } impl ConstantHasGenerics { @@ -114,6 +123,27 @@ impl ConstantHasGenerics { } } +/// Reason for why an anon const is not allowed to reference generic parameters +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub(crate) enum NoConstantGenericsReason { + /// Const arguments are only allowed to use generic parameters when: + /// - `feature(generic_const_exprs)` is enabled + /// or + /// - the const argument is a sole const generic paramater, i.e. `foo::<{ N }>()` + /// + /// If neither of the above are true then this is used as the cause. + NonTrivialConstArg, + /// Enum discriminants are not allowed to reference generic parameters ever, this + /// is used when an anon const is in the following position: + /// + /// ```rust,compile_fail + /// enum Foo { + /// Variant = { N }, // this anon const is not allowed to use generics + /// } + /// ``` + IsEnumDiscriminant, +} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub(crate) enum ConstantItemKind { Const, @@ -273,15 +303,18 @@ enum LifetimeRibKind { /// Signal we cannot find which should be the anonymous lifetime. ElisionFailure, - /// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const - /// generics. We are disallowing this until we can decide on how we want to handle non-'static - /// lifetimes in const generics. See issue #74052 for discussion. - ConstGeneric, + /// This rib forbids usage of generic parameters inside of const parameter types. + /// + /// While this is desirable to support eventually, it is difficult to do and so is + /// currently forbidden. See rust-lang/project-const-generics#28 for more info. + ConstParamTy, - /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`. - /// This function will emit an error if `generic_const_exprs` is not enabled, the body - /// identified by `body_id` is an anonymous constant and `lifetime_ref` is non-static. - AnonConst, + /// Usage of generic parameters is forbidden in various positions for anon consts: + /// - const arguments when `generic_const_exprs` is not enabled + /// - enum discriminant values + /// + /// This rib emits an error when a lifetime would resolve to a lifetime parameter. + ConcreteAnonConst(NoConstantGenericsReason), /// This rib acts as a barrier to forbid reference to lifetimes of a parent item. Item, @@ -648,13 +681,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, self.resolve_block(block); self.parent_scope.macro_rules = old_macro_rules; } - fn visit_anon_const(&mut self, constant: &'ast AnonConst) { - // We deal with repeat expressions explicitly in `resolve_expr`. - self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| { - this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { - this.resolve_anon_const(constant, IsRepeatExpr::No); - }) - }) + fn visit_anon_const(&mut self, _constant: &'ast AnonConst) { + bug!("encountered anon const without a manual call to `resolve_anon_const`"); } fn visit_expr(&mut self, expr: &'ast Expr) { self.resolve_expr(expr, None); @@ -676,7 +704,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, fn visit_ty(&mut self, ty: &'ast Ty) { let prev = self.diagnostic_metadata.current_trait_object; let prev_ty = self.diagnostic_metadata.current_type_path; - match ty.kind { + match &ty.kind { TyKind::Ref(None, _) => { // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with // NodeId `ty.id`. @@ -685,7 +713,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, self.resolve_elided_lifetime(ty.id, span); visit::walk_ty(self, ty); } - TyKind::Path(ref qself, ref path) => { + TyKind::Path(qself, path) => { self.diagnostic_metadata.current_type_path = Some(ty); self.smart_resolve_path(ty.id, &qself, path, PathSource::Type); @@ -730,11 +758,11 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, visit::walk_ty(self, ty); self.lifetime_elision_candidates = candidates; } - TyKind::TraitObject(ref bounds, ..) => { + TyKind::TraitObject(bounds, ..) => { self.diagnostic_metadata.current_trait_object = Some(&bounds[..]); visit::walk_ty(self, ty) } - TyKind::BareFn(ref bare_fn) => { + TyKind::BareFn(bare_fn) => { let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo()); self.with_generic_param_rib( &bare_fn.generic_params, @@ -769,6 +797,13 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, }, ) } + TyKind::Array(element_ty, length) => { + self.visit_ty(element_ty); + self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No)); + } + TyKind::Typeof(ct) => { + self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::No)) + } _ => visit::walk_ty(self, ty), } self.diagnostic_metadata.current_trait_object = prev; @@ -994,36 +1029,25 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, // namespace first, and if that fails we try again in the value namespace. If // resolution in the value namespace succeeds, we have an generic const argument on // our hands. - if let TyKind::Path(ref qself, ref path) = ty.kind { + if let TyKind::Path(None, ref path) = ty.kind { // We cannot disambiguate multi-segment paths right now as that requires type // checking. - if path.segments.len() == 1 && path.segments[0].args.is_none() { + if path.is_potential_trivial_const_arg() { let mut check_ns = |ns| { self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns) .is_some() }; if !check_ns(TypeNS) && check_ns(ValueNS) { - // This must be equivalent to `visit_anon_const`, but we cannot call it - // directly due to visitor lifetimes so we have to copy-paste some code. - // - // 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, - ConstantHasGenerics::Yes, - None, + self.resolve_anon_const_manual( + true, + AnonConstKind::ConstArg(IsRepeatExpr::No), |this| { this.smart_resolve_path( ty.id, - qself, + &None, path, PathSource::Expr(None), ); - - if let Some(ref qself) = *qself { - this.visit_ty(&qself.ty); - } this.visit_path(path, ty.id); }, ); @@ -1037,7 +1061,9 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, self.visit_ty(ty); } GenericArg::Lifetime(lt) => self.visit_lifetime(lt, visit::LifetimeCtxt::GenericArg), - GenericArg::Const(ct) => self.visit_anon_const(ct), + GenericArg::Const(ct) => { + self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::No)) + } } self.diagnostic_metadata.currently_processing_generics = prev; } @@ -1053,7 +1079,9 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, match constraint.kind { AssocConstraintKind::Equality { ref term } => match term { Term::Ty(ty) => self.visit_ty(ty), - Term::Const(c) => self.visit_anon_const(c), + Term::Const(c) => { + self.resolve_anon_const(c, AnonConstKind::ConstArg(IsRepeatExpr::No)) + } }, AssocConstraintKind::Bound { ref bounds } => { walk_list!(self, visit_param_bound, bounds, BoundKind::Bound); @@ -1102,8 +1130,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, | LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Elided(_) | LifetimeRibKind::ElisionFailure - | LifetimeRibKind::AnonConst - | LifetimeRibKind::ConstGeneric => {} + | LifetimeRibKind::ConcreteAnonConst(_) + | LifetimeRibKind::ConstParamTy => {} } } } @@ -1164,7 +1192,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, InlineAsmOperand::Const { anon_const, .. } => { // Although this is `DefKind::AnonConst`, it is allowed to reference outer // generic parameters like an inline const. - self.resolve_inline_const(anon_const); + self.resolve_anon_const(anon_const, AnonConstKind::InlineConst); } InlineAsmOperand::Sym { sym } => self.visit_inline_asm_sym(sym), } @@ -1188,6 +1216,10 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, visit::walk_variant(self, v) } + fn visit_variant_discr(&mut self, discr: &'ast AnonConst) { + self.resolve_anon_const(discr, AnonConstKind::EnumDiscriminant); + } + fn visit_field_def(&mut self, f: &'ast FieldDef) { self.resolve_doc_links(&f.attrs, MaybeExported::Ok(f.id)); visit::walk_field_def(self, f) @@ -1386,7 +1418,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { this.ribs[TypeNS].push(Rib::new(RibKind::ConstParamTy)); this.ribs[ValueNS].push(Rib::new(RibKind::ConstParamTy)); - this.with_lifetime_rib(LifetimeRibKind::ConstGeneric, |this| { + this.with_lifetime_rib(LifetimeRibKind::ConstParamTy, |this| { this.visit_ty(ty) }); this.ribs[TypeNS].pop().unwrap(); @@ -1395,9 +1427,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { if let Some(ref expr) = default { this.ribs[TypeNS].push(forward_ty_ban_rib); this.ribs[ValueNS].push(forward_const_ban_rib); - this.with_lifetime_rib(LifetimeRibKind::ConstGeneric, |this| { - this.resolve_anon_const(expr, IsRepeatExpr::No) - }); + this.resolve_anon_const( + expr, + AnonConstKind::ConstArg(IsRepeatExpr::No), + ); forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap(); forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap(); } @@ -1475,8 +1508,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { LifetimeUseSet::Many }), LifetimeRibKind::Generics { .. } - | LifetimeRibKind::ConstGeneric => None, - LifetimeRibKind::AnonConst => { + | LifetimeRibKind::ConstParamTy => None, + LifetimeRibKind::ConcreteAnonConst(_) => { span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind) } }) @@ -1495,7 +1528,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { match rib.kind { LifetimeRibKind::Item => break, - LifetimeRibKind::ConstGeneric => { + LifetimeRibKind::ConstParamTy => { self.emit_non_static_lt_in_const_generic_error(lifetime); self.record_lifetime_res( lifetime.id, @@ -1504,7 +1537,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ); return; } - LifetimeRibKind::AnonConst => { + LifetimeRibKind::ConcreteAnonConst(cause) => { self.maybe_emit_forbidden_non_static_lifetime_error(lifetime); self.record_lifetime_res( lifetime.id, @@ -1604,9 +1637,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { return; } LifetimeRibKind::Item => break, - LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {} - LifetimeRibKind::AnonConst => { - // There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`. + LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstParamTy => {} + LifetimeRibKind::ConcreteAnonConst(_) => { + // There is always an `Elided(LifetimeRes::Infer)` inside an `AnonConst`. span_bug!(lifetime.ident.span, "unexpected rib kind: {:?}", rib.kind) } } @@ -1826,9 +1859,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { self.report_missing_lifetime_specifiers(vec![missing_lifetime], None); break; } - LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {} - LifetimeRibKind::AnonConst => { - // There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`. + LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstParamTy => {} + LifetimeRibKind::ConcreteAnonConst(_) => { + // There is always an `Elided(LifetimeRes::Infer)` inside an `AnonConst`. span_bug!(elided_lifetime_span, "unexpected rib kind: {:?}", rib.kind) } } @@ -2560,7 +2593,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f)) } - // HACK(min_const_generics,const_evaluatable_unchecked): We + // HACK(min_const_generics, generic_const_exprs): We // want to keep allowing `[0; std::mem::size_of::<*mut T>()]` // with a future compat lint for now. We do this by adding an // additional special case for repeat expressions. @@ -2576,18 +2609,26 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { item: Option<(Ident, ConstantItemKind)>, f: impl FnOnce(&mut Self), ) { - self.with_rib(ValueNS, RibKind::ConstantItem(may_use_generics, item), |this| { - this.with_rib( - TypeNS, - RibKind::ConstantItem( - may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes), - item, - ), - |this| { - this.with_label_rib(RibKind::ConstantItem(may_use_generics, item), f); - }, - ) - }); + let f = |this: &mut Self| { + this.with_rib(ValueNS, RibKind::ConstantItem(may_use_generics, item), |this| { + this.with_rib( + TypeNS, + RibKind::ConstantItem( + may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes), + item, + ), + |this| { + this.with_label_rib(RibKind::ConstantItem(may_use_generics, item), f); + }, + ) + }) + }; + + if let ConstantHasGenerics::No(cause) = may_use_generics { + self.with_lifetime_rib(LifetimeRibKind::ConcreteAnonConst(cause), f) + } else { + f(self) + } } fn with_current_self_type(&mut self, self_type: &Ty, f: impl FnOnce(&mut Self) -> T) -> T { @@ -3924,24 +3965,54 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { debug!("(resolving block) leaving block"); } - fn resolve_anon_const(&mut self, constant: &'ast AnonConst, is_repeat: IsRepeatExpr) { - debug!("resolve_anon_const {:?} is_repeat: {:?}", constant, is_repeat); - self.with_constant_rib( - is_repeat, - if constant.value.is_potential_trivial_const_param() { - ConstantHasGenerics::Yes - } else { - ConstantHasGenerics::No - }, - None, - |this| visit::walk_anon_const(this, constant), + fn resolve_anon_const(&mut self, constant: &'ast AnonConst, anon_const_kind: AnonConstKind) { + debug!( + "resolve_anon_const(constant: {:?}, anon_const_kind: {:?})", + constant, anon_const_kind ); + + self.resolve_anon_const_manual( + constant.value.is_potential_trivial_const_arg(), + anon_const_kind, + |this| this.resolve_expr(&constant.value, None), + ) } - fn resolve_inline_const(&mut self, constant: &'ast AnonConst) { - debug!("resolve_anon_const {constant:?}"); - self.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, None, |this| { - visit::walk_anon_const(this, constant) + /// There are a few places that we need to resolve an anon const but we did not parse an + /// anon const so cannot provide an `&'ast AnonConst`. Right now this is just unbraced + /// const arguments that were parsed as type arguments, and `legact_const_generics` which + /// parse as normal function argument expressions. To avoid duplicating the code for resolving + /// an anon const we have this function which lets the caller manually call `resolve_expr` or + /// `smart_resolve_path`. + fn resolve_anon_const_manual( + &mut self, + is_trivial_const_arg: bool, + anon_const_kind: AnonConstKind, + resolve_expr: impl FnOnce(&mut Self), + ) { + let is_repeat_expr = match anon_const_kind { + AnonConstKind::ConstArg(is_repeat_expr) => is_repeat_expr, + _ => IsRepeatExpr::No, + }; + + let may_use_generics = match anon_const_kind { + AnonConstKind::EnumDiscriminant => { + ConstantHasGenerics::No(NoConstantGenericsReason::IsEnumDiscriminant) + } + AnonConstKind::InlineConst => ConstantHasGenerics::Yes, + AnonConstKind::ConstArg(_) => { + if self.r.tcx.features().generic_const_exprs || is_trivial_const_arg { + ConstantHasGenerics::Yes + } else { + ConstantHasGenerics::No(NoConstantGenericsReason::NonTrivialConstArg) + } + } + }; + + self.with_constant_rib(is_repeat_expr, may_use_generics, None, |this| { + this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { + resolve_expr(this); + }); }); } @@ -4046,17 +4117,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Constant arguments need to be treated as AnonConst since // that is how they will be later lowered to HIR. if const_args.contains(&idx) { - self.with_constant_rib( - IsRepeatExpr::No, - if argument.is_potential_trivial_const_param() { - ConstantHasGenerics::Yes - } else { - ConstantHasGenerics::No - }, - None, - |this| { - this.resolve_expr(argument, None); - }, + self.resolve_anon_const_manual( + argument.is_potential_trivial_const_arg(), + AnonConstKind::ConstArg(IsRepeatExpr::No), + |this| this.resolve_expr(argument, None), ); } else { self.resolve_expr(argument, None); @@ -4115,14 +4179,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } ExprKind::Repeat(ref elem, ref ct) => { self.visit_expr(elem); - self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| { - this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { - this.resolve_anon_const(ct, IsRepeatExpr::Yes) - }) - }); + self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes)); } ExprKind::ConstBlock(ref ct) => { - self.resolve_inline_const(ct); + self.resolve_anon_const(ct, AnonConstKind::InlineConst); } ExprKind::Index(ref elem, ref idx) => { self.resolve_expr(elem, Some(expr));