@@ -1021,6 +1021,10 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi
10211021pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriEvalContextExt < ' mir , ' tcx > {
10221022 fn retag ( & mut self , kind : RetagKind , place : & PlaceTy < ' tcx , Tag > ) -> InterpResult < ' tcx > {
10231023 let this = self . eval_context_mut ( ) ;
1024+ let retag_fields = this. machine . stacked_borrows . as_mut ( ) . unwrap ( ) . get_mut ( ) . retag_fields ;
1025+ let mut visitor = RetagVisitor { ecx : this, kind, retag_fields } ;
1026+ return visitor. visit_value ( place) ;
1027+
10241028 // Determine mutability and whether to add a protector.
10251029 // Cannot use `builtin_deref` because that reports *immutable* for `Box`,
10261030 // making it useless.
@@ -1037,90 +1041,67 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
10371041 // Raw pointers need to be enabled.
10381042 ty:: RawPtr ( tym) if kind == RetagKind :: Raw =>
10391043 Some ( ( RefKind :: Raw { mutable : tym. mutbl == Mutability :: Mut } , false ) ) ,
1040- // Boxes are handled separately due to that allocator situation.
1044+ // Boxes are handled separately due to that allocator situation,
1045+ // see the visitor below.
10411046 _ => None ,
10421047 }
10431048 }
10441049
1045- // We need a visitor to visit all references. However, that requires
1046- // a `MPlaceTy` (or `OpTy`), so we have a fast path for reference types that
1047- // avoids allocating.
1048-
1049- if let Some ( ( ref_kind, protector) ) = qualify ( place. layout . ty , kind) {
1050- // Fast path.
1051- let val = this. read_immediate ( & this. place_to_op ( place) ?) ?;
1052- let val = this. retag_reference ( & val, ref_kind, protector) ?;
1053- this. write_immediate ( * val, place) ?;
1054- return Ok ( ( ) ) ;
1055- }
1056-
1057- // If we don't want to recurse, we are already done.
1058- // EXCEPT if this is a `Box`, then we have to recurse because allocators.
1059- // (Yes this means we technically also recursively retag the allocator itself even if field
1060- // retagging is not enabled. *shrug*)
1061- if !this. machine . stacked_borrows . as_mut ( ) . unwrap ( ) . get_mut ( ) . retag_fields
1062- && !place. layout . ty . ty_adt_def ( ) . is_some_and ( |adt| adt. is_box ( ) )
1063- {
1064- return Ok ( ( ) ) ;
1065- }
1066-
1067- // Skip some types that have no further structure we might care about.
1068- if matches ! (
1069- place. layout. ty. kind( ) ,
1070- ty:: RawPtr ( ..)
1071- | ty:: Ref ( ..)
1072- | ty:: Int ( ..)
1073- | ty:: Uint ( ..)
1074- | ty:: Float ( ..)
1075- | ty:: Bool
1076- | ty:: Char
1077- ) {
1078- return Ok ( ( ) ) ;
1079- }
1080- // Now go visit this thing.
1081- let place = this. force_allocation ( place) ?;
1082-
1083- let mut visitor = RetagVisitor { ecx : this, kind } ;
1084- return visitor. visit_value ( & place) ;
1085-
10861050 // The actual visitor.
10871051 struct RetagVisitor < ' ecx , ' mir , ' tcx > {
10881052 ecx : & ' ecx mut MiriEvalContext < ' mir , ' tcx > ,
10891053 kind : RetagKind ,
1054+ retag_fields : bool ,
1055+ }
1056+ impl < ' ecx , ' mir , ' tcx > RetagVisitor < ' ecx , ' mir , ' tcx > {
1057+ #[ inline( always) ] // yes this helps in our benchmarks
1058+ fn retag_place (
1059+ & mut self ,
1060+ place : & PlaceTy < ' tcx , Tag > ,
1061+ ref_kind : RefKind ,
1062+ protector : bool ,
1063+ ) -> InterpResult < ' tcx > {
1064+ let val = self . ecx . read_immediate ( & self . ecx . place_to_op ( place) ?) ?;
1065+ let val = self . ecx . retag_reference ( & val, ref_kind, protector) ?;
1066+ self . ecx . write_immediate ( * val, place) ?;
1067+ Ok ( ( ) )
1068+ }
10901069 }
10911070 impl < ' ecx , ' mir , ' tcx > MutValueVisitor < ' mir , ' tcx , Evaluator < ' mir , ' tcx > >
10921071 for RetagVisitor < ' ecx , ' mir , ' tcx >
10931072 {
1094- type V = MPlaceTy < ' tcx , Tag > ;
1073+ type V = PlaceTy < ' tcx , Tag > ;
10951074
10961075 #[ inline( always) ]
10971076 fn ecx ( & mut self ) -> & mut MiriEvalContext < ' mir , ' tcx > {
10981077 self . ecx
10991078 }
11001079
1101- fn visit_box ( & mut self , place : & MPlaceTy < ' tcx , Tag > ) -> InterpResult < ' tcx > {
1080+ fn visit_box ( & mut self , place : & PlaceTy < ' tcx , Tag > ) -> InterpResult < ' tcx > {
11021081 // Boxes do not get a protector: protectors reflect that references outlive the call
11031082 // they were passed in to; that's just not the case for boxes.
1104- let ( ref_kind, protector) = ( RefKind :: Unique { two_phase : false } , false ) ;
1105-
1106- let val = self . ecx . read_immediate ( & place. into ( ) ) ?;
1107- let val = self . ecx . retag_reference ( & val, ref_kind, protector) ?;
1108- self . ecx . write_immediate ( * val, & place. into ( ) ) ?;
1109- Ok ( ( ) )
1083+ self . retag_place (
1084+ place,
1085+ RefKind :: Unique { two_phase : false } ,
1086+ /*protector*/ false ,
1087+ )
11101088 }
11111089
1112- fn visit_value ( & mut self , place : & MPlaceTy < ' tcx , Tag > ) -> InterpResult < ' tcx > {
1090+ fn visit_value ( & mut self , place : & PlaceTy < ' tcx , Tag > ) -> InterpResult < ' tcx > {
11131091 if let Some ( ( ref_kind, protector) ) = qualify ( place. layout . ty , self . kind ) {
1114- let val = self . ecx . read_immediate ( & place. into ( ) ) ?;
1115- let val = self . ecx . retag_reference ( & val, ref_kind, protector) ?;
1116- self . ecx . write_immediate ( * val, & place. into ( ) ) ?;
1092+ self . retag_place ( place, ref_kind, protector) ?;
11171093 } else if matches ! ( place. layout. ty. kind( ) , ty:: RawPtr ( ..) ) {
11181094 // Wide raw pointers *do* have fields and their types are strange.
11191095 // vtables have a type like `&[*const (); 3]` or so!
11201096 // Do *not* recurse into them.
1121- // (No need to worry about wide references or boxes, those always "qualify".)
1122- } else {
1123- // Maybe we need to go deeper.
1097+ // (No need to worry about wide references, those always "qualify". And Boxes
1098+ // are handles specially by the visitor anyway.)
1099+ } else if self . retag_fields
1100+ || place. layout . ty . ty_adt_def ( ) . is_some_and ( |adt| adt. is_box ( ) )
1101+ {
1102+ // Recurse deeper. Need to always recurse for `Box` to even hit `visit_box`.
1103+ // (Yes this means we technically also recursively retag the allocator itself
1104+ // even if field retagging is not enabled. *shrug*)
11241105 self . walk_value ( place) ?;
11251106 }
11261107 Ok ( ( ) )
0 commit comments