Skip to content

Commit 306dbaf

Browse files
authored
Rollup merge of #107662 - cjgillot:copy-projection, r=oli-obk
Turn projections into copies in CopyProp. The current implementation can leave behind projections that are moved out several times. This PR widens the check to turn such moves into copies: a move out of a projection of a copy is equivalent to a copy of the original projection.
2 parents 917662a + 9c5add1 commit 306dbaf

File tree

4 files changed

+69
-3
lines changed

4 files changed

+69
-3
lines changed

Diff for: compiler/rustc_mir_transform/src/copy_prop.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,9 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
153153

154154
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
155155
if let Operand::Move(place) = *operand
156-
&& let Some(local) = place.as_local()
157-
&& !self.fully_moved.contains(local)
156+
// A move out of a projection of a copy is equivalent to a copy of the original projection.
157+
&& !place.has_deref()
158+
&& !self.fully_moved.contains(place.local)
158159
{
159160
*operand = Operand::Copy(place);
160161
}
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
- // MIR for `f` before CopyProp
2+
+ // MIR for `f` after CopyProp
3+
4+
fn f(_1: Foo) -> bool {
5+
let mut _0: bool; // return place in scope 0 at $DIR/move_projection.rs:+0:17: +0:21
6+
let mut _2: Foo; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
7+
let mut _3: u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
8+
9+
bb0: {
10+
- _2 = _1; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
11+
- _3 = move (_2.0: u8); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
12+
- _0 = opaque::<Foo>(move _1) -> bb1; // scope 0 at $DIR/move_projection.rs:+6:13: +6:44
13+
+ _3 = (_1.0: u8); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
14+
+ _0 = opaque::<Foo>(_1) -> bb1; // scope 0 at $DIR/move_projection.rs:+6:13: +6:44
15+
// mir::Constant
16+
// + span: $DIR/move_projection.rs:19:28: 19:34
17+
// + literal: Const { ty: fn(Foo) -> bool {opaque::<Foo>}, val: Value(<ZST>) }
18+
}
19+
20+
bb1: {
21+
_0 = opaque::<u8>(move _3) -> bb2; // scope 0 at $DIR/move_projection.rs:+9:13: +9:44
22+
// mir::Constant
23+
// + span: $DIR/move_projection.rs:22:28: 22:34
24+
// + literal: Const { ty: fn(u8) -> bool {opaque::<u8>}, val: Value(<ZST>) }
25+
}
26+
27+
bb2: {
28+
return; // scope 0 at $DIR/move_projection.rs:+12:13: +12:21
29+
}
30+
}
31+

Diff for: tests/mir-opt/copy-prop/move_projection.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// unit-test: CopyProp
2+
3+
#![feature(custom_mir, core_intrinsics)]
4+
#![allow(unused_assignments)]
5+
extern crate core;
6+
use core::intrinsics::mir::*;
7+
8+
fn opaque(_: impl Sized) -> bool { true }
9+
10+
struct Foo(u8);
11+
12+
#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
13+
fn f(a: Foo) -> bool {
14+
mir!(
15+
{
16+
let b = a;
17+
// This is a move out of a copy, so must become a copy of `a.0`.
18+
let c = Move(b.0);
19+
Call(RET, bb1, opaque(Move(a)))
20+
}
21+
bb1 = {
22+
Call(RET, ret, opaque(Move(c)))
23+
}
24+
ret = {
25+
Return()
26+
}
27+
)
28+
}
29+
30+
fn main() {
31+
assert!(f(Foo(0)));
32+
}
33+
34+
// EMIT_MIR move_projection.f.CopyProp.diff

Diff for: tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ fn ezmap(_1: Option<i32>) -> Option<i32> {
3434
}
3535

3636
bb3: {
37-
_4 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
37+
_4 = ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
3838
StorageLive(_5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
3939
_5 = Add(_4, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
4040
_0 = Option::<i32>::Some(move _5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30

0 commit comments

Comments
 (0)