@@ -707,19 +707,52 @@ impl dyn Any + Send + Sync {
707
707
/// ```
708
708
#[ derive( Clone , Copy , Eq , PartialOrd , Ord ) ]
709
709
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
710
+ #[ lang = "type_id" ]
710
711
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 ( ) > ( ) ] ,
716
718
}
717
719
720
+ // SAFETY: the raw pointer is always an integer
718
721
#[ 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 {
720
730
#[ inline]
721
731
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
+ }
723
756
}
724
757
}
725
758
@@ -742,19 +775,19 @@ impl TypeId {
742
775
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
743
776
#[ rustc_const_unstable( feature = "const_type_id" , issue = "77125" ) ]
744
777
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 > ( ) }
754
779
}
755
780
756
781
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)
758
791
}
759
792
}
760
793
@@ -774,22 +807,19 @@ impl hash::Hash for TypeId {
774
807
// - It is correct to do so -- only hashing a subset of `self` is still
775
808
// compatible with an `Eq` implementation that considers the entire
776
809
// 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) ;
778
816
}
779
817
}
780
818
781
819
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
782
820
impl fmt:: Debug for TypeId {
783
821
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( ) )
793
823
}
794
824
}
795
825
0 commit comments