about summary refs log tree commit diff
diff options
context:
space:
mode:
authorsinkuu <sinkuu@sinkuu.xyz>2017-11-05 22:08:30 +0900
committerShotaro Yamada <sinkuu@sinkuu.xyz>2017-11-10 21:02:43 +0900
commitae5553d7b04d8ece340756f378b82d5e0bbb0ea2 (patch)
tree5039940b5c47e69b3d28899cef6a1608320cad5c
parentc0d326f06d562c3aedf0727a665e9f2c34ba9d0c (diff)
downloadrust-ae5553d7b04d8ece340756f378b82d5e0bbb0ea2.tar.gz
rust-ae5553d7b04d8ece340756f378b82d5e0bbb0ea2.zip
Fix MIR CopyPropagation errneously propagating assignments to function arguments
-rw-r--r--src/librustc_mir/transform/copy_prop.rs7
-rw-r--r--src/test/mir-opt/copy_propagation_arg.rs115
2 files changed, 122 insertions, 0 deletions
diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs
index ac8ebd306d3..3f766629bae 100644
--- a/src/librustc_mir/transform/copy_prop.rs
+++ b/src/librustc_mir/transform/copy_prop.rs
@@ -99,6 +99,13 @@ impl MirPass for CopyPropagation {
                                dest_local);
                         continue
                     }
+                    // Conservatively gives up if the dest is an argument,
+                    // because there may be uses of the original argument value.
+                    if mir.local_kind(dest_local) == LocalKind::Arg {
+                        debug!("  Can't copy-propagate local: dest {:?} (argument)",
+                            dest_local);
+                        continue;
+                    }
                     let dest_lvalue_def = dest_use_info.defs_and_uses.iter().filter(|lvalue_def| {
                         lvalue_def.context.is_mutating_use() && !lvalue_def.context.is_drop()
                     }).next().unwrap();
diff --git a/src/test/mir-opt/copy_propagation_arg.rs b/src/test/mir-opt/copy_propagation_arg.rs
new file mode 100644
index 00000000000..8303407d2e2
--- /dev/null
+++ b/src/test/mir-opt/copy_propagation_arg.rs
@@ -0,0 +1,115 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that CopyPropagation does not propagate an assignment to a function argument
+// (doing so can break usages of the original argument value)
+
+fn dummy(x: u8) -> u8 {
+    x
+}
+
+fn foo(mut x: u8) {
+    // calling `dummy` to make an use of `x` that copyprop cannot eliminate
+    x = dummy(x); // this will assign a local to `x`
+}
+
+fn bar(mut x: u8) {
+    dummy(x);
+    x = 5;
+}
+
+fn baz(mut x: i32) {
+    // self-assignment to a function argument should be eliminated
+    x = x;
+}
+
+fn main() {
+    // Make sure the function actually gets instantiated.
+    foo(0);
+    bar(0);
+}
+
+// END RUST SOURCE
+// START rustc.foo.CopyPropagation.before.mir
+// bb0: {
+//     StorageLive(_2);
+//     StorageLive(_3);
+//     _3 = _1;
+//     _2 = const dummy(_3) -> bb1;
+// }
+// bb1: {
+//     StorageDead(_3);
+//     _1 = _2;
+//     StorageDead(_2);
+//     _0 = ();
+//     return;
+// }
+// END rustc.foo.CopyPropagation.before.mir
+// START rustc.foo.CopyPropagation.after.mir
+// bb0: {
+//     StorageLive(_2);
+//     nop;
+//     nop;
+//     _2 = const dummy(_1) -> bb1;
+// }
+// bb1: {
+//     nop;
+//     _1 = _2;
+//     StorageDead(_2);
+//     _0 = ();
+//     return;
+// }
+// END rustc.foo.CopyPropagation.after.mir
+// START rustc.bar.CopyPropagation.before.mir
+// bb0: {
+//     StorageLive(_3);
+//     _3 = _1;
+//     _2 = const dummy(_3) -> bb1;
+// }
+// bb1: {
+//     StorageDead(_3);
+//     _1 = const 5u8;
+//     _0 = ();
+//     return;
+// }
+// END rustc.bar.CopyPropagation.before.mir
+// START rustc.bar.CopyPropagation.after.mir
+// bb0: {
+//     nop;
+//     nop;
+//     _2 = const dummy(_1) -> bb1;
+// }
+// bb1: {
+//     nop;
+//     _1 = const 5u8;
+//     _0 = ();
+//     return;
+// }
+// END rustc.bar.CopyPropagation.after.mir
+// START rustc.baz.CopyPropagation.before.mir
+// bb0: {
+//     StorageLive(_2);
+//     _2 = _1;
+//     _1 = _2;
+//     StorageDead(_2);
+//     _0 = ();
+//     return;
+// }
+// END rustc.baz.CopyPropagation.before.mir
+// START rustc.baz.CopyPropagation.after.mir
+// bb0: {
+//     nop;
+//     nop;
+//     nop;
+//     nop;
+//     _0 = ();
+//     return;
+// }
+// END rustc.baz.CopyPropagation.after.mir
\ No newline at end of file