Skip to content

Commit afb3b9d

Browse files
committed
Auto merge of rust-lang#143696 - oli-obk:constable-type-id2, r=RalfJung
Add opaque TypeId handles for CTFE Reopen of rust-lang#142789 (comment) after some bors insta-merge chaos r? `@RalfJung`
2 parents 93c5858 + a53271a commit afb3b9d

File tree

6 files changed

+71
-41
lines changed

6 files changed

+71
-41
lines changed

core/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ optimize_for_size = []
2323
# Make `RefCell` store additional debugging information, which is printed out when
2424
# a borrow error occurs
2525
debug_refcell = []
26-
# Make `TypeId` store a reference to the name of the type, so that it can print that name.
27-
debug_typeid = []
2826

2927
[lints.rust.unexpected_cfgs]
3028
level = "warn"

core/src/any.rs

Lines changed: 57 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -707,19 +707,52 @@ impl dyn Any + Send + Sync {
707707
/// ```
708708
#[derive(Clone, Copy, Eq, PartialOrd, Ord)]
709709
#[stable(feature = "rust1", since = "1.0.0")]
710+
#[lang = "type_id"]
710711
pub struct TypeId {
711-
// We avoid using `u128` because that imposes higher alignment requirements on many platforms.
712-
// See issue #115620 for more information.
713-
t: (u64, u64),
714-
#[cfg(feature = "debug_typeid")]
715-
name: &'static str,
712+
/// This needs to be an array of pointers, since there is provenance
713+
/// in the first array field. This provenance knows exactly which type
714+
/// the TypeId actually is, allowing CTFE and miri to operate based off it.
715+
/// At runtime all the pointers in the array contain bits of the hash, making
716+
/// the entire `TypeId` actually just be a `u128` hash of the type.
717+
pub(crate) data: [*const (); 16 / size_of::<*const ()>()],
716718
}
717719

720+
// SAFETY: the raw pointer is always an integer
718721
#[stable(feature = "rust1", since = "1.0.0")]
719-
impl PartialEq for TypeId {
722+
unsafe impl Send for TypeId {}
723+
// SAFETY: the raw pointer is always an integer
724+
#[stable(feature = "rust1", since = "1.0.0")]
725+
unsafe impl Sync for TypeId {}
726+
727+
#[stable(feature = "rust1", since = "1.0.0")]
728+
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
729+
impl const PartialEq for TypeId {
720730
#[inline]
721731
fn eq(&self, other: &Self) -> bool {
722-
self.t == other.t
732+
#[cfg(miri)]
733+
return crate::intrinsics::type_id_eq(*self, *other);
734+
#[cfg(not(miri))]
735+
{
736+
let this = self;
737+
crate::intrinsics::const_eval_select!(
738+
@capture { this: &TypeId, other: &TypeId } -> bool:
739+
if const {
740+
crate::intrinsics::type_id_eq(*this, *other)
741+
} else {
742+
// Ideally we would just invoke `type_id_eq` unconditionally here,
743+
// but since we do not MIR inline intrinsics, because backends
744+
// may want to override them (and miri does!), MIR opts do not
745+
// clean up this call sufficiently for LLVM to turn repeated calls
746+
// of `TypeId` comparisons against one specific `TypeId` into
747+
// a lookup table.
748+
// SAFETY: We know that at runtime none of the bits have provenance and all bits
749+
// are initialized. So we can just convert the whole thing to a `u128` and compare that.
750+
unsafe {
751+
crate::mem::transmute::<_, u128>(*this) == crate::mem::transmute::<_, u128>(*other)
752+
}
753+
}
754+
)
755+
}
723756
}
724757
}
725758

@@ -742,19 +775,19 @@ impl TypeId {
742775
#[stable(feature = "rust1", since = "1.0.0")]
743776
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
744777
pub const fn of<T: ?Sized + 'static>() -> TypeId {
745-
let t: u128 = const { intrinsics::type_id::<T>() };
746-
let t1 = (t >> 64) as u64;
747-
let t2 = t as u64;
748-
749-
TypeId {
750-
t: (t1, t2),
751-
#[cfg(feature = "debug_typeid")]
752-
name: type_name::<T>(),
753-
}
778+
const { intrinsics::type_id::<T>() }
754779
}
755780

756781
fn as_u128(self) -> u128 {
757-
u128::from(self.t.0) << 64 | u128::from(self.t.1)
782+
let mut bytes = [0; 16];
783+
784+
// This is a provenance-stripping memcpy.
785+
for (i, chunk) in self.data.iter().copied().enumerate() {
786+
let chunk = chunk.expose_provenance().to_ne_bytes();
787+
let start = i * chunk.len();
788+
bytes[start..(start + chunk.len())].copy_from_slice(&chunk);
789+
}
790+
u128::from_ne_bytes(bytes)
758791
}
759792
}
760793

@@ -774,22 +807,19 @@ impl hash::Hash for TypeId {
774807
// - It is correct to do so -- only hashing a subset of `self` is still
775808
// compatible with an `Eq` implementation that considers the entire
776809
// value, as ours does.
777-
self.t.1.hash(state);
810+
let data =
811+
// SAFETY: The `offset` stays in-bounds, it just moves the pointer to the 2nd half of the `TypeId`.
812+
// Only the first ptr-sized chunk ever has provenance, so that second half is always
813+
// fine to read at integer type.
814+
unsafe { crate::ptr::read_unaligned(self.data.as_ptr().cast::<u64>().offset(1)) };
815+
data.hash(state);
778816
}
779817
}
780818

