@@ -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,62 @@ 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+ Value :: Cast { kind : CastKind :: PtrToPtr , value : inner, from, to }
996+ if from. builtin_deref ( true ) ?. ptr_metadata_ty_or_tail ( self . tcx , |t| t)
997+ == to. builtin_deref ( true ) ?. ptr_metadata_ty_or_tail ( self . tcx , |t| t) =>
998+ {
999+ arg_index = * inner;
1000+ was_updated = true ;
1001+ continue ;
1002+ }
1003+
1004+ // `&mut *p`, `&raw *p`, etc don't change metadata.
1005+ Value :: Address { place, kind : _, provenance : _ }
1006+ if let PlaceRef { local, projection : [ PlaceElem :: Deref ] } =
1007+ place. as_ref ( )
1008+ && let Some ( local_index) = self . locals [ local] =>
1009+ {
1010+ arg_index = local_index;
1011+ was_updated = true ;
1012+ continue ;
1013+ }
1014+
1015+ _ => {
1016+ if was_updated && let Some ( op) = self . try_as_operand ( arg_index, location) {
1017+ * arg_op = op;
1018+ }
1019+ break ;
1020+ }
1021+ }
1022+ }
1023+ }
1024+
1025+ let value = match ( op, self . get ( arg_index) ) {
9761026 ( UnOp :: Not , Value :: UnaryOp ( UnOp :: Not , inner) ) => return Some ( * inner) ,
9771027 ( UnOp :: Neg , Value :: UnaryOp ( UnOp :: Neg , inner) ) => return Some ( * inner) ,
9781028 ( UnOp :: Not , Value :: BinaryOp ( BinOp :: Eq , lhs, rhs) ) => {
@@ -984,9 +1034,26 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
9841034 ( UnOp :: PtrMetadata , Value :: Aggregate ( AggregateTy :: RawPtr { .. } , _, fields) ) => {
9851035 return Some ( fields[ 1 ] ) ;
9861036 }
987- _ => return None ,
1037+ // We have an unsizing cast, which assigns the length to fat pointer metadata.
1038+ (
1039+ UnOp :: PtrMetadata ,
1040+ Value :: Cast {
1041+ kind : CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: Unsize ) ,
1042+ from,
1043+ to,
1044+ ..
1045+ } ,
1046+ ) if let ty:: Slice ( ..) = to. builtin_deref ( true ) . unwrap ( ) . kind ( )
1047+ && let ty:: Array ( _, len) = from. builtin_deref ( true ) . unwrap ( ) . kind ( ) =>
1048+ {
1049+ return self . insert_constant ( Const :: from_ty_const (
1050+ * len,
1051+ self . tcx . types . usize ,
1052+ self . tcx ,
1053+ ) ) ;
1054+ }
1055+ _ => Value :: UnaryOp ( op, arg_index) ,
9881056 } ;
989-
9901057 Some ( self . insert ( value) )
9911058 }
9921059
0 commit comments