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:
Guillaume Gomez 2025-06-06 23:53:16 +02:00 committed by GitHub
commit 15d9b9619c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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