Auto merge of #77595 - petrochenkov:asmident, r=oli-obk
builtin_macros: Fix use of interpolated identifiers in `asm!` Fixes https://github.com/rust-lang/rust/issues/77584
This commit is contained in:
commit
a14bf4862d
5 changed files with 95 additions and 20 deletions
|
@ -81,7 +81,7 @@ fn parse_args<'a>(
|
||||||
} // accept trailing commas
|
} // accept trailing commas
|
||||||
|
|
||||||
// Parse options
|
// Parse options
|
||||||
if p.eat(&token::Ident(sym::options, false)) {
|
if p.eat_keyword(sym::options) {
|
||||||
parse_options(&mut p, &mut args)?;
|
parse_options(&mut p, &mut args)?;
|
||||||
allow_templates = false;
|
allow_templates = false;
|
||||||
continue;
|
continue;
|
||||||
|
@ -101,19 +101,19 @@ fn parse_args<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut explicit_reg = false;
|
let mut explicit_reg = false;
|
||||||
let op = if p.eat(&token::Ident(kw::In, false)) {
|
let op = if p.eat_keyword(kw::In) {
|
||||||
let reg = parse_reg(&mut p, &mut explicit_reg)?;
|
let reg = parse_reg(&mut p, &mut explicit_reg)?;
|
||||||
let expr = p.parse_expr()?;
|
let expr = p.parse_expr()?;
|
||||||
ast::InlineAsmOperand::In { reg, expr }
|
ast::InlineAsmOperand::In { reg, expr }
|
||||||
} else if p.eat(&token::Ident(sym::out, false)) {
|
} else if p.eat_keyword(sym::out) {
|
||||||
let reg = parse_reg(&mut p, &mut explicit_reg)?;
|
let reg = parse_reg(&mut 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 p.eat(&token::Ident(sym::lateout, false)) {
|
} else if p.eat_keyword(sym::lateout) {
|
||||||
let reg = parse_reg(&mut p, &mut explicit_reg)?;
|
let reg = parse_reg(&mut 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 p.eat(&token::Ident(sym::inout, false)) {
|
} else if p.eat_keyword(sym::inout) {
|
||||||
let reg = parse_reg(&mut p, &mut explicit_reg)?;
|
let reg = parse_reg(&mut p, &mut explicit_reg)?;
|
||||||
let expr = p.parse_expr()?;
|
let expr = p.parse_expr()?;
|
||||||
if p.eat(&token::FatArrow) {
|
if p.eat(&token::FatArrow) {
|
||||||
|
@ -123,7 +123,7 @@ fn parse_args<'a>(
|
||||||
} else {
|
} else {
|
||||||
ast::InlineAsmOperand::InOut { reg, expr, late: false }
|
ast::InlineAsmOperand::InOut { reg, expr, late: false }
|
||||||
}
|
}
|
||||||
} else if p.eat(&token::Ident(sym::inlateout, false)) {
|
} else if p.eat_keyword(sym::inlateout) {
|
||||||
let reg = parse_reg(&mut p, &mut explicit_reg)?;
|
let reg = parse_reg(&mut p, &mut explicit_reg)?;
|
||||||
let expr = p.parse_expr()?;
|
let expr = p.parse_expr()?;
|
||||||
if p.eat(&token::FatArrow) {
|
if p.eat(&token::FatArrow) {
|
||||||
|
@ -133,10 +133,10 @@ fn parse_args<'a>(
|
||||||
} else {
|
} else {
|
||||||
ast::InlineAsmOperand::InOut { reg, expr, late: true }
|
ast::InlineAsmOperand::InOut { reg, expr, late: true }
|
||||||
}
|
}
|
||||||
} else if p.eat(&token::Ident(kw::Const, false)) {
|
} else if p.eat_keyword(kw::Const) {
|
||||||
let expr = p.parse_expr()?;
|
let expr = p.parse_expr()?;
|
||||||
ast::InlineAsmOperand::Const { expr }
|
ast::InlineAsmOperand::Const { expr }
|
||||||
} else if p.eat(&token::Ident(sym::sym, false)) {
|
} else if p.eat_keyword(sym::sym) {
|
||||||
let expr = p.parse_expr()?;
|
let expr = p.parse_expr()?;
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ast::ExprKind::Path(..) => {}
|
ast::ExprKind::Path(..) => {}
|
||||||
|
@ -164,7 +164,7 @@ fn parse_args<'a>(
|
||||||
args.templates.push(template);
|
args.templates.push(template);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
return Err(p.expect_one_of(&[], &[]).unwrap_err());
|
return p.unexpected();
|
||||||
};
|
};
|
||||||
|
|
||||||
allow_templates = false;
|
allow_templates = false;
|
||||||
|
@ -333,21 +333,22 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn
|
||||||
p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
|
p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
|
||||||
|
|
||||||
while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
|
while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
|
||||||
if p.eat(&token::Ident(sym::pure, false)) {
|
if p.eat_keyword(sym::pure) {
|
||||||
try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE);
|
try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE);
|
||||||
} else if p.eat(&token::Ident(sym::nomem, false)) {
|
} else if p.eat_keyword(sym::nomem) {
|
||||||
try_set_option(p, args, sym::nomem, ast::InlineAsmOptions::NOMEM);
|
try_set_option(p, args, sym::nomem, ast::InlineAsmOptions::NOMEM);
|
||||||
} else if p.eat(&token::Ident(sym::readonly, false)) {
|
} else if p.eat_keyword(sym::readonly) {
|
||||||
try_set_option(p, args, sym::readonly, ast::InlineAsmOptions::READONLY);
|
try_set_option(p, args, sym::readonly, ast::InlineAsmOptions::READONLY);
|
||||||
} else if p.eat(&token::Ident(sym::preserves_flags, false)) {
|
} else if p.eat_keyword(sym::preserves_flags) {
|
||||||
try_set_option(p, args, sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS);
|
try_set_option(p, args, sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS);
|
||||||
} else if p.eat(&token::Ident(sym::noreturn, false)) {
|
} else if p.eat_keyword(sym::noreturn) {
|
||||||
try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN);
|
try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN);
|
||||||
} else if p.eat(&token::Ident(sym::nostack, false)) {
|
} else if p.eat_keyword(sym::nostack) {
|
||||||
try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
|
try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
|
||||||
} else {
|
} else if p.eat_keyword(sym::att_syntax) {
|
||||||
p.expect(&token::Ident(sym::att_syntax, false))?;
|
|
||||||
try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
|
try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
|
||||||
|
} else {
|
||||||
|
return p.unexpected();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow trailing commas
|
// Allow trailing commas
|
||||||
|
|
|
@ -120,8 +120,7 @@ fn parse_assert<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
if parser.token != token::Eof {
|
if parser.token != token::Eof {
|
||||||
parser.expect_one_of(&[], &[])?;
|
return parser.unexpected();
|
||||||
unreachable!();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Assert { cond_expr, custom_message })
|
Ok(Assert { cond_expr, custom_message })
|
||||||
|
|
|
@ -386,7 +386,7 @@ impl<'a> Parser<'a> {
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn unexpected<T>(&mut self) -> PResult<'a, T> {
|
pub fn unexpected<T>(&mut self) -> PResult<'a, T> {
|
||||||
match self.expect_one_of(&[], &[]) {
|
match self.expect_one_of(&[], &[]) {
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
// We can get `Ok(true)` from `recover_closing_delimiter`
|
// We can get `Ok(true)` from `recover_closing_delimiter`
|
||||||
|
|
24
src/test/ui/asm/interpolated-idents.rs
Normal file
24
src/test/ui/asm/interpolated-idents.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// only-x86_64
|
||||||
|
|
||||||
|
#![feature(asm)]
|
||||||
|
|
||||||
|
macro_rules! m {
|
||||||
|
($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident
|
||||||
|
$pure:ident $nomem:ident $readonly:ident $preserves_flags:ident
|
||||||
|
$noreturn:ident $nostack:ident $att_syntax:ident $options:ident) => {
|
||||||
|
unsafe {
|
||||||
|
asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
|
||||||
|
//~^ ERROR asm outputs are not allowed with the `noreturn` option
|
||||||
|
const x, sym x,
|
||||||
|
$options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
|
||||||
|
//~^ ERROR the `nomem` and `readonly` options are mutually exclusive
|
||||||
|
//~| ERROR the `pure` and `noreturn` options are mutually exclusive
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
m!(in out lateout inout inlateout const sym
|
||||||
|
pure nomem readonly preserves_flags
|
||||||
|
noreturn nostack att_syntax options);
|
||||||
|
}
|
51
src/test/ui/asm/interpolated-idents.stderr
Normal file
51
src/test/ui/asm/interpolated-idents.stderr
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
error: the `nomem` and `readonly` options are mutually exclusive
|
||||||
|
--> $DIR/interpolated-idents.rs:13:13
|
||||||
|
|
|
||||||
|
LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | / m!(in out lateout inout inlateout const sym
|
||||||
|
LL | | pure nomem readonly preserves_flags
|
||||||
|
LL | | noreturn nostack att_syntax options);
|
||||||
|
| |____________________________________________- in this macro invocation
|
||||||
|
|
|
||||||
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: the `pure` and `noreturn` options are mutually exclusive
|
||||||
|
--> $DIR/interpolated-idents.rs:13:13
|
||||||
|
|
|
||||||
|
LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | / m!(in out lateout inout inlateout const sym
|
||||||
|
LL | | pure nomem readonly preserves_flags
|
||||||
|
LL | | noreturn nostack att_syntax options);
|
||||||
|
| |____________________________________________- in this macro invocation
|
||||||
|
|
|
||||||
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: asm outputs are not allowed with the `noreturn` option
|
||||||
|
--> $DIR/interpolated-idents.rs:10:32
|
||||||
|
|
|
||||||
|
LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
|
||||||
|
| ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | m!(in out lateout inout inlateout const sym
|
||||||
|
| _____-
|
||||||
|
| |_____|
|
||||||
|
| |_____|
|
||||||
|
| |_____|
|
||||||
|
| |
|
||||||
|
LL | | pure nomem readonly preserves_flags
|
||||||
|
LL | | noreturn nostack att_syntax options);
|
||||||
|
| | -
|
||||||
|
| |____________________________________________|
|
||||||
|
| |____________________________________________in this macro invocation
|
||||||
|
| |____________________________________________in this macro invocation
|
||||||
|
| |____________________________________________in this macro invocation
|
||||||
|
| in this macro invocation
|
||||||
|
|
|
||||||
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue