improve error message when global_asm!
uses asm!
options
This commit is contained in:
parent
eb10639928
commit
d3858f7465
@ -2265,6 +2265,11 @@ impl InlineAsmOptions: u16 {
|
||||
}
|
||||
|
||||
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![];
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,29 @@ 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 expect =
|
||||
!is_global_asm || ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option);
|
||||
|
||||
if if expect { p.eat_keyword(symbol) } else { p.eat_keyword_noexpect(symbol) } {
|
||||
try_set_option(p, args, is_global_asm, symbol, option);
|
||||
break 'blk;
|
||||
}
|
||||
}
|
||||
|
||||
return p.unexpected();
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -599,7 +599,7 @@ fn check_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
|
||||
|
||||
/// 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 @@ fn eat_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
|
||||
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
|
||||
|
@ -244,10 +244,7 @@ fn check_inline_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
|
||||
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,
|
||||
|
@ -111,11 +111,15 @@ fn main() {
|
||||
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
|
||||
|
@ -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));
|
||||
| ^^^^^ 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 `FOO`
|
||||
--> $DIR/parse-error.rs:120:32
|
||||
|
|
||||
LL | global_asm!("", options(nomem, FOO));
|
||||
| ^^^ 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`.
|
||||
|
@ -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!`
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user