Skip to content

Commit 61f9d35

Browse files
authored
Rollup merge of #125616 - RalfJung:mir-validate-downcast-projection, r=compiler-errors
MIR validation: ensure that downcast projection is followed by field projection Cc #120369
2 parents e8dd585 + 7d24f87 commit 61f9d35

File tree

3 files changed

+26
-6
lines changed

3 files changed

+26
-6
lines changed

compiler/rustc_middle/src/mir/syntax.rs

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

compiler/rustc_mir_transform/src/validate.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -689,8 +689,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
689689
if Some(adt_def.did()) == self.tcx.lang_items().dyn_metadata() {
690690
self.fail(
691691
location,
692-
format!("You can't project to field {f:?} of `DynMetadata` because \
693-
layout is weird and thinks it doesn't have fields."),
692+
format!(
693+
"You can't project to field {f:?} of `DynMetadata` because \
694+
layout is weird and thinks it doesn't have fields."
695+
),
694696
);
695697
}
696698

@@ -839,7 +841,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
839841
&& cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo)
840842
&& place.projection[1..].contains(&ProjectionElem::Deref)
841843
{
842-
self.fail(location, format!("{place:?}, has deref at the wrong place"));
844+
self.fail(
845+
location,
846+
format!("place {place:?} has deref as a later projection (it is only permitted as the first projection)"),
847+
);
848+
}
849+
850+
// Ensure all downcast projections are followed by field projections.
851+
let mut projections_iter = place.projection.iter();
852+
while let Some(proj) = projections_iter.next() {
853+
if matches!(proj, ProjectionElem::Downcast(..)) {
854+
if !matches!(projections_iter.next(), Some(ProjectionElem::Field(..))) {
855+
self.fail(
856+
location,
857+
format!(
858+
"place {place:?} has `Downcast` projection not followed by `Field`"
859+
),
860+
);
861+
}
862+
}
843863
}
844864

845865
self.super_place(place, cntxt, location);

src/tools/miri/tests/panic/mir-validation.stderr

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

66
error: the compiler unexpectedly panicked. this is a bug.

0 commit comments

Comments
 (0)