Rollup merge of #123588 - tgross35:stabilize-assert_unchecked, r=dtolnay · model-checking/verify-rust-std@b184a84 (original) (raw)
`@@ -111,41 +111,92 @@ pub const unsafe fn unreachable_unchecked() -> ! {
`
111
111
``
112
112
`` /// Makes a soundness promise to the compiler that cond
holds.
``
113
113
`///
`
114
``
`-
/// This may allow the optimizer to simplify things,
`
115
``
`-
/// but it might also make the generated code slower.
`
116
``
`-
/// Either way, calling it will most likely make compilation take longer.
`
``
114
`+
/// This may allow the optimizer to simplify things, but it might also make the generated code
`
``
115
`+
/// slower. Either way, calling it will most likely make compilation take longer.
`
117
116
`///
`
118
``
`-
/// This is a situational tool for micro-optimization, and is allowed to do nothing.
`
119
``
`-
/// Any use should come with a repeatable benchmark to show the value
`
120
``
`-
/// and allow removing it later should the optimizer get smarter and no longer need it.
`
``
117
`+
/// You may know this from other places as
`
``
118
`` +
/// llvm.assume
or, in C,
``
``
119
`` +
/// __builtin_assume
.
``
121
120
`///
`
122
``
`-
/// The more complicated the condition the less likely this is to be fruitful.
`
123
``
`` -
/// For example, assert_unchecked(foo.is_sorted())
is a complex enough value
``
124
``
`-
/// that the compiler is unlikely to be able to take advantage of it.
`
``
121
`+
/// This promotes a correctness requirement to a soundness requirement. Don't do that without
`
``
122
`+
/// very good reason.
`
125
123
`///
`
126
``
`` -
/// There's also no need to assert_unchecked
basic properties of things. For
``
127
``
`` -
/// example, the compiler already knows the range of count_ones
, so there's no
``
128
``
`` -
/// benefit to let n = u32::count_ones(x); assert_unchecked(n <= u32::BITS);
.
``
``
124
`+
/// # Usage
`
129
125
`///
`
130
``
`` -
/// If ever you're tempted to write assert_unchecked(false)
, then you're
``
131
``
`` -
/// actually looking for [unreachable_unchecked()
].
``
``
126
`+
/// This is a situational tool for micro-optimization, and is allowed to do nothing. Any use
`
``
127
`+
/// should come with a repeatable benchmark to show the value, with the expectation to drop it
`
``
128
`+
/// later should the optimizer get smarter and no longer need it.
`
132
129
`///
`
133
``
`-
/// You may know this from other places
`
134
``
`` -
/// as llvm.assume
``
135
``
`` -
/// or __builtin_assume
.
``
``
130
`+
/// The more complicated the condition, the less likely this is to be useful. For example,
`
``
131
`` +
/// assert_unchecked(foo.is_sorted())
is a complex enough value that the compiler is unlikely
``
``
132
`+
/// to be able to take advantage of it.
`
136
133
`///
`
137
``
`-
/// This promotes a correctness requirement to a soundness requirement.
`
138
``
`-
/// Don't do that without very good reason.
`
``
134
`` +
/// There's also no need to assert_unchecked
basic properties of things. For example, the
``
``
135
`` +
/// compiler already knows the range of count_ones
, so there is no benefit to
``
``
136
`` +
/// let n = u32::count_ones(x); assert_unchecked(n <= u32::BITS);
.
``
``
137
`+
///
`
``
138
`` +
/// assert_unchecked
is logically equivalent to if !cond { unreachable_unchecked(); }
. If
``
``
139
`` +
/// ever you are tempted to write assert_unchecked(false)
, you should instead use
``
``
140
`` +
/// [unreachable_unchecked()
] directly.
``
139
141
`///
`
140
142
`/// # Safety
`
141
143
`///
`
142
``
`` -
/// cond
must be true
. It's immediate UB to call this with false
.
``
``
144
`` +
/// cond
must be true
. It is immediate UB to call this with false
.
``
``
145
`+
///
`
``
146
`+
/// # Example
`
``
147
`+
///
`
``
148
/// ```
``
149
`+
/// use core::hint;
`
143
150
`///
`
``
151
`+
/// /// # Safety
`
``
152
`+
/// ///
`
``
153
`` +
/// /// p
must be nonnull and valid
``
``
154
`+
/// pub unsafe fn next_value(p: *const i32) -> i32 {
`
``
155
`` +
/// // SAFETY: caller invariants guarantee that p
is not null
``
``
156
`+
/// unsafe { hint::assert_unchecked(!p.is_null()) }
`
``
157
`+
///
`
``
158
`+
/// if p.is_null() {
`
``
159
`+
/// return -1;
`
``
160
`+
/// } else {
`
``
161
`` +
/// // SAFETY: caller invariants guarantee that p
is valid
``
``
162
`+
/// unsafe { *p + 1 }
`
``
163
`+
/// }
`
``
164
`+
/// }
`
``
165
/// ```
``
166
`+
///
`
``
167
`` +
/// Without the assert_unchecked
, the above function produces the following with optimizations
``
``
168
`+
/// enabled:
`
``
169
`+
///
`
``
170
/// ```asm
``
171
`+
/// next_value:
`
``
172
`+
/// test rdi, rdi
`
``
173
`+
/// je .LBB0_1
`
``
174
`+
/// mov eax, dword ptr [rdi]
`
``
175
`+
/// inc eax
`
``
176
`+
/// ret
`
``
177
`+
/// .LBB0_1:
`
``
178
`+
/// mov eax, -1
`
``
179
`+
/// ret
`
``
180
/// ```
``
181
`+
///
`
``
182
`+
/// Adding the assertion allows the optimizer to remove the extra check:
`
``
183
`+
///
`
``
184
/// ```asm
``
185
`+
/// next_value:
`
``
186
`+
/// mov eax, dword ptr [rdi]
`
``
187
`+
/// inc eax
`
``
188
`+
/// ret
`
``
189
/// ```
``
190
`+
///
`
``
191
`+
/// This example is quite unlike anything that would be used in the real world: it is redundant
`
``
192
`+
/// to put an an assertion right next to code that checks the same thing, and dereferencing a
`
``
193
`+
/// pointer already has the builtin assumption that it is nonnull. However, it illustrates the
`
``
194
`+
/// kind of changes the optimizer can make even when the behavior is less obviously related.
`
``
195
`+
#[track_caller]
`
144
196
`#[inline(always)]
`
145
197
`#[doc(alias = "assume")]
`
146
``
`-
#[track_caller]
`
147
``
`-
#[unstable(feature = "hint_assert_unchecked", issue = "119131")]
`
148
``
`-
#[rustc_const_unstable(feature = "const_hint_assert_unchecked", issue = "119131")]
`
``
198
`+
#[stable(feature = "hint_assert_unchecked", since = "CURRENT_RUSTC_VERSION")]
`
``
199
`+
#[rustc_const_stable(feature = "hint_assert_unchecked", since = "CURRENT_RUSTC_VERSION")]
`
149
200
`pub const unsafe fn assert_unchecked(cond: bool) {
`
150
201
`` // SAFETY: The caller promised cond
is true.
``
151
202
`unsafe {
`