Skip to content

Commit 55e1775

Browse files
committed
Update documentation for assert_unchecked
1 parent af25253 commit 55e1775

File tree

1 file changed

+53
-6
lines changed

1 file changed

+53
-6
lines changed

library/core/src/hint.rs

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,8 @@ 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
///
118117
/// This is a situational tool for micro-optimization, and is allowed to do nothing.
119118
/// Any use should come with a repeatable benchmark to show the value
@@ -130,9 +129,9 @@ pub const unsafe fn unreachable_unchecked() -> ! {
130129
/// If ever you're tempted to write `assert_unchecked(false)`, then you're
131130
/// actually looking for [`unreachable_unchecked()`].
132131
///
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).
132+
/// You may know this from other places as
133+
/// [`llvm.assume`](https://llvm.org/docs/LangRef.html#llvm-assume-intrinsic) or, in C,
134+
/// [`__builtin_assume`](https://clang.llvm.org/docs/LanguageExtensions.html#builtin-assume).
136135
///
137136
/// This promotes a correctness requirement to a soundness requirement.
138137
/// Don't do that without very good reason.
@@ -141,6 +140,54 @@ pub const unsafe fn unreachable_unchecked() -> ! {
141140
///
142141
/// `cond` must be `true`. It's immediate UB to call this with `false`.
143142
///
143+
/// # Example
144+
///
145+
/// ```
146+
/// use core::hint;
147+
///
148+
/// /// # Safety
149+
/// ///
150+
/// /// `p` must be nonnull and valid
151+
/// pub unsafe fn next_value(p: *const i32) -> i32 {
152+
/// // SAFETY: caller invariants guarantee that `p` is not null
153+
/// unsafe { hint::assert_unchecked(!p.is_null()) }
154+
///
155+
/// if p.is_null() {
156+
/// return -1;
157+
/// } else {
158+
/// // SAFETY: caller invariants guarantee that `p` is valid
159+
/// unsafe { *p + 1 }
160+
/// }
161+
/// }
162+
/// ```
163+
///
164+
/// Without the `assert_unchecked`, the above function produces the following with optimizations:
165+
///
166+
/// ```asm
167+
/// next_value:
168+
/// test rdi, rdi
169+
/// je .LBB0_1
170+
/// mov eax, dword ptr [rdi]
171+
/// inc eax
172+
/// ret
173+
/// .LBB0_1:
174+
/// mov eax, -1
175+
/// ret
176+
/// ```
177+
///
178+
/// Adding the assertion allows the optimizer to remove the extra check:
179+
///
180+
/// ```asm
181+
/// next_value:
182+
/// mov eax, dword ptr [rdi]
183+
/// inc eax
184+
/// ret
185+
/// ```
186+
///
187+
/// This example is quite unlike anything that would happen in the real world: it is redundant to
188+
/// put an an assertion right next to code that checks the same thing, and dereferencing a
189+
/// pointer already has the builtin assumption that it is nonnull. The optimizer can make use of
190+
/// this information even when it isn't obvious, such as when checks happen in called functions.
144191
#[inline(always)]
145192
#[doc(alias = "assume")]
146193
#[track_caller]

0 commit comments

Comments
 (0)