1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
// SPDX-License-Identifier: GPL-2.0
//! Various assertions that happen during build-time.
//!
//! There are three types of build-time assertions that you can use:
//! - [`static_assert!`]
//! - [`const_assert!`]
//! - [`build_assert!`]
//!
//! The ones towards the bottom of the list are more expressive, while the ones towards the top of
//! the list are more robust and trigger earlier in the compilation pipeline. Therefore, you should
//! prefer the ones towards the top of the list wherever possible.
//!
//! # Choosing the correct assertion
//!
//! If you're asserting outside any bodies (e.g. initializers or function bodies), you should use
//! [`static_assert!`] as it is the only assertion that can be used in that context.
//!
//! Inside bodies, if your assertion condition does not depend on any variable or generics, you
//! should use [`static_assert!`]. If the condition depends on generics, but not variables
//! (including function arguments), you should use [`const_assert!`]. Otherwise, use
//! [`build_assert!`]. The same is true regardless if the function is `const fn`.
//!
//! ```
//! // Outside any bodies.
//! static_assert!(core::mem::size_of::<u8>() == 1);
//! // `const_assert!` and `build_assert!` cannot be used here, they will fail to compile.
//!
//! #[inline(always)]
//! fn foo<const N: usize>(v: usize) {
//! static_assert!(core::mem::size_of::<u8>() == 1); // Preferred.
//! const_assert!(core::mem::size_of::<u8>() == 1); // Discouraged.
//! build_assert!(core::mem::size_of::<u8>() == 1); // Discouraged.
//!
//! // `static_assert!(N > 1);` is not allowed.
//! const_assert!(N > 1); // Preferred.
//! build_assert!(N > 1); // Discouraged.
//!
//! // `static_assert!(v > 1);` is not allowed.
//! // `const_assert!(v > 1);` is not allowed.
//! build_assert!(v > 1); // Works.
//! }
//! ```
//!
//! # Detailed behavior
//!
//! `static_assert!()` is equivalent to `static_assert` in C. It requires `expr` to be a constant
//! expression. This expression cannot refer to any generics. A `static_assert!(expr)` in a program
//! is always evaluated, regardless if the function it appears in is used or not. This is also the
//! only usable assertion outside a body.
//!
//! `const_assert!()` has no direct C equivalence. It is a more powerful version of
//! `static_assert!()`, where it may refer to generics in a function. Note that due to the ability
//! to refer to generics, the assertion is tied to a specific instance of a function. So if it is
//! used in a generic function that is not instantiated, the assertion will not be checked. For this
//! reason, `static_assert!()` is preferred wherever possible.
//!
//! `build_assert!()` is equivalent to `BUILD_BUG_ON`. It is even more powerful than
//! `const_assert!()` because it can be used to check tautologies that depend on runtime value (this
//! is the same as `BUILD_BUG_ON`). However, the assertion failure mechanism can possibly be
//! undefined symbols and linker errors, it is not developer friendly to debug, so it is recommended
//! to avoid it and prefer other two assertions where possible.
pub use crate::{
build_assert,
build_error,
const_assert,
static_assert, //
};
#[doc(hidden)]
pub use build_error::build_error;
/// Static assert (i.e. compile-time assert).
///
/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
///
/// An optional panic message can be supplied after the expression.
/// Currently only a string literal without formatting is supported
/// due to constness limitations of the [`assert!`] macro.
///
/// The feature may be added to Rust in the future: see [RFC 2790].
///
/// You cannot refer to generics or variables with [`static_assert!`]. If you need to refer to
/// generics, use [`const_assert!`]; if you need to refer to variables, use [`build_assert!`]. See
/// the [module documentation](self).
///
/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
///
/// # Examples
///
/// ```
/// static_assert!(42 > 24);
/// static_assert!(core::mem::size_of::<u8>() == 1);
///
/// const X: &[u8] = b"bar";
/// static_assert!(X[1] == b'a');
///
/// const fn f(x: i32) -> i32 {
/// x + 2
/// }
/// static_assert!(f(40) == 42);
/// static_assert!(f(40) == 42, "f(x) must add 2 to the given input.");
/// ```
#[macro_export]
macro_rules! static_assert {
($condition:expr $(,$arg:literal)?) => {
const _: () = ::core::assert!($condition $(,$arg)?);
};
}
/// Assertion during constant evaluation.
///
/// This is a more powerful version of [`static_assert!`] that can refer to generics inside
/// functions or implementation blocks. However, it also has a limitation where it can only appear
/// in places where statements can appear; for example, you cannot use it as an item in the module.
///
/// [`static_assert!`] should be preferred if no generics are referred to in the condition. You
/// cannot refer to variables with [`const_assert!`] (even inside `const fn`); if you need the
/// capability, use [`build_assert!`]. See the [module documentation](self).
///
/// # Examples
///
/// ```
/// fn foo<const N: usize>() {
/// const_assert!(N > 1);
/// }
///
/// fn bar<T>() {
/// const_assert!(size_of::<T>() > 0, "T cannot be ZST");
/// }
/// ```
#[macro_export]
macro_rules! const_assert {
($condition:expr $(,$arg:literal)?) => {
const { ::core::assert!($condition $(,$arg)?) };
};
}
/// Fails the build if the code path calling `build_error!` can possibly be executed.
///
/// If the macro is executed in const context, `build_error!` will panic.
/// If the compiler or optimizer cannot guarantee that `build_error!` can never
/// be called, a build error will be triggered.
///
/// # Examples
///
/// ```
/// #[inline]
/// fn foo(a: usize) -> usize {
/// a.checked_add(1).unwrap_or_else(|| build_error!("overflow"))
/// }
///
/// assert_eq!(foo(usize::MAX - 1), usize::MAX); // OK.
/// // foo(usize::MAX); // Fails to compile.
/// ```
#[macro_export]
macro_rules! build_error {
() => {{
$crate::build_assert::build_error("")
}};
($msg:expr) => {{
$crate::build_assert::build_error($msg)
}};
}
/// Asserts that a boolean expression is `true` at compile time.
///
/// If the condition is evaluated to `false` in const context, `build_assert!`
/// will panic. If the compiler or optimizer cannot guarantee the condition will
/// be evaluated to `true`, a build error will be triggered.
///
/// When a condition depends on a function argument, the function must be annotated with
/// `#[inline(always)]`. Without this attribute, the compiler may choose to not inline the
/// function, preventing it from optimizing out the error path.
///
/// If the assertion condition does not depend on any variables or generics, you should use
/// [`static_assert!`]. If the assertion condition does not depend on variables, but does depend on
/// generics, you should use [`const_assert!`]. See the [module documentation](self).
///
/// # Examples
///
/// ```
/// #[inline(always)] // Important.
/// fn bar(n: usize) {
/// build_assert!(n > 1);
/// }
///
/// fn foo() {
/// bar(2);
/// }
///
/// #[inline(always)] // Important.
/// const fn const_bar(n: usize) {
/// build_assert!(n > 1);
/// }
///
/// const _: () = const_bar(2);
/// ```
#[macro_export]
macro_rules! build_assert {
($cond:expr $(,)?) => {{
if !$cond {
$crate::build_assert::build_error(concat!("assertion failed: ", stringify!($cond)));
}
}};
($cond:expr, $msg:expr) => {{
if !$cond {
$crate::build_assert::build_error($msg);
}
}};
}
|