Skip to content

Commit f0b5145

Browse files
committed
Auto merge of #40133 - arielb1:operand-lifetimes, r=eddyb
[MIR] improve operand lifetimes r? @eddyb
2 parents 1476105 + f99f1f8 commit f0b5145

File tree

16 files changed

+356
-130
lines changed

16 files changed

+356
-130
lines changed

src/librustc_borrowck/borrowck/mir/elaborate_drops.rs

+1
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
161161
fn create_drop_flag(&mut self, index: MovePathIndex) {
162162
let tcx = self.tcx;
163163
let patch = &mut self.patch;
164+
debug!("create_drop_flag({:?})", self.mir.span);
164165
self.drop_flags.entry(index).or_insert_with(|| {
165166
patch.new_temp(tcx.types.bool)
166167
});

src/librustc_mir/build/block.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
6767
this.expr_into_pattern(block, pattern, init)
6868
}));
6969
} else {
70-
this.storage_live_for_bindings(block, &pattern);
70+
this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
71+
this.storage_live_binding(block, node, span);
72+
this.schedule_drop_for_binding(node, span);
73+
})
7174
}
7275

7376
// Enter the visibility scope, after evaluating the initializer.

src/librustc_mir/build/expr/as_lvalue.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
5656
let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty());
5757

5858
let slice = unpack!(block = this.as_lvalue(block, lhs));
59-
60-
let idx = unpack!(block = this.as_operand(block, index));
59+
// extent=None so lvalue indexes live forever. They are scalars so they
60+
// do not need storage annotations, and they are often copied between
61+
// places.
62+
let idx = unpack!(block = this.as_operand(block, None, index));
6163

6264
// bounds check:
6365
let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty));
@@ -121,7 +123,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
121123
Some(Category::Lvalue) => false,
122124
_ => true,
123125
});
124-
this.as_temp(block, expr)
126+
this.as_temp(block, expr.temp_lifetime, expr)
125127
}
126128
}
127129
}

src/librustc_mir/build/expr/as_operand.rs

+28-4
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,52 @@
1313
use build::{BlockAnd, BlockAndExtension, Builder};
1414
use build::expr::category::Category;
1515
use hair::*;
16+
use rustc::middle::region::CodeExtent;
1617
use rustc::mir::*;
1718

1819
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
20+
/// Returns an operand suitable for use until the end of the current
21+
/// scope expression.
22+
///
23+
/// The operand returned from this function will *not be valid* after
24+
/// an ExprKind::Scope is passed, so please do *not* return it from
25+
/// functions to avoid bad miscompiles.
26+
pub fn as_local_operand<M>(&mut self, block: BasicBlock, expr: M)
27+
-> BlockAnd<Operand<'tcx>>
28+
where M: Mirror<'tcx, Output = Expr<'tcx>>
29+
{
30+
let topmost_scope = self.topmost_scope(); // FIXME(#6393)
31+
self.as_operand(block, Some(topmost_scope), expr)
32+
}
33+
1934
/// Compile `expr` into a value that can be used as an operand.
2035
/// If `expr` is an lvalue like `x`, this will introduce a
2136
/// temporary `tmp = x`, so that we capture the value of `x` at
2237
/// this time.
23-
pub fn as_operand<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Operand<'tcx>>
38+
///
39+
/// The operand is known to be live until the end of `scope`.
40+
pub fn as_operand<M>(&mut self,
41+
block: BasicBlock,
42+
scope: Option<CodeExtent>,
43+
expr: M) -> BlockAnd<Operand<'tcx>>
2444
where M: Mirror<'tcx, Output = Expr<'tcx>>
2545
{
2646
let expr = self.hir.mirror(expr);
27-
self.expr_as_operand(block, expr)
47+
self.expr_as_operand(block, scope, expr)
2848
}
2949

