{"id":"a887ada273852e3e","repo":"rust-lang/rust","slug":"cannot-derive-on-union-a887ad","errorCode":null,"errorMessage":"cannot derive on union","messagePattern":"cannot derive on union","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/rustc_macros/src/type_foldable.rs","lineNumber":6,"sourceCode":"use quote::{ToTokens, quote};\nuse syn::parse_quote;\n\npub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {\n    if let syn::Data::Union(_) = s.ast().data {\n        panic!(\"cannot derive on union\")\n    }\n\n    if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == \"tcx\") {\n        s.add_impl_generic(parse_quote! { 'tcx });\n    }\n\n    s.add_bounds(synstructure::AddBounds::Generics);\n    s.bind_with(|_| synstructure::BindStyle::Move);\n    let try_body_fold = s.each_variant(|vi| {\n        let bindings = vi.bindings();\n        vi.construct(|_, index| {\n            let bind = &bindings[index];\n\n            // retain value of fields with #[type_foldable(identity)]\n            if has_ignore_attr(&bind.ast().attrs, \"type_foldable\", \"identity\") {\n                bind.to_token_stream()\n            } else {\n                quote! {","sourceCodeStart":1,"sourceCodeEnd":24,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_macros/src/type_foldable.rs#L1-L24","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n#[derive(TypeFoldable)]\nunion U {\n    a: Ty<'tcx>,\n    b: Region<'tcx>,\n}\n\n// after\n#[derive(TypeFoldable)]\nenum U {\n    A(Ty<'tcx>),\n    B(Region<'tcx>),\n}","handlingStrategy":"validation","validationCode":"// `type_foldable.rs` derive refuses unions. TypeFoldable needs to traverse\n// every field, which is undefined for a union's inactive members.\nfn assert_derive_safe(item: &syn::Item) -> Result<(), String> {\n    if let syn::Item::Union(u) = item {\n        return Err(format!(\n            \"union `{}` cannot derive TypeFoldable; provide a manual impl \\\n             that folds the active field\", u.ident));\n    }\n    Ok(())\n}","typeGuard":"fn type_foldable_derivable(item: &syn::Item) -> bool {\n    matches!(item, syn::Item::Struct(_) | syn::Item::Enum(_))\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["rustc-macros","derive","type-foldable","union"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}