From 4fefa2c75d43dcf1184c7a7116cbd9595a8e49ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Fri, 17 Jul 2020 21:57:13 +0200 Subject: [PATCH 1/4] Make unreachable_unchecked a const fn --- src/libcore/hint.rs | 3 ++- src/libcore/intrinsics.rs | 1 + src/libcore/lib.rs | 1 + src/librustc_mir/interpret/intrinsics.rs | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs index 9ebcde79b633d..3116815f5d655 100644 --- a/src/libcore/hint.rs +++ b/src/libcore/hint.rs @@ -45,7 +45,8 @@ use crate::intrinsics; /// ``` #[inline] #[stable(feature = "unreachable", since = "1.27.0")] -pub unsafe fn unreachable_unchecked() -> ! { +#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")] +pub const unsafe fn unreachable_unchecked() -> ! { // SAFETY: the safety contract for `intrinsics::unreachable` must // be upheld by the caller. unsafe { intrinsics::unreachable() } diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 080760aa81f30..8f0cf4361e708 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -932,6 +932,7 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is /// [`std::hint::unreachable_unchecked`](../../std/hint/fn.unreachable_unchecked.html). + #[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")] pub fn unreachable() -> !; /// Informs the optimizer that a condition is always true. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 96436bb253df0..a8c9b8f257700 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -91,6 +91,7 @@ #![feature(const_slice_ptr_len)] #![feature(const_type_name)] #![feature(const_likely)] +#![feature(const_unreachable_unchecked)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 851862640226f..5836fc9c95a80 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -95,6 +95,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (dest, ret) = match ret { None => match intrinsic_name { sym::transmute => throw_ub_format!("transmuting to uninhabited type"), + sym::unreachable => throw_ub!(Unreachable), sym::abort => M::abort(self)?, // Unsupported diverging intrinsic. _ => return Ok(false), From 2f28d5945dab495a77c67c6051eea116ce9ceee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Fri, 17 Jul 2020 21:59:37 +0200 Subject: [PATCH 2/4] Add a passing test for const unsafe_unreachable --- src/test/ui/consts/const_unsafe_unreachable.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/ui/consts/const_unsafe_unreachable.rs diff --git a/src/test/ui/consts/const_unsafe_unreachable.rs b/src/test/ui/consts/const_unsafe_unreachable.rs new file mode 100644 index 0000000000000..cfed6e5deb999 --- /dev/null +++ b/src/test/ui/consts/const_unsafe_unreachable.rs @@ -0,0 +1,17 @@ +// run-pass + +#![feature(const_fn)] +#![feature(const_unreachable_unchecked)] + +const unsafe fn foo(x: bool) -> bool { + match x { + true => true, + false => std::hint::unreachable_unchecked(), + } +} + +const BAR: bool = unsafe { foo(true) }; + +fn main() { + assert_eq!(BAR, true); +} From c45e9c86ca5e1aa20ec8ec9904c4ad9a33a072e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Fri, 17 Jul 2020 22:03:33 +0200 Subject: [PATCH 3/4] Add a test for const unsafe_unreachable that triggers UB --- .../ui/consts/const_unsafe_unreachable_ub.rs | 15 ++++++++++++++ .../consts/const_unsafe_unreachable_ub.stderr | 20 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/test/ui/consts/const_unsafe_unreachable_ub.rs create mode 100644 src/test/ui/consts/const_unsafe_unreachable_ub.stderr diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.rs b/src/test/ui/consts/const_unsafe_unreachable_ub.rs new file mode 100644 index 0000000000000..2e4dfd1522b9a --- /dev/null +++ b/src/test/ui/consts/const_unsafe_unreachable_ub.rs @@ -0,0 +1,15 @@ +#![feature(const_fn)] +#![feature(const_unreachable_unchecked)] + +const unsafe fn foo(x: bool) -> bool { + match x { + true => true, + false => std::hint::unreachable_unchecked(), + } +} + +const BAR: bool = unsafe { foo(false) }; + +fn main() { + assert_eq!(BAR, true); +} diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr new file mode 100644 index 0000000000000..0a7aa4e00214f --- /dev/null +++ b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr @@ -0,0 +1,20 @@ +error: any use of this value will cause an error + --> $SRC_DIR/libcore/hint.rs:LL:COL + | +LL | unsafe { intrinsics::unreachable() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | entering unreachable code + | inside `std::hint::unreachable_unchecked` at $SRC_DIR/libcore/hint.rs:LL:COL + | inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:7:18 + | inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:11:28 + | + ::: $DIR/const_unsafe_unreachable_ub.rs:11:1 + | +LL | const BAR: bool = unsafe { foo(false) }; + | ---------------------------------------- + | + = note: `#[deny(const_err)]` on by default + +error: aborting due to previous error + From 6cd164f49e6f9c2b914fa5d55755d78e3fabbc27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Sat, 18 Jul 2020 02:27:41 +0200 Subject: [PATCH 4/4] Update UB test to fail during build with contant errors --- .../ui/consts/const_unsafe_unreachable_ub.rs | 5 +++ .../consts/const_unsafe_unreachable_ub.stderr | 34 ++++++++++++++++--- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.rs b/src/test/ui/consts/const_unsafe_unreachable_ub.rs index 2e4dfd1522b9a..11920d852e02f 100644 --- a/src/test/ui/consts/const_unsafe_unreachable_ub.rs +++ b/src/test/ui/consts/const_unsafe_unreachable_ub.rs @@ -1,3 +1,5 @@ +// build-fail + #![feature(const_fn)] #![feature(const_unreachable_unchecked)] @@ -8,8 +10,11 @@ const unsafe fn foo(x: bool) -> bool { } } +#[warn(const_err)] const BAR: bool = unsafe { foo(false) }; fn main() { assert_eq!(BAR, true); + //~^ ERROR E0080 + //~| ERROR erroneous constant } diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr index 0a7aa4e00214f..3ef8043a54d88 100644 --- a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr +++ b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr @@ -1,4 +1,4 @@ -error: any use of this value will cause an error +warning: any use of this value will cause an error --> $SRC_DIR/libcore/hint.rs:LL:COL | LL | unsafe { intrinsics::unreachable() } @@ -6,15 +6,39 @@ LL | unsafe { intrinsics::unreachable() } | | | entering unreachable code | inside `std::hint::unreachable_unchecked` at $SRC_DIR/libcore/hint.rs:LL:COL - | inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:7:18 - | inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:11:28 + | inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:9:18 + | inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:14:28 | - ::: $DIR/const_unsafe_unreachable_ub.rs:11:1 + ::: $DIR/const_unsafe_unreachable_ub.rs:14:1 | LL | const BAR: bool = unsafe { foo(false) }; | ---------------------------------------- | +note: the lint level is defined here + --> $DIR/const_unsafe_unreachable_ub.rs:13:8 + | +LL | #[warn(const_err)] + | ^^^^^^^^^ + +error[E0080]: evaluation of constant expression failed + --> $DIR/const_unsafe_unreachable_ub.rs:17:3 + | +LL | assert_eq!(BAR, true); + | ^^^^^^^^^^^---^^^^^^^^ + | | + | referenced constant has errors + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: erroneous constant used + --> $DIR/const_unsafe_unreachable_ub.rs:17:3 + | +LL | assert_eq!(BAR, true); + | ^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | = note: `#[deny(const_err)]` on by default + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error +error: aborting due to 2 previous errors; 1 warning emitted +For more information about this error, try `rustc --explain E0080`.