1 use std
::convert
::TryFrom
;
3 use rustc_middle
::mir
::interpret
::{InterpResult, Pointer, PointerArithmetic}
;
4 use rustc_middle
::ty
::{
5 self, Ty
, TyCtxt
, COMMON_VTABLE_ENTRIES_ALIGN
, COMMON_VTABLE_ENTRIES_DROPINPLACE
,
6 COMMON_VTABLE_ENTRIES_SIZE
,
8 use rustc_target
::abi
::{Align, Size}
;
10 use super::util
::ensure_monomorphic_enough
;
11 use super::{FnVal, InterpCx, Machine}
;
13 impl<'mir
, 'tcx
: 'mir
, M
: Machine
<'mir
, 'tcx
>> InterpCx
<'mir
, 'tcx
, M
> {
14 /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
17 /// The `trait_ref` encodes the erased self type. Hence, if we are
18 /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
19 /// `trait_ref` would map `T: Trait`.
23 poly_trait_ref
: Option
<ty
::PolyExistentialTraitRef
<'tcx
>>,
24 ) -> InterpResult
<'tcx
, Pointer
<Option
<M
::PointerTag
>>> {
25 trace
!("get_vtable(trait_ref={:?})", poly_trait_ref
);
27 let (ty
, poly_trait_ref
) = self.tcx
.erase_regions((ty
, poly_trait_ref
));
29 // All vtables must be monomorphic, bail out otherwise.
30 ensure_monomorphic_enough(*self.tcx
, ty
)?
;
31 ensure_monomorphic_enough(*self.tcx
, poly_trait_ref
)?
;
33 let vtable_allocation
= self.tcx
.vtable_allocation((ty
, poly_trait_ref
));
35 let vtable_ptr
= self.global_base_pointer(Pointer
::from(vtable_allocation
))?
;
40 /// Resolves the function at the specified slot in the provided
41 /// vtable. Currently an index of '3' (`TyCtxt::COMMON_VTABLE_ENTRIES.len()`)
42 /// corresponds to the first method declared in the trait of the provided vtable.
43 pub fn get_vtable_slot(
45 vtable
: Pointer
<Option
<M
::PointerTag
>>,
47 ) -> InterpResult
<'tcx
, FnVal
<'tcx
, M
::ExtraFnVal
>> {
48 let ptr_size
= self.pointer_size();
49 let vtable_slot
= vtable
.offset(ptr_size
* idx
, self)?
;
50 let vtable_slot
= self
51 .get_ptr_alloc(vtable_slot
, ptr_size
, self.tcx
.data_layout
.pointer_align
.abi
)?
52 .expect("cannot be a ZST");
53 let fn_ptr
= self.scalar_to_ptr(vtable_slot
.read_pointer(Size
::ZERO
)?
.check_init()?
)?
;
54 self.get_ptr_fn(fn_ptr
)
57 /// Returns the drop fn instance as well as the actual dynamic type.
58 pub fn read_drop_type_from_vtable(
60 vtable
: Pointer
<Option
<M
::PointerTag
>>,
61 ) -> InterpResult
<'tcx
, (ty
::Instance
<'tcx
>, Ty
<'tcx
>)> {
62 let pointer_size
= self.pointer_size();
63 // We don't care about the pointee type; we just want a pointer.
67 pointer_size
* u64::try_from(TyCtxt
::COMMON_VTABLE_ENTRIES
.len()).unwrap(),
68 self.tcx
.data_layout
.pointer_align
.abi
,
70 .expect("cannot be a ZST");
72 .read_pointer(pointer_size
* u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE
).unwrap())?
74 // We *need* an instance here, no other kind of function value, to be able
75 // to determine the type.
76 let drop_instance
= self.get_ptr_fn(self.scalar_to_ptr(drop_fn
)?
)?
.as_instance()?
;
77 trace
!("Found drop fn: {:?}", drop_instance
);
78 let fn_sig
= drop_instance
.ty(*self.tcx
, self.param_env
).fn_sig(*self.tcx
);
79 let fn_sig
= self.tcx
.normalize_erasing_late_bound_regions(self.param_env
, fn_sig
);
80 // The drop function takes `*mut T` where `T` is the type being dropped, so get that.
81 let args
= fn_sig
.inputs();
83 throw_ub
!(InvalidVtableDropFn(fn_sig
));
86 args
[0].builtin_deref(true).ok_or_else(|| err_ub
!(InvalidVtableDropFn(fn_sig
)))?
.ty
;
87 Ok((drop_instance
, ty
))
90 pub fn read_size_and_align_from_vtable(
92 vtable
: Pointer
<Option
<M
::PointerTag
>>,
93 ) -> InterpResult
<'tcx
, (Size
, Align
)> {
94 let pointer_size
= self.pointer_size();
95 // We check for `size = 3 * ptr_size`, which covers the drop fn (unused here),
96 // the size, and the align (which we read below).
100 pointer_size
* u64::try_from(TyCtxt
::COMMON_VTABLE_ENTRIES
.len()).unwrap(),
101 self.tcx
.data_layout
.pointer_align
.abi
,
103 .expect("cannot be a ZST");
106 pointer_size
* u64::try_from(COMMON_VTABLE_ENTRIES_SIZE
).unwrap(),
110 let size
= size
.to_machine_usize(self)?
;
111 let size
= Size
::from_bytes(size
);
114 pointer_size
* u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN
).unwrap(),
118 let align
= align
.to_machine_usize(self)?
;
119 let align
= Align
::from_bytes(align
).map_err(|e
| err_ub
!(InvalidVtableAlignment(e
)))?
;
121 if size
> self.max_size_of_val() {
122 throw_ub
!(InvalidVtableSize
);
127 pub fn read_new_vtable_after_trait_upcasting_from_vtable(
129 vtable
: Pointer
<Option
<M
::PointerTag
>>,
131 ) -> InterpResult
<'tcx
, Pointer
<Option
<M
::PointerTag
>>> {
132 let pointer_size
= self.pointer_size();
134 let vtable_slot
= vtable
.offset(pointer_size
* idx
, self)?
;
135 let new_vtable
= self
136 .get_ptr_alloc(vtable_slot
, pointer_size
, self.tcx
.data_layout
.pointer_align
.abi
)?
137 .expect("cannot be a ZST");
139 let new_vtable
= self.scalar_to_ptr(new_vtable
.read_pointer(Size
::ZERO
)?
.check_init()?
)?
;