From 1a308ba90a1f63233ad4de828085415473a1bc9b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 23 Dec 2017 23:45:07 +0000 Subject: [PATCH] Give MIR borrowck a better understanding of inline asm --- src/librustc_mir/borrow_check/mod.rs | 2 +- src/librustc_mir/dataflow/impls/borrows.rs | 15 ++- .../dataflow/move_paths/builder.rs | 11 ++- src/test/compile-fail/asm-out-read-uninit.rs | 7 +- .../compile-fail/borrowck/borrowck-asm.rs | 97 +++++++++++++++++++ src/test/run-pass/asm-in-moved.rs | 41 ++++++++ src/test/run-pass/asm-out-assign.rs | 2 + 7 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail/borrowck/borrowck-asm.rs create mode 100644 src/test/run-pass/asm-in-moved.rs diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 1e8a67929630e..1b45e63a4d07e 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -392,7 +392,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx self.mutate_place( context, (output, span), - Deep, + if o.is_rw { Deep } else { Shallow(None) }, if o.is_rw { WriteAndRead } else { JustWrite }, flow_state, ); diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index c39ae10371cdd..3722b18a58b0f 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -416,7 +416,20 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { self.kill_borrows_on_local(sets, &local, is_activations) } - mir::StatementKind::InlineAsm { .. } | + mir::StatementKind::InlineAsm { ref outputs, ref asm, .. } => { + for (output, kind) in outputs.iter().zip(&asm.outputs) { + if !kind.is_indirect && !kind.is_rw { + // Make sure there are no remaining borrows for direct + // output variables. + if let Place::Local(ref local) = *output { + // FIXME: Handle the case in which we're assigning over + // a projection (`foo.bar`). + self.kill_borrows_on_local(sets, local, is_activations); + } + } + } + } + mir::StatementKind::SetDiscriminant { .. } | mir::StatementKind::StorageLive(..) | mir::StatementKind::Validate(..) | diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index c20beb7d8c2a7..51dfc018763ca 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -278,6 +278,16 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { } self.gather_rvalue(rval); } + StatementKind::InlineAsm { ref outputs, ref inputs, ref asm } => { + for (output, kind) in outputs.iter().zip(&asm.outputs) { + if !kind.is_indirect { + self.gather_init(output, InitKind::Deep); + } + } + for input in inputs { + self.gather_operand(input); + } + } StatementKind::StorageLive(_) => {} StatementKind::StorageDead(local) => { self.gather_move(&Place::Local(local)); @@ -286,7 +296,6 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { span_bug!(stmt.source_info.span, "SetDiscriminant should not exist during borrowck"); } - StatementKind::InlineAsm { .. } | StatementKind::EndRegion(_) | StatementKind::Validate(..) | StatementKind::Nop => {} diff --git a/src/test/compile-fail/asm-out-read-uninit.rs b/src/test/compile-fail/asm-out-read-uninit.rs index c85a097b962c8..02462bf1be7d7 100644 --- a/src/test/compile-fail/asm-out-read-uninit.rs +++ b/src/test/compile-fail/asm-out-read-uninit.rs @@ -13,6 +13,9 @@ // ignore-powerpc // ignore-sparc +// revisions: ast mir +//[mir]compile-flags: -Z borrowck=mir + #![feature(asm)] fn foo(x: isize) { println!("{}", x); } @@ -24,7 +27,9 @@ fn foo(x: isize) { println!("{}", x); } pub fn main() { let x: isize; unsafe { - asm!("mov $1, $0" : "=r"(x) : "r"(x)); //~ ERROR use of possibly uninitialized variable: `x` + asm!("mov $1, $0" : "=r"(x) : "r"(x)); + //[ast]~^ ERROR use of possibly uninitialized variable: `x` + //[mir]~^^ ERROR use of possibly uninitialized variable: `x` } foo(x); } diff --git a/src/test/compile-fail/borrowck/borrowck-asm.rs b/src/test/compile-fail/borrowck/borrowck-asm.rs new file mode 100644 index 0000000000000..6bccc83868093 --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-asm.rs @@ -0,0 +1,97 @@ +// 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. + +// ignore-s390x +// ignore-emscripten +// ignore-powerpc +// ignore-sparc + +// revisions: ast mir +//[mir]compile-flags: -Z borrowck=mir -Z nll + +#![feature(asm)] + +#[cfg(any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm", + target_arch = "aarch64"))] +mod test_cases { + fn is_move() { + let y: &mut isize; + let x = &mut 0isize; + unsafe { + asm!("nop" : : "r"(x)); + } + let z = x; //[ast]~ ERROR use of moved value: `x` + //[mir]~^ ERROR use of moved value: `x` + } + + fn in_is_read() { + let mut x = 3; + let y = &mut x; + unsafe { + asm!("nop" : : "r"(x)); //[ast]~ ERROR cannot use + //[mir]~^ ERROR cannot use + } + let z = y; + } + + fn out_is_assign() { + let x = 3; + unsafe { + asm!("nop" : "=r"(x)); //[ast]~ ERROR cannot assign twice + //[mir]~^ ERROR cannot assign twice + } + let mut a = &mut 3; + let b = &*a; + unsafe { + asm!("nop" : "=r"(a)); //[ast]~ ERROR cannot assign to `a` because it is borrowed + // No MIR error, this is a shallow write. + } + let c = b; + let d = *a; + } + + fn rw_is_assign() { + let x = 3; + unsafe { + asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign twice + //[mir]~^ ERROR cannot assign twice + } + } + + fn indirect_is_not_init() { + let x: i32; + unsafe { + asm!("nop" : "=*r"(x)); //[ast]~ ERROR use of possibly uninitialized variable + //[mir]~^ ERROR use of possibly uninitialized variable + } + } + + fn rw_is_read() { + let mut x = &mut 3; + let y = &*x; + unsafe { + asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign to `x` because it is borrowed + //[mir]~^ ERROR cannot assign to `x` because it is borrowed + } + let z = y; + } + + fn two_moves() { + let x = &mut 2; + unsafe { + asm!("nop" : : "r"(x), "r"(x) ); //[ast]~ ERROR use of moved value + //[mir]~^ ERROR use of moved value + } + } +} + +fn main() {} diff --git a/src/test/run-pass/asm-in-moved.rs b/src/test/run-pass/asm-in-moved.rs new file mode 100644 index 0000000000000..246dd83fbef29 --- /dev/null +++ b/src/test/run-pass/asm-in-moved.rs @@ -0,0 +1,41 @@ +// Copyright 2012-2015 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. + +// revisions: ast mir +//[mir]compile-flags: -Z borrowck=mir + +#![feature(asm)] + +use std::cell::Cell; + +#[repr(C)] +struct NoisyDrop<'a>(&'a Cell<&'static str>); +impl<'a> Drop for NoisyDrop<'a> { + fn drop(&mut self) { + self.0.set("destroyed"); + } +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn main() { + let status = Cell::new("alive"); + { + let _y: Box; + let x = Box::new(NoisyDrop(&status)); + unsafe { + asm!("mov $1, $0" : "=r"(_y) : "r"(x)); + } + assert_eq!(status.get(), "alive"); + } + assert_eq!(status.get(), "destroyed"); +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +fn main() {} diff --git a/src/test/run-pass/asm-out-assign.rs b/src/test/run-pass/asm-out-assign.rs index d7913b473f85a..6acb9054af5cc 100644 --- a/src/test/run-pass/asm-out-assign.rs +++ b/src/test/run-pass/asm-out-assign.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// revisions ast mir +//[mir]compile-flags: -Z borrowck=mir #![feature(asm)]