@@ -111,41 +111,92 @@ pub const unsafe fn unreachable_unchecked() -> ! {
111111
112112/// Makes a *soundness* promise to the compiler that `cond` holds.
113113///
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.
117116///
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`](https://llvm.org/docs/LangRef.html#llvm-assume-intrinsic) or, in C,
119+ /// [`__builtin_assume`](https://clang.llvm.org/docs/LanguageExtensions.html#builtin-assume) .
121120///
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.
125123///
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
129125///
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.
132129///
133- /// You may know this from other places
134- /// as [`llvm.assume`](https://llvm.org/docs/LangRef.html#llvm-assume-intrinsic)
135- /// or [`__builtin_assume`](https://clang.llvm.org/docs/LanguageExtensions.html#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 .
136133///
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.
139141///
140142/// # Safety
141143///
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;
143150///
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]
144196#[ inline( always) ]
145197#[ 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" ) ]
149200pub const unsafe fn assert_unchecked ( cond : bool ) {
150201 // SAFETY: The caller promised `cond` is true.
151202 unsafe {
0 commit comments