Refactor MIR phases

This commit is contained in:
Jakob Degen 2022-07-09 18:04:38 -07:00
parent 9f4d5d2a28
commit aad14c701e
17 changed files with 289 additions and 186 deletions

View File

@ -41,7 +41,7 @@ pub struct PromoteTemps<'tcx> {
impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
fn phase_change(&self) -> Option<MirPhase> {
Some(MirPhase::ConstsPromoted)
Some(MirPhase::Analysis(AnalysisPhase::Initial))
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@ -964,7 +964,7 @@ pub fn promote_candidates<'tcx>(
let mut scope = body.source_scopes[body.source_info(candidate.location).scope].clone();
scope.parent_scope = None;
let promoted = Body::new(
let mut promoted = Body::new(
body.source, // `promoted` gets filled in below
IndexVec::new(),
IndexVec::from_elem_n(scope, 1),
@ -976,6 +976,7 @@ pub fn promote_candidates<'tcx>(
body.generator_kind(),
body.tainted_by_errors,
);
promoted.phase = MirPhase::Analysis(AnalysisPhase::Initial);
let promoter = Promoter {
promoted,

View File

@ -8,8 +8,8 @@ use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{
traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, Local, Location,
MirPass, MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope,
Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK,
MirPass, MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, RuntimePhase, Rvalue,
SourceScope, Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK,
};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::subst::Subst;
@ -221,7 +221,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
// This check is somewhat expensive, so only run it when -Zvalidate-mir is passed.
if self.tcx.sess.opts.unstable_opts.validate_mir && self.mir_phase < MirPhase::DropsLowered
if self.tcx.sess.opts.unstable_opts.validate_mir
&& self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial)
{
// `Operand::Copy` is only supposed to be used with `Copy` types.
if let Operand::Copy(place) = operand {
@ -252,7 +253,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.fail(location, format!("bad index ({:?} != usize)", index_ty))
}
}
ProjectionElem::Deref if self.mir_phase >= MirPhase::GeneratorsLowered => {
ProjectionElem::Deref
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup) =>
{
let base_ty = Place::ty_from(local, proj_base, &self.body.local_decls, self.tcx).ty;
if base_ty.is_box() {
@ -360,7 +363,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// Set off any `bug!`s in the type computation code
let _ = place.ty(&self.body.local_decls, self.tcx);
if self.mir_phase >= MirPhase::Derefered
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial)
&& place.projection.len() > 1
&& cntxt != PlaceContext::NonUse(VarDebugInfo)
&& place.projection[1..].contains(&ProjectionElem::Deref)
@ -384,8 +387,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
Rvalue::Aggregate(agg_kind, _) => {
let disallowed = match **agg_kind {
AggregateKind::Array(..) => false,
AggregateKind::Generator(..) => self.mir_phase >= MirPhase::GeneratorsLowered,
_ => self.mir_phase >= MirPhase::Deaggregated,
_ => self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup),
};
if disallowed {
self.fail(
@ -395,10 +397,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
Rvalue::Ref(_, BorrowKind::Shallow, _) => {
if self.mir_phase >= MirPhase::DropsLowered {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase",
"`Assign` statement with a `Shallow` borrow should have been removed in runtime MIR",
);
}
}
@ -612,7 +614,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
StatementKind::AscribeUserType(..) => {
if self.mir_phase >= MirPhase::DropsLowered {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`AscribeUserType` should have been removed after drop lowering phase",
@ -620,7 +622,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
StatementKind::FakeRead(..) => {
if self.mir_phase >= MirPhase::DropsLowered {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`FakeRead` should have been removed after drop lowering phase",
@ -664,7 +666,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
StatementKind::SetDiscriminant { place, .. } => {
if self.mir_phase < MirPhase::Deaggregated {
if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location, "`SetDiscriminant`is not allowed until deaggregation");
}
let pty = place.ty(&self.body.local_decls, self.tcx).ty.kind();
@ -679,7 +681,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
StatementKind::Deinit(..) => {
if self.mir_phase < MirPhase::Deaggregated {
if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location, "`Deinit`is not allowed until deaggregation");
}
}
@ -759,7 +761,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
TerminatorKind::DropAndReplace { target, unwind, .. } => {
if self.mir_phase >= MirPhase::DropsLowered {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`DropAndReplace` should have been removed during drop elaboration",
@ -830,7 +832,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if self.body.generator.is_none() {
self.fail(location, "`Yield` cannot appear outside generator bodies");
}
if self.mir_phase >= MirPhase::GeneratorsLowered {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location, "`Yield` should have been replaced by generator lowering");
}
self.check_edge(location, *resume, EdgeKind::Normal);
@ -839,7 +841,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
TerminatorKind::FalseEdge { real_target, imaginary_target } => {
if self.mir_phase >= MirPhase::DropsLowered {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`FalseEdge` should have been removed after drop elaboration",
@ -849,7 +851,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.check_edge(location, *imaginary_target, EdgeKind::Normal);
}
TerminatorKind::FalseUnwind { real_target, unwind } => {
if self.mir_phase >= MirPhase::DropsLowered {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`FalseUnwind` should have been removed after drop elaboration",
@ -872,7 +874,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if self.body.generator.is_none() {
self.fail(location, "`GeneratorDrop` cannot appear outside generator bodies");
}
if self.mir_phase >= MirPhase::GeneratorsLowered {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`GeneratorDrop` should have been replaced by generator lowering",

View File

@ -128,8 +128,20 @@ pub trait MirPass<'tcx> {
impl MirPhase {
/// Gets the index of the current MirPhase within the set of all `MirPhase`s.
///
/// FIXME(JakobDegen): Return a `(usize, usize)` instead.
pub fn phase_index(&self) -> usize {
*self as usize
const BUILT_PHASE_COUNT: usize = 1;
const ANALYSIS_PHASE_COUNT: usize = 2;
match self {
MirPhase::Built => 1,
MirPhase::Analysis(analysis_phase) => {
1 + BUILT_PHASE_COUNT + (*analysis_phase as usize)
}
MirPhase::Runtime(runtime_phase) => {
1 + BUILT_PHASE_COUNT + ANALYSIS_PHASE_COUNT + (*runtime_phase as usize)
}
}
}
}

View File

@ -23,75 +23,110 @@ use rustc_span::symbol::Symbol;
use rustc_span::Span;
use rustc_target::asm::InlineAsmRegOrRegClass;
/// The various "big phases" that MIR goes through.
/// Represents the "flavors" of MIR.
///
/// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the
/// dialects forbid certain variants or values in certain phases. The sections below summarize the
/// changes, but do not document them thoroughly. The full documentation is found in the appropriate
/// documentation for the thing the change is affecting.
/// All flavors of MIR use the same data structure, but there are some important differences. These
/// differences come in two forms: Dialects and phases.
///
/// Warning: ordering of variants is significant.
/// Dialects represent a stronger distinction than phases. This is because the transitions between
/// dialects are semantic changes, and therefore technically *lowerings* between distinct IRs. In
/// other words, the same [`Body`](crate::mir::Body) might be well-formed for multiple dialects, but
/// have different semantic meaning and different behavior at runtime.
///
/// Each dialect additionally has a number of phases. However, phase changes never involve semantic
/// changes. If some MIR is well-formed both before and after a phase change, it is also guaranteed
/// that it has the same semantic meaning. In this sense, phase changes can only add additional
/// restrictions on what MIR is well-formed.
///
/// When adding phases, remember to update [`MirPhase::phase_index`].
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[derive(HashStable)]
pub enum MirPhase {
/// The dialect of MIR used during all phases before `DropsLowered` is the same. This is also
/// the MIR that analysis such as borrowck uses.
/// The MIR that is generated by MIR building.
///
/// One important thing to remember about the behavior of this section of MIR is that drop terminators
/// (including drop and replace) are *conditional*. The elaborate drops pass will then replace each
/// instance of a drop terminator with a nop, an unconditional drop, or a drop conditioned on a drop
/// flag. Of course, this means that it is important that the drop elaboration can accurately recognize
/// when things are initialized and when things are de-initialized. That means any code running on this
/// version of MIR must be sure to produce output that drop elaboration can reason about. See the
/// section on the drop terminatorss for more details.
Built = 0,
// FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query).
// We used to have this for pre-miri MIR based const eval.
Const = 1,
/// This phase checks the MIR for promotable elements and takes them out of the main MIR body
/// by creating a new MIR body per promoted element. After this phase (and thus the termination
/// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir`
/// query.
ConstsPromoted = 2,
/// After this projections may only contain deref projections as the first element.
Derefered = 3,
/// Beginning with this phase, the following variants are disallowed:
/// * [`TerminatorKind::DropAndReplace`]
/// The only things that operate on this dialect are unsafeck, the various MIR lints, and const
/// qualifs.
///
/// This has no distinct phases.
Built,
/// The MIR used for most analysis.
///
/// The only semantic change between analysis and built MIR is constant promotion. In built MIR,
/// sequences of statements that would generally be subject to constant promotion are
/// semantically constants, while in analysis MIR all constants are explicit.
///
/// The result of const promotion is available from the `mir_promoted` and `promoted_mir` queries.
///
/// This is the version of MIR used by borrowck and friends.
Analysis(AnalysisPhase),
/// The MIR used for CTFE, optimizations, and codegen.
///
/// The semantic changes that occur in the lowering from analysis to runtime MIR are as follows:
///
/// - Drops: In analysis MIR, `Drop` terminators represent *conditional* drops; roughly speaking,
/// if dataflow analysis determines that the place being dropped is uninitialized, the drop will
/// not be executed. The exact semantics of this aren't written down anywhere, which means they
/// are essentially "what drop elaboration does." In runtime MIR, the drops are unconditional;
/// when a `Drop` terminator is reached, if the type has drop glue that drop glue is always
/// executed. This may be UB if the underlying place is not initialized.
/// - Packed drops: Places might in general be misaligned - in most cases this is UB, the exception
/// is fields of packed structs. In analysis MIR, `Drop(P)` for a `P` that might be misaligned
/// for this reason implicitly moves `P` to a temporary before dropping. Runtime MIR has no such
/// rules, and dropping a misaligned place is simply UB.
/// - Unwinding: in analysis MIR, unwinding from a function which may not unwind aborts. In runtime
/// MIR, this is UB.
/// - Retags: If `-Zmir-emit-retag` is enabled, analysis MIR has "implicit" retags in the same way
/// that Rust itself has them. Where exactly these are is generally subject to change, and so we
/// don't document this here. Runtime MIR has all retags explicit.
/// - Generator bodies: In analysis MIR, locals may actually be behind a pointer that user code has
/// access to. This occurs in generator bodies. Such locals do not behave like other locals,
/// because they eg may be aliased in surprising ways. Runtime MIR has no such special locals -
/// all generator bodies are lowered and so all places that look like locals really are locals.
/// - Const prop lints: The lint pass which reports eg `200_u8 + 200_u8` as an error is run as a
/// part of analysis to runtime MIR lowering. This means that transformations which may supress
/// such errors may not run on analysis MIR.
Runtime(RuntimePhase),
}
/// See [`MirPhase::Analysis`].
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[derive(HashStable)]
pub enum AnalysisPhase {
Initial = 0,
/// Beginning in this phase, the following variants are disallowed:
/// * [`TerminatorKind::FalseUnwind`]
/// * [`TerminatorKind::FalseEdge`]
/// * [`StatementKind::FakeRead`]
/// * [`StatementKind::AscribeUserType`]
/// * [`Rvalue::Ref`] with `BorrowKind::Shallow`
///
/// And the following variant is allowed:
/// * [`StatementKind::Retag`]
///
/// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop`
/// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands
/// are allowed for non-`Copy` types.
DropsLowered = 4,
/// Beginning with this phase, the following variant is disallowed:
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
///
/// And the following variant is allowed:
/// * [`StatementKind::SetDiscriminant`]
Deaggregated = 5,
/// Before this phase, generators are in the "source code" form, featuring `yield` statements
/// and such. With this phase change, they are transformed into a proper state machine. Running
/// optimizations before this change can be potentially dangerous because the source code is to
/// some extent a "lie." In particular, `yield` terminators effectively make the value of all
/// locals visible to the caller. This means that dead store elimination before them, or code
/// motion across them, is not correct in general. This is also exasperated by type checking
/// having pre-computed a list of the types that it thinks are ok to be live across a yield
/// point - this is necessary to decide eg whether autotraits are implemented. Introducing new
/// types across a yield point will lead to ICEs becaues of this.
///
/// Beginning with this phase, the following variants are disallowed:
/// Furthermore, `Deref` projections must be the first projection within any place (if they
/// appear at all)
PostCleanup = 1,
}
/// See [`MirPhase::Runtime`].
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[derive(HashStable)]
pub enum RuntimePhase {
/// In addition to the semantic changes, beginning with this phase, the following variants are
/// disallowed:
/// * [`TerminatorKind::DropAndReplace`]
/// * [`TerminatorKind::Yield`]
/// * [`TerminatorKind::GeneratorDrop`]
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
///
/// And the following variants are allowed:
/// * [`StatementKind::Retag`]
/// * [`StatementKind::SetDiscriminant`]
/// * [`StatementKind::Deinit`]
///
/// Furthermore, `Copy` operands are allowed for non-`Copy` types.
Initial = 0,
/// Beginning with this phase, the following variant is disallowed:
/// * [`ProjectionElem::Deref`] of `Box`
GeneratorsLowered = 6,
Optimized = 7,
PostCleanup = 1,
Optimized = 2,
}
///////////////////////////////////////////////////////////////////////////

View File

@ -6,10 +6,6 @@ use rustc_middle::ty::TyCtxt;
pub struct Deaggregator;
impl<'tcx> MirPass<'tcx> for Deaggregator {
fn phase_change(&self) -> Option<MirPhase> {
Some(MirPhase::Deaggregated)
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
for bb in basic_blocks {

View File

@ -82,6 +82,5 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
impl<'tcx> MirPass<'tcx> for Derefer {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
deref_finder(tcx, body);
body.phase = MirPhase::Derefered;
}
}

View File

@ -21,10 +21,6 @@ use std::fmt;
pub struct ElaborateDrops;
impl<'tcx> MirPass<'tcx> for ElaborateDrops {
fn phase_change(&self) -> Option<MirPhase> {
Some(MirPhase::DropsLowered)
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);

View File

@ -1240,10 +1240,6 @@ fn create_cases<'tcx>(
}
impl<'tcx> MirPass<'tcx> for StateTransform {
fn phase_change(&self) -> Option<MirPhase> {
Some(MirPhase::GeneratorsLowered)
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let Some(yield_ty) = body.yield_ty() else {
// This only applies to generators

View File

@ -25,7 +25,9 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_index::vec::IndexVec;
use rustc_middle::mir::visit::Visitor as _;
use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
use rustc_middle::mir::{
traversal, AnalysisPhase, Body, ConstQualifs, MirPass, MirPhase, Promoted, RuntimePhase,
};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
@ -199,6 +201,8 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) ->
}
/// Make MIR ready for const evaluation. This is run on all MIR, not just on consts!
/// FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query).
/// We used to have this for pre-miri MIR based const eval.
fn mir_const<'tcx>(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
@ -234,7 +238,6 @@ fn mir_const<'tcx>(
// What we need to do constant evaluation.
&simplify::SimplifyCfg::new("initial"),
&rustc_peek::SanityCheck, // Just a lint
&marker::PhaseChange(MirPhase::Const),
],
);
tcx.alloc_steal_mir(body)
@ -340,7 +343,10 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
pm::run_passes(
tcx,
&mut body,
&[&const_prop::ConstProp, &marker::PhaseChange(MirPhase::Optimized)],
&[
&const_prop::ConstProp,
&marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)),
],
);
}
}
@ -380,38 +386,61 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
body.tainted_by_errors = Some(error_reported);
}
// IMPORTANT
pm::run_passes(tcx, &mut body, &[&remove_false_edges::RemoveFalseEdges]);
run_analysis_to_runtime_passes(tcx, &mut body);
tcx.alloc_steal_mir(body)
}
fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
assert!(body.phase == MirPhase::Analysis(AnalysisPhase::Initial));
let did = body.source.def_id();
debug!("analysis_mir_cleanup({:?})", did);
run_analysis_cleanup_passes(tcx, body);
assert!(body.phase == MirPhase::Analysis(AnalysisPhase::PostCleanup));
// Do a little drop elaboration before const-checking if `const_precise_live_drops` is enabled.
if check_consts::post_drop_elaboration::checking_enabled(&ConstCx::new(tcx, &body)) {
pm::run_passes(
tcx,
&mut body,
body,
&[
&simplify::SimplifyCfg::new("remove-false-edges"),
&remove_uninit_drops::RemoveUninitDrops,
&simplify::SimplifyCfg::new("remove-false-edges"),
],
);
check_consts::post_drop_elaboration::check_live_drops(tcx, &body); // FIXME: make this a MIR lint
}
run_post_borrowck_cleanup_passes(tcx, &mut body);
assert!(body.phase == MirPhase::Deaggregated);
tcx.alloc_steal_mir(body)
debug!("runtime_mir_lowering({:?})", did);
run_runtime_lowering_passes(tcx, body);
assert!(body.phase == MirPhase::Runtime(RuntimePhase::Initial));
debug!("runtime_mir_cleanup({:?})", did);
run_runtime_cleanup_passes(tcx, body);
assert!(body.phase == MirPhase::Runtime(RuntimePhase::PostCleanup));
}
/// After this series of passes, no lifetime analysis based on borrowing can be done.
fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("post_borrowck_cleanup({:?})", body.source.def_id());
// FIXME(JakobDegen): Can we make these lists of passes consts?
let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[
// Remove all things only needed by analysis
/// After this series of passes, no lifetime analysis based on borrowing can be done.
fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let passes: &[&dyn MirPass<'tcx>] = &[
&remove_false_edges::RemoveFalseEdges,
&simplify_branches::SimplifyConstCondition::new("initial"),
&remove_noop_landing_pads::RemoveNoopLandingPads,
&cleanup_post_borrowck::CleanupNonCodegenStatements,
&simplify::SimplifyCfg::new("early-opt"),
&deref_separator::Derefer,
&marker::PhaseChange(MirPhase::Analysis(AnalysisPhase::PostCleanup)),
];
pm::run_passes(tcx, body, passes);
}
/// Returns the sequence of passes that lowers analysis to runtime MIR.
fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let passes: &[&dyn MirPass<'tcx>] = &[
// These next passes must be executed together
&add_call_guards::CriticalCallEdges,
&elaborate_drops::ElaborateDrops,
@ -425,16 +454,27 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc
// `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late,
// but before optimizations begin.
&elaborate_box_derefs::ElaborateBoxDerefs,
&generator::StateTransform,
&add_retag::AddRetag,
&lower_intrinsics::LowerIntrinsics,
&simplify::SimplifyCfg::new("elaborate-drops"),
// `Deaggregator` is conceptually part of MIR building, some backends rely on it happening
// and it can help optimizations.
// Deaggregator is necessary for const prop. We may want to consider implementing
// CTFE support for aggregates.
&deaggregator::Deaggregator,
&Lint(const_prop_lint::ConstProp),
&marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Initial)),
];
pm::run_passes_no_validate(tcx, body, passes);
}
/// Returns the sequence of passes that do the initial cleanup of runtime MIR.
fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let passes: &[&dyn MirPass<'tcx>] = &[
&elaborate_box_derefs::ElaborateBoxDerefs,
&lower_intrinsics::LowerIntrinsics,
&simplify::SimplifyCfg::new("elaborate-drops"),
&marker::PhaseChange(MirPhase::Runtime(RuntimePhase::PostCleanup)),
];
pm::run_passes(tcx, body, post_borrowck_cleanup);
pm::run_passes(tcx, body, passes);
}
fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@ -442,9 +482,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
WithMinOptLevel(1, x)
}
// Lowering generator control-flow and variables has to happen before we do anything else
// to them. We run some optimizations before that, because they may be harder to do on the state
// machine than on MIR with async primitives.
// The main optimizations that we do on MIR.
pm::run_passes(
tcx,
body,
@ -456,17 +494,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&uninhabited_enum_branching::UninhabitedEnumBranching,
&o1(simplify::SimplifyCfg::new("after-uninhabited-enum-branching")),
&inline::Inline,
&generator::StateTransform,
],
);
assert!(body.phase == MirPhase::GeneratorsLowered);
// The main optimizations that we do on MIR.
pm::run_passes(
tcx,
body,
&[
&remove_storage_markers::RemoveStorageMarkers,
&remove_zsts::RemoveZsts,
&const_goto::ConstGoto,
@ -498,7 +525,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&deduplicate_blocks::DeduplicateBlocks,
// Some cleanup necessary at least for LLVM and potentially other codegen backends.
&add_call_guards::CriticalCallEdges,
&marker::PhaseChange(MirPhase::Optimized),
&marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)),
// Dump the end result for testing and debugging purposes.
&dump_mir::Marker("PreCodegen"),
],
@ -557,7 +584,7 @@ fn promoted_mir<'tcx>(
if let Some(error_reported) = tainted_by_errors {
body.tainted_by_errors = Some(error_reported);
}
run_post_borrowck_cleanup_passes(tcx, body);
run_analysis_to_runtime_passes(tcx, body);
}
debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");

