Skip to content

Commit 3702683

Browse files
committed
Make into schedule drop for the destination
1 parent 73c0987 commit 3702683

File tree

12 files changed

+472
-252
lines changed

12 files changed

+472
-252
lines changed

src/librustc_mir/build/block.rs

+49-21
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
22
use crate::build::ForGuard::OutsideGuard;
33
use crate::build::matches::ArmHasGuard;
4+
use crate::build::scope::DropKind;
45
use crate::hair::*;
6+
use rustc::middle::region;
57
use rustc::mir::*;
68
use rustc::hir;
79
use syntax_pos::Span;
810

911
impl<'a, 'tcx> Builder<'a, 'tcx> {
10-
pub fn ast_block(&mut self,
11-
destination: &Place<'tcx>,
12-
block: BasicBlock,
13-
ast_block: &'tcx hir::Block,
14-
source_info: SourceInfo)
15-
-> BlockAnd<()> {
12+
pub fn ast_block(
13+
&mut self,
14+
destination: &Place<'tcx>,
15+
scope: Option<region::Scope>,
16+
block: BasicBlock,
17+
ast_block: &'tcx hir::Block,
18+
source_info: SourceInfo,
19+
) -> BlockAnd<()> {
1620
let Block {
1721
region_scope,
1822
opt_destruction_scope,
@@ -21,37 +25,61 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2125
expr,
2226
targeted_by_break,
2327
safety_mode
24-
} =
25-
self.hir.mirror(ast_block);
28+
} = self.hir.mirror(ast_block);
2629
self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), move |this| {
2730
this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
2831
if targeted_by_break {
2932
// This is a `break`-able block
3033
let exit_block = this.cfg.start_new_block();
34+
if let Some(scope) = scope {
35+
// Breakable blocks assign to their destination on each
36+
// `break`, as well as when they exit normally. So we
37+
// can't schedule the drop in the last expression like
38+
// normal blocks do.
39+
let local = destination.as_local()
40+
.expect("cannot schedule drop of non-Local place");
41+
this.schedule_drop(span, scope, local, DropKind::Value);
42+
}
3143
let block_exit = this.in_breakable_scope(
3244
None, exit_block, destination.clone(), |this| {
33-
this.ast_block_stmts(destination, block, span, stmts, expr,
34-
safety_mode)
45+
this.ast_block_stmts(
46+
destination,
47+
None,
48+
block,
49+
span,
50+
stmts,
51+
expr,
52+
safety_mode,
53+
)
3554
});
3655
this.cfg.terminate(unpack!(block_exit), source_info,
3756
TerminatorKind::Goto { target: exit_block });
3857
exit_block.unit()
3958
} else {
40-
this.ast_block_stmts(destination, block, span, stmts, expr,
41-
safety_mode)
59+
this.ast_block_stmts(
60+
destination,
61+
scope,
62+
block,
63+
span,
64+
stmts,
65+
expr,
66+
safety_mode,
67+
)
4268
}
4369
})
4470
})
4571
}
4672

47-
fn ast_block_stmts(&mut self,
48-
destination: &Place<'tcx>,
49-
mut block: BasicBlock,
50-
span: Span,
51-
stmts: Vec<StmtRef<'tcx>>,
52-
expr: Option<ExprRef<'tcx>>,
53-
safety_mode: BlockSafety)
54-
-> BlockAnd<()> {
73+
fn ast_block_stmts(
74+
&mut self,
75+
destination: &Place<'tcx>,
76+
scope: Option<region::Scope>,
77+
mut block: BasicBlock,
78+
span: Span,
79+
stmts: Vec<StmtRef<'tcx>>,
80+
expr: Option<ExprRef<'tcx>>,
81+
safety_mode: BlockSafety,
82+
) -> BlockAnd<()> {
5583
let this = self;
5684

5785
// This convoluted structure is to avoid using recursion as we walk down a list
@@ -177,7 +205,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
177205
this.block_context.currently_ignores_tail_results();
178206
this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored });
179207

180-
unpack!(block = this.into(destination, block, expr));
208+
unpack!(block = this.into(destination, scope, block, expr));
181209
let popped = this.block_context.pop();
182210

183211
assert!(popped.map_or(false, |bf|bf.is_tail_expr()));

src/librustc_mir/build/expr/as_rvalue.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
136136
this.cfg
137137
.push_assign(block, source_info, &Place::from(result), box_);
138138

