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 pub use crate::{ 65 build_assert, 66 build_error, 67 const_assert, 68 static_assert, // 69 }; 70 71 #[doc(hidden)] 72 pub use build_error::build_error; 73 74 /// Static assert (i.e. compile-time assert). 75 /// 76 /// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`]. 77 /// 78 /// An optional panic message can be supplied after the expression. 79 /// Currently only a string literal without formatting is supported 80 /// due to constness limitations of the [`assert!`] macro. 81 /// 82 /// The feature may be added to Rust in the future: see [RFC 2790]. 83 /// 84 /// You cannot refer to generics or variables with [`static_assert!`]. If you need to refer to 85 /// generics, use [`const_assert!`]; if you need to refer to variables, use [`build_assert!`]. See 86 /// the [module documentation](self). 87 /// 88 /// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert 89 /// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert 90 /// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790 91 /// 92 /// # Examples 93 /// 94 /// ``` 95 /// static_assert!(42 > 24); 96 /// static_assert!(core::mem::size_of::<u8>() == 1); 97 /// 98 /// const X: &[u8] = b"bar"; 99 /// static_assert!(X[1] == b'a'); 100 /// 101 /// const fn f(x: i32) -> i32 { 102 /// x + 2 103 /// } 104 /// static_assert!(f(40) == 42); 105 /// static_assert!(f(40) == 42, "f(x) must add 2 to the given input."); 106 /// ``` 107 #[macro_export] 108 macro_rules! static_assert { 109 ($condition:expr $(,$arg:literal)?) => { 110 const _: () = ::core::assert!($condition $(,$arg)?); 111 }; 112 } 113 114 /// Assertion during constant evaluation. 115 /// 116 /// This is a more powerful version of [`static_assert!`] that can refer to generics inside 117 /// functions or implementation blocks. However, it also has a limitation where it can only appear 118 /// in places where statements can appear; for example, you cannot use it as an item in the module. 119 /// 120 /// [`static_assert!`] should be preferred if no generics are referred to in the condition. You 121 /// cannot refer to variables with [`const_assert!`] (even inside `const fn`); if you need the 122 /// capability, use [`build_assert!`]. See the [module documentation](self). 123 /// 124 /// # Examples 125 /// 126 /// ``` 127 /// fn foo<const N: usize>() { 128 /// const_assert!(N > 1); 129 /// } 130 /// 131 /// fn bar<T>() { 132 /// const_assert!(size_of::<T>() > 0, "T cannot be ZST"); 133 /// } 134 /// ``` 135 #[macro_export] 136 macro_rules! const_assert { 137 ($condition:expr $(,$arg:literal)?) => { 138 const { ::core::assert!($condition $(,$arg)?) }; 139 }; 140 } 141 142 /// Fails the build if the code path calling `build_error!` can possibly be executed. 143 /// 144 /// If the macro is executed in const context, `build_error!` will panic. 145 /// If the compiler or optimizer cannot guarantee that `build_error!` can never 146 /// be called, a build error will be triggered. 147 /// 148 /// # Examples 149 /// 150 /// ``` 151 /// #[inline] 152 /// fn foo(a: usize) -> usize { 153 /// a.checked_add(1).unwrap_or_else(|| build_error!("overflow")) 154 /// } 155 /// 156 /// assert_eq!(foo(usize::MAX - 1), usize::MAX); // OK. 157 /// // foo(usize::MAX); // Fails to compile. 158 /// ``` 159 #[macro_export] 160 macro_rules! build_error { 161 () => {{ 162 $crate::build_assert::build_error("") 163 }}; 164 ($msg:expr) => {{ 165 $crate::build_assert::build_error($msg) 166 }}; 167 } 168 169 /// Asserts that a boolean expression is `true` at compile time. 170 /// 171 /// If the condition is evaluated to `false` in const context, `build_assert!` 172 /// will panic. If the compiler or optimizer cannot guarantee the condition will 173 /// be evaluated to `true`, a build error will be triggered. 174 /// 175 /// When a condition depends on a function argument, the function must be annotated with 176 /// `#[inline(always)]`. Without this attribute, the compiler may choose to not inline the 177 /// function, preventing it from optimizing out the error path. 178 /// 179 /// If the assertion condition does not depend on any variables or generics, you should use 180 /// [`static_assert!`]. If the assertion condition does not depend on variables, but does depend on 181 /// generics, you should use [`const_assert!`]. See the [module documentation](self). 182 /// 183 /// # Examples 184 /// 185 /// ``` 186 /// #[inline(always)] // Important. 187 /// fn bar(n: usize) { 188 /// build_assert!(n > 1); 189 /// } 190 /// 191 /// fn foo() { 192 /// bar(2); 193 /// } 194 /// 195 /// #[inline(always)] // Important. 196 /// const fn const_bar(n: usize) { 197 /// build_assert!(n > 1); 198 /// } 199 /// 200 /// const _: () = const_bar(2); 201 /// ``` 202 #[macro_export] 203 macro_rules! build_assert { 204 ($cond:expr $(,)?) => {{ 205 if !$cond { 206 $crate::build_assert::build_error(concat!("assertion failed: ", stringify!($cond))); 207 } 208 }}; 209 ($cond:expr, $msg:expr) => {{ 210 if !$cond { 211 $crate::build_assert::build_error($msg); 212 } 213 }}; 214 } 215