@@ -310,13 +310,17 @@ pub fn spin_loop() {
310310/// behavior in the calling code. This property makes `black_box` useful for writing code in which 
311311/// certain optimizations are not desired, such as benchmarks. 
312312/// 
313+ /// <div class="warning"> 
314+ /// 
313315/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The 
314316/// extent to which it can block optimisations may vary depending upon the platform and code-gen 
315317/// backend used. Programs cannot rely on `black_box` for *correctness*, beyond it behaving as the 
316318/// identity function. As such, it **must not be relied upon to control critical program behavior.** 
317319/// This also means that this function does not offer any guarantees for cryptographic or security 
318320/// purposes. 
319321/// 
322+ /// </div> 
323+ /// 
320324/// [`std::convert::identity`]: crate::convert::identity 
321325/// 
322326/// # When is this useful? 
@@ -357,7 +361,7 @@ pub fn spin_loop() {
357361/// ``` 
358362/// use std::hint::black_box; 
359363/// 
360- /// // Same `contains` function 
364+ /// // Same `contains` function.  
361365/// fn contains(haystack: &[&str], needle: &str) -> bool { 
362366///     haystack.iter().any(|x| x == &needle) 
363367/// } 
@@ -366,8 +370,13 @@ pub fn spin_loop() {
366370///     let haystack = vec!["abc", "def", "ghi", "jkl", "mno"]; 
367371///     let needle = "ghi"; 
368372///     for _ in 0..10 { 
369- ///         // Adjust our benchmark loop contents 
370- ///         black_box(contains(black_box(&haystack), black_box(needle))); 
373+ ///         // Force the compiler to run `contains`, even though it is a pure function whose 
374+ ///         // results are unused. 
375+ ///         black_box(contains( 
376+ ///             // Prevent the compiler from making assumptions about the input. 
377+ ///             black_box(&haystack), 
378+ ///             black_box(needle), 
379+ ///         )); 
371380///     } 
372381/// } 
373382/// ``` 
@@ -382,6 +391,83 @@ pub fn spin_loop() {
382391/// 
383392/// This makes our benchmark much more realistic to how the function would actually be used, where 
384393/// arguments are usually not known at compile time and the result is used in some way. 
394+ /// 
395+ /// # How to use this 
396+ /// 
397+ /// In practice, `black_box` serves two purposes: 
398+ /// 
399+ /// 1. It prevents the compiler from making optimizations related to the value returned by `black_box` 
400+ /// 2. It forces the value passed to `black_box` to be calculated, even if the return value of `black_box` is unused 
401+ /// 
402+ /// ``` 
403+ /// use std::hint::black_box; 
404+ /// 
405+ /// let zero = 0; 
406+ /// let five = 5; 
407+ /// 
408+ /// // The compiler will see this and remove the `* five` call, because it knows that multiplying 
409+ /// // any integer by 0 will result in 0. 
410+ /// let c = zero * five; 
411+ /// 
412+ /// // Adding `black_box` here disables the compiler's ability to reason about the first operand in the multiplication. 
413+ /// // It is forced to assume that it can be any possible number, so it cannot remove the `* five` 
414+ /// // operation. 
415+ /// let c = black_box(zero) * five; 
416+ /// ``` 
417+ /// 
418+ /// While most cases will not be as clear-cut as the above example, it still illustrates how 
419+ /// `black_box` can be used. When benchmarking a function, you usually want to wrap its inputs in 
420+ /// `black_box` so the compiler cannot make optimizations that would be unrealistic in real-life 
421+ /// use. 
422+ /// 
423+ /// ``` 
424+ /// use std::hint::black_box; 
425+ /// 
426+ /// // This is a simple function that increments its input by 1. Note that it is pure, meaning it 
427+ /// // has no side-effects. This function has no effect if its result is unused. (An example of a 
428+ /// // function *with* side-effects is `println!()`.) 
429+ /// fn increment(x: u8) -> u8 { 
430+ ///     x + 1 
431+ /// } 
432+ /// 
433+ /// // Here, we call `increment` but discard its result. The compiler, seeing this and knowing that 
434+ /// // `increment` is pure, will eliminate this function call entirely. This may not be desired, 
435+ /// // though, especially if we're trying to track how much time `increment` takes to execute. 
436+ /// let _ = increment(black_box(5)); 
437+ /// 
438+ /// // Here, we force `increment` to be executed. This is because the compiler treats `black_box` 
439+ /// // as if it has side-effects, and thus must compute its input. 
440+ /// let _ = black_box(increment(black_box(5))); 
441+ /// ``` 
442+ /// 
443+ /// There may be additional situations where you want to wrap the result of a function in 
444+ /// `black_box` to force its execution. This is situational though, and may not have any effect 
445+ /// (such as when the function returns a zero-sized type such as [`()` unit][unit]). 
446+ /// 
447+ /// Note that `black_box` has no effect on how its input is treated, only its output. As such, 
448+ /// expressions passed to `black_box` may still be optimized: 
449+ /// 
450+ /// ``` 
451+ /// use std::hint::black_box; 
452+ /// 
453+ /// // The compiler sees this... 
454+ /// let y = black_box(5 * 10); 
455+ /// 
456+ /// // ...as this. As such, it will likely simplify `5 * 10` to just `50`. 
457+ /// let _0 = 5 * 10; 
458+ /// let y = black_box(_0); 
459+ /// ``` 
460+ /// 
461+ /// In the above example, the `5 * 10` expression is considered distinct from the `black_box` call, 
462+ /// and thus is still optimized by the compiler. You can prevent this by moving the multiplication 
463+ /// operation outside of `black_box`: 
464+ /// 
465+ /// ``` 
466+ /// use std::hint::black_box; 
467+ /// 
468+ /// // No assumptions can be made about either operand, so the multiplication is not optimized out. 
469+ /// let y = black_box(5) * black_box(10); 
470+ /// ``` 
385471#[ inline]  
386472#[ stable( feature = "bench_black_box" ,  since = "1.66.0" ) ]  
387473#[ rustc_const_unstable( feature = "const_black_box" ,  issue = "none" ) ]  
0 commit comments