-
-
Notifications
You must be signed in to change notification settings - Fork 14.9k
Rip out rustc_layout_scalar_valid_range_* attribute support #155433
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
2279f4a
2dd3567
a255a94
39240fc
bf25c7d
ac6aef6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1442,7 +1442,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, | |
| // First check that the base type is valid | ||
| self.visit_value(&val.transmute(self.ecx.layout_of(*base)?, self.ecx)?)?; | ||
| // When you extend this match, make sure to also add tests to | ||
| // tests/ui/type/pattern_types/validity.rs(( | ||
| // tests/ui/type/pattern_types/validity.rs | ||
| match **pat { | ||
| // Range and non-null patterns are precisely reflected into `valid_range` and thus | ||
| // handled fully by `visit_scalar` (called below). | ||
|
|
@@ -1457,6 +1457,34 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, | |
| // we won't see optimizations actually breaking such programs. | ||
| ty::PatternKind::Or(_patterns) => {} | ||
| } | ||
| // FIXME(pattern_types): handle everything based on the pattern, not on the layout. | ||
| // it's ok to run scalar validation even if the pattern type is `u8 is 0..=255` and thus | ||
| // allows uninit values, because that's rare and so not a perf issue. | ||
| match val.layout.backend_repr { | ||
| BackendRepr::Scalar(scalar_layout) => { | ||
| if !scalar_layout.is_uninit_valid() { | ||
| // There is something to check here. | ||
| // We read directly via `ecx` since the read cannot fail -- we already read | ||
| // this field above when recursing into the field. | ||
| let scalar = self.ecx.read_scalar(val)?; | ||
| self.visit_scalar(scalar, scalar_layout)?; | ||
| } | ||
| } | ||
| BackendRepr::ScalarPair(a_layout, b_layout) => { | ||
| // We can only proceed if *both* scalars need to be initialized. | ||
| // FIXME: find a way to also check ScalarPair when one side can be uninit but | ||
| // the other must be init. | ||
| if !a_layout.is_uninit_valid() && !b_layout.is_uninit_valid() { | ||
| // We read directly via `ecx` since the read cannot fail -- we already read | ||
| // this field above when recursing into the field. | ||
| let (a, b) = self.ecx.read_immediate(val)?.to_scalar_pair(); | ||
| self.visit_scalar(a, a_layout)?; | ||
| self.visit_scalar(b, b_layout)?; | ||
| } | ||
| } | ||
| BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => unreachable!(), | ||
| BackendRepr::Memory { .. } => unreachable!() | ||
| } | ||
| } | ||
| ty::Adt(adt, _) if adt.is_maybe_dangling() => { | ||
| 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, | |
| } | ||
| } | ||
|
|
||
| // *After* all of this, check further information stored in the layout. We need to check | ||
| // this to handle types like `NonNull` where the `Scalar` info is more restrictive than what | ||
| // the fields say (`rustc_layout_scalar_valid_range_start`). But in most cases, this will | ||
| // just propagate what the fields say, and then we want the error to point at the field -- | ||
| // so, we first recurse, then we do this check. | ||
| // *After* all of this, check further information stored in the layout. | ||
| // On leaf types like `!` or empty enums, this will raise the error. | ||
| // This means that for types wrapping such a type, we won't ever get here, but it's | ||
| // just the simplest way to check for this case. | ||
| // | ||
| // FIXME: We could avoid some redundant checks here. For newtypes wrapping | ||
| // scalars, we do the same check on every "level" (e.g., first we check | ||
| // MyNewtype and then the scalar in there). | ||
| // the fields of MyNewtype, and then we check MyNewType again). | ||
|
Comment on lines
+1510
to
+1517
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems mostly outdated now, and the FIXME is resolved because there are no longer any redundant checks. The only question that remains is why we need an
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the uninhabited check is still reachable and it's sufficiently unrelated to pattern types and layout attributes that I've decided to leave the fixme and try it in a separate PR once this one lands |
||
| if val.layout.is_uninhabited() { | ||
| let ty = val.layout.ty; | ||
| throw_validation_failure!( | ||
| self.path, | ||
| format!("encountered a value of uninhabited type `{ty}`") | ||
| ); | ||
| } | ||
| match val.layout.backend_repr { | ||
| BackendRepr::Scalar(scalar_layout) => { | ||
| if !scalar_layout.is_uninit_valid() { | ||
| // There is something to check here. | ||
| // We read directly via `ecx` since the read cannot fail -- we already read | ||
| // this field above when recursing into the field. | ||
| let scalar = self.ecx.read_scalar(val)?; | ||
| self.visit_scalar(scalar, scalar_layout)?; | ||
| if cfg!(debug_assertions) { | ||
| // Check that we don't miss any new changes to layout computation in our checks above. | ||
| match val.layout.backend_repr { | ||
| BackendRepr::Scalar(scalar_layout) => { | ||
| if !scalar_layout.is_uninit_valid() { | ||
| // There is something to check here. | ||
| // We read directly via `ecx` since the read cannot fail -- we already read | ||
| // this field above when recursing into the field. | ||
| let scalar = self | ||
| .ecx | ||
| .read_scalar(val) | ||
| .expect("the above checks should have fully handled this situation"); | ||
| self.visit_scalar(scalar, scalar_layout) | ||
| .expect("the above checks should have fully handled this situation"); | ||
| } | ||
| } | ||
| } | ||
| BackendRepr::ScalarPair(a_layout, b_layout) => { | ||
| // We can only proceed if *both* scalars need to be initialized. | ||
| // FIXME: find a way to also check ScalarPair when one side can be uninit but | ||
| // the other must be init. | ||
| if !a_layout.is_uninit_valid() && !b_layout.is_uninit_valid() { | ||
| // We read directly via `ecx` since the read cannot fail -- we already read | ||
| // this field above when recursing into the field. | ||
| let (a, b) = self.ecx.read_immediate(val)?.to_scalar_pair(); | ||
| self.visit_scalar(a, a_layout)?; | ||
| self.visit_scalar(b, b_layout)?; | ||
| BackendRepr::ScalarPair(a_layout, b_layout) => { | ||
| // We can only proceed if *both* scalars need to be initialized. | ||
| // FIXME: find a way to also check ScalarPair when one side can be uninit but | ||
| // the other must be init. | ||
| if !a_layout.is_uninit_valid() && !b_layout.is_uninit_valid() { | ||
| let (a, b) = self | ||
| .ecx | ||
| .read_immediate(val) | ||
| .expect("the above checks should have fully handled this situation") | ||
| .to_scalar_pair(); | ||
| self.visit_scalar(a, a_layout) | ||
| .expect("the above checks should have fully handled this situation"); | ||
| self.visit_scalar(b, b_layout) | ||
| .expect("the above checks should have fully handled this situation"); | ||
| } | ||
| } | ||
| } | ||
| BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => { | ||
| // No checks here, we assume layout computation gets this right. | ||
| // (This is harder to check since Miri does not represent these as `Immediate`. We | ||
| // also cannot use field projections since this might be a newtype around a vector.) | ||
| } | ||
| BackendRepr::Memory { .. } => { | ||
| // Nothing to do. | ||
| BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => {} | ||
| BackendRepr::Memory { .. } => {} | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1276,5 +1276,3 @@ mod expr; | |
| mod matches; | ||
| mod misc; | ||
| mod scope; | ||
|
|
||
| pub(crate) use expr::category::Category as ExprCategory; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine for now but structurally it'd make a lot more sense to check the pattern rather than the layout (and then somehow have a sanity check that the layout does not add extra restrictions not covered by the pattern).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it does, but I haven't figured out how to do that without just repeating a lot of logic. Tho I guess we can just not look at whether
is_uninit_validis set, because if your pattern type is the full range of what the base type allows, that's so rare, that the small perf hit is fine to takeThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is_uninit_validis only set for unions. I hope those aren't allowed in pattern types.^^