Skip to content

Commit cddc4a6

Browse files
committed
Auto merge of #46975 - matthewjasper:mir-moveck-asm, r=arielb1
[MIR Borrowck] Moveck inline asm statements Closes #45695 New behavior: * Input operands to `asm!` are moved, direct output operands are initialized. * Direct, non-read-write outputs match the assignment changes in #46752 (Shallow writes, end borrows).
2 parents 503153e + 1a308ba commit cddc4a6

File tree

7 files changed

+171
-4
lines changed

7 files changed

+171
-4
lines changed

src/librustc_mir/borrow_check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
392392
self.mutate_place(
393393
context,
394394
(output, span),
395-
Deep,
395+
if o.is_rw { Deep } else { Shallow(None) },
396396
if o.is_rw { WriteAndRead } else { JustWrite },
397397
flow_state,
398398
);

src/librustc_mir/dataflow/impls/borrows.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,20 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
416416
self.kill_borrows_on_local(sets, &local, is_activations)
417417
}
418418

419-
mir::StatementKind::InlineAsm { .. } |
419+
mir::StatementKind::InlineAsm { ref outputs, ref asm, .. } => {
420+
for (output, kind) in outputs.iter().zip(&asm.outputs) {
421+
if !kind.is_indirect && !kind.is_rw {
422+
// Make sure there are no remaining borrows for direct
423+
// output variables.
424+
if let Place::Local(ref local) = *output {
425+
// FIXME: Handle the case in which we're assigning over
426+
// a projection (`foo.bar`).
427+
self.kill_borrows_on_local(sets, local, is_activations);
428+
}
429+
}
430+
}
431+
}
432+
420433
mir::StatementKind::SetDiscriminant { .. } |
421434
mir::StatementKind::StorageLive(..) |
422435
mir::StatementKind::Validate(..) |

src/librustc_mir/dataflow/move_paths/builder.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,16 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
278278
}
279279
self.gather_rvalue(rval);
280280
}
281+
StatementKind::InlineAsm { ref outputs, ref inputs, ref asm } => {
282+
for (output, kind) in outputs.iter().zip(&asm.outputs) {
283+
if !kind.is_indirect {
284+
self.gather_init(output, InitKind::Deep);
285+
}
286+
}
287+
for input in inputs {
288+
self.gather_operand(input);
289+
}
290+
}
281291
StatementKind::StorageLive(_) => {}
282292
StatementKind::StorageDead(local) => {
283293
self.gather_move(&Place::Local(local));
@@ -286,7 +296,6 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
286296
span_bug!(stmt.source_info.span,
287297
"SetDiscriminant should not exist during borrowck");
288298
}
289-
StatementKind::InlineAsm { .. } |
290299
StatementKind::EndRegion(_) |
291300
StatementKind::Validate(..) |
292301
StatementKind::Nop => {}

src/test/compile-fail/asm-out-read-uninit.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
// ignore-powerpc
1414
// ignore-sparc
1515

16+
// revisions: ast mir
17+
//[mir]compile-flags: -Z borrowck=mir
18+
1619
#![feature(asm)]
1720

