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
- Remove `#[derive(TypeVisitable)]` from the union (and the matching `TypeFoldable` derive, since the two are co-dependent).
- Re-model the data as an `enum` and keep the derive on the enum.
- 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
- TypeVisitable and TypeFoldable usually go together; check both before annotating a union.
- Manual impls for union-backed types must only touch the active field, documented with a SAFETY note.
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
- cannot derive on union
- cannot derive on union
- cannot derive on union
- cannot derive on union
- error parsing stable_hash
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/361b1133e656d1f7.json.
Report an issue: GitHub.