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::{HasParamEnv, 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 {
@@ -864,10 +881,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
864881 rvalue : & mut Rvalue < ' tcx > ,
865882 location : Location ,
866883 ) -> Option < VnIndex > {
867- let Rvalue :: Aggregate ( box ref kind, ref mut fields ) = * rvalue else { bug ! ( ) } ;
884+ let Rvalue :: Aggregate ( box ref kind, ref mut field_ops ) = * rvalue else { bug ! ( ) } ;
868885
869886 let tcx = self . tcx ;
870- if fields . is_empty ( ) {
887+ if field_ops . is_empty ( ) {
871888 let is_zst = match * kind {
872889 AggregateKind :: Array ( ..)
873890 | AggregateKind :: Tuple
@@ -886,13 +903,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
886903 }
887904 }
888905
889- let ( ty, variant_index) = match * kind {
906+ let ( mut ty, variant_index) = match * kind {
890907 AggregateKind :: Array ( ..) => {
891- assert ! ( !fields . is_empty( ) ) ;
908+ assert ! ( !field_ops . is_empty( ) ) ;
892909 ( AggregateTy :: Array , FIRST_VARIANT )
893910 }
894911 AggregateKind :: Tuple => {
895- assert ! ( !fields . is_empty( ) ) ;
912+ assert ! ( !field_ops . is_empty( ) ) ;
896913 ( AggregateTy :: Tuple , FIRST_VARIANT )
897914 }
898915 AggregateKind :: Closure ( did, args)
@@ -903,15 +920,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
903920 }
904921 // Do not track unions.
905922 AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return None ,
906- // FIXME: Do the extra work to GVN `from_raw_parts`
907- AggregateKind :: RawPtr ( ..) => return None ,
923+ AggregateKind :: RawPtr ( pointee_ty, mtbl) => {
924+ assert_eq ! ( field_ops. len( ) , 2 ) ;
925+ let data_pointer_ty = field_ops[ FieldIdx :: ZERO ] . ty ( self . local_decls , self . tcx ) ;
926+ let output_pointer_ty = Ty :: new_ptr ( self . tcx , pointee_ty, mtbl) ;
927+ ( AggregateTy :: RawPtr { data_pointer_ty, output_pointer_ty } , FIRST_VARIANT )
928+ }
908929 } ;
909930
910- let fields: Option < Vec < _ > > = fields
931+ let fields: Option < Vec < _ > > = field_ops
911932 . iter_mut ( )
912933 . map ( |op| self . simplify_operand ( op, location) . or_else ( || self . new_opaque ( ) ) )
913934 . collect ( ) ;
914- let fields = fields?;
935+ let mut fields = fields?;
936+
937+ if let AggregateTy :: RawPtr { data_pointer_ty, output_pointer_ty } = & mut ty {
938+ let mut was_updated = false ;
939+
940+ // Any thin pointer of matching mutability is fine as the data pointer.
941+ while let Value :: Cast {
942+ kind : CastKind :: PtrToPtr ,
943+ value : cast_value,
944+ from : cast_from,
945+ to : _,
946+ } = self . get ( fields[ 0 ] )
947+ && let ty:: RawPtr ( from_pointee_ty, from_mtbl) = cast_from. kind ( )
948+ && let ty:: RawPtr ( _, output_mtbl) = output_pointer_ty. kind ( )
949+ && from_mtbl == output_mtbl
950+ && from_pointee_ty. is_sized ( self . tcx , self . param_env )
951+ {
952+ fields[ 0 ] = * cast_value;
953+ * data_pointer_ty = * cast_from;
954+ was_updated = true ;
955+ }
956+
957+ if was_updated {
958+ if let Some ( const_) = self . try_as_constant ( fields[ 0 ] ) {
959+ field_ops[ FieldIdx :: ZERO ] = Operand :: Constant ( Box :: new ( const_) ) ;
960+ } else if let Some ( local) = self . try_as_local ( fields[ 0 ] , location) {
961+ field_ops[ FieldIdx :: ZERO ] = Operand :: Copy ( Place :: from ( local) ) ;
962+ self . reused_locals . insert ( local) ;
963+ }
964+ }
965+ }
915966
916967 if let AggregateTy :: Array = ty
917968 && fields. len ( ) > 4
@@ -943,6 +994,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
943994 ( UnOp :: Not , Value :: BinaryOp ( BinOp :: Ne , lhs, rhs) ) => {
944995 Value :: BinaryOp ( BinOp :: Eq , * lhs, * rhs)
945996 }
997+ ( UnOp :: PtrMetadata , Value :: Aggregate ( AggregateTy :: RawPtr { .. } , _, fields) ) => {
998+ return Some ( fields[ 1 ] ) ;
999+ }
9461000 _ => return None ,
9471001 } ;
9481002
@@ -1094,6 +1148,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
10941148 return self . new_opaque ( ) ;
10951149 }
10961150
1151+ let mut was_updated = false ;
1152+
1153+ // If that cast just casts away the metadata again,
1154+ if let PtrToPtr = kind
1155+ && let Value :: Aggregate ( AggregateTy :: RawPtr { data_pointer_ty, .. } , _, fields) =
1156+ self . get ( value)
1157+ && let ty:: RawPtr ( to_pointee, _) = to. kind ( )
1158+ && to_pointee. is_sized ( self . tcx , self . param_env )
1159+ {
1160+ from = * data_pointer_ty;
1161+ value = fields[ 0 ] ;
1162+ was_updated = true ;
1163+ if * data_pointer_ty == to {
1164+ return Some ( fields[ 0 ] ) ;
1165+ }
1166+ }
1167+
10971168 if let PtrToPtr | PointerCoercion ( MutToConstPointer ) = kind
10981169 && let Value :: Cast { kind : inner_kind, value : inner_value, from : inner_from, to : _ } =
10991170 * self . get ( value)
@@ -1102,9 +1173,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
11021173 from = inner_from;
11031174 value = inner_value;
11041175 * kind = PtrToPtr ;
1176+ was_updated = true ;
11051177 if inner_from == to {
11061178 return Some ( inner_value) ;
11071179 }
1180+ }
1181+
1182+ if was_updated {
11081183 if let Some ( const_) = self . try_as_constant ( value) {
11091184 * operand = Operand :: Constant ( Box :: new ( const_) ) ;
11101185 } else if let Some ( local) = self . try_as_local ( value, location) {
0 commit comments