summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_transform
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
commit218caa410aa38c29984be31a5229b9fa717560ee (patch)
treec54bd55eeb6e4c508940a30e94c0032fbd45d677 /compiler/rustc_mir_transform
parentReleasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz
rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_mir_transform')
-rw-r--r--compiler/rustc_mir_transform/src/add_retag.rs2
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs43
-rw-r--r--compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs65
-rw-r--r--compiler/rustc_mir_transform/src/const_goto.rs3
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs28
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs6
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs10
-rw-r--r--compiler/rustc_mir_transform/src/coverage/tests.rs7
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs12
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs2
-rw-r--r--compiler/rustc_mir_transform/src/deduce_param_attrs.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs180
-rw-r--r--compiler/rustc_mir_transform/src/early_otherwise_branch.rs22
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs126
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs107
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs48
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs12
-rw-r--r--compiler/rustc_mir_transform/src/normalize_array_len.rs3
-rw-r--r--compiler/rustc_mir_transform/src/remove_false_edges.rs29
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs6
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs44
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs16
-rw-r--r--compiler/rustc_mir_transform/src/simplify_branches.rs7
-rw-r--r--compiler/rustc_mir_transform/src/simplify_comparison_integral.rs7
-rw-r--r--compiler/rustc_mir_transform/src/simplify_try.rs2
-rw-r--r--compiler/rustc_mir_transform/src/sroa.rs4
-rw-r--r--compiler/rustc_mir_transform/src/unreachable_prop.rs10
29 files changed, 484 insertions, 327 deletions
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 3d22035f0..7d2146214 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -120,7 +120,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
// PART 3
// Add retag after assignments where data "enters" this function: the RHS is behind a deref and the LHS is not.
for block_data in basic_blocks {
- // We want to insert statements as we iterate. To this end, we
+ // We want to insert statements as we iterate. To this end, we
// iterate backwards using indices.
for i in (0..block_data.statements.len()).rev() {
let (retag_kind, place) = match block_data.statements[i].kind {
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index e783d1891..adf6ae4c7 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -1,6 +1,7 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::hir_id::HirId;
use rustc_hir::intravisit;
@@ -134,6 +135,28 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
self.super_rvalue(rvalue, location);
}
+ fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
+ if let Operand::Constant(constant) = op {
+ let maybe_uneval = match constant.literal {
+ ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
+ ConstantKind::Unevaluated(uv, _) => Some(uv),
+ };
+
+ if let Some(uv) = maybe_uneval {
+ if uv.promoted.is_none() {
+ let def_id = uv.def.def_id_for_type_of();
+ if self.tcx.def_kind(def_id) == DefKind::InlineConst {
+ let local_def_id = def_id.expect_local();
+ let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
+ self.tcx.unsafety_check_result(local_def_id);
+ self.register_violations(violations, used_unsafe_blocks.iter().copied());
+ }
+ }
+ }
+ }
+ self.super_operand(op, location);
+ }
+
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
// On types with `scalar_valid_range`, prevent
// * `&mut x.field`
@@ -410,6 +433,12 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> {
intravisit::walk_block(self, block);
}
+ fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
+ if matches!(self.tcx.def_kind(c.def_id), DefKind::InlineConst) {
+ self.visit_body(self.tcx.hir().body(c.body))
+ }
+ }
+
fn visit_fn(
&mut self,
fk: intravisit::FnKind<'tcx>,
@@ -461,17 +490,17 @@ fn check_unused_unsafe(
unused_unsafes
}
-fn unsafety_check_result<'tcx>(
- tcx: TyCtxt<'tcx>,
+fn unsafety_check_result(
+ tcx: TyCtxt<'_>,
def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx UnsafetyCheckResult {
+) -> &UnsafetyCheckResult {
debug!("unsafety_violations({:?})", def);
// N.B., this borrow is valid because all the consumers of
// `mir_built` force this.
let body = &tcx.mir_built(def).borrow();
- if body.should_skip() {
+ if body.is_custom_mir() {
return tcx.arena.alloc(UnsafetyCheckResult {
violations: Vec::new(),
used_unsafe_blocks: FxHashSet::default(),
@@ -484,7 +513,7 @@ fn unsafety_check_result<'tcx>(
let mut checker = UnsafetyChecker::new(body, def.did, tcx, param_env);
checker.visit_body(&body);
- let unused_unsafes = (!tcx.is_closure(def.did.to_def_id()))
+ let unused_unsafes = (!tcx.is_typeck_child(def.did.to_def_id()))
.then(|| check_unused_unsafe(tcx, def.did, &checker.used_unsafe_blocks));
tcx.arena.alloc(UnsafetyCheckResult {
@@ -516,8 +545,8 @@ fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
debug!("check_unsafety({:?})", def_id);
- // closures are handled by their parent fn.
- if tcx.is_closure(def_id.to_def_id()) {
+ // closures and inline consts are handled by their parent fn.
+ if tcx.is_typeck_child(def_id.to_def_id()) {
return;
}
diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index 3378923c2..d435d3ee6 100644
--- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -1,39 +1,44 @@
-//! This module provides a pass to replacing the following statements with
-//! [`Nop`]s
+//! This module provides a pass that removes parts of MIR that are no longer relevant after
+//! analysis phase and borrowck. In particular, it removes false edges, user type annotations and
+//! replaces following statements with [`Nop`]s:
//!
//! - [`AscribeUserType`]
//! - [`FakeRead`]
//! - [`Assign`] statements with a [`Shallow`] borrow
//!
-//! The `CleanFakeReadsAndBorrows` "pass" is actually implemented as two
-//! traversals (aka visits) of the input MIR. The first traversal,
-//! `DeleteAndRecordFakeReads`, deletes the fake reads and finds the
-//! temporaries read by [`ForMatchGuard`] reads, and `DeleteFakeBorrows`
-//! deletes the initialization of those temporaries.
-//!
//! [`AscribeUserType`]: rustc_middle::mir::StatementKind::AscribeUserType
-//! [`Shallow`]: rustc_middle::mir::BorrowKind::Shallow
-//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead
//! [`Assign`]: rustc_middle::mir::StatementKind::Assign
-//! [`ForMatchGuard`]: rustc_middle::mir::FakeReadCause::ForMatchGuard
+//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead
//! [`Nop`]: rustc_middle::mir::StatementKind::Nop
+//! [`Shallow`]: rustc_middle::mir::BorrowKind::Shallow
use crate::MirPass;
-use rustc_middle::mir::visit::MutVisitor;
-use rustc_middle::mir::{Body, BorrowKind, Location, Rvalue};
-use rustc_middle::mir::{Statement, StatementKind};
+use rustc_middle::mir::{Body, BorrowKind, Rvalue, StatementKind, TerminatorKind};
use rustc_middle::ty::TyCtxt;
-pub struct CleanupNonCodegenStatements;
+pub struct CleanupPostBorrowck;
-pub struct DeleteNonCodegenStatements<'tcx> {
- tcx: TyCtxt<'tcx>,
-}
+impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
+ fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ for basic_block in body.basic_blocks.as_mut() {
+ for statement in basic_block.statements.iter_mut() {
+ match statement.kind {
+ StatementKind::AscribeUserType(..)
+ | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
+ | StatementKind::FakeRead(..) => statement.make_nop(),
+ _ => (),
+ }
+ }
+ let terminator = basic_block.terminator_mut();
+ match terminator.kind {
+ TerminatorKind::FalseEdge { real_target, .. }
+ | TerminatorKind::FalseUnwind { real_target, .. } => {
+ terminator.kind = TerminatorKind::Goto { target: real_target };
+ }
+ _ => {}
+ }
+ }
-impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let mut delete = DeleteNonCodegenStatements { tcx };
- delete.visit_body_preserves_cfg(body);
body.user_type_annotations.raw.clear();
for decl in &mut body.local_decls {
@@ -41,19 +46,3 @@ impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
}
}
}
-
-impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements<'tcx> {
- fn tcx(&self) -> TyCtxt<'tcx> {
- self.tcx
- }
-
- fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
- match statement.kind {
- StatementKind::AscribeUserType(..)
- | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
- | StatementKind::FakeRead(..) => statement.make_nop(),
- _ => (),
- }
- self.super_statement(statement, location);
- }
-}
diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs
index 0a305a402..40eefda4f 100644
--- a/compiler/rustc_mir_transform/src/const_goto.rs
+++ b/compiler/rustc_mir_transform/src/const_goto.rs
@@ -82,8 +82,9 @@ impl<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> {
}
let target_bb_terminator = target_bb.terminator();
- let (discr, switch_ty, targets) = target_bb_terminator.kind.as_switch()?;
+ let (discr, targets) = target_bb_terminator.kind.as_switch()?;
if discr.place() == Some(*place) {
+ let switch_ty = place.ty(self.body.local_decls(), self.tcx).ty;
// We now know that the Switch matches on the const place, and it is statementless
// Now find which value in the Switch matches the const value.
let const_value =
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index b0514e033..5c45abc5a 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -6,6 +6,7 @@ use std::cell::Cell;
use either::Right;
use rustc_ast::Mutability;
+use rustc_const_eval::const_eval::CheckAlignment;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::DefKind;
use rustc_index::bit_set::BitSet;
@@ -22,7 +23,7 @@ use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayo
use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable};
use rustc_span::{def_id::DefId, Span};
-use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout};
+use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout};
use rustc_target::spec::abi::Abi as CallAbi;
use rustc_trait_selection::traits;
@@ -186,16 +187,27 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
type MemoryKind = !;
#[inline(always)]
- fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+ fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
// We do not check for alignment to avoid having to carry an `Align`
// in `ConstValue::ByRef`.
- false
+ CheckAlignment::No
}
#[inline(always)]
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
false // for now, we don't enforce validity
}
+ fn alignment_check_failed(
+ ecx: &InterpCx<'mir, 'tcx, Self>,
+ _has: Align,
+ _required: Align,
+ _check: CheckAlignment,
+ ) -> InterpResult<'tcx, ()> {
+ span_bug!(
+ ecx.cur_span(),
+ "`alignment_check_failed` called when no alignment check requested"
+ )
+ }
fn load_mir(
_ecx: &InterpCx<'mir, 'tcx, Self>,
@@ -643,11 +655,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
return None;
}
- if self.tcx.sess.mir_opt_level() >= 4 {
- self.eval_rvalue_with_identities(rvalue, place)
- } else {
- self.use_ecx(|this| this.ecx.eval_rvalue_into_place(rvalue, place))
- }
+ self.eval_rvalue_with_identities(rvalue, place)
}
// Attempt to use algebraic identities to eliminate constant expressions
@@ -689,8 +697,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
BinOp::Mul if const_arg.layout.ty.is_integral() && arg_value == 0 => {
if let Rvalue::CheckedBinaryOp(_, _) = rvalue {
let val = Immediate::ScalarPair(
- const_arg.to_scalar().into(),
- Scalar::from_bool(false).into(),
+ const_arg.to_scalar(),
+ Scalar::from_bool(false),
);
this.ecx.write_immediate(val, &dest)
} else {
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 782129be0..78d28f1eb 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -282,9 +282,9 @@ impl graph::WithPredecessors for CoverageGraph {
rustc_index::newtype_index! {
/// A node in the control-flow graph of CoverageGraph.
+ #[debug_format = "bcb{}"]
pub(super) struct BasicCoverageBlock {
- DEBUG_FORMAT = "bcb{}",
- const START_BCB = 0,
+ const START_BCB = 0;
}
}
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 604810144..1468afc64 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -533,10 +533,10 @@ fn make_code_region(
}
}
-fn fn_sig_and_body<'tcx>(
- tcx: TyCtxt<'tcx>,
+fn fn_sig_and_body(
+ tcx: TyCtxt<'_>,
def_id: DefId,
-) -> (Option<&'tcx rustc_hir::FnSig<'tcx>>, &'tcx rustc_hir::Body<'tcx>) {
+) -> (Option<&rustc_hir::FnSig<'_>>, &rustc_hir::Body<'_>) {
// FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back
// to HIR for it.
let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index dc1e68b25..3bd7f31b4 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -136,7 +136,7 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) ->
coverage_visitor.info
}
-fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> {
+fn covered_code_regions(tcx: TyCtxt<'_>, def_id: DefId) -> Vec<&CodeRegion> {
let body = mir_body(tcx, def_id);
body.basic_blocks
.iter()
@@ -163,7 +163,7 @@ fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool {
/// This function ensures we obtain the correct MIR for the given item irrespective of
/// whether that means const mir or runtime mir. For `const fn` this opts for runtime
/// mir.
-fn mir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx mir::Body<'tcx> {
+fn mir_body(tcx: TyCtxt<'_>, def_id: DefId) -> &mir::Body<'_> {
let id = ty::WithOptConstParam::unknown(def_id);
let def = ty::InstanceDef::Item(id);
tcx.instance_mir(def)
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 9f842c929..c54348404 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -341,11 +341,11 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
if a.is_in_same_bcb(b) {
Some(Ordering::Equal)
} else {
- // Sort equal spans by dominator relationship, in reverse order (so
- // dominators always come after the dominated equal spans). When later
- // comparing two spans in order, the first will either dominate the second,
- // or they will have no dominator relationship.
- self.basic_coverage_blocks.dominators().rank_partial_cmp(b.bcb, a.bcb)
+ // Sort equal spans by dominator relationship (so dominators always come
+ // before the dominated equal spans). When later comparing two spans in
+ // order, the first will either dominate the second, or they will have no
+ // dominator relationship.
+ self.basic_coverage_blocks.dominators().rank_partial_cmp(a.bcb, b.bcb)
}
} else {
// Sort hi() in reverse order so shorter spans are attempted after longer spans.
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index 9c9ed5fa5..fa7f22303 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -37,7 +37,7 @@ use rustc_data_structures::graph::WithSuccessors;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::mir::*;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty;
use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP};
// All `TEMP_BLOCK` targets should be replaced before calling `to_body() -> mir::Body`.
@@ -47,7 +47,6 @@ struct MockBlocks<'tcx> {
blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
dummy_place: Place<'tcx>,
next_local: usize,
- bool_ty: Ty<'tcx>,
}
impl<'tcx> MockBlocks<'tcx> {
@@ -56,7 +55,6 @@ impl<'tcx> MockBlocks<'tcx> {
blocks: IndexVec::new(),
dummy_place: Place { local: RETURN_PLACE, projection: ty::List::empty() },
next_local: 0,
- bool_ty: TyCtxt::BOOL_TY_FOR_UNIT_TESTING,
}
}
@@ -157,7 +155,6 @@ impl<'tcx> MockBlocks<'tcx> {
fn switchint(&mut self, some_from_block: Option<BasicBlock>) -> BasicBlock {
let switchint_kind = TerminatorKind::SwitchInt {
discr: Operand::Move(Place::from(self.new_temp())),
- switch_ty: self.bool_ty, // just a dummy value
targets: SwitchTargets::static_if(0, TEMP_BLOCK, TEMP_BLOCK),
};
self.add_block_from(some_from_block, switchint_kind)
@@ -172,7 +169,7 @@ impl<'tcx> MockBlocks<'tcx> {
}
}
-fn debug_basic_blocks<'tcx>(mir_body: &Body<'tcx>) -> String {
+fn debug_basic_blocks(mir_body: &Body<'_>) -> String {
format!(
"{:?}",
mir_body
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index e90273874..c75fe2327 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -2,6 +2,7 @@
//!
//! Currently, this pass only propagates scalar values.
+use rustc_const_eval::const_eval::CheckAlignment;
use rustc_const_eval::interpret::{ConstValue, ImmTy, Immediate, InterpCx, Scalar};
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::mir::visit::{MutVisitor, Visitor};
@@ -10,6 +11,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace};
use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects};
use rustc_span::DUMMY_SP;
+use rustc_target::abi::Align;
use crate::MirPass;
@@ -448,13 +450,21 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
type MemoryKind = !;
const PANIC_ON_ALLOC_FAIL: bool = true;
- fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+ fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
unimplemented!()
}
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
unimplemented!()
}
+ fn alignment_check_failed(
+ _ecx: &InterpCx<'mir, 'tcx, Self>,
+ _has: Align,
+ _required: Align,
+ _check: CheckAlignment,
+ ) -> interpret::InterpResult<'tcx, ()> {
+ unimplemented!()
+ }
fn find_mir_or_eval_fn(
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 42c580c63..09546330c 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -71,7 +71,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
bbs[block].statements[statement_index].make_nop();
}
- crate::simplify::SimplifyLocals.run_pass(tcx, body)
+ crate::simplify::simplify_locals(body, tcx)
}
pub struct DeadStoreElimination;
diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
index 92f1fff6b..ddab7bbb2 100644
--- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
+++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
@@ -129,7 +129,7 @@ impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
}
/// Returns true if values of a given type will never be passed indirectly, regardless of ABI.
-fn type_will_always_be_passed_directly<'tcx>(ty: Ty<'tcx>) -> bool {
+fn type_will_always_be_passed_directly(ty: Ty<'_>) -> bool {
matches!(
ty.kind(),
ty::Bool
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 97485c4f5..08e296a83 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -129,18 +129,16 @@
use std::collections::hash_map::{Entry, OccupiedEntry};
+use crate::simplify::remove_dead_blocks;
use crate::MirPass;
use rustc_data_structures::fx::FxHashMap;
use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
use rustc_middle::mir::{dump_mir, PassWhere};
use rustc_middle::mir::{
traversal, BasicBlock, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place,
Rvalue, Statement, StatementKind, TerminatorKind,
};
-use rustc_middle::mir::{
- visit::{MutVisitor, PlaceContext, Visitor},
- ProjectionElem,
-};
use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::impls::MaybeLiveLocals;
use rustc_mir_dataflow::{Analysis, ResultsCursor};
@@ -238,6 +236,12 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
apply_merges(body, tcx, &merges, &merged_locals);
}
+ if round_count != 0 {
+ // Merging can introduce overlap between moved arguments and/or call destination in an
+ // unreachable code, which validator considers to be ill-formed.
+ remove_dead_blocks(tcx, body);
+ }
+
trace!(round_count);
}
}
@@ -359,40 +363,45 @@ struct FilterInformation<'a, 'body, 'alloc, 'tcx> {
// through these methods, and not directly.
impl<'alloc> Candidates<'alloc> {
/// Just `Vec::retain`, but the condition is inverted and we add debugging output
- fn vec_remove_debug(
+ fn vec_filter_candidates(
src: Local,
v: &mut Vec<Local>,
- mut f: impl FnMut(Local) -> bool,
+ mut f: impl FnMut(Local) -> CandidateFilter,
at: Location,
) {
v.retain(|dest| {
let remove = f(*dest);
- if remove {
+ if remove == CandidateFilter::Remove {
trace!("eliminating {:?} => {:?} due to conflict at {:?}", src, dest, at);
}
- !remove
+ remove == CandidateFilter::Keep
});
}
- /// `vec_remove_debug` but for an `Entry`
- fn entry_remove(
+ /// `vec_filter_candidates` but for an `Entry`
+ fn entry_filter_candidates(
mut entry: OccupiedEntry<'_, Local, Vec<Local>>,
p: Local,
- f: impl FnMut(Local) -> bool,
+ f: impl FnMut(Local) -> CandidateFilter,
at: Location,
) {
let candidates = entry.get_mut();
- Self::vec_remove_debug(p, candidates, f, at);
+ Self::vec_filter_candidates(p, candidates, f, at);
if candidates.len() == 0 {
entry.remove();
}
}
- /// Removes all candidates `(p, q)` or `(q, p)` where `p` is the indicated local and `f(q)` is true.
- fn remove_candidates_if(&mut self, p: Local, mut f: impl FnMut(Local) -> bool, at: Location) {
+ /// For all candidates `(p, q)` or `(q, p)` removes the candidate if `f(q)` says to do so
+ fn filter_candidates_by(
+ &mut self,
+ p: Local,
+ mut f: impl FnMut(Local) -> CandidateFilter,
+ at: Location,
+ ) {
// Cover the cases where `p` appears as a `src`
if let Entry::Occupied(entry) = self.c.entry(p) {
- Self::entry_remove(entry, p, &mut f, at);
+ Self::entry_filter_candidates(entry, p, &mut f, at);
}
// And the cases where `p` appears as a `dest`
let Some(srcs) = self.reverse.get_mut(&p) else {
@@ -401,18 +410,31 @@ impl<'alloc> Candidates<'alloc> {
// We use `retain` here to remove the elements from the reverse set if we've removed the
// matching candidate in the forward set.
srcs.retain(|src| {
- if !f(*src) {
+ if f(*src) == CandidateFilter::Keep {
return true;
}
let Entry::Occupied(entry) = self.c.entry(*src) else {
return false;
};
- Self::entry_remove(entry, *src, |dest| dest == p, at);
+ Self::entry_filter_candidates(
+ entry,
+ *src,
+ |dest| {
+ if dest == p { CandidateFilter::Remove } else { CandidateFilter::Keep }
+ },
+ at,
+ );
false
});
}
}
+#[derive(Copy, Clone, PartialEq, Eq)]
+enum CandidateFilter {
+ Keep,
+ Remove,
+}
+
impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
/// Filters the set of candidates to remove those that conflict.
///
@@ -460,7 +482,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
for (i, statement) in data.statements.iter().enumerate().rev() {
self.at = Location { block, statement_index: i };
self.live.seek_after_primary_effect(self.at);
- self.get_statement_write_info(&statement.kind);
+ self.write_info.for_statement(&statement.kind, self.body);
self.apply_conflicts();
}
}
@@ -469,80 +491,59 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
fn apply_conflicts(&mut self) {
let writes = &self.write_info.writes;
for p in writes {
- self.candidates.remove_candidates_if(
+ let other_skip = self.write_info.skip_pair.and_then(|(a, b)| {
+ if a == *p {
+ Some(b)
+ } else if b == *p {
+ Some(a)
+ } else {
+ None
+ }
+ });
+ self.candidates.filter_candidates_by(
*p,
- // It is possible that a local may be live for less than the
- // duration of a statement This happens in the case of function
- // calls or inline asm. Because of this, we also mark locals as
- // conflicting when both of them are written to in the same
- // statement.
- |q| self.live.contains(q) || writes.contains(&q),
+ |q| {
+ if Some(q) == other_skip {
+ return CandidateFilter::Keep;
+ }
+ // It is possible that a local may be live for less than the
+ // duration of a statement This happens in the case of function
+ // calls or inline asm. Because of this, we also mark locals as
+ // conflicting when both of them are written to in the same
+ // statement.
+ if self.live.contains(q) || writes.contains(&q) {
+ CandidateFilter::Remove
+ } else {
+ CandidateFilter::Keep
+ }
+ },
self.at,
);
}
}
-
- /// Gets the write info for the `statement`.
- fn get_statement_write_info(&mut self, statement: &StatementKind<'tcx>) {
- self.write_info.writes.clear();
- match statement {
- StatementKind::Assign(box (lhs, rhs)) => match rhs {
- Rvalue::Use(op) => {
- if !lhs.is_indirect() {
- self.get_assign_use_write_info(*lhs, op);
- return;
- }
- }
- _ => (),
- },
- _ => (),
- }
-
- self.write_info.for_statement(statement);
- }
-
- fn get_assign_use_write_info(&mut self, lhs: Place<'tcx>, rhs: &Operand<'tcx>) {
- // We register the writes for the operand unconditionally
- self.write_info.add_operand(rhs);
- // However, we cannot do the same thing for the `lhs` as that would always block the
- // optimization. Instead, we consider removing candidates manually.
- let Some(rhs) = rhs.place() else {
- self.write_info.add_place(lhs);
- return;
- };
- // Find out which candidate pair we should skip, if any
- let Some((src, dest)) = places_to_candidate_pair(lhs, rhs, self.body) else {
- self.write_info.add_place(lhs);
- return;
- };
- self.candidates.remove_candidates_if(
- lhs.local,
- |other| {
- // Check if this is the candidate pair that should not be removed
- if (lhs.local == src && other == dest) || (lhs.local == dest && other == src) {
- return false;
- }
- // Otherwise, do the "standard" thing
- self.live.contains(other)
- },
- self.at,
- )
- }
}
/// Describes where a statement/terminator writes to
#[derive(Default, Debug)]
struct WriteInfo {
writes: Vec<Local>,
+ /// If this pair of locals is a candidate pair, completely skip processing it during this
+ /// statement. All other candidates are unaffected.
+ skip_pair: Option<(Local, Local)>,
}
impl WriteInfo {
- fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>) {
+ fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>, body: &Body<'tcx>) {
+ self.reset();
match statement {
StatementKind::Assign(box (lhs, rhs)) => {
self.add_place(*lhs);
match rhs {
- Rvalue::Use(op) | Rvalue::Repeat(op, _) => {
+ Rvalue::Use(op) => {
+ self.add_operand(op);
+ self.consider_skipping_for_assign_use(*lhs, op, body);
+ }
+ Rvalue::Repeat(op, _) => {
self.add_operand(op);
}
Rvalue::Cast(_, op, _)
@@ -586,8 +587,22 @@ impl WriteInfo {
}
}
+ fn consider_skipping_for_assign_use<'tcx>(
+ &mut self,
+ lhs: Place<'tcx>,
+ rhs: &Operand<'tcx>,
+ body: &Body<'tcx>,
+ ) {
+ let Some(rhs) = rhs.place() else {
+ return
+ };
+ if let Some(pair) = places_to_candidate_pair(lhs, rhs, body) {
+ self.skip_pair = Some(pair);
+ }
+ }
+
fn for_terminator<'tcx>(&mut self, terminator: &TerminatorKind<'tcx>) {
- self.writes.clear();
+ self.reset();
match terminator {
TerminatorKind::SwitchInt { discr: op, .. }
| TerminatorKind::Assert { cond: op, .. } => {
@@ -643,7 +658,7 @@ impl WriteInfo {
}
}
- fn add_place<'tcx>(&mut self, place: Place<'tcx>) {
+ fn add_place(&mut self, place: Place<'_>) {
self.writes.push(place.local);
}
@@ -657,15 +672,16 @@ impl WriteInfo {
Operand::Copy(_) | Operand::Constant(_) => (),
}
}
+
+ fn reset(&mut self) {
+ self.writes.clear();
+ self.skip_pair = None;
+ }
}
/////////////////////////////////////////////////////
// Candidate accumulation
-fn is_constant<'tcx>(place: Place<'tcx>) -> bool {
- place.projection.iter().all(|p| !matches!(p, ProjectionElem::Deref | ProjectionElem::Index(_)))
-}
-
/// If the pair of places is being considered for merging, returns the candidate which would be
/// merged in order to accomplish this.
///
@@ -741,10 +757,6 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> {
Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
)) = &statement.kind
{
- if !is_constant(*lhs) || !is_constant(*rhs) {
- return;
- }
-
let Some((src, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else {
return;
};
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index 32e738bbc..8a7b027dd 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -121,7 +121,6 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
let TerminatorKind::SwitchInt {
discr: parent_op,
- switch_ty: parent_ty,
targets: parent_targets
} = &bbs[parent].terminator().kind else {
unreachable!()
@@ -132,6 +131,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
Operand::Copy(x) => Operand::Copy(*x),
Operand::Constant(x) => Operand::Constant(x.clone()),
};
+ let parent_ty = parent_op.ty(body.local_decls(), tcx);
let statements_before = bbs[parent].statements.len();
let parent_end = Location { block: parent, statement_index: statements_before };
@@ -153,7 +153,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
// create temp to store inequality comparison between the two discriminants, `_t` in
// example above
let nequal = BinOp::Ne;
- let comp_res_type = nequal.ty(tcx, *parent_ty, opt_data.child_ty);
+ let comp_res_type = nequal.ty(tcx, parent_ty, opt_data.child_ty);
let comp_temp = patch.new_temp(comp_res_type, opt_data.child_source.span);
patch.add_statement(parent_end, StatementKind::StorageLive(comp_temp));
@@ -181,7 +181,6 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
kind: TerminatorKind::SwitchInt {
// switch on the first discriminant, so we can mark the second one as dead
discr: parent_op,
- switch_ty: opt_data.child_ty,
targets: eq_targets,
},
}));
@@ -193,12 +192,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
let false_case = eq_bb;
patch.patch_terminator(
parent,
- TerminatorKind::if_(
- tcx,
- Operand::Move(Place::from(comp_temp)),
- true_case,
- false_case,
- ),
+ TerminatorKind::if_(Operand::Move(Place::from(comp_temp)), true_case, false_case),
);
// generate StorageDead for the second_discriminant_temp not in use anymore
@@ -319,11 +313,11 @@ fn evaluate_candidate<'tcx>(
let bbs = &body.basic_blocks;
let TerminatorKind::SwitchInt {
targets,
- switch_ty: parent_ty,
- ..
+ discr: parent_discr,
} = &bbs[parent].terminator().kind else {
return None
};
+ let parent_ty = parent_discr.ty(body.local_decls(), tcx);
let parent_dest = {
let poss = targets.otherwise();
// If the fallthrough on the parent is trivially unreachable, we can let the
@@ -339,12 +333,12 @@ fn evaluate_candidate<'tcx>(
let (_, child) = targets.iter().next()?;
let child_terminator = &bbs[child].terminator();
let TerminatorKind::SwitchInt {
- switch_ty: child_ty,
targets: child_targets,
- ..
+ discr: child_discr,
} = &child_terminator.kind else {
return None
};
+ let child_ty = child_discr.ty(body.local_decls(), tcx);
if child_ty != parent_ty {
return None;
}
@@ -372,7 +366,7 @@ fn evaluate_candidate<'tcx>(
Some(OptimizationData {
destination,
child_place: *child_place,
- child_ty: *child_ty,
+ child_ty,
child_source: child_terminator.source_info,
})
}
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 69f96fe48..39c61a34a 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -460,6 +460,104 @@ fn replace_local<'tcx>(
new_local
}
+/// Transforms the `body` of the generator applying the following transforms:
+///
+/// - Eliminates all the `get_context` calls that async lowering created.
+/// - Replace all `Local` `ResumeTy` types with `&mut Context<'_>` (`context_mut_ref`).
+///
+/// The `Local`s that have their types replaced are:
+/// - The `resume` argument itself.
+/// - The argument to `get_context`.
+/// - The yielded value of a `yield`.
+///
+/// The `ResumeTy` hides a `&mut Context<'_>` behind an unsafe raw pointer, and the
+/// `get_context` function is being used to convert that back to a `&mut Context<'_>`.
+///
+/// Ideally the async lowering would not use the `ResumeTy`/`get_context` indirection,
+/// but rather directly use `&mut Context<'_>`, however that would currently
+/// lead to higher-kinded lifetime errors.
+/// See <https://github.com/rust-lang/rust/issues/105501>.
+///
+/// The async lowering step and the type / lifetime inference / checking are
+/// still using the `ResumeTy` indirection for the time being, and that indirection
+/// is removed here. After this transform, the generator body only knows about `&mut Context<'_>`.
+fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ let context_mut_ref = tcx.mk_task_context();
+
+ // replace the type of the `resume` argument
+ replace_resume_ty_local(tcx, body, Local::new(2), context_mut_ref);
+
+ let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None);
+
+ for bb in BasicBlock::new(0)..body.basic_blocks.next_index() {
+ let bb_data = &body[bb];
+ if bb_data.is_cleanup {
+ continue;
+ }
+
+ match &bb_data.terminator().kind {
+ TerminatorKind::Call { func, .. } => {
+ let func_ty = func.ty(body, tcx);
+ if let ty::FnDef(def_id, _) = *func_ty.kind() {
+ if def_id == get_context_def_id {
+ let local = eliminate_get_context_call(&mut body[bb]);
+ replace_resume_ty_local(tcx, body, local, context_mut_ref);
+ }
+ } else {
+ continue;
+ }
+ }
+ TerminatorKind::Yield { resume_arg, .. } => {
+ replace_resume_ty_local(tcx, body, resume_arg.local, context_mut_ref);
+ }
+ _ => {}
+ }
+ }
+}
+
+fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local {
+ let terminator = bb_data.terminator.take().unwrap();
+ if let TerminatorKind::Call { mut args, destination, target, .. } = terminator.kind {
+ let arg = args.pop().unwrap();
+ let local = arg.place().unwrap().local;
+
+ let arg = Rvalue::Use(arg);
+ let assign = Statement {
+ source_info: terminator.source_info,
+ kind: StatementKind::Assign(Box::new((destination, arg))),
+ };
+ bb_data.statements.push(assign);
+ bb_data.terminator = Some(Terminator {
+ source_info: terminator.source_info,
+ kind: TerminatorKind::Goto { target: target.unwrap() },
+ });
+ local
+ } else {
+ bug!();
+ }
+}
+
+#[cfg_attr(not(debug_assertions), allow(unused))]
+fn replace_resume_ty_local<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body: &mut Body<'tcx>,
+ local: Local,
+ context_mut_ref: Ty<'tcx>,
+) {
+ let local_ty = std::mem::replace(&mut body.local_decls[local].ty, context_mut_ref);
+ // We have to replace the `ResumeTy` that is used for type and borrow checking
+ // with `&mut Context<'_>` in MIR.
+ #[cfg(debug_assertions)]
+ {
+ if let ty::Adt(resume_ty_adt, _) = local_ty.kind() {
+ let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
+ assert_eq!(*resume_ty_adt, expected_adt);
+ } else {
+ panic!("expected `ResumeTy`, found `{:?}`", local_ty);
+ };
+ }
+}
+
struct LivenessInfo {
/// Which locals are live across any suspension point.
saved_locals: GeneratorSavedLocals,
@@ -490,7 +588,7 @@ fn locals_live_across_suspend_points<'tcx>(
// Calculate when MIR locals have live storage. This gives us an upper bound of their
// lifetimes.
- let mut storage_live = MaybeStorageLive::new(always_live_locals.clone())
+ let mut storage_live = MaybeStorageLive::new(std::borrow::Cow::Borrowed(always_live_locals))
.into_engine(tcx, body_ref)
.iterate_to_fixpoint()
.into_results_cursor(body_ref);
@@ -877,11 +975,7 @@ fn insert_switch<'tcx>(
let (assign, discr) = transform.get_discr(body);
let switch_targets =
SwitchTargets::new(cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), default_block);
- let switch = TerminatorKind::SwitchInt {
- discr: Operand::Move(discr),
- switch_ty: transform.discr_ty,
- targets: switch_targets,
- };
+ let switch = TerminatorKind::SwitchInt { discr: Operand::Move(discr), targets: switch_targets };
let source_info = SourceInfo::outermost(body.span);
body.basic_blocks_mut().raw.insert(
@@ -1287,13 +1381,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
}
};
- let is_async_kind = body.generator_kind().unwrap() != GeneratorKind::Gen;
+ let is_async_kind = matches!(body.generator_kind(), Some(GeneratorKind::Async(_)));
let (state_adt_ref, state_substs) = if is_async_kind {
// Compute Poll<return_ty>
- let state_did = tcx.require_lang_item(LangItem::Poll, None);
- let state_adt_ref = tcx.adt_def(state_did);
- let state_substs = tcx.intern_substs(&[body.return_ty().into()]);
- (state_adt_ref, state_substs)
+ let poll_did = tcx.require_lang_item(LangItem::Poll, None);
+ let poll_adt_ref = tcx.adt_def(poll_did);
+ let poll_substs = tcx.intern_substs(&[body.return_ty().into()]);
+ (poll_adt_ref, poll_substs)
} else {
// Compute GeneratorState<yield_ty, return_ty>
let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
@@ -1307,13 +1401,19 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
// RETURN_PLACE then is a fresh unused local with type ret_ty.
let new_ret_local = replace_local(RETURN_PLACE, ret_ty, body, tcx);
+ // Replace all occurrences of `ResumeTy` with `&mut Context<'_>` within async bodies.
+ if is_async_kind {
+ transform_async_context(tcx, body);
+ }
+
// We also replace the resume argument and insert an `Assign`.
// This is needed because the resume argument `_2` might be live across a `yield`, in which
// case there is no `Assign` to it that the transform can turn into a store to the generator
// state. After the yield the slot in the generator state would then be uninitialized.
let resume_local = Local::new(2);
- let new_resume_local =
- replace_local(resume_local, body.local_decls[resume_local].ty, body, tcx);
+ let resume_ty =
+ if is_async_kind { tcx.mk_task_context() } else { body.local_decls[resume_local].ty };
+ let new_resume_local = replace_local(resume_local, resume_ty, body, tcx);
// When first entering the generator, move the resume argument into its new local.
let source_info = SourceInfo::outermost(body.span);
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 220cf7df9..28c9080d3 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -1,6 +1,7 @@
//! Inlining pass for MIR functions
use crate::deref_separator::deref_finder;
use rustc_attr::InlineAttr;
+use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@@ -27,6 +28,8 @@ const RESUME_PENALTY: usize = 45;
const UNKNOWN_SIZE_COST: usize = 10;
+const TOP_DOWN_DEPTH_LIMIT: usize = 5;
+
pub struct Inline;
#[derive(Copy, Clone, Debug)]
@@ -86,8 +89,13 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
let param_env = tcx.param_env_reveal_all_normalized(def_id);
- let mut this =
- Inliner { tcx, param_env, codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), changed: false };
+ let mut this = Inliner {
+ tcx,
+ param_env,
+ codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
+ history: Vec::new(),
+ changed: false,
+ };
let blocks = BasicBlock::new(0)..body.basic_blocks.next_index();
this.process_blocks(body, blocks);
this.changed
@@ -98,12 +106,26 @@ struct Inliner<'tcx> {
param_env: ParamEnv<'tcx>,
/// Caller codegen attributes.
codegen_fn_attrs: &'tcx CodegenFnAttrs,
+ /// Stack of inlined instances.
+ /// We only check the `DefId` and not the substs because we want to
+ /// avoid inlining cases of polymorphic recursion.
+ /// The number of `DefId`s is finite, so checking history is enough
+ /// to ensure that we do not loop endlessly while inlining.
+ history: Vec<DefId>,
/// Indicates that the caller body has been modified.
changed: bool,
}
impl<'tcx> Inliner<'tcx> {
fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBlock>) {
+ // How many callsites in this body are we allowed to inline? We need to limit this in order
+ // to prevent super-linear growth in MIR size
+ let inline_limit = match self.history.len() {
+ 0 => usize::MAX,
+ 1..=TOP_DOWN_DEPTH_LIMIT => 1,
+ _ => return,
+ };
+ let mut inlined_count = 0;
for bb in blocks {
let bb_data = &caller_body[bb];
if bb_data.is_cleanup {
@@ -122,12 +144,16 @@ impl<'tcx> Inliner<'tcx> {
debug!("not-inlined {} [{}]", callsite.callee, reason);
continue;
}
- Ok(_) => {
+ Ok(new_blocks) => {
debug!("inlined {}", callsite.callee);
self.changed = true;
- // We could process the blocks returned by `try_inlining` here. However, that
- // leads to exponential compile times due to the top-down nature of this kind
- // of inlining.
+ inlined_count += 1;
+ if inlined_count == inline_limit {
+ return;
+ }
+ self.history.push(callsite.callee.def_id());
+ self.process_blocks(caller_body, new_blocks);
+ self.history.pop();
}
}
}
@@ -289,7 +315,7 @@ impl<'tcx> Inliner<'tcx> {
) -> Option<CallSite<'tcx>> {
// Only consider direct calls to functions
let terminator = bb_data.terminator();
- if let TerminatorKind::Call { ref func, target, .. } = terminator.kind {
+ if let TerminatorKind::Call { ref func, target, fn_span, .. } = terminator.kind {
let func_ty = func.ty(caller_body, self.tcx);
if let ty::FnDef(def_id, substs) = *func_ty.kind() {
// To resolve an instance its substs have to be fully normalized.
@@ -301,15 +327,14 @@ impl<'tcx> Inliner<'tcx> {
return None;
}
+ if self.history.contains(&callee.def_id()) {
+ return None;
+ }
+
let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
+ let source_info = SourceInfo { span: fn_span, ..terminator.source_info };
- return Some(CallSite {
- callee,
- fn_sig,
- block: bb,
- target,
- source_info: terminator.source_info,
- });
+ return Some(CallSite { callee, fn_sig, block: bb, target, source_info });
}
}
@@ -517,6 +542,21 @@ impl<'tcx> Inliner<'tcx> {
destination
};
+ // Always create a local to hold the destination, as `RETURN_PLACE` may appear
+ // where a full `Place` is not allowed.
+ let (remap_destination, destination_local) = if let Some(d) = dest.as_local() {
+ (false, d)
+ } else {
+ (
+ true,
+ self.new_call_temp(
+ caller_body,
+ &callsite,
+ destination.ty(caller_body, self.tcx).ty,
+ ),
+ )
+ };
+
// Copy the arguments if needed.
let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body);
@@ -535,7 +575,7 @@ impl<'tcx> Inliner<'tcx> {
new_locals: Local::new(caller_body.local_decls.len())..,
new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
new_blocks: BasicBlock::new(caller_body.basic_blocks.len())..,
- destination: dest,
+ destination: destination_local,
callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
callsite,
cleanup_block: cleanup,
@@ -566,6 +606,16 @@ impl<'tcx> Inliner<'tcx> {
// To avoid repeated O(n) insert, push any new statements to the end and rotate
// the slice once.
let mut n = 0;
+ if remap_destination {
+ caller_body[block].statements.push(Statement {
+ source_info: callsite.source_info,
+ kind: StatementKind::Assign(Box::new((
+ dest,
+ Rvalue::Use(Operand::Move(destination_local.into())),
+ ))),
+ });
+ n += 1;
+ }
for local in callee_body.vars_and_temps_iter().rev() {
if !callee_body.local_decls[local].internal
&& integrator.always_live_locals.contains(local)
@@ -849,7 +899,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
};
let kind = match parent_ty.ty.kind() {
- &ty::Opaque(def_id, substs) => {
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
self.tcx.bound_type_of(def_id).subst(self.tcx, substs).kind()
}
kind => kind,
@@ -934,7 +984,7 @@ struct Integrator<'a, 'tcx> {
new_locals: RangeFrom<Local>,
new_scopes: RangeFrom<SourceScope>,
new_blocks: RangeFrom<BasicBlock>,
- destination: Place<'tcx>,
+ destination: Local,
callsite_scope: SourceScopeData<'tcx>,
callsite: &'a CallSite<'tcx>,
cleanup_block: Option<BasicBlock>,
@@ -947,7 +997,7 @@ struct Integrator<'a, 'tcx> {
impl Integrator<'_, '_> {
fn map_local(&self, local: Local) -> Local {
let new = if local == RETURN_PLACE {
- self.destination.local
+ self.destination
} else {
let idx = local.index() - 1;
if idx < self.args.len() {
@@ -1028,27 +1078,6 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
*span = span.fresh_expansion(self.expn_data);
}
- fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
- for elem in place.projection {
- // FIXME: Make sure that return place is not used in an indexing projection, since it
- // won't be rebased as it is supposed to be.
- assert_ne!(ProjectionElem::Index(RETURN_PLACE), elem);
- }
-
- // If this is the `RETURN_PLACE`, we need to rebase any projections onto it.
- let dest_proj_len = self.destination.projection.len();
- if place.local == RETURN_PLACE && dest_proj_len > 0 {
- let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len());
- projs.extend(self.destination.projection);
- projs.extend(place.projection);
-
- place.projection = self.tcx.intern_place_elems(&*projs);
- }
- // Handles integrating any locals that occur in the base
- // or projections
- self.super_place(place, context, location)
- }
-
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
self.in_cleanup_block = data.is_cleanup;
self.super_basic_block_data(block, data);
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 93200b288..20b7fdcfe 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -77,8 +77,6 @@ mod match_branches;
mod multiple_return_terminators;
mod normalize_array_len;
mod nrvo;
-// This pass is public to allow external drivers to perform MIR cleanup
-pub mod remove_false_edges;
mod remove_noop_landing_pads;
mod remove_storage_markers;
mod remove_uninit_drops;
@@ -268,10 +266,7 @@ 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>,
-) -> &'tcx Steal<Body<'tcx>> {
+fn mir_const(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Steal<Body<'_>> {
if let Some(def) = def.try_upgrade(tcx) {
return tcx.mir_const(def);
}
@@ -310,10 +305,10 @@ fn mir_const<'tcx>(
}
/// Compute the main MIR body and the list of MIR bodies of the promoteds.
-fn mir_promoted<'tcx>(
- tcx: TyCtxt<'tcx>,
+fn mir_promoted(
+ tcx: TyCtxt<'_>,
def: ty::WithOptConstParam<LocalDefId>,
-) -> (&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>) {
+) -> (&Steal<Body<'_>>, &Steal<IndexVec<Promoted, Body<'_>>>) {
if let Some(def) = def.try_upgrade(tcx) {
return tcx.mir_promoted(def);
}
@@ -352,7 +347,7 @@ fn mir_promoted<'tcx>(
}
/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it)
-fn mir_for_ctfe<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Body<'tcx> {
+fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> {
let did = def_id.expect_local();
if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
tcx.mir_for_ctfe_of_const_arg(def)
@@ -366,10 +361,7 @@ fn mir_for_ctfe<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Body<'tcx> {
/// we'd get cycle errors with `mir_for_ctfe`, because typeck would need to typeck
/// the const parameter while type checking the main body, which in turn would try
/// to type check the main body again.
-fn mir_for_ctfe_of_const_arg<'tcx>(
- tcx: TyCtxt<'tcx>,
- (did, param_did): (LocalDefId, DefId),
-) -> &'tcx Body<'tcx> {
+fn mir_for_ctfe_of_const_arg(tcx: TyCtxt<'_>, (did, param_did): (LocalDefId, DefId)) -> &Body<'_> {
tcx.arena.alloc(inner_mir_for_ctfe(
tcx,
ty::WithOptConstParam { did, const_param_did: Some(param_did) },
@@ -426,10 +418,10 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs
/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't
/// end up missing the source MIR due to stealing happening.
-fn mir_drops_elaborated_and_const_checked<'tcx>(
- tcx: TyCtxt<'tcx>,
+fn mir_drops_elaborated_and_const_checked(
+ tcx: TyCtxt<'_>,
def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx Steal<Body<'tcx>> {
+) -> &Steal<Body<'_>> {
if let Some(def) = def.try_upgrade(tcx) {
return tcx.mir_drops_elaborated_and_const_checked(def);
}
@@ -494,10 +486,8 @@ fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>
/// 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"),
+ &cleanup_post_borrowck::CleanupPostBorrowck,
&remove_noop_landing_pads::RemoveNoopLandingPads,
- &cleanup_post_borrowck::CleanupNonCodegenStatements,
&simplify::SimplifyCfg::new("early-opt"),
&deref_separator::Derefer,
];
@@ -533,11 +523,8 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
/// 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"),
- ];
+ let passes: &[&dyn MirPass<'tcx>] =
+ &[&lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops")];
pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup)));
}
@@ -569,6 +556,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&multiple_return_terminators::MultipleReturnTerminators,
&instcombine::InstCombine,
&separate_const_switch::SeparateConstSwitch,
+ &simplify::SimplifyLocals::new("before-const-prop"),
//
// FIXME(#70073): This pass is responsible for both optimization as well as some lints.
&const_prop::ConstProp,
@@ -587,7 +575,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&o1(remove_noop_landing_pads::RemoveNoopLandingPads),
&o1(simplify::SimplifyCfg::new("final")),
&nrvo::RenameReturnPlace,
- &simplify::SimplifyLocals,
+ &simplify::SimplifyLocals::new("final"),
&multiple_return_terminators::MultipleReturnTerminators,
&deduplicate_blocks::DeduplicateBlocks,
// Some cleanup necessary at least for LLVM and potentially other codegen backends.
@@ -600,7 +588,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
}
/// Optimize the MIR and prepare it for codegen.
-fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> {
+fn optimized_mir(tcx: TyCtxt<'_>, did: DefId) -> &Body<'_> {
let did = did.expect_local();
assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None);
tcx.arena.alloc(inner_optimized_mir(tcx, did))
@@ -637,10 +625,10 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
/// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for
/// constant evaluation once all substitutions become known.
-fn promoted_mir<'tcx>(
- tcx: TyCtxt<'tcx>,
+fn promoted_mir(
+ tcx: TyCtxt<'_>,
def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
+) -> &IndexVec<Promoted, Body<'_>> {
if tcx.is_constructor(def.did.to_def_id()) {
return tcx.arena.alloc(IndexVec::new());
}
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index a0ba69c89..ce05db5b7 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -55,10 +55,9 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
continue;
}
- let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind {
+ let (discr, val, first, second) = match bbs[bb_idx].terminator().kind {
TerminatorKind::SwitchInt {
discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)),
- switch_ty,
ref targets,
..
} if targets.iter().len() == 1 => {
@@ -66,7 +65,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
if target == targets.otherwise() {
continue;
}
- (discr, value, switch_ty, target, targets.otherwise())
+ (discr, value, target, targets.otherwise())
}
// Only optimize switch int statements
_ => continue,
@@ -105,10 +104,11 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
}
// Take ownership of items now that we know we can optimize.
let discr = discr.clone();
+ let discr_ty = discr.ty(&body.local_decls, tcx);
// Introduce a temporary for the discriminant value.
let source_info = bbs[bb_idx].terminator().source_info;
- let discr_local = body.local_decls.push(LocalDecl::new(switch_ty, source_info.span));
+ let discr_local = body.local_decls.push(LocalDecl::new(discr_ty, source_info.span));
// We already checked that first and second are different blocks,
// and bb_idx has a different terminator from both of them.
@@ -130,10 +130,10 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
(*f).clone()
} else {
// Different value between blocks. Make value conditional on switch condition.
- let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
+ let size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size;
let const_cmp = Operand::const_from_scalar(
tcx,
- switch_ty,
+ discr_ty,
rustc_const_eval::interpret::Scalar::from_uint(val, size),
rustc_span::DUMMY_SP,
);
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index a159e6171..1708b287e 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -16,7 +16,8 @@ pub struct NormalizeArrayLen;
impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
- sess.mir_opt_level() >= 4
+ // See #105929
+ sess.mir_opt_level() >= 4 && sess.opts.unstable_opts.unsound_mir_opts
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
diff --git a/compiler/rustc_mir_transform/src/remove_false_edges.rs b/compiler/rustc_mir_transform/src/remove_false_edges.rs
deleted file mode 100644
index 71f5ccf7e..000000000
--- a/compiler/rustc_mir_transform/src/remove_false_edges.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-use rustc_middle::mir::{Body, TerminatorKind};
-use rustc_middle::ty::TyCtxt;
-
-use crate::MirPass;
-
-/// Removes `FalseEdge` and `FalseUnwind` terminators from the MIR.
-///
-/// These are only needed for borrow checking, and can be removed afterwards.
-///
-/// FIXME: This should probably have its own MIR phase.
-pub struct RemoveFalseEdges;
-
-impl<'tcx> MirPass<'tcx> for RemoveFalseEdges {
- fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- for block in body.basic_blocks_mut() {
- let terminator = block.terminator_mut();
- terminator.kind = match terminator.kind {
- TerminatorKind::FalseEdge { real_target, .. } => {
- TerminatorKind::Goto { target: real_target }
- }
- TerminatorKind::FalseUnwind { real_target, .. } => {
- TerminatorKind::Goto { target: real_target }
- }
-
- _ => continue,
- }
- }
- }
-}
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index 569e783fe..6cabef92d 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -52,7 +52,11 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts {
fn maybe_zst(ty: Ty<'_>) -> bool {
match ty.kind() {
// maybe ZST (could be more precise)
- ty::Adt(..) | ty::Array(..) | ty::Closure(..) | ty::Tuple(..) | ty::Opaque(..) => true,
+ ty::Adt(..)
+ | ty::Array(..)
+ | ty::Closure(..)
+ | ty::Tuple(..)
+ | ty::Alias(ty::Opaque, ..) => true,
// definitely ZST
ty::FnDef(..) | ty::Never => true,
// unreachable or can't be ZST
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 16b7dcad1..dace540fa 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -174,9 +174,36 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
let mut body =
new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
+ // The first argument (index 0), but add 1 for the return value.
+ let mut dropee_ptr = Place::from(Local::new(1 + 0));
+ if tcx.sess.opts.unstable_opts.mir_emit_retag {
+ // We want to treat the function argument as if it was passed by `&mut`. As such, we
+ // generate
+ // ```
+ // temp = &mut *arg;
+ // Retag(temp, FnEntry)
+ // ```
+ // It's important that we do this first, before anything that depends on `dropee_ptr`
+ // has been put into the body.
+ let reborrow = Rvalue::Ref(
+ tcx.lifetimes.re_erased,
+ BorrowKind::Mut { allow_two_phase_borrow: false },
+ tcx.mk_place_deref(dropee_ptr),
+ );
+ let ref_ty = reborrow.ty(body.local_decls(), tcx);
+ dropee_ptr = body.local_decls.push(LocalDecl::new(ref_ty, span)).into();
+ let new_statements = [
+ StatementKind::Assign(Box::new((dropee_ptr, reborrow))),
+ StatementKind::Retag(RetagKind::FnEntry, Box::new(dropee_ptr)),
+ ];
+ for s in new_statements {
+ body.basic_blocks_mut()[START_BLOCK]
+ .statements
+ .push(Statement { source_info, kind: s });
+ }
+ }
+
if ty.is_some() {
- // The first argument (index 0), but add 1 for the return value.
- let dropee_ptr = Place::from(Local::new(1 + 0));
let patch = {
let param_env = tcx.param_env_reveal_all_normalized(def_id);
let mut elaborator =
@@ -336,8 +363,7 @@ impl<'tcx> CloneShimBuilder<'tcx> {
// we must subst the self_ty because it's
// otherwise going to be TySelf and we can't index
// or access fields of a Place of type TySelf.
- let substs = tcx.mk_substs_trait(self_ty, []);
- let sig = tcx.bound_fn_sig(def_id).subst(tcx, substs);
+ let sig = tcx.bound_fn_sig(def_id).subst(tcx, &[self_ty.into()]);
let sig = tcx.erase_late_bound_regions(sig);
let span = tcx.def_span(def_id);
@@ -417,10 +443,8 @@ impl<'tcx> CloneShimBuilder<'tcx> {
) {
let tcx = self.tcx;
- let substs = tcx.mk_substs_trait(ty, []);
-
// `func == Clone::clone(&ty) -> ty`
- let func_ty = tcx.mk_fn_def(self.def_id, substs);
+ let func_ty = tcx.mk_fn_def(self.def_id, [ty]);
let func = Operand::Constant(Box::new(Constant {
span: self.span,
user_ty: None,
@@ -548,7 +572,6 @@ impl<'tcx> CloneShimBuilder<'tcx> {
statements.push(statement);
*kind = TerminatorKind::SwitchInt {
discr: Operand::Move(temp),
- switch_ty: discr_ty,
targets: SwitchTargets::new(cases.into_iter(), unreachable),
};
}
@@ -576,9 +599,8 @@ fn build_call_shim<'tcx>(
// Create substitutions for the `Self` and `Args` generic parameters of the shim body.
let arg_tup = tcx.mk_tup(untuple_args.iter());
- let sig_substs = tcx.mk_substs_trait(ty, [ty::subst::GenericArg::from(arg_tup)]);
- (Some(sig_substs), Some(untuple_args))
+ (Some([ty.into(), arg_tup.into()]), Some(untuple_args))
} else {
(None, None)
};
@@ -589,7 +611,7 @@ fn build_call_shim<'tcx>(
assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body());
let mut sig =
- if let Some(sig_substs) = sig_substs { sig.subst(tcx, sig_substs) } else { sig.0 };
+ if let Some(sig_substs) = sig_substs { sig.subst(tcx, &sig_substs) } else { sig.0 };
if let CallKind::Indirect(fnty) = call_kind {
// `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 475e2ec9a..8f6abe7a9 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -35,7 +35,6 @@ use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Vis
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use smallvec::SmallVec;
-use std::convert::TryInto;
pub struct SimplifyCfg {
label: String,
@@ -380,9 +379,21 @@ fn save_unreachable_coverage(
));
}
-pub struct SimplifyLocals;
+pub struct SimplifyLocals {
+ label: String,
+}
+
+impl SimplifyLocals {
+ pub fn new(label: &str) -> SimplifyLocals {
+ SimplifyLocals { label: format!("SimplifyLocals-{}", label) }
+ }
+}
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
+ fn name(&self) -> &str {
+ &self.label
+ }
+
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
@@ -558,6 +569,7 @@ fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>)
StatementKind::SetDiscriminant { ref place, .. }
| StatementKind::Deinit(ref place) => used_locals.is_used(place.local),
+ StatementKind::Nop => false,
_ => true,
};
diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs
index 405ebce4d..8164b3052 100644
--- a/compiler/rustc_mir_transform/src/simplify_branches.rs
+++ b/compiler/rustc_mir_transform/src/simplify_branches.rs
@@ -24,12 +24,9 @@ impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
let terminator = block.terminator_mut();
terminator.kind = match terminator.kind {
TerminatorKind::SwitchInt {
- discr: Operand::Constant(ref c),
- switch_ty,
- ref targets,
- ..
+ discr: Operand::Constant(ref c), ref targets, ..
} => {
- let constant = c.literal.try_eval_bits(tcx, param_env, switch_ty);
+ let constant = c.literal.try_eval_bits(tcx, param_env, c.ty());
if let Some(constant) = constant {
let target = targets.target_for_value(constant);
TerminatorKind::Goto { target }
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index 321d8c63b..dcad1518e 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -127,11 +127,8 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
let targets = SwitchTargets::new(iter::once((new_value, bb_cond)), bb_otherwise);
let terminator = bb.terminator_mut();
- terminator.kind = TerminatorKind::SwitchInt {
- discr: Operand::Move(opt.to_switch_on),
- switch_ty: opt.branch_value_ty,
- targets,
- };
+ terminator.kind =
+ TerminatorKind::SwitchInt { discr: Operand::Move(opt.to_switch_on), targets };
}
for (idx, bb_idx) in storage_deads_to_remove {
diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs
index baeb620ef..e4f3ace9a 100644
--- a/compiler/rustc_mir_transform/src/simplify_try.rs
+++ b/compiler/rustc_mir_transform/src/simplify_try.rs
@@ -532,7 +532,7 @@ struct VarField<'tcx> {
}
/// Match on `((_LOCAL as Variant).FIELD: TY)`.
-fn match_variant_field_place<'tcx>(place: Place<'tcx>) -> Option<(Local, VarField<'tcx>)> {
+fn match_variant_field_place(place: Place<'_>) -> Option<(Local, VarField<'_>)> {
match place.as_ref() {
PlaceRef {
local,
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 558a372fb..42124f5a4 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -182,7 +182,7 @@ fn replace_flattened_locals<'tcx>(
let mut fragments = IndexVec::new();
for (k, v) in &replacements.fields {
fragments.ensure_contains_elem(k.local, || Vec::new());
- fragments[k.local].push((&k.projection[..], *v));
+ fragments[k.local].push((k.projection, *v));
}
debug!(?fragments);
@@ -215,7 +215,7 @@ struct ReplacementVisitor<'tcx, 'll> {
replacements: ReplacementMap<'tcx>,
/// This is used to check that we are not leaving references to replaced locals behind.
all_dead_locals: BitSet<Local>,
- /// Pre-computed list of all "new" locals for each "old" local. This is used to expand storage
+ /// Pre-computed list of all "new" locals for each "old" local. This is used to expand storage
/// and deinit statement and debuginfo.
fragments: IndexVec<Local, Vec<(&'tcx [PlaceElem<'tcx>], Local)>>,
}
diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs
index 95fda2eaf..d4b1cfe43 100644
--- a/compiler/rustc_mir_transform/src/unreachable_prop.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs
@@ -76,7 +76,7 @@ where
let terminator = match terminator_kind {
// This will unconditionally run into an unreachable and is therefore unreachable as well.
TerminatorKind::Goto { target } if is_unreachable(*target) => TerminatorKind::Unreachable,
- TerminatorKind::SwitchInt { targets, discr, switch_ty } => {
+ TerminatorKind::SwitchInt { targets, discr } => {
let otherwise = targets.otherwise();
// If all targets are unreachable, we can be unreachable as well.
@@ -87,7 +87,7 @@ where
// unless otherwise is unreachable, in which case deleting a normal branch causes it to be merged with
// the otherwise, keeping its unreachable.
// This looses information about reachability causing worse codegen.
- // For example (see src/test/codegen/match-optimizes-away.rs)
+ // For example (see tests/codegen/match-optimizes-away.rs)
//
// pub enum Two { A, B }
// pub fn identity(x: Two) -> Two {
@@ -110,11 +110,7 @@ where
return None;
}
- TerminatorKind::SwitchInt {
- discr: discr.clone(),
- switch_ty: *switch_ty,
- targets: new_targets,
- }
+ TerminatorKind::SwitchInt { discr: discr.clone(), targets: new_targets }
} else {
// If the otherwise branch is reachable, we don't want to delete any unreachable branches.
return None;