R
RUSTY YELLOW PAGES

#[automatically_derived]Attribute


Explanation

#[automatically_derived] is an attribute the compiler inserts for you on every impl block generated by #[derive(...)] — you almost never type it yourself. Its only purpose is to mark that impl block as machine-generated rather than hand-written, so that lints and other tooling can tell the two apart.

You can see it by expanding a derive with cargo expand: a struct carrying #[derive(Debug)] expands to an ordinary impl Debug for ... block, but with #[automatically_derived] silently attached above it — code you never wrote and don't normally look at, unless you're inspecting expanded macro output directly.

The practical effect is on lints, not on runtime behavior — the attribute has no effect on how the impl works, only on how tools treat it. Some Clippy lints deliberately skip or soften their check inside #[automatically_derived] blocks, on the reasoning that flagging a pattern the compiler itself generated (rather than one a human typed) is rarely actionable — there's no line of your own code to go fix. This is also why the attribute is legal to write by hand: a third-party #[proc_macro_derive] that wants its generated impls to be treated the same way the compiler's own derives are (by Clippy and similar tools) can emit #[automatically_derived] on its own generated code too.

Usage examples

Recognizing the compiler-generated attribute in expanded output

#[derive(Debug)] // <- the compiler attaches #[automatically_derived] to the impl this generates
struct Point { x: f64, y: f64 }

// roughly what `cargo expand` shows was generated (never written by hand):
// #[automatically_derived]
// impl std::fmt::Debug for Point { ... }

Designing a public API

A crate that ships its own #[proc_macro_derive], mimicking the compiler's built-in derives, should tag its own generated impl blocks with #[automatically_derived] too — matching the convention lets downstream lints treat the custom derive's output the same way they treat Debug/Clone/PartialEq.

// inside a #[proc_macro_derive(Describe)] function's generated output:
let expanded = quote::quote! {
    #[automatically_derived] // <- marks this impl as generated, matching the compiler's own derives
    impl Describe for #name {
        fn describe() -> &'static str {
            stringify!(#name)
        }
    }
};

Without the attribute, a lint has no way to distinguish a custom derive's generated code from something a human typed by hand, and may flag it with suggestions that don't apply to generated code — emitting #[automatically_derived] is how a third-party derive macro opts into the same tooling treatment the compiler's built-in derives already get.

Explanation

Embedded support: Full

#[automatically_derived] is a compiler-inserted, compile-time-only marker with no representation in the compiled artifact — it carries over unchanged in #![no_std] builds, appearing above every impl block the compiler generates from a #[derive(...)], whether that derive is one of the built-ins (Debug, Clone, ...) or a no_std-oriented third-party one like defmt's #[derive(Format)]. There's no embedded-specific behavior beyond that: it costs no flash or RAM, and lints treat it the same way regardless of target.

Usage examples

Recognizing it above a defmt-generated impl

#[derive(defmt::Format)] // <- defmt's own proc-macro derive attaches #[automatically_derived] here too
pub struct SensorReading {
    raw_adc: u16,
}

// roughly what expands (never written by hand):
// #[automatically_derived]
// impl defmt::Format for SensorReading { ... }

Marking a register-access crate's own derive output the same way

// inside a #[proc_macro_derive(RegisterField)] function's generated output for a no_std register-access crate:
let expanded = quote::quote! {
    #[automatically_derived] // <- marks this impl as generated, the same convention the compiler's own derives use
    impl RegisterField for #name {
        const OFFSET: u8 = #offset;
    }
};