Skip to content

Commit

Permalink
inliner: Emit storage markers for introduced arg temporaries
Browse files Browse the repository at this point in the history
When introducing argument temporaries during inlining, emit storage
marker statements just before the assignment and in the beginning of
the return block.

This ensures that such temporaries will not be considered live across
yield points after inlining inside a generator.
  • Loading branch information
tmiasko committed Sep 3, 2020
1 parent 08deb86 commit 9daf8fd
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 8 deletions.
36 changes: 28 additions & 8 deletions compiler/rustc_mir/src/transform/inline.rs
Expand Up @@ -494,7 +494,7 @@ impl Inliner<'tcx> {
let return_block = destination.1;

// Copy the arguments if needed.
let args: Vec<_> = self.make_call_args(args, &callsite, caller_body);
let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, return_block);

let bb_len = caller_body.basic_blocks().len();
let mut integrator = Integrator {
Expand Down Expand Up @@ -541,6 +541,7 @@ impl Inliner<'tcx> {
args: Vec<Operand<'tcx>>,
callsite: &CallSite<'tcx>,
caller_body: &mut Body<'tcx>,
return_block: BasicBlock,
) -> Vec<Local> {
let tcx = self.tcx;

Expand Down Expand Up @@ -569,8 +570,18 @@ impl Inliner<'tcx> {
// and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
if tcx.is_closure(callsite.callee) {
let mut args = args.into_iter();
let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
let self_ = self.create_temp_if_necessary(
args.next().unwrap(),
callsite,
caller_body,
return_block,
);
let tuple = self.create_temp_if_necessary(
args.next().unwrap(),
callsite,
caller_body,
return_block,
);
assert!(args.next().is_none());

let tuple = Place::from(tuple);
Expand All @@ -590,13 +601,13 @@ impl Inliner<'tcx> {
Operand::Move(tcx.mk_place_field(tuple, Field::new(i), ty.expect_ty()));

// Spill to a local to make e.g., `tmp0`.
self.create_temp_if_necessary(tuple_field, callsite, caller_body)
self.create_temp_if_necessary(tuple_field, callsite, caller_body, return_block)
});

closure_ref_arg.chain(tuple_tmp_args).collect()
} else {
args.into_iter()
.map(|a| self.create_temp_if_necessary(a, callsite, caller_body))
.map(|a| self.create_temp_if_necessary(a, callsite, caller_body, return_block))
.collect()
}
}
Expand All @@ -608,6 +619,7 @@ impl Inliner<'tcx> {
arg: Operand<'tcx>,
callsite: &CallSite<'tcx>,
caller_body: &mut Body<'tcx>,
return_block: BasicBlock,
) -> Local {
// FIXME: Analysis of the usage of the arguments to avoid
// unnecessary temporaries.
Expand All @@ -630,11 +642,19 @@ impl Inliner<'tcx> {
let arg_tmp = LocalDecl::new(ty, callsite.location.span);
let arg_tmp = caller_body.local_decls.push(arg_tmp);

let stmt = Statement {
caller_body[callsite.bb].statements.push(Statement {
source_info: callsite.location,
kind: StatementKind::StorageLive(arg_tmp),
});
caller_body[callsite.bb].statements.push(Statement {
source_info: callsite.location,
kind: StatementKind::Assign(box (Place::from(arg_tmp), arg)),
};
caller_body[callsite.bb].statements.push(stmt);
});
caller_body[return_block].statements.insert(
0,
Statement { source_info: callsite.location, kind: StatementKind::StorageDead(arg_tmp) },
);

arg_tmp
}
}
Expand Down
Expand Up @@ -22,9 +22,13 @@ fn bar() -> bool {
// + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar(<ZST>)) }
StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
_2 = _1; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
StorageLive(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
_3 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
StorageLive(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
_4 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
_0 = Eq(move _3, move _4); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:11
StorageDead(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
StorageDead(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
StorageDead(_2); // scope 1 at $DIR/inline-any-operand.rs:12:12: 12:13
StorageDead(_1); // scope 0 at $DIR/inline-any-operand.rs:13:1: 13:2
return; // scope 0 at $DIR/inline-any-operand.rs:13:2: 13:2
Expand Down
4 changes: 4 additions & 0 deletions src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir
Expand Up @@ -30,9 +30,13 @@ fn foo(_1: T, _2: i32) -> i32 {
_7 = _2; // scope 1 at $DIR/inline-closure.rs:12:10: 12:11
(_5.0: i32) = move _6; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
(_5.1: i32) = move _7; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
StorageLive(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
_8 = move (_5.0: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
StorageLive(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
_9 = move (_5.1: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
_0 = _8; // scope 2 at $DIR/inline-closure.rs:11:22: 11:24
StorageDead(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
StorageDead(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
StorageDead(_7); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12
StorageDead(_6); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12
StorageDead(_5); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12
Expand Down
Expand Up @@ -33,9 +33,13 @@ fn foo(_1: T, _2: &i32) -> i32 {
_7 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11
(_5.0: &i32) = move _6; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
(_5.1: &i32) = move _7; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
StorageLive(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
_8 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
StorageLive(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
_9 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
_0 = (*_8); // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18
StorageDead(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
StorageDead(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
StorageDead(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12
StorageDead(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12
StorageDead(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12
Expand Down
Expand Up @@ -38,6 +38,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
StorageLive(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
_8 = _2; // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
(_7.0: i32) = move _8; // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
StorageLive(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
_11 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
_9 = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
Expand All @@ -47,6 +48,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
(_0.1: T) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
StorageDead(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24
StorageDead(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24
StorageDead(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
StorageDead(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
StorageDead(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
StorageDead(_6); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
Expand Down
16 changes: 16 additions & 0 deletions src/test/ui/mir/issue-71793-inline-args-storage.rs
@@ -0,0 +1,16 @@
// Verifies that inliner emits StorageLive & StorageDead when introducing
// temporaries for arguments, so that they don't become part of the generator.
// Regression test for #71793.
//
// check-pass
// edition:2018
// compile-args: -Zmir-opt-level=2

#![crate_type = "lib"]

pub async fn connect() {}

pub async fn connect_many() {
Vec::<String>::new().first().ok_or("").unwrap();
connect().await;
}

0 comments on commit 9daf8fd

Please sign in to comment.