@@ -201,13 +201,16 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
201
201
202
202
// enums
203
203
ty:: Adt ( def, ..) if def. is_enum ( ) => {
204
- // we might be projecting *to* a variant, or to a field *in*a variant.
204
+ // we might be projecting *to* a variant, or to a field *in* a variant.
205
205
match layout. variants {
206
206
layout:: Variants :: Single { index } => {
207
207
// Inside a variant
208
208
PathElem :: Field ( def. variants [ index] . fields [ field] . ident . name )
209
209
}
210
- _ => bug ! ( ) ,
210
+ layout:: Variants :: Multiple { discr_index, .. } => {
211
+ assert_eq ! ( discr_index, field) ;
212
+ PathElem :: Tag
213
+ }
211
214
}
212
215
}
213
216
@@ -288,62 +291,6 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
288
291
289
292
Ok ( ( ) )
290
293
}
291
- }
292
-
293
- impl < ' rt , ' mir , ' tcx , M : Machine < ' mir , ' tcx > > ValueVisitor < ' mir , ' tcx , M >
294
- for ValidityVisitor < ' rt , ' mir , ' tcx , M >
295
- {
296
- type V = OpTy < ' tcx , M :: PointerTag > ;
297
-
298
- #[ inline( always) ]
299
- fn ecx ( & self ) -> & InterpCx < ' mir , ' tcx , M > {
300
- & self . ecx
301
- }
302
-
303
- #[ inline]
304
- fn visit_field (
305
- & mut self ,
306
- old_op : OpTy < ' tcx , M :: PointerTag > ,
307
- field : usize ,
308
- new_op : OpTy < ' tcx , M :: PointerTag > ,
309
- ) -> InterpResult < ' tcx > {
310
- let elem = self . aggregate_field_path_elem ( old_op. layout , field) ;
311
- self . visit_elem ( new_op, elem)
312
- }
313
-
314
- #[ inline]
315
- fn visit_variant (
316
- & mut self ,
317
- old_op : OpTy < ' tcx , M :: PointerTag > ,
318
- variant_id : VariantIdx ,
319
- new_op : OpTy < ' tcx , M :: PointerTag > ,
320
- ) -> InterpResult < ' tcx > {
321
- let name = match old_op. layout . ty . kind {
322
- ty:: Adt ( adt, _) => PathElem :: Variant ( adt. variants [ variant_id] . ident . name ) ,
323
- // Generators also have variants
324
- ty:: Generator ( ..) => PathElem :: GeneratorState ( variant_id) ,
325
- _ => bug ! ( "Unexpected type with variant: {:?}" , old_op. layout. ty) ,
326
- } ;
327
- self . visit_elem ( new_op, name)
328
- }
329
-
330
- #[ inline]
331
- fn visit_value ( & mut self , op : OpTy < ' tcx , M :: PointerTag > ) -> InterpResult < ' tcx > {
332
- trace ! ( "visit_value: {:?}, {:?}" , * op, op. layout) ;
333
- // Translate some possible errors to something nicer.
334
- match self . walk_value ( op) {
335
- Ok ( ( ) ) => Ok ( ( ) ) ,
336
- Err ( err) => match err. kind {
337
- err_ub ! ( InvalidDiscriminant ( val) ) => {
338
- throw_validation_failure ! ( val, self . path, "a valid enum discriminant" )
339
- }
340
- err_unsup ! ( ReadPointerAsBytes ) => {
341
- throw_validation_failure ! ( "a pointer" , self . path, "plain (non-pointer) bytes" )
342
- }
343
- _ => Err ( err) ,
344
- } ,
345
- }
346
- }
347
294
348
295
fn visit_primitive ( & mut self , value : OpTy < ' tcx , M :: PointerTag > ) -> InterpResult < ' tcx > {
349
296
let value = self . ecx . read_immediate ( value) ?;
@@ -421,7 +368,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
421
368
throw_validation_failure ! (
422
369
format_args!(
423
370
"unaligned reference \
424
- (required {} byte alignment but found {})",
371
+ (required {} byte alignment but found {})",
425
372
required. bytes( ) ,
426
373
has. bytes( )
427
374
) ,
@@ -485,16 +432,12 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
485
432
) ;
486
433
// FIXME: Check if the signature matches
487
434
}
488
- // This should be all the primitive types
435
+ // This should be all the (inhabited) primitive types
489
436
_ => bug ! ( "Unexpected primitive type {}" , value. layout. ty) ,
490
437
}
491
438
Ok ( ( ) )
492
439
}
493
440
494
- fn visit_uninhabited ( & mut self ) -> InterpResult < ' tcx > {
495
- throw_validation_failure ! ( "a value of an uninhabited type" , self . path)
496
- }
497
-
498
441
fn visit_scalar (
499
442
& mut self ,
500
443
op : OpTy < ' tcx , M :: PointerTag > ,
@@ -559,6 +502,116 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
559
502
)
560
503
}
561
504
}
505
+ }
506
+
507
+ impl < ' rt , ' mir , ' tcx , M : Machine < ' mir , ' tcx > > ValueVisitor < ' mir , ' tcx , M >
508
+ for ValidityVisitor < ' rt , ' mir , ' tcx , M >
509
+ {
510
+ type V = OpTy < ' tcx , M :: PointerTag > ;
511
+
512
+ #[ inline( always) ]
513
+ fn ecx ( & self ) -> & InterpCx < ' mir , ' tcx , M > {
514
+ & self . ecx
515
+ }
516
+
517
+ #[ inline]
518
+ fn visit_field (
519
+ & mut self ,
520
+ old_op : OpTy < ' tcx , M :: PointerTag > ,
521
+ field : usize ,
522
+ new_op : OpTy < ' tcx , M :: PointerTag > ,
523
+ ) -> InterpResult < ' tcx > {
524
+ let elem = self . aggregate_field_path_elem ( old_op. layout , field) ;
525
+ self . visit_elem ( new_op, elem)
526
+ }
527
+
528
+ #[ inline]
529
+ fn visit_variant (
530
+ & mut self ,
531
+ old_op : OpTy < ' tcx , M :: PointerTag > ,
532
+ variant_id : VariantIdx ,
533
+ new_op : OpTy < ' tcx , M :: PointerTag > ,
534
+ ) -> InterpResult < ' tcx > {
535
+ let name = match old_op. layout . ty . kind {
536
+ ty:: Adt ( adt, _) => PathElem :: Variant ( adt. variants [ variant_id] . ident . name ) ,
537
+ // Generators also have variants
538
+ ty:: Generator ( ..) => PathElem :: GeneratorState ( variant_id) ,
539
+ _ => bug ! ( "Unexpected type with variant: {:?}" , old_op. layout. ty) ,
540
+ } ;
541
+ self . visit_elem ( new_op, name)
542
+ }
543
+
544
+ #[ inline( always) ]
545
+ fn visit_union ( & mut self , _v : Self :: V , fields : usize ) -> InterpResult < ' tcx > {
546
+ // Empty unions are not accepted by rustc. That's great, it means we can
547
+ // use that as a signal for detecting primitives. Make sure
548
+ // we did not miss any primitive.
549
+ assert ! ( fields > 0 ) ;
550
+ Ok ( ( ) )
551
+ }
552
+
553
+ #[ inline]
554
+ fn visit_value ( & mut self , op : OpTy < ' tcx , M :: PointerTag > ) -> InterpResult < ' tcx > {
555
+ trace ! ( "visit_value: {:?}, {:?}" , * op, op. layout) ;
556
+
557
+ if op. layout . abi . is_uninhabited ( ) {
558
+ // Uninhabited types do not have sensible layout, stop right here.
559
+ throw_validation_failure ! (
560
+ format_args!( "a value of uninhabited type {:?}" , op. layout. ty) ,
561
+ self . path
562
+ )
563
+ }
564
+
565
+ // Check primitive types. We do this after checking for uninhabited types,
566
+ // to exclude fieldless enums (that also appear as fieldless unions here).
567
+ // Primitives can have varying layout, so we check them separately and before aggregate
568
+ // handling.
569
+ // It is CRITICAL that we get this check right, or we might be validating the wrong thing!
570
+ let primitive = match op. layout . fields {
571
+ // Primitives appear as Union with 0 fields - except for Boxes and fat pointers.
572
+ // (Fieldless enums also appear here, but they are uninhabited and thus handled above.)
573
+ layout:: FieldPlacement :: Union ( 0 ) => true ,
574
+ _ => op. layout . ty . builtin_deref ( true ) . is_some ( ) ,
575
+ } ;
576
+ if primitive {
577
+ // No need to recurse further or check scalar layout, this is a leaf type.
578
+ return self . visit_primitive ( op) ;
579
+ }
580
+
581
+ // Recursively walk the type. Translate some possible errors to something nicer.
582
+ match self . walk_value ( op) {
583
+ Ok ( ( ) ) => { }
584
+ Err ( err) => match err. kind {
585
+ err_ub ! ( InvalidDiscriminant ( val) ) => {
586
+ throw_validation_failure ! ( val, self . path, "a valid enum discriminant" )
587
+ }
588
+ err_unsup ! ( ReadPointerAsBytes ) => {
589
+ throw_validation_failure ! ( "a pointer" , self . path, "plain (non-pointer) bytes" )
590
+ }
591
+ _ => return Err ( err) ,
592
+ } ,
593
+ }
594
+
595
+ // *After* all of this, check the ABI. We need to check the ABI to handle
596
+ // types like `NonNull` where the `Scalar` info is more restrictive than what
597
+ // the fields say. But in most cases, this will just propagate what the fields say,
598
+ // and then we want the error to point at the field -- so, first recurse,
599
+ // then check ABI.
600
+ //
601
+ // FIXME: We could avoid some redundant checks here. For newtypes wrapping
602
+ // scalars, we do the same check on every "level" (e.g., first we check
603
+ // MyNewtype and then the scalar in there).
604
+ match op. layout . abi {
605
+ layout:: Abi :: Uninhabited => unreachable ! ( ) , // checked above
606
+ layout:: Abi :: Scalar ( ref layout) => {
607
+ self . visit_scalar ( op, layout) ?;
608
+ }
609
+ // FIXME: Should we do something for ScalarPair? Vector?
610
+ _ => { }
611
+ }
612
+
613
+ Ok ( ( ) )
614
+ }
562
615
563
616
fn visit_aggregate (
564
617
& mut self ,
0 commit comments