1821
fn foo(x: isize) { println!("{}", x); }
@@ -24,7 +27,9 @@ fn foo(x: isize) { println!("{}", x); }
2427
pub fn main() {
2528
let x: isize;
2629
unsafe {
27-
asm!("mov $1, $0" : "=r"(x) : "r"(x)); //~ ERROR use of possibly uninitialized variable: `x`
30+
asm!("mov $1, $0" : "=r"(x) : "r"(x));
31+
//[ast]~^ ERROR use of possibly uninitialized variable: `x`
32+
//[mir]~^^ ERROR use of possibly uninitialized variable: `x`
2833
}
2934
foo(x);
3035
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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+
// ignore-s390x
12+
// ignore-emscripten
13+
// ignore-powerpc
14+
// ignore-sparc
15+
16+
// revisions: ast mir
17+
//[mir]compile-flags: -Z borrowck=mir -Z nll
18+
19+
#![feature(asm)]
20+
21+
#[cfg(any(target_arch = "x86",
22+
target_arch = "x86_64",
23+
target_arch = "arm",
24+
target_arch = "aarch64"))]
25+
mod test_cases {
26+
fn is_move() {
27+
let y: &mut isize;
28+
let x = &mut 0isize;
29+
unsafe {
30+
asm!("nop" : : "r"(x));
31+
}
32+
let z = x; //[ast]~ ERROR use of moved value: `x`
33+
//[mir]~^ ERROR use of moved value: `x`
34+
}
35+
36+
fn in_is_read() {
37+
let mut x = 3;
38+
let y = &mut x;
39+
unsafe {
40+
asm!("nop" : : "r"(x)); //[ast]~ ERROR cannot use
41+
//[mir]~^ ERROR cannot use
42+
}
43+
let z = y;
44+
}
45+
46+
fn out_is_assign() {
47+
let x = 3;
48+
unsafe {
49+
asm!("nop" : "=r"(x)); //[ast]~ ERROR cannot assign twice
50+
//[mir]~^ ERROR cannot assign twice
51+
}
52+
let mut a = &mut 3;
53+
let b = &*a;
54+
unsafe {
55+
asm!("nop" : "=r"(a)); //[ast]~ ERROR cannot assign to `a` because it is borrowed
56+
// No MIR error, this is a shallow write.
57+
}
58+
let c = b;
59+
let d = *a;
60+
}
61+
62+
fn rw_is_assign() {
63+
let x = 3;
64+
unsafe {
65+
asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign twice
66+
//[mir]~^ ERROR cannot assign twice
67+
}
68+
}
69+
70+
fn indirect_is_not_init() {
71+
let x: i32;
72+
unsafe {
73+
asm!("nop" : "=*r"(x)); //[ast]~ ERROR use of possibly uninitialized variable
74+
//[mir]~^ ERROR use of possibly uninitialized variable
75+
}
76+
}
77+
78+
fn rw_is_read() {
79+
let mut x = &mut 3;
80+
let y = &*x;
81+
unsafe {
82+
asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign to `x` because it is borrowed
83+
//[mir]~^ ERROR cannot assign to `x` because it is borrowed
84+
}
85+
let z = y;
86+
}
87+
88+
fn two_moves() {
89+
let x = &mut 2;
90+
unsafe {
91+
asm!("nop" : : "r"(x), "r"(x) ); //[ast]~ ERROR use of moved value
92+
//[mir]~^ ERROR use of moved value
93+
}
94+
}
95+
}
96+
97+
fn main() {}

src/test/run-pass/asm-in-moved.rs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2012-2015 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+
// revisions: ast mir
12+
//[mir]compile-flags: -Z borrowck=mir
13+
14+
#![feature(asm)]
15+
16+
use std::cell::Cell;
17+
18+
#[repr(C)]
19+
struct NoisyDrop<'a>(&'a Cell<&'static str>);
20+
impl<'a> Drop for NoisyDrop<'a> {
21+
fn drop(&mut self) {
22+
self.0.set("destroyed");
23+
}
24+
}
25+
26+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
27+
fn main() {
28+
let status = Cell::new("alive");
29+
{
30+
let _y: Box<NoisyDrop>;
31+
let x = Box::new(NoisyDrop(&status));
32+
unsafe {
33+
asm!("mov $1, $0" : "=r"(_y) : "r"(x));
34+
}
35+
assert_eq!(status.get(), "alive");
36+
}
37+
assert_eq!(status.get(), "destroyed");
38+
}
39+
40+
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
41+
fn main() {}

src/test/run-pass/asm-out-assign.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// revisions ast mir
12+
//[mir]compile-flags: -Z borrowck=mir
1113

1214
#![feature(asm)]
1315

0 commit comments

Comments
 (0)