improve error message when global asm uses inline asm operands

This commit is contained in:
Folkert 2024-07-28 15:11:14 +02:00
parent 3954398882
commit 571f7b6589
No known key found for this signature in database
GPG Key ID: 1F17F6FFD112B97C
5 changed files with 91 additions and 15 deletions

View File

@ -199,6 +199,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_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!` 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 .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
.suggestion = remove this option .suggestion = remove this option

View File

@ -29,6 +29,29 @@ pub struct AsmArgs {
pub options_spans: Vec<Span>, 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>( fn parse_args<'a>(
ecx: &ExtCtxt<'a>, ecx: &ExtCtxt<'a>,
sp: Span, sp: Span,
@ -106,7 +129,7 @@ pub fn parse_asm_args<'a>(
}; };
let mut explicit_reg = false; 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)?; let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) { if p.eat_keyword(kw::Underscore) {
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@ -114,15 +137,15 @@ pub fn parse_asm_args<'a>(
} }
let expr = p.parse_expr()?; let expr = p.parse_expr()?;
ast::InlineAsmOperand::In { reg, 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 reg = parse_reg(p, &mut explicit_reg)?;
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::Out { reg, expr, late: false } 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 reg = parse_reg(p, &mut explicit_reg)?;
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::Out { reg, expr, late: true } 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)?; let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) { if p.eat_keyword(kw::Underscore) {
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@ -136,7 +159,7 @@ pub fn parse_asm_args<'a>(
} else { } else {
ast::InlineAsmOperand::InOut { reg, expr, late: false } 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)?; let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) { if p.eat_keyword(kw::Underscore) {
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@ -150,6 +173,9 @@ pub fn parse_asm_args<'a>(
} else { } else {
ast::InlineAsmOperand::InOut { reg, expr, late: true } 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) { } else if p.eat_keyword(kw::Const) {
let anon_const = p.parse_expr_anon_const()?; let anon_const = p.parse_expr_anon_const()?;
ast::InlineAsmOperand::Const { anon_const } ast::InlineAsmOperand::Const { anon_const }
@ -165,9 +191,6 @@ pub fn parse_asm_args<'a>(
path: path.clone(), path: path.clone(),
}; };
ast::InlineAsmOperand::Sym { sym } 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 { } else if allow_templates {
let template = p.parse_expr()?; let template = p.parse_expr()?;
// If it can't possibly expand to a string, provide diagnostics here to include other // If it can't possibly expand to a string, provide diagnostics here to include other

View File

@ -856,6 +856,15 @@ pub(crate) struct GlobalAsmUnsupportedOption {
pub(crate) full_span: Span, pub(crate) full_span: Span,
} }
#[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)] #[derive(Diagnostic)]
#[diag(builtin_macros_test_runner_invalid)] #[diag(builtin_macros_test_runner_invalid)]
pub(crate) struct TestRunnerInvalid { pub(crate) struct TestRunnerInvalid {

View File

@ -146,5 +146,16 @@ global_asm!(format!("{{{}}}", 0), const FOO);
//~^ ERROR asm template must be a string literal //~^ ERROR asm template must be a string literal
global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
//~^ ERROR asm template must be a string literal //~^ 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!`

View File

@ -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) = 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 error: the `in` operand cannot be used with `global_asm!`
--> $DIR/parse-error.rs:149:19 --> $DIR/parse-error.rs:150:19
| |
LL | global_asm!("{}", label {}); LL | global_asm!("{}", in(reg));
| ^^^^^^^^ expected operand, options, or additional template string | ^^ 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(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 error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/parse-error.rs:39:37 --> $DIR/parse-error.rs:39:37
@ -441,6 +471,6 @@ help: consider using `const` instead of `let`
LL | const bar: /* Type */ = 0; 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`. For more information about this error, try `rustc --explain E0435`.