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 #[doc(inline)] 65 pub use crate::{ 66 build_assert_macro as build_assert, 67 build_error, 68 const_assert, 69 static_assert, // 70 }; 71 72 #[doc(hidden)] 73 pub use build_error::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 #[macro_export] 109 #[doc(hidden)] 110 macro_rules! static_assert { 111 ($condition:expr $(,$arg:literal)?) => { 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 } 220