Rollup merge of #128305 - folkertdev:asm-parser-unsupported-operand, r=Amanieu
improve error message when `global_asm!` uses `asm!` operands follow-up to https://github.com/rust-lang/rust/pull/128207 what was ``` error: expected expression, found keyword `in` --> src/lib.rs:1:31 | 1 | core::arch::global_asm!("{}", in(reg)); | ^^ expected expression ``` becomes ``` 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 ``` the span of the error is just the keyword, which means that we can't create a machine-applicable suggestion here. The alternative would be to attempt to parse the full operand, but then if there are syntax errors in the operand those would be presented to the user, even though the parser already knows that the output won't be valid. Also that would require more complexity in the parser. So I think this is a nice improvement at very low cost.
This commit is contained in:
commit
b6b8330b9d
@ -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
|
||||
|
@ -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
|
||||
|
@ -851,6 +851,15 @@ pub(crate) struct GlobalAsmUnsupportedOption {
|
||||
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)]
|
||||
#[diag(builtin_macros_test_runner_invalid)]
|
||||
pub(crate) struct TestRunnerInvalid {
|
||||
|
@ -146,5 +146,16 @@ fn main() {
|
||||
//~^ 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!`
|
||||
|
@ -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!("{}", label {});
|
||||
| ^^^^^^^^ expected operand, options, or additional template string
|
||||
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(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`.
|
||||
|
Loading…
Reference in New Issue
Block a user