Skip to content

unsafe keyword docs: emphasize that an unsafe fn in a trait does not get to choose its safety contract #141471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 7, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 11 additions & 16 deletions library/std/src/keyword_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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`.
Expand All @@ -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.
Expand All @@ -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
Expand Down
Loading