View File

@ -1,6 +1,6 @@
use std::borrow::Cow;
use rustc_middle::mir::{self, Body, MirPhase};
use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
@ -72,11 +72,30 @@ where
}
}
/// Run the sequence of passes without validating the MIR after each pass. The MIR is still
/// validated at the end.
pub fn run_passes_no_validate<'tcx>(
tcx: TyCtxt<'tcx>,
body: &mut Body<'tcx>,
passes: &[&dyn MirPass<'tcx>],
) {
run_passes_inner(tcx, body, passes, false);
}
pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>]) {
run_passes_inner(tcx, body, passes, true);
}
fn run_passes_inner<'tcx>(
tcx: TyCtxt<'tcx>,
body: &mut Body<'tcx>,
passes: &[&dyn MirPass<'tcx>],
validate_each: bool,
) {
let start_phase = body.phase;
let mut cnt = 0;
let validate = tcx.sess.opts.unstable_opts.validate_mir;
let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir;
let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
trace!(?overridden_passes);
@ -127,7 +146,7 @@ pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn
}
}
if validate || body.phase == MirPhase::Optimized {
if validate || body.phase == MirPhase::Runtime(RuntimePhase::Optimized) {
validate_body(tcx, body, format!("end of phase transition to {:?}", body.phase));
}
}
@ -144,7 +163,7 @@ pub fn dump_mir<'tcx>(
cnt: usize,
is_after: bool,
) {
let phase_index = phase as u32;
let phase_index = phase.phase_index();
mir::dump_mir(
tcx,

View File

@ -17,8 +17,8 @@ use std::iter;
use crate::util::expand_aggregate;
use crate::{
abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, marker, pass_manager as pm,
remove_noop_landing_pads, simplify,
abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, marker,
pass_manager as pm, remove_noop_landing_pads, simplify,
};
use rustc_middle::mir::patch::MirPatch;
use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
@ -92,11 +92,12 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
&mut result,
&[
&add_moves_for_packed_drops::AddMovesForPackedDrops,
&deref_separator::Derefer,
&remove_noop_landing_pads::RemoveNoopLandingPads,
&simplify::SimplifyCfg::new("make_shim"),
&add_call_guards::CriticalCallEdges,
&abort_unwinding_calls::AbortUnwindingCalls,
&marker::PhaseChange(MirPhase::Const),
&marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)),
],
);

