@@ -201,13 +201,16 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
201201
202202 // enums
203203 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.
205205 match layout. variants {
206206 layout:: Variants :: Single { index } => {
207207 // Inside a variant
208208 PathElem :: Field ( def. variants [ index] . fields [ field] . ident . name )
209209 }
210- _ => bug ! ( ) ,
210+ layout:: Variants :: Multiple { discr_index, .. } => {
211+ assert_eq ! ( discr_index, field) ;
212+ PathElem :: Tag
213+ }
211214 }
212215 }
213216
@@ -288,62 +291,6 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
288291
289292 Ok ( ( ) )
290293 }
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- }
347294
348295 fn visit_primitive ( & mut self , value : OpTy < ' tcx , M :: PointerTag > ) -> InterpResult < ' tcx > {
349296 let value = self . ecx . read_immediate ( value) ?;
@@ -421,7 +368,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
421368 throw_validation_failure ! (
422369 format_args!(
423370 "unaligned reference \
424- (required {} byte alignment but found {})",
371+ (required {} byte alignment but found {})",
425372 required. bytes( ) ,
426373 has. bytes( )
427374 ) ,
@@ -485,16 +432,12 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
485432 ) ;
486433 // FIXME: Check if the signature matches
487434 }
488- // This should be all the primitive types
435+ // This should be all the (inhabited) primitive types
489436 _ => bug ! ( "Unexpected primitive type {}" , value. layout. ty) ,
490437 }
491438 Ok ( ( ) )
492439 }
493440
494- fn visit_uninhabited ( & mut self ) -> InterpResult < ' tcx > {
495- throw_validation_failure ! ( "a value of an uninhabited type" , self . path)
496- }
497-
498441 fn visit_scalar (
499442 & mut self ,
500443 op : OpTy < ' tcx , M :: PointerTag > ,
@@ -559,6 +502,116 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
559502 )
560503 }
561504 }
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+ }
562615
563616 fn visit_aggregate (
564617 & mut self ,
0 commit comments