diff --git a/src/asm.rs b/src/asm.rs index f4b2934178a..b7174a81348 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -18,7 +18,7 @@ use rustc_target::asm::*; use crate::builder::Builder; use crate::callee::get_fn; use crate::context::CodegenCx; -use crate::errors::{NulBytesInAsm, UnwindingInlineAsm}; +use crate::errors::{AsmGotoWithOutputs, NulBytesInAsm, UnwindingInlineAsm}; use crate::type_of::LayoutGccExt; // Rust asm! and GCC Extended Asm semantics differ substantially. @@ -545,6 +545,15 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { return; } + // GCC's `asm goto` cannot have output operands (libgccjit rejects them with + // "cannot add output operand to asm goto"). Emit a clean error instead of + // letting libgccjit abort with an internal error. + if dest.is_some() && !outputs.is_empty() { + let err_sp = span.first().copied().unwrap_or(DUMMY_SP); + self.sess().dcx().emit_err(AsmGotoWithOutputs { span: err_sp }); + return; + } + // 4. Generate Extended Asm block let block = self.llbb(); let extended_asm = if let Some(dest) = dest { diff --git a/src/errors.rs b/src/errors.rs index de633d3bdde..99a32cb9af0 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -30,3 +30,10 @@ pub(crate) struct NulBytesInAsm { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag("GCC backend does not support `asm goto` with output operands")] +pub(crate) struct AsmGotoWithOutputs { + #[primary_span] + pub span: Span, +} diff --git a/tests/compile/asm_goto_with_outputs.rs b/tests/compile/asm_goto_with_outputs.rs new file mode 100644 index 00000000000..2817bda8954 --- /dev/null +++ b/tests/compile/asm_goto_with_outputs.rs @@ -0,0 +1,25 @@ +// Compiler: +// status: error +// stderr: +// error: GCC backend does not support `asm goto` with output operands +// ... + +// Test that an `asm goto` with output operands emits a clean error instead of an +// ICE: libgccjit rejects output operands on an `asm goto` (issue #835). + +#![feature(asm_goto_with_outputs)] + +use std::arch::asm; + +fn main() { + let mut a: i32 = 0; + unsafe { + asm!( + "jmp {op}", + inout("eax") a, + op = label { a = 7; }, + options(nostack, nomem), + ); + } + let _ = a; +} diff --git a/tests/lang_tests.rs b/tests/lang_tests.rs index 6afd54e1c3f..81fb863c25c 100644 --- a/tests/lang_tests.rs +++ b/tests/lang_tests.rs @@ -201,7 +201,13 @@ fn compile_tests(tempdir: PathBuf, current_dir: String) { "lang compile", "tests/compile", TestMode::Compile, - &["simd-ffi.rs", "asm_nul_byte.rs", "global_asm_nul_byte.rs", "naked_asm_nul_byte.rs"], + &[ + "simd-ffi.rs", + "asm_nul_byte.rs", + "asm_goto_with_outputs.rs", + "global_asm_nul_byte.rs", + "naked_asm_nul_byte.rs", + ], ); }