139-
// initialize the box contents:
139+
// Initialize the box contents. No scope is needed since the
140+
// `Box` is already scheduled to be dropped.
140141
unpack!(
141142
block = this.into(
142143
&Place::from(result).deref(),
143-
block, value
144+
None,
145+
block,
146+
value
144147
)
145148
);
146149
block.and(Rvalue::Use(Operand::Move(Place::from(result))))

src/librustc_mir/build/expr/as_temp.rs

+1-11
Original file line numberDiff line numberDiff line change
@@ -109,17 +109,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
109109
}
110110
}
111111

112-
unpack!(block = this.into(temp_place, block, expr));
113-
114-
if let Some(temp_lifetime) = temp_lifetime {
115-
this.schedule_drop(
116-
expr_span,
117-
temp_lifetime,
118-
temp,
119-
expr_ty,
120-
DropKind::Value,
121-
);
122-
}
112+
unpack!(block = this.into(temp_place, temp_lifetime, block, expr));
123113

124114
block.and(temp)
125115
}

src/librustc_mir/build/expr/into.rs

+37-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
33
use crate::build::expr::category::{Category, RvalueFunc};
44
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
5+
use crate::build::scope::DropKind;
56
use crate::hair::*;
7+
use rustc::middle::region;
68
use rustc::mir::*;
79
use rustc::ty;
810

@@ -11,15 +13,18 @@ use rustc_target::spec::abi::Abi;
1113
impl<'a, 'tcx> Builder<'a, 'tcx> {
1214
/// Compile `expr`, storing the result into `destination`, which
1315
/// is assumed to be uninitialized.
16+
/// If a `drop_scope` is provided, `destination` is scheduled to be dropped
17+
/// in `scope` once it has been initialized.
1418
pub fn into_expr(
1519
&mut self,
1620
destination: &Place<'tcx>,
21+
scope: Option<region::Scope>,
1722
mut block: BasicBlock,
1823
expr: Expr<'tcx>,
1924
) -> BlockAnd<()> {
2025
debug!(
21-
"into_expr(destination={:?}, block={:?}, expr={:?})",
22-
destination, block, expr
26+
"into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})",
27+
destination, scope, block, expr
2328
);
2429

2530
// since we frequently have to reference `self` from within a
@@ -35,6 +40,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3540
_ => false,
3641
};
3742

43+
let schedule_drop = move |this: &mut Self| {
44+
if let Some(drop_scope) = scope {
45+
let local = destination.as_local()
46+
.expect("cannot schedule drop of non-Local place");
47+
this.schedule_drop(expr_span, drop_scope, local, DropKind::Value);
48+
}
49+
};
50+
3851
if !expr_is_block_or_scope {
3952
this.block_context.push(BlockFrame::SubExpr);
4053
}
@@ -47,14 +60,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4760
} => {
4861
let region_scope = (region_scope, source_info);
4962
this.in_scope(region_scope, lint_level, |this| {
50-
this.into(destination, block, value)
63+
this.into(destination, scope, block, value)
5164
})
5265
}
5366
ExprKind::Block { body: ast_block } => {
54-
this.ast_block(destination, block, ast_block, source_info)
67+
this.ast_block(destination, scope, block, ast_block, source_info)
5568
}
5669
ExprKind::Match { scrutinee, arms } => {
57-
this.match_expr(destination, expr_span, block, scrutinee, arms)
70+
this.match_expr(destination, scope, expr_span, block, scrutinee, arms)
5871
}
5972
ExprKind::NeverToAny { source } => {
6073
let source = this.hir.mirror(source);
@@ -67,6 +80,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6780

6881
// This is an optimization. If the expression was a call then we already have an
6982
// unreachable block. Don't bother to terminate it and create a new one.
83+
schedule_drop(this);
7084
if is_call {
7185
block.unit()
7286
} else {
@@ -164,6 +178,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
164178
TerminatorKind::Goto { target: loop_block },
165179
);
166180

181+
// Loops assign to their destination on each `break`. Since we
182+
// can't easily unschedule drops, we schedule the drop now.
183+
schedule_drop(this);
167184
this.in_breakable_scope(
168185
Some(loop_block),
169186
exit_block,
@@ -185,7 +202,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
185202
// introduce a unit temporary as the destination for the loop body.
186203
let tmp = this.get_unit_temp();
187204
// Execute the body, branching back to the test.
188-
let body_block_end = unpack!(this.into(&tmp, body_block, body));
205+
// No scope is provided, since we've scheduled the drop above.
206+
let body_block_end = unpack!(this.into(&tmp, None, body_block, body));
189207
this.cfg.terminate(
190208
body_block_end,
191209
source_info,
@@ -234,8 +252,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
234252
is_block_tail: None,
235253
});
236254
let ptr_temp = Place::from(ptr_temp);
237-
let block = unpack!(this.into(&ptr_temp, block, ptr));
238-
this.into(&ptr_temp.deref(), block, val)
255+
// No need for a scope, ptr_temp doesn't need drop
256+
let block = unpack!(this.into(&ptr_temp, None, block, ptr));
257+
// Maybe we should provide a scope here so that
258+
// `move_val_init` wouldn't leak on panic even with an
259+
// arbitrary `val` expression, but `schedule_drop`,
260+
// borrowck and drop elaboration all prevent us from
261+
// dropping `ptr_temp.deref()`.
262+
this.into(&ptr_temp.deref(), None, block, val)
239263
} else {
240264
let args: Vec<_> = args
241265
.into_iter()
@@ -265,11 +289,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
265289
from_hir_call,
266290
},
267291
);
292+
schedule_drop(this);
268293
success.unit()
269294
}
270295
}
271296
ExprKind::Use { source } => {
272-
this.into(destination, block, source)
297+
this.into(destination, scope, block, source)
273298
}
274299

