{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreif3gugoezvprf4qlqlhwpxbpmmdppz3eahbmd64ejjuz4ddy3hqwu",
    "uri": "at://did:plc:ivbknywyskln22er3nkssdhl/app.bsky.feed.post/3mmtx7r6ko4q2"
  },
  "path": "/t/pre-rfc-unsafe-traits-conditionally-depending-on-safe-trait-behaviour/24360#post_1",
  "publishedAt": "2026-05-27T15:52:29.000Z",
  "site": "https://internals.rust-lang.org",
  "tags": [
    "`dyn Allocator` together with `Allocator + Clone` requirements is unsound, leading to UB with `Arc` · Issue #156920 · rust-lang/rust · GitHub"
  ],
  "textContent": "It is currently impossible for a `dyn`-compatible `unsafe trait A` to be able to express the semantics of \"if `T: A + B` (where `B` is a safe trait), the `B` implementation must behave a certain way\". Safe code can maliciously `impl B for dyn C` with a locally-definded `trait C: A`, so requiring this in the unsafe preconditions of `A` is insufficient. This came up when we were looking to stabilise a dyn-compatible `Allocator`, notably: `dyn Allocator` together with `Allocator + Clone` requirements is unsound, leading to UB with `Arc` · Issue #156920 · rust-lang/rust · GitHub.\n\nNotably, breaking `dyn` compatiblity only makes `Allocator` sound in that implementors can rely on the orphan rule to reason about which impls may exist downstream; the underlying semantics of a sometimes-implemented safe trait affecting the correctness of an unsafe trait are currently inexpressible. The closest we could do would be making `unsafe trait A: B`, so always implemented.\n\nUpon getting a vibe-check from libs(-api), lang, and a couple of people on types, this seems feasible. The proposed idea is approximately:\n\n\n    // -- in core --\n\n    #[unsafe(has_preconditions(Allocator))]\n    trait Clone {}\n\n    unsafe trait Allocator {}\n\n    #[unsafe(satisfies_preconditions(Allocator))] // this is new\n    impl<T: Clone> Clone for Box<T> {}\n\n    unsafe impl<A: Allocator> Allocator for Box<A> {}\n\n    // -- in downstream --\n\n    struct Foo;\n    // all good\n    impl Clone for Foo {}\n\n    struct Bar;\n    #[unsafe(satisfies_preconditions(Allocator))] // if we don't write this, error\n    impl Clone for Bar {}\n    unsafe impl Allocator for Bar {}\n\n\nwith the only bit of orphan-rule reasoning _here_ being for implementability, not soundness: someone can't write a blanket `impl Clone` that breaks their downstream dependents, and if they somehow did it anyway said dependent would get a compiler error.\n\nThe one part of this we'd need to have on stable is the `unsafe(satisfies_preconditions(_))` attribute. In fairness, we could ditch that as well and make it so it's just _impossible_ to (stably) `impl Clone` on allocators, but that would be sad. The rest (e.g. the way we mark a safe trait as conditionally-unsafe-relevant) could be delegated to later syntax bikeshedding.",
  "title": "Pre-RFC: Unsafe traits conditionally depending on safe trait behaviour"
}