Rollup merge of #67466 - oli-obk:const_intrinsic, r=Centril
Require const stability attributes on intrinsics to be able to use them in constant contexts r? @Centril finally fixes #61495 cc @RalfJung
This commit is contained in:
commit
1de2705c79
|
@ -1,6 +1,22 @@
|
|||
//! Compiler intrinsics.
|
||||
//!
|
||||
//! The corresponding definitions are in `librustc_codegen_llvm/intrinsic.rs`.
|
||||
//! The corresponding const implementations are in `librustc_mir/interpret/intrinsics.rs`
|
||||
//!
|
||||
//! # Const intrinsics
|
||||
//!
|
||||
//! Note: any changes to the constness of intrinsics should be discussed with the language team.
|
||||
//! This includes changes in the stability of the constness.
|
||||
//!
|
||||
//! In order to make an intrinsic usable at compile-time, one needs to copy the implementation
|
||||
//! from https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs to
|
||||
//! `librustc_mir/interpret/intrinsics.rs` and add a
|
||||
//! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic.
|
||||
//!
|
||||
//! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
|
||||
//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
|
||||
//! without T-lang consulation, because it bakes a feature into the language that cannot be
|
||||
//! replicated in user code without compiler support.
|
||||
//!
|
||||
//! # Volatiles
|
||||
//!
|
||||
|
@ -671,6 +687,7 @@ extern "rust-intrinsic" {
|
|||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`std::mem::size_of`](../../std/mem/fn.size_of.html).
|
||||
#[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
|
||||
pub fn size_of<T>() -> usize;
|
||||
|
||||
/// Moves a value to an uninitialized memory location.
|
||||
|
@ -678,7 +695,9 @@ extern "rust-intrinsic" {
|
|||
/// Drop glue is not run on the destination.
|
||||
pub fn move_val_init<T>(dst: *mut T, src: T);
|
||||
|
||||
#[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
|
||||
pub fn min_align_of<T>() -> usize;
|
||||
#[rustc_const_unstable(feature = "const_pref_align_of", issue = "0")]
|
||||
pub fn pref_align_of<T>() -> usize;
|
||||
|
||||
/// The size of the referenced value in bytes.
|
||||
|
@ -689,11 +708,13 @@ extern "rust-intrinsic" {
|
|||
pub fn min_align_of_val<T: ?Sized>(_: &T) -> usize;
|
||||
|
||||
/// Gets a static string slice containing the name of a type.
|
||||
#[rustc_const_unstable(feature = "const_type_name", issue = "0")]
|
||||
pub fn type_name<T: ?Sized>() -> &'static str;
|
||||
|
||||
/// Gets an identifier which is globally unique to the specified type. This
|
||||
/// function will return the same value for a type regardless of whichever
|
||||
/// crate it is invoked in.
|
||||
#[rustc_const_unstable(feature = "const_type_id", issue = "0")]
|
||||
pub fn type_id<T: ?Sized + 'static>() -> u64;
|
||||
|
||||
/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
|
||||
|
@ -701,6 +722,7 @@ extern "rust-intrinsic" {
|
|||
pub fn panic_if_uninhabited<T>();
|
||||
|
||||
/// Gets a reference to a static `Location` indicating where it was called.
|
||||
#[rustc_const_unstable(feature = "const_caller_location", issue = "47809")]
|
||||
pub fn caller_location() -> &'static crate::panic::Location<'static>;
|
||||
|
||||
/// Creates a value initialized to zero.
|
||||
|
@ -957,6 +979,7 @@ extern "rust-intrinsic" {
|
|||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`std::mem::needs_drop`](../../std/mem/fn.needs_drop.html).
|
||||
#[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")]
|
||||
pub fn needs_drop<T>() -> bool;
|
||||
|
||||
/// Calculates the offset from a pointer.
|
||||
|
@ -1154,6 +1177,7 @@ extern "rust-intrinsic" {
|
|||
pub fn float_to_int_approx_unchecked<Float, Int>(value: Float) -> Int;
|
||||
|
||||
/// Returns the number of bits set in an integer type `T`
|
||||
#[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")]
|
||||
pub fn ctpop<T>(x: T) -> T;
|
||||
|
||||
/// Returns the number of leading unset bits (zeroes) in an integer type `T`.
|
||||
|
@ -1181,6 +1205,7 @@ extern "rust-intrinsic" {
|
|||
/// let num_leading = ctlz(x);
|
||||
/// assert_eq!(num_leading, 16);
|
||||
/// ```
|
||||
#[rustc_const_stable(feature = "const_ctlz", since = "1.40.0")]
|
||||
pub fn ctlz<T>(x: T) -> T;
|
||||
|
||||
/// Like `ctlz`, but extra-unsafe as it returns `undef` when
|
||||
|
@ -1197,6 +1222,7 @@ extern "rust-intrinsic" {
|
|||
/// let num_leading = unsafe { ctlz_nonzero(x) };
|
||||
/// assert_eq!(num_leading, 3);
|
||||
/// ```
|
||||
#[rustc_const_unstable(feature = "constctlz", issue = "0")]
|
||||
pub fn ctlz_nonzero<T>(x: T) -> T;
|
||||
|
||||
/// Returns the number of trailing unset bits (zeroes) in an integer type `T`.
|
||||
|
@ -1224,6 +1250,7 @@ extern "rust-intrinsic" {
|
|||
/// let num_trailing = cttz(x);
|
||||
/// assert_eq!(num_trailing, 16);
|
||||
/// ```
|
||||
#[rustc_const_stable(feature = "const_cttz", since = "1.40.0")]
|
||||
pub fn cttz<T>(x: T) -> T;
|
||||
|
||||
/// Like `cttz`, but extra-unsafe as it returns `undef` when
|
||||
|
@ -1240,30 +1267,36 @@ extern "rust-intrinsic" {
|
|||
/// let num_trailing = unsafe { cttz_nonzero(x) };
|
||||
/// assert_eq!(num_trailing, 3);
|
||||
/// ```
|
||||
#[rustc_const_unstable(feature = "const_cttz", issue = "0")]
|
||||
pub fn cttz_nonzero<T>(x: T) -> T;
|
||||
|
||||
/// Reverses the bytes in an integer type `T`.
|
||||
#[rustc_const_stable(feature = "const_bswap", since = "1.40.0")]
|
||||
pub fn bswap<T>(x: T) -> T;
|
||||
|
||||
/// Reverses the bits in an integer type `T`.
|
||||
#[rustc_const_stable(feature = "const_bitreverse", since = "1.40.0")]
|
||||
pub fn bitreverse<T>(x: T) -> T;
|
||||
|
||||
/// Performs checked integer addition.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `overflowing_add` method. For example,
|
||||
/// [`std::u32::overflowing_add`](../../std/primitive.u32.html#method.overflowing_add)
|
||||
#[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
|
||||
pub fn add_with_overflow<T>(x: T, y: T) -> (T, bool);
|
||||
|
||||
/// Performs checked integer subtraction
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `overflowing_sub` method. For example,
|
||||
/// [`std::u32::overflowing_sub`](../../std/primitive.u32.html#method.overflowing_sub)
|
||||
#[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
|
||||
pub fn sub_with_overflow<T>(x: T, y: T) -> (T, bool);
|
||||
|
||||
/// Performs checked integer multiplication
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `overflowing_mul` method. For example,
|
||||
/// [`std::u32::overflowing_mul`](../../std/primitive.u32.html#method.overflowing_mul)
|
||||
#[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
|
||||
pub fn mul_with_overflow<T>(x: T, y: T) -> (T, bool);
|
||||
|
||||
/// Performs an exact division, resulting in undefined behavior where
|
||||
|
@ -1279,9 +1312,11 @@ extern "rust-intrinsic" {
|
|||
|
||||
/// Performs an unchecked left shift, resulting in undefined behavior when
|
||||
/// y < 0 or y >= N, where N is the width of T in bits.
|
||||
#[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
|
||||
pub fn unchecked_shl<T>(x: T, y: T) -> 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.
|
||||
#[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
|
||||
pub fn unchecked_shr<T>(x: T, y: T) -> T;
|
||||
|
||||
/// Returns the result of an unchecked addition, resulting in
|
||||
|
@ -1300,39 +1335,46 @@ extern "rust-intrinsic" {
|
|||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `rotate_left` method. For example,
|
||||
/// [`std::u32::rotate_left`](../../std/primitive.u32.html#method.rotate_left)
|
||||
#[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
|
||||
pub fn rotate_left<T>(x: T, y: T) -> T;
|
||||
|
||||
/// Performs rotate right.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `rotate_right` method. For example,
|
||||
/// [`std::u32::rotate_right`](../../std/primitive.u32.html#method.rotate_right)
|
||||
#[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
|
||||
pub fn rotate_right<T>(x: T, y: T) -> T;
|
||||
|
||||
/// Returns (a + b) mod 2<sup>N</sup>, where N is the width of T in bits.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_add` method. For example,
|
||||
/// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add)
|
||||
#[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
|
||||
pub fn wrapping_add<T>(a: T, b: T) -> T;
|
||||
/// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_sub` method. For example,
|
||||
/// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub)
|
||||
#[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
|
||||
pub fn wrapping_sub<T>(a: T, b: T) -> T;
|
||||
/// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_mul` method. For example,
|
||||
/// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul)
|
||||
#[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
|
||||
pub fn wrapping_mul<T>(a: T, b: T) -> T;
|
||||
|
||||
/// Computes `a + b`, while saturating at numeric bounds.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `saturating_add` method. For example,
|
||||
/// [`std::u32::saturating_add`](../../std/primitive.u32.html#method.saturating_add)
|
||||
#[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
|
||||
pub fn saturating_add<T>(a: T, b: T) -> T;
|
||||
/// Computes `a - b`, while saturating at numeric bounds.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `saturating_sub` method. For example,
|
||||
/// [`std::u32::saturating_sub`](../../std/primitive.u32.html#method.saturating_sub)
|
||||
#[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
|
||||
pub fn saturating_sub<T>(a: T, b: T) -> T;
|
||||
|
||||
/// Returns the value of the discriminant for the variant in 'v',
|
||||
|
@ -1354,6 +1396,7 @@ extern "rust-intrinsic" {
|
|||
pub fn nontemporal_store<T>(ptr: *mut T, val: T);
|
||||
|
||||
/// See documentation of `<*const T>::offset_from` for details.
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "0")]
|
||||
pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
|
||||
|
||||
/// Internal hook used by Miri to implement unwinding.
|
||||
|
|
|
@ -127,6 +127,8 @@
|
|||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(external_doc)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(const_type_id)]
|
||||
#![feature(const_caller_location)]
|
||||
|
||||
#[prelude_import]
|
||||
#[allow(unused)]
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// the `caller_location` intrinsic, but once `#[track_caller]` is implemented,
|
||||
// `panicking::{panic, panic_fmt}` can use that instead of a `Location` argument.
|
||||
core_intrinsics,
|
||||
const_caller_location,
|
||||
)]
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
macro_rules! panic {
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::ty::query::Providers;
|
|||
use crate::hir::def_id::DefId;
|
||||
use crate::hir;
|
||||
use crate::ty::TyCtxt;
|
||||
use syntax_pos::symbol::{sym, Symbol};
|
||||
use syntax_pos::symbol::Symbol;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use crate::hir::map::blocks::FnLikeNode;
|
||||
use syntax::attr;
|
||||
|
@ -41,51 +41,12 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted
|
||||
/// for being called from stable `const fn`s (`min_const_fn`).
|
||||
///
|
||||
/// Adding more intrinsics requires sign-off from @rust-lang/lang.
|
||||
///
|
||||
/// This list differs from the list in `is_const_intrinsic` in the sense that any item on this
|
||||
/// list must be on the `is_const_intrinsic` list, too, because if an intrinsic is callable from
|
||||
/// stable, it must be callable at all.
|
||||
fn is_intrinsic_min_const_fn(self, def_id: DefId) -> bool {
|
||||
match self.item_name(def_id) {
|
||||
| sym::size_of
|
||||
| sym::min_align_of
|
||||
| sym::needs_drop
|
||||
// Arithmetic:
|
||||
| sym::add_with_overflow // ~> .overflowing_add
|
||||
| sym::sub_with_overflow // ~> .overflowing_sub
|
||||
| sym::mul_with_overflow // ~> .overflowing_mul
|
||||
| sym::wrapping_add // ~> .wrapping_add
|
||||
| sym::wrapping_sub // ~> .wrapping_sub
|
||||
| sym::wrapping_mul // ~> .wrapping_mul
|
||||
| sym::saturating_add // ~> .saturating_add
|
||||
| sym::saturating_sub // ~> .saturating_sub
|
||||
| sym::unchecked_shl // ~> .wrapping_shl
|
||||
| sym::unchecked_shr // ~> .wrapping_shr
|
||||
| sym::rotate_left // ~> .rotate_left
|
||||
| sym::rotate_right // ~> .rotate_right
|
||||
| sym::ctpop // ~> .count_ones
|
||||
| sym::ctlz // ~> .leading_zeros
|
||||
| sym::cttz // ~> .trailing_zeros
|
||||
| sym::bswap // ~> .swap_bytes
|
||||
| sym::bitreverse // ~> .reverse_bits
|
||||
=> true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this function must conform to `min_const_fn`
|
||||
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
|
||||
// Bail out if the signature doesn't contain `const`
|
||||
if !self.is_const_fn_raw(def_id) {
|
||||
return false;
|
||||
}
|
||||
if let Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
|
||||
return self.is_intrinsic_min_const_fn(def_id);
|
||||
}
|
||||
|
||||
if self.features().staged_api {
|
||||
// In order for a libstd function to be considered min_const_fn
|
||||
|
@ -134,62 +95,7 @@ pub fn provide(providers: &mut Providers<'_>) {
|
|||
fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
|
||||
match tcx.fn_sig(def_id).abi() {
|
||||
Abi::RustIntrinsic |
|
||||
Abi::PlatformIntrinsic => {
|
||||
// FIXME: deduplicate these two lists as much as possible
|
||||
match tcx.item_name(def_id) {
|
||||
// Keep this list in the same order as the match patterns in
|
||||
// `librustc_mir/interpret/intrinsics.rs`
|
||||
|
||||
// This whitelist is a list of intrinsics that have a miri-engine implementation
|
||||
// and can thus be called when enabling enough feature gates. The similar
|
||||
// whitelist in `is_intrinsic_min_const_fn` (in this file), exists for allowing
|
||||
// the intrinsics to be called by stable const fns.
|
||||
| sym::caller_location
|
||||
|
||||
| sym::min_align_of
|
||||
| sym::pref_align_of
|
||||
| sym::needs_drop
|
||||
| sym::size_of
|
||||
| sym::type_id
|
||||
| sym::type_name
|
||||
|
||||
| sym::ctpop
|
||||
| sym::cttz
|
||||
| sym::cttz_nonzero
|
||||
| sym::ctlz
|
||||
| sym::ctlz_nonzero
|
||||
| sym::bswap
|
||||
| sym::bitreverse
|
||||
|
||||
| sym::wrapping_add
|
||||
| sym::wrapping_sub
|
||||
| sym::wrapping_mul
|
||||
| sym::add_with_overflow
|
||||
| sym::sub_with_overflow
|
||||
| sym::mul_with_overflow
|
||||
|
||||
| sym::saturating_add
|
||||
| sym::saturating_sub
|
||||
|
||||
| sym::unchecked_shl
|
||||
| sym::unchecked_shr
|
||||
|
||||
| sym::rotate_left
|
||||
| sym::rotate_right
|
||||
|
||||
| sym::ptr_offset_from
|
||||
|
||||
| sym::transmute
|
||||
|
||||
| sym::simd_insert
|
||||
|
||||
| sym::simd_extract
|
||||
|
||||
=> Some(true),
|
||||
|
||||
_ => Some(false)
|
||||
}
|
||||
}
|
||||
Abi::PlatformIntrinsic => Some(tcx.lookup_const_stability(def_id).is_some()),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#![feature(const_fn)]
|
||||
#![feature(repr_simd)]
|
||||
#![feature(platform_intrinsics)]
|
||||
#![feature(staged_api)]
|
||||
#![stable(feature = "foo", since = "1.33.7")]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
#[repr(simd)] struct i8x1(i8);
|
||||
|
@ -9,7 +11,9 @@
|
|||
#[repr(simd)] struct f32x3(f32, f32, f32);
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
#[rustc_const_stable(feature = "foo", since = "1.3.37")]
|
||||
fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
|
||||
#[rustc_const_stable(feature = "foo", since = "1.3.37")]
|
||||
fn simd_extract<T, U>(x: T, idx: u32) -> U;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(const_type_name)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
const fn type_name_wrapper<T>(_: &T) -> &'static str {
|
||||
|
|
Loading…
Reference in New Issue