8383//! that contain `AllocId`s.
8484
8585use rustc_const_eval:: const_eval:: DummyMachine ;
86- use rustc_const_eval:: interpret:: { intern_const_alloc_for_constprop, MemoryKind } ;
87- use rustc_const_eval:: interpret:: { ImmTy , InterpCx , OpTy , Projectable , Scalar } ;
86+ use rustc_const_eval:: interpret:: { intern_const_alloc_for_constprop, MemPlaceMeta , MemoryKind } ;
87+ use rustc_const_eval:: interpret:: { ImmTy , Immediate , InterpCx , OpTy , Projectable , Scalar } ;
8888use rustc_data_structures:: fx:: FxIndexSet ;
8989use rustc_data_structures:: graph:: dominators:: Dominators ;
9090use rustc_hir:: def:: DefKind ;
@@ -99,7 +99,7 @@ use rustc_middle::ty::layout::LayoutOf;
9999use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
100100use rustc_span:: def_id:: DefId ;
101101use rustc_span:: DUMMY_SP ;
102- use rustc_target:: abi:: { self , Abi , Size , VariantIdx , FIRST_VARIANT } ;
102+ use rustc_target:: abi:: { self , Abi , FieldIdx , Size , VariantIdx , FIRST_VARIANT } ;
103103use smallvec:: SmallVec ;
104104use std:: borrow:: Cow ;
105105
@@ -177,6 +177,12 @@ enum AggregateTy<'tcx> {
177177 Array ,
178178 Tuple ,
179179 Def ( DefId , ty:: GenericArgsRef < ' tcx > ) ,
180+ RawPtr {
181+ /// Needed for cast propagation.
182+ data_pointer_ty : Ty < ' tcx > ,
183+ /// The data pointer can be anything thin, so doesn't determine the output.
184+ output_pointer_ty : Ty < ' tcx > ,
185+ } ,
180186}
181187
182188#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
@@ -385,11 +391,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
385391 AggregateTy :: Def ( def_id, args) => {
386392 self . tcx . type_of ( def_id) . instantiate ( self . tcx , args)
387393 }
394+ AggregateTy :: RawPtr { output_pointer_ty, .. } => output_pointer_ty,
388395 } ;
389396 let variant = if ty. is_enum ( ) { Some ( variant) } else { None } ;
390397 let ty = self . ecx . layout_of ( ty) . ok ( ) ?;
391398 if ty. is_zst ( ) {
392399 ImmTy :: uninit ( ty) . into ( )
400+ } else if matches ! ( kind, AggregateTy :: RawPtr { .. } ) {
401+ // Pointers don't have fields, so don't `project_field` them.
402+ let data = self . ecx . read_pointer ( fields[ 0 ] ) . ok ( ) ?;
403+ let meta = if fields[ 1 ] . layout . is_zst ( ) {
404+ MemPlaceMeta :: None
405+ } else {
406+ MemPlaceMeta :: Meta ( self . ecx . read_scalar ( fields[ 1 ] ) . ok ( ) ?)
407+ } ;
408+ let ptr_imm = Immediate :: new_pointer_with_meta ( data, meta, & self . ecx ) ;
409+ ImmTy :: from_immediate ( ptr_imm, ty) . into ( )
393410 } else if matches ! ( ty. abi, Abi :: Scalar ( ..) | Abi :: ScalarPair ( ..) ) {
394411 let dest = self . ecx . allocate ( ty, MemoryKind :: Stack ) . ok ( ) ?;
395412 let variant_dest = if let Some ( variant) = variant {
@@ -862,10 +879,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
862879 rvalue : & mut Rvalue < ' tcx > ,
863880 location : Location ,
864881 ) -> Option < VnIndex > {
865- let Rvalue :: Aggregate ( box ref kind, ref mut fields ) = * rvalue else { bug ! ( ) } ;
882+ let Rvalue :: Aggregate ( box ref kind, ref mut field_ops ) = * rvalue else { bug ! ( ) } ;
866883
867884 let tcx = self . tcx ;
868- if fields . is_empty ( ) {
885+ if field_ops . is_empty ( ) {
869886 let is_zst = match * kind {
870887 AggregateKind :: Array ( ..)
871888 | AggregateKind :: Tuple
@@ -884,13 +901,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
884901 }
885902 }
886903
887- let ( ty, variant_index) = match * kind {
904+ let ( mut ty, variant_index) = match * kind {
888905 AggregateKind :: Array ( ..) => {
889- assert ! ( !fields . is_empty( ) ) ;
906+ assert ! ( !field_ops . is_empty( ) ) ;
890907 ( AggregateTy :: Array , FIRST_VARIANT )
891908 }
892909 AggregateKind :: Tuple => {
893- assert ! ( !fields . is_empty( ) ) ;
910+ assert ! ( !field_ops . is_empty( ) ) ;
894911 ( AggregateTy :: Tuple , FIRST_VARIANT )
895912 }
896913 AggregateKind :: Closure ( did, args)
@@ -901,15 +918,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
901918 }
902919 // Do not track unions.
903920 AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return None ,
904- // FIXME: Do the extra work to GVN `from_raw_parts`
905- AggregateKind :: RawPtr ( ..) => return None ,
921+ AggregateKind :: RawPtr ( pointee_ty, mtbl) => {
922+ assert_eq ! ( field_ops. len( ) , 2 ) ;
923+ let data_pointer_ty = field_ops[ FieldIdx :: ZERO ] . ty ( self . local_decls , self . tcx ) ;
924+ let output_pointer_ty = Ty :: new_ptr ( self . tcx , pointee_ty, mtbl) ;
925+ ( AggregateTy :: RawPtr { data_pointer_ty, output_pointer_ty } , FIRST_VARIANT )
926+ }
906927 } ;
907928
908- let fields: Option < Vec < _ > > = fields
929+ let fields: Option < Vec < _ > > = field_ops
909930 . iter_mut ( )
910931 . map ( |op| self . simplify_operand ( op, location) . or_else ( || self . new_opaque ( ) ) )
911932 . collect ( ) ;
912- let fields = fields?;
933+ let mut fields = fields?;
934+
935+ if let AggregateTy :: RawPtr { data_pointer_ty, output_pointer_ty } = & mut ty {
936+ let mut was_updated = false ;
937+
938+ // Any thin pointer of matching mutability is fine as the data pointer.
939+ while let Value :: Cast {
940+ kind : CastKind :: PtrToPtr ,
941+ value : cast_value,
942+ from : cast_from,
943+ to : _,
944+ } = self . get ( fields[ 0 ] )
945+ && let ty:: RawPtr ( from_pointee_ty, from_mtbl) = cast_from. kind ( )
946+ && let ty:: RawPtr ( _, output_mtbl) = output_pointer_ty. kind ( )
947+ && from_mtbl == output_mtbl
948+ && from_pointee_ty. is_sized ( self . tcx , self . param_env )
949+ {
950+ fields[ 0 ] = * cast_value;
951+ * data_pointer_ty = * cast_from;
952+ was_updated = true ;
953+ }
954+
955+ if was_updated {
956+ if let Some ( const_) = self . try_as_constant ( fields[ 0 ] ) {
957+ field_ops[ FieldIdx :: ZERO ] = Operand :: Constant ( Box :: new ( const_) ) ;
958+ } else if let Some ( local) = self . try_as_local ( fields[ 0 ] , location) {
959+ field_ops[ FieldIdx :: ZERO ] = Operand :: Copy ( Place :: from ( local) ) ;
960+ self . reused_locals . insert ( local) ;
961+ }
962+ }
963+ }
913964
914965 if let AggregateTy :: Array = ty
915966 && fields. len ( ) > 4
@@ -941,6 +992,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
941992 ( UnOp :: Not , Value :: BinaryOp ( BinOp :: Ne , lhs, rhs) ) => {
942993 Value :: BinaryOp ( BinOp :: Eq , * lhs, * rhs)
943994 }
995+ ( UnOp :: PtrMetadata , Value :: Aggregate ( AggregateTy :: RawPtr { .. } , _, fields) ) => {
996+ return Some ( fields[ 1 ] ) ;
997+ }
944998 _ => return None ,
945999 } ;
9461000
@@ -1092,6 +1146,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
10921146 return self . new_opaque ( ) ;
10931147 }
10941148
1149+ let mut was_updated = false ;
1150+
1151+ // If that cast just casts away the metadata again,
1152+ if let PtrToPtr = kind
1153+ && let Value :: Aggregate ( AggregateTy :: RawPtr { data_pointer_ty, .. } , _, fields) =
1154+ self . get ( value)
1155+ && let ty:: RawPtr ( to_pointee, _) = to. kind ( )
1156+ && to_pointee. is_sized ( self . tcx , self . param_env )
1157+ {
1158+ from = * data_pointer_ty;
1159+ value = fields[ 0 ] ;
1160+ was_updated = true ;
1161+ if * data_pointer_ty == to {
1162+ return Some ( fields[ 0 ] ) ;
1163+ }
1164+ }
1165+
10951166 if let PtrToPtr | PointerCoercion ( MutToConstPointer ) = kind
10961167 && let Value :: Cast { kind : inner_kind, value : inner_value, from : inner_from, to : _ } =
10971168 * self . get ( value)
@@ -1100,9 +1171,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
11001171 from = inner_from;
11011172 value = inner_value;
11021173 * kind = PtrToPtr ;
1174+ was_updated = true ;
11031175 if inner_from == to {
11041176 return Some ( inner_value) ;
11051177 }
1178+ }
1179+
1180+ if was_updated {
11061181 if let Some ( const_) = self . try_as_constant ( value) {
11071182 * operand = Operand :: Constant ( Box :: new ( const_) ) ;
11081183 } else if let Some ( local) = self . try_as_local ( value, location) {
0 commit comments