rustc_const_eval/interpret/
traits.rs1use rustc_abi::{Align, Size};
2use rustc_middle::mir::interpret::{InterpResult, Pointer};
3use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt, Ty, TyCtxt, VtblEntry};
4use tracing::trace;
5
6use super::util::ensure_monomorphic_enough;
7use super::{
8    InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable, interp_ok, throw_ub,
9};
10
11impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
12    pub 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        trace!("get_vtable(ty={ty:?}, dyn_ty={dyn_ty:?})");
25
26        let (ty, dyn_ty) = self.tcx.erase_regions((ty, dyn_ty));
27
28        ensure_monomorphic_enough(*self.tcx, ty)?;
30        ensure_monomorphic_enough(*self.tcx, dyn_ty)?;
31
32        let salt = M::get_global_alloc_salt(self, None);
33        let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, dyn_ty, salt);
34        let vtable_ptr = self.global_root_pointer(Pointer::from(vtable_symbolic_allocation))?;
35        interp_ok(vtable_ptr.into())
36    }
37
38    pub 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)> {
43        let ty = self.get_ptr_vtable_ty(vtable, expected_trait)?;
44        let layout = self.layout_of(ty)?;
45        assert!(layout.is_sized(), "there are no vtables for unsized types");
46        interp_ok((layout.size, layout.align.abi))
47    }
48
49    pub(super) fn vtable_entries(
50        &self,
51        trait_: Option<ty::PolyExistentialTraitRef<'tcx>>,
52        dyn_ty: Ty<'tcx>,
53    ) -> &'tcx [VtblEntry<'tcx>] {
54        if let Some(trait_) = trait_ {
55            let trait_ref = trait_.with_self_ty(*self.tcx, dyn_ty);
56            let trait_ref =
57                self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
58            self.tcx.vtable_entries(trait_ref)
59        } else {
60            TyCtxt::COMMON_VTABLE_ENTRIES
61        }
62    }
63
64    pub(super) fn check_vtable_for_type(
67        &self,
68        vtable_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
69        expected_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
70    ) -> InterpResult<'tcx> {
71        let mut sorted_vtable: Vec<_> = vtable_dyn_type.without_auto_traits().collect();
77        let mut sorted_expected: Vec<_> = expected_dyn_type.without_auto_traits().collect();
78        sorted_vtable.sort_by(|a, b| a.skip_binder().stable_cmp(*self.tcx, &b.skip_binder()));
80        sorted_vtable.dedup();
81        sorted_expected.sort_by(|a, b| a.skip_binder().stable_cmp(*self.tcx, &b.skip_binder()));
82        sorted_expected.dedup();
83
84        if sorted_vtable.len() != sorted_expected.len() {
85            throw_ub!(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type });
86        }
87
88        for (a_pred, b_pred) in std::iter::zip(sorted_vtable, sorted_expected) {
93            let a_pred = self.tcx.normalize_erasing_late_bound_regions(self.typing_env, a_pred);
94            let b_pred = self.tcx.normalize_erasing_late_bound_regions(self.typing_env, b_pred);
95
96            if a_pred != b_pred {
97                throw_ub!(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type });
98            }
99        }
100
101        interp_ok(())
102    }
103
104    pub(super) fn unpack_dyn_trait(
106        &self,
107        mplace: &MPlaceTy<'tcx, M::Provenance>,
108        expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
109    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
110        assert!(
111            matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)),
112            "`unpack_dyn_trait` only makes sense on `dyn*` types"
113        );
114        let vtable = mplace.meta().unwrap_meta().to_pointer(self)?;
115        let ty = self.get_ptr_vtable_ty(vtable, Some(expected_trait))?;
116        let layout = self.layout_of(ty)?;
119        let mplace = mplace.offset_with_meta(
120            Size::ZERO,
121            OffsetMode::Wrapping,
122            MemPlaceMeta::None,
123            layout,
124            self,
125        )?;
126        interp_ok(mplace)
127    }
128}