From ae5553d7b04d8ece340756f378b82d5e0bbb0ea2 Mon Sep 17 00:00:00 2001 From: sinkuu Date: Sun, 5 Nov 2017 22:08:30 +0900 Subject: [PATCH] Fix MIR CopyPropagation errneously propagating assignments to function arguments --- src/librustc_mir/transform/copy_prop.rs | 7 ++ src/test/mir-opt/copy_propagation_arg.rs | 115 +++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 src/test/mir-opt/copy_propagation_arg.rs diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index ac8ebd306d32..3f766629bae5 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 000000000000..8303407d2e20 --- /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 or the MIT license +// , 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