3050
fn expr_as_operand(&mut self,
3151
mut block: BasicBlock,
52+
scope: Option<CodeExtent>,
3253
expr: Expr<'tcx>)
3354
-> BlockAnd<Operand<'tcx>> {
3455
debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
3556
let this = self;
3657

3758
if let ExprKind::Scope { extent, value } = expr.kind {
38-
return this.in_scope(extent, block, |this| this.as_operand(block, value));
59+
return this.in_scope(extent, block, |this| {
60+
this.as_operand(block, scope, value)
61+
});
3962
}
4063

4164
let category = Category::of(&expr.kind).unwrap();
@@ -47,7 +70,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
4770
}
4871
Category::Lvalue |
4972
Category::Rvalue(..) => {
50-
let operand = unpack!(block = this.as_temp(block, expr));
73+
let operand =
74+
unpack!(block = this.as_temp(block, scope, expr));
5175
block.and(Operand::Consume(operand))
5276
}
5377
}

src/librustc_mir/build/expr/as_rvalue.rs

+32-21
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,34 @@ use build::expr::category::{Category, RvalueFunc};
2121
use hair::*;
2222
use rustc_const_math::{ConstInt, ConstIsize};
2323
use rustc::middle::const_val::ConstVal;
24+
use rustc::middle::region::CodeExtent;
2425
use rustc::ty;
2526
use rustc::mir::*;
2627
use syntax::ast;
2728
use syntax_pos::Span;
2829

2930
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
31+
/// See comment on `as_local_operand`
32+
pub fn as_local_rvalue<M>(&mut self, block: BasicBlock, expr: M)
33+
-> BlockAnd<Rvalue<'tcx>>
34+
where M: Mirror<'tcx, Output = Expr<'tcx>>
35+
{
36+
let topmost_scope = self.topmost_scope(); // FIXME(#6393)
37+
self.as_rvalue(block, Some(topmost_scope), expr)
38+
}
39+
3040
/// Compile `expr`, yielding an rvalue.
31-
pub fn as_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>>
41+
pub fn as_rvalue<M>(&mut self, block: BasicBlock, scope: Option<CodeExtent>, expr: M)
42+
-> BlockAnd<Rvalue<'tcx>>
3243
where M: Mirror<'tcx, Output = Expr<'tcx>>
3344
{
3445
let expr = self.hir.mirror(expr);
35-
self.expr_as_rvalue(block, expr)
46+
self.expr_as_rvalue(block, scope, expr)
3647
}
3748

3849
fn expr_as_rvalue(&mut self,
3950
mut block: BasicBlock,
51+
scope: Option<CodeExtent>,
4052
expr: Expr<'tcx>)
4153
-> BlockAnd<Rvalue<'tcx>> {
4254
debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr);
@@ -47,24 +59,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
4759

