mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 07:22:42 +00:00
Refactor MIR phases
This commit is contained in:
parent
9f4d5d2a28
commit
aad14c701e
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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)),
|
||||
],
|
||||
);
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user