Skip to main content

rustc_dyn_incompatible_trait

Attribute rustc_dyn_incompatible_trait 

Source
Expand description

Opts a trait out of dyn compatibility.

This is useful to reserve the ability to add dyn incompatible supertraits or methods to a trait in the future and to ensure the soundness of various constructs - see below for more about that.

For example Field, FnPtr, Tuple, TransmuteFrom, Sized and Unsize must be dyn incompatible because these traits describe properties and layouts of types that would be invalid for trait objects.

While making a trait dyn incompatible can also be done by including a (hidden and/or unstable) dyn incompatible method in the trait, using #[rustc_dyn_incompatible_trait] should be preferred because it is self-documenting and generates better error messages.

§Example

ⓘ
//@ dont-require-annotations: ERROR
//@ compile-flags: --crate-type lib -Z ui-testing=no
#![feature(rustc_attrs)]

#[rustc_dyn_incompatible_trait]
pub trait DynIncompatible {}

pub fn f(_x: &dyn DynIncompatible) {}

produces:

error[E0038]: the trait `DynIncompatible` is not dyn compatible
--> $DIR/rustc_dyn_incompatible_trait.rs:8:15
 |
8 | pub fn f(_x: &dyn DynIncompatible) {}
 |               ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` is not dyn compatible
 |
note: for a trait to be dyn compatible it needs to allow building a vtable
     for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $DIR/rustc_dyn_incompatible_trait.rs:5:1
 |
5 | #[rustc_dyn_incompatible_trait]
 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because it opted out of dyn-compatibility
6 | pub trait DynIncompatible {}
 |           --------------- this trait is not dyn compatible...

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0038`.

§Unsafe traits and dyn (in)compatibility

Recall that a trait object (dyn Trait) implements the base trait, its auto traits, and any supertraits of the base trait. This means that it’s possible to run into subtle soundness problems when relying on the safety contract of a dyn compatible unsafe trait. See the following example:

ⓘ
//@run-fail
mod foreign_crate {
    /// # Safety requirements
    ///
    /// If this type also implements `SafeTrait`,
    /// then that implementation must always return `true`.
    pub unsafe trait UnsafeTrait {}
    unsafe impl<T: UnsafeTrait + ?Sized> UnsafeTrait for &T {}

    pub trait SafeTrait {
        fn returns_true(&self) -> bool;
    }
    impl<T: SafeTrait + ?Sized> SafeTrait for &T {
        fn returns_true(&self) -> bool {
            (*self).returns_true()
        }
    }

    impl SafeTrait for u8 {
        fn returns_true(&self) -> bool {
            true
        }
    }
    /// Safety: impl returns `true`.
    unsafe impl UnsafeTrait for u8 {}

    pub fn function(x: impl UnsafeTrait + SafeTrait) {
        // Can't panic, after all, `x: UnsafeTrait`
        // guarantees `returns_true` actually returns `true`
        assert!(x.returns_true());
    }
}

use foreign_crate::{SafeTrait, UnsafeTrait, function};

pub trait LocalTrait: UnsafeTrait {}
impl<T: UnsafeTrait> LocalTrait for T {}

// We can do this because `dyn LocalTrait` is a local type.
// But `LocalTrait: UnsafeTrait`, so `dyn LocalTrait: UnsafeTrait` holds,
// and we don't have to `unsafe impl` it.
impl SafeTrait for dyn LocalTrait {
    fn returns_true(&self) -> bool {
        false
    }
}

fn main() {
    let x = 42_u8;
    let y: &dyn LocalTrait = &x;
    function(y); // panics
}

A solution for this is to make UnsafeTrait dyn incompatible, forcing LocalTrait to also be dyn incompatible so that a dyn LocalTrait cannot be formed. This is what we ended up doing for #154619.

Allocator has had similar problems with Clone (#156920) but as we really wanted dyn Allocator to be a thing we ended up not making it dyn incompatible – we ended up moving the safety contract to AllocatorClone instead.

See also #156917 and #160045 for more examples of this problem.

See AttributeKind::RustcDynIncompatibleTrait for the internal representation of this attribute.