4860
match expr.kind {
4961
ExprKind::Scope { extent, value } => {
50-
this.in_scope(extent, block, |this| this.as_rvalue(block, value))
62+
this.in_scope(extent, block, |this| this.as_rvalue(block, scope, value))
5163
}
5264
ExprKind::Repeat { value, count } => {
53-
let value_operand = unpack!(block = this.as_operand(block, value));
65+
let value_operand = unpack!(block = this.as_operand(block, scope, value));
5466
block.and(Rvalue::Repeat(value_operand, count))
5567
}
5668
ExprKind::Borrow { region, borrow_kind, arg } => {
5769
let arg_lvalue = unpack!(block = this.as_lvalue(block, arg));
5870
block.and(Rvalue::Ref(region, borrow_kind, arg_lvalue))
5971
}
6072
ExprKind::Binary { op, lhs, rhs } => {
61-
let lhs = unpack!(block = this.as_operand(block, lhs));
62-
let rhs = unpack!(block = this.as_operand(block, rhs));
73+
let lhs = unpack!(block = this.as_operand(block, scope, lhs));
74+
let rhs = unpack!(block = this.as_operand(block, scope, rhs));
6375
this.build_binary_op(block, op, expr_span, expr.ty,
6476
lhs, rhs)
6577
}
6678
ExprKind::Unary { op, arg } => {
67-
let arg = unpack!(block = this.as_operand(block, arg));
79+
let arg = unpack!(block = this.as_operand(block, scope, arg));
6880
// Check for -MIN on signed integers
6981
if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() {
7082
let bool_ty = this.hir.bool_ty();
@@ -97,27 +109,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
97109
ExprKind::Cast { source } => {
98110
let source = this.hir.mirror(source);
99111

100-
let source = unpack!(block = this.as_operand(block, source));
112+
let source = unpack!(block = this.as_operand(block, scope, source));
101113
block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
102114
}
103115
ExprKind::Use { source } => {
104-
let source = unpack!(block = this.as_operand(block, source));
116+
let source = unpack!(block = this.as_operand(block, scope, source));
105117
block.and(Rvalue::Use(source))
106118
}
107119
ExprKind::ReifyFnPointer { source } => {
108-
let source = unpack!(block = this.as_operand(block, source));
120+
let source = unpack!(block = this.as_operand(block, scope, source));
109121
block.and(Rvalue::Cast(CastKind::ReifyFnPointer, source, expr.ty))
110122
}
111123
ExprKind::UnsafeFnPointer { source } => {
112-
let source = unpack!(block = this.as_operand(block, source));
124+
let source = unpack!(block = this.as_operand(block, scope, source));
113125
block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty))
114126
}
115127
ExprKind::ClosureFnPointer { source } => {
116-
let source = unpack!(block = this.as_operand(block, source));
128+
let source = unpack!(block = this.as_operand(block, scope, source));
117129
block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty))
118130
}
119131
ExprKind::Unsize { source } => {
120-
let source = unpack!(block = this.as_operand(block, source));
132+
let source = unpack!(block = this.as_operand(block, scope, source));
121133
block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty))
122134
}
123135
ExprKind::Array { fields } => {
@@ -151,7 +163,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
151163
let el_ty = expr.ty.sequence_element_type(this.hir.tcx());
152164
let fields: Vec<_> =
153165
fields.into_iter()
154-
.map(|f| unpack!(block = this.as_operand(block, f)))
166+
.map(|f| unpack!(block = this.as_operand(block, scope, f)))
155167
.collect();
156168

157169
block.and(Rvalue::Aggregate(AggregateKind::Array(el_ty), fields))
@@ -160,15 +172,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
160172
// first process the set of fields
161173
let fields: Vec<_> =
162174
fields.into_iter()
163-
.map(|f| unpack!(block = this.as_operand(block, f)))
175+
.map(|f| unpack!(block = this.as_operand(block, scope, f)))
164176
.collect();
165177

166178
block.and(Rvalue::Aggregate(AggregateKind::Tuple, fields))
167179
}
168180
ExprKind::Closure { closure_id, substs, upvars } => { // see (*) above
169181
let upvars =
170182
upvars.into_iter()
171-
.map(|upvar| unpack!(block = this.as_operand(block, upvar)))
183+
.map(|upvar| unpack!(block = this.as_operand(block, scope, upvar)))
172184
.collect();
173185
block.and(Rvalue::Aggregate(AggregateKind::Closure(closure_id, substs), upvars))
174186
}
@@ -180,10 +192,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
180192

181193
// first process the set of fields that were provided
182194
// (evaluating them in order given by user)
183-
let fields_map: FxHashMap<_, _> =
184-
fields.into_iter()
185-
.map(|f| (f.name, unpack!(block = this.as_operand(block, f.expr))))
186-
.collect();
195+
let fields_map: FxHashMap<_, _> = fields.into_iter()
196+
.map(|f| (f.name, unpack!(block = this.as_operand(block, scope, f.expr))))
197+
.collect();
187198

188199
let field_names = this.hir.all_fields(adt_def, variant_index);
189200

@@ -236,7 +247,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
236247
Some(Category::Rvalue(RvalueFunc::AsRvalue)) => false,
237248
_ => true,
238249
});
239-
let operand = unpack!(block = this.as_operand(block, expr));
250+
let operand = unpack!(block = this.as_operand(block, scope, expr));
240251
block.and(Rvalue::Use(operand))
241252
}
242253
}

src/librustc_mir/build/expr/as_temp.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,38 @@
1313
use build::{BlockAnd, BlockAndExtension, Builder};
1414
use build::expr::category::Category;
1515
use hair::*;
16+
use rustc::middle::region::CodeExtent;
1617
use rustc::mir::*;
1718

