rust-lang / rfcs

RFCs for changes to Rust
https://rust-lang.github.io/rfcs/
Apache License 2.0
5.92k stars 1.57k forks source link

Feature Request static asserts #2790

Open elichai opened 5 years ago

elichai commented 5 years ago

I think asserts are a pretty common thing, especially in unsafe rust (checking sizes/alignments etc.)

Now with anonymous consts we can already do things like:

use std::mem::*;
#[macro_export]
macro_rules! static_assert {
    ($condition:expr) => {
        const _: &() = &[()][1 - ($condition) as usize];
    }
}

static_assert!(size_of::<usize>() == 8);
static_assert!(size_of::<*const u8>() == 8);
static_assert!(align_of::<*const u8>() >= align_of::<u128>());
static_assert!(5>3);

I propose to add macros like this to the core library, with the whole assert/assert_eq/assert_ne facade.

I think these would be really useful

memoryruins commented 5 years ago

It is definitely useful! Check out the static_assertions crate, which offers similar macros for compile-time asserts. It might be worth seeing if there is anything left to explore in that crate before putting the macros into core. The Rust Internals forum is often a good place for discussions like these. cc @nvzqz

matthiaskrgr commented 5 years ago

https://github.com/rust-lang/rust/blob/master/src/librustc_data_structures/macros.rs#L4

nvzqz commented 5 years ago

@memoryruins it looks like you're not the only one this week suggesting this: https://github.com/rust-lang/rust/pull/61347#issuecomment-520943044.

ExoticMatter commented 5 years ago

rust-lang/rust#51999 allows panicking in constants, and rust-lang/rust#49146 will allow conditionals in constants. Once rust-lang/rust#49146 is implemented you will be able to improve the error messages:

#![feature(const_fn, const_panic)]

#[doc(hidden)]
pub use core as core_;

#[macro_export]
macro_rules! static_assert {
    ($cond:expr) => {
        $crate::static_assert!($cond, concat!("assertion failed: ", stringify!($cond)));
    };
    ($cond:expr, $($t:tt)+) => {
        #[forbid(const_err)]
        const _: () = {
            if !$cond {
                $crate::core_::panic!($($t)+)
            }
        };
    };
}

//static_assert!(1 + 1 == 3); // not actually possible yet

The error messages are noisy but more descriptive than an integer overflow error:

error: any use of this value will cause an error
  --> src/lib.rs:22:1
   |
14 | /         const _: () = {
15 | |             //if !$cond {
16 | |                 $crate::core_::panic!($($t)+)
17 | |             //}
18 | |         };
   | |__________-
...
22 |   static_assert!(1 + 1 == 3);
   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |   |
   |   the evaluated program panicked at 'assertion failed: 1 + 1 == 3', src/lib.rs:22:1
   |   in this macro invocation
   |
note: lint level defined here
  --> src/lib.rs:13:18
   |
13 |         #[forbid(const_err)]
   |                  ^^^^^^^^^
...
22 | static_assert!(1 + 1 == 3);
   | --------------------------- in this macro invocation
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
est31 commented 2 years ago

Evaluation in a const context works for assert already since 1.57.0: https://github.com/rust-lang/rust/pull/89508/