Skip to content

Commit d4a5588

Browse files
authored
Rollup merge of rust-lang#60174 - matthewjasper:add-match-arm-scopes, r=pnkfelix
Add match arm scopes and other scope fixes * Add drop and lint scopes for match arms. * Lint attributes are now respected on match arms. * Make sure we emit a StorageDead if we diverge when initializing a temporary. * Adjust MIR pretty printing of scopes for locals. * Don't generate duplicate lint scopes for `let statements`. * Add some previously missing fake borrows for matches. closes rust-lang#46525 cc @rust-lang/compiler
2 parents e7dd3eb + 5b5255d commit d4a5588

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+726
-276
lines changed

src/librustc/cfg/construct.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
419419
for arm in arms {
420420
// Add an exit node for when we've visited all the
421421
// patterns and the guard (if there is one) in the arm.
422-
let arm_exit = self.add_dummy_node(&[]);
422+
let bindings_exit = self.add_dummy_node(&[]);
423423

424424
for pat in &arm.pats {
425425
// Visit the pattern, coming from the discriminant exit
@@ -453,14 +453,16 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
453453

454454
// Add an edge from the exit of this pattern to the
455455
// exit of the arm
456-
self.add_contained_edge(pat_exit, arm_exit);
456+
self.add_contained_edge(pat_exit, bindings_exit);
457457
}
458458

459459
// Visit the body of this arm
460-
let body_exit = self.expr(&arm.body, arm_exit);
460+
let body_exit = self.expr(&arm.body, bindings_exit);
461+
462+
let arm_exit = self.add_ast_node(arm.hir_id.local_id, &[body_exit]);
461463

462464
// Link the body to the exit of the expression
463-
self.add_contained_edge(body_exit, expr_exit);
465+
self.add_contained_edge(arm_exit, expr_exit);
464466
}
465467

466468
expr_exit

src/librustc/hir/intravisit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
11021102
}
11031103

11041104
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
1105+
visitor.visit_id(arm.hir_id);
11051106
walk_list!(visitor, visit_pat, &arm.pats);
11061107
if let Some(ref g) = arm.guard {
11071108
match g {

src/librustc/hir/lowering.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1313,13 +1313,15 @@ impl<'a> LoweringContext<'a> {
13131313

13141314
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm {
13151315
hir::Arm {
1316+
hir_id: self.next_id(),
13161317
attrs: self.lower_attrs(&arm.attrs),
13171318
pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(),
13181319
guard: match arm.guard {
13191320
Some(Guard::If(ref x)) => Some(hir::Guard::If(P(self.lower_expr(x)))),
13201321
_ => None,
13211322
},
13221323
body: P(self.lower_expr(&arm.body)),
1324+
span: arm.span,
13231325
}
13241326
}
13251327

@@ -5023,9 +5025,11 @@ impl<'a> LoweringContext<'a> {
50235025

50245026
fn arm(&mut self, pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
50255027
hir::Arm {
5028+
hir_id: self.next_id(),
50265029
attrs: hir_vec![],
50275030
pats,
50285031
guard: None,
5032+
span: expr.span,
50295033
body: expr,
50305034
}
50315035
}

src/librustc/hir/map/collector.rs

+10
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,16 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
430430
});
431431
}
432432

433+
fn visit_arm(&mut self, arm: &'hir Arm) {
434+
let node = Node::Arm(arm);
435+
436+
self.insert(arm.span, arm.hir_id, node);
437+
438+
self.with_parent(arm.hir_id, |this| {
439+
intravisit::walk_arm(this, arm);
440+
});
441+
}
442+
433443
fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
434444
self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant));
435445

