diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index e6c582667ba57..871f9cc6b8165 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -48,6 +48,7 @@ pub(super) fn infer_predicates( // requirements for adt_def. let field_ty = tcx.type_of(field_def.did).instantiate_identity(); let field_span = tcx.def_span(field_def.did); + let is_self_referential = is_self_referential(field_ty, adt_def); insert_required_predicates_to_be_wf( tcx, field_ty, @@ -55,6 +56,7 @@ pub(super) fn infer_predicates( &global_inferred_outlives, &mut item_required_predicates, &mut explicit_map, + is_self_referential, ); } } @@ -67,6 +69,7 @@ pub(super) fn infer_predicates( &global_inferred_outlives, &mut item_required_predicates, &mut explicit_map, + IsSelfReferential::No, ); } @@ -104,6 +107,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( global_inferred_outlives: &FxIndexMap>>, required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, + is_self_referential: IsSelfReferential, ) { for arg in ty.walk() { let leaf_ty = match arg.unpack() { @@ -133,6 +137,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( args, global_inferred_outlives, required_predicates, + is_self_referential, ); check_explicit_predicates( tcx, @@ -154,6 +159,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( alias.args, global_inferred_outlives, required_predicates, + is_self_referential, ); check_explicit_predicates( tcx, @@ -324,6 +330,7 @@ fn check_inferred_predicates<'tcx>( args: ty::GenericArgsRef<'tcx>, global_inferred_outlives: &FxIndexMap>>, required_predicates: &mut RequiredPredicates<'tcx>, + is_self_referential: IsSelfReferential, ) { // Load the current set of inferred and explicit predicates from `global_inferred_outlives` // and filter the ones that are `TypeOutlives`. @@ -335,8 +342,13 @@ fn check_inferred_predicates<'tcx>( for (&predicate, &span) in predicates.as_ref().skip_binder() { // `predicate` is `U: 'b` in the example above. // So apply the instantiation to get `T: 'a`. - let ty::OutlivesPredicate(arg, region) = - predicates.rebind(predicate).instantiate(tcx, args); + let ty::OutlivesPredicate(arg, region) = if is_self_referential.into() { + // However, for self referential ADTs, we don't instantiate + // to avoid issues like #118163 + predicate + } else { + predicates.rebind(predicate).instantiate(tcx, args) + }; insert_outlives_predicate(tcx, arg, region, span, required_predicates); } } diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index d3bb22d715d7b..ce04af7e712c6 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -1,6 +1,6 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; -use rustc_middle::ty::{self, Region, Ty, TyCtxt}; +use rustc_middle::ty::{self, Adt, AdtDef, Ref, Region, Ty, TyCtxt}; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_span::Span; use smallvec::smallvec; @@ -182,3 +182,41 @@ fn is_free_region(region: Region<'_>) -> bool { } } } + +#[derive(Copy, Clone)] +pub(crate) enum IsSelfReferential { + Yes, + No, +} + +impl From for IsSelfReferential { + fn from(value: bool) -> Self { + match value { + true => IsSelfReferential::Yes, + false => IsSelfReferential::No, + } + } +} + +impl From for bool { + fn from(value: IsSelfReferential) -> Self { + match value { + IsSelfReferential::Yes => true, + IsSelfReferential::No => false, + } + } +} + +// Check if an ADT's field is a reference to the ADT itself. +// Example: `struct Recurse<'a, T>(T, &'a Recurse<'a, T>)` +// will return true +pub(crate) fn is_self_referential(field_ty: Ty<'_>, adt_def: AdtDef<'_>) -> IsSelfReferential { + if let Ref(_, ref_ty, _) = field_ty.kind() + && let Adt(field_ty_adt, _) = ref_ty.kind() + { + field_ty_adt.did() == adt_def.did() + } else { + false + } + .into() +} diff --git a/tests/ui/regions/regions-outlives-for-recursive-types.rs b/tests/ui/regions/regions-outlives-for-recursive-types.rs new file mode 100644 index 0000000000000..9011c40af91e0 --- /dev/null +++ b/tests/ui/regions/regions-outlives-for-recursive-types.rs @@ -0,0 +1,14 @@ +//@ check-pass + +#![allow(dead_code)] + +trait Bound { + type Assoc: Bound; +} + +struct Recurse<'a, T: Bound> { + first: &'a T, + value: &'a Recurse<'a, T::Assoc>, +} + +fn main() {}