Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

An auto trait is a marker trait that the Rust compiler automatically implements for a composite type if, and only if, all of its constituent fields also implement that trait. They act as structural properties of types, propagating implicitly through type hierarchies to enforce memory and concurrency safety guarantees at compile time without requiring explicit impl blocks.

Core Characteristics

  • Implicit Propagation: The compiler recursively evaluates the fields of structs, enums, and unions. If every field implements the auto trait, the parent type automatically inherits the implementation.
  • Marker Traits Only: Auto traits cannot contain methods, associated types, or associated constants. They exist purely to provide metadata to the compiler’s type checker.
  • Opt-Out Default: Unlike standard traits which require explicit impl blocks (opt-in), auto traits are applied by default based on structural composition and must be explicitly negated (opt-out).

Standard Library Auto Traits

The Rust standard library defines several built-in auto traits, primarily located in the std::marker and std::panic modules. The compiler treats these with special intrinsic rules:
  • Send: Types whose ownership can be safely transferred across thread boundaries.
  • Sync: Types whose references (&T) are safe to share across thread boundaries.
  • Unpin: Types that can be safely moved in memory after being pinned.
  • UnwindSafe / RefUnwindSafe: Types that are safe to observe after a thread panic.

Opting Out (Stable Rust)

In stable Rust, the idiomatic way to remove an auto trait implementation from a composite type is to include a field whose type inherently lacks that auto trait. Developers typically use zero-sized marker types like std::marker::PhantomData to achieve this without affecting the struct’s memory layout or runtime behavior. For example, raw pointers (*const T and *mut T) are intrinsically !Send and !Sync. Adding a PhantomData<*const ()> field forces the compiler to strip Send and Sync from the parent type. Similarly, std::marker::PhantomPinned is used to opt out of Unpin.
use std::marker::PhantomData;

struct MyCustomType {
    data: String, // String is Send + Sync
    // Explicitly opting out of Send and Sync using a marker type
    _marker: PhantomData<*const ()>,
}

// This struct is now !Send and !Sync because it contains a !Send/!Sync field
struct CompositeType {
    inner: MyCustomType, 
}

Negative Implementations (Unstable Rust)

On the Nightly compiler, Rust provides an experimental mechanism to explicitly remove an auto trait using a negative implementation. This uses the ! syntax in the impl block (e.g., impl !Trait for Type). This directly instructs the compiler that the type does not implement the trait, bypassing the need for marker fields. Note: A negative implementation is distinct from a negative trait bound (e.g., T: !Send), which is a separate experimental feature for constraining generics.
#![feature(negative_impls)]

struct MyCustomType {
    data: String,
}

// Explicit negative implementation
impl !Send for MyCustomType {}

Manual Implementation (Opting In)

If a type loses an auto trait due to a constituent field (e.g., wrapping a raw pointer), a developer can manually implement the trait to override the compiler’s structural analysis. Because auto traits like Send and Sync are tied to fundamental memory safety, manually implementing them requires the unsafe keyword.
struct PointerWrapper {
    ptr: *mut u8, // *mut u8 is !Send
}

// Manually overriding the compiler's auto trait derivation
// The developer asserts that the internal pointer usage is thread-safe
unsafe impl Send for PointerWrapper {}

Defining Custom Auto Traits

Creating custom auto traits is an unstable feature restricted to the Nightly compiler. It requires the auto_traits feature flag, and typically the negative_impls flag to allow types to opt out. Custom auto traits are defined using the auto keyword.
#![feature(auto_traits)]
#![feature(negative_impls)]

// Defining a custom auto trait
auto trait IsValid {}

// Implicitly implemented for standard types
struct BaseType; 

// Explicitly opting out a specific type via negative implementation
struct InvalidType;
impl !IsValid for InvalidType {}

// ValidComposite is IsValid because BaseType is IsValid
struct ValidComposite {
    field: BaseType,
}

// InvalidComposite is !IsValid because InvalidType is !IsValid
struct InvalidComposite {
    field: InvalidType,
}
Master Rust with Deep Grasping Methodology!Learn More