1//! Transforms instances and types for LLVM CFI and cross-language LLVM CFI support using Itanium
2//! C++ ABI mangling.
3//!
4//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
5//! see design document in the tracking issue #89653.
67use std::iter;
89use rustc_hir::{selfas hir, LangItem, find_attr};
10use rustc_middle::bug;
11use rustc_middle::ty::{
12self, AssocContainer, ExistentialPredicateStableCmpExtas _, Instance, IntTy, List, TraitRef,
13Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UintTy,
14Unnormalized,
15};
16use rustc_span::DUMMY_SP;
17use rustc_span::def_id::DefId;
18use rustc_trait_selection::traits;
19use tracing::{debug, instrument};
2021use crate::cfi::typeid::TypeIdOptions;
22use crate::cfi::typeid::itanium_cxx_abi::encode::EncodeTyOptions;
2324/// Options for transform_ty.
25pub(crate) type TransformTyOptions = TypeIdOptions;
2627pub(crate) struct TransformTy<'tcx> {
28 tcx: TyCtxt<'tcx>,
29 options: TransformTyOptions,
30 parents: Vec<Ty<'tcx>>,
31}
3233impl<'tcx> TransformTy<'tcx> {
34pub(crate) fn new(tcx: TyCtxt<'tcx>, options: TransformTyOptions) -> Self {
35TransformTy { tcx, options, parents: Vec::new() }
36 }
37}
3839/// Transforms a ty:Ty for being encoded and used in the substitution dictionary.
40///
41/// * Transforms all c_void types into unit types.
42/// * Generalizes pointers if TransformTyOptions::GENERALIZE_POINTERS option is set.
43/// * Normalizes integers if TransformTyOptions::NORMALIZE_INTEGERS option is set.
44/// * Generalizes any repr(transparent) user-defined type that is either a pointer or reference, and
45/// either references itself or any other type that contains or references itself, to avoid a
46/// reference cycle.
47/// * Transforms repr(transparent) types without non-ZST field into ().
48///
49impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> {
50// Transforms a ty:Ty for being encoded and used in the substitution dictionary.
51fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
52match t.kind() {
53 ty::Closure(..)
54 | ty::Coroutine(..)
55 | ty::CoroutineClosure(..)
56 | ty::CoroutineWitness(..)
57 | ty::Dynamic(..)
58 | ty::Float(..)
59 | ty::FnDef(..)
60 | ty::Foreign(..)
61 | ty::Never62 | ty::Pat(..)
63 | ty::Slice(..)
64 | ty::Str65 | ty::Tuple(..)
66 | ty::UnsafeBinder(_) => t.super_fold_with(self),
6768// Don't transform the type of the array length and keep it as `usize`.
69 // This is required for `try_to_target_usize` to work correctly.
70&ty::Array(inner, len) => {
71let inner = self.fold_ty(inner);
72Ty::new_array_with_const_len(self.tcx, inner, len)
73 }
7475 ty::Bool => {
76if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
77// Note: on all platforms that Rust's currently supports, its size and alignment
78 // are 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
79 //
80 // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
81 //
82 // Clang represents bool as an 8-bit unsigned integer.
83self.tcx.types.u8
84 } else {
85t86 }
87 }
8889 ty::Char => {
90if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
91// Since #118032, char is guaranteed to have the same size, alignment, and
92 // function call ABI as u32 on all platforms.
93self.tcx.types.u32
94 } else {
95t96 }
97 }
9899 ty::Int(..) | ty::Uint(..) => {
100if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
101// Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit
102 // wide. All platforms we currently support have a C platform, and as a
103 // consequence, isize/usize are at least 16-bit wide for all of them.
104 //
105 // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
106match t.kind() {
107 ty::Int(IntTy::Isize) => match self.tcx.sess.target.pointer_width {
10816 => self.tcx.types.i16,
10932 => self.tcx.types.i32,
11064 => self.tcx.types.i64,
111128 => self.tcx.types.i128,
112_ => ::rustc_middle::util::bug::bug_fmt(format_args!("fold_ty: unexpected pointer width `{0}`",
self.tcx.sess.target.pointer_width))bug!(
113"fold_ty: unexpected pointer width `{}`",
114self.tcx.sess.target.pointer_width
115 ),
116 },
117 ty::Uint(UintTy::Usize) => match self.tcx.sess.target.pointer_width {
11816 => self.tcx.types.u16,
11932 => self.tcx.types.u32,
12064 => self.tcx.types.u64,
121128 => self.tcx.types.u128,
122_ => ::rustc_middle::util::bug::bug_fmt(format_args!("fold_ty: unexpected pointer width `{0}`",
self.tcx.sess.target.pointer_width))bug!(
123"fold_ty: unexpected pointer width `{}`",
124self.tcx.sess.target.pointer_width
125 ),
126 },
127_ => t,
128 }
129 } else {
130t131 }
132 }
133134 ty::Adt(..) if t.is_c_void(self.tcx) => self.tcx.types.unit,
135136 ty::Adt(adt_def, args) => {
137if adt_def.repr().transparent() && adt_def.is_struct() && !self.parents.contains(&t)
138 {
139// Don't transform repr(transparent) types with an user-defined CFI encoding to
140 // preserve the user-defined CFI encoding.
141if {
{
'done:
{
for i in
::rustc_hir::attrs::HasAttrs::get_attrs(adt_def.did(),
&self.tcx) {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(CfiEncoding { .. }) => {
break 'done Some(());
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(self.tcx, adt_def.did(), CfiEncoding { .. }) {
142return t;
143 }
144let variant = adt_def.non_enum_variant();
145let typing_env = ty::TypingEnv::post_analysis(self.tcx, variant.def_id);
146let field = variant.fields.iter().find(|field| {
147let ty = self.tcx.type_of(field.did).instantiate_identity().skip_norm_wip();
148let is_zst = self149 .tcx
150 .layout_of(typing_env.as_query_input(ty))
151 .is_ok_and(|layout| layout.is_zst());
152 !is_zst153 });
154if let Some(field) = field {
155let ty0 = self.tcx.normalize_erasing_regions(
156 ty::TypingEnv::fully_monomorphized(),
157field.ty(self.tcx, args),
158 );
159// Generalize any repr(transparent) user-defined type that is either a
160 // pointer or reference, and either references itself or any other type that
161 // contains or references itself, to avoid a reference cycle.
162163 // If the self reference is not through a pointer, for example, due
164 // to using `PhantomData`, need to skip normalizing it if we hit it again.
165self.parents.push(t);
166let ty = if ty0.is_any_ptr() && ty0.contains(t) {
167let options = self.options;
168self.options |= TransformTyOptions::GENERALIZE_POINTERS;
169let ty = ty0.fold_with(self);
170self.options = options;
171ty172 } else {
173ty0.fold_with(self)
174 };
175self.parents.pop();
176ty177 } else {
178// Transform repr(transparent) types without non-ZST field into ()
179self.tcx.types.unit
180 }
181 } else {
182t.super_fold_with(self)
183 }
184 }
185186 ty::Ref(..) => {
187if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
188if t.is_mutable_ptr() {
189Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
190 } else {
191Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
192 }
193 } else {
194t.super_fold_with(self)
195 }
196 }
197198 ty::RawPtr(..) => {
199if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
200if t.is_mutable_ptr() {
201Ty::new_mut_ptr(self.tcx, self.tcx.types.unit)
202 } else {
203Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
204 }
205 } else {
206t.super_fold_with(self)
207 }
208 }
209210 ty::FnPtr(..) => {
211if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
212Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
213 } else {
214t.super_fold_with(self)
215 }
216 }
217218 ty::Alias(..) => self.fold_ty(self.tcx.normalize_erasing_regions(
219 ty::TypingEnv::fully_monomorphized(),
220Unnormalized::new_wip(t),
221 )),
222223 ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
224::rustc_middle::util::bug::bug_fmt(format_args!("fold_ty: unexpected `{0:?}`",
t.kind()));bug!("fold_ty: unexpected `{:?}`", t.kind());
225 }
226 }
227 }
228229fn cx(&self) -> TyCtxt<'tcx> {
230self.tcx
231 }
232}
233234x;#[instrument(skip(tcx), ret)]235fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> {
236assert!(!poly_trait_ref.has_non_region_param());
237let principal_pred = poly_trait_ref.map_bound(|trait_ref| {
238 ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref))
239 });
240let mut assoc_preds: Vec<_> = traits::supertraits(tcx, poly_trait_ref)
241 .flat_map(|super_poly_trait_ref| {
242 tcx.associated_items(super_poly_trait_ref.def_id())
243 .in_definition_order()
244 .filter(|item| item.is_type() || item.is_type_const())
245 .filter(|item| !tcx.generics_require_sized_self(item.def_id))
246 .map(move |assoc_item| {
247 super_poly_trait_ref.map_bound(|super_trait_ref| {
248let projection_term = ty::AliasTerm::new_from_def_id(
249 tcx,
250 assoc_item.def_id,
251 super_trait_ref.args,
252 );
253let term = tcx.normalize_erasing_regions(
254 ty::TypingEnv::fully_monomorphized(),
255 Unnormalized::new_wip(projection_term.to_term(tcx, ty::IsRigid::No)),
256 );
257debug!(
258"Projection {:?} -> {term}",
259 projection_term.to_term(tcx, ty::IsRigid::No)
260 );
261 ty::ExistentialPredicate::Projection(
262 ty::ExistentialProjection::erase_self_ty(
263 tcx,
264 ty::ProjectionPredicate { projection_term, term },
265 ),
266 )
267 })
268 })
269 })
270 .collect();
271 assoc_preds.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
272let preds = tcx.mk_poly_existential_predicates_from_iter(
273 iter::once(principal_pred).chain(assoc_preds.into_iter()),
274 );
275 Ty::new_dynamic(tcx, preds, tcx.lifetimes.re_erased)
276}
277278/// Transforms an instance for LLVM CFI and cross-language LLVM CFI support using Itanium C++ ABI
279/// mangling.
280///
281/// typeid_for_instance is called at two locations, initially when declaring/defining functions and
282/// methods, and later during code generation at call sites, after type erasure might have occurred.
283///
284/// In the first call (i.e., when declaring/defining functions and methods), it encodes type ids for
285/// an FnAbi or Instance, and these type ids are attached to functions and methods. (These type ids
286/// are used later by the LowerTypeTests LLVM pass to aggregate functions in groups derived from
287/// these type ids.)
288///
289/// In the second call (i.e., during code generation at call sites), it encodes a type id for an
290/// FnAbi or Instance, after type erasure might have occurred, and this type id is used for testing
291/// if a function is member of the group derived from this type id. Therefore, in the first call to
292/// typeid_for_fnabi (when type ids are attached to functions and methods), it can only include at
293/// most as much information that would be available in the second call (i.e., during code
294/// generation at call sites); otherwise, the type ids would not match.
295///
296/// For this, it:
297///
298/// * Adjust the type ids of DropGlues (see below).
299/// * Adjusts the type ids of VTableShims to the type id expected in the call sites for the
300/// entry in the vtable (i.e., by using the signature of the closure passed as an argument to the
301/// shim, or by just removing self).
302/// * Performs type erasure for calls on trait objects by transforming self into a trait object of
303/// the trait that defines the method.
304/// * Performs type erasure for closures call methods by transforming self into a trait object of
305/// the Fn trait that defines the method (for being attached as a secondary type id).
306///
307#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("transform_instance",
"rustc_sanitizers::cfi::typeid::itanium_cxx_abi::transform",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs"),
::tracing_core::__macro_support::Option::Some(307u32),
::tracing_core::__macro_support::Option::Some("rustc_sanitizers::cfi::typeid::itanium_cxx_abi::transform"),
::tracing_core::field::FieldSet::new(&["instance",
"options"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&instance)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&options)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Instance<'tcx> = loop {};
return __tracing_attr_fake_return;
}
{
if (#[allow(non_exhaustive_omitted_patterns)] match instance.def {
ty::InstanceKind::Virtual(..) => true,
_ => false,
} &&
tcx.is_lang_item(instance.def_id(), LangItem::DropGlue)) ||
#[allow(non_exhaustive_omitted_patterns)] match instance.def
{
ty::InstanceKind::Shim(ty::ShimKind::DropGlue(..)) => true,
_ => false,
} {
let def_id =
tcx.lang_items().drop_trait().unwrap_or_else(||
::rustc_middle::util::bug::bug_fmt(format_args!("typeid_for_instance: couldn\'t get drop_trait lang item")));
let predicate =
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new_from_args(tcx,
def_id, 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);
instance.args = tcx.mk_args_trait(self_ty, List::empty());
} else if let ty::InstanceKind::Virtual(def_id, _) = instance.def
{
let upcast_ty =
match tcx.trait_of_assoc(def_id) {
Some(trait_id) =>
trait_object_ty(tcx,
ty::Binder::dummy(ty::TraitRef::from_assoc(tcx, trait_id,
instance.args))),
None => instance.args.type_at(0),
};
let ty::Dynamic(preds, lifetime) =
upcast_ty.kind() else {
::rustc_middle::util::bug::bug_fmt(format_args!("Tried to remove autotraits from non-dynamic type {0}",
upcast_ty));
};
let self_ty =
if preds.principal().is_some() {
let filtered_preds =
tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred|
{
!#[allow(non_exhaustive_omitted_patterns)] match pred.skip_binder()
{
ty::ExistentialPredicate::AutoTrait(..) => true,
_ => false,
}
}));
Ty::new_dynamic(tcx, filtered_preds, *lifetime)
} else { tcx.types.unit };
instance.args =
tcx.mk_args_trait(self_ty,
instance.args.into_iter().skip(1));
} else if let ty::InstanceKind::Shim(ty::ShimKind::VTable(def_id))
= instance.def &&
let Some(trait_id) = tcx.trait_of_assoc(def_id) {
let trait_ref =
ty::TraitRef::new_from_args(tcx, trait_id, instance.args);
let invoke_ty =
trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
instance.args =
tcx.mk_args_trait(invoke_ty,
trait_ref.args.into_iter().skip(1));
}
if !options.contains(TransformTyOptions::USE_CONCRETE_SELF) {
if let Some((trait_ref, method_id, ancestor)) =
implemented_method(tcx, instance) {
let trait_ref =
tcx.instantiate_and_normalize_erasing_regions(instance.args,
ty::TypingEnv::fully_monomorphized(), trait_ref);
let invoke_ty =
trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
instance.def = ty::InstanceKind::Virtual(method_id, 0);
let abstract_trait_args =
tcx.mk_args_trait(invoke_ty,
trait_ref.args.into_iter().skip(1));
instance.args =
instance.args.rebase_onto(tcx, ancestor,
abstract_trait_args);
} else if tcx.is_closure_like(instance.def_id()) {
let closure_ty =
instance.ty(tcx, ty::TypingEnv::fully_monomorphized());
let (trait_id, inputs) =
match closure_ty.kind() {
ty::Closure(..) => {
let closure_args = instance.args.as_closure();
let trait_id =
tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap();
let tuple_args =
tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0];
(trait_id, Some(tuple_args))
}
ty::Coroutine(..) =>
match tcx.coroutine_kind(instance.def_id()).unwrap() {
hir::CoroutineKind::Coroutine(..) =>
(tcx.require_lang_item(LangItem::Coroutine, DUMMY_SP),
Some(instance.args.as_coroutine().resume_ty())),
hir::CoroutineKind::Desugared(desugaring, _) => {
let lang_item =
match desugaring {
hir::CoroutineDesugaring::Async => LangItem::Future,
hir::CoroutineDesugaring::AsyncGen =>
LangItem::AsyncIterator,
hir::CoroutineDesugaring::Gen => LangItem::Iterator,
};
(tcx.require_lang_item(lang_item, DUMMY_SP), None)
}
},
ty::CoroutineClosure(..) =>
(tcx.require_lang_item(LangItem::FnOnce, DUMMY_SP),
Some(tcx.instantiate_bound_regions_with_erased(instance.args.as_coroutine_closure().coroutine_closure_sig()).tupled_inputs_ty)),
x =>
::rustc_middle::util::bug::bug_fmt(format_args!("Unexpected type kind for closure-like: {0:?}",
x)),
};
let concrete_args =
tcx.mk_args_trait(closure_ty, inputs.map(Into::into));
let trait_ref =
ty::TraitRef::new_from_args(tcx, trait_id, concrete_args);
let invoke_ty =
trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
let abstract_args =
tcx.mk_args_trait(invoke_ty,
trait_ref.args.into_iter().skip(1));
let call =
tcx.associated_items(trait_id).in_definition_order().find(|it|
it.is_fn()).expect("No call-family function on closure-like Fn trait?").def_id;
instance.def = ty::InstanceKind::Virtual(call, 0);
instance.args = abstract_args;
}
}
instance
}
}
}#[instrument(level = "trace", skip(tcx))]308pub(crate) fn transform_instance<'tcx>(
309 tcx: TyCtxt<'tcx>,
310mut instance: Instance<'tcx>,
311 options: TransformTyOptions,
312) -> Instance<'tcx> {
313// FIXME: account for async-drop-glue
314if (matches!(instance.def, ty::InstanceKind::Virtual(..))
315 && tcx.is_lang_item(instance.def_id(), LangItem::DropGlue))
316 || matches!(instance.def, ty::InstanceKind::Shim(ty::ShimKind::DropGlue(..)))
317 {
318// Adjust the type ids of DropGlues
319 //
320 // DropGlues may have indirect calls to one or more given types drop function. Rust allows
321 // for types to be erased to any trait object and retains the drop function for the original
322 // type, which means at the indirect call sites in DropGlues, when typeid_for_fnabi is
323 // called a second time, it only has information after type erasure and it could be a call
324 // on any arbitrary trait object. Normalize them to a synthesized Drop trait object, both on
325 // declaration/definition, and during code generation at call sites so they have the same
326 // type id and match.
327 //
328 // FIXME(rcvalle): This allows a drop call on any trait object to call the drop function of
329 // any other type.
330 //
331let def_id = tcx
332 .lang_items()
333 .drop_trait()
334 .unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item"));
335let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new_from_args(
336 tcx,
337 def_id,
338 ty::List::empty(),
339 ));
340let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
341let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased);
342 instance.args = tcx.mk_args_trait(self_ty, List::empty());
343 } else if let ty::InstanceKind::Virtual(def_id, _) = instance.def {
344// Transform self into a trait object of the trait that defines the method for virtual
345 // functions to match the type erasure done below.
346let upcast_ty = match tcx.trait_of_assoc(def_id) {
347Some(trait_id) => trait_object_ty(
348 tcx,
349 ty::Binder::dummy(ty::TraitRef::from_assoc(tcx, trait_id, instance.args)),
350 ),
351// drop_in_place won't have a defining trait, skip the upcast
352None => instance.args.type_at(0),
353 };
354let ty::Dynamic(preds, lifetime) = upcast_ty.kind() else {
355bug!("Tried to remove autotraits from non-dynamic type {upcast_ty}");
356 };
357let self_ty = if preds.principal().is_some() {
358let filtered_preds =
359 tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
360 !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
361 }));
362 Ty::new_dynamic(tcx, filtered_preds, *lifetime)
363 } else {
364// If there's no principal type, re-encode it as a unit, since we don't know anything
365 // about it. This technically discards the knowledge that it was a type that was made
366 // into a trait object at some point, but that's not a lot.
367tcx.types.unit
368 };
369 instance.args = tcx.mk_args_trait(self_ty, instance.args.into_iter().skip(1));
370 } else if let ty::InstanceKind::Shim(ty::ShimKind::VTable(def_id)) = instance.def
371 && let Some(trait_id) = tcx.trait_of_assoc(def_id)
372 {
373// Adjust the type ids of VTableShims to the type id expected in the call sites for the
374 // entry in the vtable (i.e., by using the signature of the closure passed as an argument
375 // to the shim, or by just removing self).
376let trait_ref = ty::TraitRef::new_from_args(tcx, trait_id, instance.args);
377let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
378 instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
379 }
380381if !options.contains(TransformTyOptions::USE_CONCRETE_SELF) {
382// Perform type erasure for calls on trait objects by transforming self into a trait object
383 // of the trait that defines the method.
384if let Some((trait_ref, method_id, ancestor)) = implemented_method(tcx, instance) {
385// Trait methods will have a Self polymorphic parameter, where the concreteized
386 // implementation will not. We need to walk back to the more general trait method
387let trait_ref = tcx.instantiate_and_normalize_erasing_regions(
388 instance.args,
389 ty::TypingEnv::fully_monomorphized(),
390 trait_ref,
391 );
392let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
393394// At the call site, any call to this concrete function through a vtable will be
395 // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the
396 // original method id, and we've recovered the trait arguments, we can make the callee
397 // instance we're computing the alias set for match the caller instance.
398 //
399 // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder.
400 // If we ever *do* start encoding the vtable index, we will need to generate an alias set
401 // based on which vtables we are putting this method into, as there will be more than one
402 // index value when supertraits are involved.
403instance.def = ty::InstanceKind::Virtual(method_id, 0);
404let abstract_trait_args =
405 tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
406 instance.args = instance.args.rebase_onto(tcx, ancestor, abstract_trait_args);
407 } else if tcx.is_closure_like(instance.def_id()) {
408// We're either a closure or a coroutine. Our goal is to find the trait we're defined on,
409 // instantiate it, and take the type of its only method as our own.
410let closure_ty = instance.ty(tcx, ty::TypingEnv::fully_monomorphized());
411let (trait_id, inputs) = match closure_ty.kind() {
412 ty::Closure(..) => {
413let closure_args = instance.args.as_closure();
414let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap();
415let tuple_args =
416 tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0];
417 (trait_id, Some(tuple_args))
418 }
419 ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() {
420 hir::CoroutineKind::Coroutine(..) => (
421 tcx.require_lang_item(LangItem::Coroutine, DUMMY_SP),
422Some(instance.args.as_coroutine().resume_ty()),
423 ),
424 hir::CoroutineKind::Desugared(desugaring, _) => {
425let lang_item = match desugaring {
426 hir::CoroutineDesugaring::Async => LangItem::Future,
427 hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator,
428 hir::CoroutineDesugaring::Gen => LangItem::Iterator,
429 };
430 (tcx.require_lang_item(lang_item, DUMMY_SP), None)
431 }
432 },
433 ty::CoroutineClosure(..) => (
434 tcx.require_lang_item(LangItem::FnOnce, DUMMY_SP),
435Some(
436 tcx.instantiate_bound_regions_with_erased(
437 instance.args.as_coroutine_closure().coroutine_closure_sig(),
438 )
439 .tupled_inputs_ty,
440 ),
441 ),
442 x => bug!("Unexpected type kind for closure-like: {x:?}"),
443 };
444let concrete_args = tcx.mk_args_trait(closure_ty, inputs.map(Into::into));
445let trait_ref = ty::TraitRef::new_from_args(tcx, trait_id, concrete_args);
446let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
447let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
448// There should be exactly one method on this trait, and it should be the one we're
449 // defining.
450let call = tcx
451 .associated_items(trait_id)
452 .in_definition_order()
453 .find(|it| it.is_fn())
454 .expect("No call-family function on closure-like Fn trait?")
455 .def_id;
456457 instance.def = ty::InstanceKind::Virtual(call, 0);
458 instance.args = abstract_args;
459 }
460 }
461462 instance
463}
464465fn default_or_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Option<DefId> {
466match instance.def {
467 ty::InstanceKind::Item(def_id) | ty::InstanceKind::Shim(ty::ShimKind::FnPtr(def_id, _)) => {
468tcx.opt_associated_item(def_id).map(|item| item.def_id)
469 }
470_ => None,
471 }
472}
473474/// Determines if an instance represents a trait method implementation and returns the necessary
475/// information for type erasure.
476///
477/// This function handles two main cases:
478///
479/// * **Implementation in an `impl` block**: When the instance represents a concrete implementation
480/// of a trait method in an `impl` block, it extracts the trait reference, method ID, and trait
481/// ID from the implementation. The method ID is obtained from the `trait_item_def_id` field of
482/// the associated item, which points to the original trait method definition.
483///
484/// * **Provided method in a `trait` block or synthetic `shim`**: When the instance represents a
485/// default implementation provided in the trait definition itself or a synthetic shim, it uses
486/// the instance's own `def_id` as the method ID and determines the trait ID from the associated
487/// item.
488///
489fn implemented_method<'tcx>(
490 tcx: TyCtxt<'tcx>,
491 instance: Instance<'tcx>,
492) -> Option<(ty::EarlyBinder<'tcx, TraitRef<'tcx>>, DefId, DefId)> {
493let trait_ref;
494let method_id;
495let trait_id;
496let trait_method;
497let assoc = tcx.opt_associated_item(instance.def_id())?;
498let ancestor = if let AssocContainer::TraitImpl(Ok(trait_method_id)) = assoc.container {
499let impl_id = tcx.parent(instance.def_id());
500trait_ref = tcx.impl_trait_ref(impl_id);
501method_id = trait_method_id;
502trait_method = tcx.associated_item(method_id);
503trait_id = trait_ref.skip_binder().def_id;
504impl_id505 } else if let AssocContainer::Trait = assoc.container
506 && let Some(trait_method_def_id) = default_or_shim(tcx, instance)
507 {
508// Provided method in a `trait` block or a synthetic `shim`
509trait_method = assoc;
510method_id = trait_method_def_id;
511trait_id = tcx.parent(method_id);
512trait_ref = ty::EarlyBinder::bind(tcx, TraitRef::from_assoc(tcx, trait_id, instance.args));
513trait_id514 } else {
515return None;
516 };
517let vtable_possible = traits::is_vtable_safe_method(tcx, trait_id, trait_method)
518 && tcx.is_dyn_compatible(trait_id);
519vtable_possible.then_some((trait_ref, method_id, ancestor))
520}