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

This commit is contained in:
Ralf Jung 2024-05-27 15:28:51 +02:00
parent cdc509f7c0
commit 7d24f87068
3 changed files with 26 additions and 6 deletions

View File

@ -1008,8 +1008,8 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
/// element:
///
/// - [`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
/// index already set is not well-formed.
/// given one, and makes no other changes. A `Downcast` projection must always be followed
/// immediately by a `Field` projection.
/// - [`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
/// 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() {
self.fail(
location,
format!("You can't project to field {f:?} of `DynMetadata` because \
layout is weird and thinks it doesn't have fields."),
format!(
"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)
&& 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);

View File

@ -1,6 +1,6 @@
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]:
(*(_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:
error: the compiler unexpectedly panicked. this is a bug.