{"id":"ab8b428101acad4d","repo":"rust-lang/rust","slug":"unreachable-invalid-externabi-variant","errorCode":null,"errorMessage":"unreachable: invalid ExternAbi variant","messagePattern":"unreachable: invalid ExternAbi variant","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_abi/src/extern_abi.rs","lineNumber":159,"sourceCode":"                }\n            }\n            // FIXME(FnSigKind): when PartialEq is stably const, use it instead\n            const fn internal_const_eq(&self, other: &Self) -> bool {\n                match (self, other) {\n                    $( ( $e_name::$variant $( { unwind: $uw } )* , $e_name::$variant $( { unwind: $uw } )* ) => true,)*\n                    _ => false,\n                }\n            }\n            // ALL_VARIANTS.iter().position(|v| v == self), but const\n            pub const fn as_packed(&self) -> u8 {\n                let mut index = 0;\n                while index < $e_name::ALL_VARIANTS.len() {\n                    if self.internal_const_eq(&$e_name::ALL_VARIANTS[index]) {\n                        return index as u8;\n                    }\n                    index += 1;\n                }\n                panic!(\"unreachable: invalid ExternAbi variant\");\n            }\n            pub const fn from_packed(index: u8) -> Self {\n                let index = index as usize;\n                assert!(index < $e_name::ALL_VARIANTS.len(), \"invalid ExternAbi index\");\n                $e_name::ALL_VARIANTS[index]\n            }\n        }\n\n        impl ::core::str::FromStr for $e_name {\n            type Err = AbiFromStrErr;\n            fn from_str(s: &str) -> Result<$e_name, Self::Err> {\n                match s {\n                    $($tok => Ok($e_name::$variant $({ unwind: $uw })*),)*\n                    _ => Err(AbiFromStrErr::Unknown),\n                }\n            }\n        }\n    }","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_abi/src/extern_abi.rs#L141-L177","documentation":"`ExternAbi::as_packed` linearly scans `ALL_VARIANTS` to find the calling-ABI variant's index, and this panic is its terminal 'no match' branch. Because every variant is enumerated in `ALL_VARIANTS` by the same macro that defines `as_packed`, a real `ExternAbi` value can never fail to match — the panic is pure defensive scaffolding for memory corruption or a future variant added without updating the list.","triggerScenarios":"Calling `some_abi.as_packed()` (used to compactly serialize an ABI tag, e.g. in crate metadata or queries) on an `ExternAbi` value not present in the macro-generated `ALL_VARIANTS` list — something only possible via unsafe/transmute corruption, a partially-updated enum, or an exhaustive-match that went stale.","commonSituations":"A new ABI variant added to the enum but not to the `abi_impls!` list (or vice versa), deserializing an `as_packed` index from mismatched compiler versions, or memory/UB corruption that produced a discriminant outside the enum range (the earlier `assert!` in `from_packed` usually catches that first).","solutions":["If you added a new ABI variant, ensure it is listed in the `abi_impls! { ExternAbi = { ... } }` block so both `ALL_VARIANTS` and the matches stay in sync.","If this fires across a compiler version boundary, clear stale incremental/metadata caches and rebuild — `as_packed`/`from_packed` indices are not a stable format.","Reproduce on stock rustc; if it ICEs, file a bug with the `extern \"...\"` item and rustc commit.","Audit any unsafe code transmuting between `ExternAbi` and a numeric discriminant."],"exampleFix":"// before — new variant declared on the enum but missing from abi_impls!\n// (panics when serialized via as_packed)\n\n// after\nabi_impls! {\n    ExternAbi = {\n        // ...existing...\n        MyNewAbi =><= \"my-new-abi\",\n    }\n}","handlingStrategy":"validation","validationCode":"// ExternAbi::as_packed() panics ('unreachable: invalid ExternAbi variant')\n// if the value was not produced by a valid variant. The real risk is feeding an\n// out-of-range u8 into from_packed() and then round-tripping. Bounds-check first.\nuse rustc_abi::ExternAbi;\nfn valid_abi_packed_index(idx: u8) -> bool {\n    (idx as usize) < ExternAbi::ALL_VARIANTS.len()\n}\n// Prefer parsing a name rather than trusting a raw index:\nfn abi_from_name(name: &str) -> Option<ExternAbi> {\n    name.parse::<ExternAbi>().ok()\n}","typeGuard":"fn is_known_extern_abi(abi: &ExternAbi) -> bool {\n    // ALL_VARIANTS is the authoritative set; this is sound because ExternAbi is\n    // non-exhaustive and a future variant added upstream must still round-trip.\n    ExternAbi::ALL_VARIANTS.iter().any(|v| v.internal_const_eq(abi))\n}","tryCatchPattern":"let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| abi.as_packed()));\nmatch result {\n    Ok(packed) => { /* store the u8 */ }\n    Err(_) => {\n        // The abi value was not a member of ALL_VARIANTS (e.g. constructed via\n        // unsafe transmute). Refuse to persist it; re-resolve from a name instead.\n    }\n}","preventionTips":["Never construct ExternAbi by transmuting a u8 or by hand; obtain it via from_str / from_packed with a prior bounds check, or via ALL_VARIANTS.","If you serialize an ExternAbi, store its as_str() name and re-parse on load — that route returns Result and degrades gracefully on unknown ABIs.","Treat an out-of-range packed index as corrupt input data, not as a valid ABI; fail closed rather than indexing ALL_VARIANTS."],"tags":["rustc","abi","serialization","extern-abi","ice"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}