Skip to content

Commit

Permalink
Unrolled build for rust-lang#128207
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#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.
  • Loading branch information
rust-timer authored Jul 27, 2024
2 parents d9e1dea + 33b5ca9 commit cf295a1
Show file tree
Hide file tree
Showing 17 changed files with 224 additions and 105 deletions.
5 changes: 5 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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![];

Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_builtin_macros/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
65 changes: 43 additions & 22 deletions compiler/rustc_builtin_macros/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand All @@ -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;
}
}

Expand All @@ -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();
}

Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_builtin_macros/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,17 @@ pub(crate) struct AsmOptAlreadyprovided {
pub(crate) full_span: Span,
}

#[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 {
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_passes/src/naked_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
12 changes: 6 additions & 6 deletions tests/ui/asm/aarch64/bad-options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!`
24 changes: 12 additions & 12 deletions tests/ui/asm/aarch64/bad-options.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/asm/aarch64/parse-error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
48 changes: 30 additions & 18 deletions tests/ui/asm/aarch64/parse-error.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -218,92 +218,104 @@ 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
| |
| 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
|
= 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);
| ^^^^^^^^^^^^^^^^^^^^
|
= 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);
| ^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -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`.
10 changes: 7 additions & 3 deletions tests/ui/asm/parse-error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit cf295a1

Please sign in to comment.