rust-lang/rust · error

cannot derive on union

Error message

cannot derive on union

What it means

`type_visitable_derive` generates a `TypeVisitable::visit_with` impl that walks every field with a visitor. Visiting a union's overlapping fields is unsound and order-dependent, so the guard at type_visitable.rs:7 panics on `syn::Data::Union` before emitting any visiting code.

Source

Thrown at compiler/rustc_macros/src/type_visitable.rs:8

use quote::quote;
use syn::parse_quote;

pub(super) fn type_visitable_derive(
    mut s: synstructure::Structure<'_>,
) -> proc_macro2::TokenStream {
    if let syn::Data::Union(_) = s.ast().data {
        panic!("cannot derive on union")
    }

    // ignore fields with #[type_visitable(ignore)]
    s.filter(|bi| {
        let mut ignored = false;

        bi.ast().attrs.iter().for_each(|attr| {
            if !attr.path().is_ident("type_visitable") {
                return;
            }
            let _ = attr.parse_nested_meta(|nested| {
                if nested.path.is_ident("ignore") {
                    ignored = true;
                }
                Ok(())
            });
        });

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Remove `#[derive(TypeVisitable)]` from the union (and the matching `TypeFoldable` derive, since the two are co-dependent).
  2. Re-model the data as an `enum` and keep the derive on the enum.
  3. Hand-write `TypeVisitable` to visit only a single explicitly-tagged active field rather than the raw union storage.

Example fix

// before
#[derive(TypeVisitable)]
union U {
    a: Ty<'tcx>,
    b: Region<'tcx>,
}

// after
#[derive(TypeVisitable)]
enum U {
    A(Ty<'tcx>),
    B(Region<'tcx>),
}
Defensive patterns

Strategy: validation

Validate before calling

// `type_visitable.rs` derive also rejects unions, for the same reason as
// [214]: visiting a union's inactive field is UB.
fn assert_not_union(item: &syn::Item) -> Result<(), String> {
    if let syn::Item::Union(u) = item {
        return Err(format!(
            "union `{}` cannot derive TypeVisitable; implement it manually",
            u.ident));
    }
    Ok(())
}

Type guard

fn type_visitable_derivable(item: &syn::Item) -> bool {
    matches!(item, syn::Item::Struct(_) | syn::Item::Enum(_))
}

Prevention

When it happens

Trigger: Annotating a `union` with `#[derive(TypeVisitable)]` (the rustc_middle trait used by visitors/traversal over types); the derive reaches the union check and panics during expansion.

Common situations: Applying the standard `#[derive(TypeVisitable, TypeFoldable)]` pair (almost always present together on rustc type-system types) to a union. Refactoring a struct into a union without pruning derives. Copying derives from a sibling type definition.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/361b1133e656d1f7.json. Report an issue: GitHub.