Skip to content

Commit 6fea6c3

Browse files
committed
Only mark the first pointer-width bytes of TypeIdwith provenance
1 parent 9d6f08f commit 6fea6c3

File tree

8 files changed

+57
-101
lines changed

8 files changed

+57
-101
lines changed

compiler/rustc_codegen_llvm/src/common.rs

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,15 @@ use std::borrow::Borrow;
44

55
use libc::{c_char, c_uint};
66
use rustc_abi::Primitive::Pointer;
7-
use rustc_abi::{self as abi, Align, HasDataLayout as _, Size};
7+
use rustc_abi::{self as abi, HasDataLayout as _};
88
use rustc_ast::Mutability;
99
use rustc_codegen_ssa::common::TypeKind;
1010
use rustc_codegen_ssa::traits::*;
1111
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1212
use rustc_hashes::Hash128;
1313
use rustc_hir::def_id::DefId;
1414
use rustc_middle::bug;
15-
use rustc_middle::mir::interpret::{
16-
AllocInit, Allocation, ConstAllocation, GlobalAlloc, Scalar, alloc_range,
17-
};
15+
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
1816
use rustc_middle::ty::TyCtxt;
1917
use rustc_session::cstore::DllImport;
2018
use tracing::debug;
@@ -326,28 +324,9 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
326324
assert!(!self.tcx.is_thread_local_static(def_id));
327325
self.get_static(def_id)
328326
}
329-
GlobalAlloc::Type { ty, segment } => {
330-
let type_id = self.tcx.type_id_hash(ty).as_u128();
331-
let mut alloc: Allocation = Allocation::new(
332-
Size::from_bytes(16),
333-
Align::from_bytes(8).unwrap(),
334-
AllocInit::Uninit,
335-
(),
336-
);
337-
alloc
338-
.write_scalar(
339-
&self.tcx,
340-
alloc_range(Size::ZERO, Size::from_bytes(16)),
341-
Scalar::from_u128(type_id),
342-
)
343-
.unwrap();
344-
let pointer_size = self.tcx.data_layout.pointer_size;
345-
let offset = pointer_size * u64::from(segment);
346-
let value = alloc
347-
.read_scalar(&self.tcx, alloc_range(offset, pointer_size), false)
348-
.unwrap();
349-
let data = value.to_bits(pointer_size).unwrap() as u64;
350-
let llval = self.const_usize(data);
327+
GlobalAlloc::Type { .. } => {
328+
// Drop the provenance, the offset contains the bytes of the hash
329+
let llval = self.const_usize(offset.bytes());
351330
return unsafe { llvm::LLVMConstIntToPtr(llval, llty) };
352331
}
353332
};

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -406,33 +406,20 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
406406
sym::type_id_eq => {
407407
let a = ecx.project_field(&args[0], FieldIdx::ZERO)?;
408408
let b = ecx.project_field(&args[1], FieldIdx::ZERO)?;
409-
let mut eq = true;
410-
for index in 0..(16 / ecx.tcx.data_layout.pointer_size.bytes()) {
411-
let a = ecx.project_index(&a, index)?;
412-
let a = ecx.deref_pointer(&a)?;
413-
let (a, offset) = a.ptr().into_parts();
414-
assert_eq!(offset, Size::ZERO);
415-
let a = a.unwrap().alloc_id();
416-
let GlobalAlloc::Type { ty: a, segment: a_segment } = ecx.tcx.global_alloc(a)
417-
else {
418-
bug!()
419-
};
420-
let b = ecx.project_index(&b, index)?;
421-
let b = ecx.deref_pointer(&b)?;
422-
let (b, offset) = b.ptr().into_parts();
423-
assert_eq!(offset, Size::ZERO);
424-
let b = b.unwrap().alloc_id();
425-
let GlobalAlloc::Type { ty: b, segment: b_segment } = ecx.tcx.global_alloc(b)
426-
else {
427-
bug!()
428-
};
429-
430-
eq &= a == b && a_segment == b_segment;
431-
if !eq {
432-
break;
433-
}
434-
}
435-
ecx.write_scalar(Scalar::from_bool(eq), dest)?;
409+
410+
let a = ecx.project_index(&a, 0)?;
411+
let a = ecx.deref_pointer(&a)?;
412+
let (a, offset_a) = a.ptr().into_parts();
413+
let a = a.unwrap().alloc_id();
414+
let GlobalAlloc::Type { ty: a } = ecx.tcx.global_alloc(a) else { bug!() };
415+
416+
let b = ecx.project_index(&b, 0)?;
417+
let b = ecx.deref_pointer(&b)?;
418+
let (b, offset_b) = b.ptr().into_parts();
419+
let b = b.unwrap().alloc_id();
420+
let GlobalAlloc::Type { ty: b } = ecx.tcx.global_alloc(b) else { bug!() };
421+
422+
ecx.write_scalar(Scalar::from_bool(a == b && offset_a == offset_b), dest)?;
436423
}
437424
sym::const_allocate => {
438425
let size = ecx.read_scalar(&args[0])?.to_target_usize(ecx)?;

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,26 @@ pub(crate) fn alloc_type_id<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> AllocId {
3636
let align = tcx.data_layout.pointer_align;
3737
let mut alloc = Allocation::new(size, *align, AllocInit::Uninit, ());
3838
let ptr_size = tcx.data_layout.pointer_size;
39-
for step in 0..size.bytes() / ptr_size.bytes() {
40-
let offset = ptr_size * step;
41-
let alloc_id = tcx.reserve_and_set_type_id_alloc(ty, step.try_into().unwrap());
42-
let ptr = Pointer::new(alloc_id.into(), Size::ZERO);
43-
let val = Scalar::from_pointer(ptr, &tcx);
44-
alloc.write_scalar(&tcx, alloc_range(offset, ptr_size), val).unwrap();
45-
}
39+
let type_id_hash = tcx.type_id_hash(ty).as_u128();
40+
alloc
41+
.write_scalar(
42+
&tcx,
43+
alloc_range(Size::ZERO, Size::from_bytes(16)),
44+
Scalar::from_u128(type_id_hash),
45+
)
46+
.unwrap();
47+
48+
// Give the first pointer-size bytes provenance that knows about the type id
49+
50+
let alloc_id = tcx.reserve_and_set_type_id_alloc(ty);
51+
let offset = alloc
52+
.read_scalar(&tcx, alloc_range(Size::ZERO, ptr_size), false)
53+
.unwrap()
54+
.to_target_usize(&tcx)
55+
.unwrap();
56+
let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(offset));
57+
let val = Scalar::from_pointer(ptr, &tcx);
58+
alloc.write_scalar(&tcx, alloc_range(Size::ZERO, ptr_size), val).unwrap();
4659

4760
alloc.mutability = Mutability::Not;
4861

compiler/rustc_const_eval/src/interpret/memory.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,8 +1211,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> {
12111211
Some(GlobalAlloc::VTable(ty, dyn_ty)) => {
12121212
write!(fmt, " (vtable: impl {dyn_ty} for {ty})")?;
12131213
}
1214-
Some(GlobalAlloc::Type { ty, segment }) => {
1215-
write!(fmt, " (typeid segment {segment } for {ty})")?;
1214+
Some(GlobalAlloc::Type { ty }) => {
1215+
write!(fmt, " (typeid for {ty})")?;
12161216
}
12171217
Some(GlobalAlloc::Static(did)) => {
12181218
write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?;

compiler/rustc_middle/src/mir/interpret/mod.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,10 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>(
128128
ty.encode(encoder);
129129
poly_trait_ref.encode(encoder);
130130
}
131-
GlobalAlloc::Type { ty, segment } => {
131+
GlobalAlloc::Type { ty } => {
132132
trace!("encoding {alloc_id:?} with {ty:#?}");
133133
AllocDiscriminant::Type.encode(encoder);
134134
ty.encode(encoder);
135-
segment.encode(encoder);
136135
}
137136
GlobalAlloc::Static(did) => {
138137
assert!(!tcx.is_thread_local_static(did));
@@ -238,9 +237,8 @@ impl<'s> AllocDecodingSession<'s> {
238237
AllocDiscriminant::Type => {
239238
trace!("creating typeid alloc ID");
240239
let ty = Decodable::decode(decoder);
241-
let segment = Decodable::decode(decoder);
242-
trace!("decoded typid: {ty:?} ({segment})");
243-
decoder.interner().reserve_and_set_type_id_alloc(ty, segment)
240+
trace!("decoded typid: {ty:?}");
241+
decoder.interner().reserve_and_set_type_id_alloc(ty)
244242
}
245243
AllocDiscriminant::Static => {
246244
trace!("creating extern static alloc ID");
@@ -272,9 +270,9 @@ pub enum GlobalAlloc<'tcx> {
272270
Static(DefId),
273271
/// The alloc ID points to memory.
274272
Memory(ConstAllocation<'tcx>),
275-
/// A pointer-sized segment of a type id. On 64 bit systems, the 128 bit type id
273+
/// The first pointer-sized segment of a type id. On 64 bit systems, the 128 bit type id
276274
/// is split into two segments, on 32 bit systems there are 4 segments, and so on.
277-
Type { ty: Ty<'tcx>, segment: u8 },
275+
Type { ty: Ty<'tcx> },
278276
}
279277

280278
impl<'tcx> GlobalAlloc<'tcx> {
@@ -508,8 +506,8 @@ impl<'tcx> TyCtxt<'tcx> {
508506
}
509507

510508
/// Generates an [AllocId] for a [core::mem::type_info::TypeId]. Will get deduplicated.
511-
pub fn reserve_and_set_type_id_alloc(self, ty: Ty<'tcx>, segment: u8) -> AllocId {
512-
self.reserve_and_set_dedup(GlobalAlloc::Type { ty, segment }, 0)
509+
pub fn reserve_and_set_type_id_alloc(self, ty: Ty<'tcx>) -> AllocId {
510+
self.reserve_and_set_dedup(GlobalAlloc::Type { ty }, 0)
513511
}
514512

515513
/// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical

compiler/rustc_middle/src/mir/pretty.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,9 +1621,7 @@ pub fn write_allocations<'tcx>(
16211621
Some(GlobalAlloc::VTable(ty, dyn_ty)) => {
16221622
write!(w, " (vtable: impl {dyn_ty} for {ty})")?
16231623
}
1624-
Some(GlobalAlloc::Type { ty, segment }) => {
1625-
write!(w, " (typeid segment {segment} for {ty})")?
1626-
}
1624+
Some(GlobalAlloc::Type { ty }) => write!(w, " (typeid for {ty})")?,
16271625
Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
16281626
write!(w, " (static: {}", tcx.def_path_str(did))?;
16291627
if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup)

library/core/src/any.rs

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ impl dyn Any + Send + Sync {
709709
#[stable(feature = "rust1", since = "1.0.0")]
710710
#[lang = "type_id"]
711711
pub struct TypeId {
712-
data: [*const (); 16 / size_of::<usize>()],
712+
pub(crate) data: [*const (); 16 / size_of::<usize>()],
713713
}
714714

715715
// SAFETY: the raw pointer is always an integer
@@ -724,30 +724,7 @@ unsafe impl Sync for TypeId {}
724724
impl const PartialEq for TypeId {
725725
#[inline]
726726
fn eq(&self, other: &Self) -> bool {
727-
const fn ct(a: &TypeId, b: &TypeId) -> bool {
728-
crate::intrinsics::type_id_eq(*a, *b)
729-
}
730-
731-
#[inline]
732-
fn rt(a: &TypeId, b: &TypeId) -> bool {
733-
a.data == b.data
734-
}
735-
736-
core::intrinsics::const_eval_select((self, other), ct, rt)
737-
}
738-
739-
#[inline]
740-
fn ne(&self, other: &Self) -> bool {
741-
const fn ct(a: &TypeId, b: &TypeId) -> bool {
742-
!crate::intrinsics::type_id_eq(*a, *b)
743-
}
744-
745-
#[inline]
746-
fn rt(a: &TypeId, b: &TypeId) -> bool {
747-
a.data != b.data
748-
}
749-
750-
core::intrinsics::const_eval_select((self, other), ct, rt)
727+
crate::intrinsics::type_id_eq(*self, *other)
751728
}
752729
}
753730

library/core/src/intrinsics/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2728,8 +2728,12 @@ pub const fn type_id<T: ?Sized + 'static>() -> crate::any::TypeId;
27282728
#[rustc_nounwind]
27292729
#[unstable(feature = "core_intrinsics", issue = "none")]
27302730
#[rustc_intrinsic]
2731-
pub const fn type_id_eq(_a: crate::any::TypeId, _b: crate::any::TypeId) -> bool {
2732-
panic!("type_id_eq should only be used from const eval")
2731+
// The intrinsic is always overridden by CTFE and we don't want to limit the default body to
2732+
// const operations only, as that would require transmuting the raw pointers to usize because
2733+
// you can't do that cast in CTFE.
2734+
#[rustc_do_not_const_check]
2735+
pub const fn type_id_eq(a: crate::any::TypeId, b: crate::any::TypeId) -> bool {
2736+
a.data == b.data
27332737
}
27342738

27352739
/// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`.

0 commit comments

Comments
 (0)