diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index f704320c71d..93e1e25384e 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -181,6 +181,8 @@ ast_lowering_underscore_expr_lhs_assign = .label = `_` not allowed here ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture +ast_lowering_unstable_inline_assembly_label_operand_with_outputs = + using both label and output operands for inline assembly is unstable ast_lowering_unstable_inline_assembly_label_operands = label operands for inline assembly are unstable ast_lowering_unstable_may_unwind = the `may_unwind` option is unstable diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 215e6d84d0f..520274278a1 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -239,15 +239,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } InlineAsmOperand::Label { block } => { - if !self.tcx.features().asm_goto() { - feature_err( - sess, - sym::asm_goto, - *op_sp, - fluent::ast_lowering_unstable_inline_assembly_label_operands, - ) - .emit(); - } hir::InlineAsmOperand::Label { block: self.lower_block(block, false) } } }; @@ -466,6 +457,41 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + // Feature gate checking for asm goto. + if let Some((_, op_sp)) = + operands.iter().find(|(op, _)| matches!(op, hir::InlineAsmOperand::Label { .. })) + { + if !self.tcx.features().asm_goto() { + feature_err( + sess, + sym::asm_goto, + *op_sp, + fluent::ast_lowering_unstable_inline_assembly_label_operands, + ) + .emit(); + } + + // In addition, check if an output operand is used. + // This is gated behind an additional feature. + let output_operand_used = operands.iter().any(|(op, _)| { + matches!( + op, + hir::InlineAsmOperand::Out { expr: Some(_), .. } + | hir::InlineAsmOperand::InOut { .. } + | hir::InlineAsmOperand::SplitInOut { out_expr: Some(_), .. } + ) + }); + if output_operand_used && !self.tcx.features().asm_goto_with_outputs() { + feature_err( + sess, + sym::asm_goto_with_outputs, + *op_sp, + fluent::ast_lowering_unstable_inline_assembly_label_operand_with_outputs, + ) + .emit(); + } + } + let operands = self.arena.alloc_from_iter(operands); let template = self.arena.alloc_from_iter(asm.template.iter().cloned()); let template_strs = self.arena.alloc_from_iter( diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index cf0f2a7e48c..6a231397615 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -378,6 +378,8 @@ declare_features! ( (unstable, asm_experimental_arch, "1.58.0", Some(93335)), /// Allows using `label` operands in inline assembly. (unstable, asm_goto, "1.78.0", Some(119364)), + /// Allows using `label` operands in inline assembly together with output operands. + (unstable, asm_goto_with_outputs, "CURRENT_RUSTC_VERSION", Some(119364)), /// Allows the `may_unwind` option in inline assembly. (unstable, asm_unwind, "1.58.0", Some(93334)), /// Allows users to enforce equality of associated constants `TraitImpl`. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3d0ec2afa2b..0e4d937d6fd 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -417,6 +417,7 @@ symbols! { asm_const, asm_experimental_arch, asm_goto, + asm_goto_with_outputs, asm_sym, asm_unwind, assert, diff --git a/tests/codegen/asm/goto.rs b/tests/codegen/asm/goto.rs index 3193d3aa145..c40a43fbe1b 100644 --- a/tests/codegen/asm/goto.rs +++ b/tests/codegen/asm/goto.rs @@ -2,7 +2,7 @@ //@ only-x86_64 #![crate_type = "rlib"] -#![feature(asm_goto)] +#![feature(asm_goto, asm_goto_with_outputs)] use std::arch::asm; diff --git a/tests/ui/asm/x86_64/goto.rs b/tests/ui/asm/x86_64/goto.rs index d23018a05f5..50e7441509a 100644 --- a/tests/ui/asm/x86_64/goto.rs +++ b/tests/ui/asm/x86_64/goto.rs @@ -3,7 +3,7 @@ //@ needs-asm-support #![deny(unreachable_code)] -#![feature(asm_goto)] +#![feature(asm_goto, asm_goto_with_outputs)] use std::arch::asm; diff --git a/tests/ui/feature-gates/feature-gate-asm_goto_with_outputs.rs b/tests/ui/feature-gates/feature-gate-asm_goto_with_outputs.rs new file mode 100644 index 00000000000..294827f78d2 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-asm_goto_with_outputs.rs @@ -0,0 +1,13 @@ +//@ only-x86_64 + +#![feature(asm_goto)] + +use std::arch::asm; + +fn main() { + let mut _out: u64; + unsafe { + asm!("mov {}, 1", "jmp {}", out(reg) _out, label {}); + //~^ ERROR using both label and output operands for inline assembly is unstable + } +} diff --git a/tests/ui/feature-gates/feature-gate-asm_goto_with_outputs.stderr b/tests/ui/feature-gates/feature-gate-asm_goto_with_outputs.stderr new file mode 100644 index 00000000000..ff7a7d5760a --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-asm_goto_with_outputs.stderr @@ -0,0 +1,13 @@ +error[E0658]: using both label and output operands for inline assembly is unstable + --> $DIR/feature-gate-asm_goto_with_outputs.rs:10:52 + | +LL | asm!("mov {}, 1", "jmp {}", out(reg) _out, label {}); + | ^^^^^^^^ + | + = note: see issue #119364 for more information + = help: add `#![feature(asm_goto_with_outputs)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`.