Skip to main content

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
64pub use crate::{
65    build_assert,
66    build_error,
67    const_assert,
68    static_assert, //
69};
70
71#[doc(hidden)]
72pub 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]
108macro_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]
136macro_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]
160macro_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]
203macro_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}