1819
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1920
/// Compile `expr` into a fresh temporary. This is used when building
2021
/// up rvalues so as to freeze the value that will be consumed.
21-
pub fn as_temp<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Lvalue<'tcx>>
22+
pub fn as_temp<M>(&mut self,
23+
block: BasicBlock,
24+
temp_lifetime: Option<CodeExtent>,
25+
expr: M)
26+
-> BlockAnd<Lvalue<'tcx>>
2227
where M: Mirror<'tcx, Output = Expr<'tcx>>
2328
{
2429
let expr = self.hir.mirror(expr);
25-
self.expr_as_temp(block, expr)
30+
self.expr_as_temp(block, temp_lifetime, expr)
2631
}
2732

28-
fn expr_as_temp(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<Lvalue<'tcx>> {
33+
fn expr_as_temp(&mut self,
34+
mut block: BasicBlock,
35+
temp_lifetime: Option<CodeExtent>,
36+
expr: Expr<'tcx>)
37+
-> BlockAnd<Lvalue<'tcx>> {
2938
debug!("expr_as_temp(block={:?}, expr={:?})", block, expr);
3039
let this = self;
3140

32-
if let ExprKind::Scope { extent, value } = expr.kind {
33-
return this.in_scope(extent, block, |this| this.as_temp(block, value));
41+
if let ExprKind::Scope { .. } = expr.kind {
42+
span_bug!(expr.span, "unexpected scope expression in as_temp: {:?}",
43+
expr);
3444
}
3545

3646
let expr_ty = expr.ty.clone();
3747
let temp = this.temp(expr_ty.clone());
38-
let temp_lifetime = expr.temp_lifetime;
3948
let expr_span = expr.span;
4049
let source_info = this.source_info(expr_span);
4150

src/librustc_mir/build/expr/into.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
5252
_ => false,
5353
};
5454

55-
unpack!(block = this.as_rvalue(block, source));
55+
unpack!(block = this.as_local_rvalue(block, source));
5656

5757
// This is an optimization. If the expression was a call then we already have an
5858
// unreachable block. Don't bother to terminate it and create a new one.
@@ -65,7 +65,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
6565
}
6666
}
6767
ExprKind::If { condition: cond_expr, then: then_expr, otherwise: else_expr } => {
68-
let operand = unpack!(block = this.as_operand(block, cond_expr));
68+
let operand = unpack!(block = this.as_local_operand(block, cond_expr));
6969

7070
let mut then_block = this.cfg.start_new_block();
7171
let mut else_block = this.cfg.start_new_block();
@@ -107,15 +107,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
107107
(this.cfg.start_new_block(), this.cfg.start_new_block(),
108108
this.cfg.start_new_block(), this.cfg.start_new_block());
109109

110-
let lhs = unpack!(block = this.as_operand(block, lhs));
110+
let lhs = unpack!(block = this.as_local_operand(block, lhs));
111111
let blocks = match op {
112112
LogicalOp::And => (else_block, false_block),
113113
LogicalOp::Or => (true_block, else_block),
114114
};
115115
let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
116116
this.cfg.terminate(block, source_info, term);
117117

118-
let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
118+
let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
119119
let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
120120
this.cfg.terminate(else_block, source_info, term);
121121

@@ -173,7 +173,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
173173
if let Some(cond_expr) = opt_cond_expr {
174174
let loop_block_end;
175175
let cond = unpack!(
176-
loop_block_end = this.as_operand(loop_block, cond_expr));
176+
loop_block_end = this.as_local_operand(loop_block, cond_expr));
177177
body_block = this.cfg.start_new_block();
178178
let term = TerminatorKind::if_(this.hir.tcx(), cond,
179179
body_block, exit_block);
@@ -206,10 +206,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
206206
}
207207
_ => false
208208
};
209-
let fun = unpack!(block = this.as_operand(block, fun));
209+
let fun = unpack!(block = this.as_local_operand(block, fun));
210210
let args: Vec<_> =
211211
args.into_iter()
212-
.map(|arg| unpack!(block = this.as_operand(block, arg)))
212+
.map(|arg| unpack!(block = this.as_local_operand(block, arg)))
213213
.collect();
214214

215215
let success = this.cfg.start_new_block();
@@ -265,7 +265,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
265265
_ => true,
266266
});
267267

268-
let rvalue = unpack!(block = this.as_rvalue(block, expr));
268+
let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
269269
this.cfg.push_assign(block, source_info, destination, rvalue);
270270
block.unit()
271271
}

0 commit comments

Comments
 (0)