@@ -840,12 +840,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
840840 }
841841 Value :: BinaryOp ( op, lhs, rhs)
842842 }
843- Rvalue :: UnaryOp ( op, ref mut arg) => {
844- let arg = self . simplify_operand ( arg, location) ?;
845- if let Some ( value) = self . simplify_unary ( op, arg) {
846- return Some ( value) ;
847- }
848- Value :: UnaryOp ( op, arg)
843+ Rvalue :: UnaryOp ( op, ref mut arg_op) => {
844+ return self . simplify_unary ( op, arg_op, location) ;
849845 }
850846 Rvalue :: Discriminant ( ref mut place) => {
851847 let place = self . simplify_place_value ( place, location) ?;
@@ -975,8 +971,71 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
975971 }
976972
977973 #[ instrument( level = "trace" , skip( self ) , ret) ]
978- fn simplify_unary ( & mut self , op : UnOp , value : VnIndex ) -> Option < VnIndex > {
979- let value = match ( op, self . get ( value) ) {
974+ fn simplify_unary (
975+ & mut self ,
976+ op : UnOp ,
977+ arg_op : & mut Operand < ' tcx > ,
978+ location : Location ,
979+ ) -> Option < VnIndex > {
980+ let mut arg_index = self . simplify_operand ( arg_op, location) ?;
981+
982+ // PtrMetadata doesn't care about *const vs *mut vs & vs &mut,
983+ // so start by removing those distinctions so we can update the `Operand`
984+ if op == UnOp :: PtrMetadata {
985+ let mut was_updated = false ;
986+ loop {
987+ match self . get ( arg_index) {
988+ // Pointer casts that preserve metadata, such as
989+ // `*const [i32]` <-> `*mut [i32]` <-> `*mut [f32]`.
990+ // It's critical that this not eliminate cases like
991+ // `*const [T]` -> `*const T` which remove metadata.
992+ // We run on potentially-generic MIR, though, so unlike codegen
993+ // we can't always know exactly what the metadata are.
994+ // Thankfully, equality on `ptr_metadata_ty_or_tail` gives us
995+ // what we need: `Ok(meta_ty)` if the metadata is known, or
996+ // `Err(tail_ty)` if not. Matching metadata is ok, but if
997+ // that's not known, then matching tail types is also ok,
998+ // allowing things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`.
999+ // FIXME: remove MutToConst after #126308
1000+ Value :: Cast {
1001+ kind :
1002+ CastKind :: PtrToPtr
1003+ | CastKind :: PointerCoercion (
1004+ ty:: adjustment:: PointerCoercion :: MutToConstPointer ,
1005+ ) ,
1006+ value : inner,
1007+ from,
1008+ to,
1009+ } if from. builtin_deref ( true ) ?. ptr_metadata_ty_or_tail ( self . tcx , |t| t)
1010+ == to. builtin_deref ( true ) ?. ptr_metadata_ty_or_tail ( self . tcx , |t| t) =>
1011+ {
1012+ arg_index = * inner;
1013+ was_updated = true ;
1014+ continue ;
1015+ }
1016+
1017+ // `&mut *p`, `&raw *p`, etc don't change metadata.
1018+ Value :: Address { place, kind : _, provenance : _ }
1019+ if let PlaceRef { local, projection : [ PlaceElem :: Deref ] } =
1020+ place. as_ref ( )
1021+ && let Some ( local_index) = self . locals [ local] =>
1022+ {
1023+ arg_index = local_index;
1024+ was_updated = true ;
1025+ continue ;
1026+ }
1027+
1028+ _ => {
1029+ if was_updated && let Some ( op) = self . try_as_operand ( arg_index, location) {
1030+ * arg_op = op;
1031+ }
1032+ break ;
1033+ }
1034+ }
1035+ }
1036+ }
1037+
1038+ let value = match ( op, self . get ( arg_index) ) {
9801039 ( UnOp :: Not , Value :: UnaryOp ( UnOp :: Not , inner) ) => return Some ( * inner) ,
9811040 ( UnOp :: Neg , Value :: UnaryOp ( UnOp :: Neg , inner) ) => return Some ( * inner) ,
9821041 ( UnOp :: Not , Value :: BinaryOp ( BinOp :: Eq , lhs, rhs) ) => {
@@ -988,9 +1047,26 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
9881047 ( UnOp :: PtrMetadata , Value :: Aggregate ( AggregateTy :: RawPtr { .. } , _, fields) ) => {
9891048 return Some ( fields[ 1 ] ) ;
9901049 }
991- _ => return None ,
1050+ // We have an unsizing cast, which assigns the length to fat pointer metadata.
1051+ (
1052+ UnOp :: PtrMetadata ,
1053+ Value :: Cast {
1054+ kind : CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: Unsize ) ,
1055+ from,
1056+ to,
1057+ ..
1058+ } ,
1059+ ) if let ty:: Slice ( ..) = to. builtin_deref ( true ) . unwrap ( ) . kind ( )
1060+ && let ty:: Array ( _, len) = from. builtin_deref ( true ) . unwrap ( ) . kind ( ) =>
1061+ {
1062+ return self . insert_constant ( Const :: from_ty_const (
1063+ * len,
1064+ self . tcx . types . usize ,
1065+ self . tcx ,
1066+ ) ) ;
1067+ }
1068+ _ => Value :: UnaryOp ( op, arg_index) ,
9921069 } ;
993-
9941070 Some ( self . insert ( value) )
9951071 }
9961072
0 commit comments