rust-lang/rust · error
cannot derive on union
Error message
cannot derive on union
What it means
`type_foldable_derive` generates `TypeFoldable`/`try_fold_with`/`fold_with` impls by reconstructing each variant with folded fields. A union has overlapping fields and no constructor that selects one, so there is no way to produce a folded copy; the guard at type_foldable.rs:5 panics on `syn::Data::Union` before generating any folding code.
Source
Thrown at compiler/rustc_macros/src/type_foldable.rs:6
use quote::{ToTokens, quote};
use syn::parse_quote;
pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
if let syn::Data::Union(_) = s.ast().data {
panic!("cannot derive on union")
}
if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
s.add_impl_generic(parse_quote! { 'tcx });
}
s.add_bounds(synstructure::AddBounds::Generics);
s.bind_with(|_| synstructure::BindStyle::Move);
let try_body_fold = s.each_variant(|vi| {
let bindings = vi.bindings();
vi.construct(|_, index| {
let bind = &bindings[index];
// retain value of fields with #[type_foldable(identity)]
if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
bind.to_token_stream()
} else {
quote! {View on GitHub (pinned to 22057b88b0)
Solutions
- Remove `#[derive(TypeFoldable)]` from the union.
- Convert the union into an `enum` so each alternative is a constructible variant, then keep the derive.
- If folding is genuinely required, implement `TypeFoldable` manually by tracking the active field via an external tag and folding only that field.
Example fix
// before
#[derive(TypeFoldable)]
union U {
a: Ty<'tcx>,
b: Region<'tcx>,
}
// after
#[derive(TypeFoldable)]
enum U {
A(Ty<'tcx>),
B(Region<'tcx>),
} Defensive patterns
Strategy: validation
Validate before calling
// `type_foldable.rs` derive refuses unions. TypeFoldable needs to traverse
// every field, which is undefined for a union's inactive members.
fn assert_derive_safe(item: &syn::Item) -> Result<(), String> {
if let syn::Item::Union(u) = item {
return Err(format!(
"union `{}` cannot derive TypeFoldable; provide a manual impl \
that folds the active field", u.ident));
}
Ok(())
} Type guard
fn type_foldable_derivable(item: &syn::Item) -> bool {
matches!(item, syn::Item::Struct(_) | syn::Item::Enum(_))
} Prevention
- Never apply #[derive(TypeFoldable)] to a union.
- If a type containing a union needs TypeFoldable, derive on an outer struct and manually impl for the union field.
- Keep a CI check that flags TypeFoldable + union co-occurrence.
When it happens
Trigger: Annotating a `union` with `#[derive(TypeFoldable)]` (the rustc_middle trait used to rewrite/fold types and regions during queries); macro expansion matches the union arm and panics.
Common situations: Adding `#[derive(TypeFoldable, TypeVisitable)]` boilerplate (common on rustc_middle `Ty`/`Region` types) to a union by accident during a refactor. Changing a struct used inside the type system into a union. Bulk-applying a derive template to many types including a union.
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/a887ada273852e3e.json.
Report an issue: GitHub.