@@ -1867,11 +1867,15 @@ mod type_keyword {}
1867
1867
/// Code or interfaces whose [memory safety] cannot be verified by the type
1868
1868
/// system.
1869
1869
///
1870
- /// The `unsafe` keyword has two uses: to declare the existence of contracts the
1871
- /// compiler can't check (`unsafe fn` and `unsafe trait`), and to declare that a
1872
- /// programmer has checked that these contracts have been upheld (`unsafe {}`
1873
- /// and `unsafe impl`, but also `unsafe fn` -- see below). They are not mutually
1874
- /// exclusive, as can be seen in `unsafe fn`.
1870
+ /// The `unsafe` keyword has two uses:
1871
+ /// - to declare the existence of contracts the compiler can't check (`unsafe fn` and `unsafe
1872
+ /// trait`),
1873
+ /// - and to declare that a programmer has checked that these contracts have been upheld (`unsafe
1874
+ /// {}` and `unsafe impl`, but also `unsafe fn` -- see below).
1875
+ ///
1876
+ /// They are not mutually exclusive, as can be seen in `unsafe fn`: the body of an `unsafe fn` is,
1877
+ /// by default, treated like an unsafe block. The `unsafe_op_in_unsafe_fn` lint can be enabled to
1878
+ /// change that.
1875
1879
///
1876
1880
/// # Unsafe abilities
1877
1881
///
@@ -1914,12 +1918,12 @@ mod type_keyword {}
1914
1918
/// - `unsafe impl`: the contract necessary to implement the trait has been
1915
1919
/// checked by the programmer and is guaranteed to be respected.
1916
1920
///
1917
- /// `unsafe fn` also acts like an `unsafe {}` block
1921
+ /// By default, `unsafe fn` also acts like an `unsafe {}` block
1918
1922
/// around the code inside the function. This means it is not just a signal to
1919
1923
/// the caller, but also promises that the preconditions for the operations
1920
- /// inside the function are upheld. Mixing these two meanings can be confusing
1921
- /// and [proposal]s exist to use `unsafe {}` blocks inside such functions when
1922
- /// making `unsafe` operations .
1924
+ /// inside the function are upheld. Mixing these two meanings can be confusing, so the
1925
+ /// `unsafe_op_in_unsafe_fn` lint can be enabled to warn against that and require explicit unsafe
1926
+ /// blocks even inside `unsafe fn` .
1923
1927
///
1924
1928
/// See the [Rustnomicon] and the [Reference] for more information.
1925
1929
///
@@ -1987,13 +1991,16 @@ mod type_keyword {}
1987
1991
///
1988
1992
/// ```rust
1989
1993
/// # #![allow(dead_code)]
1994
+ /// #![deny(unsafe_op_in_unsafe_fn)]
1995
+ ///
1990
1996
/// /// Dereference the given pointer.
1991
1997
/// ///
1992
1998
/// /// # Safety
1993
1999
/// ///
1994
2000
/// /// `ptr` must be aligned and must not be dangling.
1995
2001
/// unsafe fn deref_unchecked(ptr: *const i32) -> i32 {
1996
- /// *ptr
2002
+ /// // SAFETY: the caller is required to ensure that `ptr` is aligned and dereferenceable.
2003
+ /// unsafe { *ptr }
1997
2004
/// }
1998
2005
///
1999
2006
/// let a = 3;
@@ -2003,35 +2010,118 @@ mod type_keyword {}
2003
2010
/// unsafe { assert_eq!(*b, deref_unchecked(b)); };
2004
2011
/// ```
2005
2012
///
2006
- /// Traits marked as `unsafe` must be [`impl`]emented using `unsafe impl`. This
2007
- /// makes a guarantee to other `unsafe` code that the implementation satisfies
2008
- /// the trait's safety contract. The [Send] and [Sync] traits are examples of
2009
- /// this behaviour in the standard library.
2013
+ /// ## `unsafe` and traits
2014
+ ///
2015
+ /// The interactions of `unsafe` and traits can be surprising, so let us contrast the
2016
+ /// two combinations of safe `fn` in `unsafe trait` and `unsafe fn` in safe trait using two
2017
+ /// examples:
2018
+ ///
2019
+ /// ```rust
2020
+ /// /// # Safety
2021
+ /// ///
2022
+ /// /// `make_even` must return an even number.
2023
+ /// unsafe trait MakeEven {
2024
+ /// fn make_even(&self) -> i32;
2025
+ /// }
2026
+ ///
2027
+ /// // SAFETY: Our `make_even` always returns something even.
2028
+ /// unsafe impl MakeEven for i32 {
2029
+ /// fn make_even(&self) -> i32 {
2030
+ /// self << 1
2031
+ /// }
2032
+ /// }
2033
+ ///
2034
+ /// fn use_make_even(x: impl MakeEven) {
2035
+ /// if x.make_even() % 2 == 1 {
2036
+ /// // SAFETY: this can never happen, because all `MakeEven` implementations
2037
+ /// // ensure that `make_even` returns something even.
2038
+ /// unsafe { std::hint::unreachable_unchecked() };
2039
+ /// }
2040
+ /// }
2041
+ /// ```
2042
+ ///
2043
+ /// Note how the safety contract of the trait is upheld by the implementation, and is itself used to
2044
+ /// uphold the safety contract of the unsafe function `unreachable_unchecked` called by
2045
+ /// `use_make_even`. `make_even` itself is a safe function because its *callers* do not have to
2046
+ /// worry about any contract, only the *implementation* of `MakeEven` is required to uphold a
2047
+ /// certain contract. `use_make_even` is safe because it can use the promise made by `MakeEven`
2048
+ /// implementations to uphold the safety contract of the `unsafe fn unreachable_unchecked` it calls.
2049
+ ///
2050
+ /// It is also possible to have `unsafe fn` in a regular safe `trait`:
2010
2051
///
2011
2052
/// ```rust
2012
- /// /// Implementors of this trait must guarantee an element is always
2013
- /// /// accessible with index 3.
2014
- /// unsafe trait ThreeIndexable<T> {
2015
- /// /// Returns a reference to the element with index 3 in `&self`.
2016
- /// fn three(&self) -> &T;
2053
+ /// # #![feature(never_type)]
2054
+ /// #![deny(unsafe_op_in_unsafe_fn)]
2055
+ ///
2056
+ /// trait Indexable {
2057
+ /// const LEN: usize;
2058
+ ///
2059
+ /// /// # Safety
2060
+ /// ///
2061
+ /// /// The caller must ensure that `idx < LEN`.
2062
+ /// unsafe fn idx_unchecked(&self, idx: usize) -> i32;
2017
2063
/// }
2018
2064
///
2019
- /// // The implementation of `ThreeIndexable` for `[T; 4]` is `unsafe`
2020
- /// // because the implementor must abide by a contract the compiler cannot
2021
- /// // check but as a programmer we know there will always be a valid element
2022
- /// // at index 3 to access.
2023
- /// unsafe impl<T> ThreeIndexable<T> for [T; 4] {
2024
- /// fn three(&self) -> &T {
2025
- /// // SAFETY: implementing the trait means there always is an element
2026
- /// // with index 3 accessible.
2027
- /// unsafe { self.get_unchecked(3) }
2065
+ /// // The implementation for `i32` doesn't need to do any contract reasoning.
2066
+ /// impl Indexable for i32 {
2067
+ /// const LEN: usize = 1;
2068
+ ///
2069
+ /// unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
2070
+ /// debug_assert_eq!(idx, 0);
2071
+ /// *self
2028
2072
/// }
2029
2073
/// }
2030
2074
///
2031
- /// let a = [1, 2, 4, 8];
2032
- /// assert_eq!(a.three(), &8);
2075
+ /// // The implementation for arrays exploits the function contract to
2076
+ /// // make use of `get_unchecked` on slices and avoid a run-time check.
2077
+ /// impl Indexable for [i32; 42] {
2078
+ /// const LEN: usize = 42;
2079
+ ///
2080
+ /// unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
2081
+ /// // SAFETY: As per this trait's documentation, the caller ensures
2082
+ /// // that `idx < 42`.
2083
+ /// unsafe { *self.get_unchecked(idx) }
2084
+ /// }
2085
+ /// }
2086
+ ///
2087
+ /// // The implementation for the never type declares a length of 0,
2088
+ /// // which means `idx_unchecked` can never be called.
2089
+ /// impl Indexable for ! {
2090
+ /// const LEN: usize = 0;
2091
+ ///
2092
+ /// unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
2093
+ /// // SAFETY: As per this trait's documentation, the caller ensures
2094
+ /// // that `idx < 0`, which is impossible, so this is dead code.
2095
+ /// unsafe { std::hint::unreachable_unchecked() }
2096
+ /// }
2097
+ /// }
2098
+ ///
2099
+ /// fn use_indexable<I: Indexable>(x: I, idx: usize) -> i32 {
2100
+ /// if idx < I::LEN {
2101
+ /// // SAFETY: We have checked that `idx < I::LEN`.
2102
+ /// unsafe { x.idx_unchecked(idx) }
2103
+ /// } else {
2104
+ /// panic!("index out-of-bounds")
2105
+ /// }
2106
+ /// }
2033
2107
/// ```
2034
2108
///
2109
+ /// This time, `use_indexable` is safe because it uses a run-time check to discharge the safety
2110
+ /// contract of `idx_unchecked`. Implementing `Indexable` is safe because when writing
2111
+ /// `idx_unchecked`, we don't have to worry: our *callers* need to discharge a proof obligation
2112
+ /// (like `use_indexable` does), but the *implementation* of `get_unchecked` has no proof obligation
2113
+ /// to contend with. Of course, the implementation of `Indexable` may choose to call other unsafe
2114
+ /// operations, and then it needs an `unsafe` *block* to indicate it discharged the proof
2115
+ /// obligations of its callees. (We enabled `unsafe_op_in_unsafe_fn`, so the body of `idx_unchecked`
2116
+ /// is not implicitly an unsafe block.) For that purpose it can make use of the contract that all
2117
+ /// its callers must uphold -- the fact that `idx < LEN`.
2118
+ ///
2119
+ /// Formally speaking, an `unsafe fn` in a trait is a function with *preconditions* that go beyond
2120
+ /// those encoded by the argument types (such as `idx < LEN`), whereas an `unsafe trait` can declare
2121
+ /// that some of its functions have *postconditions* that go beyond those encoded in the return type
2122
+ /// (such as returning an even integer). If a trait needs a function with both extra precondition
2123
+ /// and extra postcondition, then it needs an `unsafe fn` in an `unsafe trait`.
2124
+ ///
2035
2125
/// [`extern`]: keyword.extern.html
2036
2126
/// [`trait`]: keyword.trait.html
2037
2127
/// [`static`]: keyword.static.html
@@ -2043,7 +2133,6 @@ mod type_keyword {}
2043
2133
/// [nomicon-soundness]: ../nomicon/safe-unsafe-meaning.html
2044
2134
/// [soundness]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library
2045
2135
/// [Reference]: ../reference/unsafety.html
2046
- /// [proposal]: https://github.com/rust-lang/rfcs/pull/2585
2047
2136
/// [discussion on Rust Internals]: https://internals.rust-lang.org/t/what-does-unsafe-mean/6696
2048
2137
mod unsafe_keyword { }
2049
2138
0 commit comments