Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Stabilize transmute in constants and statics but not const fn #72920

Merged
merged 1 commit into from
Jul 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -409,6 +410,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(),
));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you only check for this in qualify_min_const_fn, transmute calls will be allowed in const fn if #![feature(const_fn)] is enabled regardless of whether the feature gate added in this PR is enabled. Is this intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that, but I don't know what our const_fn feature gate story is anymore. iirc it's "the const_fn feature will go away when we merge min_const_fn into the regular const checks"?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so. I believe it's only blocked on me finding the willpower to update several hundred //~ ERROR annotations in the min_const_fn suite. Centril had some objections IIRC, but I don't think they were substantive.

In the meantime, we should check this in check_consts/validation.rs as well. Adding a structured error type for transmute and checking for it where we handle TerminatorKind::Call should be enough.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also we should have good test coverage for this one to ensure we don't accidentally stabilize transmute in const fn under strange circumstances...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the meantime, we should check this in check_consts/validation.rs as well. Adding a structured error type for transmute and checking for it where we handle TerminatorKind::Call should be enough.

@ecstatic-morse so are you saying that should happen in this PR, or should be done some time after landing this PR but before removing min_const_fn?


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