Rollup merge of #141471 - RalfJung:unsafe-fn-in-trait, r=traviscross
unsafe keyword docs: emphasize that an unsafe fn in a trait does not get to choose its safety contract Inspired by discussion in https://github.com/rust-lang/rust/issues/139368. Cc `@hanna-kruppe`
This commit is contained in:
commit
15d9b9619c
1 changed files with 11 additions and 16 deletions
|
|
@ -1916,10 +1916,6 @@ mod type_keyword {}
|
|||
/// - and to declare that a programmer has checked that these contracts have been upheld (`unsafe
|
||||
/// {}` and `unsafe impl`, but also `unsafe fn` -- see below).
|
||||
///
|
||||
/// They are not mutually exclusive, as can be seen in `unsafe fn`: the body of an `unsafe fn` is,
|
||||
/// by default, treated like an unsafe block. The `unsafe_op_in_unsafe_fn` lint can be enabled to
|
||||
/// change that.
|
||||
///
|
||||
/// # Unsafe abilities
|
||||
///
|
||||
/// **No matter what, Safe Rust can't cause Undefined Behavior**. This is
|
||||
|
|
@ -1961,13 +1957,6 @@ mod type_keyword {}
|
|||
/// - `unsafe impl`: the contract necessary to implement the trait has been
|
||||
/// checked by the programmer and is guaranteed to be respected.
|
||||
///
|
||||
/// By default, `unsafe fn` also acts like an `unsafe {}` block
|
||||
/// around the code inside the function. This means it is not just a signal to
|
||||
/// the caller, but also promises that the preconditions for the operations
|
||||
/// inside the function are upheld. Mixing these two meanings can be confusing, so the
|
||||
/// `unsafe_op_in_unsafe_fn` lint can be enabled to warn against that and require explicit unsafe
|
||||
/// blocks even inside `unsafe fn`.
|
||||
///
|
||||
/// See the [Rustonomicon] and the [Reference] for more information.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -2109,6 +2098,7 @@ mod type_keyword {}
|
|||
/// impl Indexable for i32 {
|
||||
/// const LEN: usize = 1;
|
||||
///
|
||||
/// /// See `Indexable` for the safety contract.
|
||||
/// unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
|
||||
/// debug_assert_eq!(idx, 0);
|
||||
/// *self
|
||||
|
|
@ -2120,6 +2110,7 @@ mod type_keyword {}
|
|||
/// impl Indexable for [i32; 42] {
|
||||
/// const LEN: usize = 42;
|
||||
///
|
||||
/// /// See `Indexable` for the safety contract.
|
||||
/// unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
|
||||
/// // SAFETY: As per this trait's documentation, the caller ensures
|
||||
/// // that `idx < 42`.
|
||||
|
|
@ -2132,6 +2123,7 @@ mod type_keyword {}
|
|||
/// impl Indexable for ! {
|
||||
/// const LEN: usize = 0;
|
||||
///
|
||||
/// /// See `Indexable` for the safety contract.
|
||||
/// unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
|
||||
/// // SAFETY: As per this trait's documentation, the caller ensures
|
||||
/// // that `idx < 0`, which is impossible, so this is dead code.
|
||||
|
|
@ -2153,11 +2145,14 @@ mod type_keyword {}
|
|||
/// contract of `idx_unchecked`. Implementing `Indexable` is safe because when writing
|
||||
/// `idx_unchecked`, we don't have to worry: our *callers* need to discharge a proof obligation
|
||||
/// (like `use_indexable` does), but the *implementation* of `get_unchecked` has no proof obligation
|
||||
/// to contend with. Of course, the implementation of `Indexable` may choose to call other unsafe
|
||||
/// operations, and then it needs an `unsafe` *block* to indicate it discharged the proof
|
||||
/// obligations of its callees. (We enabled `unsafe_op_in_unsafe_fn`, so the body of `idx_unchecked`
|
||||
/// is not implicitly an unsafe block.) For that purpose it can make use of the contract that all
|
||||
/// its callers must uphold -- the fact that `idx < LEN`.
|
||||
/// to contend with. Of course, the implementation may choose to call other unsafe operations, and
|
||||
/// then it needs an `unsafe` *block* to indicate it discharged the proof obligations of its
|
||||
/// callees. For that purpose it can make use of the contract that all its callers must uphold --
|
||||
/// the fact that `idx < LEN`.
|
||||
///
|
||||
/// Note that unlike normal `unsafe fn`, an `unsafe fn` in a trait implementation does not get to
|
||||
/// just pick an arbitrary safety contract! It *has* to use the safety contract defined by the trait
|
||||
/// (or one with weaker preconditions).
|
||||
///
|
||||
/// Formally speaking, an `unsafe fn` in a trait is a function with *preconditions* that go beyond
|
||||
/// those encoded by the argument types (such as `idx < LEN`), whereas an `unsafe trait` can declare
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue