Skip to content

Commit 9daf8fd

Browse files
committed
inliner: Emit storage markers for introduced arg temporaries
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.
1 parent 08deb86 commit 9daf8fd

6 files changed

+58
-8
lines changed

compiler/rustc_mir/src/transform/inline.rs

+28-8
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ impl Inliner<'tcx> {
494494
let return_block = destination.1;
495495

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

499499
let bb_len = caller_body.basic_blocks().len();
500500
let mut integrator = Integrator {
@@ -541,6 +541,7 @@ impl Inliner<'tcx> {
541541
args: Vec<Operand<'tcx>>,
542542
callsite: &CallSite<'tcx>,
543543
caller_body: &mut Body<'tcx>,
544+
return_block: BasicBlock,
544545
) -> Vec<Local> {
545546
let tcx = self.tcx;
546547

@@ -569,8 +570,18 @@ impl Inliner<'tcx> {
569570
// and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
570571
if tcx.is_closure(callsite.callee) {
571572
let mut args = args.into_iter();
572-
let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
573-
let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
573+
let self_ = self.create_temp_if_necessary(
574+
args.next().unwrap(),
575+
callsite,
576+
caller_body,
577+
return_block,
578+
);
579+
let tuple = self.create_temp_if_necessary(
580+
args.next().unwrap(),
581+
callsite,
582+
caller_body,
583+
return_block,
584+
);
574585
assert!(args.next().is_none());
575586

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

592603
// Spill to a local to make e.g., `tmp0`.
593-
self.create_temp_if_necessary(tuple_field, callsite, caller_body)
604+
self.create_temp_if_necessary(tuple_field, callsite, caller_body, return_block)
594605
});
595606

596607
closure_ref_arg.chain(tuple_tmp_args).collect()
597608
} else {
598609
args.into_iter()
599-
.map(|a| self.create_temp_if_necessary(a, callsite, caller_body))
610+
.map(|a| self.create_temp_if_necessary(a, callsite, caller_body, return_block))
600611
.collect()
601612
}
602613
}
@@ -608,6 +619,7 @@ impl Inliner<'tcx> {
608619
arg: Operand<'tcx>,
609620
callsite: &CallSite<'tcx>,
610621
caller_body: &mut Body<'tcx>,
622+
return_block: BasicBlock,
611623
) -> Local {
612624
// FIXME: Analysis of the usage of the arguments to avoid
613625
// unnecessary temporaries.
@@ -630,11 +642,19 @@ impl Inliner<'tcx> {
630642
let arg_tmp = LocalDecl::new(ty, callsite.location.span);
631643
let arg_tmp = caller_body.local_decls.push(arg_tmp);
632644

633-
let stmt = Statement {
645+
caller_body[callsite.bb].statements.push(Statement {
646+
source_info: callsite.location,
647+
kind: StatementKind::StorageLive(arg_tmp),
648+
});
649+
caller_body[callsite.bb].statements.push(Statement {
634650
source_info: callsite.location,
635651
kind: StatementKind::Assign(box (Place::from(arg_tmp), arg)),
636-
};
637-
caller_body[callsite.bb].statements.push(stmt);
652+
});
653+
caller_body[return_block].statements.insert(
654+
0,
655+
Statement { source_info: callsite.location, kind: StatementKind::StorageDead(arg_tmp) },
656+
);
657+
638658
arg_tmp
639659
}
640660
}

src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir

+4
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@ fn bar() -> bool {
2222
// + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar(<ZST>)) }
2323
StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
2424
_2 = _1; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
25+
StorageLive(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
2526
_3 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
27+
StorageLive(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
2628
_4 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
2729
_0 = Eq(move _3, move _4); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:11
30+
StorageDead(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
31+
StorageDead(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
2832
StorageDead(_2); // scope 1 at $DIR/inline-any-operand.rs:12:12: 12:13
2933
StorageDead(_1); // scope 0 at $DIR/inline-any-operand.rs:13:1: 13:2
3034
return; // scope 0 at $DIR/inline-any-operand.rs:13:2: 13:2

src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir

+4
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@ fn foo(_1: T, _2: i32) -> i32 {
3030
_7 = _2; // scope 1 at $DIR/inline-closure.rs:12:10: 12:11
3131
(_5.0: i32) = move _6; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
3232
(_5.1: i32) = move _7; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
33+
StorageLive(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
3334
_8 = move (_5.0: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
35+
StorageLive(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
3436
_9 = move (_5.1: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
3537
_0 = _8; // scope 2 at $DIR/inline-closure.rs:11:22: 11:24
38+
StorageDead(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
39+
StorageDead(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
3640
StorageDead(_7); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12
3741
StorageDead(_6); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12
3842
StorageDead(_5); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12

src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir

+4
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,13 @@ fn foo(_1: T, _2: &i32) -> i32 {
3333
_7 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11
3434
(_5.0: &i32) = move _6; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
3535
(_5.1: &i32) = move _7; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
36+
StorageLive(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
3637
_8 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
38+
StorageLive(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
3739
_9 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
3840
_0 = (*_8); // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18
41+
StorageDead(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
42+
StorageDead(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
3943
StorageDead(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12
4044
StorageDead(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12
4145
StorageDead(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12

src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
3838
StorageLive(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
3939
_8 = _2; // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
4040
(_7.0: i32) = move _8; // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
41+
StorageLive(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
4142
_11 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
4243
StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
4344
_9 = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
@@ -47,6 +48,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
4748
(_0.1: T) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
4849
StorageDead(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24
4950
StorageDead(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24
51+
StorageDead(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
5052
StorageDead(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
5153
StorageDead(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
5254
StorageDead(_6); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Verifies that inliner emits StorageLive & StorageDead when introducing
2+
// temporaries for arguments, so that they don't become part of the generator.
3+
// Regression test for #71793.
4+
//
5+
// check-pass
6+
// edition:2018
7+
// compile-args: -Zmir-opt-level=2
8+
9+
#![crate_type = "lib"]
10+
11+
pub async fn connect() {}
12+
13+
pub async fn connect_many() {
14+
Vec::<String>::new().first().ok_or("").unwrap();
15+
connect().await;
16+
}

0 commit comments

Comments
 (0)