| 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | |
| 3 | //! Various assertions that happen during build-time. |
| 4 | //! |
| 5 | //! There are three types of build-time assertions that you can use: |
| 6 | //! - [`static_assert!`] |
| 7 | //! - [`const_assert!`] |
| 8 | //! - [`build_assert!`] |
| 9 | //! |
| 10 | //! The ones towards the bottom of the list are more expressive, while the ones towards the top of |
| 11 | //! the list are more robust and trigger earlier in the compilation pipeline. Therefore, you should |
| 12 | //! prefer the ones towards the top of the list wherever possible. |
| 13 | //! |
| 14 | //! # Choosing the correct assertion |
| 15 | //! |
| 16 | //! If you're asserting outside any bodies (e.g. initializers or function bodies), you should use |
| 17 | //! [`static_assert!`] as it is the only assertion that can be used in that context. |
| 18 | //! |
| 19 | //! Inside bodies, if your assertion condition does not depend on any variable or generics, you |
| 20 | //! should use [`static_assert!`]. If the condition depends on generics, but not variables |
| 21 | //! (including function arguments), you should use [`const_assert!`]. Otherwise, use |
| 22 | //! [`build_assert!`]. The same is true regardless if the function is `const fn`. |
| 23 | //! |
| 24 | //! ``` |
| 25 | //! // Outside any bodies. |
| 26 | //! static_assert!(core::mem::size_of::<u8>() == 1); |
| 27 | //! // `const_assert!` and `build_assert!` cannot be used here, they will fail to compile. |
| 28 | //! |
| 29 | //! #[inline(always)] |
| 30 | //! fn foo<const N: usize>(v: usize) { |
| 31 | //! static_assert!(core::mem::size_of::<u8>() == 1); // Preferred. |
| 32 | //! const_assert!(core::mem::size_of::<u8>() == 1); // Discouraged. |
| 33 | //! build_assert!(core::mem::size_of::<u8>() == 1); // Discouraged. |
| 34 | //! |
| 35 | //! // `static_assert!(N > 1);` is not allowed. |
| 36 | //! const_assert!(N > 1); // Preferred. |
| 37 | //! build_assert!(N > 1); // Discouraged. |
| 38 | //! |
| 39 | //! // `static_assert!(v > 1);` is not allowed. |
| 40 | //! // `const_assert!(v > 1);` is not allowed. |
| 41 | //! build_assert!(v > 1); // Works. |
| 42 | //! } |
| 43 | //! ``` |
| 44 | //! |
| 45 | //! # Detailed behavior |
| 46 | //! |
| 47 | //! `static_assert!()` is equivalent to `static_assert` in C. It requires `expr` to be a constant |
| 48 | //! expression. This expression cannot refer to any generics. A `static_assert!(expr)` in a program |
| 49 | //! is always evaluated, regardless if the function it appears in is used or not. This is also the |
| 50 | //! only usable assertion outside a body. |
| 51 | //! |
| 52 | //! `const_assert!()` has no direct C equivalence. It is a more powerful version of |
| 53 | //! `static_assert!()`, where it may refer to generics in a function. Note that due to the ability |
| 54 | //! to refer to generics, the assertion is tied to a specific instance of a function. So if it is |
| 55 | //! used in a generic function that is not instantiated, the assertion will not be checked. For this |
| 56 | //! reason, `static_assert!()` is preferred wherever possible. |
| 57 | //! |
| 58 | //! `build_assert!()` is equivalent to `BUILD_BUG_ON`. It is even more powerful than |
| 59 | //! `const_assert!()` because it can be used to check tautologies that depend on runtime value (this |
| 60 | //! is the same as `BUILD_BUG_ON`). However, the assertion failure mechanism can possibly be |
| 61 | //! undefined symbols and linker errors, it is not developer friendly to debug, so it is recommended |
| 62 | //! to avoid it and prefer other two assertions where possible. |
| 63 | |
| 64 | |
| 65 | pub use crate:: |
| 66 | build_assert_macro as build_assert, |
| 67 | build_error, |
| 68 | const_assert, |
| 69 | static_assert, // |
| 70 | ; |
| 71 | |
| 72 | |
| 73 | pub use build_error as build_error_fn; |
| 74 | |
| 75 | /// Static assert (i.e. compile-time assert). |
| 76 | /// |
| 77 | /// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`]. |
| 78 | /// |
| 79 | /// An optional panic message can be supplied after the expression. |
| 80 | /// Currently only a string literal without formatting is supported |
| 81 | /// due to constness limitations of the [`assert!`] macro. |
| 82 | /// |
| 83 | /// The feature may be added to Rust in the future: see [RFC 2790]. |
| 84 | /// |
| 85 | /// You cannot refer to generics or variables with [`static_assert!`]. If you need to refer to |
| 86 | /// generics, use [`const_assert!`]; if you need to refer to variables, use [`build_assert!`]. See |
| 87 | /// the [module documentation](self). |
| 88 | /// |
| 89 | /// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert |
| 90 | /// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert |
| 91 | /// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790 |
| 92 | /// |
| 93 | /// # Examples |
| 94 | /// |
| 95 | /// ``` |
| 96 | /// static_assert!(42 > 24); |
| 97 | /// static_assert!(core::mem::size_of::<u8>() == 1); |
| 98 | /// |
| 99 | /// const X: &[u8] = b"bar"; |
| 100 | /// static_assert!(X[1] == b'a'); |
| 101 | /// |
| 102 | /// const fn f(x: i32) -> i32 { |
| 103 | /// x + 2 |
| 104 | /// } |
| 105 | /// static_assert!(f(40) == 42); |
| 106 | /// static_assert!(f(40) == 42, "f(x) must add 2 to the given input."); |
| 107 | /// ``` |
| 108 | |
| 109 | |
| 110 | |
| 111 | |
| 112 | const _: () = ::core::assert!($condition $(,$arg)?); |
| 113 | }; |
| 114 | } |
| 115 | |
| 116 | /// Assertion during constant evaluation. |
| 117 | /// |
| 118 | /// This is a more powerful version of [`static_assert!`] that can refer to generics inside |
| 119 | /// functions or implementation blocks. However, it also has a limitation where it can only appear |
| 120 | /// in places where statements can appear; for example, you cannot use it as an item in the module. |
| 121 | /// |
| 122 | /// [`static_assert!`] should be preferred if no generics are referred to in the condition. You |
| 123 | /// cannot refer to variables with [`const_assert!`] (even inside `const fn`); if you need the |
| 124 | /// capability, use [`build_assert!`]. See the [module documentation](self). |
| 125 | /// |
| 126 | /// # Examples |
| 127 | /// |
| 128 | /// ``` |
| 129 | /// fn foo<const N: usize>() { |
| 130 | /// const_assert!(N > 1); |
| 131 | /// } |
| 132 | /// |
| 133 | /// fn bar<T>() { |
| 134 | /// const_assert!(size_of::<T>() > 0, "T cannot be ZST"); |
| 135 | /// } |
| 136 | /// ``` |
| 137 | #[macro_export] |
| 138 | #[doc(hidden)] |
| 139 | macro_rules! const_assert { |
| 140 | ($condition:expr $(,$arg:literal)?) => { |
| 141 | const { ::core::assert!($condition $(,$arg)?) }; |
| 142 | }; |
| 143 | } |
| 144 | |
| 145 | /// Fails the build if the code path calling `build_error!` can possibly be executed. |
| 146 | /// |
| 147 | /// If the macro is executed in const context, `build_error!` will panic. |
| 148 | /// If the compiler or optimizer cannot guarantee that `build_error!` can never |
| 149 | /// be called, a build error will be triggered. |
| 150 | /// |
| 151 | /// # Examples |
| 152 | /// |
| 153 | /// ``` |
| 154 | /// #[inline] |
| 155 | /// fn foo(a: usize) -> usize { |
| 156 | /// a.checked_add(1).unwrap_or_else(|| build_error!("overflow")) |
| 157 | /// } |
| 158 | /// |
| 159 | /// assert_eq!(foo(usize::MAX - 1), usize::MAX); // OK. |
| 160 | /// // foo(usize::MAX); // Fails to compile. |
| 161 | /// ``` |
| 162 | #[macro_export] |
| 163 | #[doc(hidden)] |
| 164 | macro_rules! build_error { |
| 165 | () => {{ |
| 166 | $crate::build_assert::build_error_fn("") |
| 167 | }}; |
| 168 | ($msg:expr) => {{ |
| 169 | $crate::build_assert::build_error_fn($msg) |
| 170 | }}; |
| 171 | } |
| 172 | |
| 173 | /// Asserts that a boolean expression is `true` at compile time. |
| 174 | /// |
| 175 | /// If the condition is evaluated to `false` in const context, `build_assert!` |
| 176 | /// will panic. If the compiler or optimizer cannot guarantee the condition will |
| 177 | /// be evaluated to `true`, a build error will be triggered. |
| 178 | /// |
| 179 | /// When a condition depends on a function argument, the function must be annotated with |
| 180 | /// `#[inline(always)]`. Without this attribute, the compiler may choose to not inline the |
| 181 | /// function, preventing it from optimizing out the error path. |
| 182 | /// |
| 183 | /// If the assertion condition does not depend on any variables or generics, you should use |
| 184 | /// [`static_assert!`]. If the assertion condition does not depend on variables, but does depend on |
| 185 | /// generics, you should use [`const_assert!`]. See the [module documentation](self). |
| 186 | /// |
| 187 | /// # Examples |
| 188 | /// |
| 189 | /// ``` |
| 190 | /// #[inline(always)] // Important. |
| 191 | /// fn bar(n: usize) { |
| 192 | /// build_assert!(n > 1); |
| 193 | /// } |
| 194 | /// |
| 195 | /// fn foo() { |
| 196 | /// bar(2); |
| 197 | /// } |
| 198 | /// |
| 199 | /// #[inline(always)] // Important. |
| 200 | /// const fn const_bar(n: usize) { |
| 201 | /// build_assert!(n > 1); |
| 202 | /// } |
| 203 | /// |
| 204 | /// const _: () = const_bar(2); |
| 205 | /// ``` |
| 206 | #[macro_export] |
| 207 | #[doc(hidden)] |
| 208 | macro_rules! build_assert_macro { |
| 209 | ($cond:expr $(,)?) => {{ |
| 210 | if !$cond { |
| 211 | $crate::build_assert::build_error_fn(concat!("assertion failed: ", stringify!($cond))); |
| 212 | } |
| 213 | }}; |
| 214 | ($cond:expr, $msg:expr) => {{ |
| 215 | if !$cond { |
| 216 | $crate::build_assert::build_error_fn($msg); |
| 217 | } |
| 218 | }}; |
| 219 | } |