@@ -151,6 +151,14 @@ macro_rules! make_value_visitor {
151
151
{
152
152
Ok ( ( ) )
153
153
}
154
+ /// Visits the given value as the pointer of a `Box`. There is nothing to recurse into.
155
+ /// The type of `v` will be a raw pointer, but this is a field of `Box<T>` and the
156
+ /// pointee type is the actual `T`.
157
+ #[ inline( always) ]
158
+ fn visit_box( & mut self , _v: & Self :: V ) -> InterpResult <' tcx>
159
+ {
160
+ Ok ( ( ) )
161
+ }
154
162
/// Visits this value as an aggregate, you are getting an iterator yielding
155
163
/// all the fields (still in an `InterpResult`, you have to do error handling yourself).
156
164
/// Recurses into the fields.
@@ -221,6 +229,47 @@ macro_rules! make_value_visitor {
221
229
// Slices do not need special handling here: they have `Array` field
222
230
// placement with length 0, so we enter the `Array` case below which
223
231
// indirectly uses the metadata to determine the actual length.
232
+
233
+ // However, `Box`... let's talk about `Box`.
234
+ ty:: Adt ( def, ..) if def. is_box( ) => {
235
+ // `Box` is a hybrid primitive-library-defined type that one the one hand is
236
+ // a dereferenceable pointer, on the other hand has *basically arbitrary
237
+ // user-defined layout* since the user controls the 'allocator' field. So it
238
+ // cannot be treated like a normal pointer, since it does not fit into an
239
+ // `Immediate`. Yeah, it is quite terrible. But many visitors want to do
240
+ // something with "all boxed pointers", so we handle this mess for them.
241
+ //
242
+ // When we hit a `Box`, we do not do the usual `visit_aggregate`; instead,
243
+ // we (a) call `visit_box` on the pointer value, and (b) recurse on the
244
+ // allocator field. We also assert tons of things to ensure we do not miss
245
+ // any other fields.
246
+
247
+ // `Box` has two fields: the pointer we care about, and the allocator.
248
+ assert_eq!( v. layout( ) . fields. count( ) , 2 , "`Box` must have exactly 2 fields" ) ;
249
+ let ( unique_ptr, alloc) =
250
+ ( v. project_field( self . ecx( ) , 0 ) ?, v. project_field( self . ecx( ) , 1 ) ?) ;
251
+ // Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`...
252
+ // (which means another 2 fields, the second of which is a `PhantomData`)
253
+ assert_eq!( unique_ptr. layout( ) . fields. count( ) , 2 ) ;
254
+ let ( nonnull_ptr, phantom) = (
255
+ unique_ptr. project_field( self . ecx( ) , 0 ) ?,
256
+ unique_ptr. project_field( self . ecx( ) , 1 ) ?,
257
+ ) ;
258
+ assert!(
259
+ phantom. layout( ) . ty. ty_adt_def( ) . is_some_and( |adt| adt. is_phantom_data( ) ) ,
260
+ "2nd field of `Unique` should be PhantomData but is {:?}" ,
261
+ phantom. layout( ) . ty,
262
+ ) ;
263
+ // ... that contains a `NonNull`... (gladly, only a single field here)
264
+ assert_eq!( nonnull_ptr. layout( ) . fields. count( ) , 1 ) ;
265
+ let raw_ptr = nonnull_ptr. project_field( self . ecx( ) , 0 ) ?; // the actual raw ptr
266
+ // ... whose only field finally is a raw ptr we can dereference.
267
+ self . visit_box( & raw_ptr) ?;
268
+
269
+ // The second `Box` field is the allocator, which we recursively check for validity
270
+ // like in regular structs.
271
+ self . visit_field( v, 1 , & alloc) ?;
272
+ }
224
273
_ => { } ,
225
274
} ;
226
275
0 commit comments