@@ -840,8 +840,56 @@ 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) ?;
843+ Rvalue :: UnaryOp ( op, ref mut arg_op) => {
844+ let mut arg = self . simplify_operand ( arg_op, location) ?;
845+
846+ // PtrMetadata doesn't care about *const vs *mut vs & vs &mut,
847+ // so start by removing those distinctions so we can update the `Operand`
848+ if op == UnOp :: PtrMetadata {
849+ let mut was_updated = false ;
850+ loop {
851+ let value = self . get ( arg) ;
852+
853+ // FIXME: remove MutToConst after #126308
854+ if let Value :: Cast {
855+ kind :
856+ CastKind :: PtrToPtr
857+ | CastKind :: PointerCoercion (
858+ ty:: adjustment:: PointerCoercion :: MutToConstPointer ,
859+ ) ,
860+ value : inner,
861+ from,
862+ to,
863+ } = value
864+ && from. builtin_deref ( true ) == to. builtin_deref ( true )
865+ {
866+ arg = * inner;
867+ was_updated = true ;
868+ continue ;
869+ }
870+
871+ if let Value :: Address { place, kind : _, provenance : _ } = value
872+ && let PlaceRef { local, projection : [ PlaceElem :: Deref ] } =
873+ place. as_ref ( )
874+ && let Some ( local_index) = self . locals [ local]
875+ {
876+ arg = local_index;
877+ was_updated = true ;
878+ continue ;
879+ }
880+
881+ if was_updated {
882+ if let Some ( const_) = self . try_as_constant ( arg) {
883+ * arg_op = Operand :: Constant ( Box :: new ( const_) ) ;
884+ } else if let Some ( local) = self . try_as_local ( arg, location) {
885+ * arg_op = Operand :: Copy ( Place :: from ( local) ) ;
886+ self . reused_locals . insert ( local) ;
887+ }
888+ }
889+ break ;
890+ }
891+ }
892+
845893 if let Some ( value) = self . simplify_unary ( op, arg) {
846894 return Some ( value) ;
847895 }
@@ -996,6 +1044,24 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
9961044 ( UnOp :: PtrMetadata , Value :: Aggregate ( AggregateTy :: RawPtr { .. } , _, fields) ) => {
9971045 return Some ( fields[ 1 ] ) ;
9981046 }
1047+ // We have an unsizing cast, which assigns the length to fat pointer metadata.
1048+ (
1049+ UnOp :: PtrMetadata ,
1050+ Value :: Cast {
1051+ kind : CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: Unsize ) ,
1052+ from,
1053+ to,
1054+ ..
1055+ } ,
1056+ ) if let ty:: Slice ( ..) = to. builtin_deref ( true ) . unwrap ( ) . kind ( )
1057+ && let ty:: Array ( _, len) = from. builtin_deref ( true ) . unwrap ( ) . kind ( ) =>
1058+ {
1059+ return self . insert_constant ( Const :: from_ty_const (
1060+ * len,
1061+ self . tcx . types . usize ,
1062+ self . tcx ,
1063+ ) ) ;
1064+ }
9991065 _ => return None ,
10001066 } ;
10011067
0 commit comments