View File

@ -21,15 +21,13 @@ yields ()
bb0: {
StorageLive(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:13: 23:14
Deinit(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
(_3.0: i32) = const 5_i32; // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
_3 = Foo(const 5_i32); // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
StorageLive(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:13: 24:14
Deinit(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
(_4.0: i32) = const 6_i32; // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
_4 = Bar(const 6_i32); // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
StorageLive(_5); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
StorageLive(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
Deinit(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
_5 = yield(move _6) -> [resume: bb1, drop: bb5]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
_6 = (); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
_5 = yield(move _6) -> [resume: bb1, drop: bb6]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
}
bb1: {
@ -38,7 +36,7 @@ yields ()
StorageLive(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16
StorageLive(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:14: 26:15
_8 = move _3; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:14: 26:15
_7 = take::<Foo>(move _8) -> [return: bb2, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16
_7 = take::<Foo>(move _8) -> [return: bb2, unwind: bb10]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16
// mir::Constant
// + span: $DIR/generator-storage-dead-unwind.rs:26:9: 26:13
// + literal: Const { ty: fn(Foo) {take::<Foo>}, val: Value(<ZST>) }
@ -50,7 +48,7 @@ yields ()
StorageLive(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16
StorageLive(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:14: 27:15
_10 = move _4; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:14: 27:15
_9 = take::<Bar>(move _10) -> [return: bb3, unwind: bb8]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16
_9 = take::<Bar>(move _10) -> [return: bb3, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16
// mir::Constant
// + span: $DIR/generator-storage-dead-unwind.rs:27:9: 27:13
// + literal: Const { ty: fn(Bar) {take::<Bar>}, val: Value(<ZST>) }
@ -61,54 +59,66 @@ yields ()
StorageDead(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:16: 27:17
_0 = const (); // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 28:6
StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
drop(_1) -> [return: bb4, unwind: bb11]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
goto -> bb4; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
}
bb4: {
return; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:18: +0:18
StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
drop(_1) -> [return: bb5, unwind: bb14]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
}
bb5: {
StorageDead(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:13: 25:14
StorageDead(_5); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:14: 25:15
StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
drop(_3) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
return; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:18: +0:18
}
bb6: {
StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
drop(_1) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
StorageDead(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:13: 25:14
StorageDead(_5); // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:14: 25:15
StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
drop(_3) -> [return: bb7, unwind: bb15]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
}
bb7: {
StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
drop(_1) -> [return: bb8, unwind: bb14]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
}
bb8: {
generator_drop; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:16: +0:18
}
bb8 (cleanup): {
bb9 (cleanup): {
StorageDead(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:15: 27:16
StorageDead(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:16: 27:17
goto -> bb10; // scope 2 at no-location
}
bb9 (cleanup): {
StorageDead(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:15: 26:16
StorageDead(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:16: 26:17
goto -> bb10; // scope 2 at no-location
goto -> bb12; // scope 2 at no-location
}
bb10 (cleanup): {
StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
drop(_1) -> bb11; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
goto -> bb11; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:15: 26:16
}
bb11 (cleanup): {
resume; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:16: +0:18
StorageDead(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:15: 26:16
StorageDead(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:16: 26:17
goto -> bb12; // scope 2 at no-location
}
bb12 (cleanup): {
StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
goto -> bb13; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
}
bb13 (cleanup): {
StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
drop(_1) -> bb11; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
drop(_1) -> bb14; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
}
bb14 (cleanup): {
resume; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:16: +0:18
}
bb15 (cleanup): {
StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
drop(_1) -> bb14; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
}
}

View File

@ -38,7 +38,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 19:24
bb1: {
_10 = move _2; // scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24
nop; // scope 0 at $DIR/generator-tiny.rs:20:13: 20:15
Deinit((((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop)); // scope 0 at $DIR/generator-tiny.rs:20:18: 20:25
(((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop) = HasDrop; // scope 0 at $DIR/generator-tiny.rs:20:18: 20:25
StorageLive(_4); // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10
goto -> bb2; // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10
}
@ -46,7 +46,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 19:24
bb2: {
StorageLive(_6); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
StorageLive(_7); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
Deinit(_7); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
_7 = (); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
Deinit(_0); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
discriminant(_0) = 0; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18

View File

@ -16,15 +16,20 @@ fn main() -> () {
StorageLive(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
StorageLive(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
StorageLive(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
_3 = Droppy(const 0_usize); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
_2 = Aligned(move _3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
Deinit(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
(_3.0: usize) = const 0_usize; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
Deinit(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
(_2.0: Droppy) = move _3; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
StorageDead(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:41: +1:42
_1 = Packed(move _2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
Deinit(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
(_1.0: Aligned) = move _2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
StorageDead(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:42: +1:43
StorageLive(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
StorageLive(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
_5 = Droppy(const 0_usize); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
_4 = Aligned(move _5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
Deinit(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
(_5.0: usize) = const 0_usize; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
Deinit(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
(_4.0: Droppy) = move _5; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
StorageDead(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
StorageLive(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
_6 = move (_1.0: Aligned); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8

View File

@ -16,15 +16,20 @@ fn main() -> () {
StorageLive(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
StorageLive(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
StorageLive(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
_3 = Droppy(const 0_usize); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
_2 = Aligned(move _3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
Deinit(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
(_3.0: usize) = const 0_usize; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
Deinit(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
(_2.0: Droppy) = move _3; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
StorageDead(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:41: +1:42
_1 = Packed(move _2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
Deinit(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
(_1.0: Aligned) = move _2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
StorageDead(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:42: +1:43
StorageLive(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
StorageLive(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
_5 = Droppy(const 0_usize); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
_4 = Aligned(move _5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
Deinit(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
(_5.0: usize) = const 0_usize; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
Deinit(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
(_4.0: Droppy) = move _5; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
StorageDead(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
StorageLive(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
_6 = move (_1.0: Aligned); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8

View File

@ -128,7 +128,9 @@ fn array_casts() -> () {
Retag(_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_18 = &(*_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Retag(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_13 = (move _14, move _18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Deinit(_13); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_13.0: &usize) = move _14; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_13.1: &usize) = move _18; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Retag(_13); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_14); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@ -154,7 +156,8 @@ fn array_casts() -> () {
bb3: {
StorageLive(_27); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_27 = core::panicking::AssertKind::Eq; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Deinit(_27); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
discriminant(_27) = 0; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_28); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_29); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_29 = move _27; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@ -171,7 +174,8 @@ fn array_casts() -> () {
_32 = &(*_33); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Retag(_32); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_34 = Option::<Arguments>::None; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Deinit(_34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
discriminant(_34) = 0; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Retag(_34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_28 = core::panicking::assert_failed::<usize, usize>(move _29, move _30, move _32, move _34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant

View File

@ -62,7 +62,8 @@ fn main() -> () {
StorageLive(_3); // scope 1 at $DIR/retag.rs:+3:13: +3:14
StorageLive(_4); // scope 1 at $DIR/retag.rs:+3:17: +3:36
StorageLive(_5); // scope 1 at $DIR/retag.rs:+3:17: +3:24
_5 = Test(const 0_i32); // scope 1 at $DIR/retag.rs:+3:17: +3:24
Deinit(_5); // scope 1 at $DIR/retag.rs:+3:17: +3:24
(_5.0: i32) = const 0_i32; // scope 1 at $DIR/retag.rs:+3:17: +3:24
_4 = &_5; // scope 1 at $DIR/retag.rs:+3:17: +3:36
Retag(_4); // scope 1 at $DIR/retag.rs:+3:17: +3:36
StorageLive(_6); // scope 1 at $DIR/retag.rs:+3:29: +3:35
@ -111,14 +112,7 @@ fn main() -> () {
StorageDead(_2); // scope 1 at $DIR/retag.rs:+8:5: +8:6
StorageLive(_13); // scope 1 at $DIR/retag.rs:+11:9: +11:10
StorageLive(_14); // scope 1 at $DIR/retag.rs:+11:31: +14:6
_14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:+11:31: +14:6
// closure
// + def_id: DefId(0:14 ~ retag[4622]::main::{closure#0})
// + substs: [
// i8,
// for<'r> extern "rust-call" fn((&'r i32,)) -> &'r i32,
// (),
// ]
Deinit(_14); // scope 1 at $DIR/retag.rs:+11:31: +14:6
Retag(_14); // scope 1 at $DIR/retag.rs:+11:31: +14:6
_13 = move _14 as for<'r> fn(&'r i32) -> &'r i32 (Pointer(ClosureFnPointer(Normal))); // scope 1 at $DIR/retag.rs:+11:31: +14:6
StorageDead(_14); // scope 1 at $DIR/retag.rs:+11:47: +11:48
@ -142,7 +136,8 @@ fn main() -> () {
StorageLive(_19); // scope 7 at $DIR/retag.rs:+18:5: +18:24
StorageLive(_20); // scope 7 at $DIR/retag.rs:+18:5: +18:24
StorageLive(_21); // scope 7 at $DIR/retag.rs:+18:5: +18:12
_21 = Test(const 0_i32); // scope 7 at $DIR/retag.rs:+18:5: +18:12
Deinit(_21); // scope 7 at $DIR/retag.rs:+18:5: +18:12
(_21.0: i32) = const 0_i32; // scope 7 at $DIR/retag.rs:+18:5: +18:12
_20 = &_21; // scope 7 at $DIR/retag.rs:+18:5: +18:24
Retag(_20); // scope 7 at $DIR/retag.rs:+18:5: +18:24
StorageLive(_22); // scope 7 at $DIR/retag.rs:+18:21: +18:23