From 8cddb6ce4f0d03999261789f63ab074ebfed1063 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 30 Aug 2019 02:01:04 +0200 Subject: [PATCH] Stabilize `transmute` in constants and statics but not const fn --- src/librustc_mir/transform/qualify_consts.rs | 7 +- src/test/ui/consts/const-eval/double_check.rs | 2 + .../ui/consts/const-eval/double_check2.rs | 2 + .../ui/consts/const-eval/double_check2.stderr | 10 ++- src/test/ui/consts/const-eval/ub-enum.rs | 21 +++++ src/test/ui/consts/const-eval/ub-enum.stderr | 85 ++++++++++++++++--- .../feature-gate-const_transmute.rs | 6 +- .../feature-gate-const_transmute.stderr | 8 +- 8 files changed, 122 insertions(+), 19 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index a77421ce15008..4db2a02650051 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1321,14 +1321,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // special intrinsic that can be called diretly without an intrinsic // feature gate needs a language feature gate "transmute" => { - if self.mode.requires_const_checking() { - // const eval transmute calls only with the feature gate + if let Mode::ConstFn = self.mode { + // permit transmute calls in const fns only with the feature + // gate. Anywhere else they are fine if !self.tcx.features().const_transmute { emit_feature_err( &self.tcx.sess.parse_sess, sym::const_transmute, self.span, GateIssue::Language, &format!("The use of std::mem::transmute() \ - is gated in {}s", self.mode)); + is gated in const fns")); } } } diff --git a/src/test/ui/consts/const-eval/double_check.rs b/src/test/ui/consts/const-eval/double_check.rs index 2cf6a5494dd8d..b031529f3872c 100644 --- a/src/test/ui/consts/const-eval/double_check.rs +++ b/src/test/ui/consts/const-eval/double_check.rs @@ -19,4 +19,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() {} diff --git a/src/test/ui/consts/const-eval/double_check2.rs b/src/test/ui/consts/const-eval/double_check2.rs index dc2b58faf9215..635d20214591f 100644 --- a/src/test/ui/consts/const-eval/double_check2.rs +++ b/src/test/ui/consts/const-eval/double_check2.rs @@ -16,5 +16,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() {} diff --git a/src/test/ui/consts/const-eval/double_check2.stderr b/src/test/ui/consts/const-eval/double_check2.stderr index 2b61d33852c98..782a66c052fab 100644 --- a/src/test/ui/consts/const-eval/double_check2.stderr +++ b/src/test/ui/consts/const-eval/double_check2.stderr @@ -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 rust compiler 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:19:1 + | +LL | static FOO2: (&Foo, &Bar) = unsafe {(std::mem::transmute(&BAR), std::mem::transmute(&BAR))}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 5 at .1., but expected a valid enum discriminant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler 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`. diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index d4b2220695102..1a6163a7bc4c4 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -18,16 +18,26 @@ union TransmuteEnum { } const GOOD_ENUM: Enum = unsafe { TransmuteEnum { in2: 0 }.out1 }; +const GOOD_ENUM_TRANSMUTE: Enum = unsafe { std::mem::transmute(0usize) }; const BAD_ENUM: Enum = unsafe { TransmuteEnum { in2: 1 }.out1 }; //~^ ERROR is undefined behavior +const BAD_ENUM_TRANSMUTE: Enum = unsafe { std::mem::transmute(1usize) }; +//~^ ERROR is undefined behavior + const BAD_ENUM_PTR: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 }; //~^ ERROR is undefined behavior +const BAD_ENUM_PTR_TRANSMUTE: Enum = unsafe { std::mem::transmute(&1) }; +//~^ ERROR is undefined behavior + const BAD_ENUM_WRAPPED: Wrap = unsafe { TransmuteEnum { in1: &1 }.out2 }; //~^ ERROR is undefined behavior +const BAD_ENUM_WRAPPED_TRANSMUTE: Wrap = unsafe { std::mem::transmute(&1) }; +//~^ ERROR is undefined behavior + // (Potentially) invalid enum discriminant #[repr(usize)] #[derive(Copy, Clone)] @@ -45,10 +55,16 @@ union TransmuteEnum2 { } const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; //~^ ERROR is undefined behavior +const BAD_ENUM2_TRANSMUTE: Enum2 = unsafe { std::mem::transmute(0usize) }; +//~^ ERROR is undefined behavior const BAD_ENUM2_PTR: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; //~^ ERROR is undefined behavior +const BAD_ENUM2_PTR_TRANSMUTE: Enum2 = unsafe { std::mem::transmute(&0) }; +//~^ ERROR is undefined behavior const BAD_ENUM2_WRAPPED: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; //~^ ERROR is undefined behavior +const BAD_ENUM2_WRAPPED_TRANSMUTE: Wrap = unsafe { std::mem::transmute(&0) }; +//~^ ERROR is undefined behavior // Undef enum discriminant. const BAD_ENUM2_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 }; @@ -57,6 +73,8 @@ const BAD_ENUM2_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 }; // Pointer value in an enum with a niche that is not just 0. const BAD_ENUM2_OPTION_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; //~^ ERROR is undefined behavior +const BAD_ENUM2_OPTION_PTR_TRANSMUTE: Option = unsafe { std::mem::transmute(&0) }; +//~^ ERROR is undefined behavior // Invalid enum field content (mostly to test printing of paths for enum tuple // variants and tuples). @@ -67,6 +85,9 @@ union TransmuteChar { // Need to create something which does not clash with enum layout optimizations. const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); //~^ ERROR is undefined behavior +const BAD_OPTION_CHAR_TRANSMUTE: Option<(char, char)> = + Some(('x', unsafe { std::mem::transmute(!0) })); +//~^^ ERROR is undefined behavior fn main() { } diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index 8ecb1aabdd0f7..f387003ad92f2 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:22:1 + --> $DIR/ub-enum.rs:23:1 | LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { in2: 1 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 1, but expected a valid enum discriminant @@ -7,7 +7,15 @@ LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { in2: 1 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:25:1 + --> $DIR/ub-enum.rs:26:1 + | +LL | const BAD_ENUM_TRANSMUTE: Enum = unsafe { std::mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 1, but expected a valid enum discriminant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:29:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant @@ -15,7 +23,15 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:28:1 + --> $DIR/ub-enum.rs:32:1 + | +LL | const BAD_ENUM_PTR_TRANSMUTE: Enum = unsafe { std::mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:35:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { TransmuteEnum { in1: &1 }.out2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be equal to 0 @@ -23,7 +39,15 @@ LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { TransmuteEnum { in1: &1 }.out = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:46:1 + --> $DIR/ub-enum.rs:38:1 + | +LL | const BAD_ENUM_WRAPPED_TRANSMUTE: Wrap = unsafe { std::mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be equal to 0 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:56:1 | LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant @@ -31,7 +55,15 @@ LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:48:1 + --> $DIR/ub-enum.rs:58:1 + | +LL | const BAD_ENUM2_TRANSMUTE: Enum2 = unsafe { std::mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:60:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant @@ -39,7 +71,15 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:50:1 + --> $DIR/ub-enum.rs:62:1 + | +LL | const BAD_ENUM2_PTR_TRANSMUTE: Enum2 = unsafe { std::mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:64:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be equal to 2 @@ -47,7 +87,15 @@ LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { TransmuteEnum2 { in2: &0 }. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:54:1 + --> $DIR/ub-enum.rs:66:1 + | +LL | const BAD_ENUM2_WRAPPED_TRANSMUTE: Wrap = unsafe { std::mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be equal to 2 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:70:1 | LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid enum discriminant @@ -55,7 +103,7 @@ LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:58:1 + --> $DIR/ub-enum.rs:74:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant @@ -63,13 +111,30 @@ LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { TransmuteEnum2 { in2: = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:68:1 + --> $DIR/ub-enum.rs:76:1 + | +LL | const BAD_ENUM2_OPTION_PTR_TRANSMUTE: Option = unsafe { std::mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:86:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at ..0.1, but expected something less or equal to 1114111 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior -error: aborting due to 9 previous errors +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:88:1 + | +LL | / const BAD_OPTION_CHAR_TRANSMUTE: Option<(char, char)> = +LL | | Some(('x', unsafe { std::mem::transmute(!0) })); + | |____________________________________________________^ type validation failed: encountered 4294967295 at ..0.1, but expected something less or equal to 1114111 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error: aborting due to 17 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/feature-gates/feature-gate-const_transmute.rs b/src/test/ui/feature-gates/feature-gate-const_transmute.rs index 6a5bbec77fdb9..1afc4ece5c0bd 100644 --- a/src/test/ui/feature-gates/feature-gate-const_transmute.rs +++ b/src/test/ui/feature-gates/feature-gate-const_transmute.rs @@ -1,9 +1,13 @@ +#![feature(const_fn)] + use std::mem; #[repr(transparent)] struct Foo(u32); const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) }; -//~^ ERROR The use of std::mem::transmute() is gated in constants + +const fn transmute_fn() -> u32 { unsafe { mem::transmute(Foo(3)) } } +//~^ ERROR The use of std::mem::transmute() is gated in const fns fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_transmute.stderr b/src/test/ui/feature-gates/feature-gate-const_transmute.stderr index 41b653d98dcbf..dfa2857510bf6 100644 --- a/src/test/ui/feature-gates/feature-gate-const_transmute.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_transmute.stderr @@ -1,8 +1,8 @@ -error[E0658]: The use of std::mem::transmute() is gated in constants - --> $DIR/feature-gate-const_transmute.rs:6:38 +error[E0658]: The use of std::mem::transmute() is gated in const fns + --> $DIR/feature-gate-const_transmute.rs:10:43 | -LL | const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | const fn transmute_fn() -> u32 { unsafe { mem::transmute(Foo(3)) } } + | ^^^^^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/53605 = help: add `#![feature(const_transmute)]` to the crate attributes to enable