about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTrevor Gross <t.gross35@gmail.com>2024-07-27 13:32:56 -0400
committerGitHub <noreply@github.com>2024-07-27 13:32:56 -0400
commit9164dbd48c7d5ca051d665bd30470ceda79d8849 (patch)
treecbd53c5f90a012d59b97bb8cfd6eeeda792c3e43
parent51734a8a6d0ac6741b715cb726b7d0ed774484a5 (diff)
parent33b5ca99b7c61aa50ce1d973648bb610394576e8 (diff)
downloadrust-9164dbd48c7d5ca051d665bd30470ceda79d8849.tar.gz
rust-9164dbd48c7d5ca051d665bd30470ceda79d8849.zip
Rollup merge of #128207 - folkertdev:asm-parser-generalize, r=Amanieu
improve error message when `global_asm!` uses `asm!` options

specifically, what was

    error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
      --> $DIR/bad-options.rs:45:25
       |
    LL | global_asm!("", options(preserves_flags));
       |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`

is now

    error: the `preserves_flags` option cannot be used with `global_asm!`
      --> $DIR/bad-options.rs:45:25
       |
    LL | global_asm!("", options(preserves_flags));
       |                         ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly

mirroring the phrasing of the [reference](https://doc.rust-lang.org/reference/inline-assembly.html#options).

This is also a bit of a refactor for a future `naked_asm!` macro (for use in `#[naked]` functions). Currently this sort of error can come up when switching from inline to global asm, or when a user just isn't that experienced with assembly. With  `naked_asm!` added to the mix hitting this error is more likely.
-rw-r--r--compiler/rustc_ast/src/ast.rs5
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl4
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs65
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs11
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs7
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs5
-rw-r--r--tests/ui/asm/aarch64/bad-options.rs12
-rw-r--r--tests/ui/asm/aarch64/bad-options.stderr24
-rw-r--r--tests/ui/asm/aarch64/parse-error.rs2
-rw-r--r--tests/ui/asm/aarch64/parse-error.stderr48
-rw-r--r--tests/ui/asm/parse-error.rs10
-rw-r--r--tests/ui/asm/parse-error.stderr58
-rw-r--r--tests/ui/asm/unsupported-option.fixed11
-rw-r--r--tests/ui/asm/unsupported-option.rs11
-rw-r--r--tests/ui/asm/unsupported-option.stderr20
-rw-r--r--tests/ui/asm/x86_64/bad-options.rs12
-rw-r--r--tests/ui/asm/x86_64/bad-options.stderr24
17 files changed, 224 insertions, 105 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 564213ee7ee..628badd6f23 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2266,6 +2266,11 @@ bitflags::bitflags! {
 }
 
 impl InlineAsmOptions {
+    pub const COUNT: usize = Self::all().bits().count_ones() as usize;
+
+    pub const GLOBAL_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW);
+    pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW).union(Self::NORETURN);
+
     pub fn human_readable_names(&self) -> Vec<&'static str> {
         let mut options = vec![];
 
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index b56bfa98357..876f3c2b135 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -199,6 +199,10 @@ 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_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
+
 builtin_macros_invalid_crate_attribute = invalid crate attribute
 
 builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index b8fe6338493..62e59f1f4d4 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -310,6 +310,16 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
     p.dcx().emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
 }
 
+/// Report an invalid option error.
+///
+/// This function must be called immediately after the option token is parsed.
+/// Otherwise, the suggestion will be incorrect.
+fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
+    // Tool-only output
+    let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span };
+    p.dcx().emit_err(errors::GlobalAsmUnsupportedOption { span, symbol, full_span });
+}
+
 /// Try to set the provided option in the provided `AsmArgs`.
 /// If it is already set, report a duplicate option error.
 ///
@@ -318,13 +328,16 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
 fn try_set_option<'a>(
     p: &Parser<'a>,
     args: &mut AsmArgs,
