From 65b112f8aca2073499a4849f115c0ed340743e9f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 12 Mar 2025 10:26:37 +0000 Subject: [PATCH 1/8] Add opaque TypeId handles for CTFE --- .../rustc_codegen_cranelift/src/constant.rs | 5 +++ compiler/rustc_codegen_gcc/src/common.rs | 2 ++ compiler/rustc_codegen_llvm/src/common.rs | 32 ++++++++++++++---- compiler/rustc_codegen_llvm/src/consts.rs | 5 ++- compiler/rustc_const_eval/messages.ftl | 2 ++ compiler/rustc_const_eval/src/errors.rs | 6 +++- .../rustc_const_eval/src/interpret/memory.rs | 15 ++++++++- .../rustc_middle/src/mir/interpret/error.rs | 2 ++ .../rustc_middle/src/mir/interpret/mod.rs | 33 ++++++++++++++++--- compiler/rustc_middle/src/mir/pretty.rs | 1 + compiler/rustc_middle/src/ty/print/pretty.rs | 1 + compiler/rustc_monomorphize/src/collector.rs | 1 + compiler/rustc_passes/src/reachable.rs | 1 + .../rustc_smir/src/rustc_smir/convert/mir.rs | 1 + 14 files changed, 91 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 3a62cd52a9d94..07c58eb05d166 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -175,6 +175,8 @@ pub(crate) fn codegen_const_value<'tcx>( fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } + // TODO: generate pointer to allocation containing the actual type id hash u128 value + GlobalAlloc::Type(_) => todo!(), GlobalAlloc::Static(def_id) => { assert!(fx.tcx.is_static(def_id)); let data_id = data_id_for_static( @@ -360,6 +362,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant GlobalAlloc::Memory(alloc) => alloc, GlobalAlloc::Function { .. } | GlobalAlloc::Static(_) + | GlobalAlloc::Type(_) | GlobalAlloc::VTable(..) => { unreachable!() } @@ -471,6 +474,8 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant .principal() .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)), ), + // TODO + GlobalAlloc::Type(_ty) => todo!(), 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 fdd47821b515b..7cef51f291bf8 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -290,6 +290,8 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { let init = self.const_data_from_alloc(alloc); self.static_addr_of(init, alloc.inner().align, None) } + // TODO: generate pointer to allocation containing the actual type id hash u128 value + GlobalAlloc::Type(_ty) => todo!(), 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 ae5add59322fe..aa47bc7b61fc3 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -3,9 +3,8 @@ use std::borrow::Borrow; use libc::{c_char, c_uint}; -use rustc_abi as abi; -use rustc_abi::HasDataLayout; use rustc_abi::Primitive::Pointer; +use rustc_abi::{self as abi, Align, HasDataLayout, Size}; use rustc_ast::Mutability; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; @@ -13,7 +12,9 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hashes::Hash128; use rustc_hir::def_id::DefId; use rustc_middle::bug; -use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; +use rustc_middle::mir::interpret::{ + AllocInit, Allocation, ConstAllocation, GlobalAlloc, Scalar, alloc_range, +}; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::DllImport; use tracing::debug; @@ -284,7 +285,8 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { self.const_bitcast(llval, llty) }; } else { - let init = const_alloc_to_llvm(self, alloc, /*static*/ false); + let init = + const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); let alloc = alloc.inner(); let value = match alloc.mutability { Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), @@ -316,7 +318,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { }), ))) .unwrap_memory(); - let init = const_alloc_to_llvm(self, alloc, /*static*/ false); + let init = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); let value = self.static_addr_of_impl(init, alloc.inner().align, None); value } @@ -325,6 +327,24 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { assert!(!self.tcx.is_thread_local_static(def_id)); self.get_static(def_id) } + GlobalAlloc::Type(ty) => { + let type_id = self.tcx.type_id_hash(ty).as_u128(); + let mut alloc = Allocation::new( + Size::from_bytes(16), + Align::from_bytes(8).unwrap(), + AllocInit::Uninit, + (), + ); + alloc + .write_scalar( + &self.tcx, + alloc_range(Size::ZERO, Size::from_bytes(16)), + Scalar::from_u128(type_id), + ) + .unwrap(); + let init = const_alloc_to_llvm(self, &alloc, /*static*/ false); + self.static_addr_of_impl(init, alloc.align, None) + } }; let base_addr_space = global_alloc.address_space(self); let llval = unsafe { @@ -346,7 +366,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { } fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value { - const_alloc_to_llvm(self, alloc, /*static*/ false) + const_alloc_to_llvm(self, alloc.inner(), /*static*/ false) } fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index a4492d76c3c59..74a4999d5097b 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -27,10 +27,9 @@ use crate::{base, debuginfo}; pub(crate) fn const_alloc_to_llvm<'ll>( cx: &CodegenCx<'ll, '_>, - alloc: ConstAllocation<'_>, + alloc: &Allocation, is_static: bool, ) -> &'ll Value { - let alloc = alloc.inner(); // We expect that callers of const_alloc_to_llvm will instead directly codegen a pointer or // integer for any &ZST where the ZST is a constant (i.e. not a static). We should never be // producing empty LLVM allocations as they're just adding noise to binaries and forcing less @@ -138,7 +137,7 @@ fn codegen_static_initializer<'ll, 'tcx>( def_id: DefId, ) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> { let alloc = cx.tcx.eval_static_initializer(def_id)?; - Ok((const_alloc_to_llvm(cx, alloc, /*static*/ true), alloc)) + Ok((const_alloc_to_llvm(cx, alloc.inner(), /*static*/ true), alloc)) } fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) { diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 22a1894ee7208..b767ca9a3c251 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -78,6 +78,8 @@ const_eval_dealloc_kind_mismatch = const_eval_deref_function_pointer = accessing {$allocation} which contains a function +const_eval_deref_typeid_pointer = + accessing {$allocation} which contains a `TypeId` const_eval_deref_vtable_pointer = accessing {$allocation} which contains a vtable const_eval_division_by_zero = diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 14abdd8c98c18..8b58031002876 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -475,6 +475,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { WriteToReadOnly(_) => const_eval_write_to_read_only, DerefFunctionPointer(_) => const_eval_deref_function_pointer, DerefVTablePointer(_) => const_eval_deref_vtable_pointer, + DerefTypeIdPointer(_) => const_eval_deref_typeid_pointer, InvalidBool(_) => const_eval_invalid_bool, InvalidChar(_) => const_eval_invalid_char, InvalidTag(_) => const_eval_invalid_tag, @@ -588,7 +589,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { diag.arg("has", has.bytes()); diag.arg("msg", format!("{msg:?}")); } - WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => { + WriteToReadOnly(alloc) + | DerefFunctionPointer(alloc) + | DerefVTablePointer(alloc) + | DerefTypeIdPointer(alloc) => { diag.arg("allocation", alloc); } InvalidBool(b) => { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 69fceb02ff931..f2e6ed6f03b8e 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -346,6 +346,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { kind = "vtable", ) } + Some(GlobalAlloc::Type(..)) => { + err_ub_custom!( + fluent::const_eval_invalid_dealloc, + alloc_id = alloc_id, + kind = "typeid", + ) + } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { err_ub_custom!( fluent::const_eval_invalid_dealloc, @@ -615,6 +622,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)), Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), + Some(GlobalAlloc::Type(..)) => throw_ub!(DerefTypeIdPointer(id)), None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccess)), Some(GlobalAlloc::Static(def_id)) => { assert!(self.tcx.is_static(def_id)); @@ -894,7 +902,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env); let mutbl = global_alloc.mutability(*self.tcx, self.typing_env); let kind = match global_alloc { - GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData, + GlobalAlloc::Type(_) | GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => { + AllocKind::LiveData + } GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"), GlobalAlloc::VTable { .. } => AllocKind::VTable, }; @@ -1204,6 +1214,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> { Some(GlobalAlloc::VTable(ty, dyn_ty)) => { write!(fmt, " (vtable: impl {dyn_ty} for {ty})")?; } + Some(GlobalAlloc::Type(ty)) => { + write!(fmt, " (typeid 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 41a166083d079..dc8985d1b962c 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -392,6 +392,8 @@ pub enum UndefinedBehaviorInfo<'tcx> { DerefFunctionPointer(AllocId), /// Trying to access the data behind a vtable pointer. DerefVTablePointer(AllocId), + /// Trying to access the actual type id. + DerefTypeIdPointer(AllocId), /// Using a non-boolean `u8` as bool. InvalidBool(u8), /// Using a non-character `u32` as character. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index ea2f84d46d7f7..563970830ecde 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -103,6 +103,7 @@ enum AllocDiscriminant { Fn, VTable, Static, + Type, } pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>( @@ -127,6 +128,11 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>( ty.encode(encoder); poly_trait_ref.encode(encoder); } + GlobalAlloc::Type(ty) => { + trace!("encoding {alloc_id:?} with {ty:#?}"); + AllocDiscriminant::Type.encode(encoder); + ty.encode(encoder); + } GlobalAlloc::Static(did) => { assert!(!tcx.is_thread_local_static(did)); // References to statics doesn't need to know about their allocations, @@ -228,6 +234,12 @@ impl<'s> AllocDecodingSession<'s> { trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}"); decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref, CTFE_ALLOC_SALT) } + AllocDiscriminant::Type => { + trace!("creating typeid alloc ID"); + let ty = Decodable::decode(decoder); + trace!("decoded typid: {ty:?}"); + decoder.interner().reserve_and_set_type_id_alloc(ty) + } AllocDiscriminant::Static => { trace!("creating extern static alloc ID"); let did = >::decode(decoder); @@ -258,6 +270,9 @@ pub enum GlobalAlloc<'tcx> { Static(DefId), /// The alloc ID points to memory. Memory(ConstAllocation<'tcx>), + /// A TypeId pointer. For now cannot be turned into a runtime value. + /// TODO: turn into actual TypeId? + Type(Ty<'tcx>), } impl<'tcx> GlobalAlloc<'tcx> { @@ -296,9 +311,10 @@ impl<'tcx> GlobalAlloc<'tcx> { pub fn address_space(&self, cx: &impl HasDataLayout) -> AddressSpace { match self { GlobalAlloc::Function { .. } => cx.data_layout().instruction_address_space, - GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => { - AddressSpace::DATA - } + GlobalAlloc::Type(_) + | GlobalAlloc::Static(..) + | GlobalAlloc::Memory(..) + | GlobalAlloc::VTable(..) => AddressSpace::DATA, } } @@ -334,7 +350,7 @@ impl<'tcx> GlobalAlloc<'tcx> { } } GlobalAlloc::Memory(alloc) => alloc.inner().mutability, - GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { + GlobalAlloc::Type(_) | GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { // These are immutable. Mutability::Not } @@ -380,8 +396,10 @@ impl<'tcx> GlobalAlloc<'tcx> { GlobalAlloc::Function { .. } => (Size::ZERO, Align::ONE), GlobalAlloc::VTable(..) => { // No data to be accessed here. But vtables are pointer-aligned. - return (Size::ZERO, tcx.data_layout.pointer_align.abi); + (Size::ZERO, tcx.data_layout.pointer_align.abi) } + // TODO make this represent normal type ids somehow + GlobalAlloc::Type(_) => (Size::from_bytes(16), Align::from_bytes(8).unwrap()), } } } @@ -487,6 +505,11 @@ impl<'tcx> TyCtxt<'tcx> { self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, dyn_ty), salt) } + /// Generates an [AllocId] for a [core::mem::type_info::TypeId]. Will get deduplicated. + pub fn reserve_and_set_type_id_alloc(self, ty: Ty<'tcx>) -> AllocId { + self.reserve_and_set_dedup(GlobalAlloc::Type(ty), 0) + } + /// 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 6b262a2750059..6250e501f9973 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1621,6 +1621,7 @@ pub fn write_allocations<'tcx>( Some(GlobalAlloc::VTable(ty, dyn_ty)) => { write!(w, " (vtable: impl {dyn_ty} for {ty})")? } + Some(GlobalAlloc::Type(ty)) => write!(w, " (typeid for {ty})")?, Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { write!(w, " (static: {}", tcx.def_path_str(did))?; if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1392d1d08fcb5..024805dc1ef00 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1780,6 +1780,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } Some(GlobalAlloc::Function { .. }) => p!(""), Some(GlobalAlloc::VTable(..)) => p!(""), + Some(GlobalAlloc::Type(_)) => p!(""), None => p!(""), } return Ok(()); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 798f4da9b3bbf..e094c2f5e0ba2 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1230,6 +1230,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt )); collect_alloc(tcx, alloc_id, output) } + GlobalAlloc::Type(_) => {} } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 7e15267a953ba..ed3260503fdcd 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -325,6 +325,7 @@ impl<'tcx> ReachableContext<'tcx> { self.visit(args); } } + GlobalAlloc::Type(ty) => self.visit(ty), GlobalAlloc::Memory(alloc) => self.propagate_from_alloc(alloc), } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 85e71ed2c2550..0047beadaa585 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -755,6 +755,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { GlobalAlloc::Static(tables.static_def(*def)) } mir::interpret::GlobalAlloc::Memory(alloc) => GlobalAlloc::Memory(alloc.stable(tables)), + mir::interpret::GlobalAlloc::Type(_) => todo!(), } } } From acdf646a8749bcc164e19616a16fd98cd76c1d60 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 12 Jun 2025 08:19:35 +0000 Subject: [PATCH 2/8] Change type id to contain a pointer to the unique type id information --- library/core/src/any.rs | 52 +++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 01dce114592a1..599e1194430eb 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -708,9 +708,15 @@ impl dyn Any + Send + Sync { #[derive(Clone, Copy, Eq, PartialOrd, Ord)] #[stable(feature = "rust1", since = "1.0.0")] pub struct TypeId { - // We avoid using `u128` because that imposes higher alignment requirements on many platforms. - // See issue #115620 for more information. - t: (u64, u64), + /// Quick accept: if pointers are the same, the ids are the same + data: &'static TypeIdData, + /// Quick reject: if hashes are different, the ids are different + partial_hash: usize, +} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +struct TypeIdData { + full_hash: [u8; 16], #[cfg(feature = "debug_typeid")] name: &'static str, } @@ -719,7 +725,16 @@ pub struct TypeId { impl PartialEq for TypeId { #[inline] fn eq(&self, other: &Self) -> bool { - self.t == other.t + self.data as *const TypeIdData == other.data as *const TypeIdData + || (self.partial_hash == other.partial_hash + && self.data.full_hash == other.data.full_hash) + } + + #[inline] + fn ne(&self, other: &Self) -> bool { + self.partial_hash != other.partial_hash + || (self.data as *const TypeIdData != other.data as *const TypeIdData + && self.data.full_hash != other.data.full_hash) } } @@ -742,19 +757,21 @@ impl TypeId { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] pub const fn of() -> TypeId { - let t: u128 = const { intrinsics::type_id::() }; - let t1 = (t >> 64) as u64; - let t2 = t as u64; - - TypeId { - t: (t1, t2), - #[cfg(feature = "debug_typeid")] - name: type_name::(), - } + let data = &const { + let t: u128 = intrinsics::type_id::(); + TypeIdData { + full_hash: t.to_ne_bytes(), + + #[cfg(feature = "debug_typeid")] + name: type_name::(), + } + }; + + TypeId { data, partial_hash: intrinsics::type_id::() as usize } } fn as_u128(self) -> u128 { - u128::from(self.t.0) << 64 | u128::from(self.t.1) + u128::from_ne_bytes(self.data.full_hash) } } @@ -774,7 +791,12 @@ impl hash::Hash for TypeId { // - It is correct to do so -- only hashing a subset of `self` is still // compatible with an `Eq` implementation that considers the entire // value, as ours does. - self.t.1.hash(state); + if cfg!(target_pointer_width = "64") { + self.partial_hash.hash(state); + } else { + let [_, _, _, _, _, _, _, _, data @ ..] = self.data.full_hash; + u64::from_ne_bytes(data).hash(state); + } } } From 4bf4d75672e4476be50203409645cfff0c6583ec Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 12 Jun 2025 08:22:04 +0000 Subject: [PATCH 3/8] Some simplifications --- library/core/Cargo.toml | 2 -- library/core/src/any.rs | 37 +++++++++++++++++----------------- library/coretests/tests/any.rs | 8 -------- library/std/Cargo.toml | 2 -- library/sysroot/Cargo.toml | 1 - 5 files changed, 18 insertions(+), 32 deletions(-) diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index 5d65b55bcdabe..31900bcc0878c 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -23,8 +23,6 @@ optimize_for_size = [] # Make `RefCell` store additional debugging information, which is printed out when # a borrow error occurs debug_refcell = [] -# Make `TypeId` store a reference to the name of the type, so that it can print that name. -debug_typeid = [] [lints.rust.unexpected_cfgs] level = "warn" diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 599e1194430eb..5bde71d68a8d3 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -711,14 +711,23 @@ pub struct TypeId { /// Quick accept: if pointers are the same, the ids are the same data: &'static TypeIdData, /// Quick reject: if hashes are different, the ids are different - partial_hash: usize, + /// We use a raw pointer instead of a `usize`, because const eval + /// will be storing this as a fake pointer that will turn into the + /// appropriate bits at codegen time. This prevents users from inspecting + /// these bits at compile time. + partial_hash: *const (), } +// SAFETY: the raw pointer is always an integer +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for TypeId {} +// SAFETY: the raw pointer is always an integer +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for TypeId {} + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] struct TypeIdData { full_hash: [u8; 16], - #[cfg(feature = "debug_typeid")] - name: &'static str, } #[stable(feature = "rust1", since = "1.0.0")] @@ -759,15 +768,13 @@ impl TypeId { pub const fn of() -> TypeId { let data = &const { let t: u128 = intrinsics::type_id::(); - TypeIdData { - full_hash: t.to_ne_bytes(), - - #[cfg(feature = "debug_typeid")] - name: type_name::(), - } + TypeIdData { full_hash: t.to_ne_bytes() } }; - TypeId { data, partial_hash: intrinsics::type_id::() as usize } + TypeId { + data, + partial_hash: crate::ptr::without_provenance(intrinsics::type_id::() as usize), + } } fn as_u128(self) -> u128 { @@ -803,15 +810,7 @@ impl hash::Hash for TypeId { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for TypeId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - #[cfg(feature = "debug_typeid")] - { - write!(f, "TypeId({:#034x} = {})", self.as_u128(), self.name)?; - } - #[cfg(not(feature = "debug_typeid"))] - { - write!(f, "TypeId({:#034x})", self.as_u128())?; - } - Ok(()) + write!(f, "TypeId({:#034x})", self.as_u128()) } } diff --git a/library/coretests/tests/any.rs b/library/coretests/tests/any.rs index 117ef0042380d..25002617d0bbd 100644 --- a/library/coretests/tests/any.rs +++ b/library/coretests/tests/any.rs @@ -118,14 +118,6 @@ fn any_unsized() { is_any::<[i32]>(); } -#[cfg(feature = "debug_typeid")] -#[test] -fn debug_typeid_includes_name() { - let type_id = TypeId::of::<[usize; 2]>(); - let debug_str = format!("{type_id:?}"); - assert!(debug_str.ends_with("= [usize; 2])"), "{debug_str:?} did not match"); -} - #[test] fn distinct_type_names() { // https://github.com/rust-lang/rust/issues/84666 diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 7c2a43ef20745..e4cb0b31c903a 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -113,8 +113,6 @@ optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"] # Make `RefCell` store additional debugging information, which is printed out when # a borrow error occurs debug_refcell = ["core/debug_refcell"] -# Make `TypeId` store a reference to the name of the type, so that it can print that name. -debug_typeid = ["core/debug_typeid"] # Enable std_detect default features for stdarch/crates/std_detect: diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 3adc022497167..c4937c36d4c9c 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -22,7 +22,6 @@ compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"] compiler-builtins-no-f16-f128 = ["std/compiler-builtins-no-f16-f128"] compiler-builtins-mangled-names = ["std/compiler-builtins-mangled-names"] debug_refcell = ["std/debug_refcell"] -debug_typeid = ["std/debug_typeid"] llvm-libunwind = ["std/llvm-libunwind"] system-llvm-libunwind = ["std/system-llvm-libunwind"] optimize_for_size = ["std/optimize_for_size"] From c5e3b6f8589482a7097f02e46d2261b64fcfc107 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 12 Jun 2025 08:22:04 +0000 Subject: [PATCH 4/8] Make TypeId robust against compile-time introspection --- compiler/rustc_codegen_llvm/src/common.rs | 10 +++ .../src/interpret/intrinsics.rs | 30 +++++++- .../rustc_const_eval/src/interpret/memory.rs | 21 ++++-- .../src/interpret/validity.rs | 68 ++++++++++--------- compiler/rustc_hir/src/lang_items.rs | 2 + .../rustc_hir_analysis/src/check/intrinsic.rs | 4 +- .../rustc_middle/src/mir/interpret/mod.rs | 35 ++++++++-- compiler/rustc_middle/src/mir/pretty.rs | 1 + compiler/rustc_middle/src/ty/print/pretty.rs | 1 + compiler/rustc_monomorphize/src/collector.rs | 1 + compiler/rustc_passes/src/reachable.rs | 2 +- .../rustc_smir/src/rustc_smir/convert/mir.rs | 1 + library/core/src/any.rs | 11 +-- library/core/src/intrinsics/mod.rs | 2 +- 14 files changed, 135 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index aa47bc7b61fc3..dccb73277d7bb 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -342,9 +342,19 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { Scalar::from_u128(type_id), ) .unwrap(); + alloc.mutability = Mutability::Not; let init = const_alloc_to_llvm(self, &alloc, /*static*/ false); self.static_addr_of_impl(init, alloc.align, None) } + GlobalAlloc::PartialHash(ty) => { + assert!(matches!(layout.primitive(), Pointer(_))); + let bytes = self.tcx.type_id_hash(ty).truncate().as_u64().to_be_bytes(); + let bits = self.tcx.data_layout.pointer_size.bits(); + let mask = u64::MAX >> (64 - bits); + // It doesn't matter which bits we pick as long as the scheme is the same with the same compiler. + let llval = self.const_usize(u64::from_be_bytes(bytes) & mask); + return unsafe { llvm::LLVMConstIntToPtr(llval, llty) }; + } }; let base_addr_space = global_alloc.address_space(self); let llval = unsafe { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index d7cede7129306..b9918c702fdc8 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -6,6 +6,8 @@ use std::assert_matches::assert_matches; use rustc_abi::Size; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; +use rustc_ast::Mutability; +use rustc_middle::mir::interpret::{AllocId, AllocInit, CtfeProvenance, alloc_range}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::{TyAndLayout, ValidityRequirement}; use rustc_middle::ty::{Ty, TyCtxt}; @@ -29,6 +31,31 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll tcx.mk_const_alloc(alloc) } +pub(crate) fn alloc_type_id<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> AllocId { + let ptr_size = tcx.data_layout.pointer_size; + let align = tcx.data_layout.pointer_align; + + let mut alloc = Allocation::new(ptr_size * 2, *align, AllocInit::Uninit, ()); + // Write a pointer pointing to the hash. At ctfe time this is an opaque pointer that you cannot deref + let ptr = tcx.reserve_and_set_type_id_alloc(ty); + let ptr = Pointer::new(CtfeProvenance::from(ptr), Size::ZERO); + alloc + .write_scalar(&tcx, alloc_range(Size::ZERO, ptr_size), Scalar::from_pointer(ptr, &tcx)) + .unwrap(); + + // Write a pointer that is not actually a pointer but will just get replaced by the first `pointer_size` bytes of the hash + // in codegen. It is a pointer in CTFE so no one can access the bits. + let ptr = tcx.reserve_and_set_type_id_partial_hash(ty); + let ptr = Pointer::new(CtfeProvenance::from(ptr), Size::ZERO); + alloc + .write_scalar(&tcx, alloc_range(ptr_size, ptr_size), Scalar::from_pointer(ptr, &tcx)) + .unwrap(); + + alloc.mutability = Mutability::Not; + + tcx.reserve_and_set_memory_alloc(tcx.mk_const_alloc(alloc)) +} + impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Returns `true` if emulation happened. /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own @@ -63,7 +90,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sym::type_id => { let tp_ty = instance.args.type_at(0); ensure_monomorphic_enough(tcx, tp_ty)?; - let val = ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128()); + let alloc_id = alloc_type_id(tcx, tp_ty); + let val = ConstValue::Indirect { alloc_id, offset: Size::ZERO }; let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?; self.copy_op(&val, dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index f2e6ed6f03b8e..8466bc6b140ce 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -353,6 +353,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { kind = "typeid", ) } + Some(GlobalAlloc::PartialHash(..)) => { + err_ub_custom!( + fluent::const_eval_invalid_dealloc, + alloc_id = alloc_id, + kind = "partial_hash", + ) + } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { err_ub_custom!( fluent::const_eval_invalid_dealloc, @@ -622,7 +629,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)), Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), - Some(GlobalAlloc::Type(..)) => throw_ub!(DerefTypeIdPointer(id)), + Some(GlobalAlloc::Type(..)) | Some(GlobalAlloc::PartialHash(..)) => { + throw_ub!(DerefTypeIdPointer(id)) + } None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccess)), Some(GlobalAlloc::Static(def_id)) => { assert!(self.tcx.is_static(def_id)); @@ -902,9 +911,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env); let mutbl = global_alloc.mutability(*self.tcx, self.typing_env); let kind = match global_alloc { - GlobalAlloc::Type(_) | GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => { - AllocKind::LiveData - } + GlobalAlloc::Type(_) + | GlobalAlloc::PartialHash(_) + | GlobalAlloc::Static { .. } + | GlobalAlloc::Memory { .. } => AllocKind::LiveData, GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"), GlobalAlloc::VTable { .. } => AllocKind::VTable, }; @@ -1217,6 +1227,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> { Some(GlobalAlloc::Type(ty)) => { write!(fmt, " (typeid for {ty})")?; } + Some(GlobalAlloc::PartialHash(ty)) => { + write!(fmt, " (partial hash of {ty})")?; + } Some(GlobalAlloc::Static(did)) => { write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?; } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 998ef3729eafe..9000b5b86a1ce 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -574,40 +574,46 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { let alloc_actual_mutbl = global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env); - if let GlobalAlloc::Static(did) = global_alloc { - let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { - bug!() - }; - // Special handling for pointers to statics (irrespective of their type). - assert!(!self.ecx.tcx.is_thread_local_static(did)); - assert!(self.ecx.tcx.is_static(did)); - // Mode-specific checks - match ctfe_mode { - CtfeValidationMode::Static { .. } - | CtfeValidationMode::Promoted { .. } => { - // We skip recursively checking other statics. These statics must be sound by - // themselves, and the only way to get broken statics here is by using - // unsafe code. - // The reasons we don't check other statics is twofold. For one, in all - // sound cases, the static was already validated on its own, and second, we - // trigger cycle errors if we try to compute the value of the other static - // and that static refers back to us (potentially through a promoted). - // This could miss some UB, but that's fine. - // We still walk nested allocations, as they are fundamentally part of this validation run. - // This means we will also recurse into nested statics of *other* - // statics, even though we do not recurse into other statics directly. - // That's somewhat inconsistent but harmless. - skip_recursive_check = !nested; - } - CtfeValidationMode::Const { .. } => { - // If this is mutable memory or an `extern static`, there's no point in checking it -- we'd - // just get errors trying to read the value. - if alloc_actual_mutbl.is_mut() || self.ecx.tcx.is_foreign_item(did) - { - skip_recursive_check = true; + match global_alloc { + GlobalAlloc::Static(did) => { + let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { + bug!() + }; + assert!(!self.ecx.tcx.is_thread_local_static(did)); + assert!(self.ecx.tcx.is_static(did)); + match ctfe_mode { + CtfeValidationMode::Static { .. } + | CtfeValidationMode::Promoted { .. } => { + // We skip recursively checking other statics. These statics must be sound by + // themselves, and the only way to get broken statics here is by using + // unsafe code. + // The reasons we don't check other statics is twofold. For one, in all + // sound cases, the static was already validated on its own, and second, we + // trigger cycle errors if we try to compute the value of the other static + // and that static refers back to us (potentially through a promoted). + // This could miss some UB, but that's fine. + // We still walk nested allocations, as they are fundamentally part of this validation run. + // This means we will also recurse into nested statics of *other* + // statics, even though we do not recurse into other statics directly. + // That's somewhat inconsistent but harmless. + skip_recursive_check = !nested; + } + CtfeValidationMode::Const { .. } => { + // If this is mutable memory or an `extern static`, there's no point in checking it -- we'd + // just get errors trying to read the value. + if alloc_actual_mutbl.is_mut() + || self.ecx.tcx.is_foreign_item(did) + { + skip_recursive_check = true; + } } } } + // These are controlled by rustc and not available for CTFE + GlobalAlloc::Type(_) | GlobalAlloc::PartialHash(_) => { + skip_recursive_check = true + } + _ => (), } // If this allocation has size zero, there is no actual mutability here. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 10dd5ff9aa76a..50f8419200005 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -274,6 +274,8 @@ language_item_table! { PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1); CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None; + TypeId, sym::type_id, type_id, Target::Struct, GenericRequirement::None; + // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and // various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays. // diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index cebf7d1b5324e..7b4bb9d512ea2 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -220,7 +220,9 @@ pub(crate) fn check_intrinsic_type( sym::needs_drop => (1, 0, vec![], tcx.types.bool), sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)), - sym::type_id => (1, 0, vec![], tcx.types.u128), + sym::type_id => { + (1, 0, vec![], tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity()) + } sym::offset => (2, 0, vec![param(0), param(1)], param(0)), sym::arith_offset => ( 1, diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 563970830ecde..d0ec50547eebc 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -104,6 +104,7 @@ enum AllocDiscriminant { VTable, Static, Type, + PartialHash, } pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>( @@ -133,6 +134,11 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>( AllocDiscriminant::Type.encode(encoder); ty.encode(encoder); } + GlobalAlloc::PartialHash(ty) => { + trace!("encoding {alloc_id:?} with {ty:#?}"); + AllocDiscriminant::PartialHash.encode(encoder); + ty.encode(encoder); + } GlobalAlloc::Static(did) => { assert!(!tcx.is_thread_local_static(did)); // References to statics doesn't need to know about their allocations, @@ -240,6 +246,12 @@ impl<'s> AllocDecodingSession<'s> { trace!("decoded typid: {ty:?}"); decoder.interner().reserve_and_set_type_id_alloc(ty) } + AllocDiscriminant::PartialHash => { + trace!("creating typeid alloc ID"); + let ty = Decodable::decode(decoder); + trace!("decoded typid: {ty:?}"); + decoder.interner().reserve_and_set_type_id_partial_hash(ty) + } AllocDiscriminant::Static => { trace!("creating extern static alloc ID"); let did = >::decode(decoder); @@ -270,9 +282,10 @@ pub enum GlobalAlloc<'tcx> { Static(DefId), /// The alloc ID points to memory. Memory(ConstAllocation<'tcx>), - /// A TypeId pointer. For now cannot be turned into a runtime value. - /// TODO: turn into actual TypeId? + /// A pointer to be stored within a TypeId pointing to the full hash. Type(Ty<'tcx>), + /// A partial type hash (the first `size_of()` bytes of the hash). + PartialHash(Ty<'tcx>), } impl<'tcx> GlobalAlloc<'tcx> { @@ -312,6 +325,7 @@ impl<'tcx> GlobalAlloc<'tcx> { match self { GlobalAlloc::Function { .. } => cx.data_layout().instruction_address_space, GlobalAlloc::Type(_) + | GlobalAlloc::PartialHash(_) | GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => AddressSpace::DATA, @@ -350,7 +364,10 @@ impl<'tcx> GlobalAlloc<'tcx> { } } GlobalAlloc::Memory(alloc) => alloc.inner().mutability, - GlobalAlloc::Type(_) | GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { + GlobalAlloc::PartialHash(_) + | GlobalAlloc::Type(_) + | GlobalAlloc::Function { .. } + | GlobalAlloc::VTable(..) => { // These are immutable. Mutability::Not } @@ -398,8 +415,8 @@ impl<'tcx> GlobalAlloc<'tcx> { // No data to be accessed here. But vtables are pointer-aligned. (Size::ZERO, tcx.data_layout.pointer_align.abi) } - // TODO make this represent normal type ids somehow - GlobalAlloc::Type(_) => (Size::from_bytes(16), Align::from_bytes(8).unwrap()), + GlobalAlloc::Type(_) => (Size::from_bytes(16), Align::ONE), + GlobalAlloc::PartialHash(_) => (Size::ZERO, Align::ONE), } } } @@ -505,11 +522,17 @@ impl<'tcx> TyCtxt<'tcx> { self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, dyn_ty), salt) } - /// Generates an [AllocId] for a [core::mem::type_info::TypeId]. Will get deduplicated. + /// Generates an [AllocId] for a [core::mem::type_info::TypeIdData]. Will get deduplicated. pub fn reserve_and_set_type_id_alloc(self, ty: Ty<'tcx>) -> AllocId { self.reserve_and_set_dedup(GlobalAlloc::Type(ty), 0) } + /// Generates an [AllocId] that will get replaced by a partial hash of a type. + /// See [core::mem::type_info::TypeId] for more information. + pub fn reserve_and_set_type_id_partial_hash(self, ty: Ty<'tcx>) -> AllocId { + self.reserve_and_set_dedup(GlobalAlloc::PartialHash(ty), 0) + } + /// 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 6250e501f9973..f5eb7d771dc31 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1622,6 +1622,7 @@ pub fn write_allocations<'tcx>( write!(w, " (vtable: impl {dyn_ty} for {ty})")? } Some(GlobalAlloc::Type(ty)) => write!(w, " (typeid for {ty})")?, + Some(GlobalAlloc::PartialHash(ty)) => write!(w, " (partial hash of {ty})")?, Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { write!(w, " (static: {}", tcx.def_path_str(did))?; if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 024805dc1ef00..1fce30ef4bf3f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1781,6 +1781,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { Some(GlobalAlloc::Function { .. }) => p!(""), Some(GlobalAlloc::VTable(..)) => p!(""), Some(GlobalAlloc::Type(_)) => p!(""), + Some(GlobalAlloc::PartialHash(_)) => p!(""), None => p!(""), } return Ok(()); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index e094c2f5e0ba2..c2aaa8da27992 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1231,6 +1231,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt collect_alloc(tcx, alloc_id, output) } GlobalAlloc::Type(_) => {} + GlobalAlloc::PartialHash(_) => {} } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index ed3260503fdcd..fea3dfa3059fe 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -325,7 +325,7 @@ impl<'tcx> ReachableContext<'tcx> { self.visit(args); } } - GlobalAlloc::Type(ty) => self.visit(ty), + GlobalAlloc::PartialHash(ty) | GlobalAlloc::Type(ty) => self.visit(ty), GlobalAlloc::Memory(alloc) => self.propagate_from_alloc(alloc), } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 0047beadaa585..86d05a04354ac 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -756,6 +756,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { } mir::interpret::GlobalAlloc::Memory(alloc) => GlobalAlloc::Memory(alloc.stable(tables)), mir::interpret::GlobalAlloc::Type(_) => todo!(), + mir::interpret::GlobalAlloc::PartialHash(_) => todo!(), } } } diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 5bde71d68a8d3..f3f42ac08654c 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -707,6 +707,7 @@ impl dyn Any + Send + Sync { /// ``` #[derive(Clone, Copy, Eq, PartialOrd, Ord)] #[stable(feature = "rust1", since = "1.0.0")] +#[lang = "type_id"] pub struct TypeId { /// Quick accept: if pointers are the same, the ids are the same data: &'static TypeIdData, @@ -766,15 +767,7 @@ impl TypeId { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] pub const fn of() -> TypeId { - let data = &const { - let t: u128 = intrinsics::type_id::(); - TypeIdData { full_hash: t.to_ne_bytes() } - }; - - TypeId { - data, - partial_hash: crate::ptr::without_provenance(intrinsics::type_id::() as usize), - } + const { intrinsics::type_id::() } } fn as_u128(self) -> u128 { diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 4250de9fb2b33..f3be88668d419 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2718,7 +2718,7 @@ pub const fn type_name() -> &'static str; #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -pub const fn type_id() -> u128; +pub const fn type_id() -> crate::any::TypeId; /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. /// From d75c0d0a724e5a69e553824c75c9163a196b4994 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 20 Jun 2025 14:18:56 +0000 Subject: [PATCH 5/8] Make TypeId const-comparable --- .../src/const_eval/machine.rs | 17 +++++++++- .../rustc_hir_analysis/src/check/intrinsic.rs | 5 +++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/any.rs | 34 ++++++++++++++----- library/core/src/intrinsics/mod.rs | 12 +++++++ tests/ui/const-generics/issues/issue-90318.rs | 3 +- .../const-generics/issues/issue-90318.stderr | 25 ++------------ tests/ui/consts/const_cmp_type_id.rs | 3 +- tests/ui/consts/const_cmp_type_id.stderr | 20 +++++------ tests/ui/consts/issue-73976-monomorphic.rs | 2 +- .../ui/consts/issue-73976-monomorphic.stderr | 9 ----- 11 files changed, 74 insertions(+), 57 deletions(-) delete mode 100644 tests/ui/consts/issue-73976-monomorphic.stderr diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 317b1229a90c1..561cf5edc0e05 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -2,7 +2,7 @@ use std::borrow::{Borrow, Cow}; use std::fmt; use std::hash::Hash; -use rustc_abi::{Align, Size}; +use rustc_abi::{Align, FieldIdx, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -403,6 +403,21 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { let cmp = ecx.guaranteed_cmp(a, b)?; ecx.write_scalar(Scalar::from_u8(cmp), dest)?; } + sym::type_id_eq => { + let a = ecx.project_field(&args[0], FieldIdx::ZERO)?; + let a = ecx.deref_pointer(&a)?; + let (a, offset) = a.ptr().into_parts(); + assert_eq!(offset, Size::ZERO); + let a = a.unwrap().alloc_id(); + let GlobalAlloc::Type(a) = ecx.tcx.global_alloc(a) else { bug!() }; + let b = ecx.project_field(&args[1], FieldIdx::ZERO)?; + let b = ecx.deref_pointer(&b)?; + let (b, offset) = b.ptr().into_parts(); + assert_eq!(offset, Size::ZERO); + let b = b.unwrap().alloc_id(); + let GlobalAlloc::Type(b) = ecx.tcx.global_alloc(b) else { bug!() }; + ecx.write_scalar(Scalar::from_bool(a == b), dest)?; + } sym::const_allocate => { let size = ecx.read_scalar(&args[0])?.to_target_usize(ecx)?; let align = ecx.read_scalar(&args[1])?.to_target_usize(ecx)?; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 7b4bb9d512ea2..e3532ade32ffe 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -93,6 +93,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::three_way_compare | sym::discriminant_value | sym::type_id + | sym::type_id_eq | sym::select_unpredictable | sym::cold_path | sym::ptr_guaranteed_cmp @@ -223,6 +224,10 @@ pub(crate) fn check_intrinsic_type( sym::type_id => { (1, 0, vec![], tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity()) } + sym::type_id_eq => { + let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity(); + (0, 0, vec![type_id, type_id], tcx.types.bool) + } sym::offset => (2, 0, vec![param(0), param(1)], param(0)), sym::arith_offset => ( 1, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4b8762d0dd1c2..3dfdf118d2d19 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2196,6 +2196,7 @@ symbols! { type_changing_struct_update, type_const, type_id, + type_id_eq, type_ir, type_ir_infer_ctxt_like, type_ir_inherent, diff --git a/library/core/src/any.rs b/library/core/src/any.rs index f3f42ac08654c..5f6fbda58f451 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -727,24 +727,42 @@ unsafe impl Send for TypeId {} unsafe impl Sync for TypeId {} #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -struct TypeIdData { +pub(crate) struct TypeIdData { full_hash: [u8; 16], } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for TypeId { +#[rustc_const_unstable(feature = "const_type_id", issue = "77125")] +impl const PartialEq for TypeId { #[inline] fn eq(&self, other: &Self) -> bool { - self.data as *const TypeIdData == other.data as *const TypeIdData - || (self.partial_hash == other.partial_hash - && self.data.full_hash == other.data.full_hash) + const fn ct(a: &TypeId, b: &TypeId) -> bool { + crate::intrinsics::type_id_eq(*a, *b) + } + + #[inline] + fn rt(a: &TypeId, b: &TypeId) -> bool { + a.data as *const TypeIdData == b.data as *const TypeIdData + || (a.partial_hash == b.partial_hash && a.data.full_hash == b.data.full_hash) + } + + core::intrinsics::const_eval_select((self, other), ct, rt) } #[inline] fn ne(&self, other: &Self) -> bool { - self.partial_hash != other.partial_hash - || (self.data as *const TypeIdData != other.data as *const TypeIdData - && self.data.full_hash != other.data.full_hash) + const fn ct(a: &TypeId, b: &TypeId) -> bool { + !crate::intrinsics::type_id_eq(*a, *b) + } + + #[inline] + fn rt(a: &TypeId, b: &TypeId) -> bool { + a.partial_hash != b.partial_hash + || (a.data as *const TypeIdData != b.data as *const TypeIdData + && a.data.full_hash != b.data.full_hash) + } + + core::intrinsics::const_eval_select((self, other), ct, rt) } } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index f3be88668d419..499e816c10d1f 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2720,6 +2720,18 @@ pub const fn type_name() -> &'static str; #[rustc_intrinsic] pub const fn type_id() -> crate::any::TypeId; +/// Tests (at compile-time) if two [`crate::any::TypeId`] instances identify the +/// same type. This is necessary because at const-eval time the actual discriminating +/// data is opaque and cannot be inspected directly. +/// +/// The stabilized version of this intrinsic is the [PartialEq] impl for [`core::any::TypeId`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +pub const fn type_id_eq(_a: crate::any::TypeId, _b: crate::any::TypeId) -> bool { + panic!("type_id_eq should only be used from const eval") +} + /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. /// /// This is used to implement functions like `slice::from_raw_parts_mut` and diff --git a/tests/ui/const-generics/issues/issue-90318.rs b/tests/ui/const-generics/issues/issue-90318.rs index 317ddad49cd4e..dfba90a557512 100644 --- a/tests/ui/const-generics/issues/issue-90318.rs +++ b/tests/ui/const-generics/issues/issue-90318.rs @@ -1,5 +1,6 @@ #![feature(const_type_id)] #![feature(generic_const_exprs)] +#![feature(const_trait_impl)] #![feature(core_intrinsics)] #![allow(incomplete_features)] @@ -13,7 +14,6 @@ fn consume(_val: T) where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, //~^ ERROR overly complex generic constant - //~| ERROR: cannot call { } @@ -21,7 +21,6 @@ fn test() where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, //~^ ERROR overly complex generic constant - //~| ERROR: cannot call { } diff --git a/tests/ui/const-generics/issues/issue-90318.stderr b/tests/ui/const-generics/issues/issue-90318.stderr index 9c7cb5ceb58c0..7031230db91c3 100644 --- a/tests/ui/const-generics/issues/issue-90318.stderr +++ b/tests/ui/const-generics/issues/issue-90318.stderr @@ -1,5 +1,5 @@ error: overly complex generic constant - --> $DIR/issue-90318.rs:14:8 + --> $DIR/issue-90318.rs:15:8 | LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,26 +20,5 @@ LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future -error[E0015]: cannot call non-const operator in constants - --> $DIR/issue-90318.rs:14:10 - | -LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const operator in constants - --> $DIR/issue-90318.rs:22:10 - | -LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs index dca0615083a78..def615bd92bb5 100644 --- a/tests/ui/consts/const_cmp_type_id.rs +++ b/tests/ui/consts/const_cmp_type_id.rs @@ -6,10 +6,9 @@ use std::any::TypeId; fn main() { const { assert!(TypeId::of::() == TypeId::of::()); - //~^ ERROR the trait bound `TypeId: const PartialEq` is not satisfied assert!(TypeId::of::<()>() != TypeId::of::()); - //~^ ERROR the trait bound `TypeId: const PartialEq` is not satisfied let _a = TypeId::of::() < TypeId::of::(); + //~^ ERROR: cannot call non-const operator in constants // can't assert `_a` because it is not deterministic // FIXME(const_trait_impl) make it pass } diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr index a8242a200eff1..540eec5098b40 100644 --- a/tests/ui/consts/const_cmp_type_id.stderr +++ b/tests/ui/consts/const_cmp_type_id.stderr @@ -1,15 +1,13 @@ -error[E0277]: the trait bound `TypeId: const PartialEq` is not satisfied - --> $DIR/const_cmp_type_id.rs:8:17 +error[E0015]: cannot call non-const operator in constants + --> $DIR/const_cmp_type_id.rs:10:18 | -LL | assert!(TypeId::of::() == TypeId::of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `TypeId: const PartialEq` is not satisfied - --> $DIR/const_cmp_type_id.rs:10:17 +LL | let _a = TypeId::of::() < TypeId::of::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | assert!(TypeId::of::<()>() != TypeId::of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: calls in constants are limited to constant functions, tuple structs and tuple variants -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/issue-73976-monomorphic.rs b/tests/ui/consts/issue-73976-monomorphic.rs index 561c197605117..3bfdb397afb23 100644 --- a/tests/ui/consts/issue-73976-monomorphic.rs +++ b/tests/ui/consts/issue-73976-monomorphic.rs @@ -1,4 +1,4 @@ -//@ known-bug: #110395 +//@ check-pass // // This test is complement to the test in issue-73976-polymorphic.rs. // In that test we ensure that polymorphic use of type_id and type_name in patterns diff --git a/tests/ui/consts/issue-73976-monomorphic.stderr b/tests/ui/consts/issue-73976-monomorphic.stderr deleted file mode 100644 index 367d5be09da4e..0000000000000 --- a/tests/ui/consts/issue-73976-monomorphic.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0277]: the trait bound `TypeId: [const] PartialEq` is not satisfied - --> $DIR/issue-73976-monomorphic.rs:21:5 - | -LL | GetTypeId::::VALUE == GetTypeId::::VALUE - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. From 69d51b259e941f4957df22dca418d971bc0702f2 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Apr 2025 09:01:34 +0000 Subject: [PATCH 6/8] Split up TypeId into pointer sized fields for CTFE to use as opaque ids --- .../rustc_codegen_cranelift/src/constant.rs | 44 ++++++++++++++-- compiler/rustc_codegen_cranelift/src/lib.rs | 1 + compiler/rustc_codegen_gcc/src/common.rs | 30 +++++++++-- compiler/rustc_codegen_gcc/src/lib.rs | 1 + compiler/rustc_codegen_llvm/src/common.rs | 27 ++++------ compiler/rustc_codegen_ssa/src/mir/operand.rs | 2 +- .../src/const_eval/machine.rs | 38 ++++++++++---- .../src/interpret/intrinsics.rs | 31 +++++------ .../rustc_const_eval/src/interpret/memory.rs | 23 ++------- .../src/interpret/validity.rs | 4 +- .../rustc_middle/src/mir/interpret/mod.rs | 51 ++++++------------- compiler/rustc_middle/src/mir/pretty.rs | 5 +- compiler/rustc_middle/src/ty/print/pretty.rs | 3 +- compiler/rustc_monomorphize/src/collector.rs | 3 +- compiler/rustc_passes/src/reachable.rs | 2 +- .../rustc_smir/src/rustc_smir/convert/mir.rs | 3 +- library/core/src/any.rs | 33 +++--------- tests/ui/consts/const_transmute_type_id.rs | 11 ++++ .../ui/consts/const_transmute_type_id.stderr | 12 +++++ 19 files changed, 177 insertions(+), 147 deletions(-) create mode 100644 tests/ui/consts/const_transmute_type_id.rs create mode 100644 tests/ui/consts/const_transmute_type_id.stderr diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 07c58eb05d166..5b2459a7d6e8b 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -3,6 +3,8 @@ use std::cmp::Ordering; use cranelift_module::*; +use rustc_abi::Align; +use rustc_const_eval::interpret::{AllocInit, Allocation, alloc_range}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{AllocId, GlobalAlloc, Scalar, read_target_uint}; @@ -175,8 +177,13 @@ pub(crate) fn codegen_const_value<'tcx>( fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } - // TODO: generate pointer to allocation containing the actual type id hash u128 value - GlobalAlloc::Type(_) => todo!(), + GlobalAlloc::Type { ty: type_id_ty, segment } => { + return CValue::const_val( + fx, + layout, + type_id_segment(fx.tcx, type_id_ty, segment), + ); + } GlobalAlloc::Static(def_id) => { assert!(fx.tcx.is_static(def_id)); let data_id = data_id_for_static( @@ -214,6 +221,23 @@ pub(crate) fn codegen_const_value<'tcx>( } } +fn type_id_segment<'tcx>(tcx: TyCtxt<'tcx>, type_id_ty: Ty<'tcx>, segment: u8) -> ScalarInt { + let type_id = tcx.type_id_hash(type_id_ty).as_u128(); + let mut alloc: Allocation = + Allocation::new(Size::from_bytes(16), Align::from_bytes(8).unwrap(), AllocInit::Uninit, ()); + alloc + .write_scalar( + &tcx, + alloc_range(Size::ZERO, Size::from_bytes(16)), + Scalar::from_u128(type_id), + ) + .unwrap(); + let pointer_size = tcx.data_layout.pointer_size; + let offset = pointer_size * u64::from(segment); + let value = alloc.read_scalar(&tcx, alloc_range(offset, pointer_size), false).unwrap(); + value.to_scalar_int().unwrap() +} + fn pointer_for_allocation<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, alloc_id: AllocId, @@ -362,7 +386,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant GlobalAlloc::Memory(alloc) => alloc, GlobalAlloc::Function { .. } | GlobalAlloc::Static(_) - | GlobalAlloc::Type(_) + | GlobalAlloc::Type { .. } | GlobalAlloc::VTable(..) => { unreachable!() } @@ -474,8 +498,18 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant .principal() .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)), ), - // TODO - GlobalAlloc::Type(_ty) => todo!(), + GlobalAlloc::Type { ty, segment } => { + let val = type_id_segment(tcx, ty, segment); + let Init::Bytes { contents } = &mut data.init else { unreachable!() }; + let start = offset.bytes_usize(); + let ptr_size = tcx.data_layout.pointer_size; + let src = val.to_bits(ptr_size); + let src = u128::to_le_bytes(src); + let len = ptr_size.bytes_usize(); + assert!(src[len..].iter().all(|b| *b == 0)); + contents[start..(start + len)].copy_from_slice(&src[..len]); + continue; + } GlobalAlloc::Static(def_id) => { if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 8e34436fb5e0a..41d0f8ddd7237 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -20,6 +20,7 @@ extern crate rustc_middle; extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_codegen_ssa; +extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_fs_util; diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 7cef51f291bf8..45764555c5671 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -1,10 +1,10 @@ use gccjit::{LValue, RValue, ToRValue, Type}; -use rustc_abi as abi; -use rustc_abi::HasDataLayout; use rustc_abi::Primitive::Pointer; +use rustc_abi::{self as abi, Align, HasDataLayout, Size}; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods, }; +use rustc_const_eval::interpret::{AllocInit, Allocation, alloc_range}; use rustc_middle::mir::Mutability; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; use rustc_middle::ty::layout::LayoutOf; @@ -290,8 +290,30 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { let init = self.const_data_from_alloc(alloc); self.static_addr_of(init, alloc.inner().align, None) } - // TODO: generate pointer to allocation containing the actual type id hash u128 value - GlobalAlloc::Type(_ty) => todo!(), + GlobalAlloc::Type { ty: type_id_ty, segment } => { + let type_id = self.tcx.type_id_hash(type_id_ty).as_u128(); + let mut alloc: Allocation = Allocation::new( + Size::from_bytes(16), + Align::from_bytes(8).unwrap(), + AllocInit::Uninit, + (), + ); + alloc + .write_scalar( + &self.tcx, + alloc_range(Size::ZERO, Size::from_bytes(16)), + Scalar::from_u128(type_id), + ) + .unwrap(); + let pointer_size = self.tcx.data_layout.pointer_size; + let offset = pointer_size * u64::from(segment); + let value = alloc + .read_scalar(&self.tcx, alloc_range(offset, pointer_size), false) + .unwrap(); + let data = value.to_bits(pointer_size).unwrap() as u64; + let val = self.const_usize(data); + return self.context.new_cast(None, val, ty); + } 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_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index a912678ef2a10..b514010db1a77 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -41,6 +41,7 @@ extern crate rustc_apfloat; extern crate rustc_ast; extern crate rustc_attr_data_structures; extern crate rustc_codegen_ssa; +extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_fluent_macro; diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index dccb73277d7bb..105ab667fa4a9 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -4,7 +4,7 @@ use std::borrow::Borrow; use libc::{c_char, c_uint}; use rustc_abi::Primitive::Pointer; -use rustc_abi::{self as abi, Align, HasDataLayout, Size}; +use rustc_abi::{self as abi, Align, HasDataLayout as _, Size}; use rustc_ast::Mutability; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; @@ -319,17 +319,16 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { ))) .unwrap_memory(); let init = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); - let value = self.static_addr_of_impl(init, alloc.inner().align, None); - value + self.static_addr_of_impl(init, alloc.inner().align, None) } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); assert!(!self.tcx.is_thread_local_static(def_id)); self.get_static(def_id) } - GlobalAlloc::Type(ty) => { + GlobalAlloc::Type { ty, segment } => { let type_id = self.tcx.type_id_hash(ty).as_u128(); - let mut alloc = Allocation::new( + let mut alloc: Allocation = Allocation::new( Size::from_bytes(16), Align::from_bytes(8).unwrap(), AllocInit::Uninit, @@ -342,17 +341,13 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { Scalar::from_u128(type_id), ) .unwrap(); - alloc.mutability = Mutability::Not; - let init = const_alloc_to_llvm(self, &alloc, /*static*/ false); - self.static_addr_of_impl(init, alloc.align, None) - } - GlobalAlloc::PartialHash(ty) => { - assert!(matches!(layout.primitive(), Pointer(_))); - let bytes = self.tcx.type_id_hash(ty).truncate().as_u64().to_be_bytes(); - let bits = self.tcx.data_layout.pointer_size.bits(); - let mask = u64::MAX >> (64 - bits); - // It doesn't matter which bits we pick as long as the scheme is the same with the same compiler. - let llval = self.const_usize(u64::from_be_bytes(bytes) & mask); + let pointer_size = self.tcx.data_layout.pointer_size; + let offset = pointer_size * u64::from(segment); + let value = alloc + .read_scalar(&self.tcx, alloc_range(offset, pointer_size), false) + .unwrap(); + let data = value.to_bits(pointer_size).unwrap() as u64; + let llval = self.const_usize(data); return unsafe { llvm::LLVMConstIntToPtr(llval, llty) }; } }; diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index da615cc9a003d..c05246c1b03d5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -185,7 +185,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { offset: Size, ) -> Self { let alloc_align = alloc.inner().align; - assert!(alloc_align >= layout.align.abi); + assert!(alloc_align >= layout.align.abi, "{alloc_align:?} < {:?}", layout.align.abi); let read_scalar = |start, size, s: abi::Scalar, ty| { match alloc.0.read_scalar( diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 561cf5edc0e05..17c7177c6e671 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -405,18 +405,34 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } sym::type_id_eq => { let a = ecx.project_field(&args[0], FieldIdx::ZERO)?; - let a = ecx.deref_pointer(&a)?; - let (a, offset) = a.ptr().into_parts(); - assert_eq!(offset, Size::ZERO); - let a = a.unwrap().alloc_id(); - let GlobalAlloc::Type(a) = ecx.tcx.global_alloc(a) else { bug!() }; let b = ecx.project_field(&args[1], FieldIdx::ZERO)?; - let b = ecx.deref_pointer(&b)?; - let (b, offset) = b.ptr().into_parts(); - assert_eq!(offset, Size::ZERO); - let b = b.unwrap().alloc_id(); - let GlobalAlloc::Type(b) = ecx.tcx.global_alloc(b) else { bug!() }; - ecx.write_scalar(Scalar::from_bool(a == b), dest)?; + let mut eq = true; + for index in 0..(16 / ecx.tcx.data_layout.pointer_size.bytes()) { + let a = ecx.project_index(&a, index)?; + let a = ecx.deref_pointer(&a)?; + let (a, offset) = a.ptr().into_parts(); + assert_eq!(offset, Size::ZERO); + let a = a.unwrap().alloc_id(); + let GlobalAlloc::Type { ty: a, segment: a_segment } = ecx.tcx.global_alloc(a) + else { + bug!() + }; + let b = ecx.project_index(&b, index)?; + let b = ecx.deref_pointer(&b)?; + let (b, offset) = b.ptr().into_parts(); + assert_eq!(offset, Size::ZERO); + let b = b.unwrap().alloc_id(); + let GlobalAlloc::Type { ty: b, segment: b_segment } = ecx.tcx.global_alloc(b) + else { + bug!() + }; + + eq &= a == b && a_segment == b_segment; + if !eq { + break; + } + } + ecx.write_scalar(Scalar::from_bool(eq), dest)?; } sym::const_allocate => { let size = ecx.read_scalar(&args[0])?.to_target_usize(ecx)?; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index b9918c702fdc8..b144e0f73a966 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -7,7 +7,7 @@ use std::assert_matches::assert_matches; use rustc_abi::Size; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_ast::Mutability; -use rustc_middle::mir::interpret::{AllocId, AllocInit, CtfeProvenance, alloc_range}; +use rustc_middle::mir::interpret::{AllocId, AllocInit, alloc_range}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::{TyAndLayout, ValidityRequirement}; use rustc_middle::ty::{Ty, TyCtxt}; @@ -32,24 +32,17 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll } pub(crate) fn alloc_type_id<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> AllocId { - let ptr_size = tcx.data_layout.pointer_size; + let size = Size::from_bytes(16); let align = tcx.data_layout.pointer_align; - - let mut alloc = Allocation::new(ptr_size * 2, *align, AllocInit::Uninit, ()); - // Write a pointer pointing to the hash. At ctfe time this is an opaque pointer that you cannot deref - let ptr = tcx.reserve_and_set_type_id_alloc(ty); - let ptr = Pointer::new(CtfeProvenance::from(ptr), Size::ZERO); - alloc - .write_scalar(&tcx, alloc_range(Size::ZERO, ptr_size), Scalar::from_pointer(ptr, &tcx)) - .unwrap(); - - // Write a pointer that is not actually a pointer but will just get replaced by the first `pointer_size` bytes of the hash - // in codegen. It is a pointer in CTFE so no one can access the bits. - let ptr = tcx.reserve_and_set_type_id_partial_hash(ty); - let ptr = Pointer::new(CtfeProvenance::from(ptr), Size::ZERO); - alloc - .write_scalar(&tcx, alloc_range(ptr_size, ptr_size), Scalar::from_pointer(ptr, &tcx)) - .unwrap(); + let mut alloc = Allocation::new(size, *align, AllocInit::Uninit, ()); + let ptr_size = tcx.data_layout.pointer_size; + for step in 0..size.bytes() / ptr_size.bytes() { + let offset = ptr_size * step; + let alloc_id = tcx.reserve_and_set_type_id_alloc(ty, step.try_into().unwrap()); + let ptr = Pointer::new(alloc_id.into(), Size::ZERO); + let val = Scalar::from_pointer(ptr, &tcx); + alloc.write_scalar(&tcx, alloc_range(offset, ptr_size), val).unwrap(); + } alloc.mutability = Mutability::Not; @@ -90,7 +83,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sym::type_id => { let tp_ty = instance.args.type_at(0); ensure_monomorphic_enough(tcx, tp_ty)?; - let alloc_id = alloc_type_id(tcx, tp_ty); + let alloc_id = alloc_type_id(tcx, tp_ty); let val = ConstValue::Indirect { alloc_id, offset: Size::ZERO }; let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?; self.copy_op(&val, dest)?; diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 8466bc6b140ce..a37df59c0dfe8 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -346,20 +346,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { kind = "vtable", ) } - Some(GlobalAlloc::Type(..)) => { + Some(GlobalAlloc::Type { .. }) => { err_ub_custom!( fluent::const_eval_invalid_dealloc, alloc_id = alloc_id, kind = "typeid", ) } - Some(GlobalAlloc::PartialHash(..)) => { - err_ub_custom!( - fluent::const_eval_invalid_dealloc, - alloc_id = alloc_id, - kind = "partial_hash", - ) - } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { err_ub_custom!( fluent::const_eval_invalid_dealloc, @@ -629,9 +622,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)), Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), - Some(GlobalAlloc::Type(..)) | Some(GlobalAlloc::PartialHash(..)) => { - throw_ub!(DerefTypeIdPointer(id)) - } + Some(GlobalAlloc::Type { .. }) => throw_ub!(DerefTypeIdPointer(id)), None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccess)), Some(GlobalAlloc::Static(def_id)) => { assert!(self.tcx.is_static(def_id)); @@ -911,8 +902,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env); let mutbl = global_alloc.mutability(*self.tcx, self.typing_env); let kind = match global_alloc { - GlobalAlloc::Type(_) - | GlobalAlloc::PartialHash(_) + GlobalAlloc::Type { .. } | GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData, GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"), @@ -1224,11 +1214,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> { Some(GlobalAlloc::VTable(ty, dyn_ty)) => { write!(fmt, " (vtable: impl {dyn_ty} for {ty})")?; } - Some(GlobalAlloc::Type(ty)) => { - write!(fmt, " (typeid for {ty})")?; - } - Some(GlobalAlloc::PartialHash(ty)) => { - write!(fmt, " (partial hash of {ty})")?; + Some(GlobalAlloc::Type { ty, segment }) => { + write!(fmt, " (typeid segment {segment } 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/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 9000b5b86a1ce..0a6d341d147ff 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -610,9 +610,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } } // These are controlled by rustc and not available for CTFE - GlobalAlloc::Type(_) | GlobalAlloc::PartialHash(_) => { - skip_recursive_check = true - } + GlobalAlloc::Type { .. } => skip_recursive_check = true, _ => (), } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index d0ec50547eebc..aea51f34dc757 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -104,7 +104,6 @@ enum AllocDiscriminant { VTable, Static, Type, - PartialHash, } pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>( @@ -129,15 +128,11 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>( ty.encode(encoder); poly_trait_ref.encode(encoder); } - GlobalAlloc::Type(ty) => { + GlobalAlloc::Type { ty, segment } => { trace!("encoding {alloc_id:?} with {ty:#?}"); AllocDiscriminant::Type.encode(encoder); ty.encode(encoder); - } - GlobalAlloc::PartialHash(ty) => { - trace!("encoding {alloc_id:?} with {ty:#?}"); - AllocDiscriminant::PartialHash.encode(encoder); - ty.encode(encoder); + segment.encode(encoder); } GlobalAlloc::Static(did) => { assert!(!tcx.is_thread_local_static(did)); @@ -243,14 +238,9 @@ impl<'s> AllocDecodingSession<'s> { AllocDiscriminant::Type => { trace!("creating typeid alloc ID"); let ty = Decodable::decode(decoder); - trace!("decoded typid: {ty:?}"); - decoder.interner().reserve_and_set_type_id_alloc(ty) - } - AllocDiscriminant::PartialHash => { - trace!("creating typeid alloc ID"); - let ty = Decodable::decode(decoder); - trace!("decoded typid: {ty:?}"); - decoder.interner().reserve_and_set_type_id_partial_hash(ty) + let segment = Decodable::decode(decoder); + trace!("decoded typid: {ty:?} ({segment})"); + decoder.interner().reserve_and_set_type_id_alloc(ty, segment) } AllocDiscriminant::Static => { trace!("creating extern static alloc ID"); @@ -282,10 +272,9 @@ pub enum GlobalAlloc<'tcx> { Static(DefId), /// The alloc ID points to memory. Memory(ConstAllocation<'tcx>), - /// A pointer to be stored within a TypeId pointing to the full hash. - Type(Ty<'tcx>), - /// A partial type hash (the first `size_of()` bytes of the hash). - PartialHash(Ty<'tcx>), + /// A pointer-sized segment of a type id. On 64 bit systems, the 128 bit type id + /// is split into two segments, on 32 bit systems there are 4 segments, and so on. + Type { ty: Ty<'tcx>, segment: u8 }, } impl<'tcx> GlobalAlloc<'tcx> { @@ -324,8 +313,7 @@ impl<'tcx> GlobalAlloc<'tcx> { pub fn address_space(&self, cx: &impl HasDataLayout) -> AddressSpace { match self { GlobalAlloc::Function { .. } => cx.data_layout().instruction_address_space, - GlobalAlloc::Type(_) - | GlobalAlloc::PartialHash(_) + GlobalAlloc::Type { .. } | GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => AddressSpace::DATA, @@ -364,10 +352,7 @@ impl<'tcx> GlobalAlloc<'tcx> { } } GlobalAlloc::Memory(alloc) => alloc.inner().mutability, - GlobalAlloc::PartialHash(_) - | GlobalAlloc::Type(_) - | GlobalAlloc::Function { .. } - | GlobalAlloc::VTable(..) => { + GlobalAlloc::Type { .. } | GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { // These are immutable. Mutability::Not } @@ -415,8 +400,8 @@ impl<'tcx> GlobalAlloc<'tcx> { // No data to be accessed here. But vtables are pointer-aligned. (Size::ZERO, tcx.data_layout.pointer_align.abi) } - GlobalAlloc::Type(_) => (Size::from_bytes(16), Align::ONE), - GlobalAlloc::PartialHash(_) => (Size::ZERO, Align::ONE), + // Fake allocation, there's nothing to access here + GlobalAlloc::Type { .. } => (Size::ZERO, Align::ONE), } } } @@ -522,15 +507,9 @@ impl<'tcx> TyCtxt<'tcx> { self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, dyn_ty), salt) } - /// Generates an [AllocId] for a [core::mem::type_info::TypeIdData]. Will get deduplicated. - pub fn reserve_and_set_type_id_alloc(self, ty: Ty<'tcx>) -> AllocId { - self.reserve_and_set_dedup(GlobalAlloc::Type(ty), 0) - } - - /// Generates an [AllocId] that will get replaced by a partial hash of a type. - /// See [core::mem::type_info::TypeId] for more information. - pub fn reserve_and_set_type_id_partial_hash(self, ty: Ty<'tcx>) -> AllocId { - self.reserve_and_set_dedup(GlobalAlloc::PartialHash(ty), 0) + /// Generates an [AllocId] for a [core::any::TypeId]. Will get deduplicated. + pub fn reserve_and_set_type_id_alloc(self, ty: Ty<'tcx>, segment: u8) -> AllocId { + self.reserve_and_set_dedup(GlobalAlloc::Type { ty, segment }, 0) } /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f5eb7d771dc31..848219dc5b4b2 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1621,8 +1621,9 @@ pub fn write_allocations<'tcx>( Some(GlobalAlloc::VTable(ty, dyn_ty)) => { write!(w, " (vtable: impl {dyn_ty} for {ty})")? } - Some(GlobalAlloc::Type(ty)) => write!(w, " (typeid for {ty})")?, - Some(GlobalAlloc::PartialHash(ty)) => write!(w, " (partial hash of {ty})")?, + Some(GlobalAlloc::Type { ty, segment }) => { + write!(w, " (typeid segment {segment} for {ty})")? + } Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { write!(w, " (static: {}", tcx.def_path_str(did))?; if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1fce30ef4bf3f..59644d060b1ab 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1780,8 +1780,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } Some(GlobalAlloc::Function { .. }) => p!(""), Some(GlobalAlloc::VTable(..)) => p!(""), - Some(GlobalAlloc::Type(_)) => p!(""), - Some(GlobalAlloc::PartialHash(_)) => p!(""), + Some(GlobalAlloc::Type { .. }) => p!(""), None => p!(""), } return Ok(()); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index c2aaa8da27992..2ba450d9d2d2a 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1230,8 +1230,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt )); collect_alloc(tcx, alloc_id, output) } - GlobalAlloc::Type(_) => {} - GlobalAlloc::PartialHash(_) => {} + GlobalAlloc::Type { .. } => {} } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index fea3dfa3059fe..88eeebf1111d1 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -325,7 +325,7 @@ impl<'tcx> ReachableContext<'tcx> { self.visit(args); } } - GlobalAlloc::PartialHash(ty) | GlobalAlloc::Type(ty) => self.visit(ty), + GlobalAlloc::Type { ty, .. } => self.visit(ty), GlobalAlloc::Memory(alloc) => self.propagate_from_alloc(alloc), } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 86d05a04354ac..9dd0e04e187ba 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -755,8 +755,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { GlobalAlloc::Static(tables.static_def(*def)) } mir::interpret::GlobalAlloc::Memory(alloc) => GlobalAlloc::Memory(alloc.stable(tables)), - mir::interpret::GlobalAlloc::Type(_) => todo!(), - mir::interpret::GlobalAlloc::PartialHash(_) => todo!(), + mir::interpret::GlobalAlloc::Type { .. } => todo!(), } } } diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 5f6fbda58f451..62409e9ee7ec4 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -709,14 +709,7 @@ impl dyn Any + Send + Sync { #[stable(feature = "rust1", since = "1.0.0")] #[lang = "type_id"] pub struct TypeId { - /// Quick accept: if pointers are the same, the ids are the same - data: &'static TypeIdData, - /// Quick reject: if hashes are different, the ids are different - /// We use a raw pointer instead of a `usize`, because const eval - /// will be storing this as a fake pointer that will turn into the - /// appropriate bits at codegen time. This prevents users from inspecting - /// these bits at compile time. - partial_hash: *const (), + data: [*const (); 16 / size_of::()], } // SAFETY: the raw pointer is always an integer @@ -726,11 +719,6 @@ unsafe impl Send for TypeId {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Sync for TypeId {} -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) struct TypeIdData { - full_hash: [u8; 16], -} - #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] impl const PartialEq for TypeId { @@ -742,8 +730,7 @@ impl const PartialEq for TypeId { #[inline] fn rt(a: &TypeId, b: &TypeId) -> bool { - a.data as *const TypeIdData == b.data as *const TypeIdData - || (a.partial_hash == b.partial_hash && a.data.full_hash == b.data.full_hash) + a.data == b.data } core::intrinsics::const_eval_select((self, other), ct, rt) @@ -757,9 +744,7 @@ impl const PartialEq for TypeId { #[inline] fn rt(a: &TypeId, b: &TypeId) -> bool { - a.partial_hash != b.partial_hash - || (a.data as *const TypeIdData != b.data as *const TypeIdData - && a.data.full_hash != b.data.full_hash) + a.data != b.data } core::intrinsics::const_eval_select((self, other), ct, rt) @@ -789,7 +774,8 @@ impl TypeId { } fn as_u128(self) -> u128 { - u128::from_ne_bytes(self.data.full_hash) + // SAFETY: we know there are 16 bytes without provenance at this location + unsafe { crate::ptr::read_unaligned(&self.data as *const _ as *const u128) } } } @@ -809,12 +795,9 @@ impl hash::Hash for TypeId { // - It is correct to do so -- only hashing a subset of `self` is still // compatible with an `Eq` implementation that considers the entire // value, as ours does. - if cfg!(target_pointer_width = "64") { - self.partial_hash.hash(state); - } else { - let [_, _, _, _, _, _, _, _, data @ ..] = self.data.full_hash; - u64::from_ne_bytes(data).hash(state); - } + // SAFETY: we know there are 16 bytes without provenance at this location + let data = unsafe { crate::ptr::read_unaligned(&self.data as *const _ as *const u64) }; + data.hash(state); } } diff --git a/tests/ui/consts/const_transmute_type_id.rs b/tests/ui/consts/const_transmute_type_id.rs new file mode 100644 index 0000000000000..52cc2853ab821 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id.rs @@ -0,0 +1,11 @@ +#![feature(const_type_id, const_trait_impl)] + +use std::any::TypeId; + +const _: () = { + let id = TypeId::of::(); + let id: u8 = unsafe { (&id as *const TypeId).cast::().read() }; + //~^ ERROR: unable to turn pointer into integer +}; + +fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id.stderr b/tests/ui/consts/const_transmute_type_id.stderr new file mode 100644 index 0000000000000..fafced4d48b97 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id.stderr @@ -0,0 +1,12 @@ +error[E0080]: unable to turn pointer into integer + --> $DIR/const_transmute_type_id.rs:7:27 + | +LL | let id: u8 = unsafe { (&id as *const TypeId).cast::().read() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. From de4ab373a9fca1d9c7094f71a21ab768be649f6a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 27 Jun 2025 09:52:47 +0000 Subject: [PATCH 7/8] Cursed gvn type_id test --- tests/mir-opt/gvn_type_id_polymorphic.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/mir-opt/gvn_type_id_polymorphic.rs b/tests/mir-opt/gvn_type_id_polymorphic.rs index 39bc5c24ecc68..6285dca9d95ea 100644 --- a/tests/mir-opt/gvn_type_id_polymorphic.rs +++ b/tests/mir-opt/gvn_type_id_polymorphic.rs @@ -6,7 +6,20 @@ fn generic() {} const fn type_id_of_val(_: &T) -> u128 { - std::intrinsics::type_id::() + let name = std::intrinsics::type_name::(); + let len = name.len() as u64; + let len = u64::to_be_bytes(len); + let mut ret = [0; 16]; + let mut i = 0; + while i < 8 { + ret[i] = len[i]; + i += 1; + } + while i < 16 { + ret[i] = name.as_bytes()[i - 8]; + i += 1; + } + u128::from_be_bytes(ret) } // EMIT_MIR gvn_type_id_polymorphic.cursed_is_i32.GVN.diff From 8a422506685f25de3427fd856d80fd2cf97cd280 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 27 Jun 2025 13:37:51 +0000 Subject: [PATCH 8/8] Only mark the first pointer-width bytes of TypeIdwith provenance --- .../rustc_codegen_cranelift/src/constant.rs | 36 +++------------- compiler/rustc_codegen_cranelift/src/lib.rs | 1 - compiler/rustc_codegen_gcc/src/common.rs | 27 ++---------- compiler/rustc_codegen_gcc/src/lib.rs | 1 - compiler/rustc_codegen_llvm/src/common.rs | 31 +++----------- .../src/const_eval/machine.rs | 41 +++++++------------ .../src/interpret/intrinsics.rs | 27 ++++++++---- .../rustc_const_eval/src/interpret/memory.rs | 4 +- .../rustc_middle/src/mir/interpret/mod.rs | 16 ++++---- compiler/rustc_middle/src/mir/pretty.rs | 4 +- library/core/src/any.rs | 27 +----------- library/core/src/intrinsics/mod.rs | 5 ++- tests/codegen/error-provide.rs | 5 ++- 13 files changed, 65 insertions(+), 160 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 5b2459a7d6e8b..864a836bf89d8 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -3,8 +3,6 @@ use std::cmp::Ordering; use cranelift_module::*; -use rustc_abi::Align; -use rustc_const_eval::interpret::{AllocInit, Allocation, alloc_range}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{AllocId, GlobalAlloc, Scalar, read_target_uint}; @@ -177,11 +175,11 @@ pub(crate) fn codegen_const_value<'tcx>( fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } - GlobalAlloc::Type { ty: type_id_ty, segment } => { + GlobalAlloc::Type { .. } => { return CValue::const_val( fx, layout, - type_id_segment(fx.tcx, type_id_ty, segment), + ScalarInt::try_from_target_usize(offset.bytes(), fx.tcx).unwrap(), ); } GlobalAlloc::Static(def_id) => { @@ -221,23 +219,6 @@ pub(crate) fn codegen_const_value<'tcx>( } } -fn type_id_segment<'tcx>(tcx: TyCtxt<'tcx>, type_id_ty: Ty<'tcx>, segment: u8) -> ScalarInt { - let type_id = tcx.type_id_hash(type_id_ty).as_u128(); - let mut alloc: Allocation = - Allocation::new(Size::from_bytes(16), Align::from_bytes(8).unwrap(), AllocInit::Uninit, ()); - alloc - .write_scalar( - &tcx, - alloc_range(Size::ZERO, Size::from_bytes(16)), - Scalar::from_u128(type_id), - ) - .unwrap(); - let pointer_size = tcx.data_layout.pointer_size; - let offset = pointer_size * u64::from(segment); - let value = alloc.read_scalar(&tcx, alloc_range(offset, pointer_size), false).unwrap(); - value.to_scalar_int().unwrap() -} - fn pointer_for_allocation<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, alloc_id: AllocId, @@ -498,16 +479,9 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant .principal() .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)), ), - GlobalAlloc::Type { ty, segment } => { - let val = type_id_segment(tcx, ty, segment); - let Init::Bytes { contents } = &mut data.init else { unreachable!() }; - let start = offset.bytes_usize(); - let ptr_size = tcx.data_layout.pointer_size; - let src = val.to_bits(ptr_size); - let src = u128::to_le_bytes(src); - let len = ptr_size.bytes_usize(); - assert!(src[len..].iter().all(|b| *b == 0)); - contents[start..(start + len)].copy_from_slice(&src[..len]); + GlobalAlloc::Type { .. } => { + // Nothing to do, the bytes/offset of this pointer have already been written together with all other bytes, + // so we just need to drop this provenance. continue; } GlobalAlloc::Static(def_id) => { diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 41d0f8ddd7237..8e34436fb5e0a 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -20,7 +20,6 @@ extern crate rustc_middle; extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_codegen_ssa; -extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_fs_util; diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 45764555c5671..394f69a24245f 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -1,10 +1,9 @@ use gccjit::{LValue, RValue, ToRValue, Type}; use rustc_abi::Primitive::Pointer; -use rustc_abi::{self as abi, Align, HasDataLayout, Size}; +use rustc_abi::{self as abi, HasDataLayout}; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods, }; -use rustc_const_eval::interpret::{AllocInit, Allocation, alloc_range}; use rustc_middle::mir::Mutability; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; use rustc_middle::ty::layout::LayoutOf; @@ -290,28 +289,8 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { let init = self.const_data_from_alloc(alloc); self.static_addr_of(init, alloc.inner().align, None) } - GlobalAlloc::Type { ty: type_id_ty, segment } => { - let type_id = self.tcx.type_id_hash(type_id_ty).as_u128(); - let mut alloc: Allocation = Allocation::new( - Size::from_bytes(16), - Align::from_bytes(8).unwrap(), - AllocInit::Uninit, - (), - ); - alloc - .write_scalar( - &self.tcx, - alloc_range(Size::ZERO, Size::from_bytes(16)), - Scalar::from_u128(type_id), - ) - .unwrap(); - let pointer_size = self.tcx.data_layout.pointer_size; - let offset = pointer_size * u64::from(segment); - let value = alloc - .read_scalar(&self.tcx, alloc_range(offset, pointer_size), false) - .unwrap(); - let data = value.to_bits(pointer_size).unwrap() as u64; - let val = self.const_usize(data); + GlobalAlloc::Type { .. } => { + let val = self.const_usize(offset.bytes()); return self.context.new_cast(None, val, ty); } GlobalAlloc::Static(def_id) => { diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index b514010db1a77..a912678ef2a10 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -41,7 +41,6 @@ extern crate rustc_apfloat; extern crate rustc_ast; extern crate rustc_attr_data_structures; extern crate rustc_codegen_ssa; -extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_fluent_macro; diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 105ab667fa4a9..605b136ebd51f 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -4,7 +4,7 @@ use std::borrow::Borrow; use libc::{c_char, c_uint}; use rustc_abi::Primitive::Pointer; -use rustc_abi::{self as abi, Align, HasDataLayout as _, Size}; +use rustc_abi::{self as abi, HasDataLayout as _}; use rustc_ast::Mutability; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; @@ -12,9 +12,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hashes::Hash128; use rustc_hir::def_id::DefId; use rustc_middle::bug; -use rustc_middle::mir::interpret::{ - AllocInit, Allocation, ConstAllocation, GlobalAlloc, Scalar, alloc_range, -}; +use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::DllImport; use tracing::debug; @@ -326,28 +324,9 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { assert!(!self.tcx.is_thread_local_static(def_id)); self.get_static(def_id) } - GlobalAlloc::Type { ty, segment } => { - let type_id = self.tcx.type_id_hash(ty).as_u128(); - let mut alloc: Allocation = Allocation::new( - Size::from_bytes(16), - Align::from_bytes(8).unwrap(), - AllocInit::Uninit, - (), - ); - alloc - .write_scalar( - &self.tcx, - alloc_range(Size::ZERO, Size::from_bytes(16)), - Scalar::from_u128(type_id), - ) - .unwrap(); - let pointer_size = self.tcx.data_layout.pointer_size; - let offset = pointer_size * u64::from(segment); - let value = alloc - .read_scalar(&self.tcx, alloc_range(offset, pointer_size), false) - .unwrap(); - let data = value.to_bits(pointer_size).unwrap() as u64; - let llval = self.const_usize(data); + GlobalAlloc::Type { .. } => { + // Drop the provenance, the offset contains the bytes of the hash + let llval = self.const_usize(offset.bytes()); return unsafe { llvm::LLVMConstIntToPtr(llval, llty) }; } }; diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 17c7177c6e671..6c0f22fab6956 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -406,33 +406,20 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { sym::type_id_eq => { let a = ecx.project_field(&args[0], FieldIdx::ZERO)?; let b = ecx.project_field(&args[1], FieldIdx::ZERO)?; - let mut eq = true; - for index in 0..(16 / ecx.tcx.data_layout.pointer_size.bytes()) { - let a = ecx.project_index(&a, index)?; - let a = ecx.deref_pointer(&a)?; - let (a, offset) = a.ptr().into_parts(); - assert_eq!(offset, Size::ZERO); - let a = a.unwrap().alloc_id(); - let GlobalAlloc::Type { ty: a, segment: a_segment } = ecx.tcx.global_alloc(a) - else { - bug!() - }; - let b = ecx.project_index(&b, index)?; - let b = ecx.deref_pointer(&b)?; - let (b, offset) = b.ptr().into_parts(); - assert_eq!(offset, Size::ZERO); - let b = b.unwrap().alloc_id(); - let GlobalAlloc::Type { ty: b, segment: b_segment } = ecx.tcx.global_alloc(b) - else { - bug!() - }; - - eq &= a == b && a_segment == b_segment; - if !eq { - break; - } - } - ecx.write_scalar(Scalar::from_bool(eq), dest)?; + + let a = ecx.project_index(&a, 0)?; + let a = ecx.deref_pointer(&a)?; + let (a, offset_a) = a.ptr().into_parts(); + let a = a.unwrap().alloc_id(); + let GlobalAlloc::Type { ty: a } = ecx.tcx.global_alloc(a) else { bug!() }; + + let b = ecx.project_index(&b, 0)?; + let b = ecx.deref_pointer(&b)?; + let (b, offset_b) = b.ptr().into_parts(); + let b = b.unwrap().alloc_id(); + let GlobalAlloc::Type { ty: b } = ecx.tcx.global_alloc(b) else { bug!() }; + + ecx.write_scalar(Scalar::from_bool(a == b && offset_a == offset_b), dest)?; } sym::const_allocate => { let size = ecx.read_scalar(&args[0])?.to_target_usize(ecx)?; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index b144e0f73a966..68757c93087dc 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -36,13 +36,26 @@ pub(crate) fn alloc_type_id<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> AllocId { let align = tcx.data_layout.pointer_align; let mut alloc = Allocation::new(size, *align, AllocInit::Uninit, ()); let ptr_size = tcx.data_layout.pointer_size; - for step in 0..size.bytes() / ptr_size.bytes() { - let offset = ptr_size * step; - let alloc_id = tcx.reserve_and_set_type_id_alloc(ty, step.try_into().unwrap()); - let ptr = Pointer::new(alloc_id.into(), Size::ZERO); - let val = Scalar::from_pointer(ptr, &tcx); - alloc.write_scalar(&tcx, alloc_range(offset, ptr_size), val).unwrap(); - } + let type_id_hash = tcx.type_id_hash(ty).as_u128(); + alloc + .write_scalar( + &tcx, + alloc_range(Size::ZERO, Size::from_bytes(16)), + Scalar::from_u128(type_id_hash), + ) + .unwrap(); + + // Give the first pointer-size bytes provenance that knows about the type id + + let alloc_id = tcx.reserve_and_set_type_id_alloc(ty); + let offset = alloc + .read_scalar(&tcx, alloc_range(Size::ZERO, ptr_size), false) + .unwrap() + .to_target_usize(&tcx) + .unwrap(); + let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(offset)); + let val = Scalar::from_pointer(ptr, &tcx); + alloc.write_scalar(&tcx, alloc_range(Size::ZERO, ptr_size), val).unwrap(); alloc.mutability = Mutability::Not; diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index a37df59c0dfe8..2f9104cbed5e2 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1214,8 +1214,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> { Some(GlobalAlloc::VTable(ty, dyn_ty)) => { write!(fmt, " (vtable: impl {dyn_ty} for {ty})")?; } - Some(GlobalAlloc::Type { ty, segment }) => { - write!(fmt, " (typeid segment {segment } for {ty})")?; + Some(GlobalAlloc::Type { ty }) => { + write!(fmt, " (typeid 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/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index aea51f34dc757..cd74702b83e5f 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -128,11 +128,10 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>( ty.encode(encoder); poly_trait_ref.encode(encoder); } - GlobalAlloc::Type { ty, segment } => { + GlobalAlloc::Type { ty } => { trace!("encoding {alloc_id:?} with {ty:#?}"); AllocDiscriminant::Type.encode(encoder); ty.encode(encoder); - segment.encode(encoder); } GlobalAlloc::Static(did) => { assert!(!tcx.is_thread_local_static(did)); @@ -238,9 +237,8 @@ impl<'s> AllocDecodingSession<'s> { AllocDiscriminant::Type => { trace!("creating typeid alloc ID"); let ty = Decodable::decode(decoder); - let segment = Decodable::decode(decoder); - trace!("decoded typid: {ty:?} ({segment})"); - decoder.interner().reserve_and_set_type_id_alloc(ty, segment) + trace!("decoded typid: {ty:?}"); + decoder.interner().reserve_and_set_type_id_alloc(ty) } AllocDiscriminant::Static => { trace!("creating extern static alloc ID"); @@ -272,9 +270,9 @@ pub enum GlobalAlloc<'tcx> { Static(DefId), /// The alloc ID points to memory. Memory(ConstAllocation<'tcx>), - /// A pointer-sized segment of a type id. On 64 bit systems, the 128 bit type id + /// The first pointer-sized segment of a type id. On 64 bit systems, the 128 bit type id /// is split into two segments, on 32 bit systems there are 4 segments, and so on. - Type { ty: Ty<'tcx>, segment: u8 }, + Type { ty: Ty<'tcx> }, } impl<'tcx> GlobalAlloc<'tcx> { @@ -508,8 +506,8 @@ impl<'tcx> TyCtxt<'tcx> { } /// Generates an [AllocId] for a [core::any::TypeId]. Will get deduplicated. - pub fn reserve_and_set_type_id_alloc(self, ty: Ty<'tcx>, segment: u8) -> AllocId { - self.reserve_and_set_dedup(GlobalAlloc::Type { ty, segment }, 0) + pub fn reserve_and_set_type_id_alloc(self, ty: Ty<'tcx>) -> AllocId { + self.reserve_and_set_dedup(GlobalAlloc::Type { ty }, 0) } /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 848219dc5b4b2..6bdbe711f9855 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1621,9 +1621,7 @@ pub fn write_allocations<'tcx>( Some(GlobalAlloc::VTable(ty, dyn_ty)) => { write!(w, " (vtable: impl {dyn_ty} for {ty})")? } - Some(GlobalAlloc::Type { ty, segment }) => { - write!(w, " (typeid segment {segment} for {ty})")? - } + Some(GlobalAlloc::Type { ty }) => write!(w, " (typeid for {ty})")?, Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { write!(w, " (static: {}", tcx.def_path_str(did))?; if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup) diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 62409e9ee7ec4..bc4bac77ab96f 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -709,7 +709,7 @@ impl dyn Any + Send + Sync { #[stable(feature = "rust1", since = "1.0.0")] #[lang = "type_id"] pub struct TypeId { - data: [*const (); 16 / size_of::()], + pub(crate) data: [*const (); 16 / size_of::()], } // SAFETY: the raw pointer is always an integer @@ -724,30 +724,7 @@ unsafe impl Sync for TypeId {} impl const PartialEq for TypeId { #[inline] fn eq(&self, other: &Self) -> bool { - const fn ct(a: &TypeId, b: &TypeId) -> bool { - crate::intrinsics::type_id_eq(*a, *b) - } - - #[inline] - fn rt(a: &TypeId, b: &TypeId) -> bool { - a.data == b.data - } - - core::intrinsics::const_eval_select((self, other), ct, rt) - } - - #[inline] - fn ne(&self, other: &Self) -> bool { - const fn ct(a: &TypeId, b: &TypeId) -> bool { - !crate::intrinsics::type_id_eq(*a, *b) - } - - #[inline] - fn rt(a: &TypeId, b: &TypeId) -> bool { - a.data != b.data - } - - core::intrinsics::const_eval_select((self, other), ct, rt) + crate::intrinsics::type_id_eq(*self, *other) } } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 499e816c10d1f..b15456ddc99ad 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2728,8 +2728,9 @@ pub const fn type_id() -> crate::any::TypeId; #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -pub const fn type_id_eq(_a: crate::any::TypeId, _b: crate::any::TypeId) -> bool { - panic!("type_id_eq should only be used from const eval") +#[rustc_do_not_const_check] +pub const fn type_id_eq(a: crate::any::TypeId, b: crate::any::TypeId) -> bool { + a.data == b.data } /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. diff --git a/tests/codegen/error-provide.rs b/tests/codegen/error-provide.rs index 25a66078fd4a8..b52b332b9f86f 100644 --- a/tests/codegen/error-provide.rs +++ b/tests/codegen/error-provide.rs @@ -37,8 +37,9 @@ impl std::error::Error for MyError { // and eliminate redundant ones, rather than compare one-by-one. // CHECK-NEXT: start: - // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i64, ptr - // CHECK-NEXT: switch i64 %[[SCRUTINEE]], label %{{.*}} [ + // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load ptr, ptr + // CHECK-NEXT: %[[MAGICPTR:[^ ]+]] = ptrtoint ptr %[[SCRUTINEE]] to i64 + // CHECK-NEXT: switch i64 %[[MAGICPTR]], label %{{.*}} [ // CHECK-COUNT-3: i64 {{.*}}, label %{{.*}} // CHECK-NEXT: ] request