src/librustc/hir/map/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ impl<'hir> Map<'hir> {
373373
Node::Pat(_) |
374374
Node::Binding(_) |
375375
Node::Local(_) |
376+
Node::Arm(_) |
376377
Node::Lifetime(_) |
377378
Node::Visibility(_) |
378379
Node::Block(_) |
@@ -1000,6 +1001,7 @@ impl<'hir> Map<'hir> {
10001001
Some(Node::Field(ref f)) => Some(&f.attrs[..]),
10011002
Some(Node::Expr(ref e)) => Some(&*e.attrs),
10021003
Some(Node::Stmt(ref s)) => Some(s.node.attrs()),
1004+
Some(Node::Arm(ref a)) => Some(&*a.attrs),
10031005
Some(Node::GenericParam(param)) => Some(&param.attrs[..]),
10041006
// Unit/tuple structs/variants take the attributes straight from
10051007
// the struct/variant definition.
@@ -1073,6 +1075,7 @@ impl<'hir> Map<'hir> {
10731075
Some(Node::TraitRef(tr)) => tr.path.span,
10741076
Some(Node::Binding(pat)) => pat.span,
10751077
Some(Node::Pat(pat)) => pat.span,
1078+
Some(Node::Arm(arm)) => arm.span,
10761079
Some(Node::Block(block)) => block.span,
10771080
Some(Node::Ctor(..)) => match self.find_by_hir_id(
10781081
self.get_parent_node_by_hir_id(hir_id))
@@ -1288,6 +1291,7 @@ impl<'a> print::State<'a> {
12881291
Node::TraitRef(a) => self.print_trait_ref(&a),
12891292
Node::Binding(a) |
12901293
Node::Pat(a) => self.print_pat(&a),
1294+
Node::Arm(a) => self.print_arm(&a),
12911295
Node::Block(a) => {
12921296
use syntax::print::pprust::PrintState;
12931297

@@ -1417,6 +1421,9 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String {
14171421
Some(Node::Pat(_)) => {
14181422
format!("pat {}{}", map.hir_to_pretty_string(id), id_str)
14191423
}
1424+
Some(Node::Arm(_)) => {
1425+
format!("arm {}{}", map.hir_to_pretty_string(id), id_str)
1426+
}
14201427
Some(Node::Block(_)) => {
14211428
format!("block {}{}", map.hir_to_pretty_string(id), id_str)
14221429
}

src/librustc/hir/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,9 @@ pub struct Local {
12281228
/// `<pats> (if <guard>) => <body>`.
12291229
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
12301230
pub struct Arm {
1231+
#[stable_hasher(ignore)]
1232+
pub hir_id: HirId,
1233+
pub span: Span,
12311234
pub attrs: HirVec<Attribute>,
12321235
/// Multiple patterns can be combined with `|`
12331236
pub pats: HirVec<P<Pat>>,
@@ -2656,6 +2659,7 @@ pub enum Node<'hir> {
26562659
TraitRef(&'hir TraitRef),
26572660
Binding(&'hir Pat),
26582661
Pat(&'hir Pat),
2662+
Arm(&'hir Arm),
26592663
Block(&'hir Block),
26602664
Local(&'hir Local),
26612665
MacroDef(&'hir MacroDef),

src/librustc/hir/print.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1862,7 +1862,7 @@ impl<'a> State<'a> {
18621862
self.ann.post(self, AnnNode::Pat(pat))
18631863
}
18641864

1865-
fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> {
1865+
pub fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> {
18661866
// I have no idea why this check is necessary, but here it
18671867
// is :(
18681868
if arm.attrs.is_empty() {

src/librustc/lint/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,12 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'a, 'tcx> {
849849
})
850850
}
851851

852+
fn visit_arm(&mut self, a: &'tcx hir::Arm) {
853+
self.with_lint_attrs(a.hir_id, &a.attrs, |builder| {
854+
intravisit::walk_arm(builder, a);
855+
})
856+
}
857+
852858
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
853859
self.with_lint_attrs(trait_item.hir_id, &trait_item.attrs, |builder| {
854860
intravisit::walk_trait_item(builder, trait_item);

src/librustc/middle/region.rs

+21-13
Original file line numberDiff line numberDiff line change
@@ -119,18 +119,18 @@ impl fmt::Debug for Scope {
119119
pub enum ScopeData {
120120
Node,
121121

122-
// Scope of the call-site for a function or closure
123-
// (outlives the arguments as well as the body).
122+
/// Scope of the call-site for a function or closure
123+
/// (outlives the arguments as well as the body).
124124
CallSite,
125125

126-
// Scope of arguments passed to a function or closure
127-
// (they outlive its body).
126+
/// Scope of arguments passed to a function or closure
127+
/// (they outlive its body).
128128
Arguments,
129129

130-
// Scope of destructors for temporaries of node-id.
130+
/// Scope of destructors for temporaries of node-id.
131131
Destruction,
132132

133-
// Scope following a `let id = expr;` binding in a block.
133+
/// Scope following a `let id = expr;` binding in a block.
134134
Remainder(FirstStatementIndex)
135135
}
136136

@@ -152,11 +152,11 @@ newtype_index! {
152152
///
153153
/// * The subscope with `first_statement_index == 1` is scope of `c`,
154154
/// and thus does not include EXPR_2, but covers the `...`.
155-
pub struct FirstStatementIndex { .. }
155+
pub struct FirstStatementIndex {
156+
derive [HashStable]
157+
}
156158
}
157159

158-
impl_stable_hash_for!(struct crate::middle::region::FirstStatementIndex { private });
159-
160160
// compilation error if size of `ScopeData` is not the same as a `u32`
161161
static_assert!(ASSERT_SCOPE_DATA: mem::size_of::<ScopeData>() == 4);
162162

@@ -814,13 +814,25 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
814814
}
815815

816816
fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &'tcx hir::Arm) {
817+
let prev_cx = visitor.cx;
818+
819+
visitor.enter_scope(
820+
Scope {
821+
id: arm.hir_id.local_id,
822+
data: ScopeData::Node,
823+
}
824+
);
825+
visitor.cx.var_parent = visitor.cx.parent;
826+
817827
visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
818828

819829
if let Some(hir::Guard::If(ref expr)) = arm.guard {
820830
visitor.terminating_scopes.insert(expr.hir_id.local_id);
821831
}
822832

823833
intravisit::walk_arm(visitor, arm);
834+
835+
visitor.cx = prev_cx;
824836
}
825837

826838
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:
893905
terminating(body.hir_id.local_id);
894906
}
895907

896-
hir::ExprKind::Match(..) => {
897-
visitor.cx.var_parent = visitor.cx.parent;
898-
}
899-
900908
hir::ExprKind::DropTemps(ref expr) => {
901909
// `DropTemps(expr)` does not denote a conditional scope.
902910
// Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`.

src/librustc_mir/build/block.rs

+28-20
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
2323
safety_mode
2424
} =
2525
self.hir.mirror(ast_block);
26-
self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), block, move |this| {
27-
this.in_scope((region_scope, source_info), LintLevel::Inherited, block, move |this| {
26+
self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), move |this| {
27+
this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
2828
if targeted_by_break {
2929
// This is a `break`-able block
3030
let exit_block = this.cfg.start_new_block();
@@ -83,9 +83,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
8383
StmtKind::Expr { scope, expr } => {
8484
this.block_context.push(BlockFrame::Statement { ignores_expr_result: true });
8585
unpack!(block = this.in_opt_scope(
86-
opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
86+
opt_destruction_scope.map(|de|(de, source_info)), |this| {
8787
let si = (scope, source_info);
88-
this.in_scope(si, LintLevel::Inherited, block, |this| {
88+
this.in_scope(si, LintLevel::Inherited, |this| {
8989
let expr = this.hir.mirror(expr);
9090
this.stmt_expr(block, expr, Some(stmt_span))
9191
})
@@ -113,31 +113,39 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
113113
let remainder_span = remainder_scope.span(this.hir.tcx(),
114114
&this.hir.region_scope_tree);
115115

116-
let scope;
116+
let visibility_scope =
117+
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
117118

118119
// Evaluate the initializer, if present.
119120
if let Some(init) = initializer {
120121
let initializer_span = init.span();
121122

122-
scope = this.declare_bindings(
123-
None,
124-
remainder_span,
125-
lint_level,
126-
&pattern,
127-
ArmHasGuard(false),
128-
Some((None, initializer_span)),
129-
);
130123
unpack!(block = this.in_opt_scope(
131-
opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
124+
opt_destruction_scope.map(|de|(de, source_info)), |this| {
132125
let scope = (init_scope, source_info);
133-
this.in_scope(scope, lint_level, block, |this| {
126+
this.in_scope(scope, lint_level, |this| {
127+
this.declare_bindings(
128+
visibility_scope,
129+
remainder_span,
130+
&pattern,
131+
ArmHasGuard(false),
132+
Some((None, initializer_span)),
133+
);
134134
this.expr_into_pattern(block, pattern, init)
135135
})
136136
}));
137137
} else {
138-
scope = this.declare_bindings(
139-
None, remainder_span, lint_level, &pattern,
140-
ArmHasGuard(false), None);
138+
let scope = (init_scope, source_info);
139+
unpack!(this.in_scope(scope, lint_level, |this| {
140+
this.declare_bindings(
141+
visibility_scope,
142+
remainder_span,
143+
&pattern,
144+
ArmHasGuard(false),
145+
None,
146+
);
147+
block.unit()
148+
}));
141149

142150
debug!("ast_block_stmts: pattern={:?}", pattern);
143151
this.visit_bindings(
@@ -149,8 +157,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
149157
})
150158
}
151159

152-
// Enter the source scope, after evaluating the initializer.
153-
if let Some(source_scope) = scope {
160+
// Enter the visibility scope, after evaluating the initializer.
161+
if let Some(source_scope) = visibility_scope {
154162
this.source_scope = source_scope;
155163
}
156164
}

src/librustc_mir/build/expr/as_operand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
5757
{
5858
let source_info = this.source_info(expr.span);
5959
let region_scope = (region_scope, source_info);
60-
return this.in_scope(region_scope, lint_level, block, |this| {
60+
return this.in_scope(region_scope, lint_level, |this| {
6161
this.as_operand(block, scope, value)
6262
});
6363
}

src/librustc_mir/build/expr/as_place.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
5252
region_scope,
5353
lint_level,
5454
value,
55-
} => this.in_scope((region_scope, source_info), lint_level, block, |this| {
55+
} => this.in_scope((region_scope, source_info), lint_level, |this| {
5656
if mutability == Mutability::Not {
5757
this.as_read_only_place(block, value)
5858
} else {

src/librustc_mir/build/expr/as_rvalue.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
5858
value,
5959
} => {
6060
let region_scope = (region_scope, source_info);
61-
this.in_scope(region_scope, lint_level, block, |this| {
61+
this.in_scope(region_scope, lint_level, |this| {
6262
this.as_rvalue(block, scope, value)
6363
})
6464
}

0 commit comments

Comments
 (0)