Skip to content

Commit

Permalink
Rollup merge of rust-lang#91323 - RalfJung:assert-type, r=oli-obk
Browse files Browse the repository at this point in the history
CTFE: support assert_zero_valid and assert_uninit_valid

This ensures the implementation of all three type-based assert_ intrinsics remains consistent in Miri.

`assert_inhabited` recently got stabilized in rust-lang#90896 (meaning stable `const fn` can call it), so do the same with these other intrinsics.

Cc `@rust-lang/wg-const-eval`
  • Loading branch information
matthiaskrgr authored Nov 29, 2021
2 parents 0e2e63a + 6c3c3e0 commit 78041be
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 29 deletions.
26 changes: 25 additions & 1 deletion compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,10 +394,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
sym::transmute => {
self.copy_op_transmute(&args[0], dest)?;
}
sym::assert_inhabited => {
sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
let ty = instance.substs.type_at(0);
let layout = self.layout_of(ty)?;

// For *all* intrinsics we first check `is_uninhabited` to give a more specific
// error message.
if layout.abi.is_uninhabited() {
// The run-time intrinsic panics just to get a good backtrace; here we abort
// since there is no problem showing a backtrace even for aborts.
Expand All @@ -409,6 +411,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
),
)?;
}
if intrinsic_name == sym::assert_zero_valid
&& !layout.might_permit_raw_init(self, /*zero:*/ true)
{
M::abort(
self,
format!(
"aborted execution: attempted to zero-initialize type `{}`, which is invalid",
ty
),
)?;
}
if intrinsic_name == sym::assert_uninit_valid
&& !layout.might_permit_raw_init(self, /*zero:*/ false)
{
M::abort(
self,
format!(
"aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
ty
),
)?;
}
}
sym::simd_insert => {
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
Expand Down
2 changes: 2 additions & 0 deletions library/core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -860,12 +860,14 @@ extern "rust-intrinsic" {
/// zero-initialization: This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
pub fn assert_zero_valid<T>();

/// A guard for unsafe functions that cannot ever be executed if `T` has invalid
/// bit patterns: This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
pub fn assert_uninit_valid<T>();

/// Gets a reference to a static `Location` indicating where it was called.
Expand Down
22 changes: 22 additions & 0 deletions src/test/ui/consts/assert-type-intrinsics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// error-pattern: any use of this value will cause an error

#![feature(never_type)]
#![feature(const_maybe_uninit_assume_init, const_assert_type2)]
#![feature(core_intrinsics)]

use std::intrinsics;

#[allow(invalid_value)]
fn main() {
use std::mem::MaybeUninit;

const _BAD1: () = unsafe {
MaybeUninit::<!>::uninit().assume_init();
};
const _BAD2: () = unsafe {
intrinsics::assert_uninit_valid::<bool>();
};
const _BAD3: () = unsafe {
intrinsics::assert_zero_valid::<&'static i32>();
};
}
39 changes: 39 additions & 0 deletions src/test/ui/consts/assert-type-intrinsics.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
error: any use of this value will cause an error
--> $DIR/assert-type-intrinsics.rs:14:9
|
LL | / const _BAD1: () = unsafe {
LL | | MaybeUninit::<!>::uninit().assume_init();
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
LL | | };
| |______-
|
= note: `#[deny(const_err)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>

error: any use of this value will cause an error
--> $DIR/assert-type-intrinsics.rs:17:9
|
LL | / const _BAD2: () = unsafe {
LL | | intrinsics::assert_uninit_valid::<bool>();
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
LL | | };
| |______-
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>

error: any use of this value will cause an error
--> $DIR/assert-type-intrinsics.rs:20:9
|
LL | / const _BAD3: () = unsafe {
LL | | intrinsics::assert_zero_valid::<&'static i32>();
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid
LL | | };
| |______-
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>

error: aborting due to 3 previous errors

13 changes: 0 additions & 13 deletions src/test/ui/consts/assume-type-intrinsics.rs

This file was deleted.

15 changes: 0 additions & 15 deletions src/test/ui/consts/assume-type-intrinsics.stderr

This file was deleted.

0 comments on commit 78041be

Please sign in to comment.