Skip to content

Commit 571f7b6

Browse files
committed
improve error message when global asm uses inline asm operands
1 parent 3954398 commit 571f7b6

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
@@ -199,6 +199,9 @@ builtin_macros_format_use_positional = consider using a positional formatting ar
199199
200200
builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
201201
202+
builtin_macros_global_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `global_asm!`
203+
.label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it
204+
202205
builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!`
203206
.label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
204207
.suggestion = remove this option

compiler/rustc_builtin_macros/src/asm.rs

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

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

108131
let mut explicit_reg = false;
109-
let op = if !is_global_asm && p.eat_keyword(kw::In) {
132+
let op = if eat_operand_keyword(p, kw::In, !is_global_asm)? {
110133
let reg = parse_reg(p, &mut explicit_reg)?;
111134
if p.eat_keyword(kw::Underscore) {
112135
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
113136
return Err(err);
114137
}
115138
let expr = p.parse_expr()?;
116139
ast::InlineAsmOperand::In { reg, expr }
117-
} else if !is_global_asm && p.eat_keyword(sym::out) {
140+
} else if eat_operand_keyword(p, sym::out, !is_global_asm)? {
118141
let reg = parse_reg(p, &mut explicit_reg)?;
119142
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
120143
ast::InlineAsmOperand::Out { reg, expr, late: false }
121-
} else if !is_global_asm && p.eat_keyword(sym::lateout) {
144+
} else if eat_operand_keyword(p, sym::lateout, !is_global_asm)? {
122145
let reg = parse_reg(p, &mut explicit_reg)?;
123146
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
124147
ast::InlineAsmOperand::Out { reg, expr, late: true }
125-
} else if !is_global_asm && p.eat_keyword(sym::inout) {
148+
} else if eat_operand_keyword(p, sym::inout, !is_global_asm)? {
126149
let reg = parse_reg(p, &mut explicit_reg)?;
127150
if p.eat_keyword(kw::Underscore) {
128151
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -136,7 +159,7 @@ pub fn parse_asm_args<'a>(
136159
} else {
137160
ast::InlineAsmOperand::InOut { reg, expr, late: false }
138161
}
139-
} else if !is_global_asm && p.eat_keyword(sym::inlateout) {
162+
} else if eat_operand_keyword(p, sym::inlateout, !is_global_asm)? {
140163
let reg = parse_reg(p, &mut explicit_reg)?;
141164
if p.eat_keyword(kw::Underscore) {
142165
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -150,6 +173,9 @@ pub fn parse_asm_args<'a>(
150173
} else {
151174
ast::InlineAsmOperand::InOut { reg, expr, late: true }
152175
}
176+
} else if eat_operand_keyword(p, sym::label, !is_global_asm)? {
177+
let block = p.parse_block()?;
178+
ast::InlineAsmOperand::Label { block }
153179
} else if p.eat_keyword(kw::Const) {
154180
let anon_const = p.parse_expr_anon_const()?;
155181
ast::InlineAsmOperand::Const { anon_const }
@@ -165,9 +191,6 @@ pub fn parse_asm_args<'a>(
165191
path: path.clone(),
166192
};
167193
ast::InlineAsmOperand::Sym { sym }
168-
} else if !is_global_asm && p.eat_keyword(sym::label) {
169-
let block = p.parse_block()?;
170-
ast::InlineAsmOperand::Label { block }
171194
} else if allow_templates {
172195
let template = p.parse_expr()?;
173196
// 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
@@ -856,6 +856,15 @@ pub(crate) struct GlobalAsmUnsupportedOption {
856856
pub(crate) full_span: Span,
857857
}
858858

859+
#[derive(Diagnostic)]
860+
#[diag(builtin_macros_global_asm_unsupported_operand)]
861+
pub(crate) struct GlobalAsmUnsupportedOperand<'a> {
862+
#[primary_span]
863+
#[label]
864+
pub(crate) span: Span,
865+
pub(crate) symbol: &'a str,
866+
}
867+
859868
#[derive(Diagnostic)]
860869
#[diag(builtin_macros_test_runner_invalid)]
861870
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)