kernel/build_assert.rs
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)]
65pub use crate::{
66 build_assert_macro as build_assert,
67 build_error,
68 const_assert,
69 static_assert, //
70};
71
72#[doc(hidden)]
73pub 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)]
110macro_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)]
139macro_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)]
164macro_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)]
208macro_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}