summaryrefslogtreecommitdiffstats
path: root/tests/ui/mir-dataflow
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
commit218caa410aa38c29984be31a5229b9fa717560ee (patch)
treec54bd55eeb6e4c508940a30e94c0032fbd45d677 /tests/ui/mir-dataflow
parentReleasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz
rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
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 000000000..a3ab14b23
--- /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 000000000..30460824a
--- /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 000000000..e2bddb54d
--- /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 000000000..8fb1d4bc7
--- /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 000000000..7a00a70af
--- /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 000000000..5eb04ae8c
--- /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 000000000..483944d73
--- /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 000000000..486f31b63
--- /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 000000000..f9480c880
--- /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 000000000..786da523a
--- /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 000000000..858cdbac3
--- /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 000000000..c2b4284a7
--- /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 000000000..c52f5ac7b
--- /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 000000000..c584ee74a
--- /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 000000000..0ef954e35
--- /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
+