Skip to content

Commit

Permalink
Rollup merge of #72920 - oli-obk:const_transmute, r=RalfJung
Browse files Browse the repository at this point in the history
Stabilize `transmute` in constants and statics but not const fn

cc #53605 (leaving issue open so we can add `transmute` to `const fn` later)

Previous attempt: #64011

r? @RalfJung

cc @rust-lang/wg-const-eval
  • Loading branch information
Manishearth committed Jul 11, 2020
2 parents 346aec9 + dd872be commit 90f1d72
Show file tree
Hide file tree
Showing 39 changed files with 238 additions and 106 deletions.
4 changes: 3 additions & 1 deletion src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1285,7 +1285,9 @@ extern "rust-intrinsic" {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_transmute", issue = "53605")]
// 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")]
pub fn transmute<T, U>(e: T) -> U;

/// Returns `true` if the actual type given as `T` requires drop
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
#![feature(rtm_target_feature)]
#![feature(f16c_target_feature)]
#![feature(hexagon_target_feature)]
#![feature(const_transmute)]
#![cfg_attr(not(bootstrap), feature(const_fn_transmute))]
#![feature(abi_unadjusted)]
#![feature(adx_target_feature)]
#![feature(maybe_uninit_slice)]
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_ast/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_fn)] // For the `transmute` in `P::new`
#![feature(const_panic)]
#![feature(const_transmute)]
#![cfg_attr(not(bootstrap), feature(const_fn_transmute))]
#![feature(crate_visibility_modifier)]
#![feature(label_break_value)]
#![feature(nll)]
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_feature/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,9 @@ declare_features! (
/// Lazily evaluate constants. This allows constants to depend on type parameters.
(active, lazy_normalization_consts, "1.46.0", Some(72219), None),

/// Alloc calling `transmute` in const fn
(active, const_fn_transmute, "1.46.0", Some(53605), None),

// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_middle/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(const_transmute)]
#![cfg_attr(not(bootstrap), feature(const_fn_transmute))]
#![feature(core_intrinsics)]
#![feature(discriminant_kind)]
#![feature(drain_filter)]
Expand Down
15 changes: 15 additions & 0 deletions src/librustc_mir/transform/qualify_min_const_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use rustc_target::spec::abi::Abi::RustIntrinsic;
use std::borrow::Cow;

type McfResult = Result<(), (Span, Cow<'static, str>)>;
Expand Down Expand Up @@ -418,6 +419,20 @@ fn check_terminator(
));
}

// 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 tcx.fn_sig(fn_def_id).abi() == RustIntrinsic
&& tcx.item_name(fn_def_id) == sym::transmute
&& !feature_allowed(tcx, def_id, sym::const_fn_transmute)
{
return Err((
span,
"can only call `transmute` from const items, not `const fn`".into(),
));
}

check_operand(tcx, func, span, fn_def_id, body)?;

