summaryrefslogtreecommitdiffstats
path: root/tests/ui/never_type
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:58 +0000
commita4b7ed7a42c716ab9f05e351f003d589124fd55d (patch)
treeb620cd3f223850b28716e474e80c58059dca5dd4 /tests/ui/never_type
parentAdding upstream version 1.67.1+dfsg1. (diff)
downloadrustc-a4b7ed7a42c716ab9f05e351f003d589124fd55d.tar.xz
rustc-a4b7ed7a42c716ab9f05e351f003d589124fd55d.zip
Adding upstream version 1.68.2+dfsg1.upstream/1.68.2+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/never_type')
-rw-r--r--tests/ui/never_type/adjust_never.rs10
-rw-r--r--tests/ui/never_type/auto-traits.rs18
-rw-r--r--tests/ui/never_type/call-fn-never-arg-wrong-type.rs11
-rw-r--r--tests/ui/never_type/call-fn-never-arg-wrong-type.stderr19
-rw-r--r--tests/ui/never_type/call-fn-never-arg.rs14
-rw-r--r--tests/ui/never_type/cast-never.rs10
-rw-r--r--tests/ui/never_type/defaulted-never-note.fallback.stderr20
-rw-r--r--tests/ui/never_type/defaulted-never-note.rs41
-rw-r--r--tests/ui/never_type/dispatch_from_dyn_zst.rs51
-rw-r--r--tests/ui/never_type/diverging-fallback-control-flow.rs100
-rw-r--r--tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr22
-rw-r--r--tests/ui/never_type/diverging-fallback-no-leak.rs19
-rw-r--r--tests/ui/never_type/diverging-fallback-unconstrained-return.rs37
-rw-r--r--tests/ui/never_type/diverging-tuple-parts-39485.rs15
-rw-r--r--tests/ui/never_type/diverging-tuple-parts-39485.stderr32
-rw-r--r--tests/ui/never_type/exhaustive_patterns.rs21
-rw-r--r--tests/ui/never_type/exhaustive_patterns.stderr25
-rw-r--r--tests/ui/never_type/expr-empty-ret.rs15
-rw-r--r--tests/ui/never_type/fallback-closure-ret.rs23
-rw-r--r--tests/ui/never_type/fallback-closure-wrap.fallback.stderr17
-rw-r--r--tests/ui/never_type/fallback-closure-wrap.rs30
-rw-r--r--tests/ui/never_type/feature-gate-never_type_fallback.rs13
-rw-r--r--tests/ui/never_type/feature-gate-never_type_fallback.stderr19
-rw-r--r--tests/ui/never_type/impl-for-never.rs27
-rw-r--r--tests/ui/never_type/impl_trait_fallback.rs10
-rw-r--r--tests/ui/never_type/impl_trait_fallback2.rs22
-rw-r--r--tests/ui/never_type/impl_trait_fallback2.stderr19
-rw-r--r--tests/ui/never_type/impl_trait_fallback3.rs15
-rw-r--r--tests/ui/never_type/impl_trait_fallback3.stderr9
-rw-r--r--tests/ui/never_type/impl_trait_fallback4.rs24
-rw-r--r--tests/ui/never_type/impl_trait_fallback4.stderr9
-rw-r--r--tests/ui/never_type/issue-10176.rs9
-rw-r--r--tests/ui/never_type/issue-10176.stderr14
-rw-r--r--tests/ui/never_type/issue-13352.rs9
-rw-r--r--tests/ui/never_type/issue-13352.stderr16
-rw-r--r--tests/ui/never_type/issue-2149.rs15
-rw-r--r--tests/ui/never_type/issue-2149.stderr25
-rw-r--r--tests/ui/never_type/issue-44402.rs33
-rw-r--r--tests/ui/never_type/issue-51506.rs41
-rw-r--r--tests/ui/never_type/issue-51506.stderr16
-rw-r--r--tests/ui/never_type/issue-52443.rs14
-rw-r--r--tests/ui/never_type/issue-52443.stderr73
-rw-r--r--tests/ui/never_type/issue-5500-1.rs15
-rw-r--r--tests/ui/never_type/issue-96335.rs5
-rw-r--r--tests/ui/never_type/issue-96335.stderr32
-rw-r--r--tests/ui/never_type/never-assign-dead-code.rs12
-rw-r--r--tests/ui/never_type/never-assign-dead-code.stderr33
-rw-r--r--tests/ui/never_type/never-assign-wrong-type.rs8
-rw-r--r--tests/ui/never_type/never-assign-wrong-type.stderr14
-rw-r--r--tests/ui/never_type/never-associated-type.rs23
-rw-r--r--tests/ui/never_type/never-from-impl-is-reserved.rs12
-rw-r--r--tests/ui/never_type/never-from-impl-is-reserved.stderr14
-rw-r--r--tests/ui/never_type/never-result.rs21
-rw-r--r--tests/ui/never_type/never-type-arg.rs17
-rw-r--r--tests/ui/never_type/never-type-rvalues.rs38
-rw-r--r--tests/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr13
-rw-r--r--tests/ui/never_type/never-value-fallback-issue-66757.rs31
-rw-r--r--tests/ui/never_type/never_coercions.rs12
-rw-r--r--tests/ui/never_type/never_transmute_never.rs23
-rw-r--r--tests/ui/never_type/return-never-coerce.rs18
-rw-r--r--tests/ui/never_type/try_from.rs37
61 files changed, 1360 insertions, 0 deletions
diff --git a/tests/ui/never_type/adjust_never.rs b/tests/ui/never_type/adjust_never.rs
new file mode 100644
index 000000000..0d7d2c0ed
--- /dev/null
+++ b/tests/ui/never_type/adjust_never.rs
@@ -0,0 +1,10 @@
+// Test that a variable of type ! can coerce to another type.
+
+// check-pass
+
+#![feature(never_type)]
+
+fn main() {
+ let x: ! = panic!();
+ let y: u32 = x;
+}
diff --git a/tests/ui/never_type/auto-traits.rs b/tests/ui/never_type/auto-traits.rs
new file mode 100644
index 000000000..42ede708e
--- /dev/null
+++ b/tests/ui/never_type/auto-traits.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+#![feature(auto_traits)]
+#![feature(negative_impls)]
+#![feature(never_type)]
+
+fn main() {
+ enum Void {}
+
+ auto trait Auto {}
+ fn assert_auto<T: Auto>() {}
+ assert_auto::<Void>();
+ assert_auto::<!>();
+
+ fn assert_send<T: Send>() {}
+ assert_send::<Void>();
+ assert_send::<!>();
+}
diff --git a/tests/ui/never_type/call-fn-never-arg-wrong-type.rs b/tests/ui/never_type/call-fn-never-arg-wrong-type.rs
new file mode 100644
index 000000000..d06637e74
--- /dev/null
+++ b/tests/ui/never_type/call-fn-never-arg-wrong-type.rs
@@ -0,0 +1,11 @@
+// Test that we can't pass other types for !
+
+#![feature(never_type)]
+
+fn foo(x: !) -> ! {
+ x
+}
+
+fn main() {
+ foo("wow"); //~ ERROR mismatched types
+}
diff --git a/tests/ui/never_type/call-fn-never-arg-wrong-type.stderr b/tests/ui/never_type/call-fn-never-arg-wrong-type.stderr
new file mode 100644
index 000000000..fa3db33c9
--- /dev/null
+++ b/tests/ui/never_type/call-fn-never-arg-wrong-type.stderr
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+ --> $DIR/call-fn-never-arg-wrong-type.rs:10:9
+ |
+LL | foo("wow");
+ | --- ^^^^^ expected `!`, found `&str`
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected type `!`
+ found reference `&'static str`
+note: function defined here
+ --> $DIR/call-fn-never-arg-wrong-type.rs:5:4
+ |
+LL | fn foo(x: !) -> ! {
+ | ^^^ ----
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/never_type/call-fn-never-arg.rs b/tests/ui/never_type/call-fn-never-arg.rs
new file mode 100644
index 000000000..9d355817e
--- /dev/null
+++ b/tests/ui/never_type/call-fn-never-arg.rs
@@ -0,0 +1,14 @@
+// Test that we can use a ! for an argument of type !
+
+// check-pass
+
+#![feature(never_type)]
+#![allow(unreachable_code)]
+
+fn foo(x: !) -> ! {
+ x
+}
+
+fn main() {
+ foo(panic!("wowzers!"))
+}
diff --git a/tests/ui/never_type/cast-never.rs b/tests/ui/never_type/cast-never.rs
new file mode 100644
index 000000000..0139ebe46
--- /dev/null
+++ b/tests/ui/never_type/cast-never.rs
@@ -0,0 +1,10 @@
+// Test that we can explicitly cast ! to another type
+
+// check-pass
+
+#![feature(never_type)]
+
+fn main() {
+ let x: ! = panic!();
+ let y: u32 = x as u32;
+}
diff --git a/tests/ui/never_type/defaulted-never-note.fallback.stderr b/tests/ui/never_type/defaulted-never-note.fallback.stderr
new file mode 100644
index 000000000..283aca1b0
--- /dev/null
+++ b/tests/ui/never_type/defaulted-never-note.fallback.stderr
@@ -0,0 +1,20 @@
+error[E0277]: the trait bound `!: ImplementedForUnitButNotNever` is not satisfied
+ --> $DIR/defaulted-never-note.rs:30:9
+ |
+LL | foo(_x);
+ | --- ^^ the trait `ImplementedForUnitButNotNever` is not implemented for `!`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `ImplementedForUnitButNotNever` is implemented for `()`
+ = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information)
+ = help: did you intend to use the type `()` here instead?
+note: required by a bound in `foo`
+ --> $DIR/defaulted-never-note.rs:25:11
+ |
+LL | fn foo<T: ImplementedForUnitButNotNever>(_t: T) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/never_type/defaulted-never-note.rs b/tests/ui/never_type/defaulted-never-note.rs
new file mode 100644
index 000000000..d30ffcd38
--- /dev/null
+++ b/tests/ui/never_type/defaulted-never-note.rs
@@ -0,0 +1,41 @@
+// revisions: nofallback fallback
+//[nofallback] run-pass
+//[fallback] check-fail
+
+// We need to opt into the `never_type_fallback` feature
+// to trigger the requirement that this is testing.
+#![cfg_attr(fallback, feature(never_type, never_type_fallback))]
+
+#![allow(unused)]
+
+trait Deserialize: Sized {
+ fn deserialize() -> Result<Self, String>;
+}
+
+impl Deserialize for () {
+ fn deserialize() -> Result<(), String> {
+ Ok(())
+ }
+}
+
+trait ImplementedForUnitButNotNever {}
+
+impl ImplementedForUnitButNotNever for () {}
+
+fn foo<T: ImplementedForUnitButNotNever>(_t: T) {}
+//[fallback]~^ NOTE required by this bound in `foo`
+//[fallback]~| NOTE required by a bound in `foo`
+fn smeg() {
+ let _x = return;
+ foo(_x);
+ //[fallback]~^ ERROR the trait bound
+ //[fallback]~| NOTE the trait `ImplementedForUnitButNotNever` is not implemented
+ //[fallback]~| HELP trait `ImplementedForUnitButNotNever` is implemented for `()`
+ //[fallback]~| NOTE this error might have been caused
+ //[fallback]~| NOTE required by a bound introduced by this call
+ //[fallback]~| HELP did you intend
+}
+
+fn main() {
+ smeg();
+}
diff --git a/tests/ui/never_type/dispatch_from_dyn_zst.rs b/tests/ui/never_type/dispatch_from_dyn_zst.rs
new file mode 100644
index 000000000..764f58ce9
--- /dev/null
+++ b/tests/ui/never_type/dispatch_from_dyn_zst.rs
@@ -0,0 +1,51 @@
+// run-pass
+
+#![feature(unsize, dispatch_from_dyn, never_type)]
+
+#![allow(dead_code)]
+
+use std::{
+ ops::DispatchFromDyn,
+ marker::{Unsize, PhantomData},
+};
+
+struct Zst;
+struct NestedZst(PhantomData<()>, Zst);
+
+
+struct WithUnit<T: ?Sized>(Box<T>, ());
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithUnit<U>> for WithUnit<T>
+ where T: Unsize<U> {}
+
+struct WithPhantom<T: ?Sized>(Box<T>, PhantomData<()>);
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithPhantom<U>> for WithPhantom<T>
+ where T: Unsize<U> {}
+
+struct WithNever<T: ?Sized>(Box<T>, !);
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithNever<U>> for WithNever<T>
+ where T: Unsize<U> {}
+
+struct WithZst<T: ?Sized>(Box<T>, Zst);
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithZst<U>> for WithZst<T>
+ where T: Unsize<U> {}
+
+struct WithNestedZst<T: ?Sized>(Box<T>, NestedZst);
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithNestedZst<U>> for WithNestedZst<T>
+ where T: Unsize<U> {}
+
+
+struct Generic<T: ?Sized, A>(Box<T>, A);
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, ()>> for Generic<T, ()>
+ where T: Unsize<U> {}
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, PhantomData<()>>>
+ for Generic<T, PhantomData<()>>
+ where T: Unsize<U> {}
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, !>> for Generic<T, !>
+ where T: Unsize<U> {}
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, Zst>> for Generic<T, Zst>
+ where T: Unsize<U> {}
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, NestedZst>> for Generic<T, NestedZst>
+ where T: Unsize<U> {}
+
+
+fn main() {}
diff --git a/tests/ui/never_type/diverging-fallback-control-flow.rs b/tests/ui/never_type/diverging-fallback-control-flow.rs
new file mode 100644
index 000000000..45a3362fa
--- /dev/null
+++ b/tests/ui/never_type/diverging-fallback-control-flow.rs
@@ -0,0 +1,100 @@
+// revisions: nofallback fallback
+// run-pass
+
+#![allow(dead_code)]
+#![allow(unused_assignments)]
+#![allow(unused_variables)]
+#![allow(unreachable_code)]
+// Test various cases where we permit an unconstrained variable
+// to fallback based on control-flow. In all of these cases,
+// the type variable winds up being the target of both a `!` coercion
+// and a coercion from a non-`!` variable, and hence falls back to `()`.
+#![cfg_attr(fallback, feature(never_type, never_type_fallback))]
+
+trait UnitDefault {
+ fn default() -> Self;
+}
+
+impl UnitDefault for u32 {
+ fn default() -> Self {
+ 0
+ }
+}
+
+impl UnitDefault for () {
+ fn default() -> () {
+ panic!()
+ }
+}
+
+fn assignment() {
+ let x;
+
+ if true {
+ x = UnitDefault::default();
+ } else {
+ x = return;
+ }
+}
+
+fn assignment_rev() {
+ let x;
+
+ if true {
+ x = return;
+ } else {
+ x = UnitDefault::default();
+ }
+}
+
+fn if_then_else() {
+ let _x = if true {
+ UnitDefault::default()
+ } else {
+ return;
+ };
+}
+
+fn if_then_else_rev() {
+ let _x = if true {
+ return;
+ } else {
+ UnitDefault::default()
+ };
+}
+
+fn match_arm() {
+ let _x = match Ok(UnitDefault::default()) {
+ Ok(v) => v,
+ Err(()) => return,
+ };
+}
+
+fn match_arm_rev() {
+ let _x = match Ok(UnitDefault::default()) {
+ Err(()) => return,
+ Ok(v) => v,
+ };
+}
+
+fn loop_break() {
+ let _x = loop {
+ if false {
+ break return;
+ } else {
+ break UnitDefault::default();
+ }
+ };
+}
+
+fn loop_break_rev() {
+ let _x = loop {
+ if false {
+ break return;
+ } else {
+ break UnitDefault::default();
+ }
+ };
+}
+
+fn main() {}
diff --git a/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr
new file mode 100644
index 000000000..3215c4669
--- /dev/null
+++ b/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr
@@ -0,0 +1,22 @@
+error[E0277]: the trait bound `!: Test` is not satisfied
+ --> $DIR/diverging-fallback-no-leak.rs:17:23
+ |
+LL | unconstrained_arg(return);
+ | ----------------- ^^^^^^ the trait `Test` is not implemented for `!`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the following other types implement trait `Test`:
+ ()
+ i32
+ = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information)
+ = help: did you intend to use the type `()` here instead?
+note: required by a bound in `unconstrained_arg`
+ --> $DIR/diverging-fallback-no-leak.rs:12:25
+ |
+LL | fn unconstrained_arg<T: Test>(_: T) {}
+ | ^^^^ required by this bound in `unconstrained_arg`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/never_type/diverging-fallback-no-leak.rs b/tests/ui/never_type/diverging-fallback-no-leak.rs
new file mode 100644
index 000000000..03478e19d
--- /dev/null
+++ b/tests/ui/never_type/diverging-fallback-no-leak.rs
@@ -0,0 +1,19 @@
+// revisions: nofallback fallback
+//[nofallback] check-pass
+
+#![cfg_attr(fallback, feature(never_type, never_type_fallback))]
+
+fn make_unit() {}
+
+trait Test {}
+impl Test for i32 {}
+impl Test for () {}
+
+fn unconstrained_arg<T: Test>(_: T) {}
+
+fn main() {
+ // Here the type variable falls back to `!`,
+ // and hence we get a type error.
+ unconstrained_arg(return);
+ //[fallback]~^ ERROR trait bound `!: Test` is not satisfied
+}
diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.rs b/tests/ui/never_type/diverging-fallback-unconstrained-return.rs
new file mode 100644
index 000000000..7ea97126f
--- /dev/null
+++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.rs
@@ -0,0 +1,37 @@
+// Variant of diverging-falllback-control-flow that tests
+// the specific case of a free function with an unconstrained
+// return type. This captures the pattern we saw in the wild
+// in the objc crate, where changing the fallback from `!` to `()`
+// resulted in unsoundness.
+//
+// check-pass
+
+// revisions: nofallback fallback
+
+#![cfg_attr(fallback, feature(never_type, never_type_fallback))]
+
+
+fn make_unit() {}
+
+trait UnitReturn {}
+impl UnitReturn for i32 {}
+impl UnitReturn for () {}
+
+fn unconstrained_return<T: UnitReturn>() -> T {
+ unsafe {
+ let make_unit_fn: fn() = make_unit;
+ let ffi: fn() -> T = std::mem::transmute(make_unit_fn);
+ ffi()
+ }
+}
+
+fn main() {
+ // In Ye Olde Days, the `T` parameter of `unconstrained_return`
+ // winds up "entangled" with the `!` type that results from
+ // `panic!`, and hence falls back to `()`. This is kind of unfortunate
+ // and unexpected. When we introduced the `!` type, the original
+ // idea was to change that fallback to `!`, but that would have resulted
+ // in this code no longer compiling (or worse, in some cases it injected
+ // unsound results).
+ let _ = if true { unconstrained_return() } else { panic!() };
+}
diff --git a/tests/ui/never_type/diverging-tuple-parts-39485.rs b/tests/ui/never_type/diverging-tuple-parts-39485.rs
new file mode 100644
index 000000000..0cde61193
--- /dev/null
+++ b/tests/ui/never_type/diverging-tuple-parts-39485.rs
@@ -0,0 +1,15 @@
+// After #39485, this test used to pass, but that change was reverted
+// due to numerous inference failures like #39808, so it now fails
+// again. #39485 made it so that diverging types never propagate
+// upward; but we now do propagate such types upward in many more
+// cases.
+
+fn g() {
+ &panic!() //~ ERROR mismatched types
+}
+
+fn f() -> isize {
+ (return 1, return 2) //~ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/never_type/diverging-tuple-parts-39485.stderr b/tests/ui/never_type/diverging-tuple-parts-39485.stderr
new file mode 100644
index 000000000..52d07ae17
--- /dev/null
+++ b/tests/ui/never_type/diverging-tuple-parts-39485.stderr
@@ -0,0 +1,32 @@
+error[E0308]: mismatched types
+ --> $DIR/diverging-tuple-parts-39485.rs:8:5
+ |
+LL | &panic!()
+ | ^^^^^^^^^ expected `()`, found reference
+ |
+ = note: expected unit type `()`
+ found reference `&_`
+help: a return type might be missing here
+ |
+LL | fn g() -> _ {
+ | ++++
+help: consider removing the borrow
+ |
+LL - &panic!()
+LL + panic!()
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/diverging-tuple-parts-39485.rs:12:5
+ |
+LL | fn f() -> isize {
+ | ----- expected `isize` because of return type
+LL | (return 1, return 2)
+ | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found tuple
+ |
+ = note: expected type `isize`
+ found tuple `(!, !)`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/never_type/exhaustive_patterns.rs b/tests/ui/never_type/exhaustive_patterns.rs
new file mode 100644
index 000000000..2e23fa182
--- /dev/null
+++ b/tests/ui/never_type/exhaustive_patterns.rs
@@ -0,0 +1,21 @@
+// check-fail
+// known-bug: #104034
+
+#![feature(exhaustive_patterns, never_type)]
+
+mod inner {
+ pub struct Wrapper<T>(T);
+}
+
+enum Either<A, B> {
+ A(A),
+ B(inner::Wrapper<B>),
+}
+
+fn foo() -> Either<(), !> {
+ Either::A(())
+}
+
+fn main() {
+ let Either::A(()) = foo();
+}
diff --git a/tests/ui/never_type/exhaustive_patterns.stderr b/tests/ui/never_type/exhaustive_patterns.stderr
new file mode 100644
index 000000000..40c7c1d10
--- /dev/null
+++ b/tests/ui/never_type/exhaustive_patterns.stderr
@@ -0,0 +1,25 @@
+error[E0005]: refutable pattern in local binding
+ --> $DIR/exhaustive_patterns.rs:20:9
+ |
+LL | let Either::A(()) = foo();
+ | ^^^^^^^^^^^^^ pattern `Either::B(_)` not covered
+ |
+ = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+ = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Either<(), !>` defined here
+ --> $DIR/exhaustive_patterns.rs:10:6
+ |
+LL | enum Either<A, B> {
+ | ^^^^^^
+LL | A(A),
+LL | B(inner::Wrapper<B>),
+ | - not covered
+ = note: the matched value is of type `Either<(), !>`
+help: you might want to use `if let` to ignore the variant that isn't matched
+ |
+LL | if let Either::A(()) = foo() { todo!() }
+ | ++ ~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/never_type/expr-empty-ret.rs b/tests/ui/never_type/expr-empty-ret.rs
new file mode 100644
index 000000000..ce8ffaf94
--- /dev/null
+++ b/tests/ui/never_type/expr-empty-ret.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+#![allow(dead_code)]
+// Issue #521
+
+// pretty-expanded FIXME #23616
+
+fn f() {
+ let _x = match true {
+ true => { 10 }
+ false => { return }
+ };
+}
+
+pub fn main() { }
diff --git a/tests/ui/never_type/fallback-closure-ret.rs b/tests/ui/never_type/fallback-closure-ret.rs
new file mode 100644
index 000000000..5c8ce48cb
--- /dev/null
+++ b/tests/ui/never_type/fallback-closure-ret.rs
@@ -0,0 +1,23 @@
+// This test verifies that never type fallback preserves the following code in a
+// compiling state. This pattern is fairly common in the wild, notably seen in
+// wasmtime v0.16. Typically this is some closure wrapper that expects a
+// collection of 'known' signatures, and -> ! is not included in that set.
+//
+// This test is specifically targeted by the unit type fallback when
+// encountering a set of obligations like `?T: Foo` and `Trait::Projection =
+// ?T`. In the code below, these are `R: Bar` and `Fn::Output = R`.
+//
+// revisions: nofallback fallback
+// check-pass
+
+#![cfg_attr(fallback, feature(never_type_fallback))]
+
+trait Bar { }
+impl Bar for () { }
+impl Bar for u32 { }
+
+fn foo<R: Bar>(_: impl Fn() -> R) {}
+
+fn main() {
+ foo(|| panic!());
+}
diff --git a/tests/ui/never_type/fallback-closure-wrap.fallback.stderr b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr
new file mode 100644
index 000000000..a0f790dba
--- /dev/null
+++ b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr
@@ -0,0 +1,17 @@
+error[E0271]: expected `[closure@fallback-closure-wrap.rs:18:40]` to be a closure that returns `()`, but it returns `!`
+ --> $DIR/fallback-closure-wrap.rs:18:31
+ |
+LL | let error = Closure::wrap(Box::new(move || {
+ | _______________________________^
+LL | |
+LL | | panic!("Can't connect to server.");
+LL | | }) as Box<dyn FnMut()>);
+ | |______^ expected `()`, found `!`
+ |
+ = note: expected unit type `()`
+ found type `!`
+ = note: required for the cast from `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to the object type `dyn FnMut()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/never_type/fallback-closure-wrap.rs b/tests/ui/never_type/fallback-closure-wrap.rs
new file mode 100644
index 000000000..f88355bb2
--- /dev/null
+++ b/tests/ui/never_type/fallback-closure-wrap.rs
@@ -0,0 +1,30 @@
+// This is a minified example from Crater breakage observed when attempting to
+// stabilize never type, nstoddard/webgl-gui @ 22f0169f.
+//
+// This particular test case currently fails as the inference to `()` rather
+// than `!` happens as a result of an `as` cast, which is not currently tracked.
+// Crater did not find many cases of this occurring, but it is included for
+// awareness.
+//
+// revisions: nofallback fallback
+//[nofallback] check-pass
+//[fallback] check-fail
+
+#![cfg_attr(fallback, feature(never_type_fallback))]
+
+use std::marker::PhantomData;
+
+fn main() {
+ let error = Closure::wrap(Box::new(move || {
+ //[fallback]~^ to be a closure that returns `()`, but it returns `!`
+ panic!("Can't connect to server.");
+ }) as Box<dyn FnMut()>);
+}
+
+struct Closure<T: ?Sized>(PhantomData<T>);
+
+impl<T: ?Sized> Closure<T> {
+ fn wrap(data: Box<T>) -> Closure<T> {
+ todo!()
+ }
+}
diff --git a/tests/ui/never_type/feature-gate-never_type_fallback.rs b/tests/ui/never_type/feature-gate-never_type_fallback.rs
new file mode 100644
index 000000000..7d0208411
--- /dev/null
+++ b/tests/ui/never_type/feature-gate-never_type_fallback.rs
@@ -0,0 +1,13 @@
+// This is a feature gate test for `never_type_fallback`.
+// It works by using a scenario where the type fall backs to `()` rather than ยด!`
+// in the case where `#![feature(never_type_fallback)]` would change it to `!`.
+
+fn main() {}
+
+trait T {}
+
+fn should_ret_unit() {
+ foo(panic!()) //~ ERROR
+}
+
+fn foo(_: impl T) {}
diff --git a/tests/ui/never_type/feature-gate-never_type_fallback.stderr b/tests/ui/never_type/feature-gate-never_type_fallback.stderr
new file mode 100644
index 000000000..2db1cc4b7
--- /dev/null
+++ b/tests/ui/never_type/feature-gate-never_type_fallback.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `(): T` is not satisfied
+ --> $DIR/feature-gate-never_type_fallback.rs:10:9
+ |
+LL | foo(panic!())
+ | --- ^^^^^^^^
+ | | |
+ | | the trait `T` is not implemented for `()`
+ | | this tail expression is of type `()`
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `foo`
+ --> $DIR/feature-gate-never_type_fallback.rs:13:16
+ |
+LL | fn foo(_: impl T) {}
+ | ^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/never_type/impl-for-never.rs b/tests/ui/never_type/impl-for-never.rs
new file mode 100644
index 000000000..9423f0885
--- /dev/null
+++ b/tests/ui/never_type/impl-for-never.rs
@@ -0,0 +1,27 @@
+// run-pass
+
+#![feature(never_type)]
+
+// Test that we can call static methods on ! both directly and when it appears in a generic
+
+trait StringifyType {
+ fn stringify_type() -> &'static str;
+}
+
+impl StringifyType for ! {
+ fn stringify_type() -> &'static str {
+ "!"
+ }
+}
+
+fn maybe_stringify<T: StringifyType>(opt: Option<T>) -> &'static str {
+ match opt {
+ Some(_) => T::stringify_type(),
+ None => "none",
+ }
+}
+
+fn main() {
+ println!("! is {}", <!>::stringify_type());
+ println!("None is {}", maybe_stringify(None::<!>));
+}
diff --git a/tests/ui/never_type/impl_trait_fallback.rs b/tests/ui/never_type/impl_trait_fallback.rs
new file mode 100644
index 000000000..cc9520c1b
--- /dev/null
+++ b/tests/ui/never_type/impl_trait_fallback.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+fn main() {}
+
+trait T {}
+impl T for () {}
+
+fn should_ret_unit() -> impl T {
+ panic!()
+}
diff --git a/tests/ui/never_type/impl_trait_fallback2.rs b/tests/ui/never_type/impl_trait_fallback2.rs
new file mode 100644
index 000000000..12c187b9e
--- /dev/null
+++ b/tests/ui/never_type/impl_trait_fallback2.rs
@@ -0,0 +1,22 @@
+#![feature(type_alias_impl_trait)]
+
+fn main() {}
+
+trait T {}
+impl T for i32 {}
+
+fn should_ret_unit() -> impl T {
+ //~^ ERROR `(): T` is not satisfied
+ panic!()
+}
+
+type Foo = impl T;
+
+fn a() -> Foo {
+ //~^ ERROR `(): T` is not satisfied
+ panic!()
+}
+
+fn b() -> Foo {
+ 42
+}
diff --git a/tests/ui/never_type/impl_trait_fallback2.stderr b/tests/ui/never_type/impl_trait_fallback2.stderr
new file mode 100644
index 000000000..78cc83bdb
--- /dev/null
+++ b/tests/ui/never_type/impl_trait_fallback2.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `(): T` is not satisfied
+ --> $DIR/impl_trait_fallback2.rs:8:25
+ |
+LL | fn should_ret_unit() -> impl T {
+ | ^^^^^^ the trait `T` is not implemented for `()`
+ |
+ = help: the trait `T` is implemented for `i32`
+
+error[E0277]: the trait bound `(): T` is not satisfied
+ --> $DIR/impl_trait_fallback2.rs:15:11
+ |
+LL | fn a() -> Foo {
+ | ^^^ the trait `T` is not implemented for `()`
+ |
+ = help: the trait `T` is implemented for `i32`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/never_type/impl_trait_fallback3.rs b/tests/ui/never_type/impl_trait_fallback3.rs
new file mode 100644
index 000000000..ed645b823
--- /dev/null
+++ b/tests/ui/never_type/impl_trait_fallback3.rs
@@ -0,0 +1,15 @@
+#![feature(type_alias_impl_trait)]
+
+fn main() {}
+
+trait T {
+ type Assoc;
+}
+
+type Foo = impl T;
+
+fn a() -> Foo {
+ //~^ ERROR the trait bound `(): T` is not satisfied
+ // This is not a defining use, it doesn't actually constrain the opaque type.
+ panic!()
+}
diff --git a/tests/ui/never_type/impl_trait_fallback3.stderr b/tests/ui/never_type/impl_trait_fallback3.stderr
new file mode 100644
index 000000000..5d5d216fb
--- /dev/null
+++ b/tests/ui/never_type/impl_trait_fallback3.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `(): T` is not satisfied
+ --> $DIR/impl_trait_fallback3.rs:11:11
+ |
+LL | fn a() -> Foo {
+ | ^^^ the trait `T` is not implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/never_type/impl_trait_fallback4.rs b/tests/ui/never_type/impl_trait_fallback4.rs
new file mode 100644
index 000000000..fe62773fa
--- /dev/null
+++ b/tests/ui/never_type/impl_trait_fallback4.rs
@@ -0,0 +1,24 @@
+#![feature(type_alias_impl_trait)]
+
+trait T {
+ type Assoc: Cake;
+}
+
+trait Cake: std::fmt::Display {
+ fn cake() -> Self;
+}
+
+type Foo = impl T;
+
+fn foo() -> impl T {
+ //~^ ERROR `(): T` is not satisfied
+ panic!()
+}
+
+fn a() -> Foo {
+ foo()
+}
+
+fn main() {
+ println!("{}", <Foo as T>::Assoc::cake());
+}
diff --git a/tests/ui/never_type/impl_trait_fallback4.stderr b/tests/ui/never_type/impl_trait_fallback4.stderr
new file mode 100644
index 000000000..f2e216e90
--- /dev/null
+++ b/tests/ui/never_type/impl_trait_fallback4.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `(): T` is not satisfied
+ --> $DIR/impl_trait_fallback4.rs:13:13
+ |
+LL | fn foo() -> impl T {
+ | ^^^^^^ the trait `T` is not implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/never_type/issue-10176.rs b/tests/ui/never_type/issue-10176.rs
new file mode 100644
index 000000000..6277aa05e
--- /dev/null
+++ b/tests/ui/never_type/issue-10176.rs
@@ -0,0 +1,9 @@
+fn f() -> isize {
+ (return 1, return 2)
+//~^ ERROR mismatched types
+//~| expected type `isize`
+//~| found tuple `(!, !)`
+//~| expected `isize`, found tuple
+}
+
+fn main() {}
diff --git a/tests/ui/never_type/issue-10176.stderr b/tests/ui/never_type/issue-10176.stderr
new file mode 100644
index 000000000..cd5361ffa
--- /dev/null
+++ b/tests/ui/never_type/issue-10176.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+ --> $DIR/issue-10176.rs:2:5
+ |
+LL | fn f() -> isize {
+ | ----- expected `isize` because of return type
+LL | (return 1, return 2)
+ | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found tuple
+ |
+ = note: expected type `isize`
+ found tuple `(!, !)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/never_type/issue-13352.rs b/tests/ui/never_type/issue-13352.rs
new file mode 100644
index 000000000..9c884a33c
--- /dev/null
+++ b/tests/ui/never_type/issue-13352.rs
@@ -0,0 +1,9 @@
+fn foo(_: Box<dyn FnMut()>) {}
+
+fn main() {
+ foo(loop {
+ std::process::exit(0);
+ });
+ 2_usize + (loop {});
+ //~^ ERROR E0277
+}
diff --git a/tests/ui/never_type/issue-13352.stderr b/tests/ui/never_type/issue-13352.stderr
new file mode 100644
index 000000000..2d22da0b4
--- /dev/null
+++ b/tests/ui/never_type/issue-13352.stderr
@@ -0,0 +1,16 @@
+error[E0277]: cannot add `()` to `usize`
+ --> $DIR/issue-13352.rs:7:13
+ |
+LL | 2_usize + (loop {});
+ | ^ no implementation for `usize + ()`
+ |
+ = help: the trait `Add<()>` is not implemented for `usize`
+ = help: the following other types implement trait `Add<Rhs>`:
+ <&'a usize as Add<usize>>
+ <&usize as Add<&usize>>
+ <usize as Add<&usize>>
+ <usize as Add>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/never_type/issue-2149.rs b/tests/ui/never_type/issue-2149.rs
new file mode 100644
index 000000000..d6426d2cf
--- /dev/null
+++ b/tests/ui/never_type/issue-2149.rs
@@ -0,0 +1,15 @@
+trait VecMonad<A> {
+ fn bind<B, F>(&self, f: F) where F: FnMut(A) -> Vec<B>;
+}
+
+impl<A> VecMonad<A> for Vec<A> {
+ fn bind<B, F>(&self, mut f: F) where F: FnMut(A) -> Vec<B> {
+ let mut r = panic!();
+ for elt in self { r = r + f(*elt); }
+ //~^ ERROR E0277
+ }
+}
+fn main() {
+ ["hi"].bind(|x| [x] );
+ //~^ ERROR no method named `bind` found
+}
diff --git a/tests/ui/never_type/issue-2149.stderr b/tests/ui/never_type/issue-2149.stderr
new file mode 100644
index 000000000..58fe2edb1
--- /dev/null
+++ b/tests/ui/never_type/issue-2149.stderr
@@ -0,0 +1,25 @@
+error[E0277]: cannot add `Vec<B>` to `()`
+ --> $DIR/issue-2149.rs:8:33
+ |
+LL | for elt in self { r = r + f(*elt); }
+ | ^ no implementation for `() + Vec<B>`
+ |
+ = help: the trait `Add<Vec<B>>` is not implemented for `()`
+
+error[E0599]: no method named `bind` found for array `[&str; 1]` in the current scope
+ --> $DIR/issue-2149.rs:13:12
+ |
+LL | ["hi"].bind(|x| [x] );
+ | ^^^^ method not found in `[&str; 1]`
+ |
+ = help: items from traits can only be used if the trait is implemented and in scope
+note: `VecMonad` defines an item `bind`, perhaps you need to implement it
+ --> $DIR/issue-2149.rs:1:1
+ |
+LL | trait VecMonad<A> {
+ | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0599.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/never_type/issue-44402.rs b/tests/ui/never_type/issue-44402.rs
new file mode 100644
index 000000000..699e480df
--- /dev/null
+++ b/tests/ui/never_type/issue-44402.rs
@@ -0,0 +1,33 @@
+// check-pass
+
+#![allow(dead_code)]
+#![feature(never_type)]
+#![feature(exhaustive_patterns)]
+
+// Regression test for inhabitedness check. The old
+// cache used to cause us to incorrectly decide
+// that `test_b` was invalid.
+
+struct Foo {
+ field1: !,
+ field2: Option<&'static Bar>,
+}
+
+struct Bar {
+ field1: &'static Foo
+}
+
+fn test_a() {
+ let x: Option<Foo> = None;
+ match x { None => () }
+}
+
+fn test_b() {
+ let x: Option<Bar> = None;
+ match x {
+ Some(_) => (),
+ None => ()
+ }
+}
+
+fn main() { }
diff --git a/tests/ui/never_type/issue-51506.rs b/tests/ui/never_type/issue-51506.rs
new file mode 100644
index 000000000..d0fe6a0f5
--- /dev/null
+++ b/tests/ui/never_type/issue-51506.rs
@@ -0,0 +1,41 @@
+#![feature(never_type, specialization)]
+#![allow(incomplete_features)]
+
+use std::iter::{self, Empty};
+
+trait Trait {
+ type Out: Iterator<Item = u32>;
+
+ fn f(&self) -> Option<Self::Out>;
+}
+
+impl<T> Trait for T {
+ default type Out = !; //~ ERROR: `!` is not an iterator
+
+ default fn f(&self) -> Option<Self::Out> {
+ None
+ }
+}
+
+struct X;
+
+impl Trait for X {
+ type Out = Empty<u32>;
+
+ fn f(&self) -> Option<Self::Out> {
+ Some(iter::empty())
+ }
+}
+
+fn f<T: Trait>(a: T) {
+ if let Some(iter) = a.f() {
+ println!("Some");
+ for x in iter {
+ println!("x = {}", x);
+ }
+ }
+}
+
+pub fn main() {
+ f(10);
+}
diff --git a/tests/ui/never_type/issue-51506.stderr b/tests/ui/never_type/issue-51506.stderr
new file mode 100644
index 000000000..293ec3a72
--- /dev/null
+++ b/tests/ui/never_type/issue-51506.stderr
@@ -0,0 +1,16 @@
+error[E0277]: `!` is not an iterator
+ --> $DIR/issue-51506.rs:13:24
+ |
+LL | default type Out = !;
+ | ^ `!` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `!`
+note: required by a bound in `Trait::Out`
+ --> $DIR/issue-51506.rs:7:15
+ |
+LL | type Out: Iterator<Item = u32>;
+ | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::Out`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/never_type/issue-52443.rs b/tests/ui/never_type/issue-52443.rs
new file mode 100644
index 000000000..0498a8a16
--- /dev/null
+++ b/tests/ui/never_type/issue-52443.rs
@@ -0,0 +1,14 @@
+fn main() {
+ [(); & { loop { continue } } ]; //~ ERROR mismatched types
+
+ [(); loop { break }]; //~ ERROR mismatched types
+
+ [(); {while true {break}; 0}];
+ //~^ WARN denote infinite loops with
+
+ [(); { for _ in 0usize.. {}; 0}];
+ //~^ ERROR `for` is not allowed in a `const`
+ //~| ERROR cannot convert
+ //~| ERROR mutable references
+ //~| ERROR cannot call
+}
diff --git a/tests/ui/never_type/issue-52443.stderr b/tests/ui/never_type/issue-52443.stderr
new file mode 100644
index 000000000..33b7a9185
--- /dev/null
+++ b/tests/ui/never_type/issue-52443.stderr
@@ -0,0 +1,73 @@
+warning: denote infinite loops with `loop { ... }`
+ --> $DIR/issue-52443.rs:6:11
+ |
+LL | [(); {while true {break}; 0}];
+ | ^^^^^^^^^^ help: use `loop`
+ |
+ = note: `#[warn(while_true)]` on by default
+
+error[E0658]: `for` is not allowed in a `const`
+ --> $DIR/issue-52443.rs:9:12
+ |
+LL | [(); { for _ in 0usize.. {}; 0}];
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
+ = help: add `#![feature(const_for)]` to the crate attributes to enable
+
+error[E0308]: mismatched types
+ --> $DIR/issue-52443.rs:2:10
+ |
+LL | [(); & { loop { continue } } ];
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference
+ |
+ = note: expected type `usize`
+ found reference `&_`
+help: consider removing the borrow
+ |
+LL - [(); & { loop { continue } } ];
+LL + [(); { loop { continue } } ];
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/issue-52443.rs:4:17
+ |
+LL | [(); loop { break }];
+ | ^^^^^
+ | |
+ | expected `usize`, found `()`
+ | help: give it a value of the expected type: `break 42`
+
+error[E0015]: cannot convert `RangeFrom<usize>` into an iterator in constants
+ --> $DIR/issue-52443.rs:9:21
+ |
+LL | [(); { for _ in 0usize.. {}; 0}];
+ | ^^^^^^^^
+ |
+note: impl defined here, but it is not `const`
+ --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+ = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+ = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+
+error[E0658]: mutable references are not allowed in constants
+ --> $DIR/issue-52443.rs:9:21
+ |
+LL | [(); { for _ in 0usize.. {}; 0}];
+ | ^^^^^^^^
+ |
+ = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0015]: cannot call non-const fn `<RangeFrom<usize> as Iterator>::next` in constants
+ --> $DIR/issue-52443.rs:9:21
+ |
+LL | [(); { for _ in 0usize.. {}; 0}];
+ | ^^^^^^^^
+ |
+ = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+ = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+
+error: aborting due to 6 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0015, E0308, E0658.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/never_type/issue-5500-1.rs b/tests/ui/never_type/issue-5500-1.rs
new file mode 100644
index 000000000..98d6e1a14
--- /dev/null
+++ b/tests/ui/never_type/issue-5500-1.rs
@@ -0,0 +1,15 @@
+// MIR doesn't generate an error because the assignment isn't reachable. This
+// is OK because the test is here to check that the compiler doesn't ICE (cf.
+// #5500).
+
+// check-pass
+
+struct TrieMapIterator<'a> {
+ node: &'a usize
+}
+
+fn main() {
+ let a = 5;
+ let _iter = TrieMapIterator{node: &a};
+ _iter.node = &panic!()
+}
diff --git a/tests/ui/never_type/issue-96335.rs b/tests/ui/never_type/issue-96335.rs
new file mode 100644
index 000000000..411a7c9df
--- /dev/null
+++ b/tests/ui/never_type/issue-96335.rs
@@ -0,0 +1,5 @@
+fn main() {
+ 0.....{loop{}1};
+ //~^ ERROR unexpected token
+ //~| ERROR mismatched types
+}
diff --git a/tests/ui/never_type/issue-96335.stderr b/tests/ui/never_type/issue-96335.stderr
new file mode 100644
index 000000000..e148b983e
--- /dev/null
+++ b/tests/ui/never_type/issue-96335.stderr
@@ -0,0 +1,32 @@
+error: unexpected token: `...`
+ --> $DIR/issue-96335.rs:2:6
+ |
+LL | 0.....{loop{}1};
+ | ^^^
+ |
+help: use `..` for an exclusive range
+ |
+LL | 0....{loop{}1};
+ | ~~
+help: or `..=` for an inclusive range
+ |
+LL | 0..=..{loop{}1};
+ | ~~~
+
+error[E0308]: mismatched types
+ --> $DIR/issue-96335.rs:2:9
+ |
+LL | 0.....{loop{}1};
+ | ----^^^^^^^^^^^
+ | | |
+ | | expected integer, found struct `RangeTo`
+ | arguments to this function are incorrect
+ |
+ = note: expected type `{integer}`
+ found struct `RangeTo<{integer}>`
+note: associated function defined here
+ --> $SRC_DIR/core/src/ops/range.rs:LL:COL
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/never_type/never-assign-dead-code.rs b/tests/ui/never_type/never-assign-dead-code.rs
new file mode 100644
index 000000000..7bb7c8709
--- /dev/null
+++ b/tests/ui/never_type/never-assign-dead-code.rs
@@ -0,0 +1,12 @@
+// Test that an assignment of type ! makes the rest of the block dead code.
+
+// check-pass
+
+#![feature(never_type)]
+#![warn(unused)]
+
+fn main() {
+ let x: ! = panic!("aah"); //~ WARN unused
+ drop(x); //~ WARN unreachable
+ //~^ WARN unreachable
+}
diff --git a/tests/ui/never_type/never-assign-dead-code.stderr b/tests/ui/never_type/never-assign-dead-code.stderr
new file mode 100644
index 000000000..521b82023
--- /dev/null
+++ b/tests/ui/never_type/never-assign-dead-code.stderr
@@ -0,0 +1,33 @@
+warning: unreachable statement
+ --> $DIR/never-assign-dead-code.rs:10:5
+ |
+LL | let x: ! = panic!("aah");
+ | ------------- any code following this expression is unreachable
+LL | drop(x);
+ | ^^^^^^^^ unreachable statement
+ |
+note: the lint level is defined here
+ --> $DIR/never-assign-dead-code.rs:6:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: `#[warn(unreachable_code)]` implied by `#[warn(unused)]`
+
+warning: unreachable call
+ --> $DIR/never-assign-dead-code.rs:10:5
+ |
+LL | drop(x);
+ | ^^^^ - any code following this expression is unreachable
+ | |
+ | unreachable call
+
+warning: unused variable: `x`
+ --> $DIR/never-assign-dead-code.rs:9:9
+ |
+LL | let x: ! = panic!("aah");
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+ |
+ = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/never_type/never-assign-wrong-type.rs b/tests/ui/never_type/never-assign-wrong-type.rs
new file mode 100644
index 000000000..67e26f566
--- /dev/null
+++ b/tests/ui/never_type/never-assign-wrong-type.rs
@@ -0,0 +1,8 @@
+// Test that we can't use another type in place of !
+
+#![feature(never_type)]
+#![deny(warnings)]
+
+fn main() {
+ let x: ! = "hello"; //~ ERROR mismatched types
+}
diff --git a/tests/ui/never_type/never-assign-wrong-type.stderr b/tests/ui/never_type/never-assign-wrong-type.stderr
new file mode 100644
index 000000000..ce34d9483
--- /dev/null
+++ b/tests/ui/never_type/never-assign-wrong-type.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+ --> $DIR/never-assign-wrong-type.rs:7:16
+ |
+LL | let x: ! = "hello";
+ | - ^^^^^^^ expected `!`, found `&str`
+ | |
+ | expected due to this
+ |
+ = note: expected type `!`
+ found reference `&'static str`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/never_type/never-associated-type.rs b/tests/ui/never_type/never-associated-type.rs
new file mode 100644
index 000000000..3bb917c93
--- /dev/null
+++ b/tests/ui/never_type/never-associated-type.rs
@@ -0,0 +1,23 @@
+// Test that we can use ! as an associated type.
+
+// check-pass
+
+#![feature(never_type)]
+
+trait Foo {
+ type Wow;
+
+ fn smeg(&self) -> Self::Wow;
+}
+
+struct Blah;
+impl Foo for Blah {
+ type Wow = !;
+ fn smeg(&self) -> ! {
+ panic!("kapow!");
+ }
+}
+
+fn main() {
+ Blah.smeg();
+}
diff --git a/tests/ui/never_type/never-from-impl-is-reserved.rs b/tests/ui/never_type/never-from-impl-is-reserved.rs
new file mode 100644
index 000000000..9d16015bd
--- /dev/null
+++ b/tests/ui/never_type/never-from-impl-is-reserved.rs
@@ -0,0 +1,12 @@
+// check that the `for<T> T: From<!>` impl is reserved
+
+#![feature(never_type)]
+
+pub struct MyFoo;
+pub trait MyTrait {}
+
+impl MyTrait for MyFoo {}
+// This will conflict with the first impl if we impl `for<T> T: From<!>`.
+impl<T> MyTrait for T where T: From<!> {} //~ ERROR conflicting implementation
+
+fn main() {}
diff --git a/tests/ui/never_type/never-from-impl-is-reserved.stderr b/tests/ui/never_type/never-from-impl-is-reserved.stderr
new file mode 100644
index 000000000..f9f7c787e
--- /dev/null
+++ b/tests/ui/never_type/never-from-impl-is-reserved.stderr
@@ -0,0 +1,14 @@
+error[E0119]: conflicting implementations of trait `MyTrait` for type `MyFoo`
+ --> $DIR/never-from-impl-is-reserved.rs:10:1
+ |
+LL | impl MyTrait for MyFoo {}
+ | ---------------------- first implementation here
+LL | // This will conflict with the first impl if we impl `for<T> T: From<!>`.
+LL | impl<T> MyTrait for T where T: From<!> {}
+ | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo`
+ |
+ = note: permitting this impl would forbid us from adding `impl<T> From<!> for T` later; see rust-lang/rust#64715 for details
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/never_type/never-result.rs b/tests/ui/never_type/never-result.rs
new file mode 100644
index 000000000..35af37910
--- /dev/null
+++ b/tests/ui/never_type/never-result.rs
@@ -0,0 +1,21 @@
+// run-pass
+
+#![allow(unused_variables)]
+#![allow(unreachable_code)]
+
+// Test that we can extract a ! through pattern matching then use it as several different types.
+
+#![feature(never_type)]
+
+fn main() {
+ let x: Result<u32, !> = Ok(123);
+ match x {
+ Ok(z) => (),
+ Err(y) => {
+ let q: u32 = y;
+ let w: i32 = y;
+ let e: String = y;
+ y
+ },
+ }
+}
diff --git a/tests/ui/never_type/never-type-arg.rs b/tests/ui/never_type/never-type-arg.rs
new file mode 100644
index 000000000..13cd59e6a
--- /dev/null
+++ b/tests/ui/never_type/never-type-arg.rs
@@ -0,0 +1,17 @@
+// Test that we can use ! as an argument to a trait impl.
+
+// check-pass
+
+#![feature(never_type)]
+
+struct Wub;
+
+impl PartialEq<!> for Wub {
+ fn eq(&self, other: &!) -> bool {
+ *other
+ }
+}
+
+fn main() {
+ let _ = Wub == panic!("oh no!");
+}
diff --git a/tests/ui/never_type/never-type-rvalues.rs b/tests/ui/never_type/never-type-rvalues.rs
new file mode 100644
index 000000000..9ccc73dbf
--- /dev/null
+++ b/tests/ui/never_type/never-type-rvalues.rs
@@ -0,0 +1,38 @@
+// run-pass
+
+#![feature(never_type)]
+#![allow(dead_code)]
+#![allow(path_statements)]
+#![allow(unreachable_patterns)]
+
+fn never_direct(x: !) {
+ x;
+}
+
+fn never_ref_pat(ref x: !) {
+ *x;
+}
+
+fn never_ref(x: &!) {
+ let &y = x;
+ y;
+}
+
+fn never_pointer(x: *const !) {
+ unsafe {
+ *x;
+ }
+}
+
+fn never_slice(x: &[!]) {
+ x[0];
+}
+
+fn never_match(x: Result<(), !>) {
+ match x {
+ Ok(_) => {},
+ Err(_) => {},
+ }
+}
+
+pub fn main() { }
diff --git a/tests/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr b/tests/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr
new file mode 100644
index 000000000..06e902bca
--- /dev/null
+++ b/tests/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr
@@ -0,0 +1,13 @@
+error[E0277]: the trait bound `E: From<()>` is not satisfied
+ --> $DIR/never-value-fallback-issue-66757.rs:28:26
+ |
+LL | <E as From<_>>::from(never);
+ | -------------------- ^^^^^ the trait `From<()>` is not implemented for `E`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `From<!>` is implemented for `E`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/never_type/never-value-fallback-issue-66757.rs b/tests/ui/never_type/never-value-fallback-issue-66757.rs
new file mode 100644
index 000000000..fc6fe6eb5
--- /dev/null
+++ b/tests/ui/never_type/never-value-fallback-issue-66757.rs
@@ -0,0 +1,31 @@
+// Regression test for #66757
+//
+// Test than when you have a `!` value (e.g., the local variable
+// never) and an uninferred variable (here the argument to `From`) it
+// doesn't fallback to `()` but rather `!`.
+//
+// revisions: nofallback fallback
+//[fallback] run-pass
+//[nofallback] check-fail
+
+#![feature(never_type)]
+
+#![cfg_attr(fallback, feature(never_type_fallback))]
+
+struct E;
+
+impl From<!> for E {
+ fn from(_: !) -> E {
+ E
+ }
+}
+
+#[allow(unreachable_code)]
+#[allow(dead_code)]
+#[allow(unused_must_use)]
+fn foo(never: !) {
+ <E as From<!>>::from(never); // Ok
+ <E as From<_>>::from(never); //[nofallback]~ ERROR trait bound `E: From<()>` is not satisfied
+}
+
+fn main() { }
diff --git a/tests/ui/never_type/never_coercions.rs b/tests/ui/never_type/never_coercions.rs
new file mode 100644
index 000000000..105c38635
--- /dev/null
+++ b/tests/ui/never_type/never_coercions.rs
@@ -0,0 +1,12 @@
+// run-pass
+// Test that having something of type ! doesn't screw up type-checking and that it coerces to the
+// LUB type of the other match arms.
+
+fn main() {
+ let v: Vec<u32> = Vec::new();
+ match 0u32 {
+ 0 => &v,
+ 1 => return,
+ _ => &v[..],
+ };
+}
diff --git a/tests/ui/never_type/never_transmute_never.rs b/tests/ui/never_type/never_transmute_never.rs
new file mode 100644
index 000000000..fce3ced9a
--- /dev/null
+++ b/tests/ui/never_type/never_transmute_never.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+#![crate_type="lib"]
+
+#![feature(never_type)]
+#![allow(dead_code)]
+#![allow(unreachable_code)]
+#![allow(unused_variables)]
+
+struct Foo;
+
+pub fn f(x: !) -> ! {
+ x
+}
+
+pub fn ub() {
+ // This is completely undefined behaviour,
+ // but we still want to make sure it compiles.
+ let x: ! = unsafe {
+ std::mem::transmute::<Foo, !>(Foo)
+ };
+ f(x)
+}
diff --git a/tests/ui/never_type/return-never-coerce.rs b/tests/ui/never_type/return-never-coerce.rs
new file mode 100644
index 000000000..d615940ef
--- /dev/null
+++ b/tests/ui/never_type/return-never-coerce.rs
@@ -0,0 +1,18 @@
+// Test that ! coerces to other types.
+
+// run-fail
+// error-pattern:aah!
+// ignore-emscripten no processes
+
+fn call_another_fn<T, F: FnOnce() -> T>(f: F) -> T {
+ f()
+}
+
+fn wub() -> ! {
+ panic!("aah!");
+}
+
+fn main() {
+ let x: i32 = call_another_fn(wub);
+ let y: u32 = wub();
+}
diff --git a/tests/ui/never_type/try_from.rs b/tests/ui/never_type/try_from.rs
new file mode 100644
index 000000000..50451576f
--- /dev/null
+++ b/tests/ui/never_type/try_from.rs
@@ -0,0 +1,37 @@
+// run-pass
+// This test relies on `TryFrom` being blanket impl for all `T: Into`
+// and `TryInto` being blanket impl for all `U: TryFrom`
+
+// This test was added to show the motivation for doing this
+// over `TryFrom` being blanket impl for all `T: From`
+
+#![feature(never_type)]
+
+use std::convert::{TryInto, Infallible};
+
+struct Foo<T> {
+ t: T,
+}
+
+// This fails to compile due to coherence restrictions
+// as of Rust version 1.32.x, therefore it could not be used
+// instead of the `Into` version of the impl, and serves as
+// motivation for a blanket impl for all `T: Into`, instead
+// of a blanket impl for all `T: From`
+/*
+impl<T> From<Foo<T>> for Box<T> {
+ fn from(foo: Foo<T>) -> Box<T> {
+ Box::new(foo.t)
+ }
+}
+*/
+
+impl<T> Into<Vec<T>> for Foo<T> {
+ fn into(self) -> Vec<T> {
+ vec![self.t]
+ }
+}
+
+pub fn main() {
+ let _: Result<Vec<i32>, Infallible> = Foo { t: 10 }.try_into();
+}