From 9daf8fd5b1d369cd2f91ac919dc5d17f4fd43c0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 3 Sep 2020 00:00:00 +0000 Subject: [PATCH] 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. --- compiler/rustc_mir/src/transform/inline.rs | 36 ++++++++++++++----- .../inline_any_operand.bar.Inline.after.mir | 4 +++ .../inline_closure.foo.Inline.after.mir | 4 +++ ...e_closure_borrows_arg.foo.Inline.after.mir | 4 +++ ...line_closure_captures.foo.Inline.after.mir | 2 ++ .../ui/mir/issue-71793-inline-args-storage.rs | 16 +++++++++ 6 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/mir/issue-71793-inline-args-storage.rs diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index 428f4e138c7f9..b451ee672f6cb 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -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 { @@ -541,6 +541,7 @@ impl Inliner<'tcx> { args: Vec>, callsite: &CallSite<'tcx>, caller_body: &mut Body<'tcx>, + return_block: BasicBlock, ) -> Vec { let tcx = self.tcx; @@ -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); @@ -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() } } @@ -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. @@ -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 } } diff --git a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir index 9d490f047f735..756f31315f18a 100644 --- a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir @@ -22,9 +22,13 @@ fn bar() -> bool { // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar()) } 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 diff --git a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir index b40a8047c4185..6ecbd3022e389 100644 --- a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir @@ -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 diff --git a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir index f6dd741364039..7475be30c0dff 100644 --- a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir @@ -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 diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir index e2b5d6567c299..0258e3c2e4b38 100644 --- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir @@ -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 @@ -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 diff --git a/src/test/ui/mir/issue-71793-inline-args-storage.rs b/src/test/ui/mir/issue-71793-inline-args-storage.rs new file mode 100644 index 0000000000000..87b2806d4e208 --- /dev/null +++ b/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::::new().first().ok_or("").unwrap(); + connect().await; +}