]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir/src/interpret/traits.rs
New upstream version 1.56.0+dfsg1
[rustc.git] / compiler / rustc_mir / src / interpret / traits.rs
CommitLineData
ba9703b0
XL
1use std::convert::TryFrom;
2
136023e0
XL
3use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic};
4use rustc_middle::ty::{
5 self, Ty, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN,
6 COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE,
7};
8use rustc_target::abi::{Align, Size};
60c5eb7d 9
3dfed10e 10use super::util::ensure_monomorphic_enough;
136023e0 11use super::{FnVal, InterpCx, Machine};
8faf50e0 12
ba9703b0 13impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ff7c6d11
XL
14 /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
15 /// objects.
16 ///
60c5eb7d 17 /// The `trait_ref` encodes the erased self type. Hence, if we are
ff7c6d11 18 /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
60c5eb7d 19 /// `trait_ref` would map `T: Trait`.
ff7c6d11
XL
20 pub fn get_vtable(
21 &mut self,
22 ty: Ty<'tcx>,
0731742a 23 poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
94222f64 24 ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
0bf4aa26
XL
25 trace!("get_vtable(trait_ref={:?})", poly_trait_ref);
26
fc512014 27 let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref));
0bf4aa26 28
e1599b0c 29 // All vtables must be monomorphic, bail out otherwise.
3dfed10e
XL
30 ensure_monomorphic_enough(*self.tcx, ty)?;
31 ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?;
e1599b0c 32
dc3f5686 33 let vtable_allocation = self.tcx.vtable_allocation((ty, poly_trait_ref));
dc9dc135 34
136023e0 35 let vtable_ptr = self.memory.global_base_pointer(Pointer::from(vtable_allocation))?;
17df50a5 36
94222f64 37 Ok(vtable_ptr.into())
ff7c6d11
XL
38 }
39
60c5eb7d 40 /// Resolves the function at the specified slot in the provided
136023e0
XL
41 /// vtable. Currently an index of '3' (`COMMON_VTABLE_ENTRIES.len()`)
42 /// corresponds to the first method declared in the trait of the provided vtable.
60c5eb7d
XL
43 pub fn get_vtable_slot(
44 &self,
136023e0 45 vtable: Pointer<Option<M::PointerTag>>,
ba9703b0 46 idx: u64,
60c5eb7d
XL
47 ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
48 let ptr_size = self.pointer_size();
136023e0 49 let vtable_slot = vtable.offset(ptr_size * idx, self)?;
dfeec247
XL
50 let vtable_slot = self
51 .memory
17df50a5 52 .get(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)?
dfeec247 53 .expect("cannot be a ZST");
136023e0 54 let fn_ptr = self.scalar_to_ptr(vtable_slot.read_ptr_sized(Size::ZERO)?.check_init()?);
6a06907d 55 self.memory.get_fn(fn_ptr)
60c5eb7d
XL
56 }
57
58 /// Returns the drop fn instance as well as the actual dynamic type.
ff7c6d11
XL
59 pub fn read_drop_type_from_vtable(
60 &self,
136023e0 61 vtable: Pointer<Option<M::PointerTag>>,
dc9dc135 62 ) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> {
136023e0 63 let pointer_size = self.pointer_size();
60c5eb7d 64 // We don't care about the pointee type; we just want a pointer.
dfeec247
XL
65 let vtable = self
66 .memory
136023e0
XL
67 .get(
68 vtable,
69 pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(),
70 self.tcx.data_layout.pointer_align.abi,
71 )?
dfeec247 72 .expect("cannot be a ZST");
136023e0
XL
73 let drop_fn = vtable
74 .read_ptr_sized(
75 pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap(),
76 )?
77 .check_init()?;
416331ca
XL
78 // We *need* an instance here, no other kind of function value, to be able
79 // to determine the type.
136023e0 80 let drop_instance = self.memory.get_fn(self.scalar_to_ptr(drop_fn))?.as_instance()?;
b7449926 81 trace!("Found drop fn: {:?}", drop_instance);
3dfed10e 82 let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx);
fc512014 83 let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig);
dc9dc135 84 // The drop function takes `*mut T` where `T` is the type being dropped, so get that.
60c5eb7d
XL
85 let args = fn_sig.inputs();
86 if args.len() != 1 {
136023e0 87 throw_ub!(InvalidVtableDropFn(fn_sig));
60c5eb7d 88 }
136023e0
XL
89 let ty =
90 args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidVtableDropFn(fn_sig)))?.ty;
b7449926 91 Ok((drop_instance, ty))
ff7c6d11
XL
92 }
93
94 pub fn read_size_and_align_from_vtable(
95 &self,
136023e0 96 vtable: Pointer<Option<M::PointerTag>>,
dc9dc135 97 ) -> InterpResult<'tcx, (Size, Align)> {
b7449926 98 let pointer_size = self.pointer_size();
60c5eb7d 99 // We check for `size = 3 * ptr_size`, which covers the drop fn (unused here),
dc9dc135 100 // the size, and the align (which we read below).
dfeec247
XL
101 let vtable = self
102 .memory
136023e0
XL
103 .get(
104 vtable,
105 pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(),
106 self.tcx.data_layout.pointer_align.abi,
107 )?
dfeec247 108 .expect("cannot be a ZST");
136023e0
XL
109 let size = vtable
110 .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap())?
111 .check_init()?;
112 let size = size.to_machine_usize(self)?;
113 let align = vtable
114 .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap())?
115 .check_init()?;
116 let align = align.to_machine_usize(self)?;
117 let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?;
e1599b0c 118
f035d41b 119 if size >= self.tcx.data_layout.obj_size_bound() {
136023e0 120 throw_ub!(InvalidVtableSize);
e1599b0c 121 }
17df50a5 122 Ok((Size::from_bytes(size), align))
ff7c6d11 123 }
94222f64
XL
124
125 pub fn read_new_vtable_after_trait_upcasting_from_vtable(
126 &self,
127 vtable: Pointer<Option<M::PointerTag>>,
128 idx: u64,
129 ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
130 let pointer_size = self.pointer_size();
131
132 let vtable_slot = vtable.offset(pointer_size * idx, self)?;
133 let new_vtable = self
134 .memory
135 .get(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)?
136 .expect("cannot be a ZST");
137
138 let new_vtable = self.scalar_to_ptr(new_vtable.read_ptr_sized(Size::ZERO)?.check_init()?);
139
140 Ok(new_vtable)
141 }
ff7c6d11 142}