for arg in args {
Expand Down
1 change: 1 addition & 0 deletions src/librustc_span/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,7 @@ symbols! {
track_caller,
trait_alias,
transmute,
const_fn_transmute,
transparent,
transparent_enums,
transparent_unions,
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-eval/dangling.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(const_transmute, const_raw_ptr_deref)]
#![feature(const_raw_ptr_deref)]

use std::{mem, usize};

Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/consts/const-eval/double_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ static FOO: (&Foo, &Bar) = unsafe {(
Union { u8: &BAR }.bar,
)};

static FOO2: (&Foo, &Bar) = unsafe {(std::mem::transmute(&BAR), std::mem::transmute(&BAR))};

fn main() {}
2 changes: 2 additions & 0 deletions src/test/ui/consts/const-eval/double_check2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ static FOO: (&Foo, &Bar) = unsafe {( //~ undefined behavior
Union { u8: &BAR }.foo,
Union { u8: &BAR }.bar,
)};
static FOO2: (&Foo, &Bar) = unsafe {(std::mem::transmute(&BAR), std::mem::transmute(&BAR))};
//~^ undefined behavior

fn main() {}
10 changes: 9 additions & 1 deletion src/test/ui/consts/const-eval/double_check2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ LL | | )};
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error: aborting due to previous error
error[E0080]: it is undefined behavior to use this value
--> $DIR/double_check2.rs:20:1
|
LL | static FOO2: (&Foo, &Bar) = unsafe {(std::mem::transmute(&BAR), std::mem::transmute(&BAR))};
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x05 at .1.<deref>.<enum-tag>, but expected a valid enum tag
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0080`.
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-eval/issue-55541.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

// Test that we can handle newtypes wrapping extern types

#![feature(extern_types, const_transmute)]
#![feature(extern_types)]

use std::marker::PhantomData;

Expand Down
2 changes: 0 additions & 2 deletions src/test/ui/consts/const-eval/transmute-const.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![feature(const_transmute)]

use std::mem;

static FOO: bool = unsafe { mem::transmute(3u8) };
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-eval/transmute-const.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0080]: it is undefined behavior to use this value
--> $DIR/transmute-const.rs:5:1
--> $DIR/transmute-const.rs:3:1
|
LL | static FOO: bool = unsafe { mem::transmute(3u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03, but expected a boolean
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-eval/ub-enum.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// normalize-stderr-64bit "0x0000000000" -> "0x00"
#![feature(const_transmute, never_type)]
#![feature(never_type)]
#![allow(const_err)] // make sure we cannot allow away the errors tested here

use std::mem;
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/consts/const-eval/ub-int-array.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#![feature(const_transmute)]
#![allow(const_err)] // make sure we cannot allow away the errors tested here

//! Test the "array of int" fast path in validity checking, and in particular whether it
Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/consts/const-eval/ub-int-array.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-int-array.rs:15:1
--> $DIR/ub-int-array.rs:14:1
|
LL | / const UNINIT_INT_0: [u32; 3] = unsafe {
LL | |
Expand All @@ -13,7 +13,7 @@ LL | | };
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-int-array.rs:24:1
--> $DIR/ub-int-array.rs:23:1
|
LL | / const UNINIT_INT_1: [u32; 3] = unsafe {
LL | |
Expand All @@ -27,7 +27,7 @@ LL | | };
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-int-array.rs:44:1
--> $DIR/ub-int-array.rs:43:1
|
LL | / const UNINIT_INT_2: [u32; 3] = unsafe {
LL | |
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-eval/ub-nonnull.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(rustc_attrs, const_transmute)]
#![feature(rustc_attrs)]
#![allow(const_err, invalid_value)] // make sure we cannot allow away the errors tested here

use std::mem;
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/consts/const-eval/ub-ref.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// ignore-tidy-linelength
#![feature(const_transmute)]
#![allow(const_err, invalid_value)] // make sure we cannot allow away the errors tested here

use std::mem;
Expand Down
18 changes: 9 additions & 9 deletions src/test/ui/consts/const-eval/ub-ref.stderr
Original file line number Diff line number Diff line change
@@ -1,69 +1,69 @@
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref.rs:7:1
--> $DIR/ub-ref.rs:6:1
|
LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref.rs:11:1
--> $DIR/ub-ref.rs:10:1
|
LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered an unaligned box (required 2 byte alignment but found 1)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref.rs:15:1
--> $DIR/ub-ref.rs:14:1
|
LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL reference
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref.rs:18:1
--> $DIR/ub-ref.rs:17:1
|
LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL box
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref.rs:24:1
--> $DIR/ub-ref.rs:23:1
|
LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc16, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref.rs:27:1
--> $DIR/ub-ref.rs:26:1
|
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref.rs:30:1
--> $DIR/ub-ref.rs:29:1
|
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref.rs:33:1
--> $DIR/ub-ref.rs:32:1
|
LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (created from integer)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref.rs:36:1
--> $DIR/ub-ref.rs:35:1
|
LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (created from integer)
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/consts/const-eval/ub-uninhabit.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#![feature(const_transmute)]
#![allow(const_err)] // make sure we cannot allow away the errors tested here

use std::mem;
Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/consts/const-eval/ub-uninhabit.stderr
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-uninhabit.rs:15:1
--> $DIR/ub-uninhabit.rs:14:1
|
LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-uninhabit.rs:18:1
--> $DIR/ub-uninhabit.rs:17:1
|
LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at .<deref>
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-uninhabit.rs:21:1
--> $DIR/ub-uninhabit.rs:20:1
|
LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at [0]
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/consts/const-eval/ub-upvars.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#![feature(const_transmute)]
#![allow(const_err, invalid_value)] // make sure we cannot allow away the errors tested here

use std::mem;
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-eval/ub-upvars.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-upvars.rs:6:1
--> $DIR/ub-upvars.rs:5:1
|
LL | / const BAD_UPVAR: &dyn FnOnce() = &{
LL | | let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) };
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/consts/const-eval/ub-wide-ptr.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// ignore-tidy-linelength
#![feature(const_transmute)]
#![allow(unused)]
#![allow(const_err)] // make sure we cannot allow away the errors tested here

Expand Down
Loading

0 comments on commit 90f1d72

Please sign in to comment.