Rollup merge of #102884 - petrochenkov:liferib, r=cjgillot
resolve: Some cleanup, asserts and tests for lifetime ribs Follow up to https://github.com/rust-lang/rust/pull/98279 and friends. r? ``@cjgillot``
This commit is contained in:
commit
39ff2a60d6
3 changed files with 166 additions and 65 deletions
|
@ -224,22 +224,14 @@ enum LifetimeUseSet {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
enum LifetimeRibKind {
|
enum LifetimeRibKind {
|
||||||
/// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
|
// -- Ribs introducing named lifetimes
|
||||||
Item,
|
//
|
||||||
|
|
||||||
/// This rib declares generic parameters.
|
/// This rib declares generic parameters.
|
||||||
|
/// Only for this kind the `LifetimeRib::bindings` field can be non-empty.
|
||||||
Generics { binder: NodeId, span: Span, kind: LifetimeBinderKind },
|
Generics { binder: NodeId, span: Span, kind: LifetimeBinderKind },
|
||||||
|
|
||||||
/// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
|
// -- Ribs introducing unnamed lifetimes
|
||||||
/// 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,
|
|
||||||
|
|
||||||
/// 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,
|
|
||||||
|
|
||||||
/// Create a new anonymous lifetime parameter and reference it.
|
/// Create a new anonymous lifetime parameter and reference it.
|
||||||
///
|
///
|
||||||
/// If `report_in_path`, report an error when encountering lifetime elision in a path:
|
/// If `report_in_path`, report an error when encountering lifetime elision in a path:
|
||||||
|
@ -256,16 +248,31 @@ enum LifetimeRibKind {
|
||||||
/// ```
|
/// ```
|
||||||
AnonymousCreateParameter { binder: NodeId, report_in_path: bool },
|
AnonymousCreateParameter { binder: NodeId, report_in_path: bool },
|
||||||
|
|
||||||
|
/// Replace all anonymous lifetimes by provided lifetime.
|
||||||
|
Elided(LifetimeRes),
|
||||||
|
|
||||||
|
// -- Barrier ribs that stop lifetime lookup, or continue it but produce an error later.
|
||||||
|
//
|
||||||
/// Give a hard error when either `&` or `'_` is written. Used to
|
/// Give a hard error when either `&` or `'_` is written. Used to
|
||||||
/// rule out things like `where T: Foo<'_>`. Does not imply an
|
/// rule out things like `where T: Foo<'_>`. Does not imply an
|
||||||
/// error on default object bounds (e.g., `Box<dyn Foo>`).
|
/// error on default object bounds (e.g., `Box<dyn Foo>`).
|
||||||
AnonymousReportError,
|
AnonymousReportError,
|
||||||
|
|
||||||
/// Replace all anonymous lifetimes by provided lifetime.
|
|
||||||
Elided(LifetimeRes),
|
|
||||||
|
|
||||||
/// 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
|
||||||
|
/// 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,
|
||||||
|
|
||||||
|
/// 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,
|
||||||
|
|
||||||
|
/// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
|
||||||
|
Item,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -748,35 +755,31 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
|
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
|
||||||
match foreign_item.kind {
|
match foreign_item.kind {
|
||||||
ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
|
ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
|
||||||
self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
|
self.with_generic_param_rib(
|
||||||
this.with_generic_param_rib(
|
&generics.params,
|
||||||
&generics.params,
|
ItemRibKind(HasGenericParams::Yes(generics.span)),
|
||||||
ItemRibKind(HasGenericParams::Yes(generics.span)),
|
LifetimeRibKind::Generics {
|
||||||
LifetimeRibKind::Generics {
|
binder: foreign_item.id,
|
||||||
binder: foreign_item.id,
|
kind: LifetimeBinderKind::Item,
|
||||||
kind: LifetimeBinderKind::Item,
|
span: generics.span,
|
||||||
span: generics.span,
|
},
|
||||||
},
|
|this| visit::walk_foreign_item(this, foreign_item),
|
||||||
|this| visit::walk_foreign_item(this, foreign_item),
|
);
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
ForeignItemKind::Fn(box Fn { ref generics, .. }) => {
|
ForeignItemKind::Fn(box Fn { ref generics, .. }) => {
|
||||||
self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
|
self.with_generic_param_rib(
|
||||||
this.with_generic_param_rib(
|
&generics.params,
|
||||||
&generics.params,
|
ItemRibKind(HasGenericParams::Yes(generics.span)),
|
||||||
ItemRibKind(HasGenericParams::Yes(generics.span)),
|
LifetimeRibKind::Generics {
|
||||||
LifetimeRibKind::Generics {
|
binder: foreign_item.id,
|
||||||
binder: foreign_item.id,
|
kind: LifetimeBinderKind::Function,
|
||||||
kind: LifetimeBinderKind::Function,
|
span: generics.span,
|
||||||
span: generics.span,
|
},
|
||||||
},
|
|this| visit::walk_foreign_item(this, foreign_item),
|
||||||
|this| visit::walk_foreign_item(this, foreign_item),
|
);
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
ForeignItemKind::Static(..) => {
|
ForeignItemKind::Static(..) => {
|
||||||
self.with_item_rib(|this| {
|
self.with_static_rib(|this| {
|
||||||
visit::walk_foreign_item(this, foreign_item);
|
visit::walk_foreign_item(this, foreign_item);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1391,9 +1394,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
return self.resolve_anonymous_lifetime(lifetime, false);
|
return self.resolve_anonymous_lifetime(lifetime, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut indices = (0..self.lifetime_ribs.len()).rev();
|
let mut lifetime_rib_iter = self.lifetime_ribs.iter().rev();
|
||||||
for i in &mut indices {
|
while let Some(rib) = lifetime_rib_iter.next() {
|
||||||
let rib = &self.lifetime_ribs[i];
|
|
||||||
let normalized_ident = ident.normalize_to_macros_2_0();
|
let normalized_ident = ident.normalize_to_macros_2_0();
|
||||||
if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
|
if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
|
||||||
self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named);
|
self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named);
|
||||||
|
@ -1423,9 +1425,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
} else {
|
} else {
|
||||||
LifetimeUseSet::Many
|
LifetimeUseSet::Many
|
||||||
}),
|
}),
|
||||||
LifetimeRibKind::Generics { .. }
|
LifetimeRibKind::Generics { .. } => None,
|
||||||
| LifetimeRibKind::ConstGeneric
|
LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => {
|
||||||
| LifetimeRibKind::AnonConst => None,
|
span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.unwrap_or(LifetimeUseSet::Many);
|
.unwrap_or(LifetimeUseSet::Many);
|
||||||
debug!(?use_ctxt, ?use_set);
|
debug!(?use_ctxt, ?use_set);
|
||||||
|
@ -1460,13 +1463,16 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ => {}
|
LifetimeRibKind::AnonymousCreateParameter { .. }
|
||||||
|
| LifetimeRibKind::Elided(_)
|
||||||
|
| LifetimeRibKind::Generics { .. }
|
||||||
|
| LifetimeRibKind::ElisionFailure
|
||||||
|
| LifetimeRibKind::AnonymousReportError => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut outer_res = None;
|
let mut outer_res = None;
|
||||||
for i in indices {
|
for rib in lifetime_rib_iter {
|
||||||
let rib = &self.lifetime_ribs[i];
|
|
||||||
let normalized_ident = ident.normalize_to_macros_2_0();
|
let normalized_ident = ident.normalize_to_macros_2_0();
|
||||||
if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) {
|
if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) {
|
||||||
outer_res = Some(outer);
|
outer_res = Some(outer);
|
||||||
|
@ -1493,8 +1499,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
count: 1,
|
count: 1,
|
||||||
};
|
};
|
||||||
let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
|
let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
|
||||||
for i in (0..self.lifetime_ribs.len()).rev() {
|
for rib in self.lifetime_ribs.iter().rev() {
|
||||||
let rib = &mut self.lifetime_ribs[i];
|
|
||||||
debug!(?rib.kind);
|
debug!(?rib.kind);
|
||||||
match rib.kind {
|
match rib.kind {
|
||||||
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
|
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
|
||||||
|
@ -1534,9 +1539,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LifetimeRibKind::Item => break,
|
LifetimeRibKind::Item => break,
|
||||||
LifetimeRibKind::Generics { .. }
|
LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {}
|
||||||
| LifetimeRibKind::ConstGeneric
|
LifetimeRibKind::AnonConst => {
|
||||||
| LifetimeRibKind::AnonConst => {}
|
// There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`.
|
||||||
|
span_bug!(lifetime.ident.span, "unexpected rib kind: {:?}", rib.kind)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
|
self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
|
||||||
|
@ -1751,9 +1758,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
|
self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
LifetimeRibKind::Generics { .. }
|
LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {}
|
||||||
| LifetimeRibKind::ConstGeneric
|
LifetimeRibKind::AnonConst => {
|
||||||
| LifetimeRibKind::AnonConst => {}
|
// There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`.
|
||||||
|
span_bug!(elided_lifetime_span, "unexpected rib kind: {:?}", rib.kind)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2204,7 +2213,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
|
ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
|
||||||
self.with_item_rib(|this| {
|
self.with_static_rib(|this| {
|
||||||
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
|
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
|
||||||
this.visit_ty(ty);
|
this.visit_ty(ty);
|
||||||
});
|
});
|
||||||
|
@ -2399,11 +2408,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
self.label_ribs.pop();
|
self.label_ribs.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) {
|
fn with_static_rib(&mut self, f: impl FnOnce(&mut Self)) {
|
||||||
let kind = ItemRibKind(HasGenericParams::No);
|
let kind = ItemRibKind(HasGenericParams::No);
|
||||||
self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
|
self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
|
||||||
this.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK(min_const_generics,const_evaluatable_unchecked): We
|
// HACK(min_const_generics,const_evaluatable_unchecked): We
|
||||||
|
@ -3938,7 +3945,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
fn_id: NodeId,
|
fn_id: NodeId,
|
||||||
async_node_id: Option<(NodeId, Span)>,
|
async_node_id: Option<(NodeId, Span)>,
|
||||||
) {
|
) {
|
||||||
if let Some((async_node_id, _)) = async_node_id {
|
if let Some((async_node_id, span)) = async_node_id {
|
||||||
let mut extra_lifetime_params =
|
let mut extra_lifetime_params =
|
||||||
self.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default();
|
self.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default();
|
||||||
for rib in self.lifetime_ribs.iter().rev() {
|
for rib in self.lifetime_ribs.iter().rev() {
|
||||||
|
@ -3952,7 +3959,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
extra_lifetime_params.extend(earlier_fresh);
|
extra_lifetime_params.extend(earlier_fresh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
LifetimeRibKind::Generics { .. } => {}
|
||||||
|
_ => {
|
||||||
|
// We are in a function definition. We should only find `Generics`
|
||||||
|
// and `AnonymousCreateParameter` inside the innermost `Item`.
|
||||||
|
span_bug!(span, "unexpected rib kind: {:?}", rib.kind)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params);
|
self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params);
|
||||||
|
|
28
src/test/ui/lifetimes/unusual-rib-combinations.rs
Normal file
28
src/test/ui/lifetimes/unusual-rib-combinations.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#![feature(inline_const)]
|
||||||
|
|
||||||
|
struct S<'a>(&'a u8);
|
||||||
|
fn foo() {}
|
||||||
|
|
||||||
|
// Paren generic args in AnonConst
|
||||||
|
fn a() -> [u8; foo::()] {
|
||||||
|
//~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
|
||||||
|
//~| ERROR mismatched types
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paren generic args in ConstGeneric
|
||||||
|
fn b<const C: u8()>() {}
|
||||||
|
//~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
|
||||||
|
|
||||||
|
// Paren generic args in AnonymousReportError
|
||||||
|
fn c<T = u8()>() {}
|
||||||
|
//~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
|
||||||
|
//~| ERROR defaults for type parameters are only allowed in
|
||||||
|
//~| WARN this was previously accepted
|
||||||
|
|
||||||
|
// Elided lifetime in path in ConstGeneric
|
||||||
|
fn d<const C: S>() {}
|
||||||
|
//~^ ERROR missing lifetime specifier
|
||||||
|
//~| ERROR `S<'static>` is forbidden as the type of a const generic parameter
|
||||||
|
|
||||||
|
fn main() {}
|
61
src/test/ui/lifetimes/unusual-rib-combinations.stderr
Normal file
61
src/test/ui/lifetimes/unusual-rib-combinations.stderr
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
error[E0106]: missing lifetime specifier
|
||||||
|
--> $DIR/unusual-rib-combinations.rs:24:15
|
||||||
|
|
|
||||||
|
LL | fn d<const C: S>() {}
|
||||||
|
| ^ expected named lifetime parameter
|
||||||
|
|
|
||||||
|
help: consider introducing a named lifetime parameter
|
||||||
|
|
|
||||||
|
LL | fn d<'a, const C: S<'a>>() {}
|
||||||
|
| +++ ++++
|
||||||
|
|
||||||
|
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
|
||||||
|
--> $DIR/unusual-rib-combinations.rs:7:16
|
||||||
|
|
|
||||||
|
LL | fn a() -> [u8; foo::()] {
|
||||||
|
| ^^^^^^^ only `Fn` traits may use parentheses
|
||||||
|
|
||||||
|
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
|
||||||
|
--> $DIR/unusual-rib-combinations.rs:14:15
|
||||||
|
|
|
||||||
|
LL | fn b<const C: u8()>() {}
|
||||||
|
| ^^^^ only `Fn` traits may use parentheses
|
||||||
|
|
||||||
|
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
|
||||||
|
--> $DIR/unusual-rib-combinations.rs:18:10
|
||||||
|
|
|
||||||
|
LL | fn c<T = u8()>() {}
|
||||||
|
| ^^^^ only `Fn` traits may use parentheses
|
||||||
|
|
||||||
|
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
|
||||||
|
--> $DIR/unusual-rib-combinations.rs:18:6
|
||||||
|
|
|
||||||
|
LL | fn c<T = u8()>() {}
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
|
||||||
|
= note: `#[deny(invalid_type_param_default)]` on by default
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/unusual-rib-combinations.rs:7:16
|
||||||
|
|
|
||||||
|
LL | fn a() -> [u8; foo::()] {
|
||||||
|
| ^^^^^^^ expected `usize`, found fn item
|
||||||
|
|
|
||||||
|
= note: expected type `usize`
|
||||||
|
found fn item `fn() {foo}`
|
||||||
|
|
||||||
|
error: `S<'static>` is forbidden as the type of a const generic parameter
|
||||||
|
--> $DIR/unusual-rib-combinations.rs:24:15
|
||||||
|
|
|
||||||
|
LL | fn d<const C: S>() {}
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= note: the only supported types are integers, `bool` and `char`
|
||||||
|
= help: more complex types are supported with `#![feature(adt_const_params)]`
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0106, E0214, E0308.
|
||||||
|
For more information about an error, try `rustc --explain E0106`.
|
Loading…
Add table
Add a link
Reference in a new issue