Skip to content

Commit 8712d90

Browse files
committed
Auto merge of #65385 - matthewjasper:drop-on-into-panic-otp, r=<try>
[WIP] Make `into` schedule drop for the destination again #61430 triggered some degenerate behavior in llvm where it would inline functions far too aggressively. This is marked as WIP because it doesn't really solve the problem in general. I've opened this PR more so that there's a place to discuss fixes. <details> <summary>Minimized example of the problem</summary> Uncommenting the `#[inline]` will cause this to take a long time to compile on nightly, since llvm will inline all of the next calls into one enormous function that it spends a very long time handling. ```rust pub trait Iterator { type Item; fn next(&mut self) -> Self::Item; } pub struct Empty; impl Iterator for Empty { type Item = (); fn next(&mut self) {} } pub struct Chain<A, B=Empty> { a: A, b: B, state: ChainState, } #[allow(dead_code)] enum ChainState { Both, Front, Back, } impl<A, B> Iterator for Chain<A, B> where A: Iterator, B: Iterator<Item = A::Item> { type Item = A::Item; //#[inline] //^ uncomment me for degenerate llvm behvaiour with `-O` fn next(&mut self) -> A::Item { let ret; match self.state { ChainState::Both => { let _x = self.a.next(); self.state = ChainState::Back; ret = self.b.next() }, ChainState::Front => ret = self.a.next(), ChainState::Back => ret = self.b.next(), }; ret } } type Chain2<T> = Chain<Chain<T>>; type Chain4<T> = Chain2<Chain2<T>>; type Chain8<T> = Chain4<Chain4<T>>; type Chain16<T> = Chain8<Chain8<T>>; pub fn call_next(x: &mut Chain16<Empty>) { x.next() } ``` </details> Closes #47949
2 parents f39205b + 7d7dc00 commit 8712d90

File tree

17 files changed

+483
-293
lines changed

17 files changed

+483
-293
lines changed

src/libcore/iter/adapters/chain.rs

-5
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ impl<A, B> Iterator for Chain<A, B> where
5454
{
5555
type Item = A::Item;
5656

57-
#[inline]
5857
fn next(&mut self) -> Option<A::Item> {
5958
match self.state {
6059
ChainState::Both => match self.a.next() {
@@ -117,7 +116,6 @@ impl<A, B> Iterator for Chain<A, B> where
117116
accum
118117
}
119118

120-
#[inline]
121119
fn nth(&mut self, mut n: usize) -> Option<A::Item> {
122120
match self.state {
123121
ChainState::Both | ChainState::Front => {
@@ -157,7 +155,6 @@ impl<A, B> Iterator for Chain<A, B> where
157155
}
158156
}
159157

160-
#[inline]
161158
fn last(self) -> Option<A::Item> {
162159
match self.state {
163160
ChainState::Both => {
@@ -198,7 +195,6 @@ impl<A, B> DoubleEndedIterator for Chain<A, B> where
198195
A: DoubleEndedIterator,
199196
B: DoubleEndedIterator<Item=A::Item>,
200197
{
201-
#[inline]
202198
fn next_back(&mut self) -> Option<A::Item> {
203199
match self.state {
204200
ChainState::Both => match self.b.next_back() {
@@ -213,7 +209,6 @@ impl<A, B> DoubleEndedIterator for Chain<A, B> where
213209
}
214210
}
215211

216-
#[inline]
217212
fn nth_back(&mut self, mut n: usize) -> Option<A::Item> {
218213
match self.state {
219214
ChainState::Both | ChainState::Back => {

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
&this.hir.tcx().mk_place_deref(Place::from(result)),
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-10
Original file line numberDiff line numberDiff line change
@@ -109,16 +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-
DropKind::Value,
120-
);
121-
}
112+
unpack!(block = this.into(temp_place, temp_lifetime, block, expr));
122113

123114
block.and(temp)
124115
}

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(&this.hir.tcx().mk_place_deref(ptr_temp), 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(&this.hir.tcx().mk_place_deref(ptr_temp), 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)