about summary refs log tree commit diff
path: root/tests/ui/mir-dataflow
diff options
context:
space:
mode:
authorAlbert Larsan <74931857+albertlarsan68@users.noreply.github.com>2023-01-05 09:13:28 +0100
committerAlbert Larsan <74931857+albertlarsan68@users.noreply.github.com>2023-01-11 09:32:08 +0000
commitcf2dff2b1e3fa55fa5415d524200070d0d7aacfe (patch)
tree40a88d9a46aaf3e8870676eb2538378b75a263eb /tests/ui/mir-dataflow
parentca855e6e42787ecd062d81d53336fe6788ef51a9 (diff)
downloadrust-cf2dff2b1e3fa55fa5415d524200070d0d7aacfe.tar.gz
rust-cf2dff2b1e3fa55fa5415d524200070d0d7aacfe.zip
Move /src/test to /tests
Diffstat (limited to 'tests/ui/mir-dataflow')
-rw-r--r--tests/ui/mir-dataflow/README.md53
-rw-r--r--tests/ui/mir-dataflow/def-inits-1.rs51
-rw-r--r--tests/ui/mir-dataflow/def-inits-1.stderr28
-rw-r--r--tests/ui/mir-dataflow/inits-1.rs53
-rw-r--r--tests/ui/mir-dataflow/inits-1.stderr22
-rw-r--r--tests/ui/mir-dataflow/liveness-enum.rs22
-rw-r--r--tests/ui/mir-dataflow/liveness-enum.stderr10
-rw-r--r--tests/ui/mir-dataflow/liveness-projection.rs32
-rw-r--r--tests/ui/mir-dataflow/liveness-projection.stderr16
-rw-r--r--tests/ui/mir-dataflow/liveness-ptr.rs28
-rw-r--r--tests/ui/mir-dataflow/liveness-ptr.stderr10
-rw-r--r--tests/ui/mir-dataflow/uninits-1.rs51
-rw-r--r--tests/ui/mir-dataflow/uninits-1.stderr34
-rw-r--r--tests/ui/mir-dataflow/uninits-2.rs24
-rw-r--r--tests/ui/mir-dataflow/uninits-2.stderr10
15 files changed, 444 insertions, 0 deletions
diff --git a/tests/ui/mir-dataflow/README.md b/tests/ui/mir-dataflow/README.md
new file mode 100644
index 00000000000..a3ab14b23c7
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/def-inits-1.rs b/tests/ui/mir-dataflow/def-inits-1.rs
new file mode 100644
index 00000000000..30460824a16
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/def-inits-1.stderr b/tests/ui/mir-dataflow/def-inits-1.stderr
new file mode 100644
index 00000000000..e2bddb54d9b
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/inits-1.rs b/tests/ui/mir-dataflow/inits-1.rs
new file mode 100644
index 00000000000..8fb1d4bc736
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/inits-1.stderr b/tests/ui/mir-dataflow/inits-1.stderr
new file mode 100644
index 00000000000..7a00a70af6f
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/liveness-enum.rs b/tests/ui/mir-dataflow/liveness-enum.rs
new file mode 100644
index 00000000000..5eb04ae8c8d
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/liveness-enum.stderr b/tests/ui/mir-dataflow/liveness-enum.stderr
new file mode 100644
index 00000000000..483944d731a
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/liveness-projection.rs b/tests/ui/mir-dataflow/liveness-projection.rs
new file mode 100644
index 00000000000..486f31b635d
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/liveness-projection.stderr b/tests/ui/mir-dataflow/liveness-projection.stderr
new file mode 100644
index 00000000000..f9480c88090
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/liveness-ptr.rs b/tests/ui/mir-dataflow/liveness-ptr.rs
new file mode 100644
index 00000000000..786da523a33
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/liveness-ptr.stderr b/tests/ui/mir-dataflow/liveness-ptr.stderr
new file mode 100644
index 00000000000..858cdbac3d3
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/uninits-1.rs b/tests/ui/mir-dataflow/uninits-1.rs
new file mode 100644
index 00000000000..c2b4284a7b4
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/uninits-1.stderr b/tests/ui/mir-dataflow/uninits-1.stderr
new file mode 100644
index 00000000000..c52f5ac7bd9
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/uninits-2.rs b/tests/ui/mir-dataflow/uninits-2.rs
new file mode 100644
index 00000000000..c584ee74afb
--- /dev/null
+++ b/tests/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/tests/ui/mir-dataflow/uninits-2.stderr b/tests/ui/mir-dataflow/uninits-2.stderr
new file mode 100644
index 00000000000..0ef954e35a4
--- /dev/null
+++ b/tests/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
+