Skip to content

Commit b6b8330

Browse files
authored
Rollup merge of #128305 - folkertdev:asm-parser-unsupported-operand, r=Amanieu
improve error message when `global_asm!` uses `asm!` operands follow-up to #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.
2 parents b389b0a + 571f7b6 commit b6b8330

File tree

5 files changed

+91
-15
lines changed

5 files changed

+91
-15
lines changed

compiler/rustc_builtin_macros/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ builtin_macros_format_use_positional = consider using a positional formatting ar
196196
197197
builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
198198
199+
builtin_macros_global_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `global_asm!`
200+
.label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it
201+
199202
builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!`
200203
.label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
201204
.suggestion = remove this option

compiler/rustc_builtin_macros/src/asm.rs

+31-8
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,29 @@ pub struct AsmArgs {
2828
pub options_spans: Vec<Span>,
2929
}
3030

31+
/// Used for better error messages when operand types are used that are not
32+
/// supported by the current macro (e.g. `in` or `out` for `global_asm!`)
33+
///
34+
/// returns
35+
///
36+
/// - `Ok(true)` if the current token matches the keyword, and was expected
37+
/// - `Ok(false)` if the current token does not match the keyword
38+
/// - `Err(_)` if the current token matches the keyword, but was not expected
39+
fn eat_operand_keyword<'a>(p: &mut Parser<'a>, symbol: Symbol, expect: bool) -> PResult<'a, bool> {
40+
if expect {
41+
Ok(p.eat_keyword(symbol))
42+
} else {
43+
let span = p.token.span;
44+
if p.eat_keyword_noexpect(symbol) {
45+
// in gets printed as `r#in` otherwise
46+
let symbol = if symbol == kw::In { "in" } else { symbol.as_str() };
47+
Err(p.dcx().create_err(errors::GlobalAsmUnsupportedOperand { span, symbol }))
48+
} else {
49+
Ok(false)
50+
}
51+
}
52+
}
53+
3154
fn parse_args<'a>(
3255
ecx: &ExtCtxt<'a>,
3356
sp: Span,
@@ -105,23 +128,23 @@ pub fn parse_asm_args<'a>(
105128
};
106129

