Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Experiment] Add never as a type alias for ! #79707

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions library/alloc/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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());
}
Expand All @@ -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) }
}
Expand Down
4 changes: 2 additions & 2 deletions library/core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down
6 changes: 4 additions & 2 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T: ?Sized> Copy for *const T {}
Expand Down
3 changes: 3 additions & 0 deletions library/core/src/prelude/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
6 changes: 6 additions & 0 deletions library/core/src/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = !;
10 changes: 5 additions & 5 deletions library/core/src/slice/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

Expand Down
16 changes: 8 additions & 8 deletions library/std/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ 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");
}

/// This function is called by the panic runtime if it catches an exception
/// 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");
}

Expand Down Expand Up @@ -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()
}
Expand All @@ -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<String>,
Expand Down Expand Up @@ -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<M: Any + Send>(msg: M) -> ! {
pub fn begin_panic<M: Any + Send>(msg: M) -> never {
if cfg!(feature = "panic_immediate_abort") {
intrinsics::abort()
}
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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<dyn Any + Send>) -> ! {
pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> never {
panic_count::increase();

struct RewrapBox(Box<dyn Any + Send>);
Expand All @@ -634,7 +634,7 @@ pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
/// 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)
Expand Down
3 changes: 3 additions & 0 deletions library/std/src/prelude/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
5 changes: 5 additions & 0 deletions src/test/ui/never_type/adjust_never.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ fn main() {
let x: ! = panic!();
let y: u32 = x;
}

fn foo() {
let x: never = panic!();
let y: u32 = x;
}
7 changes: 6 additions & 1 deletion src/test/ui/never_type/call-fn-never-arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!"))
}
2 changes: 1 addition & 1 deletion src/test/ui/never_type/diverging-fallback-control-flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl BadDefault for u32 {
}
}

impl BadDefault for ! {
impl BadDefault for never {
fn default() -> ! {
panic!()
}
Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/never_type/impl-for-never.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ trait StringifyType {
fn stringify_type() -> &'static str;
}

impl StringifyType for ! {
impl StringifyType for never {
fn stringify_type() -> &'static str {
"!"
}
Expand All @@ -22,6 +22,6 @@ fn maybe_stringify<T: StringifyType>(opt: Option<T>) -> &'static str {
}

fn main() {
println!("! is {}", <!>::stringify_type());
println!("None is {}", maybe_stringify(None::<!>));
println!("! is {}", <never>::stringify_type());
println!("None is {}", maybe_stringify(None::<never>));
}
2 changes: 1 addition & 1 deletion src/test/ui/never_type/issue-51506.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ trait Trait {
}

impl<T> 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<Self::Out> {
None
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/never_type/issue-51506.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ error[E0277]: `!` is not an iterator
LL | type Out: Iterator<Item = u32>;
| -------------------- 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 `!`

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/never_type/never-assign-wrong-type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
#![deny(warnings)]

fn main() {
let x: ! = "hello"; //~ ERROR mismatched types
let x: never = "hello"; //~ ERROR mismatched types
}
6 changes: 3 additions & 3 deletions src/test/ui/never_type/never-assign-wrong-type.stderr
Original file line number Diff line number Diff line change
@@ -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
|
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/never_type/never-result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#![feature(never_type)]

fn main() {
let x: Result<u32, !> = Ok(123);
let x: Result<u32, never> = Ok(123);
match x {
Ok(z) => (),
Err(y) => {
Expand Down
13 changes: 13 additions & 0 deletions src/test/ui/never_type/never_primitive.rs
Original file line number Diff line number Diff line change
@@ -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() { }
9 changes: 9 additions & 0 deletions src/test/ui/never_type/never_transmute_never.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, never>(Foo)
};
f(x)
}