diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index b1bfc2abe44ac..53bd865d0b723 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -342,7 +342,7 @@ extern "Rust" { // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the // default implementations below (`__rdl_oom`) otherwise. #[rustc_allocator_nounwind] - fn __rust_alloc_error_handler(size: usize, align: usize) -> !; + fn __rust_alloc_error_handler(size: usize, align: usize) -> never; } /// Abort on memory allocation error or failure. @@ -361,7 +361,7 @@ extern "Rust" { #[cfg(not(test))] #[rustc_allocator_nounwind] #[cold] -pub fn handle_alloc_error(layout: Layout) -> ! { +pub fn handle_alloc_error(layout: Layout) -> never { unsafe { __rust_alloc_error_handler(layout.size(), layout.align()); } @@ -382,17 +382,17 @@ pub mod __alloc_error_handler { // if there is no `#[alloc_error_handler]` #[rustc_std_internal_symbol] - pub unsafe extern "C" fn __rdl_oom(size: usize, _align: usize) -> ! { + pub unsafe extern "C" fn __rdl_oom(size: usize, _align: usize) -> never { panic!("memory allocation of {} bytes failed", size) } // if there is a `#[alloc_error_handler]` #[rustc_std_internal_symbol] - pub unsafe extern "C" fn __rg_oom(size: usize, align: usize) -> ! { + pub unsafe extern "C" fn __rg_oom(size: usize, align: usize) -> never { let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; extern "Rust" { #[lang = "oom"] - fn oom_impl(layout: Layout) -> !; + fn oom_impl(layout: Layout) -> never; } unsafe { oom_impl(layout) } } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 5a5aa76a07627..2c3ee868efdc9 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -710,7 +710,7 @@ extern "rust-intrinsic" { /// /// A more user-friendly and stable version of this operation is /// [`std::process::abort`](../../std/process/fn.abort.html). - pub fn abort() -> !; + pub fn abort() -> crate::primitive::never; /// Tells LLVM that this point in the code is not reachable, enabling /// further optimizations. @@ -721,7 +721,7 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`](crate::hint::unreachable_unchecked). #[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")] - pub fn unreachable() -> !; + pub fn unreachable() -> crate::primitive::never; /// Informs the optimizer that a condition is always true. /// If the condition is false, the behavior is undefined. diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 85e0e7200875d..7965807d3aad7 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -818,8 +818,10 @@ mod copy_impls { bool char } - #[unstable(feature = "never_type", issue = "35121")] - impl Copy for ! {} + // A stable attribute works, but unstable not. Interesting. + //#[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "haven't made a feature gate yet", since = "1.50.0")] + impl Copy for never {} #[stable(feature = "rust1", since = "1.0.0")] impl Copy for *const T {} diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index b4fff3d67b555..6fb1f62bfe6f6 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -76,3 +76,6 @@ pub use crate::macros::builtin::{ )] #[doc(no_inline)] pub use crate::macros::builtin::cfg_accessible; + +#[stable(feature = "haven't made a feature gate yet", since = "1.50.0")] +pub use crate::primitive::never; diff --git a/library/core/src/primitive.rs b/library/core/src/primitive.rs index e20b2c5c9382a..34295103bc3a9 100644 --- a/library/core/src/primitive.rs +++ b/library/core/src/primitive.rs @@ -65,3 +65,9 @@ pub use u64; pub use u8; #[stable(feature = "core_primitive", since = "1.43.0")] pub use usize; + +// Haven't looked into how to make this a compiler buildin, +// or if that is even needed. +#[stable(feature = "haven't made a feature gate yet", since = "1.50.0")] +#[allow(non_camel_case_types, missing_docs)] +pub type never = !; diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 660c8a2da5da0..6ea6fe991de2e 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -30,35 +30,35 @@ where #[inline(never)] #[cold] #[track_caller] -fn slice_start_index_len_fail(index: usize, len: usize) -> ! { +fn slice_start_index_len_fail(index: usize, len: usize) -> never { panic!("range start index {} out of range for slice of length {}", index, len); } #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_end_index_len_fail(index: usize, len: usize) -> ! { +pub(crate) fn slice_end_index_len_fail(index: usize, len: usize) -> never { panic!("range end index {} out of range for slice of length {}", index, len); } #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_index_order_fail(index: usize, end: usize) -> ! { +pub(crate) fn slice_index_order_fail(index: usize, end: usize) -> never { panic!("slice index starts at {} but ends at {}", index, end); } #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_start_index_overflow_fail() -> ! { +pub(crate) fn slice_start_index_overflow_fail() -> never { panic!("attempted to index slice from after maximum usize"); } #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_end_index_overflow_fail() -> ! { +pub(crate) fn slice_end_index_overflow_fail() -> never { panic!("attempted to index slice up to maximum usize"); } diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 8ba3feccb6bcc..a0841585bf400 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -56,7 +56,7 @@ extern "C" { /// with our panic count. #[cfg(not(test))] #[rustc_std_internal_symbol] -extern "C" fn __rust_drop_panic() -> ! { +extern "C" fn __rust_drop_panic() -> never { rtabort!("Rust panics must be rethrown"); } @@ -64,7 +64,7 @@ extern "C" fn __rust_drop_panic() -> ! { /// object which does not correspond to a Rust panic. #[cfg(not(test))] #[rustc_std_internal_symbol] -extern "C" fn __rust_foreign_exception() -> ! { +extern "C" fn __rust_foreign_exception() -> never { rtabort!("Rust cannot catch foreign exceptions"); } @@ -426,7 +426,7 @@ pub fn panicking() -> bool { #[cfg_attr(not(feature = "panic_immediate_abort"), track_caller)] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[cfg_attr(feature = "panic_immediate_abort", inline)] -pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! { +pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> never { if cfg!(feature = "panic_immediate_abort") { intrinsics::abort() } @@ -438,7 +438,7 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! { /// Entry point of panics from the libcore crate (`panic_impl` lang item). #[cfg_attr(not(test), panic_handler)] #[unwind(allowed)] -pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { +pub fn begin_panic_handler(info: &PanicInfo<'_>) -> never { struct PanicPayload<'a> { inner: &'a fmt::Arguments<'a>, string: Option, @@ -510,7 +510,7 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[cold] #[track_caller] -pub fn begin_panic(msg: M) -> ! { +pub fn begin_panic(msg: M) -> never { if cfg!(feature = "panic_immediate_abort") { intrinsics::abort() } @@ -562,7 +562,7 @@ fn rust_panic_with_hook( payload: &mut dyn BoxMeUp, message: Option<&fmt::Arguments<'_>>, location: &Location<'_>, -) -> ! { +) -> never { let panics = panic_count::increase(); // If this is the third nested call (e.g., panics == 2, this is 0-indexed), @@ -612,7 +612,7 @@ fn rust_panic_with_hook( /// This is the entry point for `resume_unwind`. /// It just forwards the payload to the panic runtime. -pub fn rust_panic_without_hook(payload: Box) -> ! { +pub fn rust_panic_without_hook(payload: Box) -> never { panic_count::increase(); struct RewrapBox(Box); @@ -634,7 +634,7 @@ pub fn rust_panic_without_hook(payload: Box) -> ! { /// yer breakpoints. #[inline(never)] #[cfg_attr(not(test), rustc_std_internal_symbol)] -fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! { +fn rust_panic(mut msg: &mut dyn BoxMeUp) -> never { let code = unsafe { let obj = &mut msg as *mut &mut dyn BoxMeUp; __rust_start_panic(obj as usize) diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 0fbd6b62f18ff..7c4d91258bac0 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -79,3 +79,6 @@ pub use crate::string::{String, ToString}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use crate::vec::Vec; + +#[stable(feature = "haven't made a feature gate yet", since = "1.50.0")] +pub use core::primitive::never; diff --git a/src/test/ui/never_type/adjust_never.rs b/src/test/ui/never_type/adjust_never.rs index 0d7d2c0ed3fa9..7182246cc096b 100644 --- a/src/test/ui/never_type/adjust_never.rs +++ b/src/test/ui/never_type/adjust_never.rs @@ -8,3 +8,8 @@ fn main() { let x: ! = panic!(); let y: u32 = x; } + +fn foo() { + let x: never = panic!(); + let y: u32 = x; +} diff --git a/src/test/ui/never_type/call-fn-never-arg.rs b/src/test/ui/never_type/call-fn-never-arg.rs index 9d355817ee80d..8f2a15a634048 100644 --- a/src/test/ui/never_type/call-fn-never-arg.rs +++ b/src/test/ui/never_type/call-fn-never-arg.rs @@ -9,6 +9,11 @@ fn foo(x: !) -> ! { x } +fn bar(x: never) -> never { + x +} + fn main() { - foo(panic!("wowzers!")) + foo(panic!("wowzers!")); + bar(panic!("wowzers!")) } diff --git a/src/test/ui/never_type/diverging-fallback-control-flow.rs b/src/test/ui/never_type/diverging-fallback-control-flow.rs index ea4881049d792..dae9a369fe0e7 100644 --- a/src/test/ui/never_type/diverging-fallback-control-flow.rs +++ b/src/test/ui/never_type/diverging-fallback-control-flow.rs @@ -23,7 +23,7 @@ impl BadDefault for u32 { } } -impl BadDefault for ! { +impl BadDefault for never { fn default() -> ! { panic!() } diff --git a/src/test/ui/never_type/impl-for-never.rs b/src/test/ui/never_type/impl-for-never.rs index 9423f08858b9b..fcbb6c03dc3b6 100644 --- a/src/test/ui/never_type/impl-for-never.rs +++ b/src/test/ui/never_type/impl-for-never.rs @@ -8,7 +8,7 @@ trait StringifyType { fn stringify_type() -> &'static str; } -impl StringifyType for ! { +impl StringifyType for never { fn stringify_type() -> &'static str { "!" } @@ -22,6 +22,6 @@ fn maybe_stringify(opt: Option) -> &'static str { } fn main() { - println!("! is {}", ::stringify_type()); - println!("None is {}", maybe_stringify(None::)); + println!("! is {}", ::stringify_type()); + println!("None is {}", maybe_stringify(None::)); } diff --git a/src/test/ui/never_type/issue-51506.rs b/src/test/ui/never_type/issue-51506.rs index d0fe6a0f59a87..be3ce03dc5e6f 100644 --- a/src/test/ui/never_type/issue-51506.rs +++ b/src/test/ui/never_type/issue-51506.rs @@ -10,7 +10,7 @@ trait Trait { } impl Trait for T { - default type Out = !; //~ ERROR: `!` is not an iterator + default type Out = never; //~ ERROR: `!` is not an iterator default fn f(&self) -> Option { None diff --git a/src/test/ui/never_type/issue-51506.stderr b/src/test/ui/never_type/issue-51506.stderr index 16d93c18900a9..3f9f815bad518 100644 --- a/src/test/ui/never_type/issue-51506.stderr +++ b/src/test/ui/never_type/issue-51506.stderr @@ -4,8 +4,8 @@ error[E0277]: `!` is not an iterator LL | type Out: Iterator; | -------------------- required by this bound in `Trait::Out` ... -LL | default type Out = !; - | ^^^^^^^^^^^^^^^^^^^^^ `!` is not an iterator +LL | default type Out = never; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `!` is not an iterator | = help: the trait `Iterator` is not implemented for `!` diff --git a/src/test/ui/never_type/never-assign-wrong-type.rs b/src/test/ui/never_type/never-assign-wrong-type.rs index 67e26f5663f41..2dcd5fe8c7b74 100644 --- a/src/test/ui/never_type/never-assign-wrong-type.rs +++ b/src/test/ui/never_type/never-assign-wrong-type.rs @@ -4,5 +4,5 @@ #![deny(warnings)] fn main() { - let x: ! = "hello"; //~ ERROR mismatched types + let x: never = "hello"; //~ ERROR mismatched types } diff --git a/src/test/ui/never_type/never-assign-wrong-type.stderr b/src/test/ui/never_type/never-assign-wrong-type.stderr index ce34d9483247f..23b1662c2d33f 100644 --- a/src/test/ui/never_type/never-assign-wrong-type.stderr +++ b/src/test/ui/never_type/never-assign-wrong-type.stderr @@ -1,8 +1,8 @@ error[E0308]: mismatched types - --> $DIR/never-assign-wrong-type.rs:7:16 + --> $DIR/never-assign-wrong-type.rs:7:20 | -LL | let x: ! = "hello"; - | - ^^^^^^^ expected `!`, found `&str` +LL | let x: never = "hello"; + | ----- ^^^^^^^ expected `!`, found `&str` | | | expected due to this | diff --git a/src/test/ui/never_type/never-result.rs b/src/test/ui/never_type/never-result.rs index 35af37910ef3e..d398997d5a5ce 100644 --- a/src/test/ui/never_type/never-result.rs +++ b/src/test/ui/never_type/never-result.rs @@ -8,7 +8,7 @@ #![feature(never_type)] fn main() { - let x: Result = Ok(123); + let x: Result = Ok(123); match x { Ok(z) => (), Err(y) => { diff --git a/src/test/ui/never_type/never_primitive.rs b/src/test/ui/never_type/never_primitive.rs new file mode 100644 index 0000000000000..1db6beeea9d5e --- /dev/null +++ b/src/test/ui/never_type/never_primitive.rs @@ -0,0 +1,13 @@ +// check-pass + +// For backwards compatibility, test if a type definition that is +// named `never` shadows the new `never` from the prelude. +#[allow(non_camel_case_types)] +struct never { x: u32 } + +fn foo(never: never) -> u32 { + let never { x } = never; + x +} + +fn main() { } diff --git a/src/test/ui/never_type/never_transmute_never.rs b/src/test/ui/never_type/never_transmute_never.rs index fce3ced9aac7f..2c8b82bfce519 100644 --- a/src/test/ui/never_type/never_transmute_never.rs +++ b/src/test/ui/never_type/never_transmute_never.rs @@ -21,3 +21,12 @@ pub fn ub() { }; f(x) } + +pub fn ub2() { + // This is completely undefined behaviour, + // but we still want to make sure it compiles. + let x: ! = unsafe { + std::mem::transmute::(Foo) + }; + f(x) +}