misc nameres changes for anon consts

This commit is contained in:
Boxy 2023-05-05 21:31:00 +01:00
parent 4a18324a4d
commit 442617c046
7 changed files with 202 additions and 133 deletions

View file

@ -120,6 +120,12 @@ impl Path {
pub fn is_global(&self) -> bool { pub fn is_global(&self) -> bool {
!self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot !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. /// 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 /// If this is not the case, name resolution does not resolve `N` when using
/// `min_const_generics` as more complex expressions are not supported. /// `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 let this = if let ExprKind::Block(block, None) = &self.kind
&& block.stmts.len() == 1 && block.stmts.len() == 1
&& let StmtKind::Expr(expr) = &block.stmts[0].kind && let StmtKind::Expr(expr) = &block.stmts[0].kind
@ -1165,8 +1173,7 @@ impl Expr {
}; };
if let ExprKind::Path(None, path) = &this.kind if let ExprKind::Path(None, path) = &this.kind
&& path.segments.len() == 1 && path.is_potential_trivial_const_arg()
&& path.segments[0].args.is_none()
{ {
true true
} else { } else {

View file

@ -188,6 +188,9 @@ pub trait Visitor<'ast>: Sized {
fn visit_variant(&mut self, v: &'ast Variant) { fn visit_variant(&mut self, v: &'ast Variant) {
walk_variant(self, v) 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) { fn visit_label(&mut self, label: &'ast Label) {
walk_label(self, label) walk_label(self, label)
} }
@ -380,7 +383,7 @@ where
visitor.visit_ident(variant.ident); visitor.visit_ident(variant.ident);
visitor.visit_vis(&variant.vis); visitor.visit_vis(&variant.vis);
visitor.visit_variant_data(&variant.data); 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); walk_list!(visitor, visit_attribute, &variant.attrs);
} }

View file

@ -1190,13 +1190,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// parsing. We try to resolve that ambiguity by attempting resolution in both the // 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 // type and value namespaces. If we resolved the path in the value namespace, we
// transform it into a generic const argument. // transform it into a generic const argument.
TyKind::Path(qself, path) => { TyKind::Path(None, path) => {
if let Some(res) = self if let Some(res) = self
.resolver .resolver
.get_partial_res(ty.id) .get_partial_res(ty.id)
.and_then(|partial_res| partial_res.full_res()) .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!( debug!(
"lower_generic_arg: Lowering type argument as const argument: {:?}", "lower_generic_arg: Lowering type argument as const argument: {:?}",
ty, ty,
@ -1218,7 +1220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let path_expr = Expr { let path_expr = Expr {
id: ty.id, id: ty.id,
kind: ExprKind::Path(qself.clone(), path.clone()), kind: ExprKind::Path(None, path.clone()),
span, span,
attrs: AttrVec::new(), attrs: AttrVec::new(),
tokens: None, tokens: None,

View file

@ -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 A non-`'static` lifetime was used in a const generic. This is currently not
allowed. allowed.
Erroneous code example: Erroneous code example:
```compile_fail,E0771 ```compile_fail,E0770
#![feature(adt_const_params)] #![feature(adt_const_params)]
fn function_with_str<'a, const STRING: &'a str>() {} // error! fn function_with_str<'a, const STRING: &'a str>() {} // error!

View file

@ -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<const N: usize, const M: [u8; N]>` is not allowed. // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None None
} else if tcx.lazy_normalization() { } 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: // If the def_id we are calling generics_of on is an anon ct default i.e:
// //
// struct Foo<const N: usize = { .. }>; // struct Foo<const N: usize = { .. }>;
@ -94,15 +102,15 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
has_self: generics.has_self, has_self: generics.has_self,
has_late_bound_regions: generics.has_late_bound_regions, 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 { } else {
let parent_node = tcx.hir().get_parent(hir_id); let parent_node = tcx.hir().get_parent(hir_id);
match parent_node { 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()) 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(_), .. }) => { Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
Some(tcx.typeck_root_def_id(def_id.to_def_id())) Some(tcx.typeck_root_def_id(def_id.to_def_id()))
} }

View file

@ -1188,11 +1188,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
RibKind::ConstantItem(trivial, _) => { RibKind::ConstantItem(trivial, _) => {
let features = self.tcx.sess.features_untracked(); if let ConstantHasGenerics::No(cause) = trivial {
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
if !(trivial == ConstantHasGenerics::Yes
|| features.generic_const_exprs)
{
// HACK(min_const_generics): If we encounter `Self` in an anonymous // 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 // 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 // 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::ForwardGenericParamBan => continue,
RibKind::ConstantItem(trivial, _) => { RibKind::ConstantItem(trivial, _) => {
let features = self.tcx.sess.features_untracked(); if let ConstantHasGenerics::No(cause) = trivial {
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
if !(trivial == ConstantHasGenerics::Yes
|| features.generic_const_exprs)
{
if let Some(span) = finalize { if let Some(span) = finalize {
self.report_error( self.report_error(
span, span,

View file

@ -66,6 +66,15 @@ enum IsRepeatExpr {
Yes, 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 { impl PatternSource {
fn descr(self) -> &'static str { fn descr(self) -> &'static str {
match self { match self {
@ -105,7 +114,7 @@ pub(crate) enum HasGenericParams {
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum ConstantHasGenerics { pub(crate) enum ConstantHasGenerics {
Yes, Yes,
No, No(NoConstantGenericsReason),
} }
impl ConstantHasGenerics { 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<const N: isize> {
/// Variant = { N }, // this anon const is not allowed to use generics
/// }
/// ```
IsEnumDiscriminant,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum ConstantItemKind { pub(crate) enum ConstantItemKind {
Const, Const,
@ -273,15 +303,18 @@ enum LifetimeRibKind {
/// Signal we cannot find which should be the anonymous lifetime. /// Signal we cannot find which should be the anonymous lifetime.
ElisionFailure, ElisionFailure,
/// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const /// This rib forbids usage of generic parameters inside of const parameter types.
/// 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. /// While this is desirable to support eventually, it is difficult to do and so is
ConstGeneric, /// 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`. /// Usage of generic parameters is forbidden in various positions for anon consts:
/// This function will emit an error if `generic_const_exprs` is not enabled, the body /// - const arguments when `generic_const_exprs` is not enabled
/// identified by `body_id` is an anonymous constant and `lifetime_ref` is non-static. /// - enum discriminant values
AnonConst, ///
/// 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. /// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
Item, Item,
@ -648,13 +681,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
self.resolve_block(block); self.resolve_block(block);
self.parent_scope.macro_rules = old_macro_rules; self.parent_scope.macro_rules = old_macro_rules;
} }
fn visit_anon_const(&mut self, constant: &'ast AnonConst) { fn visit_anon_const(&mut self, _constant: &'ast AnonConst) {
// We deal with repeat expressions explicitly in `resolve_expr`. bug!("encountered anon const without a manual call to `resolve_anon_const`");
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_expr(&mut self, expr: &'ast Expr) { fn visit_expr(&mut self, expr: &'ast Expr) {
self.resolve_expr(expr, None); 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) { fn visit_ty(&mut self, ty: &'ast Ty) {
let prev = self.diagnostic_metadata.current_trait_object; let prev = self.diagnostic_metadata.current_trait_object;
let prev_ty = self.diagnostic_metadata.current_type_path; let prev_ty = self.diagnostic_metadata.current_type_path;
match ty.kind { match &ty.kind {
TyKind::Ref(None, _) => { TyKind::Ref(None, _) => {
// Elided lifetime in reference: we resolve as if there was some lifetime `'_` with // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
// NodeId `ty.id`. // 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); self.resolve_elided_lifetime(ty.id, span);
visit::walk_ty(self, ty); visit::walk_ty(self, ty);
} }
TyKind::Path(ref qself, ref path) => { TyKind::Path(qself, path) => {
self.diagnostic_metadata.current_type_path = Some(ty); self.diagnostic_metadata.current_type_path = Some(ty);
self.smart_resolve_path(ty.id, &qself, path, PathSource::Type); 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); visit::walk_ty(self, ty);
self.lifetime_elision_candidates = candidates; self.lifetime_elision_candidates = candidates;
} }
TyKind::TraitObject(ref bounds, ..) => { TyKind::TraitObject(bounds, ..) => {
self.diagnostic_metadata.current_trait_object = Some(&bounds[..]); self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
visit::walk_ty(self, ty) 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()); let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo());
self.with_generic_param_rib( self.with_generic_param_rib(
&bare_fn.generic_params, &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), _ => visit::walk_ty(self, ty),
} }
self.diagnostic_metadata.current_trait_object = prev; 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 // 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 // resolution in the value namespace succeeds, we have an generic const argument on
// our hands. // 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 // We cannot disambiguate multi-segment paths right now as that requires type
// checking. // checking.
if path.segments.len() == 1 && path.segments[0].args.is_none() { if path.is_potential_trivial_const_arg() {
let mut check_ns = |ns| { let mut check_ns = |ns| {
self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns) self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
.is_some() .is_some()
}; };
if !check_ns(TypeNS) && check_ns(ValueNS) { if !check_ns(TypeNS) && check_ns(ValueNS) {
// This must be equivalent to `visit_anon_const`, but we cannot call it self.resolve_anon_const_manual(
// directly due to visitor lifetimes so we have to copy-paste some code. true,
// AnonConstKind::ConstArg(IsRepeatExpr::No),
// 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,
|this| { |this| {
this.smart_resolve_path( this.smart_resolve_path(
ty.id, ty.id,
qself, &None,
path, path,
PathSource::Expr(None), PathSource::Expr(None),
); );
if let Some(ref qself) = *qself {
this.visit_ty(&qself.ty);
}
this.visit_path(path, ty.id); 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); self.visit_ty(ty);
} }
GenericArg::Lifetime(lt) => self.visit_lifetime(lt, visit::LifetimeCtxt::GenericArg), 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; 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 { match constraint.kind {
AssocConstraintKind::Equality { ref term } => match term { AssocConstraintKind::Equality { ref term } => match term {
Term::Ty(ty) => self.visit_ty(ty), 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 } => { AssocConstraintKind::Bound { ref bounds } => {
walk_list!(self, visit_param_bound, bounds, BoundKind::Bound); 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::AnonymousReportError
| LifetimeRibKind::Elided(_) | LifetimeRibKind::Elided(_)
| LifetimeRibKind::ElisionFailure | LifetimeRibKind::ElisionFailure
| LifetimeRibKind::AnonConst | LifetimeRibKind::ConcreteAnonConst(_)
| LifetimeRibKind::ConstGeneric => {} | LifetimeRibKind::ConstParamTy => {}
} }
} }
} }
@ -1164,7 +1192,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
InlineAsmOperand::Const { anon_const, .. } => { InlineAsmOperand::Const { anon_const, .. } => {
// Although this is `DefKind::AnonConst`, it is allowed to reference outer // Although this is `DefKind::AnonConst`, it is allowed to reference outer
// generic parameters like an inline const. // 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), 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) 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) { fn visit_field_def(&mut self, f: &'ast FieldDef) {
self.resolve_doc_links(&f.attrs, MaybeExported::Ok(f.id)); self.resolve_doc_links(&f.attrs, MaybeExported::Ok(f.id));
visit::walk_field_def(self, f) 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[TypeNS].push(Rib::new(RibKind::ConstParamTy));
this.ribs[ValueNS].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.visit_ty(ty)
}); });
this.ribs[TypeNS].pop().unwrap(); 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 { if let Some(ref expr) = default {
this.ribs[TypeNS].push(forward_ty_ban_rib); this.ribs[TypeNS].push(forward_ty_ban_rib);
this.ribs[ValueNS].push(forward_const_ban_rib); this.ribs[ValueNS].push(forward_const_ban_rib);
this.with_lifetime_rib(LifetimeRibKind::ConstGeneric, |this| { this.resolve_anon_const(
this.resolve_anon_const(expr, IsRepeatExpr::No) expr,
}); AnonConstKind::ConstArg(IsRepeatExpr::No),
);
forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap(); forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
forward_ty_ban_rib = this.ribs[TypeNS].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 LifetimeUseSet::Many
}), }),
LifetimeRibKind::Generics { .. } LifetimeRibKind::Generics { .. }
| LifetimeRibKind::ConstGeneric => None, | LifetimeRibKind::ConstParamTy => None,
LifetimeRibKind::AnonConst => { LifetimeRibKind::ConcreteAnonConst(_) => {
span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind) 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 { match rib.kind {
LifetimeRibKind::Item => break, LifetimeRibKind::Item => break,
LifetimeRibKind::ConstGeneric => { LifetimeRibKind::ConstParamTy => {
self.emit_non_static_lt_in_const_generic_error(lifetime); self.emit_non_static_lt_in_const_generic_error(lifetime);
self.record_lifetime_res( self.record_lifetime_res(
lifetime.id, lifetime.id,
@ -1504,7 +1537,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
); );
return; return;
} }
LifetimeRibKind::AnonConst => { LifetimeRibKind::ConcreteAnonConst(cause) => {
self.maybe_emit_forbidden_non_static_lifetime_error(lifetime); self.maybe_emit_forbidden_non_static_lifetime_error(lifetime);
self.record_lifetime_res( self.record_lifetime_res(
lifetime.id, lifetime.id,
@ -1604,9 +1637,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
return; return;
} }
LifetimeRibKind::Item => break, LifetimeRibKind::Item => break,
LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {} LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstParamTy => {}
LifetimeRibKind::AnonConst => { LifetimeRibKind::ConcreteAnonConst(_) => {
// There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`. // There is always an `Elided(LifetimeRes::Infer)` inside an `AnonConst`.
span_bug!(lifetime.ident.span, "unexpected rib kind: {:?}", rib.kind) 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); self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
break; break;
} }
LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {} LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstParamTy => {}
LifetimeRibKind::AnonConst => { LifetimeRibKind::ConcreteAnonConst(_) => {
// There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`. // There is always an `Elided(LifetimeRes::Infer)` inside an `AnonConst`.
span_bug!(elided_lifetime_span, "unexpected rib kind: {:?}", rib.kind) 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)) 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>()]` // want to keep allowing `[0; std::mem::size_of::<*mut T>()]`
// with a future compat lint for now. We do this by adding an // with a future compat lint for now. We do this by adding an
// additional special case for repeat expressions. // 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)>, item: Option<(Ident, ConstantItemKind)>,
f: impl FnOnce(&mut Self), f: impl FnOnce(&mut Self),
) { ) {
self.with_rib(ValueNS, RibKind::ConstantItem(may_use_generics, item), |this| { let f = |this: &mut Self| {
this.with_rib( this.with_rib(ValueNS, RibKind::ConstantItem(may_use_generics, item), |this| {
TypeNS, this.with_rib(
RibKind::ConstantItem( TypeNS,
may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes), RibKind::ConstantItem(
item, may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes),
), item,
|this| { ),
this.with_label_rib(RibKind::ConstantItem(may_use_generics, item), f); |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<T>(&mut self, self_type: &Ty, f: impl FnOnce(&mut Self) -> T) -> T { fn with_current_self_type<T>(&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"); debug!("(resolving block) leaving block");
} }
fn resolve_anon_const(&mut self, constant: &'ast AnonConst, is_repeat: IsRepeatExpr) { fn resolve_anon_const(&mut self, constant: &'ast AnonConst, anon_const_kind: AnonConstKind) {
debug!("resolve_anon_const {:?} is_repeat: {:?}", constant, is_repeat); debug!(
self.with_constant_rib( "resolve_anon_const(constant: {:?}, anon_const_kind: {:?})",
is_repeat, constant, anon_const_kind
if constant.value.is_potential_trivial_const_param() {
ConstantHasGenerics::Yes
} else {
ConstantHasGenerics::No
},
None,
|this| visit::walk_anon_const(this, constant),
); );
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) { /// There are a few places that we need to resolve an anon const but we did not parse an
debug!("resolve_anon_const {constant:?}"); /// anon const so cannot provide an `&'ast AnonConst`. Right now this is just unbraced
self.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, None, |this| { /// const arguments that were parsed as type arguments, and `legact_const_generics` which
visit::walk_anon_const(this, constant) /// 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 // Constant arguments need to be treated as AnonConst since
// that is how they will be later lowered to HIR. // that is how they will be later lowered to HIR.
if const_args.contains(&idx) { if const_args.contains(&idx) {
self.with_constant_rib( self.resolve_anon_const_manual(
IsRepeatExpr::No, argument.is_potential_trivial_const_arg(),
if argument.is_potential_trivial_const_param() { AnonConstKind::ConstArg(IsRepeatExpr::No),
ConstantHasGenerics::Yes |this| this.resolve_expr(argument, None),
} else {
ConstantHasGenerics::No
},
None,
|this| {
this.resolve_expr(argument, None);
},
); );
} else { } else {
self.resolve_expr(argument, None); 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) => { ExprKind::Repeat(ref elem, ref ct) => {
self.visit_expr(elem); self.visit_expr(elem);
self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| { self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes));
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
this.resolve_anon_const(ct, IsRepeatExpr::Yes)
})
});
} }
ExprKind::ConstBlock(ref ct) => { ExprKind::ConstBlock(ref ct) => {
self.resolve_inline_const(ct); self.resolve_anon_const(ct, AnonConstKind::InlineConst);
} }
ExprKind::Index(ref elem, ref idx) => { ExprKind::Index(ref elem, ref idx) => {
self.resolve_expr(elem, Some(expr)); self.resolve_expr(elem, Some(expr));