From 7934f26613980e2dfed24551e816601b8a74879b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Nov 2024 22:09:07 +0100 Subject: [PATCH 1/5] convert all const-callable intrinsics into the new form (without extern block) --- library/core/src/intrinsics.rs | 2080 +++++++++++++++++--------------- 1 file changed, 1111 insertions(+), 969 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index fc09da7bcbc65..55746a8b5856c 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -936,21 +936,31 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn abort() -> !; - /// Informs the optimizer that this point in the code is not reachable, - /// enabling further optimizations. - /// - /// N.B., this is very different from the `unreachable!()` macro: Unlike the - /// macro, which panics when it is executed, it is *undefined behavior* to - /// reach code marked with this function. - /// - /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`]. - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + /// Executes a breakpoint trap, for inspection by a debugger. + /// + /// This intrinsic does not have a stable counterpart. #[rustc_nounwind] - pub fn unreachable() -> !; + pub fn breakpoint(); +} + +/// Informs the optimizer that this point in the code is not reachable, +/// enabling further optimizations. +/// +/// N.B., this is very different from the `unreachable!()` macro: Unlike the +/// macro, which panics when it is executed, it is *undefined behavior* to +/// reach code marked with this function. +/// +/// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`]. +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0") +)] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unreachable() -> ! { + unreachable!() } /// Informs the optimizer that a condition is always true. @@ -1044,437 +1054,465 @@ pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { if b { true_val } else { false_val } } -extern "rust-intrinsic" { - /// Executes a breakpoint trap, for inspection by a debugger. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn breakpoint(); +/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: +/// This will statically either panic, or do nothing. +/// +/// This intrinsic does not have a stable counterpart. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn assert_inhabited() { + unreachable!() +} - /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: - /// This will statically either panic, or do nothing. - /// - /// This intrinsic does not have a stable counterpart. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn assert_inhabited(); +/// A guard for unsafe functions that cannot ever be executed if `T` does not permit +/// zero-initialization: This will statically either panic, or do nothing. +/// +/// This intrinsic does not have a stable counterpart. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn assert_zero_valid() { + unreachable!() +} - /// A guard for unsafe functions that cannot ever be executed if `T` does not permit - /// zero-initialization: This will statically either panic, or do nothing. - /// - /// This intrinsic does not have a stable counterpart. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn assert_zero_valid(); +/// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. +/// +/// This intrinsic does not have a stable counterpart. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn assert_mem_uninitialized_valid() { + unreachable!() +} - /// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. - /// - /// This intrinsic does not have a stable counterpart. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn assert_mem_uninitialized_valid(); +/// Gets a reference to a static `Location` indicating where it was called. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// Consider using [`core::panic::Location::caller`] instead. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn caller_location() -> &'static crate::panic::Location<'static> { + unreachable!() +} - /// Gets a reference to a static `Location` indicating where it was called. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// Consider using [`core::panic::Location::caller`] instead. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn caller_location() -> &'static crate::panic::Location<'static>; +/// Moves a value out of scope without running drop glue. +/// +/// This exists solely for [`crate::mem::forget_unsized`]; normal `forget` uses +/// `ManuallyDrop` instead. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn forget(_: T) { + unreachable!() +} - /// Moves a value out of scope without running drop glue. - /// - /// This exists solely for [`crate::mem::forget_unsized`]; normal `forget` uses - /// `ManuallyDrop` instead. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn forget(_: T); - - /// Reinterprets the bits of a value of one type as another type. - /// - /// Both types must have the same size. Compilation will fail if this is not guaranteed. - /// - /// `transmute` is semantically equivalent to a bitwise move of one type - /// into another. It copies the bits from the source value into the - /// destination value, then forgets the original. Note that source and destination - /// are passed by-value, which means if `Src` or `Dst` contain padding, that padding - /// is *not* guaranteed to be preserved by `transmute`. - /// - /// Both the argument and the result must be [valid](../../nomicon/what-unsafe-does.html) at - /// their given type. Violating this condition leads to [undefined behavior][ub]. The compiler - /// will generate code *assuming that you, the programmer, ensure that there will never be - /// undefined behavior*. It is therefore your responsibility to guarantee that every value - /// passed to `transmute` is valid at both types `Src` and `Dst`. Failing to uphold this condition - /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly - /// unsafe**. `transmute` should be the absolute last resort. - /// - /// Because `transmute` is a by-value operation, alignment of the *transmuted values - /// themselves* is not a concern. As with any other function, the compiler already ensures - /// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point - /// elsewhere* (such as pointers, references, boxes…), the caller has to ensure proper - /// alignment of the pointed-to values. - /// - /// The [nomicon](../../nomicon/transmutes.html) has additional documentation. - /// - /// [ub]: ../../reference/behavior-considered-undefined.html - /// - /// # Transmutation between pointers and integers - /// - /// Special care has to be taken when transmuting between pointers and integers, e.g. - /// transmuting between `*const ()` and `usize`. - /// - /// Transmuting *pointers to integers* in a `const` context is [undefined behavior][ub], unless - /// the pointer was originally created *from* an integer. (That includes this function - /// specifically, integer-to-pointer casts, and helpers like [`dangling`][crate::ptr::dangling], - /// but also semantically-equivalent conversions such as punning through `repr(C)` union - /// fields.) Any attempt to use the resulting value for integer operations will abort - /// const-evaluation. (And even outside `const`, such transmutation is touching on many - /// unspecified aspects of the Rust memory model and should be avoided. See below for - /// alternatives.) - /// - /// Transmuting *integers to pointers* is a largely unspecified operation. It is likely *not* - /// equivalent to an `as` cast. Doing non-zero-sized memory accesses with a pointer constructed - /// this way is currently considered undefined behavior. - /// - /// All this also applies when the integer is nested inside an array, tuple, struct, or enum. - /// However, `MaybeUninit` is not considered an integer type for the purpose of this - /// section. Transmuting `*const ()` to `MaybeUninit` is fine---but then calling - /// `assume_init()` on that result is considered as completing the pointer-to-integer transmute - /// and thus runs into the issues discussed above. - /// - /// In particular, doing a pointer-to-integer-to-pointer roundtrip via `transmute` is *not* a - /// lossless process. If you want to round-trip a pointer through an integer in a way that you - /// can get back the original pointer, you need to use `as` casts, or replace the integer type - /// by `MaybeUninit<$int>` (and never call `assume_init()`). If you are looking for a way to - /// store data of arbitrary type, also use `MaybeUninit` (that will also handle uninitialized - /// memory due to padding). If you specifically need to store something that is "either an - /// integer or a pointer", use `*mut ()`: integers can be converted to pointers and back without - /// any loss (via `as` casts or via `transmute`). - /// - /// # Examples - /// - /// There are a few things that `transmute` is really useful for. - /// - /// Turning a pointer into a function pointer. This is *not* portable to - /// machines where function pointers and data pointers have different sizes. - /// - /// ``` - /// fn foo() -> i32 { - /// 0 - /// } - /// // Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer. - /// // This avoids an integer-to-pointer `transmute`, which can be problematic. - /// // Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine. - /// let pointer = foo as *const (); - /// let function = unsafe { - /// std::mem::transmute::<*const (), fn() -> i32>(pointer) - /// }; - /// assert_eq!(function(), 0); - /// ``` - /// - /// Extending a lifetime, or shortening an invariant lifetime. This is - /// advanced, very unsafe Rust! - /// - /// ``` - /// struct R<'a>(&'a i32); - /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { - /// std::mem::transmute::, R<'static>>(r) - /// } - /// - /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) - /// -> &'b mut R<'c> { - /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) - /// } - /// ``` - /// - /// # Alternatives - /// - /// Don't despair: many uses of `transmute` can be achieved through other means. - /// Below are common applications of `transmute` which can be replaced with safer - /// constructs. - /// - /// Turning raw bytes (`[u8; SZ]`) into `u32`, `f64`, etc.: - /// - /// ``` - /// let raw_bytes = [0x78, 0x56, 0x34, 0x12]; - /// - /// let num = unsafe { - /// std::mem::transmute::<[u8; 4], u32>(raw_bytes) - /// }; - /// - /// // use `u32::from_ne_bytes` instead - /// let num = u32::from_ne_bytes(raw_bytes); - /// // or use `u32::from_le_bytes` or `u32::from_be_bytes` to specify the endianness - /// let num = u32::from_le_bytes(raw_bytes); - /// assert_eq!(num, 0x12345678); - /// let num = u32::from_be_bytes(raw_bytes); - /// assert_eq!(num, 0x78563412); - /// ``` - /// - /// Turning a pointer into a `usize`: - /// - /// ```no_run - /// let ptr = &0; - /// let ptr_num_transmute = unsafe { - /// std::mem::transmute::<&i32, usize>(ptr) - /// }; - /// - /// // Use an `as` cast instead - /// let ptr_num_cast = ptr as *const i32 as usize; - /// ``` - /// - /// Note that using `transmute` to turn a pointer to a `usize` is (as noted above) [undefined - /// behavior][ub] in `const` contexts. Also outside of consts, this operation might not behave - /// as expected -- this is touching on many unspecified aspects of the Rust memory model. - /// Depending on what the code is doing, the following alternatives are preferable to - /// pointer-to-integer transmutation: - /// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a - /// type for that buffer, it can use [`MaybeUninit`][crate::mem::MaybeUninit]. - /// - If the code actually wants to work on the address the pointer points to, it can use `as` - /// casts or [`ptr.addr()`][pointer::addr]. - /// - /// Turning a `*mut T` into a `&mut T`: - /// - /// ``` - /// let ptr: *mut i32 = &mut 0; - /// let ref_transmuted = unsafe { - /// std::mem::transmute::<*mut i32, &mut i32>(ptr) - /// }; - /// - /// // Use a reborrow instead - /// let ref_casted = unsafe { &mut *ptr }; - /// ``` - /// - /// Turning a `&mut T` into a `&mut U`: - /// - /// ``` - /// let ptr = &mut 0; - /// let val_transmuted = unsafe { - /// std::mem::transmute::<&mut i32, &mut u32>(ptr) - /// }; - /// - /// // Now, put together `as` and reborrowing - note the chaining of `as` - /// // `as` is not transitive - /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; - /// ``` - /// - /// Turning a `&str` into a `&[u8]`: - /// - /// ``` - /// // this is not a good way to do this. - /// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, &[82, 117, 115, 116]); - /// - /// // You could use `str::as_bytes` - /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, &[82, 117, 115, 116]); - /// - /// // Or, just use a byte string, if you have control over the string - /// // literal - /// assert_eq!(b"Rust", &[82, 117, 115, 116]); - /// ``` - /// - /// Turning a `Vec<&T>` into a `Vec>`. - /// - /// To transmute the inner type of the contents of a container, you must make sure to not - /// violate any of the container's invariants. For `Vec`, this means that both the size - /// *and alignment* of the inner types have to match. Other containers might rely on the - /// size of the type, alignment, or even the `TypeId`, in which case transmuting wouldn't - /// be possible at all without violating the container invariants. - /// - /// ``` - /// let store = [0, 1, 2, 3]; - /// let v_orig = store.iter().collect::>(); - /// - /// // clone the vector as we will reuse them later - /// let v_clone = v_orig.clone(); - /// - /// // Using transmute: this relies on the unspecified data layout of `Vec`, which is a - /// // bad idea and could cause Undefined Behavior. - /// // However, it is no-copy. - /// let v_transmuted = unsafe { - /// std::mem::transmute::, Vec>>(v_clone) - /// }; - /// - /// let v_clone = v_orig.clone(); - /// - /// // This is the suggested, safe way. - /// // It may copy the entire vector into a new one though, but also may not. - /// let v_collected = v_clone.into_iter() - /// .map(Some) - /// .collect::>>(); - /// - /// let v_clone = v_orig.clone(); - /// - /// // This is the proper no-copy, unsafe way of "transmuting" a `Vec`, without relying on the - /// // data layout. Instead of literally calling `transmute`, we perform a pointer cast, but - /// // in terms of converting the original inner type (`&i32`) to the new one (`Option<&i32>`), - /// // this has all the same caveats. Besides the information provided above, also consult the - /// // [`from_raw_parts`] documentation. - /// let v_from_raw = unsafe { - // FIXME Update this when vec_into_raw_parts is stabilized - /// // Ensure the original vector is not dropped. - /// let mut v_clone = std::mem::ManuallyDrop::new(v_clone); - /// Vec::from_raw_parts(v_clone.as_mut_ptr() as *mut Option<&i32>, - /// v_clone.len(), - /// v_clone.capacity()) - /// }; - /// ``` - /// - /// [`from_raw_parts`]: ../../std/vec/struct.Vec.html#method.from_raw_parts - /// - /// Implementing `split_at_mut`: - /// - /// ``` - /// use std::{slice, mem}; - /// - /// // There are multiple ways to do this, and there are multiple problems - /// // with the following (transmute) way. - /// fn split_at_mut_transmute(slice: &mut [T], mid: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(mid <= len); - /// unsafe { - /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); - /// // first: transmute is not type safe; all it checks is that T and - /// // U are of the same size. Second, right here, you have two - /// // mutable references pointing to the same memory. - /// (&mut slice[0..mid], &mut slice2[mid..len]) - /// } - /// } - /// - /// // This gets rid of the type safety problems; `&mut *` will *only* give - /// // you a `&mut T` from a `&mut T` or `*mut T`. - /// fn split_at_mut_casts(slice: &mut [T], mid: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(mid <= len); - /// unsafe { - /// let slice2 = &mut *(slice as *mut [T]); - /// // however, you still have two mutable references pointing to - /// // the same memory. - /// (&mut slice[0..mid], &mut slice2[mid..len]) - /// } - /// } - /// - /// // This is how the standard library does it. This is the best method, if - /// // you need to do something like this - /// fn split_at_stdlib(slice: &mut [T], mid: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(mid <= len); - /// unsafe { - /// let ptr = slice.as_mut_ptr(); - /// // This now has three mutable references pointing at the same - /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. - /// // `slice` is never used after `let ptr = ...`, and so one can - /// // treat it as "dead", and therefore, you only have two real - /// // mutable slices. - /// (slice::from_raw_parts_mut(ptr, mid), - /// slice::from_raw_parts_mut(ptr.add(mid), len - mid)) - /// } - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_allowed_through_unstable_modules] - #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] - #[rustc_diagnostic_item = "transmute"] - #[rustc_nounwind] - pub fn transmute(src: Src) -> Dst; - - /// Like [`transmute`], but even less checked at compile-time: rather than - /// giving an error for `size_of::() != size_of::()`, it's - /// **Undefined Behavior** at runtime. - /// - /// Prefer normal `transmute` where possible, for the extra checking, since - /// both do exactly the same thing at runtime, if they both compile. - /// - /// This is not expected to ever be exposed directly to users, rather it - /// may eventually be exposed through some more-constrained API. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn transmute_unchecked(src: Src) -> Dst; +/// Reinterprets the bits of a value of one type as another type. +/// +/// Both types must have the same size. Compilation will fail if this is not guaranteed. +/// +/// `transmute` is semantically equivalent to a bitwise move of one type +/// into another. It copies the bits from the source value into the +/// destination value, then forgets the original. Note that source and destination +/// are passed by-value, which means if `Src` or `Dst` contain padding, that padding +/// is *not* guaranteed to be preserved by `transmute`. +/// +/// Both the argument and the result must be [valid](../../nomicon/what-unsafe-does.html) at +/// their given type. Violating this condition leads to [undefined behavior][ub]. The compiler +/// will generate code *assuming that you, the programmer, ensure that there will never be +/// undefined behavior*. It is therefore your responsibility to guarantee that every value +/// passed to `transmute` is valid at both types `Src` and `Dst`. Failing to uphold this condition +/// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly +/// unsafe**. `transmute` should be the absolute last resort. +/// +/// Because `transmute` is a by-value operation, alignment of the *transmuted values +/// themselves* is not a concern. As with any other function, the compiler already ensures +/// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point +/// elsewhere* (such as pointers, references, boxes…), the caller has to ensure proper +/// alignment of the pointed-to values. +/// +/// The [nomicon](../../nomicon/transmutes.html) has additional documentation. +/// +/// [ub]: ../../reference/behavior-considered-undefined.html +/// +/// # Transmutation between pointers and integers +/// +/// Special care has to be taken when transmuting between pointers and integers, e.g. +/// transmuting between `*const ()` and `usize`. +/// +/// Transmuting *pointers to integers* in a `const` context is [undefined behavior][ub], unless +/// the pointer was originally created *from* an integer. (That includes this function +/// specifically, integer-to-pointer casts, and helpers like [`dangling`][crate::ptr::dangling], +/// but also semantically-equivalent conversions such as punning through `repr(C)` union +/// fields.) Any attempt to use the resulting value for integer operations will abort +/// const-evaluation. (And even outside `const`, such transmutation is touching on many +/// unspecified aspects of the Rust memory model and should be avoided. See below for +/// alternatives.) +/// +/// Transmuting *integers to pointers* is a largely unspecified operation. It is likely *not* +/// equivalent to an `as` cast. Doing non-zero-sized memory accesses with a pointer constructed +/// this way is currently considered undefined behavior. +/// +/// All this also applies when the integer is nested inside an array, tuple, struct, or enum. +/// However, `MaybeUninit` is not considered an integer type for the purpose of this +/// section. Transmuting `*const ()` to `MaybeUninit` is fine---but then calling +/// `assume_init()` on that result is considered as completing the pointer-to-integer transmute +/// and thus runs into the issues discussed above. +/// +/// In particular, doing a pointer-to-integer-to-pointer roundtrip via `transmute` is *not* a +/// lossless process. If you want to round-trip a pointer through an integer in a way that you +/// can get back the original pointer, you need to use `as` casts, or replace the integer type +/// by `MaybeUninit<$int>` (and never call `assume_init()`). If you are looking for a way to +/// store data of arbitrary type, also use `MaybeUninit` (that will also handle uninitialized +/// memory due to padding). If you specifically need to store something that is "either an +/// integer or a pointer", use `*mut ()`: integers can be converted to pointers and back without +/// any loss (via `as` casts or via `transmute`). +/// +/// # Examples +/// +/// There are a few things that `transmute` is really useful for. +/// +/// Turning a pointer into a function pointer. This is *not* portable to +/// machines where function pointers and data pointers have different sizes. +/// +/// ``` +/// fn foo() -> i32 { +/// 0 +/// } +/// // Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer. +/// // This avoids an integer-to-pointer `transmute`, which can be problematic. +/// // Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine. +/// let pointer = foo as *const (); +/// let function = unsafe { +/// std::mem::transmute::<*const (), fn() -> i32>(pointer) +/// }; +/// assert_eq!(function(), 0); +/// ``` +/// +/// Extending a lifetime, or shortening an invariant lifetime. This is +/// advanced, very unsafe Rust! +/// +/// ``` +/// struct R<'a>(&'a i32); +/// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { +/// std::mem::transmute::, R<'static>>(r) +/// } +/// +/// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) +/// -> &'b mut R<'c> { +/// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) +/// } +/// ``` +/// +/// # Alternatives +/// +/// Don't despair: many uses of `transmute` can be achieved through other means. +/// Below are common applications of `transmute` which can be replaced with safer +/// constructs. +/// +/// Turning raw bytes (`[u8; SZ]`) into `u32`, `f64`, etc.: +/// +/// ``` +/// let raw_bytes = [0x78, 0x56, 0x34, 0x12]; +/// +/// let num = unsafe { +/// std::mem::transmute::<[u8; 4], u32>(raw_bytes) +/// }; +/// +/// // use `u32::from_ne_bytes` instead +/// let num = u32::from_ne_bytes(raw_bytes); +/// // or use `u32::from_le_bytes` or `u32::from_be_bytes` to specify the endianness +/// let num = u32::from_le_bytes(raw_bytes); +/// assert_eq!(num, 0x12345678); +/// let num = u32::from_be_bytes(raw_bytes); +/// assert_eq!(num, 0x78563412); +/// ``` +/// +/// Turning a pointer into a `usize`: +/// +/// ```no_run +/// let ptr = &0; +/// let ptr_num_transmute = unsafe { +/// std::mem::transmute::<&i32, usize>(ptr) +/// }; +/// +/// // Use an `as` cast instead +/// let ptr_num_cast = ptr as *const i32 as usize; +/// ``` +/// +/// Note that using `transmute` to turn a pointer to a `usize` is (as noted above) [undefined +/// behavior][ub] in `const` contexts. Also outside of consts, this operation might not behave +/// as expected -- this is touching on many unspecified aspects of the Rust memory model. +/// Depending on what the code is doing, the following alternatives are preferable to +/// pointer-to-integer transmutation: +/// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a +/// type for that buffer, it can use [`MaybeUninit`][crate::mem::MaybeUninit]. +/// - If the code actually wants to work on the address the pointer points to, it can use `as` +/// casts or [`ptr.addr()`][pointer::addr]. +/// +/// Turning a `*mut T` into a `&mut T`: +/// +/// ``` +/// let ptr: *mut i32 = &mut 0; +/// let ref_transmuted = unsafe { +/// std::mem::transmute::<*mut i32, &mut i32>(ptr) +/// }; +/// +/// // Use a reborrow instead +/// let ref_casted = unsafe { &mut *ptr }; +/// ``` +/// +/// Turning a `&mut T` into a `&mut U`: +/// +/// ``` +/// let ptr = &mut 0; +/// let val_transmuted = unsafe { +/// std::mem::transmute::<&mut i32, &mut u32>(ptr) +/// }; +/// +/// // Now, put together `as` and reborrowing - note the chaining of `as` +/// // `as` is not transitive +/// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; +/// ``` +/// +/// Turning a `&str` into a `&[u8]`: +/// +/// ``` +/// // this is not a good way to do this. +/// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") }; +/// assert_eq!(slice, &[82, 117, 115, 116]); +/// +/// // You could use `str::as_bytes` +/// let slice = "Rust".as_bytes(); +/// assert_eq!(slice, &[82, 117, 115, 116]); +/// +/// // Or, just use a byte string, if you have control over the string +/// // literal +/// assert_eq!(b"Rust", &[82, 117, 115, 116]); +/// ``` +/// +/// Turning a `Vec<&T>` into a `Vec>`. +/// +/// To transmute the inner type of the contents of a container, you must make sure to not +/// violate any of the container's invariants. For `Vec`, this means that both the size +/// *and alignment* of the inner types have to match. Other containers might rely on the +/// size of the type, alignment, or even the `TypeId`, in which case transmuting wouldn't +/// be possible at all without violating the container invariants. +/// +/// ``` +/// let store = [0, 1, 2, 3]; +/// let v_orig = store.iter().collect::>(); +/// +/// // clone the vector as we will reuse them later +/// let v_clone = v_orig.clone(); +/// +/// // Using transmute: this relies on the unspecified data layout of `Vec`, which is a +/// // bad idea and could cause Undefined Behavior. +/// // However, it is no-copy. +/// let v_transmuted = unsafe { +/// std::mem::transmute::, Vec>>(v_clone) +/// }; +/// +/// let v_clone = v_orig.clone(); +/// +/// // This is the suggested, safe way. +/// // It may copy the entire vector into a new one though, but also may not. +/// let v_collected = v_clone.into_iter() +/// .map(Some) +/// .collect::>>(); +/// +/// let v_clone = v_orig.clone(); +/// +/// // This is the proper no-copy, unsafe way of "transmuting" a `Vec`, without relying on the +/// // data layout. Instead of literally calling `transmute`, we perform a pointer cast, but +/// // in terms of converting the original inner type (`&i32`) to the new one (`Option<&i32>`), +/// // this has all the same caveats. Besides the information provided above, also consult the +/// // [`from_raw_parts`] documentation. +/// let v_from_raw = unsafe { +// FIXME Update this when vec_into_raw_parts is stabilized +/// // Ensure the original vector is not dropped. +/// let mut v_clone = std::mem::ManuallyDrop::new(v_clone); +/// Vec::from_raw_parts(v_clone.as_mut_ptr() as *mut Option<&i32>, +/// v_clone.len(), +/// v_clone.capacity()) +/// }; +/// ``` +/// +/// [`from_raw_parts`]: ../../std/vec/struct.Vec.html#method.from_raw_parts +/// +/// Implementing `split_at_mut`: +/// +/// ``` +/// use std::{slice, mem}; +/// +/// // There are multiple ways to do this, and there are multiple problems +/// // with the following (transmute) way. +/// fn split_at_mut_transmute(slice: &mut [T], mid: usize) +/// -> (&mut [T], &mut [T]) { +/// let len = slice.len(); +/// assert!(mid <= len); +/// unsafe { +/// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); +/// // first: transmute is not type safe; all it checks is that T and +/// // U are of the same size. Second, right here, you have two +/// // mutable references pointing to the same memory. +/// (&mut slice[0..mid], &mut slice2[mid..len]) +/// } +/// } +/// +/// // This gets rid of the type safety problems; `&mut *` will *only* give +/// // you a `&mut T` from a `&mut T` or `*mut T`. +/// fn split_at_mut_casts(slice: &mut [T], mid: usize) +/// -> (&mut [T], &mut [T]) { +/// let len = slice.len(); +/// assert!(mid <= len); +/// unsafe { +/// let slice2 = &mut *(slice as *mut [T]); +/// // however, you still have two mutable references pointing to +/// // the same memory. +/// (&mut slice[0..mid], &mut slice2[mid..len]) +/// } +/// } +/// +/// // This is how the standard library does it. This is the best method, if +/// // you need to do something like this +/// fn split_at_stdlib(slice: &mut [T], mid: usize) +/// -> (&mut [T], &mut [T]) { +/// let len = slice.len(); +/// assert!(mid <= len); +/// unsafe { +/// let ptr = slice.as_mut_ptr(); +/// // This now has three mutable references pointing at the same +/// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. +/// // `slice` is never used after `let ptr = ...`, and so one can +/// // treat it as "dead", and therefore, you only have two real +/// // mutable slices. +/// (slice::from_raw_parts_mut(ptr, mid), +/// slice::from_raw_parts_mut(ptr.add(mid), len - mid)) +/// } +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_allowed_through_unstable_modules] +#[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] +#[rustc_diagnostic_item = "transmute"] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn transmute(_src: Src) -> Dst { + unreachable!() +} - /// Returns `true` if the actual type given as `T` requires drop - /// glue; returns `false` if the actual type provided for `T` - /// implements `Copy`. - /// - /// If the actual type neither requires drop glue nor implements - /// `Copy`, then the return value of this function is unspecified. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn needs_drop() -> bool; +/// Like [`transmute`], but even less checked at compile-time: rather than +/// giving an error for `size_of::() != size_of::()`, it's +/// **Undefined Behavior** at runtime. +/// +/// Prefer normal `transmute` where possible, for the extra checking, since +/// both do exactly the same thing at runtime, if they both compile. +/// +/// This is not expected to ever be exposed directly to users, rather it +/// may eventually be exposed through some more-constrained API. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn transmute_unchecked(_src: Src) -> Dst { + unreachable!() +} - /// Calculates the offset from a pointer. - /// - /// This is implemented as an intrinsic to avoid converting to and from an - /// integer, since the conversion would throw away aliasing information. - /// - /// This can only be used with `Ptr` as a raw pointer type (`*mut` or `*const`) - /// to a `Sized` pointee and with `Delta` as `usize` or `isize`. Any other - /// instantiations may arbitrarily misbehave, and that's *not* a compiler bug. - /// - /// # Safety - /// - /// If the computed offset is non-zero, then both the starting and resulting pointer must be - /// either in bounds or at the end of an allocated object. If either pointer is out - /// of bounds or arithmetic overflow occurs then this operation is undefined behavior. - /// - /// The stabilized version of this intrinsic is [`pointer::offset`]. - #[must_use = "returns a new pointer rather than modifying its argument"] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn offset(dst: Ptr, offset: Delta) -> Ptr; +/// Returns `true` if the actual type given as `T` requires drop +/// glue; returns `false` if the actual type provided for `T` +/// implements `Copy`. +/// +/// If the actual type neither requires drop glue nor implements +/// `Copy`, then the return value of this function is unspecified. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn needs_drop() -> bool { + unreachable!() +} - /// Calculates the offset from a pointer, potentially wrapping. - /// - /// This is implemented as an intrinsic to avoid converting to and from an - /// integer, since the conversion inhibits certain optimizations. - /// - /// # Safety - /// - /// Unlike the `offset` intrinsic, this intrinsic does not restrict the - /// resulting pointer to point into or at the end of an allocated - /// object, and it wraps with two's complement arithmetic. The resulting - /// value is not necessarily valid to be used to actually access memory. - /// - /// The stabilized version of this intrinsic is [`pointer::wrapping_offset`]. - #[must_use = "returns a new pointer rather than modifying its argument"] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn arith_offset(dst: *const T, offset: isize) -> *const T; +/// Calculates the offset from a pointer. +/// +/// This is implemented as an intrinsic to avoid converting to and from an +/// integer, since the conversion would throw away aliasing information. +/// +/// This can only be used with `Ptr` as a raw pointer type (`*mut` or `*const`) +/// to a `Sized` pointee and with `Delta` as `usize` or `isize`. Any other +/// instantiations may arbitrarily misbehave, and that's *not* a compiler bug. +/// +/// # Safety +/// +/// If the computed offset is non-zero, then both the starting and resulting pointer must be +/// either in bounds or at the end of an allocated object. If either pointer is out +/// of bounds or arithmetic overflow occurs then this operation is undefined behavior. +/// +/// The stabilized version of this intrinsic is [`pointer::offset`]. +#[must_use = "returns a new pointer rather than modifying its argument"] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn offset(_dst: Ptr, _offset: Delta) -> Ptr { + unreachable!() +} + +/// Calculates the offset from a pointer, potentially wrapping. +/// +/// This is implemented as an intrinsic to avoid converting to and from an +/// integer, since the conversion inhibits certain optimizations. +/// +/// # Safety +/// +/// Unlike the `offset` intrinsic, this intrinsic does not restrict the +/// resulting pointer to point into or at the end of an allocated +/// object, and it wraps with two's complement arithmetic. The resulting +/// value is not necessarily valid to be used to actually access memory. +/// +/// The stabilized version of this intrinsic is [`pointer::wrapping_offset`]. +#[must_use = "returns a new pointer rather than modifying its argument"] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn arith_offset(_dst: *const T, _offset: isize) -> *const T { + unreachable!() +} +extern "rust-intrinsic" { /// Masks out bits of the pointer according to a mask. /// /// Note that, unlike most intrinsics, this is safe to call; @@ -2143,474 +2181,569 @@ extern "rust-intrinsic" { /// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`]. #[rustc_nounwind] pub fn float_to_int_unchecked(value: Float) -> Int; +} - /// Returns the number of bits set in an integer type `T` - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `count_ones` method. For example, - /// [`u32::count_ones`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn ctpop(x: T) -> u32; - - /// Returns the number of leading unset bits (zeroes) in an integer type `T`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `leading_zeros` method. For example, - /// [`u32::leading_zeros`] - /// - /// # Examples - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::ctlz; - /// - /// let x = 0b0001_1100_u8; - /// let num_leading = ctlz(x); - /// assert_eq!(num_leading, 3); - /// ``` - /// - /// An `x` with value `0` will return the bit width of `T`. - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::ctlz; - /// - /// let x = 0u16; - /// let num_leading = ctlz(x); - /// assert_eq!(num_leading, 16); - /// ``` - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn ctlz(x: T) -> u32; +/// Returns the number of bits set in an integer type `T` +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `count_ones` method. For example, +/// [`u32::count_ones`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn ctpop(_x: T) -> u32 { + unimplemented!() +} - /// Like `ctlz`, but extra-unsafe as it returns `undef` when - /// given an `x` with value `0`. - /// - /// This intrinsic does not have a stable counterpart. - /// - /// # Examples - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::ctlz_nonzero; - /// - /// let x = 0b0001_1100_u8; - /// let num_leading = unsafe { ctlz_nonzero(x) }; - /// assert_eq!(num_leading, 3); - /// ``` - #[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn ctlz_nonzero(x: T) -> u32; +/// Returns the number of leading unset bits (zeroes) in an integer type `T`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `leading_zeros` method. For example, +/// [`u32::leading_zeros`] +/// +/// # Examples +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::ctlz; +/// +/// let x = 0b0001_1100_u8; +/// let num_leading = ctlz(x); +/// assert_eq!(num_leading, 3); +/// ``` +/// +/// An `x` with value `0` will return the bit width of `T`. +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::ctlz; +/// +/// let x = 0u16; +/// let num_leading = ctlz(x); +/// assert_eq!(num_leading, 16); +/// ``` +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn ctlz(_x: T) -> u32 { + unimplemented!() +} - /// Returns the number of trailing unset bits (zeroes) in an integer type `T`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `trailing_zeros` method. For example, - /// [`u32::trailing_zeros`] - /// - /// # Examples - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::cttz; - /// - /// let x = 0b0011_1000_u8; - /// let num_trailing = cttz(x); - /// assert_eq!(num_trailing, 3); - /// ``` - /// - /// An `x` with value `0` will return the bit width of `T`: - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::cttz; - /// - /// let x = 0u16; - /// let num_trailing = cttz(x); - /// assert_eq!(num_trailing, 16); - /// ``` - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn cttz(x: T) -> u32; +/// Like `ctlz`, but extra-unsafe as it returns `undef` when +/// given an `x` with value `0`. +/// +/// This intrinsic does not have a stable counterpart. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::ctlz_nonzero; +/// +/// let x = 0b0001_1100_u8; +/// let num_leading = unsafe { ctlz_nonzero(x) }; +/// assert_eq!(num_leading, 3); +/// ``` +#[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn ctlz_nonzero(_x: T) -> u32 { + unimplemented!() +} - /// Like `cttz`, but extra-unsafe as it returns `undef` when - /// given an `x` with value `0`. - /// - /// This intrinsic does not have a stable counterpart. - /// - /// # Examples - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::cttz_nonzero; - /// - /// let x = 0b0011_1000_u8; - /// let num_trailing = unsafe { cttz_nonzero(x) }; - /// assert_eq!(num_trailing, 3); - /// ``` - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn cttz_nonzero(x: T) -> u32; +/// Returns the number of trailing unset bits (zeroes) in an integer type `T`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `trailing_zeros` method. For example, +/// [`u32::trailing_zeros`] +/// +/// # Examples +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::cttz; +/// +/// let x = 0b0011_1000_u8; +/// let num_trailing = cttz(x); +/// assert_eq!(num_trailing, 3); +/// ``` +/// +/// An `x` with value `0` will return the bit width of `T`: +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::cttz; +/// +/// let x = 0u16; +/// let num_trailing = cttz(x); +/// assert_eq!(num_trailing, 16); +/// ``` +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn cttz(_x: T) -> u32 { + unimplemented!() +} - /// Reverses the bytes in an integer type `T`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `swap_bytes` method. For example, - /// [`u32::swap_bytes`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn bswap(x: T) -> T; +/// Like `cttz`, but extra-unsafe as it returns `undef` when +/// given an `x` with value `0`. +/// +/// This intrinsic does not have a stable counterpart. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::cttz_nonzero; +/// +/// let x = 0b0011_1000_u8; +/// let num_trailing = unsafe { cttz_nonzero(x) }; +/// assert_eq!(num_trailing, 3); +/// ``` +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn cttz_nonzero(_x: T) -> u32 { + unimplemented!() +} - /// Reverses the bits in an integer type `T`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `reverse_bits` method. For example, - /// [`u32::reverse_bits`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn bitreverse(x: T) -> T; +/// Reverses the bytes in an integer type `T`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `swap_bytes` method. For example, +/// [`u32::swap_bytes`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn bswap(_x: T) -> T { + unimplemented!() +} - /// Does a three-way comparison between the two integer arguments. - /// - /// This is included as an intrinsic as it's useful to let it be one thing - /// in MIR, rather than the multiple checks and switches that make its IR - /// large and difficult to optimize. - /// - /// The stabilized version of this intrinsic is [`Ord::cmp`]. - #[rustc_const_unstable(feature = "const_three_way_compare", issue = "none")] - #[rustc_safe_intrinsic] - pub fn three_way_compare(lhs: T, rhs: T) -> crate::cmp::Ordering; +/// Reverses the bits in an integer type `T`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `reverse_bits` method. For example, +/// [`u32::reverse_bits`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn bitreverse(_x: T) -> T { + unimplemented!() +} - /// Performs checked integer addition. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `overflowing_add` method. For example, - /// [`u32::overflowing_add`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn add_with_overflow(x: T, y: T) -> (T, bool); +/// Does a three-way comparison between the two integer arguments. +/// +/// This is included as an intrinsic as it's useful to let it be one thing +/// in MIR, rather than the multiple checks and switches that make its IR +/// large and difficult to optimize. +/// +/// The stabilized version of this intrinsic is [`Ord::cmp`]. +#[rustc_const_unstable(feature = "const_three_way_compare", issue = "none")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Ordering { + unimplemented!() +} - /// Performs checked integer subtraction - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `overflowing_sub` method. For example, - /// [`u32::overflowing_sub`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn sub_with_overflow(x: T, y: T) -> (T, bool); +/// Performs checked integer addition. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `overflowing_add` method. For example, +/// [`u32::overflowing_add`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn add_with_overflow(_x: T, _y: T) -> (T, bool) { + unimplemented!() +} - /// Performs checked integer multiplication - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `overflowing_mul` method. For example, - /// [`u32::overflowing_mul`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn mul_with_overflow(x: T, y: T) -> (T, bool); +/// Performs checked integer subtraction +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `overflowing_sub` method. For example, +/// [`u32::overflowing_sub`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn sub_with_overflow(_x: T, _y: T) -> (T, bool) { + unimplemented!() +} - /// Performs an exact division, resulting in undefined behavior where - /// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_exact_div", issue = "none")] - #[rustc_nounwind] - pub fn exact_div(x: T, y: T) -> T; +/// Performs checked integer multiplication +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `overflowing_mul` method. For example, +/// [`u32::overflowing_mul`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn mul_with_overflow(_x: T, _y: T) -> (T, bool) { + unimplemented!() +} - /// Performs an unchecked division, resulting in undefined behavior - /// where `y == 0` or `x == T::MIN && y == -1` - /// - /// Safe wrappers for this intrinsic are available on the integer - /// primitives via the `checked_div` method. For example, - /// [`u32::checked_div`] - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_div(x: T, y: T) -> T; - /// Returns the remainder of an unchecked division, resulting in - /// undefined behavior when `y == 0` or `x == T::MIN && y == -1` - /// - /// Safe wrappers for this intrinsic are available on the integer - /// primitives via the `checked_rem` method. For example, - /// [`u32::checked_rem`] - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_rem(x: T, y: T) -> T; +/// Performs an exact division, resulting in undefined behavior where +/// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_const_unstable(feature = "const_exact_div", issue = "none")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn exact_div(_x: T, _y: T) -> T { + unimplemented!() +} - /// Performs an unchecked left shift, resulting in undefined behavior when - /// `y < 0` or `y >= N`, where N is the width of T in bits. - /// - /// Safe wrappers for this intrinsic are available on the integer - /// primitives via the `checked_shl` method. For example, - /// [`u32::checked_shl`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_shl(x: T, y: U) -> T; - /// Performs an unchecked right shift, resulting in undefined behavior when - /// `y < 0` or `y >= N`, where N is the width of T in bits. - /// - /// Safe wrappers for this intrinsic are available on the integer - /// primitives via the `checked_shr` method. For example, - /// [`u32::checked_shr`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_shr(x: T, y: U) -> T; +/// Performs an unchecked division, resulting in undefined behavior +/// where `y == 0` or `x == T::MIN && y == -1` +/// +/// Safe wrappers for this intrinsic are available on the integer +/// primitives via the `checked_div` method. For example, +/// [`u32::checked_div`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_div(_x: T, _y: T) -> T { + unimplemented!() +} +/// Returns the remainder of an unchecked division, resulting in +/// undefined behavior when `y == 0` or `x == T::MIN && y == -1` +/// +/// Safe wrappers for this intrinsic are available on the integer +/// primitives via the `checked_rem` method. For example, +/// [`u32::checked_rem`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_rem(_x: T, _y: T) -> T { + unimplemented!() +} - /// Returns the result of an unchecked addition, resulting in - /// undefined behavior when `x + y > T::MAX` or `x + y < T::MIN`. - /// - /// The stable counterpart of this intrinsic is `unchecked_add` on the various - /// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`]. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_add(x: T, y: T) -> T; +/// Performs an unchecked left shift, resulting in undefined behavior when +/// `y < 0` or `y >= N`, where N is the width of T in bits. +/// +/// Safe wrappers for this intrinsic are available on the integer +/// primitives via the `checked_shl` method. For example, +/// [`u32::checked_shl`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_shl(_x: T, _y: U) -> T { + unimplemented!() +} +/// Performs an unchecked right shift, resulting in undefined behavior when +/// `y < 0` or `y >= N`, where N is the width of T in bits. +/// +/// Safe wrappers for this intrinsic are available on the integer +/// primitives via the `checked_shr` method. For example, +/// [`u32::checked_shr`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_shr(_x: T, _y: U) -> T { + unimplemented!() +} - /// Returns the result of an unchecked subtraction, resulting in - /// undefined behavior when `x - y > T::MAX` or `x - y < T::MIN`. - /// - /// The stable counterpart of this intrinsic is `unchecked_sub` on the various - /// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`]. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_sub(x: T, y: T) -> T; +/// Returns the result of an unchecked addition, resulting in +/// undefined behavior when `x + y > T::MAX` or `x + y < T::MIN`. +/// +/// The stable counterpart of this intrinsic is `unchecked_add` on the various +/// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`]. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_add(_x: T, _y: T) -> T { + unimplemented!() +} + +/// Returns the result of an unchecked subtraction, resulting in +/// undefined behavior when `x - y > T::MAX` or `x - y < T::MIN`. +/// +/// The stable counterpart of this intrinsic is `unchecked_sub` on the various +/// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`]. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_sub(_x: T, _y: T) -> T { + unimplemented!() +} - /// Returns the result of an unchecked multiplication, resulting in - /// undefined behavior when `x * y > T::MAX` or `x * y < T::MIN`. - /// - /// The stable counterpart of this intrinsic is `unchecked_mul` on the various - /// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`]. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_mul(x: T, y: T) -> T; +/// Returns the result of an unchecked multiplication, resulting in +/// undefined behavior when `x * y > T::MAX` or `x * y < T::MIN`. +/// +/// The stable counterpart of this intrinsic is `unchecked_mul` on the various +/// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`]. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_mul(_x: T, _y: T) -> T { + unimplemented!() +} - /// Performs rotate left. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `rotate_left` method. For example, - /// [`u32::rotate_left`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn rotate_left(x: T, shift: u32) -> T; +/// Performs rotate left. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `rotate_left` method. For example, +/// [`u32::rotate_left`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn rotate_left(_x: T, _shift: u32) -> T { + unimplemented!() +} - /// Performs rotate right. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `rotate_right` method. For example, - /// [`u32::rotate_right`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn rotate_right(x: T, shift: u32) -> T; +/// Performs rotate right. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `rotate_right` method. For example, +/// [`u32::rotate_right`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn rotate_right(_x: T, _shift: u32) -> T { + unimplemented!() +} - /// Returns (a + b) mod 2N, where N is the width of T in bits. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `wrapping_add` method. For example, - /// [`u32::wrapping_add`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn wrapping_add(a: T, b: T) -> T; - /// Returns (a - b) mod 2N, where N is the width of T in bits. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `wrapping_sub` method. For example, - /// [`u32::wrapping_sub`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn wrapping_sub(a: T, b: T) -> T; - /// Returns (a * b) mod 2N, where N is the width of T in bits. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `wrapping_mul` method. For example, - /// [`u32::wrapping_mul`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn wrapping_mul(a: T, b: T) -> T; +/// Returns (a + b) mod 2N, where N is the width of T in bits. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `wrapping_add` method. For example, +/// [`u32::wrapping_add`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn wrapping_add(_a: T, _b: T) -> T { + unimplemented!() +} +/// Returns (a - b) mod 2N, where N is the width of T in bits. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `wrapping_sub` method. For example, +/// [`u32::wrapping_sub`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn wrapping_sub(_a: T, _b: T) -> T { + unimplemented!() +} +/// Returns (a * b) mod 2N, where N is the width of T in bits. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `wrapping_mul` method. For example, +/// [`u32::wrapping_mul`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn wrapping_mul(_a: T, _b: T) -> T { + unimplemented!() +} - /// Computes `a + b`, saturating at numeric bounds. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `saturating_add` method. For example, - /// [`u32::saturating_add`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn saturating_add(a: T, b: T) -> T; - /// Computes `a - b`, saturating at numeric bounds. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `saturating_sub` method. For example, - /// [`u32::saturating_sub`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn saturating_sub(a: T, b: T) -> T; +/// Computes `a + b`, saturating at numeric bounds. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `saturating_add` method. For example, +/// [`u32::saturating_add`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn saturating_add(_a: T, _b: T) -> T { + unimplemented!() +} +/// Computes `a - b`, saturating at numeric bounds. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `saturating_sub` method. For example, +/// [`u32::saturating_sub`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn saturating_sub(_a: T, _b: T) -> T { + unimplemented!() +} - /// This is an implementation detail of [`crate::ptr::read`] and should - /// not be used anywhere else. See its comments for why this exists. - /// - /// This intrinsic can *only* be called where the pointer is a local without - /// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it - /// trivially obeys runtime-MIR rules about derefs in operands. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn read_via_copy(ptr: *const T) -> T; +/// This is an implementation detail of [`crate::ptr::read`] and should +/// not be used anywhere else. See its comments for why this exists. +/// +/// This intrinsic can *only* be called where the pointer is a local without +/// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it +/// trivially obeys runtime-MIR rules about derefs in operands. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn read_via_copy(_ptr: *const T) -> T { + unimplemented!() +} - /// This is an implementation detail of [`crate::ptr::write`] and should - /// not be used anywhere else. See its comments for why this exists. - /// - /// This intrinsic can *only* be called where the pointer is a local without - /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so - /// that it trivially obeys runtime-MIR rules about derefs in operands. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn write_via_move(ptr: *mut T, value: T); +/// This is an implementation detail of [`crate::ptr::write`] and should +/// not be used anywhere else. See its comments for why this exists. +/// +/// This intrinsic can *only* be called where the pointer is a local without +/// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so +/// that it trivially obeys runtime-MIR rules about derefs in operands. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn write_via_move(_ptr: *mut T, _value: T) { + unimplemented!() +} - /// Returns the value of the discriminant for the variant in 'v'; - /// if `T` has no discriminant, returns `0`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is [`core::mem::discriminant`]. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn discriminant_value(v: &T) -> ::Discriminant; +/// Returns the value of the discriminant for the variant in 'v'; +/// if `T` has no discriminant, returns `0`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`core::mem::discriminant`]. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn discriminant_value(_v: &T) -> ::Discriminant { + unimplemented!() +} +extern "rust-intrinsic" { /// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the /// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs. /// @@ -2638,17 +2771,25 @@ extern "rust-intrinsic" { /// in ways that are not allowed for regular writes). #[rustc_nounwind] pub fn nontemporal_store(ptr: *mut T, val: T); +} - /// See documentation of `<*const T>::offset_from` for details. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn ptr_offset_from(ptr: *const T, base: *const T) -> isize; +/// See documentation of `<*const T>::offset_from` for details. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn ptr_offset_from(_ptr: *const T, _base: *const T) -> isize { + unimplemented!() +} - /// See documentation of `<*const T>::sub_ptr` for details. - #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] - #[rustc_nounwind] - pub fn ptr_offset_from_unsigned(ptr: *const T, base: *const T) -> usize; +/// See documentation of `<*const T>::sub_ptr` for details. +#[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn ptr_offset_from_unsigned(_ptr: *const T, _base: *const T) -> usize { + unimplemented!() } /// See documentation of `<*const T>::guaranteed_eq` for details. @@ -2666,59 +2807,68 @@ pub const fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8 { (ptr == other) as u8 } -extern "rust-intrinsic" { - /// Determines whether the raw bytes of the two values are equal. - /// - /// This is particularly handy for arrays, since it allows things like just - /// comparing `i96`s instead of forcing `alloca`s for `[6 x i16]`. - /// - /// Above some backend-decided threshold this will emit calls to `memcmp`, - /// like slice equality does, instead of causing massive code size. - /// - /// Since this works by comparing the underlying bytes, the actual `T` is - /// not particularly important. It will be used for its size and alignment, - /// but any validity restrictions will be ignored, not enforced. - /// - /// # Safety - /// - /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized. - /// Note that this is a stricter criterion than just the *values* being - /// fully-initialized: if `T` has padding, it's UB to call this intrinsic. - /// - /// At compile-time, it is furthermore UB to call this if any of the bytes - /// in `*a` or `*b` have provenance. - /// - /// (The implementation is allowed to branch on the results of comparisons, - /// which is UB if any of their inputs are `undef`.) - #[rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none")] - #[rustc_nounwind] - pub fn raw_eq(a: &T, b: &T) -> bool; +/// Determines whether the raw bytes of the two values are equal. +/// +/// This is particularly handy for arrays, since it allows things like just +/// comparing `i96`s instead of forcing `alloca`s for `[6 x i16]`. +/// +/// Above some backend-decided threshold this will emit calls to `memcmp`, +/// like slice equality does, instead of causing massive code size. +/// +/// Since this works by comparing the underlying bytes, the actual `T` is +/// not particularly important. It will be used for its size and alignment, +/// but any validity restrictions will be ignored, not enforced. +/// +/// # Safety +/// +/// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized. +/// Note that this is a stricter criterion than just the *values* being +/// fully-initialized: if `T` has padding, it's UB to call this intrinsic. +/// +/// At compile-time, it is furthermore UB to call this if any of the bytes +/// in `*a` or `*b` have provenance. +/// +/// (The implementation is allowed to branch on the results of comparisons, +/// which is UB if any of their inputs are `undef`.) +#[rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn raw_eq(_a: &T, _b: &T) -> bool { + unimplemented!() +} - /// Lexicographically compare `[left, left + bytes)` and `[right, right + bytes)` - /// as unsigned bytes, returning negative if `left` is less, zero if all the - /// bytes match, or positive if `left` is greater. - /// - /// This underlies things like `<[u8]>::cmp`, and will usually lower to `memcmp`. - /// - /// # Safety - /// - /// `left` and `right` must each be [valid] for reads of `bytes` bytes. - /// - /// Note that this applies to the whole range, not just until the first byte - /// that differs. That allows optimizations that can read in large chunks. - /// - /// [valid]: crate::ptr#safety - #[rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none")] - #[rustc_nounwind] - pub fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32; +/// Lexicographically compare `[left, left + bytes)` and `[right, right + bytes)` +/// as unsigned bytes, returning negative if `left` is less, zero if all the +/// bytes match, or positive if `left` is greater. +/// +/// This underlies things like `<[u8]>::cmp`, and will usually lower to `memcmp`. +/// +/// # Safety +/// +/// `left` and `right` must each be [valid] for reads of `bytes` bytes. +/// +/// Note that this applies to the whole range, not just until the first byte +/// that differs. That allows optimizations that can read in large chunks. +/// +/// [valid]: crate::ptr#safety +#[rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn compare_bytes(_left: *const u8, _right: *const u8, _bytes: usize) -> i32 { + unimplemented!() +} - /// See documentation of [`std::hint::black_box`] for details. - /// - /// [`std::hint::black_box`]: crate::hint::black_box - #[rustc_const_unstable(feature = "const_black_box", issue = "none")] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn black_box(dummy: T) -> T; +/// See documentation of [`std::hint::black_box`] for details. +/// +/// [`std::hint::black_box`]: crate::hint::black_box +#[rustc_const_unstable(feature = "const_black_box", issue = "none")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn black_box(_dummy: T) -> T { + unimplemented!() } /// Selects which function to call depending on the context. @@ -3261,18 +3411,13 @@ pub const fn ptr_metadata + ?Sized, M>(_ptr: *cons #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { - extern "rust-intrinsic" { - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0") - )] - #[cfg_attr( - not(bootstrap), - rustc_const_unstable(feature = "core_intrinsics", issue = "none") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + const unsafe fn copy_nonoverlapping(_src: *const T, _dst: *mut T, _count: usize) { + unreachable!() } ub_checks::assert_unsafe_precondition!( @@ -3373,18 +3518,13 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_copy"] pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { - extern "rust-intrinsic" { - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0") - )] - #[cfg_attr( - not(bootstrap), - rustc_const_unstable(feature = "core_intrinsics", issue = "none") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - fn copy(src: *const T, dst: *mut T, count: usize); + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + const unsafe fn copy(_src: *const T, _dst: *mut T, _count: usize) { + unreachable!() } // SAFETY: the safety contract for `copy` must be upheld by the caller. @@ -3462,11 +3602,13 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_write_bytes"] pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { - extern "rust-intrinsic" { - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - fn write_bytes(dst: *mut T, val: u8, count: usize); + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + const unsafe fn write_bytes(_dst: *mut T, _val: u8, _count: usize) { + unreachable!() } // SAFETY: the safety contract for `write_bytes` must be upheld by the caller. From 10723c28964d582814ea8e07dbd8fa7367e0eaee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Nov 2024 22:19:42 +0100 Subject: [PATCH 2/5] remove support for extern-block const intrinsics --- compiler/rustc_attr/src/builtin.rs | 10 +- .../src/const_eval/fn_queries.rs | 12 +-- compiler/rustc_passes/src/stability.rs | 15 --- tests/rustdoc/const-intrinsic.rs | 28 +++--- .../closures/coerce-unsafe-to-closure.stderr | 4 +- .../ui/consts/auxiliary/unstable_intrinsic.rs | 31 ++---- .../consts/const-eval/simd/insert_extract.rs | 20 ++-- tests/ui/consts/const-unstable-intrinsic.rs | 54 +++------- .../ui/consts/const-unstable-intrinsic.stderr | 99 +++++-------------- tests/ui/consts/copy-intrinsic.rs | 20 ++-- tests/ui/consts/copy-intrinsic.stderr | 8 +- tests/ui/intrinsics/reify-intrinsic.stderr | 4 +- tests/ui/repr/16-bit-repr-c-enum.rs | 11 ++- .../missing-const-stability.rs | 6 -- tests/ui/target-feature/feature-hierarchy.rs | 10 +- tests/ui/target-feature/no-llvm-leaks.rs | 10 +- 16 files changed, 118 insertions(+), 224 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 6af75bc94bb63..2753ac529d12d 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -273,8 +273,7 @@ pub fn find_stability( /// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable` /// attributes in `attrs`. Returns `None` if no stability attributes are found. /// -/// `is_const_fn` indicates whether this is a function marked as `const`. It will always -/// be false for intrinsics in an `extern` block! +/// `is_const_fn` indicates whether this is a function marked as `const`. pub fn find_const_stability( sess: &Session, attrs: &[Attribute], @@ -330,7 +329,7 @@ pub fn find_const_stability( } } - // Merge promotable and not_exposed_on_stable into stability info + // Merge promotable and const_stable_indirect into stability info if promotable { match &mut const_stab { Some((stab, _)) => stab.promotable = promotable, @@ -352,10 +351,7 @@ pub fn find_const_stability( }) } } - _ => { - // We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by - // the `default_const_unstable` logic. - } + _ => {} } } // Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 037fdcbcf9b4c..beff0cd99fc47 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -25,15 +25,9 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { hir::Constness::Const } hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness, - hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { - // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other - // foreign items cannot be evaluated at compile-time. - let is_const = if tcx.intrinsic(def_id).is_some() { - tcx.lookup_const_stability(def_id).is_some() - } else { - false - }; - if is_const { hir::Constness::Const } else { hir::Constness::NotConst } + hir::Node::ForeignItem(_) => { + // Foreign items cannot be evaluated at compile-time. + hir::Constness::NotConst } hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness, _ => { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 737e163efcef1..cd47c8ece6015 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -106,7 +106,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { def_id: LocalDefId, item_sp: Span, fn_sig: Option<&'tcx hir::FnSig<'tcx>>, - is_foreign_item: bool, kind: AnnotationKind, inherit_deprecation: InheritDeprecation, inherit_const_stability: InheritConstStability, @@ -175,11 +174,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // implied), check if the function/method is const or the parent impl block is const. if let Some(fn_sig) = fn_sig && !fn_sig.header.is_const() - // We have to exclude foreign items as they might be intrinsics. Sadly we can't check - // their ABI; `fn_sig.abi` is *not* correct for foreign functions. - && !is_foreign_item && const_stab.is_some() - && (!self.in_trait_impl || !self.tcx.is_const_fn(def_id.to_def_id())) { self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span }); } @@ -398,7 +393,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ctor_def_id, i.span, None, - /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -417,7 +411,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { i.owner_id.def_id, i.span, fn_sig, - /* is_foreign_item */ false, kind, InheritDeprecation::Yes, const_stab_inherit, @@ -437,7 +430,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ti.owner_id.def_id, ti.span, fn_sig, - /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -461,7 +453,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ii.owner_id.def_id, ii.span, fn_sig, - /* is_foreign_item */ false, kind, InheritDeprecation::Yes, InheritConstStability::No, @@ -477,7 +468,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { var.def_id, var.span, None, - /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -488,7 +478,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ctor_def_id, var.span, None, - /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -507,7 +496,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { s.def_id, s.span, None, - /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -527,7 +515,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { i.owner_id.def_id, i.span, fn_sig, - /* is_foreign_item */ true, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -550,7 +537,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { p.def_id, p.span, None, - /* is_foreign_item */ false, kind, InheritDeprecation::No, InheritConstStability::No, @@ -712,7 +698,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID), None, - /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, diff --git a/tests/rustdoc/const-intrinsic.rs b/tests/rustdoc/const-intrinsic.rs index 520e253469c63..8444d4a3aa768 100644 --- a/tests/rustdoc/const-intrinsic.rs +++ b/tests/rustdoc/const-intrinsic.rs @@ -1,20 +1,26 @@ -#![feature(intrinsics)] +#![feature(intrinsics, rustc_attrs)] #![feature(staged_api)] #![crate_name = "foo"] #![stable(since="1.0.0", feature="rust1")] -extern "rust-intrinsic" { - //@ has 'foo/fn.transmute.html' - //@ has - '//pre[@class="rust item-decl"]' 'pub const unsafe extern "rust-intrinsic" fn transmute(_: T) -> U' - #[stable(since="1.0.0", feature="rust1")] - #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] - pub fn transmute(_: T) -> U; +//@ has 'foo/fn.transmute.html' +//@ has - '//pre[@class="rust item-decl"]' 'pub const unsafe fn transmute(_: T) -> U' +#[stable(since="1.0.0", feature="rust1")] +#[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn transmute(_: T) -> U { + loop {} +} - //@ has 'foo/fn.unreachable.html' - //@ has - '//pre[@class="rust item-decl"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !' - #[stable(since="1.0.0", feature="rust1")] - pub fn unreachable() -> !; +//@ has 'foo/fn.unreachable.html' +//@ has - '//pre[@class="rust item-decl"]' 'pub unsafe fn unreachable() -> !' +#[stable(since="1.0.0", feature="rust1")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub unsafe fn unreachable() -> ! { + loop {} } extern "C" { diff --git a/tests/ui/closures/coerce-unsafe-to-closure.stderr b/tests/ui/closures/coerce-unsafe-to-closure.stderr index 2538fc0361c37..013b9009da406 100644 --- a/tests/ui/closures/coerce-unsafe-to-closure.stderr +++ b/tests/ui/closures/coerce-unsafe-to-closure.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `FnOnce(&str)` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` +error[E0277]: expected a `FnOnce(&str)` closure, found `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` --> $DIR/coerce-unsafe-to-closure.rs:2:44 | LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute); @@ -6,7 +6,7 @@ LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute); | | | required by a bound introduced by this call | - = help: the trait `FnOnce(&str)` is not implemented for fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` + = help: the trait `FnOnce(&str)` is not implemented for fn item `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `Option::::map` --> $SRC_DIR/core/src/option.rs:LL:COL diff --git a/tests/ui/consts/auxiliary/unstable_intrinsic.rs b/tests/ui/consts/auxiliary/unstable_intrinsic.rs index edef499dbb182..0749e7e6df884 100644 --- a/tests/ui/consts/auxiliary/unstable_intrinsic.rs +++ b/tests/ui/consts/auxiliary/unstable_intrinsic.rs @@ -1,26 +1,11 @@ #![feature(staged_api, rustc_attrs, intrinsics)] #![stable(since="1.0.0", feature = "stable")] -#[stable(since="1.0.0", feature = "stable")] -pub mod old_way { - extern "rust-intrinsic" { - #[unstable(feature = "unstable", issue = "42")] - pub fn size_of_val(x: *const T) -> usize; - - #[unstable(feature = "unstable", issue = "42")] - #[rustc_const_unstable(feature = "unstable", issue = "42")] - pub fn min_align_of_val(x: *const T) -> usize; - } -} - -#[stable(since="1.0.0", feature = "stable")] -pub mod new_way { - #[unstable(feature = "unstable", issue = "42")] - #[rustc_intrinsic] - pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } - - #[unstable(feature = "unstable", issue = "42")] - #[rustc_const_unstable(feature = "unstable", issue = "42")] - #[rustc_intrinsic] - pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } -} +#[unstable(feature = "unstable", issue = "42")] +#[rustc_intrinsic] +pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } + +#[unstable(feature = "unstable", issue = "42")] +#[rustc_const_unstable(feature = "unstable", issue = "42")] +#[rustc_intrinsic] +pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } diff --git a/tests/ui/consts/const-eval/simd/insert_extract.rs b/tests/ui/consts/const-eval/simd/insert_extract.rs index 57d4b4888caa9..e5873ea26e8d8 100644 --- a/tests/ui/consts/const-eval/simd/insert_extract.rs +++ b/tests/ui/consts/const-eval/simd/insert_extract.rs @@ -1,6 +1,6 @@ //@ run-pass #![feature(repr_simd)] -#![feature(intrinsics)] +#![feature(intrinsics, rustc_attrs)] #![feature(staged_api)] #![stable(feature = "foo", since = "1.3.37")] #![allow(non_camel_case_types)] @@ -10,14 +10,18 @@ #[repr(simd)] struct u16x2([u16; 2]); #[repr(simd)] struct f32x4([f32; 4]); -extern "rust-intrinsic" { - #[stable(feature = "foo", since = "1.3.37")] - #[rustc_const_stable(feature = "foo", since = "1.3.37")] - fn simd_insert(x: T, idx: u32, val: U) -> T; +#[stable(feature = "foo", since = "1.3.37")] +#[rustc_const_stable(feature = "foo", since = "1.3.37")] +#[rustc_intrinsic] +const unsafe fn simd_insert(_x: T, _idx: u32, _val: U) -> T { + unimplemented!() +} - #[stable(feature = "foo", since = "1.3.37")] - #[rustc_const_stable(feature = "foo", since = "1.3.37")] - fn simd_extract(x: T, idx: u32) -> U; +#[stable(feature = "foo", since = "1.3.37")] +#[rustc_const_stable(feature = "foo", since = "1.3.37")] +#[rustc_intrinsic] +const unsafe fn simd_extract(_x: T, _idx: u32) -> U { + unimplemented!() } fn main() { diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs index 5d43cdf5da6df..fbe491e067176 100644 --- a/tests/ui/consts/const-unstable-intrinsic.rs +++ b/tests/ui/consts/const-unstable-intrinsic.rs @@ -14,63 +14,39 @@ fn main() { const fn const_main() { let x = 42; unsafe { - unstable_intrinsic::old_way::size_of_val(&x); - //~^ERROR: unstable library feature `unstable` - //~|ERROR: cannot call non-const intrinsic - unstable_intrinsic::old_way::min_align_of_val(&x); - //~^ERROR: unstable library feature `unstable` - //~|ERROR: not yet stable as a const intrinsic - unstable_intrinsic::new_way::size_of_val(&x); + unstable_intrinsic::size_of_val(&x); //~^ERROR: unstable library feature `unstable` //~|ERROR: cannot be (indirectly) exposed to stable - unstable_intrinsic::new_way::min_align_of_val(&x); + unstable_intrinsic::min_align_of_val(&x); //~^ERROR: unstable library feature `unstable` //~|ERROR: not yet stable as a const intrinsic - old_way::size_of_val(&x); - //~^ERROR: cannot call non-const intrinsic - old_way::min_align_of_val(&x); - //~^ERROR: cannot use `#[feature(local)]` - new_way::size_of_val(&x); + size_of_val(&x); //~^ERROR: cannot be (indirectly) exposed to stable - new_way::min_align_of_val(&x); + min_align_of_val(&x); //~^ERROR: cannot use `#[feature(local)]` } } -#[stable(since="1.0.0", feature = "stable")] -pub mod old_way { - extern "rust-intrinsic" { - #[unstable(feature = "local", issue = "42")] - pub fn size_of_val(x: *const T) -> usize; - - #[unstable(feature = "local", issue = "42")] - #[rustc_const_unstable(feature = "local", issue = "42")] - pub fn min_align_of_val(x: *const T) -> usize; - } -} - -#[stable(since="1.0.0", feature = "stable")] -pub mod new_way { - #[unstable(feature = "local", issue = "42")] - #[rustc_intrinsic] - pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } +#[unstable(feature = "local", issue = "42")] +#[rustc_intrinsic] +pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } - #[unstable(feature = "local", issue = "42")] - #[rustc_const_unstable(feature = "local", issue = "42")] - #[rustc_intrinsic] - pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } -} +#[unstable(feature = "local", issue = "42")] +#[rustc_const_unstable(feature = "local", issue = "42")] +#[rustc_intrinsic] +pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[inline] pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { // Const stability attributes are not inherited from parent items. - extern "rust-intrinsic" { - fn copy(src: *const T, dst: *mut T, count: usize); + #[rustc_intrinsic] + const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { + unimplemented!() } unsafe { copy(src, dst, count) } - //~^ ERROR cannot call non-const intrinsic + //~^ ERROR cannot be (indirectly) exposed to stable } diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index c2e38f54dc637..a997379663d6e 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -1,8 +1,8 @@ error[E0658]: use of unstable library feature `unstable` --> $DIR/const-unstable-intrinsic.rs:17:9 | -LL | unstable_intrinsic::old_way::size_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unstable_intrinsic::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #42 for more information = help: add `#![feature(unstable)]` to the crate attributes to enable @@ -11,99 +11,42 @@ LL | unstable_intrinsic::old_way::size_of_val(&x); error[E0658]: use of unstable library feature `unstable` --> $DIR/const-unstable-intrinsic.rs:20:9 | -LL | unstable_intrinsic::old_way::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #42 for more information - = help: add `#![feature(unstable)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature `unstable` - --> $DIR/const-unstable-intrinsic.rs:23:9 - | -LL | unstable_intrinsic::new_way::size_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #42 for more information - = help: add `#![feature(unstable)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature `unstable` - --> $DIR/const-unstable-intrinsic.rs:26:9 - | -LL | unstable_intrinsic::new_way::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unstable_intrinsic::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #42 for more information = help: add `#![feature(unstable)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: cannot call non-const intrinsic `size_of_val` in constant functions +error: intrinsic `unstable_intrinsic::size_of_val` cannot be (indirectly) exposed to stable --> $DIR/const-unstable-intrinsic.rs:17:9 | -LL | unstable_intrinsic::old_way::size_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `min_align_of_val` is not yet stable as a const intrinsic - --> $DIR/const-unstable-intrinsic.rs:20:9 - | -LL | unstable_intrinsic::old_way::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unstable)]` to the crate attributes to enable - -error: intrinsic `unstable_intrinsic::new_way::size_of_val` cannot be (indirectly) exposed to stable - --> $DIR/const-unstable-intrinsic.rs:23:9 - | -LL | unstable_intrinsic::new_way::size_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unstable_intrinsic::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) error: `min_align_of_val` is not yet stable as a const intrinsic - --> $DIR/const-unstable-intrinsic.rs:26:9 + --> $DIR/const-unstable-intrinsic.rs:20:9 | -LL | unstable_intrinsic::new_way::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unstable_intrinsic::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(unstable)]` to the crate attributes to enable -error: cannot call non-const intrinsic `size_of_val` in constant functions - --> $DIR/const-unstable-intrinsic.rs:30:9 - | -LL | old_way::size_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` - --> $DIR/const-unstable-intrinsic.rs:32:9 - | -LL | old_way::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +error: intrinsic `size_of_val` cannot be (indirectly) exposed to stable + --> $DIR/const-unstable-intrinsic.rs:24:9 | -LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_main() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local)] -LL | const fn const_main() { - | - -error: intrinsic `new_way::size_of_val` cannot be (indirectly) exposed to stable - --> $DIR/const-unstable-intrinsic.rs:34:9 - | -LL | new_way::size_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | size_of_val(&x); + | ^^^^^^^^^^^^^^^ | = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` - --> $DIR/const-unstable-intrinsic.rs:36:9 + --> $DIR/const-unstable-intrinsic.rs:26:9 | -LL | new_way::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^ | help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) | @@ -116,12 +59,14 @@ LL + #[rustc_allow_const_fn_unstable(local)] LL | const fn const_main() { | -error: cannot call non-const intrinsic `copy` in constant functions - --> $DIR/const-unstable-intrinsic.rs:74:14 +error: intrinsic `copy::copy` cannot be (indirectly) exposed to stable + --> $DIR/const-unstable-intrinsic.rs:50:14 | LL | unsafe { copy(src, dst, count) } | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) -error: aborting due to 13 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs index 62917c0b98b2c..08fbcc107e7ec 100644 --- a/tests/ui/consts/copy-intrinsic.rs +++ b/tests/ui/consts/copy-intrinsic.rs @@ -1,17 +1,21 @@ #![stable(feature = "dummy", since = "1.0.0")] // ignore-tidy-linelength -#![feature(intrinsics, staged_api)] +#![feature(intrinsics, staged_api, rustc_attrs)] use std::mem; -extern "rust-intrinsic" { - #[stable(feature = "dummy", since = "1.0.0")] - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] - fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); +#[stable(feature = "dummy", since = "1.0.0")] +#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] +#[rustc_intrinsic] +const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { + unimplemented!() +} - #[stable(feature = "dummy", since = "1.0.0")] - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] - fn copy(src: *const T, dst: *mut T, count: usize); +#[stable(feature = "dummy", since = "1.0.0")] +#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] +#[rustc_intrinsic] +const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { + unimplemented!() } const COPY_ZERO: () = unsafe { diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr index 29a88f6270bc6..41af3a2cd2dc2 100644 --- a/tests/ui/consts/copy-intrinsic.stderr +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -1,23 +1,23 @@ error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:30:5 + --> $DIR/copy-intrinsic.rs:34:5 | LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x100[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:39:5 + --> $DIR/copy-intrinsic.rs:43:5 | LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:46:5 + --> $DIR/copy-intrinsic.rs:50:5 | LL | copy(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:52:5 + --> $DIR/copy-intrinsic.rs:56:5 | LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping` diff --git a/tests/ui/intrinsics/reify-intrinsic.stderr b/tests/ui/intrinsics/reify-intrinsic.stderr index 21b7bf4e1cb83..7af17147f28f0 100644 --- a/tests/ui/intrinsics/reify-intrinsic.stderr +++ b/tests/ui/intrinsics/reify-intrinsic.stderr @@ -7,9 +7,9 @@ LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::tr | expected due to this | = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(isize) -> usize` - found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` + found fn item `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` -error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid +error[E0606]: casting `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid --> $DIR/reify-intrinsic.rs:11:13 | LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize; diff --git a/tests/ui/repr/16-bit-repr-c-enum.rs b/tests/ui/repr/16-bit-repr-c-enum.rs index 2509416ad87d4..2b6bbf1265083 100644 --- a/tests/ui/repr/16-bit-repr-c-enum.rs +++ b/tests/ui/repr/16-bit-repr-c-enum.rs @@ -21,11 +21,12 @@ enum Foo { Bar, } -extern "rust-intrinsic" { - #[stable(feature = "intrinsics_for_test", since = "3.3.3")] - #[rustc_const_stable(feature = "intrinsics_for_test", since = "3.3.3")] - #[rustc_safe_intrinsic] - fn size_of() -> usize; +#[stable(feature = "intrinsics_for_test", since = "3.3.3")] +#[rustc_const_stable(feature = "intrinsics_for_test", since = "3.3.3")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +const fn size_of() -> usize { + loop {} } #[lang="sized"] diff --git a/tests/ui/stability-attribute/missing-const-stability.rs b/tests/ui/stability-attribute/missing-const-stability.rs index 6d49996c3b5e9..10c31d7943866 100644 --- a/tests/ui/stability-attribute/missing-const-stability.rs +++ b/tests/ui/stability-attribute/missing-const-stability.rs @@ -36,10 +36,4 @@ impl const Bar for Foo { pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } //~^ ERROR function has missing const stability attribute -extern "rust-intrinsic" { - #[stable(feature = "stable", since = "1.0.0")] - #[rustc_const_stable_indirect] - pub fn min_align_of_val(x: *const T) -> usize; -} - fn main() {} diff --git a/tests/ui/target-feature/feature-hierarchy.rs b/tests/ui/target-feature/feature-hierarchy.rs index 7f14d700ecba6..d62b86693c2ce 100644 --- a/tests/ui/target-feature/feature-hierarchy.rs +++ b/tests/ui/target-feature/feature-hierarchy.rs @@ -18,10 +18,12 @@ trait Sized {} trait Copy {} impl Copy for bool {} -extern "rust-intrinsic" { - #[stable(feature = "test", since = "1.0.0")] - #[rustc_const_stable(feature = "test", since = "1.0.0")] - fn unreachable() -> !; +#[stable(feature = "test", since = "1.0.0")] +#[rustc_const_stable(feature = "test", since = "1.0.0")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +const unsafe fn unreachable() -> ! { + loop {} } #[rustc_builtin_macro] diff --git a/tests/ui/target-feature/no-llvm-leaks.rs b/tests/ui/target-feature/no-llvm-leaks.rs index f0c887bc1e0ff..102686864050a 100644 --- a/tests/ui/target-feature/no-llvm-leaks.rs +++ b/tests/ui/target-feature/no-llvm-leaks.rs @@ -16,10 +16,12 @@ trait Sized {} trait Copy {} impl Copy for bool {} -extern "rust-intrinsic" { - #[stable(feature = "test", since = "1.0.0")] - #[rustc_const_stable(feature = "test", since = "1.0.0")] - fn unreachable() -> !; +#[stable(feature = "test", since = "1.0.0")] +#[rustc_const_stable(feature = "test", since = "1.0.0")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +const unsafe fn unreachable() -> ! { + loop {} } #[rustc_builtin_macro] From 1f0ed2b0f54aff2dbc63ff72261b8acb2c186404 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Nov 2024 22:53:59 +0100 Subject: [PATCH 3/5] add new rustc_const_stable_intrinsic attribute for const-stable intrinsics --- compiler/rustc_const_eval/messages.ftl | 2 +- .../src/check_consts/check.rs | 13 +- .../rustc_const_eval/src/check_consts/ops.rs | 4 +- compiler/rustc_feature/src/builtin_attrs.rs | 4 + compiler/rustc_middle/src/ty/intrinsic.rs | 2 + compiler/rustc_middle/src/ty/util.rs | 2 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics.rs | 114 +++++++++--------- .../ui/consts/const-unstable-intrinsic.stderr | 6 +- 9 files changed, 80 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 2bc5adb2dce60..826e34930eae7 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -399,7 +399,7 @@ const_eval_uninhabited_enum_variant_written = const_eval_unmarked_const_fn_exposed = `{$def_path}` cannot be (indirectly) exposed to stable .help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` const_eval_unmarked_intrinsic_exposed = intrinsic `{$def_path}` cannot be (indirectly) exposed to stable - .help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) + .help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) const_eval_unreachable = entering unreachable code const_eval_unreachable_unwind = diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 8cb7e02036fd8..1c17421e78218 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -736,16 +736,19 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Intrinsics are language primitives, not regular calls, so treat them separately. if let Some(intrinsic) = tcx.intrinsic(callee) { + // We use `intrinsic.const_stable` to determine if this can be safely exposed to + // stable code, rather than `const_stable_indirect`. This is to make + // `#[rustc_const_stable_indirect]` an attribute that is always safe to add. match tcx.lookup_const_stability(callee) { None => { // Non-const intrinsic. self.check_op(ops::IntrinsicNonConst { name: intrinsic.name }); } - Some(ConstStability { feature: None, const_stable_indirect, .. }) => { + Some(ConstStability { feature: None, .. }) => { // Intrinsic does not need a separate feature gate (we rely on the // regular stability checker). However, we have to worry about recursive // const stability. - if !const_stable_indirect && self.enforce_recursive_const_stability() { + if !intrinsic.const_stable && self.enforce_recursive_const_stability() { self.dcx().emit_err(errors::UnmarkedIntrinsicExposed { span: self.span, def_path: self.tcx.def_path_str(callee), @@ -755,17 +758,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Some(ConstStability { feature: Some(feature), level: StabilityLevel::Unstable { .. }, - const_stable_indirect, .. }) => { self.check_op(ops::IntrinsicUnstable { name: intrinsic.name, feature, - const_stable_indirect, + const_stable: intrinsic.const_stable, }); } Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { - // All good. + // All good. But ensure this is indeed a const-stable intrinsic. + assert!(intrinsic.const_stable); } } // This completes the checks for intrinsics. diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index d264cab1511b9..2931159842f95 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -354,14 +354,14 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst { pub(crate) struct IntrinsicUnstable { pub name: Symbol, pub feature: Symbol, - pub const_stable_indirect: bool, + pub const_stable: bool, } impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable { fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { Status::Unstable { gate: self.feature, - safe_to_expose_on_stable: self.const_stable_indirect, + safe_to_expose_on_stable: self.const_stable, // We do *not* want to suggest to mark the intrinsic as `const_stable_indirect`, // that's not a trivial change! is_function_call: false, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 0069b07ad6259..cc0bdec701929 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -837,6 +837,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_const_stable_indirect, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL, ), + rustc_attr!( + rustc_const_stable_intrinsic, Normal, + template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL, + ), gated!( rustc_allow_const_fn_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No, diff --git a/compiler/rustc_middle/src/ty/intrinsic.rs b/compiler/rustc_middle/src/ty/intrinsic.rs index ed0fb37d3b897..6a3ddacb424e8 100644 --- a/compiler/rustc_middle/src/ty/intrinsic.rs +++ b/compiler/rustc_middle/src/ty/intrinsic.rs @@ -9,6 +9,8 @@ pub struct IntrinsicDef { pub name: Symbol, /// Whether the intrinsic has no meaningful body and all backends need to shim all calls to it. pub must_be_overridden: bool, + /// Whether the intrinsic can be invoked from stable const fn + pub const_stable: bool, } impl TyCtxt<'_> { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 83276808a28e6..b5811824683a8 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1789,6 +1789,8 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option to -//! and add a -//! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration. +//! In order to make an intrinsic usable at compile-time, it needs to be declared in the "new" +//! style, i.e. as a `#[rustc_intrinsic]` function, not inside an `extern` block. Then copy the +//! implementation from to +//! +//! and make the intrinsic declaration a `const fn`. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, -//! `#[rustc_const_stable_indirect]` needs to be added to the intrinsic (`#[rustc_const_unstable]` -//! can be removed then). Such a change should not be done without T-lang consultation, because it -//! may bake a feature into the language that cannot be replicated in user code without compiler -//! support. +//! `#[rustc_const_stable_intrinsic]` needs to be added to the intrinsic. Such a change requires +//! T-lang approval, because it may bake a feature into the language that cannot be replicated in +//! user code without compiler support. //! //! # Volatiles //! @@ -955,7 +955,7 @@ extern "rust-intrinsic" { bootstrap, rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0") )] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -974,7 +974,7 @@ pub const unsafe fn unreachable() -> ! { /// /// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assume", since = "1.77.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] @@ -1000,7 +1000,7 @@ pub const unsafe fn assume(b: bool) { bootstrap, rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") )] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_nounwind] @@ -1024,7 +1024,7 @@ pub const fn likely(b: bool) -> bool { bootstrap, rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") )] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_nounwind] @@ -1059,7 +1059,7 @@ pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { /// /// This intrinsic does not have a stable counterpart. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1072,7 +1072,7 @@ pub const fn assert_inhabited() { /// /// This intrinsic does not have a stable counterpart. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1084,7 +1084,7 @@ pub const fn assert_zero_valid() { /// /// This intrinsic does not have a stable counterpart. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1101,7 +1101,7 @@ pub const fn assert_mem_uninitialized_valid() { /// /// Consider using [`core::panic::Location::caller`] instead. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1119,7 +1119,7 @@ pub const fn caller_location() -> &'static crate::panic::Location<'static> { /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1433,7 +1433,7 @@ pub const unsafe fn transmute(_src: Src) -> Dst { /// This is not expected to ever be exposed directly to users, rather it /// may eventually be exposed through some more-constrained API. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1455,7 +1455,7 @@ pub const unsafe fn transmute_unchecked(_src: Src) -> Dst { /// /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1481,7 +1481,7 @@ pub const fn needs_drop() -> bool { /// The stabilized version of this intrinsic is [`pointer::offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1504,7 +1504,7 @@ pub const unsafe fn offset(_dst: Ptr, _offset: Delta) -> Ptr { /// The stabilized version of this intrinsic is [`pointer::wrapping_offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2194,7 +2194,7 @@ extern "rust-intrinsic" { /// primitives via the `count_ones` method. For example, /// [`u32::count_ones`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2239,7 +2239,7 @@ pub const fn ctpop(_x: T) -> u32 { /// assert_eq!(num_leading, 16); /// ``` #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2265,7 +2265,7 @@ pub const fn ctlz(_x: T) -> u32 { /// assert_eq!(num_leading, 3); /// ``` #[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2310,7 +2310,7 @@ pub const unsafe fn ctlz_nonzero(_x: T) -> u32 { /// assert_eq!(num_trailing, 16); /// ``` #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2336,7 +2336,7 @@ pub const fn cttz(_x: T) -> u32 { /// assert_eq!(num_trailing, 3); /// ``` #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2355,7 +2355,7 @@ pub const unsafe fn cttz_nonzero(_x: T) -> u32 { /// primitives via the `swap_bytes` method. For example, /// [`u32::swap_bytes`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2374,7 +2374,7 @@ pub const fn bswap(_x: T) -> T { /// primitives via the `reverse_bits` method. For example, /// [`u32::reverse_bits`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2407,7 +2407,7 @@ pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Orderi /// primitives via the `overflowing_add` method. For example, /// [`u32::overflowing_add`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2426,7 +2426,7 @@ pub const fn add_with_overflow(_x: T, _y: T) -> (T, bool) { /// primitives via the `overflowing_sub` method. For example, /// [`u32::overflowing_sub`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2445,7 +2445,7 @@ pub const fn sub_with_overflow(_x: T, _y: T) -> (T, bool) { /// primitives via the `overflowing_mul` method. For example, /// [`u32::overflowing_mul`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2472,7 +2472,7 @@ pub const unsafe fn exact_div(_x: T, _y: T) -> T { /// primitives via the `checked_div` method. For example, /// [`u32::checked_div`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2486,7 +2486,7 @@ pub const unsafe fn unchecked_div(_x: T, _y: T) -> T { /// primitives via the `checked_rem` method. For example, /// [`u32::checked_rem`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2501,7 +2501,7 @@ pub const unsafe fn unchecked_rem(_x: T, _y: T) -> T { /// primitives via the `checked_shl` method. For example, /// [`u32::checked_shl`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2515,7 +2515,7 @@ pub const unsafe fn unchecked_shl(_x: T, _y: U) -> T { /// primitives via the `checked_shr` method. For example, /// [`u32::checked_shr`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2529,7 +2529,7 @@ pub const unsafe fn unchecked_shr(_x: T, _y: U) -> T { /// The stable counterpart of this intrinsic is `unchecked_add` on the various /// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2543,7 +2543,7 @@ pub const unsafe fn unchecked_add(_x: T, _y: T) -> T { /// The stable counterpart of this intrinsic is `unchecked_sub` on the various /// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2557,7 +2557,7 @@ pub const unsafe fn unchecked_sub(_x: T, _y: T) -> T { /// The stable counterpart of this intrinsic is `unchecked_mul` on the various /// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2576,7 +2576,7 @@ pub const unsafe fn unchecked_mul(_x: T, _y: T) -> T { /// primitives via the `rotate_left` method. For example, /// [`u32::rotate_left`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2595,7 +2595,7 @@ pub const fn rotate_left(_x: T, _shift: u32) -> T { /// primitives via the `rotate_right` method. For example, /// [`u32::rotate_right`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2614,7 +2614,7 @@ pub const fn rotate_right(_x: T, _shift: u32) -> T { /// primitives via the `wrapping_add` method. For example, /// [`u32::wrapping_add`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2632,7 +2632,7 @@ pub const fn wrapping_add(_a: T, _b: T) -> T { /// primitives via the `wrapping_sub` method. For example, /// [`u32::wrapping_sub`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2650,7 +2650,7 @@ pub const fn wrapping_sub(_a: T, _b: T) -> T { /// primitives via the `wrapping_mul` method. For example, /// [`u32::wrapping_mul`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2669,7 +2669,7 @@ pub const fn wrapping_mul(_a: T, _b: T) -> T { /// primitives via the `saturating_add` method. For example, /// [`u32::saturating_add`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2687,7 +2687,7 @@ pub const fn saturating_add(_a: T, _b: T) -> T { /// primitives via the `saturating_sub` method. For example, /// [`u32::saturating_sub`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2702,7 +2702,7 @@ pub const fn saturating_sub(_a: T, _b: T) -> T { /// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it /// trivially obeys runtime-MIR rules about derefs in operands. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2717,7 +2717,7 @@ pub const unsafe fn read_via_copy(_ptr: *const T) -> T { /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so /// that it trivially obeys runtime-MIR rules about derefs in operands. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2735,7 +2735,7 @@ pub const unsafe fn write_via_move(_ptr: *mut T, _value: T) { /// /// The stabilized version of this intrinsic is [`core::mem::discriminant`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2775,7 +2775,7 @@ extern "rust-intrinsic" { /// See documentation of `<*const T>::offset_from` for details. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3058,7 +3058,7 @@ pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { /// user has UB checks disabled, the checks will still get optimized out. This intrinsic is /// primarily used by [`ub_checks::assert_unsafe_precondition`]. #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // just for UB checks +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] // just for UB checks #[unstable(feature = "core_intrinsics", issue = "none")] #[inline(always)] #[rustc_intrinsic] @@ -3144,7 +3144,7 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_size_of", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn size_of() -> usize { @@ -3162,7 +3162,7 @@ pub const fn size_of() -> usize { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_min_align_of", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn min_align_of() -> usize { @@ -3276,7 +3276,7 @@ pub const fn type_id() -> u128 { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn aggregate_raw_ptr, D, M>(_data: D, _meta: M) -> P { @@ -3305,7 +3305,7 @@ impl AggregateRawPtr<*mut T> for *mut P { bootstrap, cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")) )] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn ptr_metadata + ?Sized, M>(_ptr: *const P) -> M { @@ -3412,7 +3412,7 @@ pub const fn ptr_metadata + ?Sized, M>(_ptr: *cons #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3519,7 +3519,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us #[rustc_diagnostic_item = "ptr_copy"] pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3603,7 +3603,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { #[rustc_diagnostic_item = "ptr_write_bytes"] pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index a997379663d6e..2cf76732cf2cc 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -24,7 +24,7 @@ error: intrinsic `unstable_intrinsic::size_of_val` cannot be (indirectly) expose LL | unstable_intrinsic::size_of_val(&x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) error: `min_align_of_val` is not yet stable as a const intrinsic --> $DIR/const-unstable-intrinsic.rs:20:9 @@ -40,7 +40,7 @@ error: intrinsic `size_of_val` cannot be (indirectly) exposed to stable LL | size_of_val(&x); | ^^^^^^^^^^^^^^^ | - = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` --> $DIR/const-unstable-intrinsic.rs:26:9 @@ -65,7 +65,7 @@ error: intrinsic `copy::copy` cannot be (indirectly) exposed to stable LL | unsafe { copy(src, dst, count) } | ^^^^^^^^^^^^^^^^^^^^^ | - = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) error: aborting due to 7 previous errors From 5069434c816aa13ffd2807cf95133ade5a9306df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Nov 2024 08:25:30 +0100 Subject: [PATCH 4/5] most const intrinsics don't need an explicit rustc_const_unstable any more --- library/core/src/intrinsics.rs | 74 +++++++++---------- library/core/src/lib.rs | 2 +- library/core/tests/lib.rs | 2 +- tests/ui/consts/const-compare-bytes-ub.rs | 1 - tests/ui/consts/const-compare-bytes-ub.stderr | 16 ++-- tests/ui/consts/const-compare-bytes.rs | 1 - .../intrinsics/intrinsic-raw_eq-const-bad.rs | 1 - .../intrinsic-raw_eq-const-bad.stderr | 6 +- tests/ui/intrinsics/intrinsic-raw_eq-const.rs | 1 - 9 files changed, 46 insertions(+), 58 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 4458a822d733e..c0d4a1eb34dcb 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2389,7 +2389,7 @@ pub const fn bitreverse(_x: T) -> T { /// large and difficult to optimize. /// /// The stabilized version of this intrinsic is [`Ord::cmp`]. -#[rustc_const_unstable(feature = "const_three_way_compare", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_three_way_compare", issue = "none"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Ordering { @@ -2457,7 +2457,7 @@ pub const fn mul_with_overflow(_x: T, _y: T) -> (T, bool) { /// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` /// /// This intrinsic does not have a stable counterpart. -#[rustc_const_unstable(feature = "const_exact_div", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_exact_div", issue = "none"))] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2784,7 +2784,7 @@ pub const unsafe fn ptr_offset_from(_ptr: *const T, _base: *const T) -> isize } /// See documentation of `<*const T>::sub_ptr` for details. -#[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892"))] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2796,8 +2796,7 @@ pub const unsafe fn ptr_offset_from_unsigned(_ptr: *const T, _base: *const T) /// Returns `2` if the result is unknown. /// Returns `1` if the pointers are guaranteed equal /// Returns `0` if the pointers are guaranteed inequal -#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] -#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020"))] #[rustc_intrinsic] #[rustc_nounwind] #[rustc_do_not_const_check] @@ -2830,7 +2829,7 @@ pub const fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8 { /// /// (The implementation is allowed to branch on the results of comparisons, /// which is UB if any of their inputs are `undef`.) -#[rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none"))] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2852,7 +2851,10 @@ pub const unsafe fn raw_eq(_a: &T, _b: &T) -> bool { /// that differs. That allows optimizations that can read in large chunks. /// /// [valid]: crate::ptr#safety -#[rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none")] +#[cfg_attr( + bootstrap, + rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none") +)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2863,7 +2865,7 @@ pub const unsafe fn compare_bytes(_left: *const u8, _right: *const u8, _bytes: u /// See documentation of [`std::hint::black_box`] for details. /// /// [`std::hint::black_box`]: crate::hint::black_box -#[rustc_const_unstable(feature = "const_black_box", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_black_box", issue = "none"))] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3036,7 +3038,7 @@ pub const fn is_val_statically_known(_arg: T) -> bool { #[rustc_nounwind] #[inline] #[rustc_intrinsic] -// This has fallback `const fn` MIR, so shouldn't need stability, see #122652 +// Const-unstable because `swap_nonoverlapping` is const-unstable. #[rustc_const_unstable(feature = "const_typed_swap", issue = "none")] pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { // SAFETY: The caller provided single non-overlapping items behind @@ -3059,7 +3061,6 @@ pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { /// primarily used by [`ub_checks::assert_unsafe_precondition`]. #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] // just for UB checks -#[unstable(feature = "core_intrinsics", issue = "none")] #[inline(always)] #[rustc_intrinsic] pub const fn ub_checks() -> bool { @@ -3075,7 +3076,6 @@ pub const fn ub_checks() -> bool { /// - At compile time, a compile error occurs if this constraint is violated. /// - At runtime, it is not checked. #[rustc_const_unstable(feature = "const_heap", issue = "79597")] -#[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_nounwind] #[rustc_intrinsic] #[miri::intrinsic_fallback_is_spec] @@ -3175,7 +3175,7 @@ pub const fn min_align_of() -> usize { /// It's "tracking issue" is [#91971](https://github.com/rust-lang/rust/issues/91971). #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_pref_align_of", issue = "91971")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_pref_align_of", issue = "91971"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn pref_align_of() -> usize { @@ -3193,7 +3193,7 @@ pub const unsafe fn pref_align_of() -> usize { /// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "variant_count", issue = "73662")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "variant_count", issue = "73662"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn variant_count() -> usize { @@ -3209,7 +3209,7 @@ pub const fn variant_count() -> usize { /// See [`crate::mem::size_of_val_raw`] for safety conditions. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_size_of_val", issue = "46571"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn size_of_val(_ptr: *const T) -> usize { @@ -3225,7 +3225,7 @@ pub const unsafe fn size_of_val(_ptr: *const T) -> usize { /// See [`crate::mem::align_of_val_raw`] for safety conditions. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_align_of_val", issue = "46571"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn min_align_of_val(_ptr: *const T) -> usize { @@ -3242,7 +3242,7 @@ pub const unsafe fn min_align_of_val(_ptr: *const T) -> usize { /// The stabilized version of this intrinsic is [`core::any::type_name`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_type_name", issue = "63084")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_type_name", issue = "63084"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn type_name() -> &'static str { @@ -3261,7 +3261,7 @@ pub const fn type_name() -> &'static str { /// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_type_id", issue = "77125")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_type_id", issue = "77125"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn type_id() -> u128 { @@ -3636,8 +3636,7 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { /// The stabilized version of this intrinsic is /// [`f16::min`] #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn minnumf16(_x: f16, _y: f16) -> f16 { @@ -3654,7 +3653,7 @@ pub const fn minnumf16(_x: f16, _y: f16) -> f16 { /// The stabilized version of this intrinsic is /// [`f32::min`] #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn minnumf32(_x: f32, _y: f32) -> f32 { @@ -3671,7 +3670,7 @@ pub const fn minnumf32(_x: f32, _y: f32) -> f32 { /// The stabilized version of this intrinsic is /// [`f64::min`] #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn minnumf64(_x: f64, _y: f64) -> f64 { @@ -3688,8 +3687,7 @@ pub const fn minnumf64(_x: f64, _y: f64) -> f64 { /// The stabilized version of this intrinsic is /// [`f128::min`] #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn minnumf128(_x: f128, _y: f128) -> f128 { @@ -3706,8 +3704,7 @@ pub const fn minnumf128(_x: f128, _y: f128) -> f128 { /// The stabilized version of this intrinsic is /// [`f16::max`] #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn maxnumf16(_x: f16, _y: f16) -> f16 { @@ -3724,7 +3721,7 @@ pub const fn maxnumf16(_x: f16, _y: f16) -> f16 { /// The stabilized version of this intrinsic is /// [`f32::max`] #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn maxnumf32(_x: f32, _y: f32) -> f32 { @@ -3741,7 +3738,7 @@ pub const fn maxnumf32(_x: f32, _y: f32) -> f32 { /// The stabilized version of this intrinsic is /// [`f64::max`] #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn maxnumf64(_x: f64, _y: f64) -> f64 { @@ -3758,8 +3755,7 @@ pub const fn maxnumf64(_x: f64, _y: f64) -> f64 { /// The stabilized version of this intrinsic is /// [`f128::max`] #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn maxnumf128(_x: f128, _y: f128) -> f128 { @@ -3771,8 +3767,7 @@ pub const fn maxnumf128(_x: f128, _y: f128) -> f128 { /// The stabilized version of this intrinsic is /// [`f16::abs`](../../std/primitive.f16.html#method.abs) #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn fabsf16(_x: f16) -> f16 { @@ -3784,7 +3779,7 @@ pub const unsafe fn fabsf16(_x: f16) -> f16 { /// The stabilized version of this intrinsic is /// [`f32::abs`](../../std/primitive.f32.html#method.abs) #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn fabsf32(_x: f32) -> f32 { @@ -3796,7 +3791,7 @@ pub const unsafe fn fabsf32(_x: f32) -> f32 { /// The stabilized version of this intrinsic is /// [`f64::abs`](../../std/primitive.f64.html#method.abs) #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn fabsf64(_x: f64) -> f64 { @@ -3808,8 +3803,7 @@ pub const unsafe fn fabsf64(_x: f64) -> f64 { /// The stabilized version of this intrinsic is /// [`f128::abs`](../../std/primitive.f128.html#method.abs) #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn fabsf128(_x: f128) -> f128 { @@ -3821,8 +3815,7 @@ pub const unsafe fn fabsf128(_x: f128) -> f128 { /// The stabilized version of this intrinsic is /// [`f16::copysign`](../../std/primitive.f16.html#method.copysign) #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 { @@ -3834,7 +3827,7 @@ pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 { /// The stabilized version of this intrinsic is /// [`f32::copysign`](../../std/primitive.f32.html#method.copysign) #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 { @@ -3845,7 +3838,7 @@ pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 { /// The stabilized version of this intrinsic is /// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 { @@ -3857,8 +3850,7 @@ pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 { /// The stabilized version of this intrinsic is /// [`f128::copysign`](../../std/primitive.f128.html#method.copysign) #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128 { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 12f6997dbeae7..444f733adff00 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -107,6 +107,7 @@ // // Library features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(const_exact_div))] #![cfg_attr(bootstrap, feature(const_fmt_arguments_new))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] @@ -116,7 +117,6 @@ #![feature(const_black_box)] #![feature(const_char_encode_utf16)] #![feature(const_eval_select)] -#![feature(const_exact_div)] #![feature(const_float_methods)] #![feature(const_heap)] #![feature(const_nonnull_new)] diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 0c5bf58564781..b9706ea2a9e35 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(const_three_way_compare))] #![cfg_attr(bootstrap, feature(strict_provenance))] #![cfg_attr(not(bootstrap), feature(strict_provenance_lints))] #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] @@ -22,7 +23,6 @@ #![feature(const_nonnull_new)] #![feature(const_option_ext)] #![feature(const_pin_2)] -#![feature(const_three_way_compare)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] diff --git a/tests/ui/consts/const-compare-bytes-ub.rs b/tests/ui/consts/const-compare-bytes-ub.rs index 903ba15e62291..9dafae1efd1a6 100644 --- a/tests/ui/consts/const-compare-bytes-ub.rs +++ b/tests/ui/consts/const-compare-bytes-ub.rs @@ -1,7 +1,6 @@ //@ check-fail #![feature(core_intrinsics)] -#![feature(const_intrinsic_compare_bytes)] use std::intrinsics::compare_bytes; use std::mem::MaybeUninit; diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr index 7f83dee640969..9ef5c8ad43a1c 100644 --- a/tests/ui/consts/const-compare-bytes-ub.stderr +++ b/tests/ui/consts/const-compare-bytes-ub.stderr @@ -1,47 +1,47 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:10:9 + --> $DIR/const-compare-bytes-ub.rs:9:9 | LL | compare_bytes(0 as *const u8, 2 as *const u8, 1) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got a null pointer error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:14:9 + --> $DIR/const-compare-bytes-ub.rs:13:9 | LL | compare_bytes(1 as *const u8, 0 as *const u8, 1) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:18:9 + --> $DIR/const-compare-bytes-ub.rs:17:9 | LL | compare_bytes(1 as *const u8, 2 as *const u8, 1) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:22:9 + --> $DIR/const-compare-bytes-ub.rs:21:9 | LL | compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0 which is only 3 bytes from the end of the allocation error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:26:9 + --> $DIR/const-compare-bytes-ub.rs:25:9 | LL | compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC1 which is only 3 bytes from the end of the allocation error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:30:9 + --> $DIR/const-compare-bytes-ub.rs:29:9 | LL | compare_bytes(MaybeUninit::uninit().as_ptr(), [1].as_ptr(), 1) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:34:9 + --> $DIR/const-compare-bytes-ub.rs:33:9 | LL | compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC3[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:38:9 + --> $DIR/const-compare-bytes-ub.rs:37:9 | LL | compare_bytes([&1].as_ptr().cast(), [&2].as_ptr().cast(), std::mem::size_of::()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer diff --git a/tests/ui/consts/const-compare-bytes.rs b/tests/ui/consts/const-compare-bytes.rs index 8596a2d9df910..cd5cdfd0400ec 100644 --- a/tests/ui/consts/const-compare-bytes.rs +++ b/tests/ui/consts/const-compare-bytes.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] -#![feature(const_intrinsic_compare_bytes)] use std::intrinsics::compare_bytes; fn main() { diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs index 99f98c3f27ada..76b6a8c8395cc 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs @@ -1,5 +1,4 @@ #![feature(core_intrinsics)] -#![feature(const_intrinsic_raw_eq)] const RAW_EQ_PADDING: bool = unsafe { std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr index bedfc8283ea45..b8fdfe7bef35a 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr @@ -1,11 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/intrinsic-raw_eq-const-bad.rs:5:5 + --> $DIR/intrinsic-raw_eq-const-bad.rs:4:5 | LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory error[E0080]: evaluation of constant value failed - --> $DIR/intrinsic-raw_eq-const-bad.rs:11:5 + --> $DIR/intrinsic-raw_eq-const-bad.rs:10:5 | LL | std::intrinsics::raw_eq(&(&0), &(&1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer @@ -14,7 +14,7 @@ LL | std::intrinsics::raw_eq(&(&0), &(&1)) = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: evaluation of constant value failed - --> $DIR/intrinsic-raw_eq-const-bad.rs:19:5 + --> $DIR/intrinsic-raw_eq-const-bad.rs:18:5 | LL | std::intrinsics::raw_eq(aref, aref) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment 1, but alignment 4 is required diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const.rs b/tests/ui/intrinsics/intrinsic-raw_eq-const.rs index 47b4e20dfbb7e..b37def85bb7c2 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const.rs +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] -#![feature(const_intrinsic_raw_eq)] pub fn main() { use std::intrinsics::raw_eq; From a741b33c145a5f1fa3e7f42a4488750ce8719d4f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Nov 2024 08:49:49 +0100 Subject: [PATCH 5/5] when an intrinsic has a const-stable fallback body, we can easily expose it on stable --- .../rustc_const_eval/src/check_consts/check.rs | 16 ++++++++++++---- compiler/rustc_middle/src/ty/util.rs | 3 +-- tests/ui/consts/auxiliary/unstable_intrinsic.rs | 2 ++ tests/ui/consts/const-unstable-intrinsic.rs | 12 ++++++++++++ tests/ui/consts/const-unstable-intrinsic.stderr | 12 ++++++++++-- 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 1c17421e78218..aea3d5bd3e70f 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -739,6 +739,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // We use `intrinsic.const_stable` to determine if this can be safely exposed to // stable code, rather than `const_stable_indirect`. This is to make // `#[rustc_const_stable_indirect]` an attribute that is always safe to add. + // We also ask is_safe_to_expose_on_stable_const_fn; this determines whether the intrinsic + // fallback body is safe to expose on stable. + let is_const_stable = intrinsic.const_stable + || (!intrinsic.must_be_overridden + && tcx.is_const_fn(callee) + && is_safe_to_expose_on_stable_const_fn(tcx, callee)); match tcx.lookup_const_stability(callee) { None => { // Non-const intrinsic. @@ -748,7 +754,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Intrinsic does not need a separate feature gate (we rely on the // regular stability checker). However, we have to worry about recursive // const stability. - if !intrinsic.const_stable && self.enforce_recursive_const_stability() { + if !is_const_stable && self.enforce_recursive_const_stability() { self.dcx().emit_err(errors::UnmarkedIntrinsicExposed { span: self.span, def_path: self.tcx.def_path_str(callee), @@ -763,12 +769,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { self.check_op(ops::IntrinsicUnstable { name: intrinsic.name, feature, - const_stable: intrinsic.const_stable, + const_stable: is_const_stable, }); } Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { - // All good. But ensure this is indeed a const-stable intrinsic. - assert!(intrinsic.const_stable); + // All good. Note that a `#[rustc_const_stable]` intrinsic (meaning it + // can be *directly* invoked from stable const code) does not always + // have the `#[rustc_const_stable_intrinsic]` attribute (which controls + // exposing an intrinsic indirectly); we accept this call anyway. } } // This completes the checks for intrinsics. diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index b5811824683a8..6ffd149ef1475 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1789,8 +1789,7 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option(x: *const T) -> usize { 42 } #[unstable(feature = "unstable", issue = "42")] #[rustc_const_unstable(feature = "unstable", issue = "42")] #[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs index fbe491e067176..56b552b6a3f35 100644 --- a/tests/ui/consts/const-unstable-intrinsic.rs +++ b/tests/ui/consts/const-unstable-intrinsic.rs @@ -30,11 +30,13 @@ const fn const_main() { #[unstable(feature = "local", issue = "42")] #[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } #[unstable(feature = "local", issue = "42")] #[rustc_const_unstable(feature = "local", issue = "42")] #[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } #[stable(feature = "rust1", since = "1.0.0")] @@ -43,6 +45,7 @@ pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { // Const stability attributes are not inherited from parent items. #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { unimplemented!() } @@ -50,3 +53,12 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { unsafe { copy(src, dst, count) } //~^ ERROR cannot be (indirectly) exposed to stable } + +// Ensure that a fallback body is recursively-const-checked. +mod fallback { + #[rustc_intrinsic] + const unsafe fn copy(src: *const T, _dst: *mut T, _count: usize) { + super::size_of_val(src); + //~^ ERROR cannot be (indirectly) exposed to stable + } +} diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index 2cf76732cf2cc..3e605f3d0037e 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -60,13 +60,21 @@ LL | const fn const_main() { | error: intrinsic `copy::copy` cannot be (indirectly) exposed to stable - --> $DIR/const-unstable-intrinsic.rs:50:14 + --> $DIR/const-unstable-intrinsic.rs:53:14 | LL | unsafe { copy(src, dst, count) } | ^^^^^^^^^^^^^^^^^^^^^ | = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) -error: aborting due to 7 previous errors +error: intrinsic `size_of_val` cannot be (indirectly) exposed to stable + --> $DIR/const-unstable-intrinsic.rs:61:9 + | +LL | super::size_of_val(src); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0658`.