diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_codegen_cranelift/src/unsize.rs | 63 | ||||
| -rw-r--r-- | compiler/rustc_codegen_cranelift/src/vtable.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/base.rs | 107 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 27 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/query/mod.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/interpret/cast.rs | 32 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/interpret/operand.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/interpret/traits.rs | 22 | ||||
| -rw-r--r-- | compiler/rustc_query_impl/src/keys.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/mod.rs | 16 |
10 files changed, 211 insertions, 93 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index b9d379c6117..d594731b4df 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -25,39 +25,73 @@ pub(crate) fn unsized_info<'tcx>( .bcx .ins() .iconst(fx.pointer_type, len.eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64), - (&ty::Dynamic(..), &ty::Dynamic(..)) => { - // For now, upcasts are limited to changes in marker - // traits, and hence never actually require an actual - // change to the vtable. - old_info.expect("unsized_info: missing old info for trait upcast") + (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { + let old_info = + old_info.expect("unsized_info: missing old info for trait upcasting coercion"); + if data_a.principal_def_id() == data_b.principal_def_id() { + return old_info; + } + // trait upcasting coercion + + // if both of the two `principal`s are `None`, this function would have returned early above. + // and if one of the two `principal`s is `None`, typechecking would have rejected this case. + let principal_a = data_a + .principal() + .expect("unsized_info: missing principal trait for trait upcasting coercion"); + let principal_b = data_b + .principal() + .expect("unsized_info: missing principal trait for trait upcasting coercion"); + + let vptr_entry_idx = fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot(( + principal_a.with_self_ty(fx.tcx, source), + principal_b.with_self_ty(fx.tcx, source), + )); + + if let Some(entry_idx) = vptr_entry_idx { + let entry_idx = u32::try_from(entry_idx).unwrap(); + let entry_offset = entry_idx * fx.pointer_type.bytes(); + let vptr_ptr = Pointer::new(old_info).offset_i64(fx, entry_offset.into()).load( + fx, + fx.pointer_type, + crate::vtable::vtable_memflags(), + ); + vptr_ptr + } else { + old_info + } } (_, &ty::Dynamic(ref data, ..)) => crate::vtable::get_vtable(fx, source, data.principal()), _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target), } } -/// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer. -fn unsize_thin_ptr<'tcx>( +/// Coerce `src` to `dst_ty`. +fn unsize_ptr<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, src: Value, src_layout: TyAndLayout<'tcx>, dst_layout: TyAndLayout<'tcx>, + old_info: Option<Value>, ) -> (Value, Value) { match (&src_layout.ty.kind(), &dst_layout.ty.kind()) { (&ty::Ref(_, a, _), &ty::Ref(_, b, _)) | (&ty::Ref(_, a, _), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => { assert!(!fx.layout_of(a).is_unsized()); - (src, unsized_info(fx, a, b, None)) + (src, unsized_info(fx, a, b, old_info)) } (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => { let (a, b) = (src_layout.ty.boxed_ty(), dst_layout.ty.boxed_ty()); assert!(!fx.layout_of(a).is_unsized()); - (src, unsized_info(fx, a, b, None)) + (src, unsized_info(fx, a, b, old_info)) } (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { assert_eq!(def_a, def_b); + if src_layout == dst_layout { + return (src, old_info.unwrap()); + } + let mut result = None; for i in 0..src_layout.fields.count() { let src_f = src_layout.field(fx, i); @@ -71,11 +105,11 @@ fn unsize_thin_ptr<'tcx>( let dst_f = dst_layout.field(fx, i); assert_ne!(src_f.ty, dst_f.ty); assert_eq!(result, None); - result = Some(unsize_thin_ptr(fx, src, src_f, dst_f)); + result = Some(unsize_ptr(fx, src, src_f, dst_f, old_info)); } result.unwrap() } - _ => bug!("unsize_thin_ptr: called on bad types"), + _ => bug!("unsize_ptr: called on bad types"), } } @@ -91,12 +125,11 @@ pub(crate) fn coerce_unsized_into<'tcx>( let mut coerce_ptr = || { let (base, info) = if fx.layout_of(src.layout().ty.builtin_deref(true).unwrap().ty).is_unsized() { - // fat-ptr to fat-ptr unsize preserves the vtable - // i.e., &'a fmt::Debug+Send => &'a fmt::Debug - src.load_scalar_pair(fx) + let (old_base, old_info) = src.load_scalar_pair(fx); + unsize_ptr(fx, old_base, src.layout(), dst.layout(), Some(old_info)) } else { let base = src.load_scalar(fx); - unsize_thin_ptr(fx, base, src.layout(), dst.layout()) + unsize_ptr(fx, base, src.layout(), dst.layout(), None) }; dst.write_cvalue(fx, CValue::by_val_pair(base, info, dst.layout())); }; diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 4a5f9f133a2..1b315874308 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -5,7 +5,7 @@ use crate::constant::data_id_for_alloc_id; use crate::prelude::*; -fn vtable_memflags() -> MemFlags { +pub(crate) fn vtable_memflags() -> MemFlags { let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap. flags.set_readonly(); // A vtable is always read-only. flags diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index be2bf8b1997..87b342e8443 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -23,7 +23,6 @@ use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::middle::lang_items; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; -use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::cgu_reuse_tracker::CguReuse; @@ -32,6 +31,7 @@ use rustc_session::Session; use rustc_span::symbol::sym; use rustc_target::abi::{Align, LayoutOf, VariantIdx}; +use std::convert::TryFrom; use std::ops::{Deref, DerefMut}; use std::time::{Duration, Instant}; @@ -128,55 +128,92 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( /// /// The `old_info` argument is a bit odd. It is intended for use in an upcast, /// where the new vtable for an object will be derived from the old one. -pub fn unsized_info<'tcx, Cx: CodegenMethods<'tcx>>( - cx: &Cx, +pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, source: Ty<'tcx>, target: Ty<'tcx>, - old_info: Option<Cx::Value>, -) -> Cx::Value { + old_info: Option<Bx::Value>, +) -> Bx::Value { + let cx = bx.cx(); let (source, target) = - cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, cx.param_env()); + cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, bx.param_env()); match (source.kind(), target.kind()) { (&ty::Array(_, len), &ty::Slice(_)) => { cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all())) } - (&ty::Dynamic(..), &ty::Dynamic(..)) => { - // For now, upcasts are limited to changes in marker - // traits, and hence never actually require an actual - // change to the vtable. - old_info.expect("unsized_info: missing old info for trait upcast") + (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { + let old_info = + old_info.expect("unsized_info: missing old info for trait upcasting coercion"); + if data_a.principal_def_id() == data_b.principal_def_id() { + return old_info; + } + + // trait upcasting coercion + + // if both of the two `principal`s are `None`, this function would have returned early above. + // and if one of the two `principal`s is `None`, typechecking would have rejected this case. + let principal_a = data_a + .principal() + .expect("unsized_info: missing principal trait for trait upcasting coercion"); + let principal_b = data_b + .principal() + .expect("unsized_info: missing principal trait for trait upcasting coercion"); + + let vptr_entry_idx = cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot(( + principal_a.with_self_ty(cx.tcx(), source), + principal_b.with_self_ty(cx.tcx(), source), + )); + + if let Some(entry_idx) = vptr_entry_idx { + let ptr_ty = cx.type_i8p(); + let ptr_align = cx.tcx().data_layout.pointer_align.abi; + let llvtable = bx.pointercast(old_info, bx.type_ptr_to(ptr_ty)); + let gep = + bx.inbounds_gep(llvtable, &[bx.const_usize(u64::try_from(entry_idx).unwrap())]); + let new_vptr = bx.load(ptr_ty, gep, ptr_align); + bx.nonnull_metadata(new_vptr); + // Vtable loads are invariant. + bx.set_invariant_load(new_vptr); + new_vptr + } else { + old_info + } } (_, &ty::Dynamic(ref data, ..)) => { - let vtable_ptr = cx.layout_of(cx.tcx().mk_mut_ptr(target)).field(cx, FAT_PTR_EXTRA); - cx.const_ptrcast( - meth::get_vtable(cx, source, data.principal()), - cx.backend_type(vtable_ptr), - ) + let vtable_ptr_ty = cx.scalar_pair_element_backend_type( + cx.layout_of(cx.tcx().mk_mut_ptr(target)), + 1, + true, + ); + cx.const_ptrcast(meth::get_vtable(cx, source, data.principal()), vtable_ptr_ty) } _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target), } } -/// Coerces `src` to `dst_ty`. `src_ty` must be a thin pointer. -pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( +/// Coerces `src` to `dst_ty`. `src_ty` must be a pointer. +pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, src: Bx::Value, src_ty: Ty<'tcx>, dst_ty: Ty<'tcx>, + old_info: Option<Bx::Value>, ) -> (Bx::Value, Bx::Value) { - debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty); + debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty); match (src_ty.kind(), dst_ty.kind()) { (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => { - assert!(bx.cx().type_is_sized(a)); + assert_eq!(bx.cx().type_is_sized(a), old_info.is_none()); let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(bx.cx().layout_of(b))); - (bx.pointercast(src, ptr_ty), unsized_info(bx.cx(), a, b, None)) + (bx.pointercast(src, ptr_ty), unsized_info(bx, a, b, old_info)) } (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { assert_eq!(def_a, def_b); - let src_layout = bx.cx().layout_of(src_ty); let dst_layout = bx.cx().layout_of(dst_ty); + if src_ty == dst_ty { + return (src, old_info.unwrap()); + } let mut result = None; for i in 0..src_layout.fields.count() { let src_f = src_layout.field(bx.cx(), i); @@ -190,18 +227,15 @@ pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let dst_f = dst_layout.field(bx.cx(), i); assert_ne!(src_f.ty, dst_f.ty); assert_eq!(result, None); - result = Some(unsize_thin_ptr(bx, src, src_f.ty, dst_f.ty)); + result = Some(unsize_ptr(bx, src, src_f.ty, dst_f.ty, old_info)); } let (lldata, llextra) = result.unwrap(); + let lldata_ty = bx.cx().scalar_pair_element_backend_type(dst_layout, 0, true); + let llextra_ty = bx.cx().scalar_pair_element_backend_type(dst_layout, 1, true); // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. - // FIXME(eddyb) move these out of this `match` arm, so they're always - // applied, uniformly, no matter the source/destination types. - ( - bx.bitcast(lldata, bx.cx().scalar_pair_element_backend_type(dst_layout, 0, true)), - bx.bitcast(llextra, bx.cx().scalar_pair_element_backend_type(dst_layout, 1, true)), - ) + (bx.bitcast(lldata, lldata_ty), bx.bitcast(llextra, llextra_ty)) } - _ => bug!("unsize_thin_ptr: called on bad types"), + _ => bug!("unsize_ptr: called on bad types"), } } @@ -217,17 +251,8 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( match (src_ty.kind(), dst_ty.kind()) { (&ty::Ref(..), &ty::Ref(..) | &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => { let (base, info) = match bx.load_operand(src).val { - OperandValue::Pair(base, info) => { - // fat-ptr to fat-ptr unsize preserves the vtable - // i.e., &'a fmt::Debug+Send => &'a fmt::Debug - // So we need to pointercast the base to ensure - // the types match up. - // FIXME(eddyb) use `scalar_pair_element_backend_type` here, - // like `unsize_thin_ptr` does. - let thin_ptr = dst.layout.field(bx.cx(), FAT_PTR_ADDR); - (bx.pointercast(base, bx.cx().backend_type(thin_ptr)), info) - } - OperandValue::Immediate(base) => unsize_thin_ptr(bx, base, src_ty, dst_ty), + OperandValue::Pair(base, info) => unsize_ptr(bx, base, src_ty, dst_ty, Some(info)), + OperandValue::Immediate(base) => unsize_ptr(bx, base, src_ty, dst_ty, None), OperandValue::Ref(..) => bug!(), }; OperandValue::Pair(base, info).store(bx, dst); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 530de3de9e8..7e1dfeb2457 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -220,34 +220,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::CastKind::Pointer(PointerCast::Unsize) => { assert!(bx.cx().is_backend_scalar_pair(cast)); - match operand.val { + let (lldata, llextra) = match operand.val { OperandValue::Pair(lldata, llextra) => { // unsize from a fat pointer -- this is a - // "trait-object-to-supertrait" coercion, for - // example, `&'a fmt::Debug + Send => &'a fmt::Debug`. - - // HACK(eddyb) have to bitcast pointers - // until LLVM removes pointee types. - let lldata = bx.pointercast( - lldata, - bx.cx().scalar_pair_element_backend_type(cast, 0, true), - ); - OperandValue::Pair(lldata, llextra) + // "trait-object-to-supertrait" coercion. + (lldata, Some(llextra)) } OperandValue::Immediate(lldata) => { // "standard" unsize - let (lldata, llextra) = base::unsize_thin_ptr( - &mut bx, - lldata, - operand.layout.ty, - cast.ty, - ); - OperandValue::Pair(lldata, llextra) + (lldata, None) } OperandValue::Ref(..) => { bug!("by-ref operand {:?} in `codegen_rvalue_operand`", operand); } - } + }; + let (lldata, llextra) = + base::unsize_ptr(&mut bx, lldata, operand.layout.ty, cast.ty, llextra); + OperandValue::Pair(lldata, llextra) } mir::CastKind::Pointer(PointerCast::MutToConstPointer) | mir::CastKind::Misc diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 2de836c058c..3c16852df05 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -977,6 +977,11 @@ rustc_queries! { desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) } } + query vtable_trait_upcasting_coercion_new_vptr_slot(key: (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>)) -> Option<usize> { + desc { |tcx| "finding the slot within vtable for trait {} vtable ptr during trait upcasting coercion from {} vtable", + tcx.def_path_str(key.1.def_id()), tcx.def_path_str(key.0.def_id()) } + } + query codegen_fulfill_obligation( key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) ) -> Result<ImplSource<'tcx, ()>, ErrorReported> { diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs index 514c1aa9646..cee4c2e30aa 100644 --- a/compiler/rustc_mir/src/interpret/cast.rs +++ b/compiler/rustc_mir/src/interpret/cast.rs @@ -269,12 +269,34 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self); self.write_immediate(val, dest) } - (&ty::Dynamic(..), &ty::Dynamic(..)) => { - // For now, upcasts are limited to changes in marker - // traits, and hence never actually require an actual - // change to the vtable. + (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { let val = self.read_immediate(src)?; - self.write_immediate(*val, dest) + if data_a.principal_def_id() == data_b.principal_def_id() { + return self.write_immediate(*val, dest); + } + // trait upcasting coercion + let principal_a = data_a.principal().expect( + "unsize_into_ptr: missing principal trait for trait upcasting coercion", + ); + let principal_b = data_b.principal().expect( + "unsize_into_ptr: missing principal trait for trait upcasting coercion", + ); + + let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot(( + principal_a.with_self_ty(*self.tcx, src_pointee_ty), + principal_b.with_self_ty(*self.tcx, src_pointee_ty), + )); + + if let Some(entry_idx) = vptr_entry_idx { + let entry_idx = u64::try_from(entry_idx).unwrap(); + let (old_data, old_vptr) = val.to_scalar_pair()?; + let old_vptr = self.scalar_to_ptr(old_vptr); + let new_vptr = self + .read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?; + self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) + } else { + self.write_immediate(*val, dest) + } } (_, &ty::Dynamic(ref data, _)) => { // Initial cast from sized to dyn trait diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index aba7db78168..d5bc2b1e2ea 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -63,15 +63,19 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> { Immediate::ScalarPair(val.into(), Scalar::from_machine_usize(len, cx).into()) } - pub fn new_dyn_trait(val: Scalar<Tag>, vtable: Pointer<Tag>, cx: &impl HasDataLayout) -> Self { - Immediate::ScalarPair(val.into(), ScalarMaybeUninit::from_pointer(vtable, cx)) + pub fn new_dyn_trait( + val: Scalar<Tag>, + vtable: Pointer<Option<Tag>>, + cx: &impl HasDataLayout, + ) -> Self { + Immediate::ScalarPair(val.into(), ScalarMaybeUninit::from_maybe_pointer(vtable, cx)) } #[inline] pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit<Tag> { match self { Immediate::Scalar(val) => val, - Immediate::ScalarPair(..) => bug!("Got a wide pointer where a scalar was expected"), + Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"), } } @@ -79,6 +83,16 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> { pub fn to_scalar(self) -> InterpResult<'tcx, Scalar<Tag>> { self.to_scalar_or_uninit().check_init() } + + #[inline] + pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> { + match self { + Immediate::ScalarPair(val1, val2) => Ok((val1.check_init()?, val2.check_init()?)), + Immediate::Scalar(..) => { + bug!("Got a scalar where a scalar pair was expected") + } + } + } } // ScalarPair needs a type to interpret, so we often have an immediate and a type together diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs index 7a93fcee78e..a6ba00ec695 100644 --- a/compiler/rustc_mir/src/interpret/traits.rs +++ b/compiler/rustc_mir/src/interpret/traits.rs @@ -21,7 +21,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, ty: Ty<'tcx>, poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, - ) -> InterpResult<'tcx, Pointer<M::PointerTag>> { + ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> { trace!("get_vtable(trait_ref={:?})", poly_trait_ref); let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref)); @@ -34,7 +34,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let vtable_ptr = self.memory.global_base_pointer(Pointer::from(vtable_allocation))?; - Ok(vtable_ptr) + Ok(vtable_ptr.into()) } /// Resolves the function at the specified slot in the provided @@ -121,4 +121,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Ok((Size::from_bytes(size), align)) } + + pub fn read_new_vtable_after_trait_upcasting_from_vtable( + &self, + vtable: Pointer<Option<M::PointerTag>>, + idx: u64, + ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> { + let pointer_size = self.pointer_size(); + + let vtable_slot = vtable.offset(pointer_size * idx, self)?; + let new_vtable = self + .memory + .get(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)? + .expect("cannot be a ZST"); + + let new_vtable = self.scalar_to_ptr(new_vtable.read_ptr_sized(Size::ZERO)?.check_init()?); + + Ok(new_vtable) + } } diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 0ad360c7d89..ace7cffd16d 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -282,6 +282,16 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx> { } } +impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { + #[inline(always)] + fn query_crate_is_local(&self) -> bool { + self.0.def_id().krate == LOCAL_CRATE + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.def_span(self.0.def_id()) + } +} + impl<'tcx> Key for GenericArg<'tcx> { #[inline(always)] fn query_crate_is_local(&self) -> bool { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 693384602a7..585fcf795b7 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -756,16 +756,17 @@ fn vtable_trait_first_method_offset<'tcx>( } /// Find slot offset for trait vptr within vtable entries of another trait -/// FIXME: This function is not yet used. Remove `#[allow(dead_code)]` when it's used in upcoming pr. -#[allow(dead_code)] -fn vtable_trait_vptr_slot_offset<'tcx>( +pub fn vtable_trait_upcasting_coercion_new_vptr_slot( tcx: TyCtxt<'tcx>, key: ( - ty::PolyTraitRef<'tcx>, // trait_to_be_found - ty::PolyTraitRef<'tcx>, // trait_owning_vtable + ty::PolyTraitRef<'tcx>, // trait owning vtable + ty::PolyTraitRef<'tcx>, // super trait ref ), ) -> Option<usize> { - let (trait_to_be_found, trait_owning_vtable) = key; + let (trait_owning_vtable, super_trait_ref) = key; + let super_trait_did = super_trait_ref.def_id(); + // FIXME: take substsref part into account here after upcasting coercion allows the same def_id occur + // multiple times. let vtable_segment_callback = { let mut vptr_offset = 0; @@ -776,7 +777,7 @@ fn vtable_trait_vptr_slot_offset<'tcx>( } VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { vptr_offset += util::count_own_vtable_entries(tcx, trait_ref); - if trait_ref == trait_to_be_found { + if trait_ref.def_id() == super_trait_did { if emit_vptr { return ControlFlow::Break(Some(vptr_offset)); } else { @@ -810,6 +811,7 @@ pub fn provide(providers: &mut ty::query::Providers) { specializes: specialize::specializes, codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, vtable_entries, + vtable_trait_upcasting_coercion_new_vptr_slot, subst_and_check_impossible_predicates, mir_abstract_const: |tcx, def_id| { let def_id = def_id.expect_local(); |