107130
let mut explicit_reg = false;
108-
let op = if !is_global_asm && p.eat_keyword(kw::In) {
131+
let op = if eat_operand_keyword(p, kw::In, !is_global_asm)? {
109132
let reg = parse_reg(p, &mut explicit_reg)?;
110133
if p.eat_keyword(kw::Underscore) {
111134
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
112135
return Err(err);
113136
}
114137
let expr = p.parse_expr()?;
115138
ast::InlineAsmOperand::In { reg, expr }
116-
} else if !is_global_asm && p.eat_keyword(sym::out) {
139+
} else if eat_operand_keyword(p, sym::out, !is_global_asm)? {
117140
let reg = parse_reg(p, &mut explicit_reg)?;
118141
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
119142
ast::InlineAsmOperand::Out { reg, expr, late: false }
120-
} else if !is_global_asm && p.eat_keyword(sym::lateout) {
143+
} else if eat_operand_keyword(p, sym::lateout, !is_global_asm)? {
121144
let reg = parse_reg(p, &mut explicit_reg)?;
122145
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
123146
ast::InlineAsmOperand::Out { reg, expr, late: true }
124-
} else if !is_global_asm && p.eat_keyword(sym::inout) {
147+
} else if eat_operand_keyword(p, sym::inout, !is_global_asm)? {
125148
let reg = parse_reg(p, &mut explicit_reg)?;
126149
if p.eat_keyword(kw::Underscore) {
127150
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -135,7 +158,7 @@ pub fn parse_asm_args<'a>(
135158
} else {
136159
ast::InlineAsmOperand::InOut { reg, expr, late: false }
137160
}
138-
} else if !is_global_asm && p.eat_keyword(sym::inlateout) {
161+
} else if eat_operand_keyword(p, sym::inlateout, !is_global_asm)? {
139162
let reg = parse_reg(p, &mut explicit_reg)?;
140163
if p.eat_keyword(kw::Underscore) {
141164
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -149,6 +172,9 @@ pub fn parse_asm_args<'a>(
149172
} else {
150173
ast::InlineAsmOperand::InOut { reg, expr, late: true }
151174
}
175+
} else if eat_operand_keyword(p, sym::label, !is_global_asm)? {
176+
let block = p.parse_block()?;
177+
ast::InlineAsmOperand::Label { block }
152178
} else if p.eat_keyword(kw::Const) {
153179
let anon_const = p.parse_expr_anon_const()?;
154180
ast::InlineAsmOperand::Const { anon_const }
@@ -164,9 +190,6 @@ pub fn parse_asm_args<'a>(
164190
path: path.clone(),
165191
};
166192
ast::InlineAsmOperand::Sym { sym }
167-
} else if !is_global_asm && p.eat_keyword(sym::label) {
168-
let block = p.parse_block()?;
169-
ast::InlineAsmOperand::Label { block }
170193
} else if allow_templates {
171194
let template = p.parse_expr()?;
172195
// If it can't possibly expand to a string, provide diagnostics here to include other

compiler/rustc_builtin_macros/src/errors.rs

+9
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,15 @@ pub(crate) struct GlobalAsmUnsupportedOption {
851851
pub(crate) full_span: Span,
852852
}
853853

854+
#[derive(Diagnostic)]
855+
#[diag(builtin_macros_global_asm_unsupported_operand)]
856+
pub(crate) struct GlobalAsmUnsupportedOperand<'a> {
857+
#[primary_span]
858+
#[label]
859+
pub(crate) span: Span,
860+
pub(crate) symbol: &'a str,
861+
}
862+
854863
#[derive(Diagnostic)]
855864
#[diag(builtin_macros_test_runner_invalid)]
856865
pub(crate) struct TestRunnerInvalid {

tests/ui/asm/parse-error.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -146,5 +146,16 @@ global_asm!(format!("{{{}}}", 0), const FOO);
146146
//~^ ERROR asm template must be a string literal
147147
global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
148148
//~^ ERROR asm template must be a string literal
149-
global_asm!("{}", label {});
150-
//~^ ERROR expected operand, options, or additional template string
149+
150+
global_asm!("{}", in(reg));
151+
//~^ ERROR the `in` operand cannot be used with `global_asm!`
152+
global_asm!("{}", out(reg));
153+
//~^ ERROR the `out` operand cannot be used with `global_asm!`
154+
global_asm!("{}", lateout(reg));
155+
//~^ ERROR the `lateout` operand cannot be used with `global_asm!`
156+
global_asm!("{}", inout(reg));
157+
//~^ ERROR the `inout` operand cannot be used with `global_asm!`
158+
global_asm!("{}", inlateout(reg));
159+
//~^ ERROR the `inlateout` operand cannot be used with `global_asm!`
160+
global_asm!("{}", label(reg));
161+
//~^ ERROR the `label` operand cannot be used with `global_asm!`

tests/ui/asm/parse-error.stderr

+35-5
Original file line numberDiff line numberDiff line change
@@ -380,11 +380,41 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
380380
|
381381
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
382382

383-
error: expected operand, options, or additional template string
384-
--> $DIR/parse-error.rs:149:19
383+
error: the `in` operand cannot be used with `global_asm!`
384+
--> $DIR/parse-error.rs:150:19
385+
|
386+
LL | global_asm!("{}", in(reg));
387+
| ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it
388+
389+
error: the `out` operand cannot be used with `global_asm!`
390+
--> $DIR/parse-error.rs:152:19
391+
|
392+
LL | global_asm!("{}", out(reg));
393+
| ^^^ the `out` operand is not meaningful for global-scoped inline assembly, remove it
394+
395+
error: the `lateout` operand cannot be used with `global_asm!`
396+
--> $DIR/parse-error.rs:154:19
397+
|
398+
LL | global_asm!("{}", lateout(reg));
399+
| ^^^^^^^ the `lateout` operand is not meaningful for global-scoped inline assembly, remove it
400+
401+
error: the `inout` operand cannot be used with `global_asm!`
402+
--> $DIR/parse-error.rs:156:19
403+
|
404+
LL | global_asm!("{}", inout(reg));
405+
| ^^^^^ the `inout` operand is not meaningful for global-scoped inline assembly, remove it
406+
407+
error: the `inlateout` operand cannot be used with `global_asm!`
408+
--> $DIR/parse-error.rs:158:19
409+
|
410+
LL | global_asm!("{}", inlateout(reg));
411+
| ^^^^^^^^^ the `inlateout` operand is not meaningful for global-scoped inline assembly, remove it
412+
413+
error: the `label` operand cannot be used with `global_asm!`
414+
--> $DIR/parse-error.rs:160:19
385415
|
386-
LL | global_asm!("{}", label {});
387-
| ^^^^^^^^ expected operand, options, or additional template string
416+
LL | global_asm!("{}", label(reg));
417+
| ^^^^^ the `label` operand is not meaningful for global-scoped inline assembly, remove it
388418

389419
error[E0435]: attempt to use a non-constant value in a constant
390420
--> $DIR/parse-error.rs:39:37
@@ -441,6 +471,6 @@ help: consider using `const` instead of `let`
441471
LL | const bar: /* Type */ = 0;
442472
| ~~~~~ ++++++++++++
443473

444-
error: aborting due to 67 previous errors
474+
error: aborting due to 72 previous errors
445475

446476
For more information about this error, try `rustc --explain E0435`.

0 commit comments

Comments
 (0)