From 9368b9f57e7e3a82b5becdfd17a1eeb606e6fd5f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 30 Sep 2024 00:34:58 -0400 Subject: [PATCH 1/2] Debug assert that unevaluated consts have the right substs --- compiler/rustc_middle/src/ty/consts.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 73d0acf95f4..ebc6cac3c42 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -109,6 +109,7 @@ pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> #[inline] pub fn new_unevaluated(tcx: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Const<'tcx> { + tcx.debug_assert_args_compatible(uv.def, uv.args); Const::new(tcx, ty::ConstKind::Unevaluated(uv)) } From 2239f1c5cd6da232b5d92765deace77519bdd209 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 30 Sep 2024 01:00:38 -0400 Subject: [PATCH 2/2] Validate ExistentialPredicate args --- .../src/hir_ty_lowering/dyn_compatibility.rs | 3 +- compiler/rustc_middle/src/ty/context.rs | 20 +++++++++ compiler/rustc_passes/src/reachable.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 8 ++-- .../cfi/typeid/itanium_cxx_abi/transform.rs | 21 +++++---- .../rustc_smir/src/rustc_internal/internal.rs | 20 +++++---- .../rustc_smir/src/rustc_smir/convert/ty.rs | 4 +- compiler/rustc_type_ir/src/interner.rs | 8 ++-- compiler/rustc_type_ir/src/predicate.rs | 45 ++++++++++++++++++- compiler/rustc_type_ir/src/relate.rs | 4 +- 10 files changed, 103 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index e7b8e6e69b0..ff90f89f666 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -250,7 +250,6 @@ pub(super) fn lower_trait_object_ty( } }) .collect(); - let args = tcx.mk_args(&args); let span = i.bottom().1; let empty_generic_args = hir_trait_bounds.iter().any(|(hir_bound, _)| { @@ -283,7 +282,7 @@ pub(super) fn lower_trait_object_ty( .emit(); } - ty::ExistentialTraitRef { def_id: trait_ref.def_id, args } + ty::ExistentialTraitRef::new(tcx, trait_ref.def_id, args) }) }); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2ffb273cb6f..711dc80e933 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -279,6 +279,26 @@ fn debug_assert_args_compatible(self, def_id: DefId, args: ty::GenericArgsRef<'t self.debug_assert_args_compatible(def_id, args); } + /// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection` + /// are compatible with the `DefId`. Since we're missing a `Self` type, stick on + /// a dummy self type and forward to `debug_assert_args_compatible`. + fn debug_assert_existential_args_compatible( + self, + def_id: Self::DefId, + args: Self::GenericArgs, + ) { + // FIXME: We could perhaps add a `skip: usize` to `debug_assert_args_compatible` + // to avoid needing to reintern the set of args... + if cfg!(debug_assertions) { + self.debug_assert_args_compatible( + def_id, + self.mk_args_from_iter( + [self.types.trait_object_dummy_self.into()].into_iter().chain(args.iter()), + ), + ); + } + } + fn mk_type_list_from_iter(self, args: I) -> T::Output where I: Iterator, diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 925ee262022..0cb0e961c0e 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -322,7 +322,7 @@ fn propagate_from_alloc(&mut self, alloc: ConstAllocation<'tcx>) { self.visit(ty); // Manually visit to actually see the trait's `DefId`. Type visitors won't see it if let Some(trait_ref) = dyn_ty.principal() { - let ExistentialTraitRef { def_id, args } = trait_ref.skip_binder(); + let ExistentialTraitRef { def_id, args, .. } = trait_ref.skip_binder(); self.visit_def_id(def_id, "", &""); self.visit(args); } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9094b00fbfb..0f820654ec8 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -32,8 +32,8 @@ use rustc_middle::query::Providers; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ - self, Const, GenericArgs, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitor, + self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitor, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -246,10 +246,10 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { ty::ExistentialPredicate::Trait(trait_ref) => trait_ref, ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx), ty::ExistentialPredicate::AutoTrait(def_id) => { - ty::ExistentialTraitRef { def_id, args: GenericArgs::empty() } + ty::ExistentialTraitRef::new(tcx, def_id, ty::GenericArgs::empty()) } }; - let ty::ExistentialTraitRef { def_id, args: _ } = trait_ref; + let ty::ExistentialTraitRef { def_id, .. } = trait_ref; try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)); } } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 5f7184a4240..a97a00f6ac0 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -245,11 +245,15 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc alias_ty.to_ty(tcx), ); debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx)); - ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - def_id: assoc_ty.def_id, - args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args, - term: resolved.into(), - }) + ty::ExistentialPredicate::Projection( + ty::ExistentialProjection::erase_self_ty( + tcx, + ty::ProjectionPredicate { + projection_term: alias_ty.into(), + term: resolved.into(), + }, + ), + ) }) }) }) @@ -318,10 +322,11 @@ pub fn transform_instance<'tcx>( .lang_items() .drop_trait() .unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item")); - let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { + let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new_from_args( + tcx, def_id, - args: List::empty(), - }); + ty::List::empty(), + )); let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]); let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn); instance.args = tcx.mk_args_trait(self_ty, List::empty()); diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index e9c3b3ffc1d..7be7db1fd3d 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -380,11 +380,12 @@ impl RustcInternal for ExistentialProjection { type T<'tcx> = rustc_ty::ExistentialProjection<'tcx>; fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { - rustc_ty::ExistentialProjection { - def_id: self.def_id.0.internal(tables, tcx), - args: self.generic_args.internal(tables, tcx), - term: self.term.internal(tables, tcx), - } + rustc_ty::ExistentialProjection::new_from_args( + tcx, + self.def_id.0.internal(tables, tcx), + self.generic_args.internal(tables, tcx), + self.term.internal(tables, tcx), + ) } } @@ -403,10 +404,11 @@ impl RustcInternal for ExistentialTraitRef { type T<'tcx> = rustc_ty::ExistentialTraitRef<'tcx>; fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { - rustc_ty::ExistentialTraitRef { - def_id: self.def_id.0.internal(tables, tcx), - args: self.generic_args.internal(tables, tcx), - } + rustc_ty::ExistentialTraitRef::new_from_args( + tcx, + self.def_id.0.internal(tables, tcx), + self.generic_args.internal(tables, tcx), + ) } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index b9372283feb..ef2ee9a166a 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -68,7 +68,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> { type T = stable_mir::ty::ExistentialTraitRef; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - let ty::ExistentialTraitRef { def_id, args } = self; + let ty::ExistentialTraitRef { def_id, args, .. } = self; stable_mir::ty::ExistentialTraitRef { def_id: tables.trait_def(*def_id), generic_args: args.stable(tables), @@ -95,7 +95,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> { type T = stable_mir::ty::ExistentialProjection; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - let ty::ExistentialProjection { def_id, args, term } = self; + let ty::ExistentialProjection { def_id, args, term, .. } = self; stable_mir::ty::ExistentialProjection { def_id: tables.trait_def(*def_id), generic_args: args.stable(tables), diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index b2ac67efef6..3f5d19108f2 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -15,9 +15,7 @@ CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode, }; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; -use crate::{ - search_graph, {self as ty}, -}; +use crate::{self as ty, search_graph}; pub trait Interner: Sized @@ -173,6 +171,10 @@ fn mk_args_from_iter(self, args: I) -> T::Output fn debug_assert_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs); + /// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection` + /// are compatible with the `DefId`. + fn debug_assert_existential_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs); + fn mk_type_list_from_iter(self, args: I) -> T::Output where I: Iterator, diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 76065c10d19..fed689652a5 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -289,9 +289,26 @@ pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> I::Clause { pub struct ExistentialTraitRef { pub def_id: I::DefId, pub args: I::GenericArgs, + /// This field exists to prevent the creation of `ExistentialTraitRef` without + /// calling [`ExistentialTraitRef::new_from_args`]. + _use_existential_trait_ref_new_instead: (), } impl ExistentialTraitRef { + pub fn new_from_args(interner: I, trait_def_id: I::DefId, args: I::GenericArgs) -> Self { + interner.debug_assert_existential_args_compatible(trait_def_id, args); + Self { def_id: trait_def_id, args, _use_existential_trait_ref_new_instead: () } + } + + pub fn new( + interner: I, + trait_def_id: I::DefId, + args: impl IntoIterator>, + ) -> Self { + let args = interner.mk_args_from_iter(args.into_iter().map(Into::into)); + Self::new_from_args(interner, trait_def_id, args) + } + pub fn erase_self_ty(interner: I, trait_ref: TraitRef) -> ExistentialTraitRef { // Assert there is a Self. trait_ref.args.type_at(0); @@ -299,6 +316,7 @@ pub fn erase_self_ty(interner: I, trait_ref: TraitRef) -> ExistentialTraitRef ExistentialTraitRef { def_id: trait_ref.def_id, args: interner.mk_args(&trait_ref.args.as_slice()[1..]), + _use_existential_trait_ref_new_instead: (), } } @@ -336,9 +354,33 @@ pub struct ExistentialProjection { pub def_id: I::DefId, pub args: I::GenericArgs, pub term: I::Term, + + /// This field exists to prevent the creation of `ExistentialProjection` + /// without using [`ExistentialProjection::new_from_args`]. + use_existential_projection_new_instead: (), } impl ExistentialProjection { + pub fn new_from_args( + interner: I, + def_id: I::DefId, + args: I::GenericArgs, + term: I::Term, + ) -> ExistentialProjection { + interner.debug_assert_existential_args_compatible(def_id, args); + Self { def_id, args, term, use_existential_projection_new_instead: () } + } + + pub fn new( + interner: I, + def_id: I::DefId, + args: impl IntoIterator>, + term: I::Term, + ) -> ExistentialProjection { + let args = interner.mk_args_from_iter(args.into_iter().map(Into::into)); + Self::new_from_args(interner, def_id, args, term) + } + /// Extracts the underlying existential trait reference from this projection. /// For example, if this is a projection of `exists T. ::Item == X`, /// then this function would return an `exists T. T: Iterator` existential trait @@ -347,7 +389,7 @@ pub fn trait_ref(&self, interner: I) -> ExistentialTraitRef { let def_id = interner.parent(self.def_id); let args_count = interner.generics_of(def_id).count() - 1; let args = interner.mk_args(&self.args.as_slice()[..args_count]); - ExistentialTraitRef { def_id, args } + ExistentialTraitRef { def_id, args, _use_existential_trait_ref_new_instead: () } } pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate { @@ -372,6 +414,7 @@ pub fn erase_self_ty(interner: I, projection_predicate: ProjectionPredicate) def_id: projection_predicate.projection_term.def_id, args: interner.mk_args(&projection_predicate.projection_term.args.as_slice()[1..]), term: projection_predicate.term, + use_existential_projection_new_instead: (), } } } diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 9c725f34d8e..61dd2390c80 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -308,7 +308,7 @@ fn relate>( a.args, b.args, )?; - Ok(ty::ExistentialProjection { def_id: a.def_id, args, term }) + Ok(ty::ExistentialProjection::new_from_args(relation.cx(), a.def_id, args, term)) } } } @@ -348,7 +348,7 @@ fn relate>( })) } else { let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::ExistentialTraitRef { def_id: a.def_id, args }) + Ok(ty::ExistentialTraitRef::new_from_args(relation.cx(), a.def_id, args)) } } }