From da5e4d73f192b5c0faa357992e6b6c61707ae592 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 11:36:37 -0400 Subject: [PATCH 01/16] add a Vtable kind of symbolic allocations --- .../rustc_codegen_cranelift/src/constant.rs | 26 ++++++++---- compiler/rustc_codegen_gcc/src/common.rs | 8 ++++ compiler/rustc_codegen_llvm/src/common.rs | 8 ++++ compiler/rustc_codegen_llvm/src/consts.rs | 4 +- .../rustc_const_eval/src/interpret/memory.rs | 18 +++++++- .../rustc_middle/src/mir/interpret/error.rs | 3 ++ .../rustc_middle/src/mir/interpret/mod.rs | 41 +++++++++++++++++-- compiler/rustc_middle/src/mir/pretty.rs | 2 + compiler/rustc_middle/src/ty/codec.rs | 1 + compiler/rustc_middle/src/ty/print/pretty.rs | 3 +- compiler/rustc_monomorphize/src/collector.rs | 7 ++++ 11 files changed, 106 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 48972321a9f40..389ff7231b0af 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -195,9 +195,13 @@ pub(crate) fn codegen_const_value<'tcx>( } Scalar::Ptr(ptr, _size) => { let (alloc_id, offset) = ptr.into_parts(); // we know the `offset` is relative - let alloc_kind = fx.tcx.get_global_alloc(alloc_id); - let base_addr = match alloc_kind { - Some(GlobalAlloc::Memory(alloc)) => { + // For vtables, get the underlying data allocation. + let alloc_id = match fx.tcx.global_alloc(alloc_id) { + GlobalAlloc::Vtable(ty, trait_ref) => fx.tcx.vtable_allocation((ty, trait_ref)), + _ => alloc_id, + }; + let base_addr = match fx.tcx.global_alloc(alloc_id) { + GlobalAlloc::Memory(alloc) => { let data_id = data_id_for_alloc_id( &mut fx.constants_cx, fx.module, @@ -211,13 +215,14 @@ pub(crate) fn codegen_const_value<'tcx>( } fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } - Some(GlobalAlloc::Function(instance)) => { + GlobalAlloc::Function(instance) => { let func_id = crate::abi::import_function(fx.tcx, fx.module, instance); let local_func_id = fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); fx.bcx.ins().func_addr(fx.pointer_type, local_func_id) } - Some(GlobalAlloc::Static(def_id)) => { + GlobalAlloc::Vtable(..) => bug!("vtables are already handled"), + GlobalAlloc::Static(def_id) => { assert!(fx.tcx.is_static(def_id)); let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); let local_data_id = @@ -227,7 +232,6 @@ pub(crate) fn codegen_const_value<'tcx>( } fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } - None => bug!("missing allocation {:?}", alloc_id), }; let val = if offset.bytes() != 0 { fx.bcx.ins().iadd_imm(base_addr, i64::try_from(offset.bytes()).unwrap()) @@ -360,7 +364,9 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant //println!("alloc_id {}", alloc_id); let alloc = match tcx.get_global_alloc(alloc_id).unwrap() { GlobalAlloc::Memory(alloc) => alloc, - GlobalAlloc::Function(_) | GlobalAlloc::Static(_) => unreachable!(), + GlobalAlloc::Function(_) | GlobalAlloc::Static(_) | GlobalAlloc::Vtable(..) => { + unreachable!() + } }; let data_id = *cx.anon_allocs.entry(alloc_id).or_insert_with(|| { module @@ -424,7 +430,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant read_target_uint(endianness, bytes).unwrap() }; - let reloc_target_alloc = tcx.get_global_alloc(alloc_id).unwrap(); + let reloc_target_alloc = tcx.global_alloc(alloc_id); let data_id = match reloc_target_alloc { GlobalAlloc::Function(instance) => { assert_eq!(addend, 0); @@ -436,6 +442,10 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant GlobalAlloc::Memory(target_alloc) => { data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability) } + GlobalAlloc::Vtable(ty, trait_ref) => { + let alloc_id = tcx.vtable_allocation((ty, trait_ref)); + data_id_for_alloc_id(cx, module, alloc_id, Mutability::Not) + } GlobalAlloc::Static(def_id) => { if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index fc391f53f18e7..3868f2f7a4951 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -183,6 +183,13 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } Scalar::Ptr(ptr, _size) => { let (alloc_id, offset) = ptr.into_parts(); + // For vtables, get the underlying data allocation. + let alloc_id = match self.tcx.global_alloc(alloc_id) { + GlobalAlloc::Vtable(ty, trait_ref) => { + self.tcx.vtable_allocation((ty, trait_ref)) + } + _ => alloc_id, + }; let base_addr = match self.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { @@ -201,6 +208,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { GlobalAlloc::Function(fn_instance) => { self.get_fn_addr(fn_instance) }, + GlobalAlloc::Vtable(..) => panic!("vtables are already handled"), GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); self.get_static(def_id).get_address(None) diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 77cbbf4c6cacf..b465f65fcab30 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -240,6 +240,13 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { } Scalar::Ptr(ptr, _size) => { let (alloc_id, offset) = ptr.into_parts(); + // For vtables, get the underlying data allocation. + let alloc_id = match self.tcx.global_alloc(alloc_id) { + GlobalAlloc::Vtable(ty, trait_ref) => { + self.tcx.vtable_allocation((ty, trait_ref)) + } + _ => alloc_id, + }; let (base_addr, base_addr_space) = match self.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { let init = const_alloc_to_llvm(self, alloc); @@ -257,6 +264,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.get_fn_addr(fn_instance.polymorphize(self.tcx)), self.data_layout().instruction_address_space, ), + GlobalAlloc::Vtable(..) => bug!("vtables are already handled"), GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); assert!(!self.tcx.is_thread_local_static(def_id)); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 2b16ae1a88de0..1fef22796ddad 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -101,7 +101,9 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation< let address_space = match cx.tcx.global_alloc(alloc_id) { GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space, - GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) => AddressSpace::DATA, + GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::Vtable(..) => { + AddressSpace::DATA + } }; llvals.push(cx.scalar_to_backend( diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index b665b21096061..5d6620d8782d4 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -62,6 +62,8 @@ pub enum AllocKind { LiveData, /// A function allocation (that fn ptrs point to). Function, + /// A (symbolic) vtable allocation. + Vtable, /// A dead allocation. Dead, } @@ -291,6 +293,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Some(GlobalAlloc::Function(..)) => { err_ub_format!("deallocating {alloc_id:?}, which is a function") } + Some(GlobalAlloc::Vtable(..)) => { + err_ub_format!("deallocating {alloc_id:?}, which is a vtable") + } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { err_ub_format!("deallocating {alloc_id:?}, which is static memory") } @@ -479,6 +484,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (mem, None) } Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)), + Some(GlobalAlloc::Vtable(..)) => throw_ub!(DerefVtablePointer(id)), None => throw_ub!(PointerUseAfterFree(id)), Some(GlobalAlloc::Static(def_id)) => { assert!(self.tcx.is_static(def_id)); @@ -678,6 +684,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (alloc.size(), alloc.align, AllocKind::LiveData) } Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), + Some(GlobalAlloc::Vtable(..)) => { + // No data to be accessed here. + return (Size::ZERO, Align::ONE, AllocKind::Vtable); + } // The rest must be dead. None => { // Deallocated pointers are allowed, we should be able to find @@ -840,7 +850,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, )?; } Some(GlobalAlloc::Function(func)) => { - write!(fmt, " (fn: {})", func)?; + write!(fmt, " (fn: {func})")?; + } + Some(GlobalAlloc::Vtable(ty, Some(trait_ref))) => { + write!(fmt, " (vtable: impl {trait_ref} for {ty})")?; + } + Some(GlobalAlloc::Vtable(ty, None)) => { + write!(fmt, " (vtable: impl ? for {ty})")?; } Some(GlobalAlloc::Static(did)) => { write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?; diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 795f23edb3186..68559ae2249fb 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -271,6 +271,8 @@ pub enum UndefinedBehaviorInfo<'tcx> { WriteToReadOnly(AllocId), // Trying to access the data behind a function pointer. DerefFunctionPointer(AllocId), + // Trying to access the data behind a vtable pointer. + DerefVtablePointer(AllocId), /// The value validity check found a problem. /// Should only be thrown by `validity.rs` and always point out which part of the value /// is the problem. @@ -359,6 +361,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { ), WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"), DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"), + DerefVtablePointer(a) => write!(f, "accessing {a:?} which contains a vtable"), ValidationFailure { path: None, msg } => { write!(f, "constructing invalid value: {msg}") } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 698024b23301e..d1039ed30b08b 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -196,6 +196,7 @@ impl fmt::Debug for AllocId { enum AllocDiscriminant { Alloc, Fn, + Vtable, Static, } @@ -215,6 +216,12 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder>>( AllocDiscriminant::Fn.encode(encoder); fn_instance.encode(encoder); } + GlobalAlloc::Vtable(ty, poly_trait_ref) => { + trace!("encoding {:?} with {ty:#?}, {poly_trait_ref:#?}", alloc_id); + AllocDiscriminant::Vtable.encode(encoder); + ty.encode(encoder); + poly_trait_ref.encode(encoder); + } GlobalAlloc::Static(did) => { assert!(!tcx.is_thread_local_static(did)); // References to statics doesn't need to know about their allocations, @@ -305,7 +312,7 @@ impl<'s> AllocDecodingSession<'s> { State::InProgress(TinyList::new_single(self.session_id), alloc_id); Some(alloc_id) } - AllocDiscriminant::Fn | AllocDiscriminant::Static => { + AllocDiscriminant::Fn | AllocDiscriminant::Static | AllocDiscriminant::Vtable => { // Fns and statics cannot be cyclic, and their `AllocId` // is determined later by interning. *entry = @@ -355,6 +362,15 @@ impl<'s> AllocDecodingSession<'s> { let alloc_id = decoder.interner().create_fn_alloc(instance); alloc_id } + AllocDiscriminant::Vtable => { + assert!(alloc_id.is_none()); + trace!("creating static alloc ID"); + let ty = as Decodable>::decode(decoder); + let poly_trait_ref = > as Decodable>::decode(decoder); + trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}"); + let alloc_id = decoder.interner().create_vtable_alloc(ty, poly_trait_ref); + alloc_id + } AllocDiscriminant::Static => { assert!(alloc_id.is_none()); trace!("creating extern static alloc ID"); @@ -380,6 +396,8 @@ impl<'s> AllocDecodingSession<'s> { pub enum GlobalAlloc<'tcx> { /// The alloc ID is used as a function pointer. Function(Instance<'tcx>), + /// This alloc ID points to a symbolic (not-reified) vtable. + Vtable(Ty<'tcx>, Option>), /// The alloc ID points to a "lazy" static variable that did not get computed (yet). /// This is also used to break the cycle in recursive statics. Static(DefId), @@ -407,6 +425,16 @@ impl<'tcx> GlobalAlloc<'tcx> { _ => bug!("expected function, got {:?}", self), } } + + /// Panics if the `GlobalAlloc` is not `GlobalAlloc::Vtable` + #[track_caller] + #[inline] + pub fn unwrap_vtable(&self) -> (Ty<'tcx>, Option>) { + match *self { + GlobalAlloc::Vtable(ty, poly_trait_ref) => (ty, poly_trait_ref), + _ => bug!("expected vtable, got {:?}", self), + } + } } pub(crate) struct AllocMap<'tcx> { @@ -454,12 +482,12 @@ impl<'tcx> TyCtxt<'tcx> { } /// Reserves a new ID *if* this allocation has not been dedup-reserved before. - /// Should only be used for function pointers and statics, we don't want - /// to dedup IDs for "real" memory! + /// Should only be used for "symbolic" allocations (function pointers, vtables, statics), we + /// don't want to dedup IDs for "real" memory! fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId { let mut alloc_map = self.alloc_map.lock(); match alloc { - GlobalAlloc::Function(..) | GlobalAlloc::Static(..) => {} + GlobalAlloc::Function(..) | GlobalAlloc::Static(..) | GlobalAlloc::Vtable(..) => {} GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"), } if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) { @@ -504,6 +532,11 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated. + pub fn create_vtable_alloc(self, ty: Ty<'tcx>, poly_trait_ref: Option>) -> AllocId { + self.reserve_and_set_dedup(GlobalAlloc::Vtable(ty, poly_trait_ref)) + } + /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical /// `Allocation` with a different `AllocId`. /// Statics with identical content will still point to the same `Allocation`, i.e., diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 437776ad76546..120dfb5a36116 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -725,6 +725,8 @@ pub fn write_allocations<'tcx>( // gracefully handle it and allow buggy rustc to be debugged via allocation printing. None => write!(w, " (deallocated)")?, Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {inst})")?, + Some(GlobalAlloc::Vtable(ty, Some(trait_ref))) => write!(w, " (vtable: impl {trait_ref} for {ty})")?, + Some(GlobalAlloc::Vtable(ty, None)) => write!(w, " (vtable: impl ? for {ty})")?, Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { match tcx.eval_static_initializer(did) { Ok(alloc) => { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index e6ea3d8885376..51137c52659db 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -523,4 +523,5 @@ impl_binder_encode_decode! { ty::ExistentialPredicate<'tcx>, ty::TraitRef<'tcx>, Vec>, + ty::ExistentialTraitRef<'tcx>, } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index da9394128ac38..d46e9ae949d72 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1282,11 +1282,12 @@ pub trait PrettyPrinter<'tcx>: p!("") } } - // FIXME: for statics and functions, we could in principle print more detail. + // FIXME: for statics, vtables, and functions, we could in principle print more detail. Some(GlobalAlloc::Static(def_id)) => { p!(write("", def_id)) } Some(GlobalAlloc::Function(_)) => p!(""), + Some(GlobalAlloc::Vtable(..)) => p!(""), None => p!(""), } return Ok(self); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index e3cfb034e40ad..3cee9a460c126 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1427,6 +1427,13 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIte output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); } } + GlobalAlloc::Vtable(ty, trait_ref) => { + // FIXME(RJ) no ideas if this is correct. There is this nice + // `create_mono_items_for_vtable_methods` method but I wouldn't know how to call it from + // here. So instead we just generate the actual vtable and recurse. + let alloc_id = tcx.vtable_allocation((ty, trait_ref)); + collect_miri(tcx, alloc_id, output) + } } } From a10d8e458118b3feac96fe5e56c25e70cee99b88 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 11:40:34 -0400 Subject: [PATCH 02/16] rename get_global_alloc to try_get_global_alloc --- .../rustc_codegen_cranelift/src/constant.rs | 2 +- .../rustc_const_eval/src/const_eval/machine.rs | 2 +- compiler/rustc_const_eval/src/const_eval/mod.rs | 2 +- .../rustc_const_eval/src/interpret/intern.rs | 4 ++-- .../rustc_const_eval/src/interpret/memory.rs | 12 ++++++------ .../rustc_const_eval/src/interpret/validity.rs | 2 +- compiler/rustc_middle/src/mir/interpret/mod.rs | 17 ++++++++++++----- compiler/rustc_middle/src/mir/pretty.rs | 6 ++++-- compiler/rustc_middle/src/ty/impls_ty.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 5 +++-- 10 files changed, 32 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 389ff7231b0af..a1508d7c72b42 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -362,7 +362,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant let (data_id, alloc, section_name) = match todo_item { TodoItem::Alloc(alloc_id) => { //println!("alloc_id {}", alloc_id); - let alloc = match tcx.get_global_alloc(alloc_id).unwrap() { + let alloc = match tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => alloc, GlobalAlloc::Function(_) | GlobalAlloc::Static(_) | GlobalAlloc::Vtable(..) => { unreachable!() diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index cc20f05e55612..fc2e6652a3d72 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -369,7 +369,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // we don't deallocate it. let (alloc_id, _, _) = ecx.ptr_get_alloc_id(ptr)?; let is_allocated_in_another_const = matches!( - ecx.tcx.get_global_alloc(alloc_id), + ecx.tcx.try_get_global_alloc(alloc_id), Some(interpret::GlobalAlloc::Memory(_)) ); diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index edc4c13b6e8f6..948c334949826 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -138,7 +138,7 @@ pub(crate) fn deref_mir_constant<'tcx>( let mplace = ecx.deref_operand(&op).unwrap(); if let Some(alloc_id) = mplace.ptr.provenance { assert_eq!( - tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().0.0.mutability, + tcx.global_alloc(alloc_id).unwrap_memory().0.0.mutability, Mutability::Not, "deref_mir_constant cannot be used with mutable allocations as \ that could allow pattern matching to observe mutable statics", diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 2a977779e4267..23526edcc343a 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -94,7 +94,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval: // to validation to error -- it has the much better error messages, pointing out where // in the value the dangling reference lies. // The `delay_span_bug` ensures that we don't forget such a check in validation. - if tcx.get_global_alloc(alloc_id).is_none() { + if tcx.try_get_global_alloc(alloc_id).is_none() { tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer"); } // treat dangling pointers like other statics @@ -454,7 +454,7 @@ pub fn intern_const_alloc_recursive< .sess .span_err(ecx.tcx.span, "encountered dangling pointer in final constant"); return Err(reported); - } else if ecx.tcx.get_global_alloc(alloc_id).is_none() { + } else if ecx.tcx.try_get_global_alloc(alloc_id).is_none() { // We have hit an `AllocId` that is neither in local or global memory and isn't // marked as dangling by local memory. That should be impossible. span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id); diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 5d6620d8782d4..0287c180e94b6 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -161,7 +161,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, Pointer> { let alloc_id = ptr.provenance; // We need to handle `extern static`. - match self.tcx.get_global_alloc(alloc_id) { + match self.tcx.try_get_global_alloc(alloc_id) { Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => { bug!("global memory cannot point to thread-local static") } @@ -289,7 +289,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let Some((alloc_kind, mut alloc)) = self.memory.alloc_map.remove(&alloc_id) else { // Deallocating global memory -- always an error - return Err(match self.tcx.get_global_alloc(alloc_id) { + return Err(match self.tcx.try_get_global_alloc(alloc_id) { Some(GlobalAlloc::Function(..)) => { err_ub_format!("deallocating {alloc_id:?}, which is a function") } @@ -478,7 +478,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { id: AllocId, is_write: bool, ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { - let (alloc, def_id) = match self.tcx.get_global_alloc(id) { + let (alloc, def_id) = match self.tcx.try_get_global_alloc(id) { Some(GlobalAlloc::Memory(mem)) => { // Memory of a constant or promoted or anonymous memory referenced by a static. (mem, None) @@ -669,7 +669,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // # Statics // Can't do this in the match argument, we may get cycle errors since the lock would // be held throughout the match. - match self.tcx.get_global_alloc(id) { + match self.tcx.try_get_global_alloc(id) { Some(GlobalAlloc::Static(did)) => { assert!(!self.tcx.is_thread_local_static(did)); // Use size and align of the type. @@ -715,7 +715,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let Some(extra) = self.memory.extra_fn_ptr_map.get(&id) { Some(FnVal::Other(*extra)) } else { - match self.tcx.get_global_alloc(id) { + match self.tcx.try_get_global_alloc(id) { Some(GlobalAlloc::Function(instance)) => Some(FnVal::Instance(instance)), _ => None, } @@ -839,7 +839,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, } None => { // global alloc - match self.ecx.tcx.get_global_alloc(id) { + match self.ecx.tcx.try_get_global_alloc(id) { Some(GlobalAlloc::Memory(alloc)) => { write!(fmt, " (unchanged global, ")?; write_allocation_track_relocs( diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 54ae9065f74af..569af01c4853a 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -447,7 +447,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // `!` is a ZST and we want to validate it. if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr) { // Special handling for pointers to statics (irrespective of their type). - let alloc_kind = self.ecx.tcx.get_global_alloc(alloc_id); + let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id); if let Some(GlobalAlloc::Static(did)) = alloc_kind { assert!(!self.ecx.tcx.is_thread_local_static(did)); assert!(self.ecx.tcx.is_static(did)); diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index d1039ed30b08b..9b0fe593cfc88 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -312,7 +312,9 @@ impl<'s> AllocDecodingSession<'s> { State::InProgress(TinyList::new_single(self.session_id), alloc_id); Some(alloc_id) } - AllocDiscriminant::Fn | AllocDiscriminant::Static | AllocDiscriminant::Vtable => { + AllocDiscriminant::Fn + | AllocDiscriminant::Static + | AllocDiscriminant::Vtable => { // Fns and statics cannot be cyclic, and their `AllocId` // is determined later by interning. *entry = @@ -366,7 +368,8 @@ impl<'s> AllocDecodingSession<'s> { assert!(alloc_id.is_none()); trace!("creating static alloc ID"); let ty = as Decodable>::decode(decoder); - let poly_trait_ref = > as Decodable>::decode(decoder); + let poly_trait_ref = + > as Decodable>::decode(decoder); trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}"); let alloc_id = decoder.interner().create_vtable_alloc(ty, poly_trait_ref); alloc_id @@ -533,7 +536,11 @@ impl<'tcx> TyCtxt<'tcx> { } /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated. - pub fn create_vtable_alloc(self, ty: Ty<'tcx>, poly_trait_ref: Option>) -> AllocId { + pub fn create_vtable_alloc( + self, + ty: Ty<'tcx>, + poly_trait_ref: Option>, + ) -> AllocId { self.reserve_and_set_dedup(GlobalAlloc::Vtable(ty, poly_trait_ref)) } @@ -554,7 +561,7 @@ impl<'tcx> TyCtxt<'tcx> { /// This function exists to allow const eval to detect the difference between evaluation- /// local dangling pointers and allocations in constants/statics. #[inline] - pub fn get_global_alloc(self, id: AllocId) -> Option> { + pub fn try_get_global_alloc(self, id: AllocId) -> Option> { self.alloc_map.lock().alloc_map.get(&id).cloned() } @@ -565,7 +572,7 @@ impl<'tcx> TyCtxt<'tcx> { /// ids), this function is frequently used throughout rustc, but should not be used within /// the miri engine. pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> { - match self.get_global_alloc(id) { + match self.try_get_global_alloc(id) { Some(alloc) => alloc, None => bug!("could not find allocation for {id:?}"), } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 120dfb5a36116..013b67ea2b969 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -720,12 +720,14 @@ pub fn write_allocations<'tcx>( write!(w, "{}", display_allocation(tcx, alloc.inner())) }; write!(w, "\n{id:?}")?; - match tcx.get_global_alloc(id) { + match tcx.try_get_global_alloc(id) { // This can't really happen unless there are bugs, but it doesn't cost us anything to // gracefully handle it and allow buggy rustc to be debugged via allocation printing. None => write!(w, " (deallocated)")?, Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {inst})")?, - Some(GlobalAlloc::Vtable(ty, Some(trait_ref))) => write!(w, " (vtable: impl {trait_ref} for {ty})")?, + Some(GlobalAlloc::Vtable(ty, Some(trait_ref))) => { + write!(w, " (vtable: impl {trait_ref} for {ty})")? + } Some(GlobalAlloc::Vtable(ty, None)) => write!(w, " (vtable: impl ? for {ty})")?, Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { match tcx.eval_static_initializer(did) { diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index b78087ba7607e..263d64a57776a 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -147,7 +147,7 @@ impl<'a> HashStable> for mir::interpret::AllocId { ty::tls::with_opt(|tcx| { trace!("hashing {:?}", *self); let tcx = tcx.expect("can't hash AllocIds during hir lowering"); - tcx.get_global_alloc(*self).hash_stable(hcx, hasher); + tcx.try_get_global_alloc(*self).hash_stable(hcx, hasher); }); } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index d46e9ae949d72..43abed847e000 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1269,7 +1269,7 @@ pub trait PrettyPrinter<'tcx>: if let ty::Array(elem, len) = inner.kind() { if let ty::Uint(ty::UintTy::U8) = elem.kind() { if let ty::ConstKind::Value(ty::ValTree::Leaf(int)) = len.kind() { - match self.tcx().get_global_alloc(alloc_id) { + match self.tcx().try_get_global_alloc(alloc_id) { Some(GlobalAlloc::Memory(alloc)) => { let len = int.assert_bits(self.tcx().data_layout.pointer_size); let range = @@ -1298,7 +1298,8 @@ pub trait PrettyPrinter<'tcx>: ty::FnPtr(_) => { // FIXME: We should probably have a helper method to share code with the "Byte strings" // printing above (which also has to handle pointers to all sorts of things). - if let Some(GlobalAlloc::Function(instance)) = self.tcx().get_global_alloc(alloc_id) + if let Some(GlobalAlloc::Function(instance)) = + self.tcx().try_get_global_alloc(alloc_id) { self = self.typed_value( |this| this.print_value_path(instance.def_id(), instance.substs), From fe00573324854e5681546b660bbbaf4e1ec38eb2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 16:02:49 -0400 Subject: [PATCH 03/16] make use of symbolic vtables in interpreter --- .../rustc_const_eval/src/interpret/cast.rs | 34 +++-- .../src/interpret/eval_context.rs | 2 +- .../rustc_const_eval/src/interpret/memory.rs | 33 ++++- .../rustc_const_eval/src/interpret/place.rs | 15 +- .../src/interpret/terminator.rs | 16 ++- .../rustc_const_eval/src/interpret/traits.rs | 133 ++++-------------- .../src/interpret/validity.rs | 51 +------ .../rustc_const_eval/src/interpret/visitor.rs | 2 +- .../rustc_middle/src/mir/interpret/error.rs | 27 ++-- .../ui/consts/const-eval/const_transmute.rs | 54 ------- .../ub-incorrect-vtable.32bit.stderr | 36 ++++- .../ub-incorrect-vtable.64bit.stderr | 36 ++++- .../consts/const-eval/ub-incorrect-vtable.rs | 62 +++++++- .../consts/const-eval/ub-ref-ptr.32bit.stderr | 6 +- .../consts/const-eval/ub-ref-ptr.64bit.stderr | 6 +- .../consts/const-eval/ub-upvars.32bit.stderr | 2 +- .../consts/const-eval/ub-upvars.64bit.stderr | 2 +- .../const-eval/ub-wide-ptr.32bit.stderr | 61 +++----- .../const-eval/ub-wide-ptr.64bit.stderr | 61 +++----- src/test/ui/consts/const-eval/ub-wide-ptr.rs | 9 +- src/test/ui/consts/issue-79690.64bit.stderr | 4 +- .../mutable_references_err.32bit.stderr | 4 +- .../mutable_references_err.64bit.stderr | 4 +- 23 files changed, 283 insertions(+), 377 deletions(-) delete mode 100644 src/test/ui/consts/const-eval/const_transmute.rs diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 2e6cbb131ef3c..473ba848a5830 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -299,29 +299,35 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { let val = self.read_immediate(src)?; + let (old_data, old_vptr) = val.to_scalar_pair()?; + let old_vptr = self.scalar_to_ptr(old_vptr)?; if data_a.principal_def_id() == data_b.principal_def_id() { return self.write_immediate(*val, dest); } // trait upcasting coercion - let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot(( + let Some(vptr_entry_idx) = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot(( src_pointee_ty, dest_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) - } + )) else { + return self.write_immediate(*val, dest); + }; + + let (ty, _) = self.get_ptr_vtable(old_vptr)?; + let Some(ty::VtblEntry::TraitVPtr(new_trait)) = self.get_vtable_entries(old_vptr)?.get(vptr_entry_idx) else { + throw_ub_format!( + "upcasting to index {vptr_entry_idx} of vtable {old_vptr} but \ + that vtable is too small or does not have an upcast-vtable at that index" + ) + }; + let new_trait = new_trait.map_bound(|trait_ref| { + ty::ExistentialTraitRef::erase_self_ty(*self.tcx, trait_ref) + }); + let new_vptr = self.get_vtable_ptr(ty, Some(new_trait))?; + self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) } (_, &ty::Dynamic(ref data, _)) => { // Initial cast from sized to dyn trait - let vtable = self.get_vtable(src_pointee_ty, data.principal())?; + let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?; let ptr = self.read_immediate(src)?.to_scalar()?; let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx); self.write_immediate(val, dest) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 45928d7b02e36..fdf243c4108d3 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -631,7 +631,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::Dynamic(..) => { let vtable = self.scalar_to_ptr(metadata.unwrap_meta())?; // Read size and align from vtable (already checks size). - Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) + Ok(Some(self.get_vtable_size_and_align(vtable)?)) } ty::Slice(_) | ty::Str => { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 0287c180e94b6..5e49e6a4f0845 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -16,7 +16,7 @@ use std::ptr; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::display_allocation; -use rustc_middle::ty::{Instance, ParamEnv, TyCtxt}; +use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ @@ -500,6 +500,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // contains a reference to memory that was created during its evaluation (i.e., not // to another static), those inner references only exist in "resolved" form. if self.tcx.is_foreign_item(def_id) { + // This is unreachable in Miri, but can happen in CTFE where we actually *do* support + // referencing arbitrary (declared) extern statics. throw_unsup!(ReadExternStatic(def_id)); } @@ -670,11 +672,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Can't do this in the match argument, we may get cycle errors since the lock would // be held throughout the match. match self.tcx.try_get_global_alloc(id) { - Some(GlobalAlloc::Static(did)) => { - assert!(!self.tcx.is_thread_local_static(did)); + Some(GlobalAlloc::Static(def_id)) => { + assert!(self.tcx.is_static(def_id)); + assert!(!self.tcx.is_thread_local_static(def_id)); // Use size and align of the type. - let ty = self.tcx.type_of(did); + let ty = self.tcx.type_of(def_id); let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); + assert!(!layout.is_unsized()); (layout.size, layout.align.abi, AllocKind::LiveData) } Some(GlobalAlloc::Memory(alloc)) => { @@ -685,8 +689,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), Some(GlobalAlloc::Vtable(..)) => { - // No data to be accessed here. - return (Size::ZERO, Align::ONE, AllocKind::Vtable); + // No data to be accessed here. But vtables are pointer-aligned. + return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::Vtable); } // The rest must be dead. None => { @@ -726,7 +730,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, ptr: Pointer>, ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { - trace!("get_fn({:?})", ptr); + trace!("get_ptr_fn({:?})", ptr); let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr)?; if offset.bytes() != 0 { throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))) @@ -735,6 +739,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into()) } + pub fn get_ptr_vtable( + &self, + ptr: Pointer>, + ) -> InterpResult<'tcx, (Ty<'tcx>, Option>)> { + trace!("get_ptr_vtable({:?})", ptr); + let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?; + if offset.bytes() != 0 { + throw_ub!(InvalidVtablePointer(Pointer::new(alloc_id, offset))) + } + match self.tcx.try_get_global_alloc(alloc_id) { + Some(GlobalAlloc::Vtable(ty, trait_ref)) => Ok((ty, trait_ref)), + _ => throw_ub!(InvalidVtablePointer(Pointer::new(alloc_id, offset))), + } + } + pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { self.get_alloc_raw_mut(id)?.0.mutability = Mutability::Not; Ok(()) diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 4a45d979a79a2..c7d8a744f7c09 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -885,28 +885,19 @@ where } /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. - /// Also return some more information so drop doesn't have to run the same code twice. pub(super) fn unpack_dyn_trait( &self, mplace: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::Provenance>)> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { let vtable = self.scalar_to_ptr(mplace.vtable())?; // also sanity checks the type - let (instance, ty) = self.read_drop_type_from_vtable(vtable)?; + let (ty, _) = self.get_ptr_vtable(vtable)?; let layout = self.layout_of(ty)?; - // More sanity checks - if cfg!(debug_assertions) { - let (size, align) = self.read_size_and_align_from_vtable(vtable)?; - assert_eq!(size, layout.size); - // only ABI alignment is preserved - assert_eq!(align, layout.align.abi); - } - let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, layout, align: layout.align.abi, }; - Ok((instance, mplace)) + Ok(mplace) } } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 279ecef08c650..2ae0e1a6f5ac7 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -1,5 +1,4 @@ use std::borrow::Cow; -use std::convert::TryFrom; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_middle::ty::Instance; @@ -563,7 +562,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::Dynamic(..) )); let vtable = self.scalar_to_ptr(receiver_place.meta.unwrap_meta())?; - let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?; + let Some(ty::VtblEntry::Method(fn_inst)) = self.get_vtable_entries(vtable)?.get(idx).copied() else { + throw_ub_format!( + "calling index {idx} of vtable {vtable} but \ + that vtable is too small or does not have a method at that index" + ) + }; // `*mut receiver_place.layout.ty` is almost the layout that we // want for args[0]: We have to project to field 0 because we want @@ -579,7 +583,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { trace!("Patched receiver operand to {:#?}", args[0]); // recurse with concrete function self.eval_fn_call( - fn_val, + FnVal::Instance(fn_inst), (caller_abi, caller_fn_abi), &args, with_caller_location, @@ -606,8 +610,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (instance, place) = match place.layout.ty.kind() { ty::Dynamic(..) => { - // Dropping a trait object. - self.unpack_dyn_trait(&place)? + // Dropping a trait object. Need to find actual drop fn. + let place = self.unpack_dyn_trait(&place)?; + let instance = ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty); + (instance, place) } _ => (instance, place), }; diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index e4052b6178274..bddca2a20edec 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -1,14 +1,10 @@ -use std::convert::TryFrom; - -use rustc_middle::mir::interpret::{alloc_range, InterpResult, Pointer, PointerArithmetic}; -use rustc_middle::ty::{ - self, Ty, TyCtxt, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE, - COMMON_VTABLE_ENTRIES_SIZE, -}; +use rustc_middle::mir::interpret::{InterpResult, Pointer}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_target::abi::{Align, Size}; use super::util::ensure_monomorphic_enough; -use super::{FnVal, InterpCx, Machine}; +use super::{InterpCx, Machine}; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for @@ -17,8 +13,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// The `trait_ref` encodes the erased self type. Hence, if we are /// making an object `Foo` from a value of type `Foo`, then /// `trait_ref` would map `T: Trait`. - pub fn get_vtable( - &mut self, + pub fn get_vtable_ptr( + &self, ty: Ty<'tcx>, poly_trait_ref: Option>, ) -> InterpResult<'tcx, Pointer>> { @@ -30,114 +26,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ensure_monomorphic_enough(*self.tcx, ty)?; ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?; - let vtable_allocation = self.tcx.vtable_allocation((ty, poly_trait_ref)); - - let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_allocation))?; - + let vtable_symbolic_allocation = self.tcx.create_vtable_alloc(ty, poly_trait_ref); + let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_symbolic_allocation))?; Ok(vtable_ptr.into()) } - /// Resolves the function at the specified slot in the provided - /// vtable. Currently an index of '3' (`TyCtxt::COMMON_VTABLE_ENTRIES.len()`) - /// corresponds to the first method declared in the trait of the provided vtable. - pub fn get_vtable_slot( + /// Returns a high-level representation of the entires of the given vtable. + pub fn get_vtable_entries( &self, vtable: Pointer>, - idx: u64, - ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { - let ptr_size = self.pointer_size(); - let vtable_slot = vtable.offset(ptr_size * idx, self)?; - let vtable_slot = self - .get_ptr_alloc(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)? - .expect("cannot be a ZST"); - let fn_ptr = self.scalar_to_ptr(vtable_slot.read_pointer(Size::ZERO)?.check_init()?)?; - self.get_ptr_fn(fn_ptr) + ) -> InterpResult<'tcx, &'tcx [ty::VtblEntry<'tcx>]> { + let (ty, poly_trait_ref) = self.get_ptr_vtable(vtable)?; + Ok(if let Some(poly_trait_ref) = poly_trait_ref { + let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty); + let trait_ref = self.tcx.erase_regions(trait_ref); + self.tcx.vtable_entries(trait_ref) + } else { + TyCtxt::COMMON_VTABLE_ENTRIES + }) } - /// Returns the drop fn instance as well as the actual dynamic type. - pub fn read_drop_type_from_vtable( - &self, - vtable: Pointer>, - ) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> { - let pointer_size = self.pointer_size(); - // We don't care about the pointee type; we just want a pointer. - let vtable = self - .get_ptr_alloc( - vtable, - pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(), - self.tcx.data_layout.pointer_align.abi, - )? - .expect("cannot be a ZST"); - let drop_fn = vtable - .read_pointer(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap())? - .check_init()?; - // We *need* an instance here, no other kind of function value, to be able - // to determine the type. - let drop_instance = self.get_ptr_fn(self.scalar_to_ptr(drop_fn)?)?.as_instance()?; - trace!("Found drop fn: {:?}", drop_instance); - let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx); - let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig); - // The drop function takes `*mut T` where `T` is the type being dropped, so get that. - let args = fn_sig.inputs(); - if args.len() != 1 { - throw_ub!(InvalidVtableDropFn(fn_sig)); - } - let ty = - args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidVtableDropFn(fn_sig)))?.ty; - Ok((drop_instance, ty)) - } - - pub fn read_size_and_align_from_vtable( + pub fn get_vtable_size_and_align( &self, vtable: Pointer>, ) -> InterpResult<'tcx, (Size, Align)> { - let pointer_size = self.pointer_size(); - // We check for `size = 3 * ptr_size`, which covers the drop fn (unused here), - // the size, and the align (which we read below). - let vtable = self - .get_ptr_alloc( - vtable, - pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(), - self.tcx.data_layout.pointer_align.abi, - )? - .expect("cannot be a ZST"); - let size = vtable - .read_integer(alloc_range( - pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap(), - pointer_size, - ))? - .check_init()?; - let size = size.to_machine_usize(self)?; - let size = Size::from_bytes(size); - let align = vtable - .read_integer(alloc_range( - pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap(), - pointer_size, - ))? - .check_init()?; - let align = align.to_machine_usize(self)?; - let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?; - - if size > self.max_size_of_val() { - throw_ub!(InvalidVtableSize); - } - Ok((size, align)) - } - - pub fn read_new_vtable_after_trait_upcasting_from_vtable( - &self, - vtable: Pointer>, - idx: u64, - ) -> InterpResult<'tcx, Pointer>> { - let pointer_size = self.pointer_size(); - - let vtable_slot = vtable.offset(pointer_size * idx, self)?; - let new_vtable = self - .get_ptr_alloc(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_pointer(Size::ZERO)?.check_init()?)?; - - Ok(new_vtable) + let (ty, _trait_ref) = self.get_ptr_vtable(vtable)?; + let layout = self.layout_of(ty)?; + assert!(!layout.is_unsized(), "there are no vtables for unsized types"); + Ok((layout.size, layout.align.abi)) } } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 569af01c4853a..190eb732f9ad3 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -313,50 +313,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' match tail.kind() { ty::Dynamic(..) => { let vtable = self.ecx.scalar_to_ptr(meta.unwrap_meta())?; - // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. - try_validation!( - self.ecx.check_ptr_access_align( - vtable, - 3 * self.ecx.tcx.data_layout.pointer_size, // drop, size, align - self.ecx.tcx.data_layout.pointer_align.abi, - CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message - ), - self.path, - err_ub!(DanglingIntPointer(..)) | - err_ub!(PointerUseAfterFree(..)) => - { "dangling vtable pointer in wide pointer" }, - err_ub!(AlignmentCheckFailed { .. }) => - { "unaligned vtable pointer in wide pointer" }, - err_ub!(PointerOutOfBounds { .. }) => - { "too small vtable" }, - ); - try_validation!( - self.ecx.read_drop_type_from_vtable(vtable), + // Make sure it is a genuine vtable pointer. + let (_ty, _trait) = try_validation!( + self.ecx.get_ptr_vtable(vtable), self.path, err_ub!(DanglingIntPointer(..)) | - err_ub!(InvalidFunctionPointer(..)) => - { "invalid drop function pointer in vtable (not pointing to a function)" }, - err_ub!(InvalidVtableDropFn(..)) => - { "invalid drop function pointer in vtable (function has incompatible signature)" }, - // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123. - // (We assume there are no other MachineStop errors possible here.) - InterpError::MachineStop(_) => - { "vtable pointer does not have permission to read drop function pointer" }, - ); - try_validation!( - self.ecx.read_size_and_align_from_vtable(vtable), - self.path, - err_ub!(InvalidVtableSize) => - { "invalid vtable: size is bigger than largest supported object" }, - err_ub!(InvalidVtableAlignment(msg)) => - { "invalid vtable: alignment {}", msg }, - err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" }, - // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123. - // (We assume there are no other MachineStop errors possible here.) - InterpError::MachineStop(_) => - { "vtable pointer does not have permission to read size and alignment" }, + err_ub!(InvalidVtablePointer(..)) => + { "{vtable}" } expected { "a vtable pointer" }, ); - // FIXME: More checks for the vtable. + // FIXME: check if the type/trait match what ty::Dynamic says? } ty::Slice(..) | ty::Str => { let _len = try_validation!( @@ -607,11 +572,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let _fn = try_validation!( self.ecx.get_ptr_fn(ptr), self.path, - err_ub!(DanglingIntPointer(0, _)) => - { "a null function pointer" }, err_ub!(DanglingIntPointer(..)) | err_ub!(InvalidFunctionPointer(..)) => - { "{:x}", value } expected { "a function pointer" }, + { "{ptr}" } expected { "a function pointer" }, ); // FIXME: Check if the signature matches } else { diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 24228feb73e7d..aee1f93b1a39c 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -425,7 +425,7 @@ macro_rules! make_value_visitor { // unsized values are never immediate, so we can assert_mem_place let op = v.to_op_for_read(self.ecx())?; let dest = op.assert_mem_place(); - let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?.1; + let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?; trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout); // recurse with the inner type return self.visit_field(&v, 0, &$value_trait::from_op(&inner_mplace.into())); diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 68559ae2249fb..81d9db98478f9 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,7 +1,7 @@ use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar}; use crate::mir::interpret::ConstValue; -use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree}; +use crate::ty::{layout, query::TyCtxtAt, tls, Ty, ValTree}; use rustc_data_structures::sync::Lock; use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed}; @@ -219,7 +219,7 @@ pub struct ScalarSizeMismatch { } /// Error information for when the program caused Undefined Behavior. -pub enum UndefinedBehaviorInfo<'tcx> { +pub enum UndefinedBehaviorInfo { /// Free-form case. Only for errors that are never caught! Ub(String), /// Unreachable code was executed. @@ -241,12 +241,6 @@ pub enum UndefinedBehaviorInfo<'tcx> { PointerArithOverflow, /// Invalid metadata in a wide pointer (using `str` to avoid allocations). InvalidMeta(&'static str), - /// Invalid drop function in vtable. - InvalidVtableDropFn(FnSig<'tcx>), - /// Invalid size in a vtable: too large. - InvalidVtableSize, - /// Invalid alignment in a vtable: too large, or not a power of 2. - InvalidVtableAlignment(String), /// Reading a C string that does not end within its allocation. UnterminatedCString(Pointer), /// Dereferencing a dangling pointer after it got freed. @@ -290,6 +284,8 @@ pub enum UndefinedBehaviorInfo<'tcx> { InvalidTag(Scalar), /// Using a pointer-not-to-a-function as function pointer. InvalidFunctionPointer(Pointer), + /// Using a pointer-not-to-a-vtable as vtable pointer. + InvalidVtablePointer(Pointer), /// Using a string that is not valid UTF-8, InvalidStr(std::str::Utf8Error), /// Using uninitialized data where it is not allowed. @@ -302,7 +298,7 @@ pub enum UndefinedBehaviorInfo<'tcx> { UninhabitedEnumVariantWritten, } -impl fmt::Display for UndefinedBehaviorInfo<'_> { +impl fmt::Display for UndefinedBehaviorInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use UndefinedBehaviorInfo::*; match self { @@ -317,14 +313,6 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"), PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"), InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {msg}"), - InvalidVtableDropFn(sig) => write!( - f, - "invalid drop function signature: got {sig}, expected exactly one argument which must be a pointer type", - ), - InvalidVtableSize => { - write!(f, "invalid vtable: size is bigger than largest supported object") - } - InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {msg}"), UnterminatedCString(p) => write!( f, "reading a null-terminated string starting at {p:?} with no null found before end of allocation", @@ -378,6 +366,9 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { InvalidFunctionPointer(p) => { write!(f, "using {p:?} as function pointer but it does not point to a function") } + InvalidVtablePointer(p) => { + write!(f, "using {p:?} as vtable pointer but it does not point to a vtable") + } InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"), InvalidUninitBytes(Some((alloc, info))) => write!( f, @@ -497,7 +488,7 @@ impl dyn MachineStopType { pub enum InterpError<'tcx> { /// The program caused undefined behavior. - UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), + UndefinedBehavior(UndefinedBehaviorInfo), /// The program did something the interpreter does not support (some of these *might* be UB /// but the interpreter is not sure). Unsupported(UnsupportedOpInfo), diff --git a/src/test/ui/consts/const-eval/const_transmute.rs b/src/test/ui/consts/const-eval/const_transmute.rs deleted file mode 100644 index 90a454c75a1ce..0000000000000 --- a/src/test/ui/consts/const-eval/const_transmute.rs +++ /dev/null @@ -1,54 +0,0 @@ -// run-pass - -#![allow(dead_code)] - -#[repr(C)] -union Transmute { - t: T, - u: U, -} - -trait Bar { - fn bar(&self) -> u32; -} - -struct Foo { - foo: u32, - bar: bool, -} - -impl Bar for Foo { - fn bar(&self) -> u32 { - self.foo - } -} - -impl Drop for Foo { - fn drop(&mut self) { - assert!(!self.bar); - self.bar = true; - println!("dropping Foo"); - } -} - -#[derive(Copy, Clone)] -struct Fat<'a>(&'a Foo, &'static VTable); - -struct VTable { - drop: Option fn(&'a mut Foo)>, - size: usize, - align: usize, - bar: for<'a> fn(&'a Foo) -> u32, -} - -const FOO: &dyn Bar = &Foo { foo: 128, bar: false }; -const G: Fat = unsafe { Transmute { t: FOO }.u }; -const F: Option fn(&'a mut Foo)> = G.1.drop; -const H: for<'a> fn(&'a Foo) -> u32 = G.1.bar; - -fn main() { - let mut foo = Foo { foo: 99, bar: false }; - (F.unwrap())(&mut foo); - std::mem::forget(foo); // already ran the drop impl - assert_eq!(H(&Foo { foo: 42, bar: false }), 42); -} diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr index c6422447a4b79..965256de21a0f 100644 --- a/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr @@ -2,19 +2,19 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-incorrect-vtable.rs:19:14 | LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: alignment `1000` is not a power of 2 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: evaluation of constant value failed --> $DIR/ub-incorrect-vtable.rs:24:14 | LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: size is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:34:1 + --> $DIR/ub-incorrect-vtable.rs:33:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: alignment `1000` is not a power of 2 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -22,16 +22,38 @@ LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:39:1 + --> $DIR/ub-incorrect-vtable.rs:38:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: size is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ } -error: aborting due to 4 previous errors +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:44:1 + | +LL | const INVALID_VTABLE_UB: W<&dyn Trait> = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:91:1 + | +LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; + | ^^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ + } + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr index e594ad71b5b48..bd542a7a5f293 100644 --- a/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr @@ -2,19 +2,19 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-incorrect-vtable.rs:19:14 | LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: alignment `1000` is not a power of 2 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: evaluation of constant value failed --> $DIR/ub-incorrect-vtable.rs:24:14 | LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: size is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:34:1 + --> $DIR/ub-incorrect-vtable.rs:33:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: alignment `1000` is not a power of 2 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -22,16 +22,38 @@ LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:39:1 + --> $DIR/ub-incorrect-vtable.rs:38:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: size is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ } -error: aborting due to 4 previous errors +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:44:1 + | +LL | const INVALID_VTABLE_UB: W<&dyn Trait> = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:91:1 + | +LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; + | ^^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ + } + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs b/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs index 4ec853576c91b..4bb30b75bc8eb 100644 --- a/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs +++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs @@ -18,27 +18,79 @@ trait Trait {} const INVALID_VTABLE_ALIGNMENT: &dyn Trait = unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; //~^ ERROR evaluation of constant value failed -//~| invalid vtable: alignment `1000` is not a power of 2 +//~| does not point to a vtable const INVALID_VTABLE_SIZE: &dyn Trait = unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; //~^ ERROR evaluation of constant value failed -//~| invalid vtable: size is bigger than largest supported object +//~| does not point to a vtable #[repr(transparent)] struct W(T); -// The drop fn is checked before size/align are, so get ourselves a "sufficiently valid" drop fn fn drop_me(_: *mut usize) {} const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) }; //~^^ ERROR it is undefined behavior to use this value -//~| invalid vtable: alignment `1000` is not a power of 2 +//~| expected a vtable pointer const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) }; //~^^ ERROR it is undefined behavior to use this value -//~| invalid vtable: size is bigger than largest supported object +//~| expected a vtable pointer + +// Even if the vtable has a fn ptr and a reasonable size+align, it still does not work. +const INVALID_VTABLE_UB: W<&dyn Trait> = + unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1usize))) }; +//~^^ ERROR it is undefined behavior to use this value +//~| expected a vtable pointer + +// Trying to access the data in a vtable does not work, either. + +#[derive(Copy, Clone)] +struct Wide<'a>(&'a Foo, &'static VTable); + +struct VTable { + drop: Option fn(&'a mut Foo)>, + size: usize, + align: usize, + bar: for<'a> fn(&'a Foo) -> u32, +} + +trait Bar { + fn bar(&self) -> u32; +} + +struct Foo { + foo: u32, + bar: bool, +} + +impl Bar for Foo { + fn bar(&self) -> u32 { + self.foo + } +} + +impl Drop for Foo { + fn drop(&mut self) { + assert!(!self.bar); + self.bar = true; + println!("dropping Foo"); + } +} + +#[repr(C)] +union Transmute { + t: T, + u: U, +} + +const FOO: &dyn Bar = &Foo { foo: 128, bar: false }; +const G: Wide = unsafe { Transmute { t: FOO }.u }; +//~^ ERROR it is undefined behavior to use this value +//~| encountered a dangling reference +// (it is dangling because vtables do not contain memory that can be dereferenced) fn main() {} diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr index 2cae35bc4d0ed..ae114233c0f72 100644 --- a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr @@ -125,7 +125,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:56:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -147,7 +147,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:60:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x0000000d, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -158,7 +158,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:62:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc41, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr index e2cd0e64db806..1b93a869c0dd9 100644 --- a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr @@ -125,7 +125,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:56:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -147,7 +147,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:60:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x000000000000000d, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -158,7 +158,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:62:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc41, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { diff --git a/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr b/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr index 43f73f6ec7f27..f7898e55ee2c5 100644 --- a/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr @@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{ | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─alloc3──╼ ╾─alloc6──╼ │ ╾──╼╾──╼ + ╾─alloc3──╼ ╾─alloc4──╼ │ ╾──╼╾──╼ } error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr b/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr index 64185a0636297..60432380e1347 100644 --- a/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr @@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{ | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────alloc3────────╼ ╾───────alloc6────────╼ │ ╾──────╼╾──────╼ + ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼ } error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr index 2fd98ea322b02..ee27651dca03f 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr @@ -209,7 +209,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:117:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -220,7 +220,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:120:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -231,51 +231,36 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:123:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered dangling vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾allocN─╼ 04 00 00 00 │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:125:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:125:57 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered unaligned vtable pointer in wide pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼ - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:127:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:128:57 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼ - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:129:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:131:56 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼ - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:131:1 + --> $DIR/ub-wide-ptr.rs:134:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid drop function pointer in vtable (not pointing to a function) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -283,7 +268,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:135:1 + --> $DIR/ub-wide-ptr.rs:138:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..: encountered 0x03, but expected a boolean @@ -294,10 +279,10 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:139:1 + --> $DIR/ub-wide-ptr.rs:142:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -305,10 +290,10 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:141:1 + --> $DIR/ub-wide-ptr.rs:144:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -316,16 +301,16 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm } error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:147:5 + --> $DIR/ub-wide-ptr.rs:150:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:151:5 + --> $DIR/ub-wide-ptr.rs:154:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 12 bytes starting at offset N is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error: aborting due to 32 previous errors diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr index bae249076598e..84c323e87b6c8 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr @@ -209,7 +209,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:117:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -220,7 +220,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:120:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -231,51 +231,36 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:123:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered dangling vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾──────allocN───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:125:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:125:57 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered unaligned vtable pointer in wide pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼ - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:127:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:128:57 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼ - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:129:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:131:56 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼ - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:131:1 + --> $DIR/ub-wide-ptr.rs:134:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid drop function pointer in vtable (not pointing to a function) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -283,7 +268,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:135:1 + --> $DIR/ub-wide-ptr.rs:138:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..: encountered 0x03, but expected a boolean @@ -294,10 +279,10 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:139:1 + --> $DIR/ub-wide-ptr.rs:142:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -305,10 +290,10 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:141:1 + --> $DIR/ub-wide-ptr.rs:144:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -316,16 +301,16 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm } error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:147:5 + --> $DIR/ub-wide-ptr.rs:150:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:151:5 + --> $DIR/ub-wide-ptr.rs:154:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 24 bytes starting at offset N is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error: aborting due to 32 previous errors diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs index f2e5738f88c9f..9e3d349cd7eb0 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs @@ -123,11 +123,14 @@ const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8 const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; //~^ ERROR it is undefined behavior to use this value const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed +//~| does not point to a vtable const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed +//~| does not point to a vtable const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed +//~| does not point to a vtable const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; //~^ ERROR it is undefined behavior to use this value diff --git a/src/test/ui/consts/issue-79690.64bit.stderr b/src/test/ui/consts/issue-79690.64bit.stderr index c7aba55537088..b8798a9755fe2 100644 --- a/src/test/ui/consts/issue-79690.64bit.stderr +++ b/src/test/ui/consts/issue-79690.64bit.stderr @@ -2,11 +2,11 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-79690.rs:30:1 | LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; - | ^^^^^^^^^^^^ constructing invalid value at .1..size.foo: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + | ^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────alloc3────────╼ ╾───────alloc6────────╼ │ ╾──────╼╾──────╼ + ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼ } error: aborting due to previous error diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr index bb8636f1225ad..7ea35f70d108e 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr @@ -17,7 +17,7 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─alloc7──╼ ╾─alloc9──╼ │ ╾──╼╾──╼ + ╾─alloc7──╼ ╾─alloc8──╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value @@ -28,7 +28,7 @@ LL | const BLUNT: &mut i32 = &mut 42; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾─alloc11─╼ │ ╾──╼ + ╾─alloc10─╼ │ ╾──╼ } warning: skipping const checks diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr index f1652da922a57..5ad3989308909 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr @@ -17,7 +17,7 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────alloc7────────╼ ╾───────alloc9────────╼ │ ╾──────╼╾──────╼ + ╾───────alloc7────────╼ ╾───────alloc8────────╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value @@ -28,7 +28,7 @@ LL | const BLUNT: &mut i32 = &mut 42; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc11───────╼ │ ╾──────╼ + ╾───────alloc10───────╼ │ ╾──────╼ } warning: skipping const checks From b5a32d01f4cbc032efa093ff672f1e33087f0efb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 16:17:25 -0400 Subject: [PATCH 04/16] we seem to monomorphize fewer vtables by default now, so adjust some tests --- src/test/ui/traits/vtable/vtable-diamond.rs | 5 ++ .../ui/traits/vtable/vtable-multi-level.rs | 25 ++++++++- .../traits/vtable/vtable-multi-level.stderr | 51 ++++++++++++++----- src/test/ui/traits/vtable/vtable-multiple.rs | 2 + 4 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/test/ui/traits/vtable/vtable-diamond.rs b/src/test/ui/traits/vtable/vtable-diamond.rs index ec25e8a707111..dc3c17ac3144b 100644 --- a/src/test/ui/traits/vtable/vtable-diamond.rs +++ b/src/test/ui/traits/vtable/vtable-diamond.rs @@ -34,6 +34,11 @@ fn foo(d: &dyn D) { d.foo_d(); } +fn bar(d: &dyn C) { + d.foo_c(); +} + fn main() { foo(&S); + bar(&S); } diff --git a/src/test/ui/traits/vtable/vtable-multi-level.rs b/src/test/ui/traits/vtable/vtable-multi-level.rs index fcb5fd5274be4..ebd55bcf39b17 100644 --- a/src/test/ui/traits/vtable/vtable-multi-level.rs +++ b/src/test/ui/traits/vtable/vtable-multi-level.rs @@ -12,6 +12,7 @@ #[rustc_dump_vtable] trait A { + //~^ error vtable fn foo_a(&self) {} } @@ -23,6 +24,7 @@ trait B { #[rustc_dump_vtable] trait C: A + B { + //~^ error vtable fn foo_c(&self) {} } @@ -115,8 +117,27 @@ impl M for S {} impl N for S {} impl O for S {} -fn foo(_: &dyn O) {} +macro_rules! monomorphize_vtable { + ($trait:ident) => {{ + fn foo(_ : &dyn $trait) {} + foo(&S); + }} +} fn main() { - foo(&S); + monomorphize_vtable!(O); + + monomorphize_vtable!(A); + monomorphize_vtable!(B); + monomorphize_vtable!(C); + monomorphize_vtable!(D); + monomorphize_vtable!(E); + monomorphize_vtable!(F); + monomorphize_vtable!(H); + monomorphize_vtable!(I); + monomorphize_vtable!(J); + monomorphize_vtable!(K); + monomorphize_vtable!(L); + monomorphize_vtable!(M); + monomorphize_vtable!(N); } diff --git a/src/test/ui/traits/vtable/vtable-multi-level.stderr b/src/test/ui/traits/vtable/vtable-multi-level.stderr index d4d7a8fa3a470..c4389e23fc10f 100644 --- a/src/test/ui/traits/vtable/vtable-multi-level.stderr +++ b/src/test/ui/traits/vtable/vtable-multi-level.stderr @@ -29,29 +29,54 @@ error: vtable entries for ``: [ TraitVPtr(), Method(::foo_o), ] - --> $DIR/vtable-multi-level.rs:95:1 + --> $DIR/vtable-multi-level.rs:97:1 | LL | trait O: G + N { | ^^^^^^^^^^^^^^ +error: vtable entries for ``: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::foo_a), + ] + --> $DIR/vtable-multi-level.rs:14:1 + | +LL | trait A { + | ^^^^^^^ + error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(::foo_b), ] - --> $DIR/vtable-multi-level.rs:19:1 + --> $DIR/vtable-multi-level.rs:20:1 | LL | trait B { | ^^^^^^^ +error: vtable entries for ``: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::foo_a), + Method(::foo_b), + TraitVPtr(), + Method(::foo_c), + ] + --> $DIR/vtable-multi-level.rs:26:1 + | +LL | trait C: A + B { + | ^^^^^^^^^^^^^^ + error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(::foo_d), ] - --> $DIR/vtable-multi-level.rs:30:1 + --> $DIR/vtable-multi-level.rs:32:1 | LL | trait D { | ^^^^^^^ @@ -62,7 +87,7 @@ error: vtable entries for ``: [ MetadataAlign, Method(::foo_e), ] - --> $DIR/vtable-multi-level.rs:36:1 + --> $DIR/vtable-multi-level.rs:38:1 | LL | trait E { | ^^^^^^^ @@ -76,7 +101,7 @@ error: vtable entries for ``: [ TraitVPtr(), Method(::foo_f), ] - --> $DIR/vtable-multi-level.rs:42:1 + --> $DIR/vtable-multi-level.rs:44:1 | LL | trait F: D + E { | ^^^^^^^^^^^^^^ @@ -87,7 +112,7 @@ error: vtable entries for ``: [ MetadataAlign, Method(::foo_h), ] - --> $DIR/vtable-multi-level.rs:53:1 + --> $DIR/vtable-multi-level.rs:55:1 | LL | trait H { | ^^^^^^^ @@ -98,7 +123,7 @@ error: vtable entries for ``: [ MetadataAlign, Method(::foo_i), ] - --> $DIR/vtable-multi-level.rs:59:1 + --> $DIR/vtable-multi-level.rs:61:1 | LL | trait I { | ^^^^^^^ @@ -112,7 +137,7 @@ error: vtable entries for ``: [ TraitVPtr(), Method(::foo_j), ] - --> $DIR/vtable-multi-level.rs:65:1 + --> $DIR/vtable-multi-level.rs:67:1 | LL | trait J: H + I { | ^^^^^^^^^^^^^^ @@ -123,7 +148,7 @@ error: vtable entries for ``: [ MetadataAlign, Method(::foo_k), ] - --> $DIR/vtable-multi-level.rs:71:1 + --> $DIR/vtable-multi-level.rs:73:1 | LL | trait K { | ^^^^^^^ @@ -134,7 +159,7 @@ error: vtable entries for ``: [ MetadataAlign, Method(::foo_l), ] - --> $DIR/vtable-multi-level.rs:77:1 + --> $DIR/vtable-multi-level.rs:79:1 | LL | trait L { | ^^^^^^^ @@ -148,7 +173,7 @@ error: vtable entries for ``: [ TraitVPtr(), Method(::foo_m), ] - --> $DIR/vtable-multi-level.rs:83:1 + --> $DIR/vtable-multi-level.rs:85:1 | LL | trait M: K + L { | ^^^^^^^^^^^^^^ @@ -169,10 +194,10 @@ error: vtable entries for ``: [ TraitVPtr(), Method(::foo_n), ] - --> $DIR/vtable-multi-level.rs:89:1 + --> $DIR/vtable-multi-level.rs:91:1 | LL | trait N: J + M { | ^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors +error: aborting due to 14 previous errors diff --git a/src/test/ui/traits/vtable/vtable-multiple.rs b/src/test/ui/traits/vtable/vtable-multiple.rs index 8e7098a495ed1..7a0111c5ef251 100644 --- a/src/test/ui/traits/vtable/vtable-multiple.rs +++ b/src/test/ui/traits/vtable/vtable-multiple.rs @@ -25,7 +25,9 @@ impl B for S {} impl C for S {} fn foo(c: &dyn C) {} +fn bar(c: &dyn B) {} fn main() { foo(&S); + bar(&S); } From 8affef2ccba424f37445f6df6592426600d00a31 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 09:48:20 -0400 Subject: [PATCH 05/16] add intrinsic to access vtable size and align --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 14 ++++++++++ .../src/interpret/intrinsics.rs | 12 +++++++++ compiler/rustc_span/src/symbol.rs | 2 ++ compiler/rustc_typeck/src/check/intrinsic.rs | 4 +++ library/core/src/intrinsics.rs | 10 +++++++ library/core/src/ptr/metadata.rs | 26 +++++++++++++++++-- 6 files changed, 66 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 9f3647492877c..01e276ac90285 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -363,6 +363,20 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { return; } + sym::vtable_size | sym::vtable_align => { + let ptr = args[0].immediate(); + let layout = self.layout_of(self.tcx.types.usize); + let type_ = self.backend_type(layout); + let offset = match name { + sym::vtable_size => 1, + sym::vtable_align => 2, + _ => bug!(), + }; + let offset = self.const_int(type_, offset); + let vtable_field_ptr = self.inbounds_gep(type_, ptr, &[offset]); + self.load(type_, vtable_field_ptr, layout.align.abi) + } + _ if name.as_str().starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { Ok(llval) => llval, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 0f6eb2ecaa342..025f8647c95b5 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -492,6 +492,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let result = self.raw_eq_intrinsic(&args[0], &args[1])?; self.write_scalar(result, dest)?; } + + sym::vtable_size => { + let ptr = self.read_pointer(&args[0])?; + let (size, _align) = self.get_vtable_size_and_align(ptr)?; + self.write_scalar(Scalar::from_machine_usize(size.bytes(), self), dest)?; + } + sym::vtable_align => { + let ptr = self.read_pointer(&args[0])?; + let (_size, align) = self.get_vtable_size_and_align(ptr)?; + self.write_scalar(Scalar::from_machine_usize(align.bytes(), self), dest)?; + } + _ => return Ok(false), } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ec1d2c39b8092..a207927c9d299 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1564,6 +1564,8 @@ symbols! { volatile_store, vreg, vreg_low16, + vtable_align, + vtable_size, warn, wasm_abi, wasm_import_module, diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 7fe710cf8f4f2..3f2a0da8d6515 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -400,6 +400,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)), + sym::vtable_size | sym::vtable_align => { + (0, vec![tcx.mk_imm_ptr(tcx.mk_unit())], tcx.types.usize) + } + other => { tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other }); return; diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 998f7be3f7396..dc82b32214c37 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2291,6 +2291,16 @@ extern "rust-intrinsic" { /// [`std::hint::black_box`]: crate::hint::black_box #[rustc_const_unstable(feature = "const_black_box", issue = "none")] pub fn black_box(dummy: T) -> T; + + /// `ptr` must point to a vtable. + /// The intrinsic will return the size stored in that vtable. + #[cfg(not(bootstrap))] + pub fn vtable_size(ptr: *const ()) -> usize; + + /// `ptr` must point to a vtable. + /// The intrinsic will return the alignment stored in that vtable. + #[cfg(not(bootstrap))] + pub fn vtable_align(ptr: *const ()) -> usize; } // Some functions are defined here because they accidentally got made diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 287ae69acd198..fc0fd221b4022 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -180,10 +180,20 @@ pub struct DynMetadata { phantom: crate::marker::PhantomData, } +/// Opaque type for accessing vtables. +/// +/// Private implementation detail of `DynMetadata::size_of` etc. +/// Must be zero-sized since there is conceptually not actually any Abstract Machine memory behind this pointer. +/// However, we can require pointer alignment. +#[repr(C)] +#[cfg(not(bootstrap))] +struct VTable([usize; 0]); + /// The common prefix of all vtables. It is followed by function pointers for trait methods. /// /// Private implementation detail of `DynMetadata::size_of` etc. #[repr(C)] +#[cfg(bootstrap)] struct VTable { drop_in_place: fn(*mut ()), size_of: usize, @@ -194,13 +204,25 @@ impl DynMetadata { /// Returns the size of the type associated with this vtable. #[inline] pub fn size_of(self) -> usize { - self.vtable_ptr.size_of + #[cfg(bootstrap)] + return self.vtable_ptr.size_of; + #[cfg(not(bootstrap))] + // SAFETY: DynMetadata always contains a valid vtable pointer + return unsafe { + crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ()) + }; } /// Returns the alignment of the type associated with this vtable. #[inline] pub fn align_of(self) -> usize { - self.vtable_ptr.align_of + #[cfg(bootstrap)] + return self.vtable_ptr.align_of; + #[cfg(not(bootstrap))] + // SAFETY: DynMetadata always contains a valid vtable pointer + return unsafe { + crate::intrinsics::vtable_align(self.vtable_ptr as *const VTable as *const ()) + }; } /// Returns the size and alignment together as a `Layout` From 5e840c5c8c75081dda4b33f8afcb0c77ad3105bb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 19:50:04 -0400 Subject: [PATCH 06/16] incorporate some review feedback --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 15 +++++------ .../rustc_const_eval/src/interpret/cast.rs | 27 +++---------------- .../rustc_const_eval/src/interpret/memory.rs | 2 +- .../rustc_const_eval/src/interpret/traits.rs | 7 ++--- compiler/rustc_middle/src/mir/pretty.rs | 2 +- library/core/src/ptr/metadata.rs | 3 +++ 6 files changed, 18 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 01e276ac90285..9cca9bcf72467 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -10,6 +10,7 @@ use crate::value::Value; use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh}; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; +use rustc_codegen_ssa::meth; use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; @@ -364,17 +365,13 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { } sym::vtable_size | sym::vtable_align => { - let ptr = args[0].immediate(); - let layout = self.layout_of(self.tcx.types.usize); - let type_ = self.backend_type(layout); - let offset = match name { - sym::vtable_size => 1, - sym::vtable_align => 2, + let vtable = args[0].immediate(); + let idx = match name { + sym::vtable_size => ty::COMMON_VTABLE_ENTRIES_SIZE, + sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN, _ => bug!(), }; - let offset = self.const_int(type_, offset); - let vtable_field_ptr = self.inbounds_gep(type_, ptr, &[offset]); - self.load(type_, vtable_field_ptr, layout.align.abi) + meth::VirtualIndex::from_index(idx).get_usize(self, vtable) } _ if name.as_str().starts_with("simd_") => { diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 473ba848a5830..5d5c49c25a358 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -297,32 +297,11 @@ 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(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { - let val = self.read_immediate(src)?; - let (old_data, old_vptr) = val.to_scalar_pair()?; + (&ty::Dynamic(ref _data_a, ..), &ty::Dynamic(ref data_b, ..)) => { + let (old_data, old_vptr) = self.read_immediate(src)?.to_scalar_pair()?; let old_vptr = self.scalar_to_ptr(old_vptr)?; - if data_a.principal_def_id() == data_b.principal_def_id() { - return self.write_immediate(*val, dest); - } - // trait upcasting coercion - let Some(vptr_entry_idx) = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot(( - src_pointee_ty, - dest_pointee_ty, - )) else { - return self.write_immediate(*val, dest); - }; - let (ty, _) = self.get_ptr_vtable(old_vptr)?; - let Some(ty::VtblEntry::TraitVPtr(new_trait)) = self.get_vtable_entries(old_vptr)?.get(vptr_entry_idx) else { - throw_ub_format!( - "upcasting to index {vptr_entry_idx} of vtable {old_vptr} but \ - that vtable is too small or does not have an upcast-vtable at that index" - ) - }; - let new_trait = new_trait.map_bound(|trait_ref| { - ty::ExistentialTraitRef::erase_self_ty(*self.tcx, trait_ref) - }); - let new_vptr = self.get_vtable_ptr(ty, Some(new_trait))?; + let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) } (_, &ty::Dynamic(ref data, _)) => { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 5e49e6a4f0845..b07530753c552 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -875,7 +875,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, write!(fmt, " (vtable: impl {trait_ref} for {ty})")?; } Some(GlobalAlloc::Vtable(ty, None)) => { - write!(fmt, " (vtable: impl ? for {ty})")?; + write!(fmt, " (vtable: impl for {ty})")?; } Some(GlobalAlloc::Static(did)) => { write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?; diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index bddca2a20edec..b3a511d5a492b 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -10,9 +10,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for /// objects. /// - /// The `trait_ref` encodes the erased self type. Hence, if we are - /// making an object `Foo` from a value of type `Foo`, then - /// `trait_ref` would map `T: Trait`. + /// The `trait_ref` encodes the erased self type. Hence, if we are making an object `Foo` + /// from a value of type `Foo`, then `trait_ref` would map `T: Trait`. `None` here means that + /// this is an auto trait without any methods, so we only need the basic vtable (drop, size, + /// align). pub fn get_vtable_ptr( &self, ty: Ty<'tcx>, diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 013b67ea2b969..bd9e6a9141d47 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -728,7 +728,7 @@ pub fn write_allocations<'tcx>( Some(GlobalAlloc::Vtable(ty, Some(trait_ref))) => { write!(w, " (vtable: impl {trait_ref} for {ty})")? } - Some(GlobalAlloc::Vtable(ty, None)) => write!(w, " (vtable: impl ? for {ty})")?, + Some(GlobalAlloc::Vtable(ty, None)) => write!(w, " (vtable: impl for {ty})")?, Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { match tcx.eval_static_initializer(did) { Ok(alloc) => { diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index fc0fd221b4022..25cc852200a04 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -204,6 +204,9 @@ impl DynMetadata { /// Returns the size of the type associated with this vtable. #[inline] pub fn size_of(self) -> usize { + // Note that "size stored in vtable" is *not* the same as "result of size_of_val_raw". + // Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the + // `Send` part! #[cfg(bootstrap)] return self.vtable_ptr.size_of; #[cfg(not(bootstrap))] From 114da8499642b0b29d624c7e30c8f07e25933ff6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 19:57:25 -0400 Subject: [PATCH 07/16] use extern type for extra opaqueness --- library/core/src/ptr/metadata.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 25cc852200a04..2becaa8336254 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -180,14 +180,15 @@ pub struct DynMetadata { phantom: crate::marker::PhantomData, } -/// Opaque type for accessing vtables. -/// -/// Private implementation detail of `DynMetadata::size_of` etc. -/// Must be zero-sized since there is conceptually not actually any Abstract Machine memory behind this pointer. -/// However, we can require pointer alignment. -#[repr(C)] #[cfg(not(bootstrap))] -struct VTable([usize; 0]); +extern "C" { + /// Opaque type for accessing vtables. + /// + /// Private implementation detail of `DynMetadata::size_of` etc. + /// Must be zero-sized since there is conceptually not actually any Abstract Machine memory behind this pointer. + /// However, we can require pointer alignment. + type VTable; +} /// The common prefix of all vtables. It is followed by function pointers for trait methods. /// From 3dad266f4018a8356b8259012d09088520735b13 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 19:57:44 -0400 Subject: [PATCH 08/16] consistently use VTable over Vtable (matching stable stdlib API RawWakerVTable) --- .../rustc_codegen_cranelift/src/constant.rs | 8 ++++---- compiler/rustc_codegen_gcc/src/common.rs | 4 ++-- compiler/rustc_codegen_llvm/src/common.rs | 4 ++-- compiler/rustc_codegen_llvm/src/consts.rs | 2 +- .../src/debuginfo/metadata.rs | 2 +- .../src/debuginfo/metadata/type_map.rs | 6 +++--- compiler/rustc_codegen_ssa/src/base.rs | 2 +- compiler/rustc_codegen_ssa/src/meth.rs | 4 ++-- .../rustc_const_eval/src/interpret/memory.rs | 20 +++++++++---------- .../src/interpret/terminator.rs | 2 +- .../src/interpret/validity.rs | 2 +- .../rustc_middle/src/mir/interpret/error.rs | 8 ++++---- .../rustc_middle/src/mir/interpret/mod.rs | 20 +++++++++---------- compiler/rustc_middle/src/mir/mono.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 6 ++++-- compiler/rustc_middle/src/mir/visit.rs | 2 +- compiler/rustc_middle/src/ty/instance.rs | 14 ++++++------- compiler/rustc_middle/src/ty/layout.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- .../rustc_middle/src/ty/structural_impls.rs | 6 +++--- compiler/rustc_mir_transform/src/inline.rs | 2 +- .../rustc_mir_transform/src/inline/cycle.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 6 +++--- compiler/rustc_monomorphize/src/collector.rs | 6 +++--- .../src/partitioning/default.rs | 4 ++-- compiler/rustc_query_impl/src/lib.rs | 2 +- compiler/rustc_query_impl/src/plumbing.rs | 4 ++-- .../rustc_query_system/src/query/config.rs | 6 +++--- compiler/rustc_query_system/src/query/mod.rs | 2 +- .../rustc_query_system/src/query/plumbing.rs | 12 +++++------ compiler/rustc_symbol_mangling/src/legacy.rs | 4 ++-- compiler/rustc_symbol_mangling/src/v0.rs | 2 +- compiler/rustc_typeck/src/check/cast.rs | 6 +++--- 34 files changed, 90 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index a1508d7c72b42..2380f3e1df022 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -197,7 +197,7 @@ pub(crate) fn codegen_const_value<'tcx>( let (alloc_id, offset) = ptr.into_parts(); // we know the `offset` is relative // For vtables, get the underlying data allocation. let alloc_id = match fx.tcx.global_alloc(alloc_id) { - GlobalAlloc::Vtable(ty, trait_ref) => fx.tcx.vtable_allocation((ty, trait_ref)), + GlobalAlloc::VTable(ty, trait_ref) => fx.tcx.vtable_allocation((ty, trait_ref)), _ => alloc_id, }; let base_addr = match fx.tcx.global_alloc(alloc_id) { @@ -221,7 +221,7 @@ pub(crate) fn codegen_const_value<'tcx>( fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); fx.bcx.ins().func_addr(fx.pointer_type, local_func_id) } - GlobalAlloc::Vtable(..) => bug!("vtables are already handled"), + GlobalAlloc::VTable(..) => bug!("vtables are already handled"), GlobalAlloc::Static(def_id) => { assert!(fx.tcx.is_static(def_id)); let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); @@ -364,7 +364,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant //println!("alloc_id {}", alloc_id); let alloc = match tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => alloc, - GlobalAlloc::Function(_) | GlobalAlloc::Static(_) | GlobalAlloc::Vtable(..) => { + GlobalAlloc::Function(_) | GlobalAlloc::Static(_) | GlobalAlloc::VTable(..) => { unreachable!() } }; @@ -442,7 +442,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant GlobalAlloc::Memory(target_alloc) => { data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability) } - GlobalAlloc::Vtable(ty, trait_ref) => { + GlobalAlloc::VTable(ty, trait_ref) => { let alloc_id = tcx.vtable_allocation((ty, trait_ref)); data_id_for_alloc_id(cx, module, alloc_id, Mutability::Not) } diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 3868f2f7a4951..d1afca18427d6 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -185,7 +185,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let (alloc_id, offset) = ptr.into_parts(); // For vtables, get the underlying data allocation. let alloc_id = match self.tcx.global_alloc(alloc_id) { - GlobalAlloc::Vtable(ty, trait_ref) => { + GlobalAlloc::VTable(ty, trait_ref) => { self.tcx.vtable_allocation((ty, trait_ref)) } _ => alloc_id, @@ -208,7 +208,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { GlobalAlloc::Function(fn_instance) => { self.get_fn_addr(fn_instance) }, - GlobalAlloc::Vtable(..) => panic!("vtables are already handled"), + GlobalAlloc::VTable(..) => panic!("vtables are already handled"), GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); self.get_static(def_id).get_address(None) diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index b465f65fcab30..f83b359743802 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -242,7 +242,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { let (alloc_id, offset) = ptr.into_parts(); // For vtables, get the underlying data allocation. let alloc_id = match self.tcx.global_alloc(alloc_id) { - GlobalAlloc::Vtable(ty, trait_ref) => { + GlobalAlloc::VTable(ty, trait_ref) => { self.tcx.vtable_allocation((ty, trait_ref)) } _ => alloc_id, @@ -264,7 +264,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.get_fn_addr(fn_instance.polymorphize(self.tcx)), self.data_layout().instruction_address_space, ), - GlobalAlloc::Vtable(..) => bug!("vtables are already handled"), + GlobalAlloc::VTable(..) => bug!("vtables are already handled"), GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); assert!(!self.tcx.is_thread_local_static(def_id)); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 1fef22796ddad..863f1f09a16dc 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -101,7 +101,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation< let address_space = match cx.tcx.global_alloc(alloc_id) { GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space, - GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::Vtable(..) => { + GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => { AddressSpace::DATA } }; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index f8bd2d234f32a..bd84100e0e883 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1420,7 +1420,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>( cx, type_map::stub( cx, - Stub::VtableTy { vtable_holder }, + Stub::VTableTy { vtable_holder }, unique_type_id, &vtable_type_name, (size, pointer_align), diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index 8fc8118849bae..ce2f419c4acdc 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -146,7 +146,7 @@ impl<'ll> DINodeCreationResult<'ll> { pub enum Stub<'ll> { Struct, Union, - VtableTy { vtable_holder: &'ll DIType }, + VTableTy { vtable_holder: &'ll DIType }, } pub struct StubInfo<'ll, 'tcx> { @@ -180,9 +180,9 @@ pub(super) fn stub<'ll, 'tcx>( let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx); let metadata = match kind { - Stub::Struct | Stub::VtableTy { .. } => { + Stub::Struct | Stub::VTableTy { .. } => { let vtable_holder = match kind { - Stub::VtableTy { vtable_holder } => Some(vtable_holder), + Stub::VTableTy { vtable_holder } => Some(vtable_holder), _ => None, }; unsafe { diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 7def30af2b309..d95194e320be1 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -171,7 +171,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ); let new_vptr = bx.load(ptr_ty, gep, ptr_align); bx.nonnull_metadata(new_vptr); - // Vtable loads are invariant. + // VTable loads are invariant. bx.set_invariant_load(new_vptr); new_vptr } else { diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index df42d80456690..27d791d90a51a 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -39,7 +39,7 @@ impl<'a, 'tcx> VirtualIndex { let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]); let ptr = bx.load(llty, gep, ptr_align); bx.nonnull_metadata(ptr); - // Vtable loads are invariant. + // VTable loads are invariant. bx.set_invariant_load(ptr); ptr } @@ -58,7 +58,7 @@ impl<'a, 'tcx> VirtualIndex { let usize_align = bx.tcx().data_layout.pointer_align.abi; let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]); let ptr = bx.load(llty, gep, usize_align); - // Vtable loads are invariant. + // VTable loads are invariant. bx.set_invariant_load(ptr); ptr } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index b07530753c552..86914f50383e8 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -63,7 +63,7 @@ pub enum AllocKind { /// A function allocation (that fn ptrs point to). Function, /// A (symbolic) vtable allocation. - Vtable, + VTable, /// A dead allocation. Dead, } @@ -293,7 +293,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Some(GlobalAlloc::Function(..)) => { err_ub_format!("deallocating {alloc_id:?}, which is a function") } - Some(GlobalAlloc::Vtable(..)) => { + Some(GlobalAlloc::VTable(..)) => { err_ub_format!("deallocating {alloc_id:?}, which is a vtable") } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { @@ -484,7 +484,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (mem, None) } Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)), - Some(GlobalAlloc::Vtable(..)) => throw_ub!(DerefVtablePointer(id)), + Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), None => throw_ub!(PointerUseAfterFree(id)), Some(GlobalAlloc::Static(def_id)) => { assert!(self.tcx.is_static(def_id)); @@ -688,9 +688,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (alloc.size(), alloc.align, AllocKind::LiveData) } Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), - Some(GlobalAlloc::Vtable(..)) => { + Some(GlobalAlloc::VTable(..)) => { // No data to be accessed here. But vtables are pointer-aligned. - return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::Vtable); + return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::VTable); } // The rest must be dead. None => { @@ -746,11 +746,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { trace!("get_ptr_vtable({:?})", ptr); let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?; if offset.bytes() != 0 { - throw_ub!(InvalidVtablePointer(Pointer::new(alloc_id, offset))) + throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))) } match self.tcx.try_get_global_alloc(alloc_id) { - Some(GlobalAlloc::Vtable(ty, trait_ref)) => Ok((ty, trait_ref)), - _ => throw_ub!(InvalidVtablePointer(Pointer::new(alloc_id, offset))), + Some(GlobalAlloc::VTable(ty, trait_ref)) => Ok((ty, trait_ref)), + _ => throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))), } } @@ -871,10 +871,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, Some(GlobalAlloc::Function(func)) => { write!(fmt, " (fn: {func})")?; } - Some(GlobalAlloc::Vtable(ty, Some(trait_ref))) => { + Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => { write!(fmt, " (vtable: impl {trait_ref} for {ty})")?; } - Some(GlobalAlloc::Vtable(ty, None)) => { + Some(GlobalAlloc::VTable(ty, None)) => { write!(fmt, " (vtable: impl for {ty})")?; } Some(GlobalAlloc::Static(did)) => { diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 2ae0e1a6f5ac7..90e06f55cbf57 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -364,7 +364,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic. M::call_intrinsic(self, instance, args, destination, target, unwind) } - ty::InstanceDef::VtableShim(..) + ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::FnPtrShim(..) diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 190eb732f9ad3..f2e104da04a41 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -318,7 +318,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' self.ecx.get_ptr_vtable(vtable), self.path, err_ub!(DanglingIntPointer(..)) | - err_ub!(InvalidVtablePointer(..)) => + err_ub!(InvalidVTablePointer(..)) => { "{vtable}" } expected { "a vtable pointer" }, ); // FIXME: check if the type/trait match what ty::Dynamic says? diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 81d9db98478f9..cecb55578d332 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -266,7 +266,7 @@ pub enum UndefinedBehaviorInfo { // Trying to access the data behind a function pointer. DerefFunctionPointer(AllocId), // Trying to access the data behind a vtable pointer. - DerefVtablePointer(AllocId), + DerefVTablePointer(AllocId), /// The value validity check found a problem. /// Should only be thrown by `validity.rs` and always point out which part of the value /// is the problem. @@ -285,7 +285,7 @@ pub enum UndefinedBehaviorInfo { /// Using a pointer-not-to-a-function as function pointer. InvalidFunctionPointer(Pointer), /// Using a pointer-not-to-a-vtable as vtable pointer. - InvalidVtablePointer(Pointer), + InvalidVTablePointer(Pointer), /// Using a string that is not valid UTF-8, InvalidStr(std::str::Utf8Error), /// Using uninitialized data where it is not allowed. @@ -349,7 +349,7 @@ impl fmt::Display for UndefinedBehaviorInfo { ), WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"), DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"), - DerefVtablePointer(a) => write!(f, "accessing {a:?} which contains a vtable"), + DerefVTablePointer(a) => write!(f, "accessing {a:?} which contains a vtable"), ValidationFailure { path: None, msg } => { write!(f, "constructing invalid value: {msg}") } @@ -366,7 +366,7 @@ impl fmt::Display for UndefinedBehaviorInfo { InvalidFunctionPointer(p) => { write!(f, "using {p:?} as function pointer but it does not point to a function") } - InvalidVtablePointer(p) => { + InvalidVTablePointer(p) => { write!(f, "using {p:?} as vtable pointer but it does not point to a vtable") } InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"), diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 9b0fe593cfc88..7ef4dfe7c0dd8 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -196,7 +196,7 @@ impl fmt::Debug for AllocId { enum AllocDiscriminant { Alloc, Fn, - Vtable, + VTable, Static, } @@ -216,9 +216,9 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder>>( AllocDiscriminant::Fn.encode(encoder); fn_instance.encode(encoder); } - GlobalAlloc::Vtable(ty, poly_trait_ref) => { + GlobalAlloc::VTable(ty, poly_trait_ref) => { trace!("encoding {:?} with {ty:#?}, {poly_trait_ref:#?}", alloc_id); - AllocDiscriminant::Vtable.encode(encoder); + AllocDiscriminant::VTable.encode(encoder); ty.encode(encoder); poly_trait_ref.encode(encoder); } @@ -314,7 +314,7 @@ impl<'s> AllocDecodingSession<'s> { } AllocDiscriminant::Fn | AllocDiscriminant::Static - | AllocDiscriminant::Vtable => { + | AllocDiscriminant::VTable => { // Fns and statics cannot be cyclic, and their `AllocId` // is determined later by interning. *entry = @@ -364,7 +364,7 @@ impl<'s> AllocDecodingSession<'s> { let alloc_id = decoder.interner().create_fn_alloc(instance); alloc_id } - AllocDiscriminant::Vtable => { + AllocDiscriminant::VTable => { assert!(alloc_id.is_none()); trace!("creating static alloc ID"); let ty = as Decodable>::decode(decoder); @@ -400,7 +400,7 @@ pub enum GlobalAlloc<'tcx> { /// The alloc ID is used as a function pointer. Function(Instance<'tcx>), /// This alloc ID points to a symbolic (not-reified) vtable. - Vtable(Ty<'tcx>, Option>), + VTable(Ty<'tcx>, Option>), /// The alloc ID points to a "lazy" static variable that did not get computed (yet). /// This is also used to break the cycle in recursive statics. Static(DefId), @@ -429,12 +429,12 @@ impl<'tcx> GlobalAlloc<'tcx> { } } - /// Panics if the `GlobalAlloc` is not `GlobalAlloc::Vtable` + /// Panics if the `GlobalAlloc` is not `GlobalAlloc::VTable` #[track_caller] #[inline] pub fn unwrap_vtable(&self) -> (Ty<'tcx>, Option>) { match *self { - GlobalAlloc::Vtable(ty, poly_trait_ref) => (ty, poly_trait_ref), + GlobalAlloc::VTable(ty, poly_trait_ref) => (ty, poly_trait_ref), _ => bug!("expected vtable, got {:?}", self), } } @@ -490,7 +490,7 @@ impl<'tcx> TyCtxt<'tcx> { fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId { let mut alloc_map = self.alloc_map.lock(); match alloc { - GlobalAlloc::Function(..) | GlobalAlloc::Static(..) | GlobalAlloc::Vtable(..) => {} + GlobalAlloc::Function(..) | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {} GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"), } if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) { @@ -541,7 +541,7 @@ impl<'tcx> TyCtxt<'tcx> { ty: Ty<'tcx>, poly_trait_ref: Option>, ) -> AllocId { - self.reserve_and_set_dedup(GlobalAlloc::Vtable(ty, poly_trait_ref)) + self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref)) } /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 8b51c5b3da50a..21ae121e1ce69 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -362,7 +362,7 @@ impl<'tcx> CodegenUnit<'tcx> { // the codegen tests and can even make item order // unstable. InstanceDef::Item(def) => def.did.as_local().map(Idx::index), - InstanceDef::VtableShim(..) + InstanceDef::VTableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::Intrinsic(..) | InstanceDef::FnPtrShim(..) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index bd9e6a9141d47..78b5131bac65e 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -725,10 +725,12 @@ pub fn write_allocations<'tcx>( // gracefully handle it and allow buggy rustc to be debugged via allocation printing. None => write!(w, " (deallocated)")?, Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {inst})")?, - Some(GlobalAlloc::Vtable(ty, Some(trait_ref))) => { + Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => { write!(w, " (vtable: impl {trait_ref} for {ty})")? } - Some(GlobalAlloc::Vtable(ty, None)) => write!(w, " (vtable: impl for {ty})")?, + Some(GlobalAlloc::VTable(ty, None)) => { + write!(w, " (vtable: impl for {ty})")? + } Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { match tcx.eval_static_initializer(did) { Ok(alloc) => { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index d285728ec0783..891608764017c 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -394,7 +394,7 @@ macro_rules! make_mir_visitor { ty::InstanceDef::Item(_def_id) => {} ty::InstanceDef::Intrinsic(_def_id) | - ty::InstanceDef::VtableShim(_def_id) | + ty::InstanceDef::VTableShim(_def_id) | ty::InstanceDef::ReifyShim(_def_id) | ty::InstanceDef::Virtual(_def_id, _) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 4f9bbc135ec12..33a46f809b0d3 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -49,7 +49,7 @@ pub enum InstanceDef<'tcx> { /// /// The generated shim will take `Self` via `*mut Self` - conceptually this is `&owned Self` - /// and dereference the argument to call the original function. - VtableShim(DefId), + VTableShim(DefId), /// `fn()` pointer where the function itself cannot be turned into a pointer. /// @@ -145,7 +145,7 @@ impl<'tcx> InstanceDef<'tcx> { pub fn def_id(self) -> DefId { match self { InstanceDef::Item(def) => def.did, - InstanceDef::VtableShim(def_id) + InstanceDef::VTableShim(def_id) | InstanceDef::ReifyShim(def_id) | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) @@ -161,7 +161,7 @@ impl<'tcx> InstanceDef<'tcx> { match self { ty::InstanceDef::Item(def) => Some(def.did), ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id), - InstanceDef::VtableShim(..) + InstanceDef::VTableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) | InstanceDef::Virtual(..) @@ -176,7 +176,7 @@ impl<'tcx> InstanceDef<'tcx> { pub fn with_opt_param(self) -> ty::WithOptConstParam { match self { InstanceDef::Item(def) => def, - InstanceDef::VtableShim(def_id) + InstanceDef::VTableShim(def_id) | InstanceDef::ReifyShim(def_id) | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) @@ -273,7 +273,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Intrinsic(..) | InstanceDef::ReifyShim(..) | InstanceDef::Virtual(..) - | InstanceDef::VtableShim(..) => true, + | InstanceDef::VTableShim(..) => true, } } } @@ -290,7 +290,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> { match self.def { InstanceDef::Item(_) => Ok(()), - InstanceDef::VtableShim(_) => write!(f, " - shim(vtable)"), + InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"), InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"), InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"), InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num), @@ -434,7 +434,7 @@ impl<'tcx> Instance<'tcx> { && tcx.generics_of(def_id).has_self; if is_vtable_shim { debug!(" => associated item with unsizeable self: Self"); - Some(Instance { def: InstanceDef::VtableShim(def_id), substs }) + Some(Instance { def: InstanceDef::VTableShim(def_id), substs }) } else { Instance::resolve(tcx, param_env, def_id, substs).ok().flatten().map(|mut resolved| { match resolved.def { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 4491965347bd6..ab76ad5098413 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2771,7 +2771,7 @@ impl<'tcx> ty::Instance<'tcx> { _ => unreachable!(), }; - if let ty::InstanceDef::VtableShim(..) = self.def { + if let ty::InstanceDef::VTableShim(..) = self.def { // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. sig = sig.map_bound(|mut sig| { let mut inputs_and_output = sig.inputs_and_output.to_vec(); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 53919826bf617..78a0e24063ca5 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2135,7 +2135,7 @@ impl<'tcx> TyCtxt<'tcx> { } } } - ty::InstanceDef::VtableShim(..) + ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::FnPtrShim(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 43abed847e000..09b9c80669128 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1287,7 +1287,7 @@ pub trait PrettyPrinter<'tcx>: p!(write("", def_id)) } Some(GlobalAlloc::Function(_)) => p!(""), - Some(GlobalAlloc::Vtable(..)) => p!(""), + Some(GlobalAlloc::VTable(..)) => p!(""), None => p!(""), } return Ok(self); diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 391a0a20c9662..a4be3d02d1935 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -624,7 +624,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { match self { ty::InstanceDef::Item(def_id) => Some(ty::InstanceDef::Item(def_id)), - ty::InstanceDef::VtableShim(def_id) => Some(ty::InstanceDef::VtableShim(def_id)), + ty::InstanceDef::VTableShim(def_id) => Some(ty::InstanceDef::VTableShim(def_id)), ty::InstanceDef::ReifyShim(def_id) => Some(ty::InstanceDef::ReifyShim(def_id)), ty::InstanceDef::Intrinsic(def_id) => Some(ty::InstanceDef::Intrinsic(def_id)), ty::InstanceDef::FnPtrShim(def_id, ty) => { @@ -927,7 +927,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { substs: self.substs.try_fold_with(folder)?, def: match self.def { Item(def) => Item(def.try_fold_with(folder)?), - VtableShim(did) => VtableShim(did.try_fold_with(folder)?), + VTableShim(did) => VTableShim(did.try_fold_with(folder)?), ReifyShim(did) => ReifyShim(did.try_fold_with(folder)?), Intrinsic(did) => Intrinsic(did.try_fold_with(folder)?), FnPtrShim(did, ty) => { @@ -954,7 +954,7 @@ impl<'tcx> TypeVisitable<'tcx> for ty::instance::Instance<'tcx> { self.substs.visit_with(visitor)?; match self.def { Item(def) => def.visit_with(visitor), - VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => { + VTableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => { did.visit_with(visitor) } FnPtrShim(did, ty) | CloneShim(did, ty) => { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index dc5d5cee879f8..1e46b0a0e8164 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -246,7 +246,7 @@ impl<'tcx> Inliner<'tcx> { // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we // do not need to catch this here, we can wait until the inliner decides to continue // inlining a second time. - InstanceDef::VtableShim(_) + InstanceDef::VTableShim(_) | InstanceDef::ReifyShim(_) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index a3a35f95071e9..7810218fd6744 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -79,7 +79,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( // These have MIR and if that MIR is inlined, substituted and then inlining is run // again, a function item can end up getting inlined. Thus we'll be able to cause // a cycle that way - InstanceDef::VtableShim(_) + InstanceDef::VTableShim(_) | InstanceDef::ReifyShim(_) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index eaa61d8614d8c..3620e94bec7d7 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -32,7 +32,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' let mut result = match instance { ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), - ty::InstanceDef::VtableShim(def_id) => { + ty::InstanceDef::VTableShim(def_id) => { build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id)) } ty::InstanceDef::FnPtrShim(def_id, ty) => { @@ -113,7 +113,7 @@ enum Adjustment { /// We get passed `&[mut] self` and call the target with `*self`. /// /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it - /// (for `VtableShim`, which effectively is passed `&own Self`). + /// (for `VTableShim`, which effectively is passed `&own Self`). Deref, /// We get passed `self: Self` and call the target with `&mut self`. @@ -569,7 +569,7 @@ fn build_call_shim<'tcx>( // FIXME(eddyb) avoid having this snippet both here and in // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?). - if let ty::InstanceDef::VtableShim(..) = instance { + if let ty::InstanceDef::VTableShim(..) = instance { // Modify fn(self, ...) to fn(self: *mut Self, ...) let mut inputs_and_output = sig.inputs_and_output.to_vec(); let self_arg = &mut inputs_and_output[0]; diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 3cee9a460c126..86331056d4440 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -25,7 +25,7 @@ //! codegen unit: //! //! - Constants -//! - Vtables +//! - VTables //! - Object Shims //! //! @@ -992,7 +992,7 @@ fn visit_instance_use<'tcx>( } } ty::InstanceDef::DropGlue(_, Some(_)) - | ty::InstanceDef::VtableShim(..) + | ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Item(..) @@ -1427,7 +1427,7 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIte output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); } } - GlobalAlloc::Vtable(ty, trait_ref) => { + GlobalAlloc::VTable(ty, trait_ref) => { // FIXME(RJ) no ideas if this is correct. There is this nice // `create_mono_items_for_vtable_methods` method but I wouldn't know how to call it from // here. So instead we just generate the actual vtable and recurse. diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index d18b1c26c174f..15276569c32f5 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -271,7 +271,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( MonoItem::Fn(instance) => { let def_id = match instance.def { ty::InstanceDef::Item(def) => def.did, - ty::InstanceDef::VtableShim(..) + ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::ClosureOnceShim { .. } @@ -425,7 +425,7 @@ fn mono_item_visibility<'tcx>( InstanceDef::DropGlue(def_id, Some(_)) => def_id, // These are all compiler glue and such, never exported, always hidden. - InstanceDef::VtableShim(..) + InstanceDef::VTableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) | InstanceDef::Virtual(..) diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 7c1fdc4e306a4..eda61df7700d7 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -37,7 +37,7 @@ mod values; use self::values::Value; pub use rustc_query_system::query::QueryConfig; -pub(crate) use rustc_query_system::query::{QueryDescription, QueryVtable}; +pub(crate) use rustc_query_system::query::{QueryDescription, QueryVTable}; mod on_disk_cache; pub use on_disk_cache::OnDiskCache; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 333dc5aa668b0..eda4401c81d01 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -340,11 +340,11 @@ macro_rules! define_queries { #[inline] fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) -> - QueryVtable, Self::Key, Self::Value> + QueryVTable, Self::Key, Self::Value> { let compute = get_provider!([$($modifiers)*][tcx, $name, key]); let cache_on_disk = Self::cache_on_disk(tcx.tcx, key); - QueryVtable { + QueryVTable { anon: is_anon!([$($modifiers)*]), eval_always: is_eval_always!([$($modifiers)*]), dep_kind: dep_graph::DepKind::$name, diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index 7ca668f8a1f06..964914a1326bd 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -19,7 +19,7 @@ pub trait QueryConfig { type Stored: Clone; } -pub struct QueryVtable { +pub struct QueryVTable { pub anon: bool, pub dep_kind: CTX::DepKind, pub eval_always: bool, @@ -31,7 +31,7 @@ pub struct QueryVtable { pub try_load_from_disk: Option Option>, } -impl QueryVtable { +impl QueryVTable { pub(crate) fn to_dep_node(&self, tcx: CTX::DepContext, key: &K) -> DepNode where K: crate::dep_graph::DepNodeParams, @@ -69,7 +69,7 @@ pub trait QueryDescription: QueryConfig { CTX: 'a; // Don't use this method to compute query results, instead use the methods on TyCtxt - fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVtable; + fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVTable; fn cache_on_disk(tcx: CTX::DepContext, key: &Self::Key) -> bool; } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index f698a853d1e7b..fb2258434f4d3 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -12,7 +12,7 @@ pub use self::caches::{ }; mod config; -pub use self::config::{QueryConfig, QueryDescription, QueryVtable}; +pub use self::config::{QueryConfig, QueryDescription, QueryVTable}; use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 792f2b0317357..5e8ea07d00f99 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -4,7 +4,7 @@ use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams}; use crate::query::caches::QueryCache; -use crate::query::config::{QueryDescription, QueryVtable}; +use crate::query::config::{QueryDescription, QueryVTable}; use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo}; use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame}; use rustc_data_structures::fingerprint::Fingerprint; @@ -331,7 +331,7 @@ fn try_execute_query( span: Span, key: C::Key, dep_node: Option>, - query: &QueryVtable, + query: &QueryVTable, ) -> (C::Stored, Option) where C: QueryCache, @@ -368,7 +368,7 @@ fn execute_job( tcx: CTX, key: K, mut dep_node_opt: Option>, - query: &QueryVtable, + query: &QueryVTable, job_id: QueryJobId, ) -> (V, DepNodeIndex) where @@ -437,7 +437,7 @@ fn try_load_from_disk_and_cache_in_memory( tcx: CTX, key: &K, dep_node: &DepNode, - query: &QueryVtable, + query: &QueryVTable, ) -> Option<(V, DepNodeIndex)> where K: Clone, @@ -530,7 +530,7 @@ fn incremental_verify_ich( tcx: CTX::DepContext, result: &V, dep_node: &DepNode, - query: &QueryVtable, + query: &QueryVTable, ) where CTX: QueryContext, { @@ -642,7 +642,7 @@ fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: D fn ensure_must_run( tcx: CTX, key: &K, - query: &QueryVtable, + query: &QueryVTable, ) -> (bool, Option>) where K: crate::dep_graph::DepNodeParams, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index e3045c9321d1c..9241fd82c745f 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -67,7 +67,7 @@ pub(super) fn mangle<'tcx>( ) .unwrap(); - if let ty::InstanceDef::VtableShim(..) = instance.def { + if let ty::InstanceDef::VTableShim(..) = instance.def { let _ = printer.write_str("{{vtable-shim}}"); } @@ -129,7 +129,7 @@ fn get_symbol_hash<'tcx>( } // We want to avoid accidental collision between different types of instances. - // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original + // Especially, `VTableShim`s and `ReifyShim`s may overlap with their original // instances without this. discriminant(&instance.def).hash_stable(hcx, &mut hasher); }); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 13229a3995c22..79e3f10526c99 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -42,7 +42,7 @@ pub(super) fn mangle<'tcx>( // Append `::{shim:...#0}` to shims that can coexist with a non-shim instance. let shim_kind = match instance.def { - ty::InstanceDef::VtableShim(_) => Some("vtable"), + ty::InstanceDef::VTableShim(_) => Some("vtable"), ty::InstanceDef::ReifyShim(_) => Some("reify"), _ => None, diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 66dd558249052..7aaddc2bd7aab 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -69,7 +69,7 @@ enum PointerKind<'tcx> { /// No metadata attached, ie pointer to sized type or foreign type Thin, /// A trait object - Vtable(Option), + VTable(Option), /// Slice Length, /// The unsize info of this projection @@ -102,7 +102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(match *t.kind() { ty::Slice(_) | ty::Str => Some(PointerKind::Length), - ty::Dynamic(ref tty, ..) => Some(PointerKind::Vtable(tty.principal_def_id())), + ty::Dynamic(ref tty, ..) => Some(PointerKind::VTable(tty.principal_def_id())), ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().fields.last() { None => Some(PointerKind::Thin), Some(f) => { @@ -951,7 +951,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { match fcx.pointer_kind(m_cast.ty, self.span)? { None => Err(CastError::UnknownCastPtrKind), Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast), - Some(PointerKind::Vtable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))), + Some(PointerKind::VTable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))), Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))), Some( PointerKind::OfProjection(_) From adf6d37d83500f7a39f55c64f380e7dbdb221511 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 20:19:15 -0400 Subject: [PATCH 09/16] slightly cleaner, if more verbose, vtable handling in codegen backends --- .../rustc_codegen_cranelift/src/constant.rs | 20 +++++++++++++------ compiler/rustc_codegen_gcc/src/common.rs | 13 +++++------- compiler/rustc_codegen_llvm/src/common.rs | 17 ++++++++-------- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 2380f3e1df022..b5a143485893f 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -195,11 +195,6 @@ pub(crate) fn codegen_const_value<'tcx>( } Scalar::Ptr(ptr, _size) => { let (alloc_id, offset) = ptr.into_parts(); // we know the `offset` is relative - // For vtables, get the underlying data allocation. - let alloc_id = match fx.tcx.global_alloc(alloc_id) { - GlobalAlloc::VTable(ty, trait_ref) => fx.tcx.vtable_allocation((ty, trait_ref)), - _ => alloc_id, - }; let base_addr = match fx.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { let data_id = data_id_for_alloc_id( @@ -221,7 +216,20 @@ pub(crate) fn codegen_const_value<'tcx>( fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); fx.bcx.ins().func_addr(fx.pointer_type, local_func_id) } - GlobalAlloc::VTable(..) => bug!("vtables are already handled"), + GlobalAlloc::VTable(ty, trait_ref) => { + let alloc_id = fx.tcx.vtable_allocation((ty, trait_ref)); + let alloc = fx.tcx.global_alloc(alloc_id).unwrap_memory(); + // FIXME: factor this common code with the `Memory` arm into a function? + let data_id = data_id_for_alloc_id( + &mut fx.constants_cx, + fx.module, + alloc_id, + alloc.inner().mutability, + ); + let local_data_id = + fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + fx.bcx.ins().global_value(fx.pointer_type, local_data_id) + } GlobalAlloc::Static(def_id) => { assert!(fx.tcx.is_static(def_id)); let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index d1afca18427d6..ccb6cbbc2c8a7 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -183,13 +183,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } Scalar::Ptr(ptr, _size) => { let (alloc_id, offset) = ptr.into_parts(); - // For vtables, get the underlying data allocation. - let alloc_id = match self.tcx.global_alloc(alloc_id) { - GlobalAlloc::VTable(ty, trait_ref) => { - self.tcx.vtable_allocation((ty, trait_ref)) - } - _ => alloc_id, - }; let base_addr = match self.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { @@ -208,7 +201,11 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { GlobalAlloc::Function(fn_instance) => { self.get_fn_addr(fn_instance) }, - GlobalAlloc::VTable(..) => panic!("vtables are already handled"), + GlobalAlloc::VTable(ty, trait_ref) => { + let alloc = self.tcx.global_alloc(self.tcx.vtable_allocation((ty, trait_ref))).unwrap_memory(); + let init = const_alloc_to_gcc(self, alloc); + self.static_addr_of(init, alloc.inner().align, None) + } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); self.get_static(def_id).get_address(None) diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index f83b359743802..fb4da9a5f3370 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -240,13 +240,6 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { } Scalar::Ptr(ptr, _size) => { let (alloc_id, offset) = ptr.into_parts(); - // For vtables, get the underlying data allocation. - let alloc_id = match self.tcx.global_alloc(alloc_id) { - GlobalAlloc::VTable(ty, trait_ref) => { - self.tcx.vtable_allocation((ty, trait_ref)) - } - _ => alloc_id, - }; let (base_addr, base_addr_space) = match self.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { let init = const_alloc_to_llvm(self, alloc); @@ -264,7 +257,15 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.get_fn_addr(fn_instance.polymorphize(self.tcx)), self.data_layout().instruction_address_space, ), - GlobalAlloc::VTable(..) => bug!("vtables are already handled"), + GlobalAlloc::VTable(ty, trait_ref) => { + let alloc = self + .tcx + .global_alloc(self.tcx.vtable_allocation((ty, trait_ref))) + .unwrap_memory(); + let init = const_alloc_to_llvm(self, alloc); + let value = self.static_addr_of(init, alloc.inner().align, None); + (value, AddressSpace::DATA) + } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); assert!(!self.tcx.is_thread_local_static(def_id)); From b4c377e75054c69055f2572f465f9cad2b323204 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 20:49:16 -0400 Subject: [PATCH 10/16] bless some tests --- .../const-eval/ub-wide-ptr.32bit.stderr | 40 +++++++------------ .../const-eval/ub-wide-ptr.64bit.stderr | 40 +++++++------------ src/test/ui/consts/const-eval/ub-wide-ptr.rs | 11 ++++- 3 files changed, 39 insertions(+), 52 deletions(-) diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr index ee27651dca03f..345ead48151df 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr @@ -217,7 +217,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:120:1 + --> $DIR/ub-wide-ptr.rs:121:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer @@ -228,7 +228,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:123:1 + --> $DIR/ub-wide-ptr.rs:125:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer @@ -239,25 +239,25 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u } error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:125:57 + --> $DIR/ub-wide-ptr.rs:128:57 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:128:57 + --> $DIR/ub-wide-ptr.rs:131:57 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:131:56 + --> $DIR/ub-wide-ptr.rs:134:56 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:134:1 + --> $DIR/ub-wide-ptr.rs:137:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer @@ -268,7 +268,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:138:1 + --> $DIR/ub-wide-ptr.rs:142:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..: encountered 0x03, but expected a boolean @@ -278,36 +278,26 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:142:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:147:62 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - ╾allocN─╼ 00 00 00 00 │ ╾──╼.... - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:144:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:150:65 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼ - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:150:5 + --> $DIR/ub-wide-ptr.rs:157:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:154:5 + --> $DIR/ub-wide-ptr.rs:161:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr index 84c323e87b6c8..501932cb95c63 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr @@ -217,7 +217,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:120:1 + --> $DIR/ub-wide-ptr.rs:121:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer @@ -228,7 +228,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:123:1 + --> $DIR/ub-wide-ptr.rs:125:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer @@ -239,25 +239,25 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u } error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:125:57 + --> $DIR/ub-wide-ptr.rs:128:57 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:128:57 + --> $DIR/ub-wide-ptr.rs:131:57 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:131:56 + --> $DIR/ub-wide-ptr.rs:134:56 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:134:1 + --> $DIR/ub-wide-ptr.rs:137:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer @@ -268,7 +268,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:138:1 + --> $DIR/ub-wide-ptr.rs:142:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..: encountered 0x03, but expected a boolean @@ -278,36 +278,26 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:142:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:147:62 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - ╾──────allocN───────╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........ - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:144:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:150:65 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼ - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:150:5 + --> $DIR/ub-wide-ptr.rs:157:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:154:5 + --> $DIR/ub-wide-ptr.rs:161:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs index 9e3d349cd7eb0..a0377ab1efd23 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs @@ -116,12 +116,15 @@ const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { // bad trait object const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; //~^ ERROR it is undefined behavior to use this value +//~| expected a vtable // bad trait object const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; //~^ ERROR it is undefined behavior to use this value +//~| expected a vtable // bad trait object const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; //~^ ERROR it is undefined behavior to use this value +//~| expected a vtable const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; //~^ ERROR evaluation of constant value failed //~| does not point to a vtable @@ -133,16 +136,20 @@ const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[ //~| does not point to a vtable const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; //~^ ERROR it is undefined behavior to use this value +//~| expected a vtable // bad data *inside* the trait object const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; //~^ ERROR it is undefined behavior to use this value +//~| expected a boolean // # raw trait object const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed +//~| null pointer const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed +//~| does not point to a vtable const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) } as *const dyn Trait; // ok because raw // Const eval fails for these, so they need to be statics to error. From 1afea1f86a098a61e3044520bbd6725b547397ae Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 20 Jul 2022 13:36:58 +0000 Subject: [PATCH 11/16] Implement vtable_size and vtable_align intrinsics for cg_clif --- compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 4b2207f375879..d5a79e254a891 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -431,6 +431,16 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, CValue::by_val(align, usize_layout)); }; + vtable_size, (v vtable) { + let size = crate::vtable::size_of_obj(fx, vtable); + ret.write_cvalue(fx, CValue::by_val(size, usize_layout)); + }; + + vtable_align, (v vtable) { + let align = crate::vtable::min_align_of_obj(fx, vtable); + ret.write_cvalue(fx, CValue::by_val(align, usize_layout)); + }; + unchecked_add | unchecked_sub | unchecked_mul | unchecked_div | exact_div | unchecked_rem | unchecked_shl | unchecked_shr, (c x, c y) { // FIXME trap on overflow From 399e020b96b0194e734c698d3ef4eee5c5fa59ea Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 20 Jul 2022 13:40:30 +0000 Subject: [PATCH 12/16] Move vtable_size and vtable_align impls to cg_ssa --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 11 ----------- compiler/rustc_codegen_ssa/src/mir/intrinsic.rs | 10 ++++++++++ 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 9cca9bcf72467..9f3647492877c 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -10,7 +10,6 @@ use crate::value::Value; use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh}; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; -use rustc_codegen_ssa::meth; use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; @@ -364,16 +363,6 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { return; } - sym::vtable_size | sym::vtable_align => { - let vtable = args[0].immediate(); - let idx = match name { - sym::vtable_size => ty::COMMON_VTABLE_ENTRIES_SIZE, - sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN, - _ => bug!(), - }; - meth::VirtualIndex::from_index(idx).get_usize(self, vtable) - } - _ if name.as_str().starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { Ok(llval) => llval, diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 645afae30d887..1fffa3beaaa85 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -3,6 +3,7 @@ use super::place::PlaceRef; use super::FunctionCx; use crate::common::{span_invalid_monomorphization_error, IntPredicate}; use crate::glue; +use crate::meth; use crate::traits::*; use crate::MemFlags; @@ -102,6 +103,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes()) } } + sym::vtable_size | sym::vtable_align => { + let vtable = args[0].immediate(); + let idx = match name { + sym::vtable_size => ty::COMMON_VTABLE_ENTRIES_SIZE, + sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN, + _ => bug!(), + }; + meth::VirtualIndex::from_index(idx).get_usize(bx, vtable) + } sym::pref_align_of | sym::needs_drop | sym::type_id From 9cbd1066d711ef4b5de00fc105f05ee6a3db9ae9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 10:45:09 -0400 Subject: [PATCH 13/16] add range metadata to alignment loads --- compiler/rustc_codegen_ssa/src/mir/intrinsic.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 1fffa3beaaa85..0a8bd91482319 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -9,7 +9,7 @@ use crate::MemFlags; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::{sym, Span}; -use rustc_target::abi::call::{FnAbi, PassMode}; +use rustc_target::abi::{WrappingRange, call::{FnAbi, PassMode}}; fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, @@ -110,7 +110,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN, _ => bug!(), }; - meth::VirtualIndex::from_index(idx).get_usize(bx, vtable) + let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable); + if name == sym::vtable_align { + // Alignment is always nonzero. + bx.range_metadata(value, WrappingRange { start: 1, end: !0 }); + }; + value } sym::pref_align_of | sym::needs_drop From 0318f07bddd9911cb23d33eb668a911de2a02f3a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 10:47:49 -0400 Subject: [PATCH 14/16] various nits from review --- compiler/rustc_codegen_cranelift/src/constant.rs | 1 - compiler/rustc_codegen_ssa/src/mir/intrinsic.rs | 5 ++++- compiler/rustc_middle/src/mir/interpret/mod.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 3 --- library/core/src/ptr/metadata.rs | 3 +-- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index b5a143485893f..94a2fb2fbddc2 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -369,7 +369,6 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant while let Some(todo_item) = cx.todo.pop() { let (data_id, alloc, section_name) = match todo_item { TodoItem::Alloc(alloc_id) => { - //println!("alloc_id {}", alloc_id); let alloc = match tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => alloc, GlobalAlloc::Function(_) | GlobalAlloc::Static(_) | GlobalAlloc::VTable(..) => { diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 0a8bd91482319..94ac71a4dd263 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -9,7 +9,10 @@ use crate::MemFlags; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::{sym, Span}; -use rustc_target::abi::{WrappingRange, call::{FnAbi, PassMode}}; +use rustc_target::abi::{ + call::{FnAbi, PassMode}, + WrappingRange, +}; fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 7ef4dfe7c0dd8..967f8ece16cf9 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -366,7 +366,7 @@ impl<'s> AllocDecodingSession<'s> { } AllocDiscriminant::VTable => { assert!(alloc_id.is_none()); - trace!("creating static alloc ID"); + trace!("creating vtable alloc ID"); let ty = as Decodable>::decode(decoder); let poly_trait_ref = > as Decodable>::decode(decoder); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 86331056d4440..68b65658c72b5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1428,9 +1428,6 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIte } } GlobalAlloc::VTable(ty, trait_ref) => { - // FIXME(RJ) no ideas if this is correct. There is this nice - // `create_mono_items_for_vtable_methods` method but I wouldn't know how to call it from - // here. So instead we just generate the actual vtable and recurse. let alloc_id = tcx.vtable_allocation((ty, trait_ref)); collect_miri(tcx, alloc_id, output) } diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 2becaa8336254..cd5edee0460ad 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -185,8 +185,7 @@ extern "C" { /// Opaque type for accessing vtables. /// /// Private implementation detail of `DynMetadata::size_of` etc. - /// Must be zero-sized since there is conceptually not actually any Abstract Machine memory behind this pointer. - /// However, we can require pointer alignment. + /// There is conceptually not actually any Abstract Machine memory behind this pointer. type VTable; } From 9927b3173b28fc334683cf3b5b254526c735911e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 11:36:19 -0400 Subject: [PATCH 15/16] detect bad vtables on an upcast --- compiler/rustc_const_eval/src/interpret/cast.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 5d5c49c25a358..883387851eaf0 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -297,10 +297,13 @@ 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(ref _data_a, ..), &ty::Dynamic(ref data_b, ..)) => { + (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { let (old_data, old_vptr) = self.read_immediate(src)?.to_scalar_pair()?; let old_vptr = self.scalar_to_ptr(old_vptr)?; - let (ty, _) = self.get_ptr_vtable(old_vptr)?; + let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?; + if old_trait != data_a.principal() { + throw_ub_format!("upcast on a pointer whose vtable does not match its type"); + } let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) } From d46dfa25d46be353a0cda39373e0319eb4f3ec69 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 18:33:51 -0400 Subject: [PATCH 16/16] detect bad vptrs on dyn calls --- .../src/interpret/terminator.rs | 61 ++++++++++++++----- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 90e06f55cbf57..e7e60b5fa2362 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -519,7 +519,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } // cannot use the shim here, because that will only result in infinite recursion - ty::InstanceDef::Virtual(_, idx) => { + ty::InstanceDef::Virtual(def_id, idx) => { let mut args = args.to_vec(); // We have to implement all "object safe receivers". So we have to go search for a // pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively @@ -552,22 +552,53 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } }; - // Find and consult vtable. The type now could be something like RcBox, - // i.e., it is still not necessarily `ty::Dynamic` (so we cannot use - // `place.vtable()`), but it should have a `dyn Trait` tail. - assert!(matches!( - self.tcx - .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env) - .kind(), - ty::Dynamic(..) - )); - let vtable = self.scalar_to_ptr(receiver_place.meta.unwrap_meta())?; - let Some(ty::VtblEntry::Method(fn_inst)) = self.get_vtable_entries(vtable)?.get(idx).copied() else { + // Obtain the underlying trait we are working on. + let receiver_tail = self + .tcx + .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env); + let ty::Dynamic(data, ..) = receiver_tail.kind() else { + span_bug!(self.cur_span(), "dyanmic call on non-`dyn` type {}", receiver_tail) + }; + + // Get the required information from the vtable. + let vptr = self.scalar_to_ptr(receiver_place.meta.unwrap_meta())?; + let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?; + if dyn_trait != data.principal() { throw_ub_format!( - "calling index {idx} of vtable {vtable} but \ - that vtable is too small or does not have a method at that index" - ) + "`dyn` call on a pointer whose vtable does not match its type" + ); + } + + // Now determine the actual method to call. We can do that in two different ways and + // compare them to ensure everything fits. + let ty::VtblEntry::Method(fn_inst) = self.get_vtable_entries(vptr)?[idx] else { + span_bug!(self.cur_span(), "dyn call index points at something that is not a method") }; + if cfg!(debug_assertions) { + let tcx = *self.tcx; + + let trait_def_id = tcx.trait_of_item(def_id).unwrap(); + let virtual_trait_ref = + ty::TraitRef::from_method(tcx, trait_def_id, instance.substs); + assert_eq!( + receiver_tail, + virtual_trait_ref.self_ty(), + "mismatch in underlying dyn trait computation within Miri and MIR building", + ); + let existential_trait_ref = + ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref); + let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty); + + let concrete_method = Instance::resolve( + tcx, + self.param_env, + def_id, + instance.substs.rebase_onto(tcx, trait_def_id, concrete_trait_ref.substs), + ) + .unwrap() + .unwrap(); + assert_eq!(fn_inst, concrete_method); + } // `*mut receiver_place.layout.ty` is almost the layout that we // want for args[0]: We have to project to field 0 because we want