rust-lang/rust · error
restore_register for {:?}
Error message
restore_register for {:?} What it means
Thrown by rustc_codegen_cranelift when restoring a register from its stack slot after a user asm! block. restore_register() emits the architecture-specific load (e.g. mov reg, [rbx+off]) to undo a clobber. Only X86_64, AArch64, and RiscV64 are implemented; other arches hit `_ => unimplemented!("restore_register for {:?}", arch)`. It is the symmetric counterpart of save_register (error 73).
Source
Thrown at compiler/rustc_codegen_cranelift/src/inline_asm.rs:822
writeln!(generated_asm, ", [rbx+0x{:x}]", offset.bytes()).unwrap();
}
InlineAsmArch::AArch64 => {
generated_asm.push_str(" ldr ");
match reg {
InlineAsmReg::AArch64(reg) if reg.vreg_index().is_some() => {
// rustc emits v0 rather than q0
reg.emit(generated_asm, InlineAsmArch::AArch64, Some('q')).unwrap()
}
_ => reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(),
}
writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap();
}
InlineAsmArch::RiscV64 => {
generated_asm.push_str(" ld ");
reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap();
writeln!(generated_asm, ", 0x{:x}(s1)", offset.bytes()).unwrap();
}
_ => unimplemented!("restore_register for {:?}", arch),
}
}
}
fn call_inline_asm<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
asm_name: &str,
slot_size: Size,
inputs: Vec<(Size, Value)>,
outputs: Vec<(Size, CPlace<'tcx>)>,
) {
let stack_slot =
fx.create_stack_slot(u32::try_from(slot_size.bytes().next_multiple_of(16)).unwrap(), 16);
let inline_asm_func = fx
.module
.declare_function(
asm_name,View on GitHub (pinned to 22057b88b0)
Solutions
- Use the LLVM backend for the unsupported target.
- Gate the asm to x86_64/aarch64/riscv64 with cfg attributes.
- Replace explicit register asm operands with portable Rust where possible.
- Implement the arch arm in restore_register() (mirror the corresponding save_register() store as a load) and submit upstream.
Example fix
// before
let mut v: u64;
asm!("mov {}, 1", inout("rax") v, options(nostack));
// after - no register clobber
let mut v: u64 = 1; Defensive patterns
Strategy: validation
Validate before calling
// Symmetric to save_register: scan for restore-path operands (out/inout
// named registers) which trigger restore_register in cg_clif.
let re = regex::Regex::new(r#"asm!.*\b(out|inout)\("(?:rax|rbx|rcx|rdx|rsi|rdi|rbp|r[0-9]+)""#).unwrap();
if src.contains("asm!") && re.is_match(&src) {
return Err("restore_register path unimplemented in cranelift backend");
} Try / catch
// Not recoverable at runtime — rustc_codegen_cranelift panics. // Switch the affected crate to the LLVM codegen backend.
Prevention
- Treat every asm! clobber as a potential save/restore pair; minimize them under cg_clif.
- Keep a per-target `.cargo/config` that forces LLVM for crates containing inline asm.
- Subscribe to cg_clif release notes; restore_register lands after save_register in the support timeline.
When it happens
Trigger: Any asm! with out/inout register operands that clobber a callee-saved or allocated register, on a target other than X86_64/AArch64/RiscV64 with the Cranelift backend. The restore runs on the post-asm path for every register saved by save_register.
Common situations: Cross-compiling register-heavy inline asm (crypto, SIMD, bit manipulation) to LoongArch/PowerPC/Arm32/S390x/Mips under cg_clif; tier-3 target bring-up where the asm save/restore sequences were never ported.
Related errors
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/1c19055510ae08dc.json.
Report an issue: GitHub.