about summary refs log tree commit diff
path: root/tests/ui/rfcs/rfc-0000-never_patterns
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-01-22 22:12:07 +0100
committerGitHub <noreply@github.com>2024-01-22 22:12:07 +0100
commit042cc7269cc756abccc89820755c2c05a33b2b6b (patch)
treed2a7279fc10e264601be6ee63d68335c25606c57 /tests/ui/rfcs/rfc-0000-never_patterns
parent67d093682ce1b63f34b0038068819bd46aadf048 (diff)
parent3ff10242fee5356cb4be91db6df2eee6b9a34089 (diff)
downloadrust-042cc7269cc756abccc89820755c2c05a33b2b6b.tar.gz
rust-042cc7269cc756abccc89820755c2c05a33b2b6b.zip
Rollup merge of #120104 - Nadrieril:never-pat-diverges, r=compiler-errors
never_patterns: Count `!` bindings as diverging

A binding that is a never pattern is not reachable, hence counts as diverging code. This allows in particular `fn foo(!: Void) -> SomeType {}` to typecheck.

r? ``@compiler-errors``
Diffstat (limited to 'tests/ui/rfcs/rfc-0000-never_patterns')
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.rs16
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.stderr12
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs36
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr49
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs56
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr55
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs38
7 files changed, 262 insertions, 0 deletions
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.rs b/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.rs
new file mode 100644
index 00000000000..9150c831c89
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.rs
@@ -0,0 +1,16 @@
+// edition: 2018
+// known-bug: #120240
+#![feature(never_patterns)]
+#![allow(incomplete_features)]
+
+fn main() {}
+
+enum Void {}
+
+// Divergence is not detected.
+async fn async_never(!: Void) -> ! {} // gives an error
+
+// Divergence is detected
+async fn async_let(x: Void) -> ! {
+    let ! = x;
+}
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.stderr
new file mode 100644
index 00000000000..fa71feee5f5
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/120240-async-fn-never-arg.rs:11:36
+   |
+LL | async fn async_never(!: Void) -> ! {} // gives an error
+   |                                    ^^ expected `!`, found `()`
+   |
+   = note:   expected type `!`
+           found unit type `()`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs
new file mode 100644
index 00000000000..f7e4007b920
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs
@@ -0,0 +1,36 @@
+#![feature(never_patterns)]
+#![allow(incomplete_features)]
+#![deny(unreachable_patterns)]
+#![deny(unreachable_code)]
+
+fn main() {}
+
+enum Void {}
+
+fn never_arg(!: Void) -> u32 {
+    println!();
+    //~^ ERROR unreachable statement
+}
+
+fn ref_never_arg(&!: &Void) -> u32 {
+    println!();
+    //~^ ERROR unreachable statement
+}
+
+fn never_let() -> u32 {
+    let ptr: *const Void = std::ptr::null();
+    unsafe {
+        let ! = *ptr;
+    }
+    println!();
+    //~^ ERROR unreachable statement
+}
+
+fn never_match() -> u32 {
+    let ptr: *const Void = std::ptr::null();
+    unsafe {
+        match *ptr { ! };
+    }
+    println!();
+    //~^ ERROR unreachable statement
+}
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr
new file mode 100644
index 00000000000..c33a5855d50
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr
@@ -0,0 +1,49 @@
+error: unreachable statement
+  --> $DIR/diverge-causes-unreachable-code.rs:11:5
+   |
+LL | fn never_arg(!: Void) -> u32 {
+   |              - any code following a never pattern is unreachable
+LL |     println!();
+   |     ^^^^^^^^^^ unreachable statement
+   |
+note: the lint level is defined here
+  --> $DIR/diverge-causes-unreachable-code.rs:4:9
+   |
+LL | #![deny(unreachable_code)]
+   |         ^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unreachable statement
+  --> $DIR/diverge-causes-unreachable-code.rs:16:5
+   |
+LL | fn ref_never_arg(&!: &Void) -> u32 {
+   |                  -- any code following a never pattern is unreachable
+LL |     println!();
+   |     ^^^^^^^^^^ unreachable statement
+   |
+   = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unreachable statement
+  --> $DIR/diverge-causes-unreachable-code.rs:25:5
+   |
+LL |         let ! = *ptr;
+   |             - any code following a never pattern is unreachable
+LL |     }
+LL |     println!();
+   |     ^^^^^^^^^^ unreachable statement
+   |
+   = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unreachable statement
+  --> $DIR/diverge-causes-unreachable-code.rs:34:5
+   |
+LL |         match *ptr { ! };
+   |         ---------------- any code following this `match` expression is unreachable, as all arms diverge
+LL |     }
+LL |     println!();
+   |     ^^^^^^^^^^ unreachable statement
+   |
+   = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs
new file mode 100644
index 00000000000..6b85ada3aad
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs
@@ -0,0 +1,56 @@
+#![feature(never_patterns)]
+#![feature(let_chains)]
+#![allow(incomplete_features)]
+#![deny(unreachable_patterns)]
+
+fn main() {}
+
+enum Void {}
+
+// Contrast with `./diverges.rs`: merely having an empty type around isn't enough to diverge.
+
+fn wild_void(_: Void) -> u32 {}
+//~^ ERROR: mismatched types
+
+fn wild_let() -> u32 {
+    let ptr: *const Void = std::ptr::null();
+    unsafe {
+        //~^ ERROR: mismatched types
+        let _ = *ptr;
+    }
+}
+
+fn wild_match() -> u32 {
+    let ptr: *const Void = std::ptr::null();
+    unsafe {
+        match *ptr {
+            _ => {} //~ ERROR: mismatched types
+        }
+    }
+}
+
+fn binding_void(_x: Void) -> u32 {}
+//~^ ERROR: mismatched types
+
+fn binding_let() -> u32 {
+    let ptr: *const Void = std::ptr::null();
+    unsafe {
+        //~^ ERROR: mismatched types
+        let _x = *ptr;
+    }
+}
+
+fn binding_match() -> u32 {
+    let ptr: *const Void = std::ptr::null();
+    unsafe {
+        match *ptr {
+            _x => {} //~ ERROR: mismatched types
+        }
+    }
+}
+
+// Don't confuse this with a `let !` statement.
+fn let_chain(x: Void) -> u32 {
+    if let true = true && let ! = x {}
+    //~^ ERROR: mismatched types
+}
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr
new file mode 100644
index 00000000000..08a1bbe9bff
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr
@@ -0,0 +1,55 @@
+error[E0308]: mismatched types
+  --> $DIR/diverges-not.rs:12:26
+   |
+LL | fn wild_void(_: Void) -> u32 {}
+   |    ---------             ^^^ expected `u32`, found `()`
+   |    |
+   |    implicitly returns `()` as its body has no tail or `return` expression
+
+error[E0308]: mismatched types
+  --> $DIR/diverges-not.rs:17:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         let _ = *ptr;
+LL | |     }
+   | |_____^ expected `u32`, found `()`
+
+error[E0308]: mismatched types
+  --> $DIR/diverges-not.rs:27:18
+   |
+LL |             _ => {}
+   |                  ^^ expected `u32`, found `()`
+
+error[E0308]: mismatched types
+  --> $DIR/diverges-not.rs:32:30
+   |
+LL | fn binding_void(_x: Void) -> u32 {}
+   |    ------------              ^^^ expected `u32`, found `()`
+   |    |
+   |    implicitly returns `()` as its body has no tail or `return` expression
+
+error[E0308]: mismatched types
+  --> $DIR/diverges-not.rs:37:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         let _x = *ptr;
+LL | |     }
+   | |_____^ expected `u32`, found `()`
+
+error[E0308]: mismatched types
+  --> $DIR/diverges-not.rs:47:19
+   |
+LL |             _x => {}
+   |                   ^^ expected `u32`, found `()`
+
+error[E0308]: mismatched types
+  --> $DIR/diverges-not.rs:54:37
+   |
+LL |     if let true = true && let ! = x {}
+   |                                     ^^ expected `u32`, found `()`
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs
new file mode 100644
index 00000000000..3783100b502
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs
@@ -0,0 +1,38 @@
+// check-pass
+// edition: 2018
+#![feature(never_patterns)]
+#![allow(incomplete_features)]
+#![deny(unreachable_patterns)]
+
+fn main() {}
+
+enum Void {}
+
+// A never pattern alone diverges.
+
+fn never_arg(!: Void) -> ! {}
+
+fn never_arg_returns_anything<T>(!: Void) -> T {}
+
+fn ref_never_arg(&!: &Void) -> ! {}
+
+fn never_let() -> ! {
+    let ptr: *const Void = std::ptr::null();
+    unsafe {
+        let ! = *ptr;
+    }
+}
+
+fn never_match() -> ! {
+    let ptr: *const Void = std::ptr::null();
+    unsafe {
+        match *ptr { ! };
+    }
+    // Ensures this typechecks because of divergence and not the type of the match expression.
+    println!();
+}
+
+// Note: divergence is not detected for async fns when the `!` is in the argument (#120240).
+async fn async_let(x: Void) -> ! {
+    let ! = x;
+}