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 ) ]
@@ -386,11 +392,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
386392 AggregateTy :: Def ( def_id, args) => {
387393 self . tcx . type_of ( def_id) . instantiate ( self . tcx , args)
388394 }
395+ AggregateTy :: RawPtr { output_pointer_ty, .. } => output_pointer_ty,
389396 } ;
390397 let variant = if ty. is_enum ( ) { Some ( variant) } else { None } ;
391398 let ty = self . ecx . layout_of ( ty) . ok ( ) ?;
392399 if ty. is_zst ( ) {
393400 ImmTy :: uninit ( ty) . into ( )
401+ } else if matches ! ( kind, AggregateTy :: RawPtr { .. } ) {
402+ // Pointers don't have fields, so don't `project_field` them.
403+ let data = self . ecx . read_pointer ( fields[ 0 ] ) . ok ( ) ?;
404+ let meta = if fields[ 1 ] . layout . is_zst ( ) {
405+ MemPlaceMeta :: None
406+ } else {
407+ MemPlaceMeta :: Meta ( self . ecx . read_scalar ( fields[ 1 ] ) . ok ( ) ?)
408+ } ;
409+ let ptr_imm = Immediate :: new_pointer_with_meta ( data, meta, & self . ecx ) ;
410+ ImmTy :: from_immediate ( ptr_imm, ty) . into ( )
394411 } else if matches ! ( ty. abi, Abi :: Scalar ( ..) | Abi :: ScalarPair ( ..) ) {
395412 let dest = self . ecx . allocate ( ty, MemoryKind :: Stack ) . ok ( ) ?;
396413 let variant_dest = if let Some ( variant) = variant {
@@ -881,10 +898,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
881898 rvalue : & mut Rvalue < ' tcx > ,
882899 location : Location ,
883900 ) -> Option < VnIndex > {
884- let Rvalue :: Aggregate ( box ref kind, ref mut fields ) = * rvalue else { bug ! ( ) } ;
901+ let Rvalue :: Aggregate ( box ref kind, ref mut field_ops ) = * rvalue else { bug ! ( ) } ;
885902
886903 let tcx = self . tcx ;
887- if fields . is_empty ( ) {
904+ if field_ops . is_empty ( ) {
888905 let is_zst = match * kind {
889906 AggregateKind :: Array ( ..)
890907 | AggregateKind :: Tuple
@@ -903,13 +920,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
903920 }
904921 }
905922
906- let ( ty, variant_index) = match * kind {
923+ let ( mut ty, variant_index) = match * kind {
907924 AggregateKind :: Array ( ..) => {
908- assert ! ( !fields . is_empty( ) ) ;
925+ assert ! ( !field_ops . is_empty( ) ) ;
909926 ( AggregateTy :: Array , FIRST_VARIANT )
910927 }
911928 AggregateKind :: Tuple => {
912- assert ! ( !fields . is_empty( ) ) ;
929+ assert ! ( !field_ops . is_empty( ) ) ;
913930 ( AggregateTy :: Tuple , FIRST_VARIANT )
914931 }
915932 AggregateKind :: Closure ( did, args)
@@ -920,15 +937,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
920937 }
921938 // Do not track unions.
922939 AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return None ,
923- // FIXME: Do the extra work to GVN `from_raw_parts`
924- AggregateKind :: RawPtr ( ..) => return None ,
940+ AggregateKind :: RawPtr ( pointee_ty, mtbl) => {
941+ assert_eq ! ( field_ops. len( ) , 2 ) ;
942+ let data_pointer_ty = field_ops[ FieldIdx :: ZERO ] . ty ( self . local_decls , self . tcx ) ;
943+ let output_pointer_ty = Ty :: new_ptr ( self . tcx , pointee_ty, mtbl) ;
944+ ( AggregateTy :: RawPtr { data_pointer_ty, output_pointer_ty } , FIRST_VARIANT )
945+ }
925946 } ;
926947
927- let fields: Option < Vec < _ > > = fields
948+ let fields: Option < Vec < _ > > = field_ops
928949 . iter_mut ( )
929950 . map ( |op| self . simplify_operand ( op, location) . or_else ( || self . new_opaque ( ) ) )
930951 . collect ( ) ;
931- let fields = fields?;
952+ let mut fields = fields?;
953+
954+ if let AggregateTy :: RawPtr { data_pointer_ty, output_pointer_ty } = & mut ty {
955+ let mut was_updated = false ;
956+
957+ // Any thin pointer of matching mutability is fine as the data pointer.
958+ while let Value :: Cast {
959+ kind : CastKind :: PtrToPtr ,
960+ value : cast_value,
961+ from : cast_from,
962+ to : _,
963+ } = self . get ( fields[ 0 ] )
964+ && let ty:: RawPtr ( from_pointee_ty, from_mtbl) = cast_from. kind ( )
965+ && let ty:: RawPtr ( _, output_mtbl) = output_pointer_ty. kind ( )
966+ && from_mtbl == output_mtbl
967+ && from_pointee_ty. is_sized ( self . tcx , self . param_env )
968+ {
969+ fields[ 0 ] = * cast_value;
970+ * data_pointer_ty = * cast_from;
971+ was_updated = true ;
972+ }
973+
974+ if was_updated {
975+ if let Some ( const_) = self . try_as_constant ( fields[ 0 ] ) {
976+ field_ops[ FieldIdx :: ZERO ] = Operand :: Constant ( Box :: new ( const_) ) ;
977+ } else if let Some ( local) = self . try_as_local ( fields[ 0 ] , location) {
978+ field_ops[ FieldIdx :: ZERO ] = Operand :: Copy ( Place :: from ( local) ) ;
979+ self . reused_locals . insert ( local) ;
980+ }
981+ }
982+ }
932983
933984 if let AggregateTy :: Array = ty
934985 && fields. len ( ) > 4
@@ -960,6 +1011,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
9601011 ( UnOp :: Not , Value :: BinaryOp ( BinOp :: Ne , lhs, rhs) ) => {
9611012 Value :: BinaryOp ( BinOp :: Eq , * lhs, * rhs)
9621013 }
1014+ ( UnOp :: PtrMetadata , Value :: Aggregate ( AggregateTy :: RawPtr { .. } , _, fields) ) => {
1015+ return Some ( fields[ 1 ] ) ;
1016+ }
9631017 _ => return None ,
9641018 } ;
9651019
@@ -1082,6 +1136,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
10821136 return self . new_opaque ( ) ;
10831137 }
10841138
1139+ let mut was_updated = false ;
1140+
1141+ // If that cast just casts away the metadata again,
1142+ if let PtrToPtr = kind
1143+ && let Value :: Aggregate ( AggregateTy :: RawPtr { data_pointer_ty, .. } , _, fields) =
1144+ self . get ( value)
1145+ && let ty:: RawPtr ( to_pointee, _) = to. kind ( )
1146+ && to_pointee. is_sized ( self . tcx , self . param_env )
1147+ {
1148+ from = * data_pointer_ty;
1149+ value = fields[ 0 ] ;
1150+ was_updated = true ;
1151+ if * data_pointer_ty == to {
1152+ return Some ( fields[ 0 ] ) ;
1153+ }
1154+ }
1155+
10851156 if let PtrToPtr | PointerCoercion ( MutToConstPointer ) = kind
10861157 && let Value :: Cast { kind : inner_kind, value : inner_value, from : inner_from, to : _ } =
10871158 * self . get ( value)
@@ -1090,9 +1161,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
10901161 from = inner_from;
10911162 value = inner_value;
10921163 * kind = PtrToPtr ;
1164+ was_updated = true ;
10931165 if inner_from == to {
10941166 return Some ( inner_value) ;
10951167 }
1168+ }
1169+
1170+ if was_updated {
10961171 if let Some ( const_) = self . try_as_constant ( value) {
10971172 * operand = Operand :: Constant ( Box :: new ( const_) ) ;
10981173 } else if let Some ( local) = self . try_as_local ( value, location) {
0 commit comments