Stabilize const_fn_transmute

This commit is contained in:
Jacob Pratt 2021-06-03 02:11:14 -04:00
parent fd853c00e2
commit 36f02f3523
No known key found for this signature in database
GPG Key ID: B80E19E4662B5AA4
12 changed files with 15 additions and 47 deletions

View File

@ -10,7 +10,7 @@
)]
#![feature(box_syntax)]
#![feature(box_patterns)]
#![feature(const_fn_transmute)]
#![cfg_attr(bootstrap, feature(const_fn_transmute))]
#![feature(crate_visibility_modifier)]
#![feature(iter_zip)]
#![feature(label_break_value)]

View File

@ -290,6 +290,8 @@ macro_rules! declare_features {
/// Allows bindings in the subpattern of a binding pattern.
/// For example, you can write `x @ Some(y)`.
(accepted, bindings_after_at, "1.54.0", Some(65490), None),
/// Allows calling `transmute` in const fn
(accepted, const_fn_transmute, "1.56.0", Some(53605), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features

View File

@ -565,9 +565,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
/// Lazily evaluate constants. This allows constants to depend on type parameters.
(incomplete, lazy_normalization_consts, "1.46.0", Some(72219), None),
/// Allows calling `transmute` in const fn
(active, const_fn_transmute, "1.46.0", Some(53605), None),
/// Allows `if let` guard in match arms.
(incomplete, if_let_guard, "1.47.0", Some(51114), None),

View File

@ -876,15 +876,6 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
// HACK: This is to "unstabilize" the `transmute` intrinsic
// within const fns. `transmute` is allowed in all other const contexts.
// This won't really scale to more intrinsics or functions. Let's allow const
// transmutes in const fn before we add more hacks to this.
if is_intrinsic && tcx.item_name(callee) == sym::transmute {
self.check_op(ops::Transmute);
return;
}
if !tcx.is_const_fn_raw(callee) {
let mut permitted = false;

View File

@ -501,29 +501,6 @@ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<
}
}
#[derive(Debug)]
pub struct Transmute;
impl NonConstOp for Transmute {
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
if ccx.const_kind() != hir::ConstContext::ConstFn {
Status::Allowed
} else {
Status::Unstable(sym::const_fn_transmute)
}
}
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_transmute,
span,
&format!("`transmute` is not allowed in {}s", ccx.const_kind()),
);
err.note("`transmute` is only allowed in constants and statics for now");
err
}
}
#[derive(Debug)]
pub struct UnionAccess;
impl NonConstOp for UnionAccess {

View File

@ -911,6 +911,9 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
/// cause [undefined behavior][ub] with this function. `transmute` should be
/// the absolute last resort.
///
/// Transmuting pointers to integers in a `const` context is [undefined behavior][ub].
/// Any attempt to use the resulting value for integer operations will abort const-evaluation.
///
/// The [nomicon](../../nomicon/transmutes.html) has additional
/// documentation.
///
@ -1128,8 +1131,6 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
// NOTE: While this makes the intrinsic const stable, we have some custom code in const fn
// checks that prevent its use within `const fn`.
#[rustc_const_stable(feature = "const_transmute", since = "1.46.0")]
#[rustc_diagnostic_item = "transmute"]
pub fn transmute<T, U>(e: T) -> U;

View File

@ -159,7 +159,7 @@
#![feature(rtm_target_feature)]
#![feature(f16c_target_feature)]
#![feature(hexagon_target_feature)]
#![feature(const_fn_transmute)]
#![cfg_attr(bootstrap, feature(const_fn_transmute))]
#![feature(abi_unadjusted)]
#![feature(adx_target_feature)]
#![feature(associated_type_bounds)]

View File

@ -2096,7 +2096,7 @@ pub const fn is_negative(self) -> bool { self < 0 }
#[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
// SAFETY: const sound because integers are plain old datatypes so we can always
// transmute them to arrays of bytes
#[rustc_allow_const_fn_unstable(const_fn_transmute)]
#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))]
#[inline]
pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
// SAFETY: integers are plain old datatypes so we can always transmute them to
@ -2202,7 +2202,7 @@ pub const fn is_negative(self) -> bool { self < 0 }
#[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
// SAFETY: const sound because integers are plain old datatypes so we can always
// transmute to them
#[rustc_allow_const_fn_unstable(const_fn_transmute)]
#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))]
#[inline]
pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
// SAFETY: integers are plain old datatypes so we can always transmute to them

View File

@ -1926,7 +1926,7 @@ pub const fn wrapping_next_power_of_two(self) -> Self {
#[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
// SAFETY: const sound because integers are plain old datatypes so we can always
// transmute them to arrays of bytes
#[rustc_allow_const_fn_unstable(const_fn_transmute)]
#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))]
#[inline]
pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
// SAFETY: integers are plain old datatypes so we can always transmute them to
@ -2032,7 +2032,7 @@ pub const fn wrapping_next_power_of_two(self) -> Self {
#[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
// SAFETY: const sound because integers are plain old datatypes so we can always
// transmute to them
#[rustc_allow_const_fn_unstable(const_fn_transmute)]
#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))]
#[inline]
pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
// SAFETY: integers are plain old datatypes so we can always transmute to them

View File

@ -157,7 +157,7 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")]
#[rustc_allow_const_fn_unstable(const_fn_transmute)]
#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))]
pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
// SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8.
// Also relies on `&str` and `&[u8]` having the same layout.

View File

@ -231,7 +231,7 @@ pub fn is_char_boundary(&self, index: usize) -> bool {
#[rustc_const_stable(feature = "str_as_bytes", since = "1.39.0")]
#[inline(always)]
#[allow(unused_attributes)]
#[rustc_allow_const_fn_unstable(const_fn_transmute)]
#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))]
pub const fn as_bytes(&self) -> &[u8] {
// SAFETY: const sound because we transmute two types with the same layout
unsafe { mem::transmute(self) }

View File

@ -1087,7 +1087,7 @@ impl Ipv6Addr {
///
/// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
/// ```
#[rustc_allow_const_fn_unstable(const_fn_transmute)]
#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))]
#[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@ -1149,7 +1149,7 @@ pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16)
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(),
/// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]);
/// ```
#[rustc_allow_const_fn_unstable(const_fn_transmute)]
#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))]
#[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]