Skip to content

Commit c66e0c8

Browse files
authored
Rollup merge of #94655 - JakobDegen:mir-phase-docs, r=oli-obk
Clarify which kinds of MIR are allowed during which phases. This enhances documentation with these details and extends the validator to check these requirements more thoroughly. Most of these conditions were already being checked. There was also some disagreement between the `MirPhase` docs and validator as to what it meant for the `body.phase` field to have a certain value. This PR resolves those disagreements in favor of the `MirPhase` docs (which is what the pass manager implemented), adjusting the validator accordingly. The result is now that the `DropLowering` phase begins with the end of the elaborate drops pass, and lasts until the beginning of the generator lowring pass. This doesn't feel entirely natural to me, but as long as it's documented accurately it should be ok. r? rust-lang/mir-opt
2 parents d1d4613 + 26d7b8d commit c66e0c8

File tree

8 files changed

+113
-52
lines changed

8 files changed

+113
-52
lines changed

compiler/rustc_const_eval/src/transform/promote_consts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub struct PromoteTemps<'tcx> {
4242

4343
impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
4444
fn phase_change(&self) -> Option<MirPhase> {
45-
Some(MirPhase::ConstPromotion)
45+
Some(MirPhase::ConstsPromoted)
4646
}
4747

4848
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {

compiler/rustc_const_eval/src/transform/validate.rs

+47-27
Original file line numberDiff line numberDiff line change
@@ -266,30 +266,23 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
266266
);
267267
}
268268
}
269-
// The deaggregator currently does not deaggreagate arrays.
270-
// So for now, we ignore them here.
271-
Rvalue::Aggregate(box AggregateKind::Array { .. }, _) => {}
272-
// All other aggregates must be gone after some phases.
273-
Rvalue::Aggregate(box kind, _) => {
274-
if self.mir_phase > MirPhase::DropLowering
275-
&& !matches!(kind, AggregateKind::Generator(..))
276-
{
277-
// Generators persist until the state machine transformation, but all
278-
// other aggregates must have been lowered.
279-
self.fail(
280-
location,
281-
format!("{:?} have been lowered to field assignments", rvalue),
282-
)
283-
} else if self.mir_phase > MirPhase::GeneratorLowering {
284-
// No more aggregates after drop and generator lowering.
269+
Rvalue::Aggregate(agg_kind, _) => {
270+
let disallowed = match **agg_kind {
271+
AggregateKind::Array(..) => false,
272+
AggregateKind::Generator(..) => {
273+
self.mir_phase >= MirPhase::GeneratorsLowered
274+
}
275+
_ => self.mir_phase >= MirPhase::Deaggregated,
276+
};
277+
if disallowed {
285278
self.fail(
286279
location,
287280
format!("{:?} have been lowered to field assignments", rvalue),
288281
)
289282
}
290283
}
291284
Rvalue::Ref(_, BorrowKind::Shallow, _) => {
292-
if self.mir_phase > MirPhase::DropLowering {
285+
if self.mir_phase >= MirPhase::DropsLowered {
293286
self.fail(
294287
location,
295288
"`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase",
@@ -300,15 +293,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
300293
}
301294
}
302295
StatementKind::AscribeUserType(..) => {
303-
if self.mir_phase > MirPhase::DropLowering {
296+
if self.mir_phase >= MirPhase::DropsLowered {
304297
self.fail(
305298
location,
306299
"`AscribeUserType` should have been removed after drop lowering phase",
307300
);
308301
}
309302
}
310303
StatementKind::FakeRead(..) => {
311-
if self.mir_phase > MirPhase::DropLowering {
304+
if self.mir_phase >= MirPhase::DropsLowered {
312305
self.fail(
313306
location,
314307
"`FakeRead` should have been removed after drop lowering phase",
@@ -351,10 +344,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
351344
self.fail(location, format!("bad arg ({:?} != usize)", op_cnt_ty))
352345
}
353346
}
354-
StatementKind::SetDiscriminant { .. }
355-
| StatementKind::StorageLive(..)
347+
StatementKind::SetDiscriminant { .. } => {
348+
if self.mir_phase < MirPhase::DropsLowered {
349+
self.fail(location, "`SetDiscriminant` is not allowed until drop elaboration");
350+
}
351+
}
352+
StatementKind::Retag(_, _) => {
353+
// FIXME(JakobDegen) The validator should check that `self.mir_phase <
354+
// DropsLowered`. However, this causes ICEs with generation of drop shims, which
355+
// seem to fail to set their `MirPhase` correctly.
356+
}
357+
StatementKind::StorageLive(..)
356358
| StatementKind::StorageDead(..)
357-
| StatementKind::Retag(_, _)
358359
| StatementKind::Coverage(_)
359360
| StatementKind::Nop => {}
360361
}
@@ -424,10 +425,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
424425
}
425426
}
426427
TerminatorKind::DropAndReplace { target, unwind, .. } => {
427-
if self.mir_phase > MirPhase::DropLowering {
428+
if self.mir_phase >= MirPhase::DropsLowered {
428429
self.fail(
429430
location,
430-
"`DropAndReplace` is not permitted to exist after drop elaboration",
431+
"`DropAndReplace` should have been removed during drop elaboration",
431432
);
432433
}
433434
self.check_edge(location, *target, EdgeKind::Normal);
@@ -494,7 +495,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
494495
}
495496
}
496497
TerminatorKind::Yield { resume, drop, .. } => {
497-
if self.mir_phase > MirPhase::GeneratorLowering {
498+
if self.mir_phase >= MirPhase::GeneratorsLowered {
498499
self.fail(location, "`Yield` should have been replaced by generator lowering");
499500
}
500501
self.check_edge(location, *resume, EdgeKind::Normal);
@@ -503,10 +504,22 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
503504
}
504505
}
505506
TerminatorKind::FalseEdge { real_target, imaginary_target } => {
507+
if self.mir_phase >= MirPhase::DropsLowered {
508+
self.fail(
509+
location,
510+
"`FalseEdge` should have been removed after drop elaboration",
511+
);
512+
}
506513
self.check_edge(location, *real_target, EdgeKind::Normal);
507514
self.check_edge(location, *imaginary_target, EdgeKind::Normal);
508515
}
509516
TerminatorKind::FalseUnwind { real_target, unwind } => {
517+
if self.mir_phase >= MirPhase::DropsLowered {
518+
self.fail(
519+
location,
520+
"`FalseUnwind` should have been removed after drop elaboration",
521+
);
522+
}
510523
self.check_edge(location, *real_target, EdgeKind::Normal);
511524
if let Some(unwind) = unwind {
512525
self.check_edge(location, *unwind, EdgeKind::Unwind);
@@ -520,12 +533,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
520533
self.check_edge(location, *cleanup, EdgeKind::Unwind);
521534
}
522535
}
536+
TerminatorKind::GeneratorDrop => {
537+
if self.mir_phase >= MirPhase::GeneratorsLowered {
538+
self.fail(
539+
location,
540+
"`GeneratorDrop` should have been replaced by generator lowering",
541+
);
542+
}
543+
}
523544
// Nothing to validate for these.
524545
TerminatorKind::Resume
525546
| TerminatorKind::Abort
526547
| TerminatorKind::Return
527-
| TerminatorKind::Unreachable
528-
| TerminatorKind::GeneratorDrop => {}
548+
| TerminatorKind::Unreachable => {}
529549
}
530550

531551
self.super_terminator(terminator, location);

compiler/rustc_middle/src/mir/mod.rs

+54-17
Original file line numberDiff line numberDiff line change
@@ -127,32 +127,44 @@ pub trait MirPass<'tcx> {
127127
/// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the
128128
/// dialects forbid certain variants or values in certain phases.
129129
///
130-
/// Note: Each phase's validation checks all invariants of the *previous* phases' dialects. A phase
131-
/// that changes the dialect documents what invariants must be upheld *after* that phase finishes.
132-
///
133130
/// Warning: ordering of variants is significant.
134131
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
135132
#[derive(HashStable)]
136133
pub enum MirPhase {
137-
Build = 0,
134+
Built = 0,
138135
// FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query).
139136
// We used to have this for pre-miri MIR based const eval.
140137
Const = 1,
141138
/// This phase checks the MIR for promotable elements and takes them out of the main MIR body
142139
/// by creating a new MIR body per promoted element. After this phase (and thus the termination
143140
/// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir`
144141
/// query.
145-
ConstPromotion = 2,
146-
/// After this phase
147-
/// * the only `AggregateKind`s allowed are `Array` and `Generator`,
148-
/// * `DropAndReplace` is gone for good
149-
/// * `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop` terminator
150-
/// means that the auto-generated drop glue will be invoked.
151-
DropLowering = 3,
152-
/// After this phase, generators are explicit state machines (no more `Yield`).
153-
/// `AggregateKind::Generator` is gone for good.
154-
GeneratorLowering = 4,
155-
Optimization = 5,
142+
ConstsPromoted = 2,
143+
/// Beginning with this phase, the following variants are disallowed:
144+
/// * [`TerminatorKind::DropAndReplace`](terminator::TerminatorKind::DropAndReplace)
145+
/// * [`TerminatorKind::FalseUnwind`](terminator::TerminatorKind::FalseUnwind)
146+
/// * [`TerminatorKind::FalseEdge`](terminator::TerminatorKind::FalseEdge)
147+
/// * [`StatementKind::FakeRead`]
148+
/// * [`StatementKind::AscribeUserType`]
149+
/// * [`Rvalue::Ref`] with `BorrowKind::Shallow`
150+
///
151+
/// And the following variant is allowed:
152+
/// * [`StatementKind::Retag`]
153+
///
154+
/// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop`
155+
/// terminator means that the auto-generated drop glue will be invoked.
156+
DropsLowered = 3,
157+
/// Beginning with this phase, the following variant is disallowed:
158+
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
159+
///
160+
/// And the following variant is allowed:
161+
/// * [`StatementKind::SetDiscriminant`]
162+
Deaggregated = 4,
163+
/// Beginning with this phase, the following variants are disallowed:
164+
/// * [`TerminatorKind::Yield`](terminator::TerminatorKind::Yield)
165+
/// * [`TerminatorKind::GeneratorDrop](terminator::TerminatorKind::GeneratorDrop)
166+
GeneratorsLowered = 5,
167+
Optimized = 6,
156168
}
157169

158170
impl MirPhase {
@@ -311,7 +323,7 @@ impl<'tcx> Body<'tcx> {
311323
);
312324

313325
let mut body = Body {
314-
phase: MirPhase::Build,
326+
phase: MirPhase::Built,
315327
source,
316328
basic_blocks,
317329
source_scopes,
@@ -346,7 +358,7 @@ impl<'tcx> Body<'tcx> {
346358
/// crate.
347359
pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
348360
let mut body = Body {
349-
phase: MirPhase::Build,
361+
phase: MirPhase::Built,
350362
source: MirSource::item(DefId::local(CRATE_DEF_INDEX)),
351363
basic_blocks,
352364
source_scopes: IndexVec::new(),
@@ -1541,9 +1553,16 @@ impl Statement<'_> {
15411553
}
15421554
}
15431555

1556+
/// The various kinds of statements that can appear in MIR.
1557+
///
1558+
/// Not all of these are allowed at every [`MirPhase`]. Check the documentation there to see which
1559+
/// ones you do not have to worry about. The MIR validator will generally enforce such restrictions,
1560+
/// causing an ICE if they are violated.
15441561
#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
15451562
pub enum StatementKind<'tcx> {
15461563
/// Write the RHS Rvalue to the LHS Place.
1564+
///
1565+
/// The LHS place may not overlap with any memory accessed on the RHS.
15471566
Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),
15481567

15491568
/// This represents all the reading that a pattern match may do
@@ -1761,6 +1780,19 @@ static_assert_size!(Place<'_>, 16);
17611780
pub enum ProjectionElem<V, T> {
17621781
Deref,
17631782
Field(Field, T),
1783+
/// Index into a slice/array.
1784+
///
1785+
/// Note that this does not also dereference, and so it does not exactly correspond to slice
1786+
/// indexing in Rust. In other words, in the below Rust code:
1787+
///
1788+
/// ```rust
1789+
/// let x = &[1, 2, 3, 4];
1790+
/// let i = 2;
1791+
/// x[i];
1792+
/// ```
1793+
///
1794+
/// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same
1795+
/// thing is true of the `ConstantIndex` and `Subslice` projections below.
17641796
Index(V),
17651797

17661798
/// These indices are generated by slice patterns. Easiest to explain
@@ -2223,6 +2255,11 @@ impl<'tcx> Operand<'tcx> {
22232255
/// Rvalues
22242256
22252257
#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
2258+
/// The various kinds of rvalues that can appear in MIR.
2259+
///
2260+
/// Not all of these are allowed at every [`MirPhase`]. Check the documentation there to see which
2261+
/// ones you do not have to worry about. The MIR validator will generally enforce such restrictions,
2262+
/// causing an ICE if they are violated.
22262263
pub enum Rvalue<'tcx> {
22272264
/// x (either a move or copy, depending on type of x)
22282265
Use(Operand<'tcx>),

compiler/rustc_mir_transform/src/deaggregator.rs

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ use rustc_middle::ty::TyCtxt;
66
pub struct Deaggregator;
77

88
impl<'tcx> MirPass<'tcx> for Deaggregator {
9+
fn phase_change(&self) -> Option<MirPhase> {
10+
Some(MirPhase::Deaggregated)
11+
}
12+
913
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
1014
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
1115
let local_decls = &*local_decls;

compiler/rustc_mir_transform/src/elaborate_drops.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub struct ElaborateDrops;
2020

2121
impl<'tcx> MirPass<'tcx> for ElaborateDrops {
2222
fn phase_change(&self) -> Option<MirPhase> {
23-
Some(MirPhase::DropLowering)
23+
Some(MirPhase::DropsLowered)
2424
}
2525

2626
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {

compiler/rustc_mir_transform/src/generator.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1235,7 +1235,7 @@ fn create_cases<'tcx>(
12351235

12361236
impl<'tcx> MirPass<'tcx> for StateTransform {
12371237
fn phase_change(&self) -> Option<MirPhase> {
1238-
Some(MirPhase::GeneratorLowering)
1238+
Some(MirPhase::GeneratorsLowered)
12391239
}
12401240

12411241
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {

compiler/rustc_mir_transform/src/lib.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
342342
pm::run_passes(
343343
tcx,
344344
&mut body,
345-
&[&const_prop::ConstProp, &marker::PhaseChange(MirPhase::Optimization)],
345+
&[&const_prop::ConstProp, &marker::PhaseChange(MirPhase::Optimized)],
346346
);
347347
}
348348
}
@@ -399,7 +399,7 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
399399
}
400400

401401
run_post_borrowck_cleanup_passes(tcx, &mut body);
402-
assert!(body.phase == MirPhase::DropLowering);
402+
assert!(body.phase == MirPhase::Deaggregated);
403403
tcx.alloc_steal_mir(body)
404404
}
405405

@@ -460,7 +460,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
460460
],
461461
);
462462

463-
assert!(body.phase == MirPhase::GeneratorLowering);
463+
assert!(body.phase == MirPhase::GeneratorsLowered);
464464

465465
// The main optimizations that we do on MIR.
466466
pm::run_passes(
@@ -497,7 +497,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
497497
&deduplicate_blocks::DeduplicateBlocks,
498498
// Some cleanup necessary at least for LLVM and potentially other codegen backends.
499499
&add_call_guards::CriticalCallEdges,
500-
&marker::PhaseChange(MirPhase::Optimization),
500+
&marker::PhaseChange(MirPhase::Optimized),
501501
// Dump the end result for testing and debugging purposes.
502502
&dump_mir::Marker("PreCodegen"),
503503
],

compiler/rustc_mir_transform/src/pass_manager.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn
114114
}
115115
}
116116

117-
if validate || body.phase == MirPhase::Optimization {
117+
if validate || body.phase == MirPhase::Optimized {
118118
validate_body(tcx, body, format!("end of phase transition to {:?}", body.phase));
119119
}
120120
}

0 commit comments

Comments
 (0)