mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 01:04:03 +00:00
Give match arms a drop/region scope
Also give arms the correct lint scope in MIR.
This commit is contained in:
parent
af6a9a2c62
commit
f506aea1fa
@ -419,7 +419,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||
for arm in arms {
|
||||
// Add an exit node for when we've visited all the
|
||||
// patterns and the guard (if there is one) in the arm.
|
||||
let arm_exit = self.add_dummy_node(&[]);
|
||||
let bindings_exit = self.add_dummy_node(&[]);
|
||||
|
||||
for pat in &arm.pats {
|
||||
// Visit the pattern, coming from the discriminant exit
|
||||
@ -453,14 +453,16 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||
|
||||
// Add an edge from the exit of this pattern to the
|
||||
// exit of the arm
|
||||
self.add_contained_edge(pat_exit, arm_exit);
|
||||
self.add_contained_edge(pat_exit, bindings_exit);
|
||||
}
|
||||
|
||||
// Visit the body of this arm
|
||||
let body_exit = self.expr(&arm.body, arm_exit);
|
||||
let body_exit = self.expr(&arm.body, bindings_exit);
|
||||
|
||||
let arm_exit = self.add_ast_node(arm.hir_id.local_id, &[body_exit]);
|
||||
|
||||
// Link the body to the exit of the expression
|
||||
self.add_contained_edge(body_exit, expr_exit);
|
||||
self.add_contained_edge(arm_exit, expr_exit);
|
||||
}
|
||||
|
||||
expr_exit
|
||||
|
@ -119,18 +119,18 @@ impl fmt::Debug for Scope {
|
||||
pub enum ScopeData {
|
||||
Node,
|
||||
|
||||
// Scope of the call-site for a function or closure
|
||||
// (outlives the arguments as well as the body).
|
||||
/// Scope of the call-site for a function or closure
|
||||
/// (outlives the arguments as well as the body).
|
||||
CallSite,
|
||||
|
||||
// Scope of arguments passed to a function or closure
|
||||
// (they outlive its body).
|
||||
/// Scope of arguments passed to a function or closure
|
||||
/// (they outlive its body).
|
||||
Arguments,
|
||||
|
||||
// Scope of destructors for temporaries of node-id.
|
||||
/// Scope of destructors for temporaries of node-id.
|
||||
Destruction,
|
||||
|
||||
// Scope following a `let id = expr;` binding in a block.
|
||||
/// Scope following a `let id = expr;` binding in a block.
|
||||
Remainder(FirstStatementIndex)
|
||||
}
|
||||
|
||||
@ -152,11 +152,11 @@ newtype_index! {
|
||||
///
|
||||
/// * The subscope with `first_statement_index == 1` is scope of `c`,
|
||||
/// and thus does not include EXPR_2, but covers the `...`.
|
||||
pub struct FirstStatementIndex { .. }
|
||||
pub struct FirstStatementIndex {
|
||||
derive [HashStable]
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct crate::middle::region::FirstStatementIndex { private });
|
||||
|
||||
// compilation error if size of `ScopeData` is not the same as a `u32`
|
||||
static_assert_size!(ScopeData, 4);
|
||||
|
||||
@ -814,6 +814,16 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
|
||||
}
|
||||
|
||||
fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &'tcx hir::Arm) {
|
||||
let prev_cx = visitor.cx;
|
||||
|
||||
visitor.enter_scope(
|
||||
Scope {
|
||||
id: arm.hir_id.local_id,
|
||||
data: ScopeData::Node,
|
||||
}
|
||||
);
|
||||
visitor.cx.var_parent = visitor.cx.parent;
|
||||
|
||||
visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
|
||||
|
||||
if let Some(hir::Guard::If(ref expr)) = arm.guard {
|
||||
@ -821,6 +831,8 @@ fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &
|
||||
}
|
||||
|
||||
intravisit::walk_arm(visitor, arm);
|
||||
|
||||
visitor.cx = prev_cx;
|
||||
}
|
||||
|
||||
fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &'tcx hir::Pat) {
|
||||
@ -893,10 +905,6 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
|
||||
terminating(body.hir_id.local_id);
|
||||
}
|
||||
|
||||
hir::ExprKind::Match(..) => {
|
||||
visitor.cx.var_parent = visitor.cx.parent;
|
||||
}
|
||||
|
||||
hir::ExprKind::DropTemps(ref expr) => {
|
||||
// `DropTemps(expr)` does not denote a conditional scope.
|
||||
// Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`.
|
||||
|
@ -12,6 +12,7 @@ use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
|
||||
use crate::hair::{self, *};
|
||||
use rustc::hir::HirId;
|
||||
use rustc::mir::*;
|
||||
use rustc::middle::region;
|
||||
use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty};
|
||||
use rustc::ty::layout::VariantIdx;
|
||||
use rustc_data_structures::bit_set::BitSet;
|
||||
@ -251,37 +252,39 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
|
||||
// Step 5. Create everything else: the guards and the arms.
|
||||
|
||||
let outer_source_info = self.source_info(span);
|
||||
let arm_end_blocks: Vec<_> = arm_candidates.into_iter().map(|(arm, candidates)| {
|
||||
let mut arm_block = self.cfg.start_new_block();
|
||||
let arm_source_info = self.source_info(arm.span);
|
||||
let region_scope = (arm.scope, arm_source_info);
|
||||
self.in_scope(region_scope, arm.lint_level, |this| {
|
||||
let arm_block = this.cfg.start_new_block();
|
||||
|
||||
let body = self.hir.mirror(arm.body.clone());
|
||||
let scope = self.declare_bindings(
|
||||
None,
|
||||
body.span,
|
||||
&arm.patterns[0],
|
||||
ArmHasGuard(arm.guard.is_some()),
|
||||
Some((Some(&scrutinee_place), scrutinee_span)),
|
||||
);
|
||||
|
||||
if let Some(source_scope) = scope {
|
||||
this.source_scope = source_scope;
|
||||
}
|
||||
|
||||
for candidate in candidates {
|
||||
self.bind_and_guard_matched_candidate(
|
||||
candidate,
|
||||
arm.guard.clone(),
|
||||
arm_block,
|
||||
&fake_borrow_temps,
|
||||
scrutinee_span,
|
||||
let body = this.hir.mirror(arm.body.clone());
|
||||
let scope = this.declare_bindings(
|
||||
None,
|
||||
arm.span,
|
||||
&arm.patterns[0],
|
||||
ArmHasGuard(arm.guard.is_some()),
|
||||
Some((Some(&scrutinee_place), scrutinee_span)),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(source_scope) = scope {
|
||||
this.source_scope = source_scope;
|
||||
}
|
||||
|
||||
unpack!(arm_block = self.into(destination, arm_block, body));
|
||||
for candidate in candidates {
|
||||
this.clear_top_scope(arm.scope);
|
||||
this.bind_and_guard_matched_candidate(
|
||||
candidate,
|
||||
arm.guard.clone(),
|
||||
arm_block,
|
||||
&fake_borrow_temps,
|
||||
scrutinee_span,
|
||||
region_scope,
|
||||
);
|
||||
}
|
||||
|
||||
arm_block
|
||||
this.into(destination, arm_block, body)
|
||||
})
|
||||
}).collect();
|
||||
|
||||
// all the arm blocks will rejoin here
|
||||
@ -289,7 +292,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
|
||||
for arm_block in arm_end_blocks {
|
||||
self.cfg.terminate(
|
||||
arm_block,
|
||||
unpack!(arm_block),
|
||||
outer_source_info,
|
||||
TerminatorKind::Goto { target: end_block },
|
||||
);
|
||||
@ -502,7 +505,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
visibility_scope =
|
||||
Some(this.new_source_scope(scope_span, LintLevel::Inherited, None));
|
||||
}
|
||||
let source_info = SourceInfo { span, this.source_scope };
|
||||
let source_info = SourceInfo { span, scope: this.source_scope };
|
||||
let visibility_scope = visibility_scope.unwrap();
|
||||
this.declare_binding(
|
||||
source_info,
|
||||
@ -1315,6 +1318,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
arm_block: BasicBlock,
|
||||
fake_borrows: &Vec<(&Place<'tcx>, Local)>,
|
||||
scrutinee_span: Span,
|
||||
region_scope: (region::Scope, SourceInfo),
|
||||
) {
|
||||
debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
|
||||
|
||||
@ -1497,17 +1501,40 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
//
|
||||
// and that is clearly not correct.
|
||||
let post_guard_block = self.cfg.start_new_block();
|
||||
let otherwise_post_guard_block = self.cfg.start_new_block();
|
||||
self.cfg.terminate(
|
||||
block,
|
||||
source_info,
|
||||
TerminatorKind::if_(
|
||||
self.hir.tcx(),
|
||||
cond,
|
||||
cond.clone(),
|
||||
post_guard_block,
|
||||
candidate.otherwise_block.unwrap()
|
||||
otherwise_post_guard_block,
|
||||
),
|
||||
);
|
||||
|
||||
self.exit_scope(
|
||||
source_info.span,
|
||||
region_scope,
|
||||
otherwise_post_guard_block,
|
||||
candidate.otherwise_block.unwrap(),
|
||||
);
|
||||
|
||||
if let Operand::Copy(cond_place) | Operand::Move(cond_place) = cond {
|
||||
if let Place::Base(PlaceBase::Local(cond_temp)) = cond_place {
|
||||
// We will call `clear_top_scope` if there's another guard. So
|
||||
// we have to drop this variable now or it will be "storage
|
||||
// leaked".
|
||||
self.pop_variable(
|
||||
post_guard_block,
|
||||
region_scope.0,
|
||||
cond_temp
|
||||
);
|
||||
} else {
|
||||
bug!("Expected as_local_operand to produce a temporary");
|
||||
}
|
||||
}
|
||||
|
||||
let by_value_bindings = candidate.bindings.iter().filter(|binding| {
|
||||
if let BindingMode::ByValue = binding.binding_mode { true } else { false }
|
||||
});
|
||||
|
@ -19,13 +19,18 @@ paragraph). This is because region scopes are tied to
|
||||
them. Eventually, when we shift to non-lexical lifetimes, there should
|
||||
be no need to remember this mapping.
|
||||
|
||||
There is one additional wrinkle, actually, that I wanted to hide from
|
||||
you but duty compels me to mention. In the course of building
|
||||
matches, it sometimes happen that certain code (namely guards) gets
|
||||
executed multiple times. This means that the scope lexical scope may
|
||||
in fact correspond to multiple, disjoint SEME regions. So in fact our
|
||||
### Not so SEME Regions
|
||||
|
||||
In the course of building matches, it sometimes happens that certain code
|
||||
(namely guards) gets executed multiple times. This means that the scope lexical
|
||||
scope may in fact correspond to multiple, disjoint SEME regions. So in fact our
|
||||
mapping is from one scope to a vector of SEME regions.
|
||||
|
||||
Also in matches, the scopes assigned to arms are not even SEME regions! Each
|
||||
arm has a single region with one entry for each pattern. We manually
|
||||
manipulate the scheduled drops in this scope to avoid dropping things multiple
|
||||
times, although drop elaboration would clean this up for value drops.
|
||||
|
||||
### Drops
|
||||
|
||||
The primary purpose for scopes is to insert drops: while building
|
||||
@ -731,7 +736,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
// Note that this code iterates scopes from the inner-most to the outer-most,
|
||||
// invalidating caches of each scope visited. This way bare minimum of the
|
||||
// caches gets invalidated. i.e., if a new drop is added into the middle scope, the
|
||||
// cache of outer scpoe stays intact.
|
||||
// cache of outer scope stays intact.
|
||||
scope.invalidate_cache(!needs_drop, this_scope);
|
||||
if this_scope {
|
||||
if let DropKind::Value { .. } = drop_kind {
|
||||
@ -873,6 +878,73 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
|
||||
success_block
|
||||
}
|
||||
|
||||
// `match` arm scopes
|
||||
// ==================
|
||||
/// Unschedules any drops in the top scope.
|
||||
///
|
||||
/// This is only needed for `match` arm scopes, because they have one
|
||||
/// entrance per pattern, but only one exit.
|
||||
pub fn clear_top_scope(&mut self, region_scope: region::Scope) {
|
||||
let top_scope = self.scopes.last_mut().unwrap();
|
||||
|
||||
assert_eq!(top_scope.region_scope, region_scope);
|
||||
|
||||
top_scope.drops.clear();
|
||||
top_scope.invalidate_cache(false, true);
|
||||
}
|
||||
|
||||
/// Drops the single variable provided
|
||||
///
|
||||
/// * The scope must be the top scope.
|
||||
/// * The variable must be in that scope.
|
||||
/// * The variable must be at the top of that scope: it's the next thing
|
||||
/// scheduled to drop.
|
||||
/// * The drop must be of DropKind::Storage.
|
||||
///
|
||||
/// This is used for the boolean holding the result of the match guard. We
|
||||
/// do this because:
|
||||
///
|
||||
/// * The boolean is different for each pattern
|
||||
/// * There is only one exit for the arm scope
|
||||
/// * The guard expression scope is too short, it ends just before the
|
||||
/// boolean is tested.
|
||||
pub fn pop_variable(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
region_scope: region::Scope,
|
||||
variable: Local,
|
||||
) {
|
||||
let top_scope = self.scopes.last_mut().unwrap();
|
||||
|
||||
assert_eq!(top_scope.region_scope, region_scope);
|
||||
|
||||
let top_drop_data = top_scope.drops.pop().unwrap();
|
||||
|
||||
match top_drop_data.kind {
|
||||
DropKind::Value { .. } => {
|
||||
bug!("Should not be calling pop_top_variable on non-copy type!")
|
||||
}
|
||||
DropKind::Storage => {
|
||||
// Drop the storage for both value and storage drops.
|
||||
// Only temps and vars need their storage dead.
|
||||
match top_drop_data.location {
|
||||
Place::Base(PlaceBase::Local(index)) => {
|
||||
let source_info = top_scope.source_info(top_drop_data.span);
|
||||
assert_eq!(index, variable);
|
||||
self.cfg.push(block, Statement {
|
||||
source_info,
|
||||
kind: StatementKind::StorageDead(index)
|
||||
});
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
top_scope.invalidate_cache(true, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Builds drops for pop_scope and exit_scope.
|
||||
|
@ -879,8 +879,12 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm)
|
||||
_ => None,
|
||||
},
|
||||
body: arm.body.to_ref(),
|
||||
// BUG: fix this
|
||||
lint_level: LintLevel::Inherited,
|
||||
lint_level: LintLevel::Explicit(arm.hir_id),
|
||||
scope: region::Scope {
|
||||
id: arm.hir_id.local_id,
|
||||
data: region::ScopeData::Node
|
||||
},
|
||||
span: arm.span,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,13 +45,13 @@ fn main() {
|
||||
// _2 = std::option::Option::<i32>::Some(const 42i32,);
|
||||
// FakeRead(ForMatchedPlace, _2);
|
||||
// _3 = discriminant(_2);
|
||||
// switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb7];
|
||||
// switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb6];
|
||||
// }
|
||||
// bb1 (cleanup): {
|
||||
// resume;
|
||||
// }
|
||||
// bb2: {
|
||||
// falseEdges -> [real: bb8, imaginary: bb3]; //pre_binding1
|
||||
// falseEdges -> [real: bb7, imaginary: bb3]; //pre_binding1
|
||||
// }
|
||||
// bb3: {
|
||||
// falseEdges -> [real: bb11, imaginary: bb4]; //pre_binding2
|
||||
@ -62,48 +62,56 @@ fn main() {
|
||||
// bb5: {
|
||||
// unreachable;
|
||||
// }
|
||||
// bb6: { // to pre_binding2
|
||||
// falseEdges -> [real: bb3, imaginary: bb3];
|
||||
// }
|
||||
// bb7: {
|
||||
// bb6: {
|
||||
// unreachable;
|
||||
// }
|
||||
// bb8: { // binding1 and guard
|
||||
// bb7: { // binding1 and guard
|
||||
// StorageLive(_6);
|
||||
// _6 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
|
||||
// _4 = &shallow _2;
|
||||
// StorageLive(_7);
|
||||
// _7 = const guard() -> [return: bb9, unwind: bb1];
|
||||
// _7 = const guard() -> [return: bb8, unwind: bb1];
|
||||
// }
|
||||
// bb9: {
|
||||
// bb8: { // end of guard
|
||||
// FakeRead(ForMatchGuard, _4);
|
||||
// FakeRead(ForGuardBinding, _6);
|
||||
// switchInt(move _7) -> [false: bb6, otherwise: bb10];
|
||||
// switchInt(move _7) -> [false: bb10, otherwise: bb9];
|
||||
// }
|
||||
// bb10: {
|
||||
// bb9: { // arm1
|
||||
// StorageDead(_7);
|
||||
// StorageLive(_5);
|
||||
// _5 = ((_2 as Some).0: i32);
|
||||
// StorageLive(_8);
|
||||
// _8 = _5;
|
||||
// _1 = (const 1i32, move _8);
|
||||
// StorageDead(_8);
|
||||
// StorageDead(_5);
|
||||
// StorageDead(_6);
|
||||
// goto -> bb13;
|
||||
// }
|
||||
// bb11: {
|
||||
// bb10: { // to pre_binding2
|
||||
// StorageDead(_7);
|
||||
// StorageDead(_6);
|
||||
// falseEdges -> [real: bb3, imaginary: bb3];
|
||||
// }
|
||||
// bb11: { // arm2
|
||||
// StorageLive(_9);
|
||||
// _9 = ((_2 as Some).0: i32);
|
||||
// StorageLive(_10);
|
||||
// _10 = _9;
|
||||
// _1 = (const 2i32, move _10);
|
||||
// StorageDead(_10);
|
||||
// StorageDead(_9);
|
||||
// goto -> bb13;
|
||||
// }
|
||||
// bb12: {
|
||||
// bb12: { // arm3
|
||||
// _1 = (const 3i32, const 3i32);
|
||||
// goto -> bb13;
|
||||
// }
|
||||
// bb13: {
|
||||
// ...
|
||||
// StorageDead(_1);
|
||||
// StorageDead(_2);
|
||||
// _0 = ();
|
||||
// return;
|
||||
// }
|
||||
// END rustc.full_tested_match.QualifyAndPromoteConstants.after.mir
|
||||
@ -114,13 +122,13 @@ fn main() {
|
||||
// _2 = std::option::Option::<i32>::Some(const 42i32,);
|
||||
// FakeRead(ForMatchedPlace, _2);
|
||||
// _3 = discriminant(_2);
|
||||
// switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb7];
|
||||
// switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb6];
|
||||
// }
|
||||
// bb1 (cleanup): {
|
||||
// resume;
|
||||
// }
|
||||
// bb2: {
|
||||
// falseEdges -> [real: bb8, imaginary: bb3];
|
||||
// falseEdges -> [real: bb7, imaginary: bb3];
|
||||
// }
|
||||
// bb3: {
|
||||
// falseEdges -> [real: bb11, imaginary: bb4];
|
||||
@ -131,33 +139,38 @@ fn main() {
|
||||
// bb5: {
|
||||
// unreachable;
|
||||
// }
|
||||
// bb6: { // to pre_binding3 (can skip 2 since this is `Some`)
|
||||
// falseEdges -> [real: bb4, imaginary: bb3];
|
||||
// }
|
||||
// bb7: {
|
||||
// bb6: {
|
||||
// unreachable;
|
||||
// }
|
||||
// bb8: { // binding1 and guard
|
||||
// bb7: { // binding1 and guard
|
||||
// StorageLive(_6);
|
||||
// _6 = &((_2 as Some).0: i32);
|
||||
// _4 = &shallow _2;
|
||||
// StorageLive(_7);
|
||||
// _7 = const guard() -> [return: bb9, unwind: bb1];
|
||||
// _7 = const guard() -> [return: bb8, unwind: bb1];
|
||||
// }
|
||||
// bb9: { // end of guard
|
||||
// bb8: { // end of guard
|
||||
// FakeRead(ForMatchGuard, _4);
|
||||
// FakeRead(ForGuardBinding, _6);
|
||||
// switchInt(move _7) -> [false: bb6, otherwise: bb10];
|
||||
// switchInt(move _7) -> [false: bb10, otherwise: bb9];
|
||||
// }
|
||||
// bb10: { // arm1
|
||||
// bb9: { // arm1
|
||||
// StorageDead(_7);
|
||||
// StorageLive(_5);
|
||||
// _5 = ((_2 as Some).0: i32);
|
||||
// StorageLive(_8);
|
||||
// _8 = _5;
|
||||
// _1 = (const 1i32, move _8);
|
||||
// StorageDead(_8);
|
||||
// StorageDead(_5);
|
||||
// StorageDead(_6);
|
||||
// goto -> bb13;
|
||||
// }
|
||||
// bb10: { // to pre_binding3 (can skip 2 since this is `Some`)
|
||||
// StorageDead(_7);
|
||||
// StorageDead(_6);
|
||||
// falseEdges -> [real: bb4, imaginary: bb3];
|
||||
// }
|
||||
// bb11: { // arm2
|
||||
// _1 = (const 3i32, const 3i32);
|
||||
// goto -> bb13;
|
||||
@ -169,16 +182,19 @@ fn main() {
|
||||
// _10 = _9;
|
||||
// _1 = (const 2i32, move _10);
|
||||
// StorageDead(_10);
|
||||
// StorageDead(_9);
|
||||
// goto -> bb13;
|
||||
// }
|
||||
// bb13: {
|
||||
// ...
|
||||
// StorageDead(_1);
|
||||
// StorageDead(_2);
|
||||
// _0 = ();
|
||||
// return;
|
||||
// }
|
||||
// END rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
|
||||
//
|
||||
// START rustc.main.QualifyAndPromoteConstants.before.mir
|
||||
// bb0: {
|
||||
// bb0: {
|
||||
// ...
|
||||
// _2 = std::option::Option::<i32>::Some(const 1i32,);
|
||||
// FakeRead(ForMatchedPlace, _2);
|
||||
@ -189,13 +205,13 @@ fn main() {
|
||||
// resume;
|
||||
// }
|
||||
// bb2: {
|
||||
// falseEdges -> [real: bb9, imaginary: bb3];
|
||||
// falseEdges -> [real: bb7, imaginary: bb3];
|
||||
// }
|
||||
// bb3: {
|
||||
// falseEdges -> [real: bb12, imaginary: bb4];
|
||||
// falseEdges -> [real: bb11, imaginary: bb4];
|
||||
// }
|
||||
// bb4: {
|
||||
// falseEdges -> [real: bb13, imaginary: bb5];
|
||||
// falseEdges -> [real: bb12, imaginary: bb5];
|
||||
// }
|
||||
// bb5: {
|
||||
// falseEdges -> [real: bb16, imaginary: bb6];
|
||||
@ -203,65 +219,79 @@ fn main() {
|
||||
// bb6: {
|
||||
// unreachable;
|
||||
// }
|
||||
// bb7: {
|
||||
// falseEdges -> [real: bb3, imaginary: bb3];
|
||||
// }
|
||||
// bb8: {
|
||||
// falseEdges -> [real: bb5, imaginary: bb5];
|
||||
// }
|
||||
// bb9: { // binding1: Some(w) if guard()
|
||||
// bb7: { // binding1: Some(w) if guard()
|
||||
// StorageLive(_7);
|
||||
// _7 = &((_2 as Some).0: i32);
|
||||
// _5 = &shallow _2;
|
||||
// StorageLive(_8);
|
||||
// _8 = const guard() -> [return: bb10, unwind: bb1];
|
||||
// _8 = const guard() -> [return: bb8, unwind: bb1];
|
||||
// }
|
||||
// bb10: { //end of guard
|
||||
// bb8: { //end of guard1
|
||||
// FakeRead(ForMatchGuard, _5);
|
||||
// FakeRead(ForGuardBinding, _7);
|
||||
// switchInt(move _8) -> [false: bb7, otherwise: bb11];
|
||||
// switchInt(move _8) -> [false: bb10, otherwise: bb9];
|
||||
// }
|
||||
// bb11: { // set up bindings for arm1
|
||||
// bb9: {
|
||||
// StorageDead(_8);
|
||||
// StorageLive(_6);
|
||||
// _6 = ((_2 as Some).0: i32);
|
||||
// _1 = const 1i32;
|
||||
// StorageDead(_6);
|
||||
// StorageDead(_7);
|
||||
// goto -> bb17;
|
||||
// }
|
||||
// bb12: { // binding2 & arm2
|
||||
// bb10: {
|
||||
// StorageDead(_8);
|
||||
// StorageDead(_7);
|
||||
// falseEdges -> [real: bb3, imaginary: bb3];
|
||||
// }
|
||||
// bb11: { // binding2 & arm2
|
||||
// StorageLive(_9);
|
||||
// _9 = _2;
|
||||
// _1 = const 2i32;
|
||||
// StorageDead(_9);
|
||||
// goto -> bb17;
|
||||
// }
|
||||
// bb13: { // binding3: Some(y) if guard2(y)
|
||||
// bb12: { // binding3: Some(y) if guard2(y)
|
||||
// StorageLive(_11);
|
||||
// _11 = &((_2 as Some).0: i32);
|
||||
// _5 = &shallow _2;
|
||||
// StorageLive(_12);
|
||||
// StorageLive(_13);
|
||||
// _13 = (*_11);
|
||||
// _12 = const guard2(move _13) -> [return: bb14, unwind: bb1];
|
||||
// _12 = const guard2(move _13) -> [return: bb13, unwind: bb1];
|
||||
// }
|
||||
// bb14: { // end of guard2
|
||||
// bb13: { // end of guard2
|
||||
// StorageDead(_13);
|
||||
// FakeRead(ForMatchGuard, _5);
|
||||
// FakeRead(ForGuardBinding, _11);
|
||||
// switchInt(move _12) -> [false: bb8, otherwise: bb15];
|
||||
// switchInt(move _12) -> [false: bb15, otherwise: bb14];
|
||||
// }
|
||||
// bb15: { // binding4 & arm4
|
||||
// bb14: { // binding4 & arm4
|
||||
// StorageDead(_12);
|
||||
// StorageLive(_10);
|
||||
// _10 = ((_2 as Some).0: i32);
|
||||
// _1 = const 3i32;
|
||||
// StorageDead(_10);
|
||||
// StorageDead(_11);
|
||||
// goto -> bb17;
|
||||
// }
|
||||
// bb15: {
|
||||
// StorageDead(_12);
|
||||
// StorageDead(_11);
|
||||
// falseEdges -> [real: bb5, imaginary: bb5];
|
||||
// }
|
||||
// bb16: {
|
||||
// StorageLive(_14);
|
||||
// _14 = _2;
|
||||
// _1 = const 4i32;
|
||||
// StorageDead(_14);
|
||||
// goto -> bb17;
|
||||
// }
|
||||
// bb17: {
|
||||
// ...
|
||||
// StorageDead(_1);
|
||||
// StorageDead(_2);
|
||||
// _0 = ();
|
||||
// return;
|
||||
// }
|
||||
// END rustc.main.QualifyAndPromoteConstants.before.mir
|
||||
|
@ -20,10 +20,10 @@ fn main() {
|
||||
// START rustc.main.SimplifyCfg-initial.after.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// switchInt(move _4) -> [false: bb7, otherwise: bb8];
|
||||
// switchInt(move _4) -> [false: bb6, otherwise: bb7];
|
||||
// }
|
||||
// bb1: {
|
||||
// falseEdges -> [real: bb12, imaginary: bb2];
|
||||
// falseEdges -> [real: bb10, imaginary: bb2];
|
||||
// }
|
||||
// bb2: {
|
||||
// falseEdges -> [real: bb13, imaginary: bb3];
|
||||
@ -38,33 +38,35 @@ fn main() {
|
||||
// unreachable;
|
||||
// }
|
||||
// bb6: {
|
||||
// falseEdges -> [real: bb4, imaginary: bb2];
|
||||
// _6 = Le(const 10i32, _1);
|
||||
// switchInt(move _6) -> [false: bb8, otherwise: bb9];
|
||||
// }
|
||||
// bb7: {
|
||||
// _6 = Le(const 10i32, _1);
|
||||
// switchInt(move _6) -> [false: bb9, otherwise: bb10];
|
||||
// _5 = Lt(_1, const 10i32);
|
||||
// switchInt(move _5) -> [false: bb6, otherwise: bb1];
|
||||
// }
|
||||
// bb8: {
|
||||
// _5 = Lt(_1, const 10i32);
|
||||
// switchInt(move _5) -> [false: bb7, otherwise: bb1];
|
||||
// }
|
||||
// bb9: {
|
||||
// switchInt(_1) -> [-1i32: bb3, otherwise: bb4];
|
||||
// }
|
||||
// bb10: {
|
||||
// bb9: {
|
||||
// _7 = Le(_1, const 20i32);
|
||||
// switchInt(move _7) -> [false: bb9, otherwise: bb2];
|
||||
// switchInt(move _7) -> [false: bb8, otherwise: bb2];
|
||||
// }
|
||||
// bb11: {
|
||||
// _3 = const 0i32;
|
||||
// goto -> bb16;
|
||||
// }
|
||||
// bb12: {
|
||||
// bb10: {
|
||||
// _8 = &shallow _1;
|
||||
// StorageLive(_9);
|
||||
// _9 = _2;
|
||||
// FakeRead(ForMatchGuard, _8);
|
||||
// switchInt(move _9) -> [false: bb6, otherwise: bb11];
|
||||
// switchInt(move _9) -> [false: bb12, otherwise: bb11];
|
||||
// }
|
||||
// bb11: {
|
||||
// StorageDead(_9);
|
||||
// _3 = const 0i32;
|
||||
// goto -> bb16;
|
||||
// }
|
||||
// bb12: {
|
||||
// StorageDead(_9);
|
||||
// falseEdges -> [real: bb4, imaginary: bb2];
|
||||
// }
|
||||
// bb13: {
|
||||
// _3 = const 1i32;
|
||||
@ -79,7 +81,6 @@ fn main() {
|
||||
// goto -> bb16;
|
||||
// }
|
||||
// bb16: {
|
||||
// StorageDead(_9);
|
||||
// _0 = ();
|
||||
// StorageDead(_2);
|
||||
// StorageDead(_1);
|
||||
|
@ -19,10 +19,10 @@ fn main() {
|
||||
// bb0: {
|
||||
// FakeRead(ForMatchedPlace, _1);
|
||||
// _3 = discriminant(_1);
|
||||
// switchInt(move _3) -> [1isize: bb5, otherwise: bb2];
|
||||
// switchInt(move _3) -> [1isize: bb4, otherwise: bb2];
|
||||
// }
|
||||
// bb1: {
|
||||
// goto -> bb7;
|
||||
// goto -> bb5;
|
||||
// }
|
||||
// bb2: {
|
||||
// goto -> bb8;
|
||||
@ -31,16 +31,9 @@ fn main() {
|
||||
// unreachable;
|
||||
// }
|
||||
// bb4: {
|
||||
// goto -> bb2;
|
||||
// }
|
||||
// bb5: {
|
||||
// switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb1, otherwise: bb2];
|
||||
// }
|
||||
// bb6: {
|
||||
// _0 = const 0i32;
|
||||
// goto -> bb9;
|
||||
// }
|
||||
// bb7: {
|
||||
// bb5: {
|
||||
// _4 = &shallow _1;
|
||||
// _5 = &shallow ((_1 as Some).0: &'<empty> &'<empty> i32);
|
||||
// _6 = &shallow (*((_1 as Some).0: &'<empty> &'<empty> i32));
|
||||
@ -51,14 +44,22 @@ fn main() {
|
||||
// FakeRead(ForMatchGuard, _5);
|
||||
// FakeRead(ForMatchGuard, _6);
|
||||
// FakeRead(ForMatchGuard, _7);
|
||||
// switchInt(move _8) -> [false: bb4, otherwise: bb6];
|
||||
// switchInt(move _8) -> [false: bb7, otherwise: bb6];
|
||||
// }
|
||||
// bb6: {
|
||||
// StorageDead(_8);
|
||||
// _0 = const 0i32;
|
||||
// goto -> bb9;
|
||||
// }
|
||||
// bb7: {
|
||||
// StorageDead(_8);
|
||||
// goto -> bb2;
|
||||
// }
|
||||
// bb8: {
|
||||
// _0 = const 1i32;
|
||||
// goto -> bb9;
|
||||
// }
|
||||
// bb9: {
|
||||
// StorageDead(_8);
|
||||
// return;
|
||||
// }
|
||||
// bb10 (cleanup): {
|
||||
@ -70,10 +71,10 @@ fn main() {
|
||||
// bb0: {
|
||||
// nop;
|
||||
// _3 = discriminant(_1);
|
||||
// switchInt(move _3) -> [1isize: bb5, otherwise: bb2];
|
||||
// switchInt(move _3) -> [1isize: bb4, otherwise: bb2];
|
||||
// }
|
||||
// bb1: {
|
||||
// goto -> bb7;
|
||||
// goto -> bb5;
|
||||
// }
|
||||
// bb2: {
|
||||
// goto -> bb8;
|
||||
@ -82,16 +83,9 @@ fn main() {
|
||||
// unreachable;
|
||||
// }
|
||||
// bb4: {
|
||||
// goto -> bb2;
|
||||
// }
|
||||
// bb5: {
|
||||
// switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb1, otherwise: bb2];
|
||||
// }
|
||||
// bb6: {
|
||||
// _0 = const 0i32;
|
||||
// goto -> bb9;
|
||||
// }
|
||||
// bb7: {
|
||||
// bb5: {
|
||||
// nop;
|
||||
// nop;
|
||||
// nop;
|
||||
@ -102,14 +96,22 @@ fn main() {
|
||||
// nop;
|
||||
// nop;
|
||||
// nop;
|
||||
// switchInt(move _8) -> [false: bb4, otherwise: bb6];
|
||||
// switchInt(move _8) -> [false: bb7, otherwise: bb6];
|
||||
// }
|
||||
// bb6: {
|
||||
// StorageDead(_8);
|
||||
// _0 = const 0i32;
|
||||
// goto -> bb9;
|
||||
// }
|
||||
// bb7: {
|
||||
// StorageDead(_8);
|
||||
// goto -> bb2;
|
||||
// }
|
||||
// bb8: {
|
||||
// _0 = const 1i32;
|
||||
// goto -> bb9;
|
||||
// }
|
||||
// bb9: {
|
||||
// StorageDead(_8);
|
||||
// return;
|
||||
// }
|
||||
// bb10 (cleanup): {
|
||||
|
@ -105,6 +105,14 @@ fn main() {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Attribute should be respected on match arms
|
||||
match 0 {
|
||||
#[allow(unused_mut)]
|
||||
mut x => {
|
||||
let mut y = 1;
|
||||
},
|
||||
}
|
||||
|
||||
let x = |mut y: isize| y = 32;
|
||||
fn nothing(mut foo: isize) { foo = 37; }
|
||||
|
||||
|
@ -133,7 +133,7 @@ LL | fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
|
||||
| help: remove this `mut`
|
||||
|
||||
error: variable does not need to be mutable
|
||||
--> $DIR/lint-unused-mut-variables.rs:130:9
|
||||
--> $DIR/lint-unused-mut-variables.rs:138:9
|
||||
|
|
||||
LL | let mut b = vec![2];
|
||||
| ----^
|
||||
@ -141,7 +141,7 @@ LL | let mut b = vec![2];
|
||||
| help: remove this `mut`
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/lint-unused-mut-variables.rs:126:8
|
||||
--> $DIR/lint-unused-mut-variables.rs:134:8
|
||||
|
|
||||
LL | #[deny(unused_mut)]
|
||||
| ^^^^^^^^^^
|
||||
|
Loading…
Reference in New Issue
Block a user