781819
#[stable(feature = "rust1", since = "1.0.0")]
782820
impl fmt::Debug for TypeId {
783821
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
784-
#[cfg(feature = "debug_typeid")]
785-
{
786-
write!(f, "TypeId({:#034x} = {})", self.as_u128(), self.name)?;
787-
}
788-
#[cfg(not(feature = "debug_typeid"))]
789-
{
790-
write!(f, "TypeId({:#034x})", self.as_u128())?;
791-
}
792-
Ok(())
822+
write!(f, "TypeId({:#034x})", self.as_u128())
793823
}
794824
}
795825

core/src/intrinsics/mod.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2724,7 +2724,20 @@ pub const fn type_name<T: ?Sized>() -> &'static str;
27242724
#[rustc_nounwind]
27252725
#[unstable(feature = "core_intrinsics", issue = "none")]
27262726
#[rustc_intrinsic]
2727-
pub const fn type_id<T: ?Sized + 'static>() -> u128;
2727+
pub const fn type_id<T: ?Sized + 'static>() -> crate::any::TypeId;
2728+
2729+
/// Tests (at compile-time) if two [`crate::any::TypeId`] instances identify the
2730+
/// same type. This is necessary because at const-eval time the actual discriminating
2731+
/// data is opaque and cannot be inspected directly.
2732+
///
2733+
/// The stabilized version of this intrinsic is the [PartialEq] impl for [`core::any::TypeId`].
2734+
#[rustc_nounwind]
2735+
#[unstable(feature = "core_intrinsics", issue = "none")]
2736+
#[rustc_intrinsic]
2737+
#[rustc_do_not_const_check]
2738+
pub const fn type_id_eq(a: crate::any::TypeId, b: crate::any::TypeId) -> bool {
2739+
a.data == b.data
2740+
}
27282741

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

coretests/tests/any.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,6 @@ fn any_unsized() {
118118
is_any::<[i32]>();
119119
}
120120

121-
#[cfg(feature = "debug_typeid")]
122-
#[test]
123-
fn debug_typeid_includes_name() {
124-
let type_id = TypeId::of::<[usize; 2]>();
125-
let debug_str = format!("{type_id:?}");
126-
assert!(debug_str.ends_with("= [usize; 2])"), "{debug_str:?} did not match");
127-
}
128-
129121
#[test]
130122
fn distinct_type_names() {
131123
// https://github.com/rust-lang/rust/issues/84666

std/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"]
113113
# Make `RefCell` store additional debugging information, which is printed out when
114114
# a borrow error occurs
115115
debug_refcell = ["core/debug_refcell"]
116-
# Make `TypeId` store a reference to the name of the type, so that it can print that name.
117-
debug_typeid = ["core/debug_typeid"]
118116

119117

120118
# Enable std_detect default features for stdarch/crates/std_detect:

sysroot/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"]
2222
compiler-builtins-no-f16-f128 = ["std/compiler-builtins-no-f16-f128"]
2323
compiler-builtins-mangled-names = ["std/compiler-builtins-mangled-names"]
2424
debug_refcell = ["std/debug_refcell"]
25-
debug_typeid = ["std/debug_typeid"]
2625
llvm-libunwind = ["std/llvm-libunwind"]
2726
system-llvm-libunwind = ["std/system-llvm-libunwind"]
2827
optimize_for_size = ["std/optimize_for_size"]

0 commit comments

Comments
 (0)