11// SPDX-License-Identifier: GPL-2.0
22
33//! 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+ } ;
470
571#[ doc( hidden) ]
672pub use build_error:: build_error;
@@ -15,6 +81,10 @@ pub use build_error::build_error;
1581///
1682/// The feature may be added to Rust in the future: see [RFC 2790].
1783///
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+ ///
1888/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
1989/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
2090/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
@@ -47,6 +117,10 @@ macro_rules! static_assert {
47117/// functions or implementation blocks. However, it also has a limitation where it can only appear
48118/// in places where statements can appear; for example, you cannot use it as an item in the module.
49119///
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+ ///
50124/// # Examples
51125///
52126/// ```
@@ -98,41 +172,32 @@ macro_rules! build_error {
98172/// will panic. If the compiler or optimizer cannot guarantee the condition will
99173/// be evaluated to `true`, a build error will be triggered.
100174///
101- /// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
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).
102182///
103183/// # Examples
104184///
105- /// These examples show that different types of [`assert!`] will trigger errors
106- /// at different stage of compilation. It is preferred to err as early as
107- /// possible, so [`static_assert!`] should be used whenever possible.
108- /// ```ignore
109- /// fn foo() {
110- /// static_assert!(1 > 1); // Compile-time error
111- /// build_assert!(1 > 1); // Build-time error
112- /// assert!(1 > 1); // Run-time error
113- /// }
114185/// ```
186+ /// #[inline(always)] // Important.
187+ /// fn bar(n: usize) {
188+ /// build_assert!(n > 1);
189+ /// }
115190///
116- /// When the condition refers to generic parameters or parameters of an inline function,
117- /// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
118- /// ```
119- /// fn foo<const N: usize>() {
120- /// // `static_assert!(N > 1);` is not allowed
121- /// build_assert!(N > 1); // Build-time check
122- /// assert!(N > 1); // Run-time check
191+ /// fn foo() {
192+ /// bar(2);
123193/// }
124- /// ```
125194///
126- /// When a condition depends on a function argument, the function must be annotated with
127- /// `#[inline(always)]`. Without this attribute, the compiler may choose to not inline the
128- /// function, preventing it from optimizing out the error path.
129- /// ```
130- /// #[inline(always)]
131- /// fn bar(n: usize) {
132- /// // `static_assert!(n > 1);` is not allowed
133- /// build_assert!(n > 1); // Build-time check
134- /// assert!(n > 1); // Run-time check
195+ /// #[inline(always)] // Important.
196+ /// const fn const_bar(n: usize) {
197+ /// build_assert!(n > 1);
135198/// }
199+ ///
200+ /// const _: () = const_bar(2);
136201/// ```
137202#[ macro_export]
138203macro_rules! build_assert {
0 commit comments