{"id":"da0a44605fdf0f58","repo":"rust-lang/rust","slug":"op-is-not-a-register-operand","errorCode":null,"errorMessage":"{op:?} is not a register operand","messagePattern":"(.+?) is not a register operand","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_ast_lowering/src/asm.rs","lineNumber":361,"sourceCode":"                    continue;\n                }\n\n                // Check for conflicts between explicit register operands.\n                if let asm::InlineAsmRegOrRegClass::Reg(reg) = reg {\n                    let (input, output) = match op {\n                        hir::InlineAsmOperand::In { .. } => (true, false),\n\n                        // Late output do not conflict with inputs, but normal outputs do\n                        hir::InlineAsmOperand::Out { late, .. } => (!late, true),\n\n                        hir::InlineAsmOperand::InOut { .. }\n                        | hir::InlineAsmOperand::SplitInOut { .. } => (true, true),\n\n                        hir::InlineAsmOperand::Const { .. }\n                        | hir::InlineAsmOperand::SymFn { .. }\n                        | hir::InlineAsmOperand::SymStatic { .. }\n                        | hir::InlineAsmOperand::Label { .. } => {\n                            unreachable!(\"{op:?} is not a register operand\");\n                        }\n                    };\n\n                    // Flag to output the error only once per operand\n                    let mut skip = false;\n\n                    let mut check = |used_regs: &mut FxHashMap<asm::InlineAsmReg, usize>,\n                                     input,\n                                     r: asm::InlineAsmReg| {\n                        match used_regs.entry(r) {\n                            Entry::Occupied(o) => {\n                                if skip {\n                                    return;\n                                }\n                                skip = true;\n\n                                let idx2 = *o.get();\n                                let (ref op2, op_sp2) = operands[idx2];","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_ast_lowering/src/asm.rs#L343-L379","documentation":"unreachable! in asm lowering (line 361) inside the explicit-register conflict check. After matching the operand against In/Out/InOut/SplitInOut, the compiler asserts that Const, SymFn, SymStatic, and Label operands — which do not bind to a register — never reach the explicit-register-conflict branch. Hitting it means a non-register operand was paired with an explicit register operand (`Reg(reg)`) in a way the AST/HIR shape should forbid.","triggerScenarios":"Triggered during lowering of a core::arch::asm! block where an explicit register constraint (in(\"rax\"), out(\"rbx\"), etc.) is somehow attached to a Const/SymFn/SymStatic/Label operand. Should be structurally impossible because the AST does not allow register specifiers on those operand kinds; reachable only via malformed AST from a proc-macro or an internal bug.","commonSituations":"Nightly regressions in inline asm lowering; proc-macros that emit asm! AST with mismatched operand/register pairs; fuzzing of asm! inputs. Hand-written asm! with valid syntax hits normal diagnostics, not this panic.","solutions":["Report the ICE to rust-lang/rust with the asm! block and rustc version.","Reduce the asm! macro invocation to the smallest block that still panics and include it in the report.","If using a proc-macro that generates asm!, verify it does not attach register specifiers to const/sym/label operands.","Pin to a stable or older nightly where the asm! feature worked."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"// The explicit-register conflict check only applies to In/Out/InOut operands.\n// Const/SymFn/SymStatic/Label operands are skipped earlier; reaching the\n// register check with one of them is an internal invariant violation.\n// Before building the InlineAsm, partition operands:\nfn register_operands<'a>(operands: &'a [hir::InlineAsmOperand<'_>]) -> impl Iterator<Item = &'a hir::InlineAsmOperand<'a>> {\n    operands.iter().filter(|op| matches!(op, hir::InlineAsmOperand::In { .. } | hir::InlineAsmOperand::Out { .. } | hir::InlineAsmOperand::InOut { .. } | hir::InlineAsmOperand::SplitInOut { .. }))\n}","typeGuard":"fn is_register_operand(op: &hir::InlineAsmOperand<'_>) -> bool {\n    matches!(\n        op,\n        hir::InlineAsmOperand::In { .. }\n            | hir::InlineAsmOperand::Out { .. }\n            | hir::InlineAsmOperand::InOut { .. }\n            | hir::InlineAsmOperand::SplitInOut { .. }\n    )\n}","tryCatchPattern":"// Tooling (rust-analyzer / clippy-like) that lowers asm:\nlet checked = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| lower_inline_asm(asm)));\nmatch checked {\n    Ok(hir_asm) => hir_asm,\n    Err(_) => return Err(\"inline asm lowering panicked: non-register operand reached the register-conflict check\"),\n}","preventionTips":["Only attach explicit registers (in(\"rax\"), out(\"rbx\"), inout(\"rcx\")) to In/Out/InOut/SplitInOut operands — never to const(\"...\"), sym fn, sym static, or label operands.","When generating asm! from a macro, separate register operands from non-register operands into distinct lists and never cross-assign clobber names to them.","Audit hand-written asm! blocks for stray explicit-register specs on a const/sym/label operand before relying on the conflict diagnostics.","If you wrap asm! in a proc-macro, validate each operand's register spec matches its operand kind before emitting the call."],"tags":["rustc","ice","inline-asm","lowering","register"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}