+    is_global_asm: bool,
     symbol: Symbol,
     option: ast::InlineAsmOptions,
 ) {
-    if !args.options.contains(option) {
-        args.options |= option;
-    } else {
+    if is_global_asm && !ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) {
+        err_unsupported_option(p, symbol, p.prev_token.span);
+    } else if args.options.contains(option) {
         err_duplicate_option(p, symbol, p.prev_token.span);
+    } else {
+        args.options |= option;
     }
 }
 
@@ -338,25 +351,33 @@ fn parse_options<'a>(
     p.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
 
     while !p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
-        if !is_global_asm && p.eat_keyword(sym::pure) {
-            try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE);
-        } else if !is_global_asm && p.eat_keyword(sym::nomem) {
-            try_set_option(p, args, sym::nomem, ast::InlineAsmOptions::NOMEM);
-        } else if !is_global_asm && p.eat_keyword(sym::readonly) {
-            try_set_option(p, args, sym::readonly, ast::InlineAsmOptions::READONLY);
-        } else if !is_global_asm && p.eat_keyword(sym::preserves_flags) {
-            try_set_option(p, args, sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS);
-        } else if !is_global_asm && p.eat_keyword(sym::noreturn) {
-            try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN);
-        } else if !is_global_asm && p.eat_keyword(sym::nostack) {
-            try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
-        } else if !is_global_asm && p.eat_keyword(sym::may_unwind) {
-            try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND);
-        } else if p.eat_keyword(sym::att_syntax) {
-            try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
-        } else if p.eat_keyword(kw::Raw) {
-            try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::RAW);
-        } else {
+        const OPTIONS: [(Symbol, ast::InlineAsmOptions); ast::InlineAsmOptions::COUNT] = [
+            (sym::pure, ast::InlineAsmOptions::PURE),
+            (sym::nomem, ast::InlineAsmOptions::NOMEM),
+            (sym::readonly, ast::InlineAsmOptions::READONLY),
+            (sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS),
+            (sym::noreturn, ast::InlineAsmOptions::NORETURN),
+            (sym::nostack, ast::InlineAsmOptions::NOSTACK),
+            (sym::may_unwind, ast::InlineAsmOptions::MAY_UNWIND),
+            (sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX),
+            (kw::Raw, ast::InlineAsmOptions::RAW),
+        ];
+
+        'blk: {
+            for (symbol, option) in OPTIONS {
+                let kw_matched =
+                    if !is_global_asm || ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) {
+                        p.eat_keyword(symbol)
+                    } else {
+                        p.eat_keyword_noexpect(symbol)
+                    };
+
+                if kw_matched {
+                    try_set_option(p, args, is_global_asm, symbol, option);
+                    break 'blk;
+                }
+            }
+
             return p.unexpected();
         }
 
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 49d640436c2..2e6bdae14a8 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -846,6 +846,17 @@ pub(crate) struct AsmOptAlreadyprovided {
 }
 
 #[derive(Diagnostic)]
