Skip to content

Commit ae5553d

Browse files
committed
Fix MIR CopyPropagation errneously propagating assignments to function arguments
1 parent c0d326f commit ae5553d

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed

src/librustc_mir/transform/copy_prop.rs

+7
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ impl MirPass for CopyPropagation {
9999
dest_local);
100100
continue
101101
}
102+
// Conservatively gives up if the dest is an argument,
103+
// because there may be uses of the original argument value.
104+
if mir.local_kind(dest_local) == LocalKind::Arg {
105+
debug!(" Can't copy-propagate local: dest {:?} (argument)",
106+
dest_local);
107+
continue;
108+
}
102109
let dest_lvalue_def = dest_use_info.defs_and_uses.iter().filter(|lvalue_def| {
103110
lvalue_def.context.is_mutating_use() && !lvalue_def.context.is_drop()
104111
}).next().unwrap();
+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Check that CopyPropagation does not propagate an assignment to a function argument
12+
// (doing so can break usages of the original argument value)
13+
14+
fn dummy(x: u8) -> u8 {
15+
x
16+
}
17+
18+
fn foo(mut x: u8) {
19+
// calling `dummy` to make an use of `x` that copyprop cannot eliminate
20+
x = dummy(x); // this will assign a local to `x`
21+
}
22+
23+
fn bar(mut x: u8) {
24+
dummy(x);
25+
x = 5;
26+
}
27+
28+
fn baz(mut x: i32) {
29+
// self-assignment to a function argument should be eliminated
30+
x = x;
31+
}
32+
33+
fn main() {
34+
// Make sure the function actually gets instantiated.
35+
foo(0);
36+
bar(0);
37+
}
38+
39+
// END RUST SOURCE
40+
// START rustc.foo.CopyPropagation.before.mir
41+
// bb0: {
42+
// StorageLive(_2);
43+
// StorageLive(_3);
44+
// _3 = _1;
45+
// _2 = const dummy(_3) -> bb1;
46+
// }
47+
// bb1: {
48+
// StorageDead(_3);
49+
// _1 = _2;
50+
// StorageDead(_2);
51+
// _0 = ();
52+
// return;
53+
// }
54+
// END rustc.foo.CopyPropagation.before.mir
55+
// START rustc.foo.CopyPropagation.after.mir
56+
// bb0: {
57+
// StorageLive(_2);
58+
// nop;
59+
// nop;
60+
// _2 = const dummy(_1) -> bb1;
61+
// }
62+
// bb1: {
63+
// nop;
64+
// _1 = _2;
65+
// StorageDead(_2);
66+
// _0 = ();
67+
// return;
68+
// }
69+
// END rustc.foo.CopyPropagation.after.mir
70+
// START rustc.bar.CopyPropagation.before.mir
71+
// bb0: {
72+
// StorageLive(_3);
73+
// _3 = _1;
74+
// _2 = const dummy(_3) -> bb1;
75+
// }
76+
// bb1: {
77+
// StorageDead(_3);
78+
// _1 = const 5u8;
79+
// _0 = ();
80+
// return;
81+
// }
82+
// END rustc.bar.CopyPropagation.before.mir
83+
// START rustc.bar.CopyPropagation.after.mir
84+
// bb0: {
85+
// nop;
86+
// nop;
87+
// _2 = const dummy(_1) -> bb1;
88+
// }
89+
// bb1: {
90+
// nop;
91+
// _1 = const 5u8;
92+
// _0 = ();
93+
// return;
94+
// }
95+
// END rustc.bar.CopyPropagation.after.mir
96+
// START rustc.baz.CopyPropagation.before.mir
97+
// bb0: {
98+
// StorageLive(_2);
99+
// _2 = _1;
100+
// _1 = _2;
101+
// StorageDead(_2);
102+
// _0 = ();
103+
// return;
104+
// }
105+
// END rustc.baz.CopyPropagation.before.mir
106+
// START rustc.baz.CopyPropagation.after.mir
107+
// bb0: {
108+
// nop;
109+
// nop;
110+
// nop;
111+
// nop;
112+
// _0 = ();
113+
// return;
114+
// }
115+
// END rustc.baz.CopyPropagation.after.mir

0 commit comments

Comments
 (0)