//@ only-x86_64 //@ run-pass //@ needs-asm-support #![deny(unreachable_code)] #![feature(asm_goto, asm_goto_with_outputs)] use std::arch::asm; fn goto_fallthough() { unsafe { asm!( "/* {} */", label { unreachable!(); } ) } } fn goto_jump() { unsafe { let mut value = false; asm!( "jmp {}", label { value = true; } ); assert!(value); } } fn goto_out_fallthrough() { unsafe { let mut out: usize; asm!( "lea {}, [{} + 1]", "/* {} */", out(reg) out, in(reg) 0x12345678usize, label { unreachable!(); } ); assert_eq!(out, 0x12345679); } } fn goto_out_jump() { unsafe { let mut value = false; let mut out: usize; asm!( "lea {}, [{} + 1]", "jmp {}", out(reg) out, in(reg) 0x12345678usize, label { value = true; assert_eq!(out, 0x12345679); } ); assert!(value); } } fn goto_out_jump_noreturn() { unsafe { let mut value = false; let mut out: usize; asm!( "lea {}, [{} + 1]", "jmp {}", out(reg) out, in(reg) 0x12345678usize, label { value = true; assert_eq!(out, 0x12345679); }, options(noreturn) ); assert!(value); } } // asm goto with outputs cause miscompilation in LLVM when multiple outputs are present. // The code sample below is adapted from https://github.com/llvm/llvm-project/issues/74483 // and does not work with `-C opt-level=0` #[expect(unused)] fn goto_multi_out() { #[inline(never)] #[allow(unused)] fn goto_multi_out(a: usize, b: usize) -> usize { let mut x: usize; let mut y: usize; let mut z: usize; unsafe { core::arch::asm!( "mov {x}, {a}", "test {a}, {a}", "jnz {label1}", "/* {y} {z} {b} {label2} */", x = out(reg) x, y = out(reg) y, z = out(reg) z, a = in(reg) a, b = in(reg) b, label1 = label { return x }, label2 = label { return 1 }, ); 0 } } assert_eq!(goto_multi_out(11, 22), 11); } fn goto_noreturn() { unsafe { let a; asm!( "jmp {}", label { a = 1; }, options(noreturn) ); assert_eq!(a, 1); } } #[warn(unreachable_code)] fn goto_noreturn_diverge() { unsafe { asm!( "jmp {}", label { return; }, options(noreturn) ); unreachable!(); //~^ WARN unreachable statement } } fn main() { goto_fallthough(); goto_jump(); goto_out_fallthrough(); goto_out_jump(); goto_out_jump_noreturn(); // goto_multi_out(); goto_noreturn(); goto_noreturn_diverge(); }