@@ -1442,7 +1442,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
14421442 // First check that the base type is valid
14431443 self . visit_value ( & val. transmute ( self . ecx . layout_of ( * base) ?, self . ecx ) ?) ?;
14441444 // When you extend this match, make sure to also add tests to
1445- // tests/ui/type/pattern_types/validity.rs((
1445+ // tests/ui/type/pattern_types/validity.rs
14461446 match * * pat {
14471447 // Range and non-null patterns are precisely reflected into `valid_range` and thus
14481448 // handled fully by `visit_scalar` (called below).
@@ -1457,6 +1457,34 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
14571457 // we won't see optimizations actually breaking such programs.
14581458 ty:: PatternKind :: Or ( _patterns) => { }
14591459 }
1460+ // FIXME(pattern_types): handle everything based on the pattern, not on the layout.
1461+ // it's ok to run scalar validation even if the pattern type is `u8 is 0..=255` and thus
1462+ // allows uninit values, because that's rare and so not a perf issue.
1463+ match val. layout . backend_repr {
1464+ BackendRepr :: Scalar ( scalar_layout) => {
1465+ if !scalar_layout. is_uninit_valid ( ) {
1466+ // There is something to check here.
1467+ // We read directly via `ecx` since the read cannot fail -- we already read
1468+ // this field above when recursing into the field.
1469+ let scalar = self . ecx . read_scalar ( val) ?;
1470+ self . visit_scalar ( scalar, scalar_layout) ?;
1471+ }
1472+ }
1473+ BackendRepr :: ScalarPair ( a_layout, b_layout) => {
1474+ // We can only proceed if *both* scalars need to be initialized.
1475+ // FIXME: find a way to also check ScalarPair when one side can be uninit but
1476+ // the other must be init.
1477+ if !a_layout. is_uninit_valid ( ) && !b_layout. is_uninit_valid ( ) {
1478+ // We read directly via `ecx` since the read cannot fail -- we already read
1479+ // this field above when recursing into the field.
1480+ let ( a, b) = self . ecx . read_immediate ( val) ?. to_scalar_pair ( ) ;
1481+ self . visit_scalar ( a, a_layout) ?;
1482+ self . visit_scalar ( b, b_layout) ?;
1483+ }
1484+ }
1485+ BackendRepr :: SimdVector { .. } | BackendRepr :: SimdScalableVector { .. } => unreachable ! ( ) ,
1486+ BackendRepr :: Memory { .. } => unreachable ! ( )
1487+ }
14601488 }
14611489 ty:: Adt ( adt, _) if adt. is_maybe_dangling ( ) => {
14621490 let old_may_dangle = mem:: replace ( & mut self . may_dangle , true ) ;
@@ -1479,51 +1507,55 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
14791507 }
14801508 }
14811509
1482- // *After* all of this, check further information stored in the layout. We need to check
1483- // this to handle types like `NonNull` where the `Scalar` info is more restrictive than what
1484- // the fields say (`rustc_layout_scalar_valid_range_start`). But in most cases, this will
1485- // just propagate what the fields say, and then we want the error to point at the field --
1486- // so, we first recurse, then we do this check.
1510+ // *After* all of this, check further information stored in the layout.
1511+ // On leaf types like `!` or empty enums, this will raise the error.
1512+ // This means that for types wrapping such a type, we won't ever get here, but it's
1513+ // just the simplest way to check for this case.
14871514 //
14881515 // FIXME: We could avoid some redundant checks here. For newtypes wrapping
14891516 // scalars, we do the same check on every "level" (e.g., first we check
1490- // MyNewtype and then the scalar in there ).
1517+ // the fields of MyNewtype, and then we check MyNewType again ).
14911518 if val. layout . is_uninhabited ( ) {
14921519 let ty = val. layout . ty ;
14931520 throw_validation_failure ! (
14941521 self . path,
14951522 format!( "encountered a value of uninhabited type `{ty}`" )
14961523 ) ;
14971524 }
1498- match val. layout . backend_repr {
1499- BackendRepr :: Scalar ( scalar_layout) => {
1500- if !scalar_layout. is_uninit_valid ( ) {
1501- // There is something to check here.
1502- // We read directly via `ecx` since the read cannot fail -- we already read
1503- // this field above when recursing into the field.
1504- let scalar = self . ecx . read_scalar ( val) ?;
1505- self . visit_scalar ( scalar, scalar_layout) ?;
1525+ if cfg ! ( debug_assertions) {
1526+ // Check that we don't miss any new changes to layout computation in our checks above.
1527+ match val. layout . backend_repr {
1528+ BackendRepr :: Scalar ( scalar_layout) => {
1529+ if !scalar_layout. is_uninit_valid ( ) {
1530+ // There is something to check here.
1531+ // We read directly via `ecx` since the read cannot fail -- we already read
1532+ // this field above when recursing into the field.
1533+ let scalar = self
1534+ . ecx
1535+ . read_scalar ( val)
1536+ . expect ( "the above checks should have fully handled this situation" ) ;
1537+ self . visit_scalar ( scalar, scalar_layout)
1538+ . expect ( "the above checks should have fully handled this situation" ) ;
1539+ }
15061540 }
1507- }
1508- BackendRepr :: ScalarPair ( a_layout, b_layout) => {
1509- // We can only proceed if *both* scalars need to be initialized.
1510- // FIXME: find a way to also check ScalarPair when one side can be uninit but
1511- // the other must be init.
1512- if !a_layout. is_uninit_valid ( ) && !b_layout. is_uninit_valid ( ) {
1513- // We read directly via `ecx` since the read cannot fail -- we already read
1514- // this field above when recursing into the field.
1515- let ( a, b) = self . ecx . read_immediate ( val) ?. to_scalar_pair ( ) ;
1516- self . visit_scalar ( a, a_layout) ?;
1517- self . visit_scalar ( b, b_layout) ?;
1541+ BackendRepr :: ScalarPair ( a_layout, b_layout) => {
1542+ // We can only proceed if *both* scalars need to be initialized.
1543+ // FIXME: find a way to also check ScalarPair when one side can be uninit but
1544+ // the other must be init.
1545+ if !a_layout. is_uninit_valid ( ) && !b_layout. is_uninit_valid ( ) {
1546+ let ( a, b) = self
1547+ . ecx
1548+ . read_immediate ( val)
1549+ . expect ( "the above checks should have fully handled this situation" )
1550+ . to_scalar_pair ( ) ;
1551+ self . visit_scalar ( a, a_layout)
1552+ . expect ( "the above checks should have fully handled this situation" ) ;
1553+ self . visit_scalar ( b, b_layout)
1554+ . expect ( "the above checks should have fully handled this situation" ) ;
1555+ }
15181556 }
1519- }
1520- BackendRepr :: SimdVector { .. } | BackendRepr :: SimdScalableVector { .. } => {
1521- // No checks here, we assume layout computation gets this right.
1522- // (This is harder to check since Miri does not represent these as `Immediate`. We
1523- // also cannot use field projections since this might be a newtype around a vector.)
1524- }
1525- BackendRepr :: Memory { .. } => {
1526- // Nothing to do.
1557+ BackendRepr :: SimdVector { .. } | BackendRepr :: SimdScalableVector { .. } => { }
1558+ BackendRepr :: Memory { .. } => { }
15271559 }
15281560 }
15291561
0 commit comments