+#[diag(builtin_macros_global_asm_unsupported_option)]
+pub(crate) struct GlobalAsmUnsupportedOption {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    pub(crate) symbol: Symbol,
+    #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
+    pub(crate) full_span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(builtin_macros_test_runner_invalid)]
 pub(crate) struct TestRunnerInvalid {
     #[primary_span]
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 7326b9ec51f..e7240869a39 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -599,7 +599,7 @@ impl<'a> Parser<'a> {
 
     /// If the next token is the given keyword, eats it and returns `true`.
     /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes.
-    // Public for rustfmt usage.
+    // Public for rustc_builtin_macros and rustfmt usage.
     #[inline]
     pub fn eat_keyword(&mut self, kw: Symbol) -> bool {
         if self.check_keyword(kw) {
@@ -631,8 +631,11 @@ impl<'a> Parser<'a> {
         false
     }
 
+    /// If the next token is the given keyword, eats it and returns `true`.
+    /// Otherwise, returns `false`. No expectation is added.
+    // Public for rustc_builtin_macros usage.
     #[inline]
-    fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool {
+    pub fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool {
         if self.token.is_keyword(kw) {
             self.bump();
             true
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index dbbf802c920..4c5089b8676 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -244,10 +244,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
             self.tcx.dcx().emit_err(NakedFunctionsOperands { unsupported_operands });
         }
 
-        let supported_options =
-            InlineAsmOptions::RAW | InlineAsmOptions::NORETURN | InlineAsmOptions::ATT_SYNTAX;
-        let unsupported_options = asm.options.difference(supported_options);
-
+        let unsupported_options = asm.options.difference(InlineAsmOptions::NAKED_OPTIONS);
         if !unsupported_options.is_empty() {
             self.tcx.dcx().emit_err(NakedFunctionsAsmOptions {
                 span,
diff --git a/tests/ui/asm/aarch64/bad-options.rs b/tests/ui/asm/aarch64/bad-options.rs
index 33b77367a4f..9e721d55b2d 100644
--- a/tests/ui/asm/aarch64/bad-options.rs
+++ b/tests/ui/asm/aarch64/bad-options.rs
@@ -26,14 +26,14 @@ fn main() {
 }
 
 global_asm!("", options(nomem));
-//~^ ERROR expected one of
+//~^ ERROR the `nomem` option cannot be used with `global_asm!`
 global_asm!("", options(readonly));
-//~^ ERROR expected one of
+//~^ ERROR the `readonly` option cannot be used with `global_asm!`
 global_asm!("", options(noreturn));
-//~^ ERROR expected one of
+//~^ ERROR the `noreturn` option cannot be used with `global_asm!`
 global_asm!("", options(pure));
-//~^ ERROR expected one of
+//~^ ERROR the `pure` option cannot be used with `global_asm!`
 global_asm!("", options(nostack));
-//~^ ERROR expected one of
+//~^ ERROR the `nostack` option cannot be used with `global_asm!`
 global_asm!("", options(preserves_flags));
-//~^ ERROR expected one of
+//~^ ERROR the `preserves_flags` option cannot be used with `global_asm!`
diff --git a/tests/ui/asm/aarch64/bad-options.stderr b/tests/ui/asm/aarch64/bad-options.stderr
index 21bcc4a9c7b..54ab7cafa49 100644
--- a/tests/ui/asm/aarch64/bad-options.stderr
+++ b/tests/ui/asm/aarch64/bad-options.stderr
@@ -36,41 +36,41 @@ LL |         asm!("{}", out(reg) foo, clobber_abi("C"));
    |                    |
    |                    generic outputs
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: the `nomem` option cannot be used with `global_asm!`
   --> $DIR/bad-options.rs:28:25
    |
 LL | global_asm!("", options(nomem));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
+error: the `readonly` option cannot be used with `global_asm!`
   --> $DIR/bad-options.rs:30:25
    |
 LL | global_asm!("", options(readonly));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
+error: the `noreturn` option cannot be used with `global_asm!`
   --> $DIR/bad-options.rs:32:25
    |
 LL | global_asm!("", options(noreturn));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
+error: the `pure` option cannot be used with `global_asm!`
   --> $DIR/bad-options.rs:34:25
    |
 LL | global_asm!("", options(pure));
-   |                         ^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^ the `pure` option is not meaningful for global-scoped inline assembly
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
+error: the `nostack` option cannot be used with `global_asm!`
   --> $DIR/bad-options.rs:36:25
    |
 LL | global_asm!("", options(nostack));
-   |                         ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
+error: the `preserves_flags` option cannot be used with `global_asm!`
   --> $DIR/bad-options.rs:38:25
    |
 LL | global_asm!("", options(preserves_flags));
-   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly
 
 error: invalid ABI for `clobber_abi`
   --> $DIR/bad-options.rs:20:18
diff --git a/tests/ui/asm/aarch64/parse-error.rs b/tests/ui/asm/aarch64/parse-error.rs
index fbb1e08df91..ac73bbf99c9 100644
--- a/tests/ui/asm/aarch64/parse-error.rs
+++ b/tests/ui/asm/aarch64/parse-error.rs
@@ -98,8 +98,10 @@ global_asm!("", options(FOO));
 //~^ ERROR expected one of
 global_asm!("", options(nomem FOO));
 //~^ ERROR expected one of
+//~| ERROR the `nomem` option cannot be used with `global_asm!`
 global_asm!("", options(nomem, FOO));
 //~^ ERROR expected one of
+//~| ERROR the `nomem` option cannot be used with `global_asm!`
 global_asm!("{}", options(), const FOO);
 global_asm!("", clobber_abi(FOO));
 //~^ ERROR expected string literal
diff --git a/tests/ui/asm/aarch64/parse-error.stderr b/tests/ui/asm/aarch64/parse-error.stderr
index d21a8ab1f85..e2c798c798e 100644
--- a/tests/ui/asm/aarch64/parse-error.stderr
+++ b/tests/ui/asm/aarch64/parse-error.stderr
@@ -218,56 +218,68 @@ error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
 LL | global_asm!("", options(FOO));
    |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: the `nomem` option cannot be used with `global_asm!`
   --> $DIR/parse-error.rs:99:25
    |
 LL | global_asm!("", options(nomem FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
-  --> $DIR/parse-error.rs:101:25
+error: expected one of `)` or `,`, found `FOO`
+  --> $DIR/parse-error.rs:99:31
+   |
+LL | global_asm!("", options(nomem FOO));
+   |                               ^^^ expected one of `)` or `,`
+
+error: the `nomem` option cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:102:25
+   |
+LL | global_asm!("", options(nomem, FOO));
+   |                         ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
+  --> $DIR/parse-error.rs:102:32
    |
 LL | global_asm!("", options(nomem, FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                                ^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: expected string literal
-  --> $DIR/parse-error.rs:104:29
+  --> $DIR/parse-error.rs:106:29
    |
 LL | global_asm!("", clobber_abi(FOO));
    |                             ^^^ not a string literal
 
 error: expected one of `)` or `,`, found `FOO`
-  --> $DIR/parse-error.rs:106:33
+  --> $DIR/parse-error.rs:108:33
    |
 LL | global_asm!("", clobber_abi("C" FOO));
    |                                 ^^^ expected one of `)` or `,`
 
 error: expected string literal
-  --> $DIR/parse-error.rs:108:34
+  --> $DIR/parse-error.rs:110:34
    |
 LL | global_asm!("", clobber_abi("C", FOO));
    |                                  ^^^ not a string literal
 
 error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:110:19
+  --> $DIR/parse-error.rs:112:19
    |
 LL | global_asm!("{}", clobber_abi("C"), const FOO);
    |                   ^^^^^^^^^^^^^^^^
 
 error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:112:28
+  --> $DIR/parse-error.rs:114:28
    |
 LL | global_asm!("", options(), clobber_abi("C"));
    |                            ^^^^^^^^^^^^^^^^
 
 error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:114:30
+  --> $DIR/parse-error.rs:116:30
    |
 LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
    |                              ^^^^^^^^^^^^^^^^
 
 error: duplicate argument named `a`
-  --> $DIR/parse-error.rs:116:35
+  --> $DIR/parse-error.rs:118:35
    |
 LL | global_asm!("{a}", a = const FOO, a = const BAR);
    |                    -------------  ^^^^^^^^^^^^^ duplicate argument
@@ -275,7 +287,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
    |                    previously here
 
 error: argument never used
-  --> $DIR/parse-error.rs:116:35
+  --> $DIR/parse-error.rs:118:35
    |
 LL | global_asm!("{a}", a = const FOO, a = const BAR);
    |                                   ^^^^^^^^^^^^^ argument never used
@@ -283,19 +295,19 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
 
 error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""`
-  --> $DIR/parse-error.rs:119:28
+  --> $DIR/parse-error.rs:121:28
    |
 LL | global_asm!("", options(), "");
    |                            ^^ expected one of `clobber_abi`, `const`, `options`, or `sym`
 
 error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"`
-  --> $DIR/parse-error.rs:121:30
+  --> $DIR/parse-error.rs:123:30
    |
 LL | global_asm!("{}", const FOO, "{}", const FOO);
    |                              ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym`
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:123:13
+  --> $DIR/parse-error.rs:125:13
    |
 LL | global_asm!(format!("{{{}}}", 0), const FOO);
    |             ^^^^^^^^^^^^^^^^^^^^
@@ -303,7 +315,7 @@ LL | global_asm!(format!("{{{}}}", 0), const FOO);
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:125:20
+  --> $DIR/parse-error.rs:127:20
    |
 LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
    |                    ^^^^^^^^^^^^^^^^^^^^
@@ -398,6 +410,6 @@ help: consider using `const` instead of `let`
 LL |     const bar: /* Type */ = 0;
    |     ~~~~~    ++++++++++++
 
-error: aborting due to 57 previous errors
+error: aborting due to 59 previous errors
 
 For more information about this error, try `rustc --explain E0435`.
diff --git a/tests/ui/asm/parse-error.rs b/tests/ui/asm/parse-error.rs
index a0251c6763b..9dec3a1c394 100644
--- a/tests/ui/asm/parse-error.rs
+++ b/tests/ui/asm/parse-error.rs
@@ -111,11 +111,15 @@ global_asm!("{}", const);
 global_asm!("{}", const(reg) FOO);
 //~^ ERROR expected one of
 global_asm!("", options(FOO));
-//~^ ERROR expected one of
+//~^ ERROR expected one of `)`, `att_syntax`, or `raw`, found `FOO`
+global_asm!("", options(FOO,));
+//~^ ERROR expected one of `)`, `att_syntax`, or `raw`, found `FOO`
 global_asm!("", options(nomem FOO));
-//~^ ERROR expected one of
+//~^ ERROR the `nomem` option cannot be used with `global_asm!`
+//~| ERROR expected one of `)` or `,`, found `FOO`
 global_asm!("", options(nomem, FOO));
-//~^ ERROR expected one of
+//~^ ERROR the `nomem` option cannot be used with `global_asm!`
+//~| ERROR expected one of `)`, `att_syntax`, or `raw`, found `FOO`
 global_asm!("{}", options(), const FOO);
 global_asm!("", clobber_abi(FOO));
 //~^ ERROR expected string literal
diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr
index 1999cd09aa3..e9ecd712bc3 100644
--- a/tests/ui/asm/parse-error.stderr
+++ b/tests/ui/asm/parse-error.stderr
@@ -264,62 +264,80 @@ error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
 LL | global_asm!("", options(FOO));
    |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
   --> $DIR/parse-error.rs:115:25
    |
-LL | global_asm!("", options(nomem FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+LL | global_asm!("", options(FOO,));
+   |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: the `nomem` option cannot be used with `global_asm!`
   --> $DIR/parse-error.rs:117:25
    |
+LL | global_asm!("", options(nomem FOO));
+   |                         ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly
+
+error: expected one of `)` or `,`, found `FOO`
+  --> $DIR/parse-error.rs:117:31
+   |
+LL | global_asm!("", options(nomem FOO));
+   |                               ^^^ expected one of `)` or `,`
+
+error: the `nomem` option cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:120:25
+   |
+LL | global_asm!("", options(nomem, FOO));
+   |                         ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
+  --> $DIR/parse-error.rs:120:32
+   |
 LL | global_asm!("", options(nomem, FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                                ^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: expected string literal
-  --> $DIR/parse-error.rs:120:29
+  --> $DIR/parse-error.rs:124:29
    |
 LL | global_asm!("", clobber_abi(FOO));
    |                             ^^^ not a string literal
 
 error: expected one of `)` or `,`, found `FOO`
-  --> $DIR/parse-error.rs:122:33
+  --> $DIR/parse-error.rs:126:33
    |
 LL | global_asm!("", clobber_abi("C" FOO));
    |                                 ^^^ expected one of `)` or `,`
 
 error: expected string literal
-  --> $DIR/parse-error.rs:124:34
+  --> $DIR/parse-error.rs:128:34
    |
 LL | global_asm!("", clobber_abi("C", FOO));
    |                                  ^^^ not a string literal
 
 error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:126:19
+  --> $DIR/parse-error.rs:130:19
    |
 LL | global_asm!("{}", clobber_abi("C"), const FOO);
    |                   ^^^^^^^^^^^^^^^^
 
 error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:128:28
+  --> $DIR/parse-error.rs:132:28
    |
 LL | global_asm!("", options(), clobber_abi("C"));
    |                            ^^^^^^^^^^^^^^^^
 
 error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:130:30
+  --> $DIR/parse-error.rs:134:30
    |
 LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
    |                              ^^^^^^^^^^^^^^^^
 
 error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:132:17
+  --> $DIR/parse-error.rs:136:17
    |
 LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
    |                 ^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^
 
 error: duplicate argument named `a`
-  --> $DIR/parse-error.rs:134:35
+  --> $DIR/parse-error.rs:138:35
    |
 LL | global_asm!("{a}", a = const FOO, a = const BAR);
    |                    -------------  ^^^^^^^^^^^^^ duplicate argument
@@ -327,7 +345,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
    |                    previously here
 
 error: argument never used
-  --> $DIR/parse-error.rs:134:35
+  --> $DIR/parse-error.rs:138:35
    |
 LL | global_asm!("{a}", a = const FOO, a = const BAR);
    |                                   ^^^^^^^^^^^^^ argument never used
@@ -335,19 +353,19 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
 
 error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""`
-  --> $DIR/parse-error.rs:137:28
+  --> $DIR/parse-error.rs:141:28
    |
 LL | global_asm!("", options(), "");
    |                            ^^ expected one of `clobber_abi`, `const`, `options`, or `sym`
 
 error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"`
-  --> $DIR/parse-error.rs:139:30
+  --> $DIR/parse-error.rs:143:30
    |
 LL | global_asm!("{}", const FOO, "{}", const FOO);
    |                              ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym`
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:141:13
+  --> $DIR/parse-error.rs:145:13
    |
 LL | global_asm!(format!("{{{}}}", 0), const FOO);
    |             ^^^^^^^^^^^^^^^^^^^^
@@ -355,7 +373,7 @@ LL | global_asm!(format!("{{{}}}", 0), const FOO);
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:143:20
+  --> $DIR/parse-error.rs:147:20
    |
 LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
    |                    ^^^^^^^^^^^^^^^^^^^^
@@ -363,7 +381,7 @@ 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:145:19
+  --> $DIR/parse-error.rs:149:19
    |
 LL | global_asm!("{}", label {});
    |                   ^^^^^^^^ expected operand, options, or additional template string
@@ -423,6 +441,6 @@ help: consider using `const` instead of `let`
 LL |     const bar: /* Type */ = 0;
    |     ~~~~~    ++++++++++++
 
-error: aborting due to 64 previous errors
+error: aborting due to 67 previous errors
 
 For more information about this error, try `rustc --explain E0435`.
diff --git a/tests/ui/asm/unsupported-option.fixed b/tests/ui/asm/unsupported-option.fixed
new file mode 100644
index 00000000000..d313d8028b6
--- /dev/null
+++ b/tests/ui/asm/unsupported-option.fixed
@@ -0,0 +1,11 @@
+//@ needs-asm-support
+//@ run-rustfix
+
+use std::arch::global_asm;
+
+fn main() {}
+
+global_asm!("", options(   raw));
+//~^ ERROR the `nomem` option cannot be used with `global_asm!`
+//~| ERROR the `readonly` option cannot be used with `global_asm!`
+//~| ERROR the `noreturn` option cannot be used with `global_asm!`
diff --git a/tests/ui/asm/unsupported-option.rs b/tests/ui/asm/unsupported-option.rs
new file mode 100644
index 00000000000..d75f8e7f569
--- /dev/null
+++ b/tests/ui/asm/unsupported-option.rs
@@ -0,0 +1,11 @@
+//@ needs-asm-support
+//@ run-rustfix
+
+use std::arch::global_asm;
+
+fn main() {}
+
+global_asm!("", options(nomem, readonly, noreturn, raw));
+//~^ ERROR the `nomem` option cannot be used with `global_asm!`
+//~| ERROR the `readonly` option cannot be used with `global_asm!`
+//~| ERROR the `noreturn` option cannot be used with `global_asm!`
diff --git a/tests/ui/asm/unsupported-option.stderr b/tests/ui/asm/unsupported-option.stderr
new file mode 100644
index 00000000000..7a6927152b6
--- /dev/null
+++ b/tests/ui/asm/unsupported-option.stderr
@@ -0,0 +1,20 @@
+error: the `nomem` option cannot be used with `global_asm!`
+  --> $DIR/unsupported-option.rs:8:25
+   |
+LL | global_asm!("", options(nomem, readonly, noreturn, raw));
+   |                         ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly
+
+error: the `readonly` option cannot be used with `global_asm!`
+  --> $DIR/unsupported-option.rs:8:32
+   |
+LL | global_asm!("", options(nomem, readonly, noreturn, raw));
+   |                                ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly
+
+error: the `noreturn` option cannot be used with `global_asm!`
+  --> $DIR/unsupported-option.rs:8:42
+   |
+LL | global_asm!("", options(nomem, readonly, noreturn, raw));
+   |                                          ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/asm/x86_64/bad-options.rs b/tests/ui/asm/x86_64/bad-options.rs
index f9cc13cfc5a..6424a1b1d42 100644
--- a/tests/ui/asm/x86_64/bad-options.rs
+++ b/tests/ui/asm/x86_64/bad-options.rs
@@ -33,14 +33,14 @@ fn main() {
 }
 
 global_asm!("", options(nomem));
-//~^ ERROR expected one of
+//~^ ERROR the `nomem` option cannot be used with `global_asm!`
 global_asm!("", options(readonly));
-//~^ ERROR expected one of
+//~^ ERROR the `readonly` option cannot be used with `global_asm!`
 global_asm!("", options(noreturn));
-//~^ ERROR expected one of
+//~^ ERROR the `noreturn` option cannot be used with `global_asm!`
 global_asm!("", options(pure));
-//~^ ERROR expected one of
+//~^ ERROR the `pure` option cannot be used with `global_asm!`
 global_asm!("", options(nostack));
-//~^ ERROR expected one of
+//~^ ERROR the `nostack` option cannot be used with `global_asm!`
 global_asm!("", options(preserves_flags));
-//~^ ERROR expected one of
+//~^ ERROR the `preserves_flags` option cannot be used with `global_asm!`
diff --git a/tests/ui/asm/x86_64/bad-options.stderr b/tests/ui/asm/x86_64/bad-options.stderr
index aa167e7913c..366eb7cb90f 100644
--- a/tests/ui/asm/x86_64/bad-options.stderr
+++ b/tests/ui/asm/x86_64/bad-options.stderr
@@ -51,41 +51,41 @@ LL |         asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
    |                    |             clobber_abi
    |                    generic outputs
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: the `nomem` option cannot be used with `global_asm!`
   --> $DIR/bad-options.rs:35:25
    |
 LL | global_asm!("", options(nomem));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
+error: the `readonly` option cannot be used with `global_asm!`
   --> $DIR/bad-options.rs:37:25
    |
 LL | global_asm!("", options(readonly));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
+error: the `noreturn` option cannot be used with `global_asm!`
   --> $DIR/bad-options.rs:39:25
    |
 LL | global_asm!("", options(noreturn));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
+error: the `pure` option cannot be used with `global_asm!`
   --> $DIR/bad-options.rs:41:25
    |
 LL | global_asm!("", options(pure));
-   |                         ^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^ the `pure` option is not meaningful for global-scoped inline assembly
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
+error: the `nostack` option cannot be used with `global_asm!`
   --> $DIR/bad-options.rs:43:25
    |
 LL | global_asm!("", options(nostack));
-   |                         ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
+error: the `preserves_flags` option cannot be used with `global_asm!`
   --> $DIR/bad-options.rs:45:25
    |
 LL | global_asm!("", options(preserves_flags));
-   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly
 
 error: invalid ABI for `clobber_abi`
   --> $DIR/bad-options.rs:24:18