@@ -836,12 +836,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
836
836
}
837
837
Value :: BinaryOp ( op, lhs, rhs)
838
838
}
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) ;
845
841
}
846
842
Rvalue :: Discriminant ( ref mut place) => {
847
843
let place = self . simplify_place_value ( place, location) ?;
@@ -971,8 +967,62 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
971
967
}
972
968
973
969
#[ 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) ) {
976
1026
( UnOp :: Not , Value :: UnaryOp ( UnOp :: Not , inner) ) => return Some ( * inner) ,
977
1027
( UnOp :: Neg , Value :: UnaryOp ( UnOp :: Neg , inner) ) => return Some ( * inner) ,
978
1028
( UnOp :: Not , Value :: BinaryOp ( BinOp :: Eq , lhs, rhs) ) => {
@@ -984,9 +1034,26 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
984
1034
( UnOp :: PtrMetadata , Value :: Aggregate ( AggregateTy :: RawPtr { .. } , _, fields) ) => {
985
1035
return Some ( fields[ 1 ] ) ;
986
1036
}
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) ,
988
1056
} ;
989
-
990
1057
Some ( self . insert ( value) )
991
1058
}
992
1059
0 commit comments