diff options
Diffstat (limited to 'src/test/ui/mir-dataflow')
-rw-r--r-- | src/test/ui/mir-dataflow/README.md | 53 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/def-inits-1.rs | 51 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/def-inits-1.stderr | 28 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/inits-1.rs | 53 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/inits-1.stderr | 22 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/liveness-enum.rs | 22 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/liveness-enum.stderr | 10 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/liveness-projection.rs | 32 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/liveness-projection.stderr | 16 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/liveness-ptr.rs | 28 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/liveness-ptr.stderr | 10 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/uninits-1.rs | 51 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/uninits-1.stderr | 34 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/uninits-2.rs | 24 | ||||
-rw-r--r-- | src/test/ui/mir-dataflow/uninits-2.stderr | 10 |
15 files changed, 444 insertions, 0 deletions
diff --git a/src/test/ui/mir-dataflow/README.md b/src/test/ui/mir-dataflow/README.md new file mode 100644 index 000000000..a3ab14b23 --- /dev/null +++ b/src/test/ui/mir-dataflow/README.md @@ -0,0 +1,53 @@ +This directory contains unit tests for the MIR-based dataflow +analysis. + +These unit tests check the dataflow analysis by embedding calls to a +special `rustc_peek` intrinsic within the code, in tandem with an +attribute `#[rustc_mir(rustc_peek_maybe_init)]` (\*). With that +attribute in place, `rustc_peek` calls are a signal to the compiler to +lookup the computed dataflow state for the Lvalue corresponding to the +argument expression being fed to `rustc_peek`. If the dataflow state +for that Lvalue is a 1-bit at that point in the control flow, then no +error is emitted by the compiler at that point; if it is a 0-bit, then +that invocation of `rustc_peek` will emit an error with the message +"rustc_peek: bit not set". + +(\*): Or `#[rustc_mir(rustc_peek_maybe_uninit)]`, and perhaps other +variants in the future. + +The end effect is that one can write unit tests for MIR dataflow that +perform simple-queries of the computed dataflow state, and the tests +should be able to be robust in the face of changes to how MIR is +represented or constructed. + +---- + +Sometimes understanding the dataflow results is difficult without +looking at the actual MIR control-flow graph being processed with the +corresponding GEN and KILL sets. + +For a graphviz-rendering with dataflow annotations, add the attribute +`#[rustc_mir(borrowck_graphviz_postflow="/path/to/suffix.dot")]` to +the function in question. (You can change the content of +`"suffix.dot"` to control the filenames used for the output). This +will generate a separate file for each dataflow analysis, adding a +prefix (corresponding to the name of the analysis) to the filename in +each generated output path. + + * For example, the above attribute will currently cause two files to + be generated: `/path/to/maybe_init_suffix.dot` and + `/path/to/maybe_uninit_suffix.dot`. + + * The generated `.dot` file shows both the computed dataflow results + on *entry* to each block, as well as the gen- and kill-sets that + were so-called "transfer functions" summarizing the effect of each + basic block. + + * (In addition to the `borrowck_graphviz_postflow` attribute-key + noted above, there is also `borrowck_graphviz_preflow`; it has the + same interface and generates the same set of files, but it renders + the dataflow state after building the gen- and kill-sets but + *before* running the dataflow analysis itself, so each entry-set is + just the initial default state for that dataflow analysis. This is + less useful for understanding the error message output in these + tests.) diff --git a/src/test/ui/mir-dataflow/def-inits-1.rs b/src/test/ui/mir-dataflow/def-inits-1.rs new file mode 100644 index 000000000..30460824a --- /dev/null +++ b/src/test/ui/mir-dataflow/def-inits-1.rs @@ -0,0 +1,51 @@ +// General test of maybe_uninits state computed by MIR dataflow. + +#![feature(core_intrinsics, rustc_attrs)] + +use std::intrinsics::rustc_peek; +use std::mem::{drop, replace}; + +struct S(i32); + +#[rustc_mir(rustc_peek_definite_init,stop_after_dataflow)] +fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S { + let ret; + // `ret` starts off uninitialized + rustc_peek(&ret); //~ ERROR rustc_peek: bit not set + + // All function formal parameters start off initialized. + + rustc_peek(&x); + rustc_peek(&y); + rustc_peek(&z); + + ret = if test { + ::std::mem::replace(x, y) + } else { + z = y; + z + }; + + // `z` may be uninitialized here. + rustc_peek(&z); //~ ERROR rustc_peek: bit not set + + // `y` is definitely uninitialized here. + rustc_peek(&y); //~ ERROR rustc_peek: bit not set + + // `x` is still (definitely) initialized (replace above is a reborrow). + rustc_peek(&x); + + ::std::mem::drop(x); + + // `x` is *definitely* uninitialized here + rustc_peek(&x); //~ ERROR rustc_peek: bit not set + + // `ret` is now definitely initialized (via `if` above). + rustc_peek(&ret); + + ret +} +fn main() { + foo(true, &mut S(13), S(14), S(15)); + foo(false, &mut S(13), S(14), S(15)); +} diff --git a/src/test/ui/mir-dataflow/def-inits-1.stderr b/src/test/ui/mir-dataflow/def-inits-1.stderr new file mode 100644 index 000000000..e2bddb54d --- /dev/null +++ b/src/test/ui/mir-dataflow/def-inits-1.stderr @@ -0,0 +1,28 @@ +error: rustc_peek: bit not set + --> $DIR/def-inits-1.rs:14:5 + | +LL | rustc_peek(&ret); + | ^^^^^^^^^^^^^^^^ + +error: rustc_peek: bit not set + --> $DIR/def-inits-1.rs:30:5 + | +LL | rustc_peek(&z); + | ^^^^^^^^^^^^^^ + +error: rustc_peek: bit not set + --> $DIR/def-inits-1.rs:33:5 + | +LL | rustc_peek(&y); + | ^^^^^^^^^^^^^^ + +error: rustc_peek: bit not set + --> $DIR/def-inits-1.rs:41:5 + | +LL | rustc_peek(&x); + | ^^^^^^^^^^^^^^ + +error: stop_after_dataflow ended compilation + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/mir-dataflow/inits-1.rs b/src/test/ui/mir-dataflow/inits-1.rs new file mode 100644 index 000000000..8fb1d4bc7 --- /dev/null +++ b/src/test/ui/mir-dataflow/inits-1.rs @@ -0,0 +1,53 @@ +// General test of maybe_inits state computed by MIR dataflow. + +#![feature(core_intrinsics, rustc_attrs)] + +use std::intrinsics::rustc_peek; +use std::mem::{drop, replace}; + +struct S(i32); + +#[rustc_mir(rustc_peek_maybe_init,stop_after_dataflow)] +fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S { + let ret; + // `ret` starts off uninitialized, so we get an error report here. + rustc_peek(&ret); //~ ERROR rustc_peek: bit not set + + // All function formal parameters start off initialized. + + rustc_peek(&x); + rustc_peek(&y); + rustc_peek(&z); + + ret = if test { + ::std::mem::replace(x, y) + } else { + z = y; + z + }; + + + // `z` may be initialized here. + rustc_peek(&z); + + // `y` is definitely uninitialized here. + rustc_peek(&y); //~ ERROR rustc_peek: bit not set + + // `x` is still (definitely) initialized (replace above is a reborrow). + rustc_peek(&x); + + ::std::mem::drop(x); + + // `x` is *definitely* uninitialized here + rustc_peek(&x); //~ ERROR rustc_peek: bit not set + + // `ret` is now definitely initialized (via `if` above). + rustc_peek(&ret); + + ret +} + +fn main() { + foo(true, &mut S(13), S(14), S(15)); + foo(false, &mut S(13), S(14), S(15)); +} diff --git a/src/test/ui/mir-dataflow/inits-1.stderr b/src/test/ui/mir-dataflow/inits-1.stderr new file mode 100644 index 000000000..7a00a70af --- /dev/null +++ b/src/test/ui/mir-dataflow/inits-1.stderr @@ -0,0 +1,22 @@ +error: rustc_peek: bit not set + --> $DIR/inits-1.rs:14:5 + | +LL | rustc_peek(&ret); + | ^^^^^^^^^^^^^^^^ + +error: rustc_peek: bit not set + --> $DIR/inits-1.rs:34:5 + | +LL | rustc_peek(&y); + | ^^^^^^^^^^^^^^ + +error: rustc_peek: bit not set + --> $DIR/inits-1.rs:42:5 + | +LL | rustc_peek(&x); + | ^^^^^^^^^^^^^^ + +error: stop_after_dataflow ended compilation + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/mir-dataflow/liveness-enum.rs b/src/test/ui/mir-dataflow/liveness-enum.rs new file mode 100644 index 000000000..5eb04ae8c --- /dev/null +++ b/src/test/ui/mir-dataflow/liveness-enum.rs @@ -0,0 +1,22 @@ +#![feature(core_intrinsics, rustc_attrs)] + +use std::intrinsics::rustc_peek; + +#[rustc_mir(rustc_peek_liveness, stop_after_dataflow)] +fn foo() -> Option<i32> { + let mut x = None; + + // `x` is live here since it is used in the next statement... + rustc_peek(x); + + dbg!(x); + + // But not here, since it is overwritten below + rustc_peek(x); //~ ERROR rustc_peek: bit not set + + x = Some(4); + + x +} + +fn main() {} diff --git a/src/test/ui/mir-dataflow/liveness-enum.stderr b/src/test/ui/mir-dataflow/liveness-enum.stderr new file mode 100644 index 000000000..483944d73 --- /dev/null +++ b/src/test/ui/mir-dataflow/liveness-enum.stderr @@ -0,0 +1,10 @@ +error: rustc_peek: bit not set + --> $DIR/liveness-enum.rs:15:5 + | +LL | rustc_peek(x); + | ^^^^^^^^^^^^^ + +error: stop_after_dataflow ended compilation + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/mir-dataflow/liveness-projection.rs b/src/test/ui/mir-dataflow/liveness-projection.rs new file mode 100644 index 000000000..486f31b63 --- /dev/null +++ b/src/test/ui/mir-dataflow/liveness-projection.rs @@ -0,0 +1,32 @@ +#![feature(core_intrinsics, rustc_attrs)] + +use std::intrinsics::rustc_peek; + +#[rustc_mir(rustc_peek_liveness, stop_after_dataflow)] +fn foo() { + { + let mut x: (i32, i32) = (42, 0); + + // Assignment to a projection does not cause `x` to become live + unsafe { rustc_peek(x); } //~ ERROR bit not set + x.1 = 42; + + x = (0, 42); + + // ...but a read from a projection does. + unsafe { rustc_peek(x); } + println!("{}", x.1); + } + + { + let mut x = 42; + + // Derefs are treated like a read of a local even if they are on the LHS of an assignment. + let p = &mut x; + unsafe { rustc_peek(&p); } + *p = 24; + unsafe { rustc_peek(&p); } //~ ERROR bit not set + } +} + +fn main() {} diff --git a/src/test/ui/mir-dataflow/liveness-projection.stderr b/src/test/ui/mir-dataflow/liveness-projection.stderr new file mode 100644 index 000000000..f9480c880 --- /dev/null +++ b/src/test/ui/mir-dataflow/liveness-projection.stderr @@ -0,0 +1,16 @@ +error: rustc_peek: bit not set + --> $DIR/liveness-projection.rs:11:18 + | +LL | unsafe { rustc_peek(x); } + | ^^^^^^^^^^^^^ + +error: rustc_peek: bit not set + --> $DIR/liveness-projection.rs:28:18 + | +LL | unsafe { rustc_peek(&p); } + | ^^^^^^^^^^^^^^ + +error: stop_after_dataflow ended compilation + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/mir-dataflow/liveness-ptr.rs b/src/test/ui/mir-dataflow/liveness-ptr.rs new file mode 100644 index 000000000..786da523a --- /dev/null +++ b/src/test/ui/mir-dataflow/liveness-ptr.rs @@ -0,0 +1,28 @@ +#![feature(core_intrinsics, rustc_attrs)] + +use std::intrinsics::rustc_peek; + +#[rustc_mir(rustc_peek_liveness, stop_after_dataflow)] +fn foo() -> i32 { + let mut x: i32; + let mut p: *const i32; + + x = 0; + + // `x` is live here since it is used in the next statement... + rustc_peek(x); + + p = &x; + + // ... but not here, even while it can be accessed through `p`. + rustc_peek(x); //~ ERROR rustc_peek: bit not set + let tmp = unsafe { *p }; + + x = tmp + 1; + + rustc_peek(x); + + x +} + +fn main() {} diff --git a/src/test/ui/mir-dataflow/liveness-ptr.stderr b/src/test/ui/mir-dataflow/liveness-ptr.stderr new file mode 100644 index 000000000..858cdbac3 --- /dev/null +++ b/src/test/ui/mir-dataflow/liveness-ptr.stderr @@ -0,0 +1,10 @@ +error: rustc_peek: bit not set + --> $DIR/liveness-ptr.rs:18:5 + | +LL | rustc_peek(x); + | ^^^^^^^^^^^^^ + +error: stop_after_dataflow ended compilation + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/mir-dataflow/uninits-1.rs b/src/test/ui/mir-dataflow/uninits-1.rs new file mode 100644 index 000000000..c2b4284a7 --- /dev/null +++ b/src/test/ui/mir-dataflow/uninits-1.rs @@ -0,0 +1,51 @@ +// General test of maybe_uninits state computed by MIR dataflow. + +#![feature(core_intrinsics, rustc_attrs)] + +use std::intrinsics::rustc_peek; +use std::mem::{drop, replace}; + +struct S(i32); + +#[rustc_mir(rustc_peek_maybe_uninit,stop_after_dataflow)] +fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S { + let ret; + // `ret` starts off uninitialized + rustc_peek(&ret); + + // All function formal parameters start off initialized. + + rustc_peek(&x); //~ ERROR rustc_peek: bit not set + rustc_peek(&y); //~ ERROR rustc_peek: bit not set + rustc_peek(&z); //~ ERROR rustc_peek: bit not set + + ret = if test { + ::std::mem::replace(x, y) + } else { + z = y; + z + }; + + // `z` may be uninitialized here. + rustc_peek(&z); + + // `y` is definitely uninitialized here. + rustc_peek(&y); + + // `x` is still (definitely) initialized (replace above is a reborrow). + rustc_peek(&x); //~ ERROR rustc_peek: bit not set + + ::std::mem::drop(x); + + // `x` is *definitely* uninitialized here + rustc_peek(&x); + + // `ret` is now definitely initialized (via `if` above). + rustc_peek(&ret); //~ ERROR rustc_peek: bit not set + + ret +} +fn main() { + foo(true, &mut S(13), S(14), S(15)); + foo(false, &mut S(13), S(14), S(15)); +} diff --git a/src/test/ui/mir-dataflow/uninits-1.stderr b/src/test/ui/mir-dataflow/uninits-1.stderr new file mode 100644 index 000000000..c52f5ac7b --- /dev/null +++ b/src/test/ui/mir-dataflow/uninits-1.stderr @@ -0,0 +1,34 @@ +error: rustc_peek: bit not set + --> $DIR/uninits-1.rs:18:5 + | +LL | rustc_peek(&x); + | ^^^^^^^^^^^^^^ + +error: rustc_peek: bit not set + --> $DIR/uninits-1.rs:19:5 + | +LL | rustc_peek(&y); + | ^^^^^^^^^^^^^^ + +error: rustc_peek: bit not set + --> $DIR/uninits-1.rs:20:5 + | +LL | rustc_peek(&z); + | ^^^^^^^^^^^^^^ + +error: rustc_peek: bit not set + --> $DIR/uninits-1.rs:36:5 + | +LL | rustc_peek(&x); + | ^^^^^^^^^^^^^^ + +error: rustc_peek: bit not set + --> $DIR/uninits-1.rs:44:5 + | +LL | rustc_peek(&ret); + | ^^^^^^^^^^^^^^^^ + +error: stop_after_dataflow ended compilation + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/mir-dataflow/uninits-2.rs b/src/test/ui/mir-dataflow/uninits-2.rs new file mode 100644 index 000000000..c584ee74a --- /dev/null +++ b/src/test/ui/mir-dataflow/uninits-2.rs @@ -0,0 +1,24 @@ +// General test of maybe_uninits state computed by MIR dataflow. + +#![feature(core_intrinsics, rustc_attrs)] + +use std::intrinsics::rustc_peek; +use std::mem::{drop, replace}; + +struct S(i32); + +#[rustc_mir(rustc_peek_maybe_uninit,stop_after_dataflow)] +fn foo(x: &mut S) { + // `x` is initialized here, so maybe-uninit bit is 0. + + rustc_peek(&x); //~ ERROR rustc_peek: bit not set + + ::std::mem::drop(x); + + // `x` definitely uninitialized here, so maybe-uninit bit is 1. + rustc_peek(&x); +} +fn main() { + foo(&mut S(13)); + foo(&mut S(13)); +} diff --git a/src/test/ui/mir-dataflow/uninits-2.stderr b/src/test/ui/mir-dataflow/uninits-2.stderr new file mode 100644 index 000000000..0ef954e35 --- /dev/null +++ b/src/test/ui/mir-dataflow/uninits-2.stderr @@ -0,0 +1,10 @@ +error: rustc_peek: bit not set + --> $DIR/uninits-2.rs:14:5 + | +LL | rustc_peek(&x); + | ^^^^^^^^^^^^^^ + +error: stop_after_dataflow ended compilation + +error: aborting due to 2 previous errors + |