Rollup merge of #125616 - RalfJung:mir-validate-downcast-projection, r=compiler-errors

MIR validation: ensure that downcast projection is followed by field projection

Cc https://github.com/rust-lang/rust/issues/120369
This commit is contained in:
Matthias Krüger 2024-05-27 20:43:26 +02:00 committed by GitHub
commit 61f9d35798
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 26 additions and 6 deletions

View File

@ -1008,8 +1008,8 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
/// element: /// element:
/// ///
/// - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the /// - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the
/// given one, and makes no other changes. A `Downcast` projection on a place with its variant /// given one, and makes no other changes. A `Downcast` projection must always be followed
/// index already set is not well-formed. /// immediately by a `Field` projection.
/// - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a /// - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a
/// place referring to one of the fields of the type. The resulting address is the parent /// place referring to one of the fields of the type. The resulting address is the parent
/// address, plus the offset of the field. The type becomes the type of the field. If the parent /// address, plus the offset of the field. The type becomes the type of the field. If the parent

View File

@ -689,8 +689,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if Some(adt_def.did()) == self.tcx.lang_items().dyn_metadata() { if Some(adt_def.did()) == self.tcx.lang_items().dyn_metadata() {
self.fail( self.fail(
location, location,
format!("You can't project to field {f:?} of `DynMetadata` because \ format!(
layout is weird and thinks it doesn't have fields."), "You can't project to field {f:?} of `DynMetadata` because \
layout is weird and thinks it doesn't have fields."
),
); );
} }
@ -839,7 +841,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
&& cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo) && cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo)
&& place.projection[1..].contains(&ProjectionElem::Deref) && place.projection[1..].contains(&ProjectionElem::Deref)
{ {
self.fail(location, format!("{place:?}, has deref at the wrong place")); self.fail(
location,
format!("place {place:?} has deref as a later projection (it is only permitted as the first projection)"),
);
}
// Ensure all downcast projections are followed by field projections.
let mut projections_iter = place.projection.iter();
while let Some(proj) = projections_iter.next() {
if matches!(proj, ProjectionElem::Downcast(..)) {
if !matches!(projections_iter.next(), Some(ProjectionElem::Field(..))) {
self.fail(
location,
format!(
"place {place:?} has `Downcast` projection not followed by `Field`"
),
);
}
}
} }
self.super_place(place, cntxt, location); self.super_place(place, cntxt, location);

View File

@ -1,6 +1,6 @@
thread 'rustc' panicked at compiler/rustc_mir_transform/src/validate.rs:LL:CC: thread 'rustc' panicked at compiler/rustc_mir_transform/src/validate.rs:LL:CC:
broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]: broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]:
(*(_2.0: *mut i32)), has deref at the wrong place place (*(_2.0: *mut i32)) has deref as a later projection (it is only permitted as the first projection)
stack backtrace: stack backtrace:
error: the compiler unexpectedly panicked. this is a bug. error: the compiler unexpectedly panicked. this is a bug.