@@ -1492,7 +1492,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
14921492 // First check that the base type is valid
14931493 self . visit_value ( & val. transmute ( self . ecx . layout_of ( * base) ?, self . ecx ) ?) ?;
14941494 // When you extend this match, make sure to also add tests to
1495- // tests/ui/type/pattern_types/validity.rs((
1495+ // tests/ui/type/pattern_types/validity.rs
14961496 match * * pat {
14971497 // Range and non-null patterns are precisely reflected into `valid_range` and thus
14981498 // handled fully by `visit_scalar` (called below).
@@ -1507,6 +1507,34 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
15071507 // we won't see optimizations actually breaking such programs.
15081508 ty:: PatternKind :: Or ( _patterns) => { }
15091509 }
1510+ // FIXME(pattern_types): handle everything based on the pattern, not on the layout.
1511+ // it's ok to run scalar validation even if the pattern type is `u8 is 0..=255` and thus
1512+ // allows uninit values, because that's rare and so not a perf issue.
1513+ match val. layout . backend_repr {
1514+ BackendRepr :: Scalar ( scalar_layout) => {
1515+ if !scalar_layout. is_uninit_valid ( ) {
1516+ // There is something to check here.
1517+ // We read directly via `ecx` since the read cannot fail -- we already read
1518+ // this field above when recursing into the field.
1519+ let scalar = self . ecx . read_scalar ( val) ?;
1520+ self . visit_scalar ( scalar, scalar_layout) ?;
1521+ }
1522+ }
1523+ BackendRepr :: ScalarPair ( a_layout, b_layout) => {
1524+ // We can only proceed if *both* scalars need to be initialized.
1525+ // FIXME: find a way to also check ScalarPair when one side can be uninit but
1526+ // the other must be init.
1527+ if !a_layout. is_uninit_valid ( ) && !b_layout. is_uninit_valid ( ) {
1528+ // We read directly via `ecx` since the read cannot fail -- we already read
1529+ // this field above when recursing into the field.
1530+ let ( a, b) = self . ecx . read_immediate ( val) ?. to_scalar_pair ( ) ;
1531+ self . visit_scalar ( a, a_layout) ?;
1532+ self . visit_scalar ( b, b_layout) ?;
1533+ }
1534+ }
1535+ BackendRepr :: SimdVector { .. } | BackendRepr :: SimdScalableVector { .. } => unreachable ! ( ) ,
1536+ BackendRepr :: Memory { .. } => unreachable ! ( )
1537+ }
15101538 }
15111539 ty:: Adt ( adt, _) if adt. is_maybe_dangling ( ) => {
15121540 let old_may_dangle = mem:: replace ( & mut self . may_dangle , true ) ;
@@ -1529,51 +1557,55 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
15291557 }
15301558 }
15311559
1532- // *After* all of this, check further information stored in the layout. We need to check
1533- // this to handle types like `NonNull` where the `Scalar` info is more restrictive than what
1534- // the fields say (`rustc_layout_scalar_valid_range_start`). But in most cases, this will
1535- // just propagate what the fields say, and then we want the error to point at the field --
1536- // so, we first recurse, then we do this check.
1560+ // *After* all of this, check further information stored in the layout.
1561+ // On leaf types like `!` or empty enums, this will raise the error.
1562+ // This means that for types wrapping such a type, we won't ever get here, but it's
1563+ // just the simplest way to check for this case.
15371564 //
15381565 // FIXME: We could avoid some redundant checks here. For newtypes wrapping
15391566 // scalars, we do the same check on every "level" (e.g., first we check
1540- // MyNewtype and then the scalar in there ).
1567+ // the fields of MyNewtype, and then we check MyNewType again ).
15411568 if val. layout . is_uninhabited ( ) {
15421569 let ty = val. layout . ty ;
15431570 throw_validation_failure ! (
15441571 self . path,
15451572 format!( "encountered a value of uninhabited type `{ty}`" )
15461573 ) ;
15471574 }
1548- match val. layout . backend_repr {
1549- BackendRepr :: Scalar ( scalar_layout) => {
1550- if !scalar_layout. is_uninit_valid ( ) {
1551- // There is something to check here.
1552- // We read directly via `ecx` since the read cannot fail -- we already read
1553- // this field above when recursing into the field.
1554- let scalar = self . ecx . read_scalar ( val) ?;
1555- self . visit_scalar ( scalar, scalar_layout) ?;
1575+ if cfg ! ( debug_assertions) {
1576+ // Check that we don't miss any new changes to layout computation in our checks above.
1577+ match val. layout . backend_repr {
1578+ BackendRepr :: Scalar ( scalar_layout) => {
1579+ if !scalar_layout. is_uninit_valid ( ) {
1580+ // There is something to check here.
1581+ // We read directly via `ecx` since the read cannot fail -- we already read
1582+ // this field above when recursing into the field.
1583+ let scalar = self
1584+ . ecx
1585+ . read_scalar ( val)
1586+ . expect ( "the above checks should have fully handled this situation" ) ;
1587+ self . visit_scalar ( scalar, scalar_layout)
1588+ . expect ( "the above checks should have fully handled this situation" ) ;
1589+ }
15561590 }
1557- }
1558- BackendRepr :: ScalarPair ( a_layout, b_layout) => {
1559- // We can only proceed if *both* scalars need to be initialized.
1560- // FIXME: find a way to also check ScalarPair when one side can be uninit but
1561- // the other must be init.
1562- if !a_layout. is_uninit_valid ( ) && !b_layout. is_uninit_valid ( ) {
1563- // We read directly via `ecx` since the read cannot fail -- we already read
1564- // this field above when recursing into the field.
1565- let ( a, b) = self . ecx . read_immediate ( val) ?. to_scalar_pair ( ) ;
1566- self . visit_scalar ( a, a_layout) ?;
1567- self . visit_scalar ( b, b_layout) ?;
1591+ BackendRepr :: ScalarPair ( a_layout, b_layout) => {
1592+ // We can only proceed if *both* scalars need to be initialized.
1593+ // FIXME: find a way to also check ScalarPair when one side can be uninit but
1594+ // the other must be init.
1595+ if !a_layout. is_uninit_valid ( ) && !b_layout. is_uninit_valid ( ) {
1596+ let ( a, b) = self
1597+ . ecx
1598+ . read_immediate ( val)
1599+ . expect ( "the above checks should have fully handled this situation" )
1600+ . to_scalar_pair ( ) ;
1601+ self . visit_scalar ( a, a_layout)
1602+ . expect ( "the above checks should have fully handled this situation" ) ;
1603+ self . visit_scalar ( b, b_layout)
1604+ . expect ( "the above checks should have fully handled this situation" ) ;
1605+ }
15681606 }
1569- }
1570- BackendRepr :: SimdVector { .. } | BackendRepr :: SimdScalableVector { .. } => {
1571- // No checks here, we assume layout computation gets this right.
1572- // (This is harder to check since Miri does not represent these as `Immediate`. We
1573- // also cannot use field projections since this might be a newtype around a vector.)
1574- }
1575- BackendRepr :: Memory { .. } => {
1576- // Nothing to do.
1607+ BackendRepr :: SimdVector { .. } | BackendRepr :: SimdScalableVector { .. } => { }
1608+ BackendRepr :: Memory { .. } => { }
15771609 }
15781610 }
15791611
0 commit comments