From 6d03bbd480ef9bef09321fbfdc00229a03091b11 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 8 Mar 2020 14:24:32 +0100 Subject: [PATCH 1/6] constify `mem::discriminant` --- src/libcore/intrinsics.rs | 1 + src/libcore/lib.rs | 1 + src/libcore/mem/mod.rs | 3 ++- src/librustc_mir/interpret/intrinsics.rs | 5 +++++ src/librustc_span/symbol.rs | 1 + src/test/ui/consts/const_discriminant.rs | 22 ++++++++++++++++++++++ 6 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/consts/const_discriminant.rs diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index a889eff75c044..63c5d782e6566 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1852,6 +1852,7 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is /// [`std::mem::discriminant`](../../std/mem/fn.discriminant.html) + #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] pub fn discriminant_value(v: &T) -> u64; /// Rust's "try catch" construct which invokes the function pointer `f` with diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 41fb4a77c7ae8..cac61c2c674ad 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -72,6 +72,7 @@ #![feature(concat_idents)] #![feature(const_ascii_ctype_on_intrinsics)] #![feature(const_alloc_layout)] +#![feature(const_discriminant)] #![feature(const_if_match)] #![feature(const_loop)] #![feature(const_checked_int_methods)] diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 90144d11dc9d1..c23d0adab5c0d 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -864,6 +864,7 @@ impl fmt::Debug for Discriminant { /// assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3))); /// ``` #[stable(feature = "discriminant_value", since = "1.21.0")] -pub fn discriminant(v: &T) -> Discriminant { +#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] +pub const fn discriminant(v: &T) -> Discriminant { Discriminant(intrinsics::discriminant_value(v), PhantomData) } diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 891afbf437f2b..1e5ed76c467b4 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -216,6 +216,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; self.write_scalar(val, dest)?; } + sym::discriminant_value => { + let place = self.deref_operand(args[0])?; + let discr_val = self.read_discriminant(place.into())?.0; + self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; + } sym::unchecked_shl | sym::unchecked_shr | sym::unchecked_add diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index c39f9f360c027..0d37e9c2c7b08 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -265,6 +265,7 @@ symbols! { derive, diagnostic, direct, + discriminant_value, doc, doc_alias, doc_cfg, diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs new file mode 100644 index 0000000000000..5a32ff2915849 --- /dev/null +++ b/src/test/ui/consts/const_discriminant.rs @@ -0,0 +1,22 @@ +// run-pass +#![feature(const_discriminant)] + +use std::mem::{discriminant, Discriminant}; + +enum Test { + A(u8), + B, + C { a: u8, b: u8 }, +} + +const TEST_A: Discriminant = discriminant(&Test::A(5)); +const TEST_A_OTHER: Discriminant = discriminant(&Test::A(17)); +const TEST_B: Discriminant = discriminant(&Test::B); + +fn main() { + assert_eq!(TEST_A, TEST_A_OTHER); + assert_eq!(TEST_A, discriminant(&Test::A(17))); + assert_eq!(TEST_B, discriminant(&Test::B)); + assert_ne!(TEST_A, TEST_B); + assert_ne!(TEST_B, discriminant(&Test::C { a: 42, b: 7 })); +} From 22f2385a738827fb682bc72bb9e1d794bb436672 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 8 Mar 2020 15:12:46 +0100 Subject: [PATCH 2/6] prevent potential promotion in const_discriminant --- src/test/ui/consts/const_discriminant.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs index 5a32ff2915849..564434bb6fa36 100644 --- a/src/test/ui/consts/const_discriminant.rs +++ b/src/test/ui/consts/const_discriminant.rs @@ -3,6 +3,8 @@ use std::mem::{discriminant, Discriminant}; +fn identity(x: T) -> T { x } + enum Test { A(u8), B, @@ -15,8 +17,8 @@ const TEST_B: Discriminant = discriminant(&Test::B); fn main() { assert_eq!(TEST_A, TEST_A_OTHER); - assert_eq!(TEST_A, discriminant(&Test::A(17))); - assert_eq!(TEST_B, discriminant(&Test::B)); + assert_eq!(TEST_A, discriminant(identity(&Test::A(17)))); + assert_eq!(TEST_B, discriminant(identity(&Test::B))); assert_ne!(TEST_A, TEST_B); - assert_ne!(TEST_B, discriminant(&Test::C { a: 42, b: 7 })); + assert_ne!(TEST_B, discriminant(identity(&Test::C { a: 42, b: 7 }))); } From 6bbb9b86c4d4be72a92676e2d51dcc8032e1fe3e Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 8 Mar 2020 17:04:02 +0100 Subject: [PATCH 3/6] test discriminant of enum with uninhabited variant --- src/test/ui/consts/const_discriminant.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs index 564434bb6fa36..9aac3c4532f47 100644 --- a/src/test/ui/consts/const_discriminant.rs +++ b/src/test/ui/consts/const_discriminant.rs @@ -15,10 +15,21 @@ const TEST_A: Discriminant = discriminant(&Test::A(5)); const TEST_A_OTHER: Discriminant = discriminant(&Test::A(17)); const TEST_B: Discriminant = discriminant(&Test::B); +enum Void {} + +enum SingleVariant { + V, + Never(Void), +} + +const TEST_V: Discriminant = discriminant(&SingleVariant::V); + fn main() { assert_eq!(TEST_A, TEST_A_OTHER); assert_eq!(TEST_A, discriminant(identity(&Test::A(17)))); assert_eq!(TEST_B, discriminant(identity(&Test::B))); assert_ne!(TEST_A, TEST_B); assert_ne!(TEST_B, discriminant(identity(&Test::C { a: 42, b: 7 }))); + + assert_eq!(TEST_V, discriminant(identity(&SingleVariant::V))); } From 4b724e82d2b1065eea10a96fafb19e1390edf0d7 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 8 Mar 2020 18:56:15 +0100 Subject: [PATCH 4/6] allow dead code in discriminant test --- src/test/ui/consts/const_discriminant.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs index 9aac3c4532f47..c67be3c3713f5 100644 --- a/src/test/ui/consts/const_discriminant.rs +++ b/src/test/ui/consts/const_discriminant.rs @@ -1,5 +1,6 @@ // run-pass #![feature(const_discriminant)] +#![allow(dead_code)] use std::mem::{discriminant, Discriminant}; From 314da73797ede5da3ed658208aa31d6aab9cfbf0 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 9 Mar 2020 10:12:44 +0100 Subject: [PATCH 5/6] discrimant test must not be inlined! --- src/test/ui/consts/const_discriminant.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs index c67be3c3713f5..55e2918c85f93 100644 --- a/src/test/ui/consts/const_discriminant.rs +++ b/src/test/ui/consts/const_discriminant.rs @@ -4,6 +4,7 @@ use std::mem::{discriminant, Discriminant}; +#[inline(never)] fn identity(x: T) -> T { x } enum Test { From 7b3e3ff39aa45103a6f8432466f8078970866142 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 10 Mar 2020 12:46:22 +0100 Subject: [PATCH 6/6] explain the use of a custom identity function --- src/test/ui/consts/const_discriminant.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs index 55e2918c85f93..1ad5134e71c52 100644 --- a/src/test/ui/consts/const_discriminant.rs +++ b/src/test/ui/consts/const_discriminant.rs @@ -4,6 +4,9 @@ use std::mem::{discriminant, Discriminant}; +// `discriminant(const_expr)` may get const-propagated. +// As we want to check that const-eval is equal to ordinary exection, +// we wrap `const_expr` with a function which is not const to prevent this. #[inline(never)] fn identity(x: T) -> T { x }