-
Notifications
You must be signed in to change notification settings - Fork 13.3k
improve error message when global_asm!
uses asm!
operands
#128305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,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> { | ||
Comment on lines
+32
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Every time this gets called, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. like the previous PR, this is in preparation of adding |
||
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, | ||
|
@@ -106,23 +129,23 @@ 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 }); | ||
return Err(err); | ||
} | ||
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 }); | ||
|
@@ -136,7 +159,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 }); | ||
|
@@ -150,6 +173,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 } | ||
|
@@ -165,9 +191,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 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on https://doc.rust-lang.org/reference/inline-assembly.html#syntax, it seems like
in
/out
/inout
/etc are "direction specifiers", while "operand" includes the variable. So maybe "specifier" rather than "operand" here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the word "operand" is used for the whole thing, so all of
x = inout(reg) x,
is an operand. The word "specifier" does not occur on that page, "spec" only in the grammar.The section describing these items is https://doc.rust-lang.org/reference/inline-assembly.html#operand-type. It says that "Several types of operands are supported" and then lists
in
,out
etc. So I think using the word "operand" is the most helpful.The error message points to the specifier specifically because it is easy to parse without emitting any unhelpful errors, but the operand as a whole is unsupported.