about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl3
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs39
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs9
-rw-r--r--tests/ui/asm/parse-error.rs15
-rw-r--r--tests/ui/asm/parse-error.stderr40
5 files changed, 91 insertions, 15 deletions
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index ae3cce40f5d..9695df9c87e 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -196,6 +196,9 @@ builtin_macros_format_use_positional = consider using a positional formatting ar
 
 builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
 
+builtin_macros_global_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `global_asm!`
+    .label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it
+
 builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!`
     .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
     .suggestion = remove this option
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 06a49dc72b6..17439dd3e3e 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -28,6 +28,29 @@ pub struct AsmArgs {
     pub options_spans: Vec<Span>,
 }
 
+/// Used for better error messages when operand types are used that are not
+/// supported by the current macro (e.g. `in` or `out` for `global_asm!`)
+///
+/// returns
+///
+/// - `Ok(true)` if the current token matches the keyword, and was expected
+/// - `Ok(false)` if the current token does not match the keyword
+/// - `Err(_)` if the current token matches the keyword, but was not expected
+fn eat_operand_keyword<'a>(p: &mut Parser<'a>, symbol: Symbol, expect: bool) -> PResult<'a, bool> {
+    if expect {
+        Ok(p.eat_keyword(symbol))
+    } else {
+        let span = p.token.span;
+        if p.eat_keyword_noexpect(symbol) {
+            // in gets printed as `r#in` otherwise
+            let symbol = if symbol == kw::In { "in" } else { symbol.as_str() };
+            Err(p.dcx().create_err(errors::GlobalAsmUnsupportedOperand { span, symbol }))
+        } else {
+            Ok(false)
+        }
+    }
+}
+
 fn parse_args<'a>(
     ecx: &ExtCtxt<'a>,
     sp: Span,
@@ -105,7 +128,7 @@ pub fn parse_asm_args<'a>(
         };
 
         let mut explicit_reg = false;
-        let op = if !is_global_asm && p.eat_keyword(kw::In) {
+        let op = if eat_operand_keyword(p, kw::In, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -113,15 +136,15 @@ pub fn parse_asm_args<'a>(
             }
             let expr = p.parse_expr()?;
             ast::InlineAsmOperand::In { reg, expr }
-        } else if !is_global_asm && p.eat_keyword(sym::out) {
+        } else if eat_operand_keyword(p, sym::out, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: false }
-        } else if !is_global_asm && p.eat_keyword(sym::lateout) {
+        } else if eat_operand_keyword(p, sym::lateout, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: true }
-        } else if !is_global_asm && p.eat_keyword(sym::inout) {
+        } else if eat_operand_keyword(p, sym::inout, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -135,7 +158,7 @@ pub fn parse_asm_args<'a>(
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: false }
             }
-        } else if !is_global_asm && p.eat_keyword(sym::inlateout) {
+        } else if eat_operand_keyword(p, sym::inlateout, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -149,6 +172,9 @@ pub fn parse_asm_args<'a>(
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: true }
             }
+        } else if eat_operand_keyword(p, sym::label, !is_global_asm)? {
+            let block = p.parse_block()?;
+            ast::InlineAsmOperand::Label { block }
         } else if p.eat_keyword(kw::Const) {
             let anon_const = p.parse_expr_anon_const()?;
             ast::InlineAsmOperand::Const { anon_const }
@@ -164,9 +190,6 @@ pub fn parse_asm_args<'a>(
                 path: path.clone(),
             };
             ast::InlineAsmOperand::Sym { sym }
-        } else if !is_global_asm && p.eat_keyword(sym::label) {
-            let block = p.parse_block()?;
-            ast::InlineAsmOperand::Label { block }
         } else if allow_templates {
             let template = p.parse_expr()?;
             // If it can't possibly expand to a string, provide diagnostics here to include other
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 93fc9bcb9d2..6ca43441e05 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -852,6 +852,15 @@ pub(crate) struct GlobalAsmUnsupportedOption {
 }
 
 #[derive(Diagnostic)]
+#[diag(builtin_macros_global_asm_unsupported_operand)]
+pub(crate) struct GlobalAsmUnsupportedOperand<'a> {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    pub(crate) symbol: &'a str,
+}
+
+#[derive(Diagnostic)]
 #[diag(builtin_macros_test_runner_invalid)]
 pub(crate) struct TestRunnerInvalid {
     #[primary_span]
diff --git a/tests/ui/asm/parse-error.rs b/tests/ui/asm/parse-error.rs
index 9dec3a1c394..16ae0282864 100644
--- a/tests/ui/asm/parse-error.rs
+++ b/tests/ui/asm/parse-error.rs
@@ -146,5 +146,16 @@ global_asm!(format!("{{{}}}", 0), const FOO);
 //~^ ERROR asm template must be a string literal
 global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
 //~^ ERROR asm template must be a string literal
-global_asm!("{}", label {});
-//~^ ERROR expected operand, options, or additional template string
+
+global_asm!("{}", in(reg));
+//~^ ERROR the `in` operand cannot be used with `global_asm!`
+global_asm!("{}", out(reg));
+//~^ ERROR the `out` operand cannot be used with `global_asm!`
+global_asm!("{}", lateout(reg));
+//~^ ERROR the `lateout` operand cannot be used with `global_asm!`
+global_asm!("{}", inout(reg));
+//~^ ERROR the `inout` operand cannot be used with `global_asm!`
+global_asm!("{}", inlateout(reg));
+//~^ ERROR the `inlateout` operand cannot be used with `global_asm!`
+global_asm!("{}", label(reg));
+//~^ ERROR the `label` operand cannot be used with `global_asm!`
diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr
index e9ecd712bc3..f5f8d537d86 100644
--- a/tests/ui/asm/parse-error.stderr
+++ b/tests/ui/asm/parse-error.stderr
@@ -380,11 +380,41 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
    |
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: expected operand, options, or additional template string
-  --> $DIR/parse-error.rs:149:19
+error: the `in` operand cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:150:19
+   |
+LL | global_asm!("{}", in(reg));
+   |                   ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it
+
+error: the `out` operand cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:152:19
+   |
+LL | global_asm!("{}", out(reg));
+   |                   ^^^ the `out` operand is not meaningful for global-scoped inline assembly, remove it
+
+error: the `lateout` operand cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:154:19
+   |
+LL | global_asm!("{}", lateout(reg));
+   |                   ^^^^^^^ the `lateout` operand is not meaningful for global-scoped inline assembly, remove it
+
+error: the `inout` operand cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:156:19
+   |
+LL | global_asm!("{}", inout(reg));
+   |                   ^^^^^ the `inout` operand is not meaningful for global-scoped inline assembly, remove it
+
+error: the `inlateout` operand cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:158:19
+   |
+LL | global_asm!("{}", inlateout(reg));
+   |                   ^^^^^^^^^ the `inlateout` operand is not meaningful for global-scoped inline assembly, remove it
+
+error: the `label` operand cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:160:19
    |
-LL | global_asm!("{}", label {});
-   |                   ^^^^^^^^ expected operand, options, or additional template string
+LL | global_asm!("{}", label(reg));
+   |                   ^^^^^ the `label` operand is not meaningful for global-scoped inline assembly, remove it
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:39:37
@@ -441,6 +471,6 @@ help: consider using `const` instead of `let`
 LL |     const bar: /* Type */ = 0;
    |     ~~~~~    ++++++++++++
 
-error: aborting due to 67 previous errors
+error: aborting due to 72 previous errors
 
 For more information about this error, try `rustc --explain E0435`.