@@ -836,12 +836,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
836836 }
837837 Value :: BinaryOp ( op, lhs, rhs)
838838 }
839- Rvalue :: UnaryOp ( op, ref mut arg) => {
840- let arg = self . simplify_operand ( arg, location) ?;
841- if let Some ( value) = self . simplify_unary ( op, arg) {
842- return Some ( value) ;
843- }
844- Value :: UnaryOp ( op, arg)
839+ Rvalue :: UnaryOp ( op, ref mut arg_op) => {
840+ return self . simplify_unary ( op, arg_op, location) ;
845841 }
846842 Rvalue :: Discriminant ( ref mut place) => {
847843 let place = self . simplify_place_value ( place, location) ?;
@@ -971,8 +967,71 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
971967 }
972968
973969 #[ instrument( level = "trace" , skip( self ) , ret) ]
974- fn simplify_unary ( & mut self , op : UnOp , value : VnIndex ) -> Option < VnIndex > {
975- let value = match ( op, self . get ( value) ) {
970+ fn simplify_unary (
971+ & mut self ,
972+ op : UnOp ,
973+ arg_op : & mut Operand < ' tcx > ,
974+ location : Location ,
975+ ) -> Option < VnIndex > {
976+ let mut arg_index = self . simplify_operand ( arg_op, location) ?;
977+
978+ // PtrMetadata doesn't care about *const vs *mut vs & vs &mut,
979+ // so start by removing those distinctions so we can update the `Operand`
980+ if op == UnOp :: PtrMetadata {
981+ let mut was_updated = false ;
982+ loop {
983+ match self . get ( arg_index) {
984+ // Pointer casts that preserve metadata, such as
985+ // `*const [i32]` <-> `*mut [i32]` <-> `*mut [f32]`.
986+ // It's critical that this not eliminate cases like
987+ // `*const [T]` -> `*const T` which remove metadata.
988+ // We run on potentially-generic MIR, though, so unlike codegen
989+ // we can't always know exactly what the metadata are.
990+ // Thankfully, equality on `ptr_metadata_ty_or_tail` gives us
991+ // what we need: `Ok(meta_ty)` if the metadata is known, or
992+ // `Err(tail_ty)` if not. Matching metadata is ok, but if
993+ // that's not known, then matching tail types is also ok,
994+ // allowing things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`.
995+ // FIXME: Would it be worth trying to normalize, rather than
996+ // passing the identity closure? Or are the types in the
997+ // Cast realistically about as normalized as we can get anyway?
998+ Value :: Cast { kind : CastKind :: PtrToPtr , value : inner, from, to }
999+ if from
1000+ . builtin_deref ( true )
1001+ . unwrap ( )
1002+ . ptr_metadata_ty_or_tail ( self . tcx , |t| t)
1003+ == to
1004+ . builtin_deref ( true )
1005+ . unwrap ( )
1006+ . ptr_metadata_ty_or_tail ( self . tcx , |t| t) =>
1007+ {
1008+ arg_index = * inner;
1009+ was_updated = true ;
1010+ continue ;
1011+ }
1012+
1013+ // `&mut *p`, `&raw *p`, etc don't change metadata.
1014+ Value :: Address { place, kind : _, provenance : _ }
1015+ if let PlaceRef { local, projection : [ PlaceElem :: Deref ] } =
1016+ place. as_ref ( )
1017+ && let Some ( local_index) = self . locals [ local] =>
1018+ {
1019+ arg_index = local_index;
1020+ was_updated = true ;
1021+ continue ;
1022+ }
1023+
1024+ _ => {
1025+ if was_updated && let Some ( op) = self . try_as_operand ( arg_index, location) {
1026+ * arg_op = op;
1027+ }
1028+ break ;
1029+ }
1030+ }
1031+ }
1032+ }
1033+
1034+ let value = match ( op, self . get ( arg_index) ) {
9761035 ( UnOp :: Not , Value :: UnaryOp ( UnOp :: Not , inner) ) => return Some ( * inner) ,
9771036 ( UnOp :: Neg , Value :: UnaryOp ( UnOp :: Neg , inner) ) => return Some ( * inner) ,
9781037 ( UnOp :: Not , Value :: BinaryOp ( BinOp :: Eq , lhs, rhs) ) => {
@@ -984,9 +1043,26 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
9841043 ( UnOp :: PtrMetadata , Value :: Aggregate ( AggregateTy :: RawPtr { .. } , _, fields) ) => {
9851044 return Some ( fields[ 1 ] ) ;
9861045 }
987- _ => return None ,
1046+ // We have an unsizing cast, which assigns the length to fat pointer metadata.
1047+ (
1048+ UnOp :: PtrMetadata ,
1049+ Value :: Cast {
1050+ kind : CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: Unsize ) ,
1051+ from,
1052+ to,
1053+ ..
1054+ } ,
1055+ ) if let ty:: Slice ( ..) = to. builtin_deref ( true ) . unwrap ( ) . kind ( )
1056+ && let ty:: Array ( _, len) = from. builtin_deref ( true ) . unwrap ( ) . kind ( ) =>
1057+ {
1058+ return self . insert_constant ( Const :: from_ty_const (
1059+ * len,
1060+ self . tcx . types . usize ,
1061+ self . tcx ,
1062+ ) ) ;
1063+ }
1064+ _ => Value :: UnaryOp ( op, arg_index) ,
9881065 } ;
989-
9901066 Some ( self . insert ( value) )
9911067 }
9921068
0 commit comments