275300
// These cases don't actually need a destination
@@ -296,6 +321,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
296321
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
297322
this.cfg
298323
.push_assign(block, source_info, destination, rvalue);
324+
schedule_drop(this);
299325
block.unit()
300326
}
301327
ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
@@ -315,6 +341,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
315341
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
316342
this.cfg
317343
.push_assign(block, source_info, destination, rvalue);
344+
schedule_drop(this);
318345
block.unit()
319346
}
320347

@@ -346,6 +373,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
346373

347374
let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
348375
this.cfg.push_assign(block, source_info, destination, rvalue);
376+
schedule_drop(this);
349377
block.unit()
350378
}
351379
};

src/librustc_mir/build/into.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,31 @@
66
77
use crate::build::{BlockAnd, Builder};
88
use crate::hair::*;
9+
use rustc::middle::region;
910
use rustc::mir::*;
1011

1112
pub(in crate::build) trait EvalInto<'tcx> {
1213
fn eval_into(
1314
self,
1415
builder: &mut Builder<'_, 'tcx>,
1516
destination: &Place<'tcx>,
17+
scope: Option<region::Scope>,
1618
block: BasicBlock,
1719
) -> BlockAnd<()>;
1820
}
1921

2022
impl<'a, 'tcx> Builder<'a, 'tcx> {
21-
pub fn into<E>(&mut self,
22-
destination: &Place<'tcx>,
23-
block: BasicBlock,
24-
expr: E)
25-
-> BlockAnd<()>
26-
where E: EvalInto<'tcx>
23+
pub fn into<E>(
24+
&mut self,
25+
destination: &Place<'tcx>,
26+
scope: Option<region::Scope>,
27+
block: BasicBlock,
28+
expr: E,
29+
) -> BlockAnd<()>
30+
where
31+
E: EvalInto<'tcx>,
2732
{
28-
expr.eval_into(self, destination, block)
33+
expr.eval_into(self, destination, scope, block)
2934
}
3035
}
3136

@@ -34,10 +39,11 @@ impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
3439
self,
3540
builder: &mut Builder<'_, 'tcx>,
3641
destination: &Place<'tcx>,
42+
scope: Option<region::Scope>,
3743
block: BasicBlock,
3844
) -> BlockAnd<()> {
3945
let expr = builder.hir.mirror(self);
40-
builder.into_expr(destination, block, expr)
46+
builder.into_expr(destination, scope, block, expr)
4147
}
4248
}
4349

@@ -46,8 +52,9 @@ impl<'tcx> EvalInto<'tcx> for Expr<'tcx> {
4652
self,
4753
builder: &mut Builder<'_, 'tcx>,
4854
destination: &Place<'tcx>,
55+
scope: Option<region::Scope>,
4956
block: BasicBlock,
5057
) -> BlockAnd<()> {
51-
builder.into_expr(destination, block, self)
58+
builder.into_expr(destination, scope, block, self)
5259
}
5360
}

0 commit comments

Comments
 (0)