@@ -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" ]
710711pub 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" ) ]
782820impl 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
0 commit comments