1use rustc_abi::{Align, Size};
2use rustc_middle::mir::interpret::{InterpResult, Pointer};
3use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt, Ty, TyCtxt, VtblEntry};
4use tracing::trace;
56use super::util::ensure_monomorphic_enough;
7use super::{
8InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable, interp_ok, throw_ub,
9};
1011impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
12/// Creates a dynamic vtable for the given type and vtable origin. This is used only for
13 /// objects.
14 ///
15 /// The `dyn_ty` encodes the erased self type. Hence, if we are making an object
16 /// `Foo<dyn Trait<Assoc = A> + Send>` from a value of type `Foo<T>`, then `dyn_ty`
17 /// would be `Trait<Assoc = A> + Send`. If this list doesn't have a principal trait ref,
18 /// we only need the basic vtable prefix (drop, size, align).
19pub fn get_vtable_ptr(
20&self,
21 ty: Ty<'tcx>,
22 dyn_ty: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
23 ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
24{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_const_eval/src/interpret/traits.rs:24",
"rustc_const_eval::interpret::traits",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/interpret/traits.rs"),
::tracing_core::__macro_support::Option::Some(24u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::traits"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("get_vtable(ty={0:?}, dyn_ty={1:?})",
ty, dyn_ty) as &dyn Value))])
});
} else { ; }
};trace!("get_vtable(ty={ty:?}, dyn_ty={dyn_ty:?})");
2526let (ty, dyn_ty) = self.tcx.erase_and_anonymize_regions((ty, dyn_ty));
2728// All vtables must be monomorphic, bail out otherwise.
29ensure_monomorphic_enough(*self.tcx, ty)?;
30ensure_monomorphic_enough(*self.tcx, dyn_ty)?;
3132let salt = M::get_global_alloc_salt(self, None);
33let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, dyn_ty, salt);
34let vtable_ptr = self.global_root_pointer(Pointer::from(vtable_symbolic_allocation))?;
35interp_ok(vtable_ptr.into())
36 }
3738pub fn get_vtable_size_and_align(
39&self,
40 vtable: Pointer<Option<M::Provenance>>,
41 expected_trait: Option<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>,
42 ) -> InterpResult<'tcx, (Size, Align)> {
43let ty = self.get_ptr_vtable_ty(vtable, expected_trait)?;
44let layout = self.layout_of(ty)?;
45if !layout.is_sized() {
{
::core::panicking::panic_fmt(format_args!("there are no vtables for unsized types"));
}
};assert!(layout.is_sized(), "there are no vtables for unsized types");
46interp_ok((layout.size, layout.align.abi))
47 }
4849pub(super) fn vtable_entries(
50&self,
51 trait_: Option<ty::PolyExistentialTraitRef<'tcx>>,
52 dyn_ty: Ty<'tcx>,
53 ) -> &'tcx [VtblEntry<'tcx>] {
54if let Some(trait_) = trait_ {
55let trait_ref = trait_.with_self_ty(*self.tcx, dyn_ty);
56let trait_ref = self.tcx.erase_and_anonymize_regions(
57self.tcx.instantiate_bound_regions_with_erased(trait_ref),
58 );
59self.tcx.vtable_entries(trait_ref)
60 } else {
61TyCtxt::COMMON_VTABLE_ENTRIES62 }
63 }
6465/// Check that the given vtable trait is valid for a pointer/reference/place with the given
66 /// expected trait type.
67pub(super) fn check_vtable_for_type(
68&self,
69 vtable_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
70 expected_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
71 ) -> InterpResult<'tcx> {
72// We check validity by comparing the lists of predicates for equality. We *could* instead
73 // check that the dynamic type to which the vtable belongs satisfies all the expected
74 // predicates, but that would likely be a lot slower and seems unnecessarily permissive.
7576 // FIXME: we are skipping auto traits for now, but might revisit this in the future.
77let mut sorted_vtable: Vec<_> = vtable_dyn_type.without_auto_traits().collect();
78let mut sorted_expected: Vec<_> = expected_dyn_type.without_auto_traits().collect();
79// `skip_binder` here is okay because `stable_cmp` doesn't look at binders
80sorted_vtable.sort_by(|a, b| a.skip_binder().stable_cmp(*self.tcx, &b.skip_binder()));
81sorted_vtable.dedup();
82sorted_expected.sort_by(|a, b| a.skip_binder().stable_cmp(*self.tcx, &b.skip_binder()));
83sorted_expected.dedup();
8485if sorted_vtable.len() != sorted_expected.len() {
86do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::InvalidVTableTrait {
vtable_dyn_type,
expected_dyn_type,
});throw_ub!(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type });
87 }
8889// This checks whether there is a subtyping relation between the predicates in either direction.
90 // For example:
91 // - casting between `dyn for<'a> Trait<fn(&'a u8)>` and `dyn Trait<fn(&'static u8)>` is OK
92 // - casting between `dyn Trait<for<'a> fn(&'a u8)>` and either of the above is UB
93for (a_pred, b_pred) in std::iter::zip(sorted_vtable, sorted_expected) {
94let a_pred = self.tcx.normalize_erasing_late_bound_regions(self.typing_env, a_pred);
95let b_pred = self.tcx.normalize_erasing_late_bound_regions(self.typing_env, b_pred);
9697if a_pred != b_pred {
98do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::InvalidVTableTrait {
vtable_dyn_type,
expected_dyn_type,
});throw_ub!(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type });
99 }
100 }
101102interp_ok(())
103 }
104105/// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
106pub(super) fn unpack_dyn_trait(
107&self,
108 mplace: &MPlaceTy<'tcx, M::Provenance>,
109 expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
110 ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
111if !#[allow(non_exhaustive_omitted_patterns)] match mplace.layout.ty.kind() {
ty::Dynamic(_, _) => true,
_ => false,
} {
{
::core::panicking::panic_fmt(format_args!("`unpack_dyn_trait` only makes sense on `dyn*` types"));
}
};assert!(
112matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _)),
113"`unpack_dyn_trait` only makes sense on `dyn*` types"
114);
115let vtable = mplace.meta().unwrap_meta().to_pointer(self)?;
116let ty = self.get_ptr_vtable_ty(vtable, Some(expected_trait))?;
117// This is a kind of transmute, from a place with unsized type and metadata to
118 // a place with sized type and no metadata.
119let layout = self.layout_of(ty)?;
120let mplace = mplace.offset_with_meta(
121Size::ZERO,
122 OffsetMode::Wrapping,
123 MemPlaceMeta::None,
124layout,
125self,
126 )?;
127interp_ok(mplace)
128 }
129}