diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 8dc5ed2db7e49..15e74db8d7458 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1162,10 +1162,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if should_encode_type(tcx, local_id, def_kind) { record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); } - if let DefKind::TyParam | DefKind::ConstParam = def_kind { - if let Some(default) = self.tcx.object_lifetime_default(def_id) { - record!(self.tables.object_lifetime_default[def_id] <- default); - } + if let DefKind::TyParam = def_kind { + let default = self.tcx.object_lifetime_default(def_id); + record!(self.tables.object_lifetime_default[def_id] <- default); } if let DefKind::Trait | DefKind::TraitAlias = def_kind { record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index abaef0354ade5..8e7bacca262e1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1593,12 +1593,13 @@ rustc_queries! { query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxIndexSet> { desc { "testing if a region is late bound" } } - /// For a given item (like a struct), gets the default lifetimes to be used + /// For a given item's generic parameter, gets the default lifetimes to be used /// for each parameter if a trait object were to be passed for that parameter. - /// For example, for `struct Foo<'a, T, U>`, this would be `['static, 'static]`. - /// For `struct Foo<'a, T: 'a, U>`, this would instead be `['a, 'static]`. - query object_lifetime_default(key: DefId) -> Option { - desc { "looking up lifetime defaults for generic parameter `{:?}`", key } + /// For example, for `T` in `struct Foo<'a, T>`, this would be `'static`. + /// For `T` in `struct Foo<'a, T: 'a>`, this would instead be `'a`. + /// This query will panic if passed something that is not a type parameter. + query object_lifetime_default(key: DefId) -> ObjectLifetimeDefault { + desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(key) } separate_provide_extern } query late_bound_vars_map(_: LocalDefId) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 100adedfb5052..a63af4159e8cb 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -173,9 +173,7 @@ impl CheckAttrVisitor<'_> { sym::no_implicit_prelude => { self.check_generic_attr(hir_id, attr, target, &[Target::Mod]) } - sym::rustc_object_lifetime_default => { - self.check_object_lifetime_default(hir_id, span) - } + sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id), _ => {} } @@ -415,26 +413,21 @@ impl CheckAttrVisitor<'_> { } /// Debugging aid for `object_lifetime_default` query. - fn check_object_lifetime_default(&self, hir_id: HirId, span: Span) { + fn check_object_lifetime_default(&self, hir_id: HirId) { let tcx = self.tcx; if let Some(generics) = tcx.hir().get_generics(tcx.hir().local_def_id(hir_id)) { - let object_lifetime_default_reprs: String = generics - .params - .iter() - .filter_map(|p| { - let param_id = tcx.hir().local_def_id(p.hir_id); - let default = tcx.object_lifetime_default(param_id)?; - Some(match default { - ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(), - ObjectLifetimeDefault::Static => "'static".to_owned(), - ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(), - ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(), - }) - }) - .collect::>() - .join(","); - - tcx.sess.span_err(span, &object_lifetime_default_reprs); + for p in generics.params { + let hir::GenericParamKind::Type { .. } = p.kind else { continue }; + let param_id = tcx.hir().local_def_id(p.hir_id); + let default = tcx.object_lifetime_default(param_id); + let repr = match default { + ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(), + ObjectLifetimeDefault::Static => "'static".to_owned(), + ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(), + ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(), + }; + tcx.sess.span_err(p.span, &repr); + } } } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index c16eab222f625..c72981ed96f67 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1148,21 +1148,18 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } -fn object_lifetime_default<'tcx>( - tcx: TyCtxt<'tcx>, - param_def_id: DefId, -) -> Option { +fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> ObjectLifetimeDefault { + debug_assert_eq!(tcx.def_kind(param_def_id), DefKind::TyParam); let param_def_id = param_def_id.expect_local(); let parent_def_id = tcx.local_parent(param_def_id); - let generics = tcx.hir().get_generics(parent_def_id)?; + let generics = tcx.hir().get_generics(parent_def_id).unwrap(); let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id); - let param = generics.params.iter().find(|p| p.hir_id == param_hir_id)?; + let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap(); // Scan the bounds and where-clauses on parameters to extract bounds // of the form `T:'a` so as to determine the `ObjectLifetimeDefault` // for each type parameter. match param.kind { - GenericParamKind::Lifetime { .. } => None, GenericParamKind::Type { .. } => { let mut set = Set1::Empty; @@ -1181,21 +1178,17 @@ fn object_lifetime_default<'tcx>( } } - Some(match set { + match set { Set1::Empty => ObjectLifetimeDefault::Empty, Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static, Set1::One(hir::LifetimeName::Param(param_def_id, _)) => { ObjectLifetimeDefault::Param(param_def_id.to_def_id()) } _ => ObjectLifetimeDefault::Ambiguous, - }) + } } - GenericParamKind::Const { .. } => { - // Generic consts don't impose any constraints. - // - // We still store a dummy value here to allow generic parameters - // in an arbitrary order. - Some(ObjectLifetimeDefault::Empty) + _ => { + bug!("object_lifetime_default_raw must only be called on a type parameter") } } } @@ -1512,7 +1505,20 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { generics .params .iter() - .filter_map(|param| self.tcx.object_lifetime_default(param.def_id)) + .filter_map(|param| { + match self.tcx.def_kind(param.def_id) { + // Generic consts don't impose any constraints. + // + // We still store a dummy value here to allow generic parameters + // in an arbitrary order. + DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty), + DefKind::TyParam => Some(self.tcx.object_lifetime_default(param.def_id)), + // We may also get a `Trait` or `TraitAlias` because of how generics `Self` parameter + // works. Ignore it because it can't have a meaningful lifetime default. + DefKind::LifetimeParam | DefKind::Trait | DefKind::TraitAlias => None, + dk => bug!("unexpected def_kind {:?}", dk), + } + }) .map(set_to_region) .collect() }); diff --git a/src/test/ui/object-lifetime/object-lifetime-default.rs b/src/test/ui/object-lifetime/object-lifetime-default.rs index 60b6629e694db..74f5bb7ddb0ec 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default.rs +++ b/src/test/ui/object-lifetime/object-lifetime-default.rs @@ -1,24 +1,50 @@ #![feature(rustc_attrs)] #[rustc_object_lifetime_default] -struct A(T); //~ ERROR BaseDefault +struct A< + T, //~ ERROR BaseDefault +>(T); #[rustc_object_lifetime_default] -struct B<'a,T>(&'a (), T); //~ ERROR BaseDefault +struct B< + 'a, + T, //~ ERROR BaseDefault +>(&'a (), T); #[rustc_object_lifetime_default] -struct C<'a,T:'a>(&'a T); //~ ERROR 'a +struct C< + 'a, + T: 'a, //~ ERROR 'a +>(&'a T); #[rustc_object_lifetime_default] -struct D<'a,'b,T:'a+'b>(&'a T, &'b T); //~ ERROR Ambiguous +struct D< + 'a, + 'b, + T: 'a + 'b, //~ ERROR Ambiguous +>(&'a T, &'b T); #[rustc_object_lifetime_default] -struct E<'a,'b:'a,T:'b>(&'a T, &'b T); //~ ERROR 'b +struct E< + 'a, + 'b: 'a, + T: 'b, //~ ERROR 'b +>(&'a T, &'b T); #[rustc_object_lifetime_default] -struct F<'a,'b,T:'a,U:'b>(&'a T, &'b U); //~ ERROR 'a,'b +struct F< + 'a, + 'b, + T: 'a, //~ ERROR 'a + U: 'b, //~ ERROR 'b +>(&'a T, &'b U); #[rustc_object_lifetime_default] -struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U); //~ ERROR 'a,Ambiguous - -fn main() { } +struct G< + 'a, + 'b, + T: 'a, //~ ERROR 'a + U: 'a + 'b, //~ ERROR Ambiguous +>(&'a T, &'b U); + +fn main() {} diff --git a/src/test/ui/object-lifetime/object-lifetime-default.stderr b/src/test/ui/object-lifetime/object-lifetime-default.stderr index 60cb98c8fd372..a58afad3ef2be 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default.stderr @@ -1,44 +1,56 @@ error: BaseDefault - --> $DIR/object-lifetime-default.rs:4:1 + --> $DIR/object-lifetime-default.rs:5:5 | -LL | struct A(T); - | ^^^^^^^^^^^^^^^ +LL | T, + | ^ error: BaseDefault - --> $DIR/object-lifetime-default.rs:7:1 + --> $DIR/object-lifetime-default.rs:11:5 | -LL | struct B<'a,T>(&'a (), T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | T, + | ^ error: 'a - --> $DIR/object-lifetime-default.rs:10:1 + --> $DIR/object-lifetime-default.rs:17:5 | -LL | struct C<'a,T:'a>(&'a T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | T: 'a, + | ^ error: Ambiguous - --> $DIR/object-lifetime-default.rs:13:1 + --> $DIR/object-lifetime-default.rs:24:5 | -LL | struct D<'a,'b,T:'a+'b>(&'a T, &'b T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | T: 'a + 'b, + | ^ error: 'b - --> $DIR/object-lifetime-default.rs:16:1 + --> $DIR/object-lifetime-default.rs:31:5 | -LL | struct E<'a,'b:'a,T:'b>(&'a T, &'b T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | T: 'b, + | ^ -error: 'a,'b - --> $DIR/object-lifetime-default.rs:19:1 +error: 'a + --> $DIR/object-lifetime-default.rs:38:5 + | +LL | T: 'a, + | ^ + +error: 'b + --> $DIR/object-lifetime-default.rs:39:5 | -LL | struct F<'a,'b,T:'a,U:'b>(&'a T, &'b U); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | U: 'b, + | ^ -error: 'a,Ambiguous - --> $DIR/object-lifetime-default.rs:22:1 +error: 'a + --> $DIR/object-lifetime-default.rs:46:5 + | +LL | T: 'a, + | ^ + +error: Ambiguous + --> $DIR/object-lifetime-default.rs:47:5 | -LL | struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | U: 'a + 'b, + | ^ -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors