Skip to content

Commit 0b65a3d

Browse files
committed
Auto merge of #76123 - tmiasko:inline-args-storage, r=wesleywiser
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. Fixes #71793.
2 parents 1eb00ab + 9daf8fd commit 0b65a3d

6 files changed

+58
-8
lines changed

compiler/rustc_mir/src/transform/inline.rs

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

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

511511
let bb_len = caller_body.basic_blocks().len();
512512
let mut integrator = Integrator {
@@ -553,6 +553,7 @@ impl Inliner<'tcx> {
553553
args: Vec<Operand<'tcx>>,
554554
callsite: &CallSite<'tcx>,
555555
caller_body: &mut Body<'tcx>,
556+
return_block: BasicBlock,
556557
) -> Vec<Local> {
557558
let tcx = self.tcx;
558559

@@ -581,8 +582,18 @@ impl Inliner<'tcx> {
581582
// and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
582583
if tcx.is_closure(callsite.callee) {
583584
let mut args = args.into_iter();
584-
let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
585-
let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
585+
let self_ = self.create_temp_if_necessary(
586+
args.next().unwrap(),
587+
callsite,
588+
caller_body,
589+
return_block,
590+
);
591+
let tuple = self.create_temp_if_necessary(
592+
args.next().unwrap(),
593+
callsite,
594+
caller_body,
595+
return_block,
596+
);
586597
assert!(args.next().is_none());
587598

588599
let tuple = Place::from(tuple);
@@ -602,13 +613,13 @@ impl Inliner<'tcx> {
602613
Operand::Move(tcx.mk_place_field(tuple, Field::new(i), ty.expect_ty()));
603614

604615
// Spill to a local to make e.g., `tmp0`.
605-
self.create_temp_if_necessary(tuple_field, callsite, caller_body)
616+
self.create_temp_if_necessary(tuple_field, callsite, caller_body, return_block)
606617
});
607618

608619
closure_ref_arg.chain(tuple_tmp_args).collect()
609620
} else {
610621
args.into_iter()
611-
.map(|a| self.create_temp_if_necessary(a, callsite, caller_body))
622+
.map(|a| self.create_temp_if_necessary(a, callsite, caller_body, return_block))
612623
.collect()
613624
}
614625
}
@@ -620,6 +631,7 @@ impl Inliner<'tcx> {
620631
arg: Operand<'tcx>,
621632
callsite: &CallSite<'tcx>,
622633
caller_body: &mut Body<'tcx>,
634+
return_block: BasicBlock,
623635
) -> Local {
624636
// FIXME: Analysis of the usage of the arguments to avoid
625637
// unnecessary temporaries.
@@ -642,11 +654,19 @@ impl Inliner<'tcx> {
642654
let arg_tmp = LocalDecl::new(ty, callsite.location.span);
643655
let arg_tmp = caller_body.local_decls.push(arg_tmp);
644656

645-
let stmt = Statement {
657+
caller_body[callsite.bb].statements.push(Statement {
658+
source_info: callsite.location,
659+
kind: StatementKind::StorageLive(arg_tmp),
660+
});
661+
caller_body[callsite.bb].statements.push(Statement {
646662
source_info: callsite.location,
647663
kind: StatementKind::Assign(box (Place::from(arg_tmp), arg)),
648-
};
649-
caller_body[callsite.bb].statements.push(stmt);
664+
});
665+
caller_body[return_block].statements.insert(
666+
0,
667+
Statement { source_info: callsite.location, kind: StatementKind::StorageDead(arg_tmp) },
668+
);
669+
650670
arg_tmp
651671
}
652672
}

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)