From 299136b9c71596830dd31919df0c3f50628bab71 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 5 Oct 2020 23:36:51 +0300 Subject: [PATCH 1/2] builtin_macros: Fix use of interpolated identifiers in `asm!` --- compiler/rustc_builtin_macros/src/asm.rs | 33 +++++++------- src/test/ui/asm/interpolated-idents.rs | 24 ++++++++++ src/test/ui/asm/interpolated-idents.stderr | 51 ++++++++++++++++++++++ 3 files changed, 92 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/asm/interpolated-idents.rs create mode 100644 src/test/ui/asm/interpolated-idents.stderr diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 09985959b67..2cdfc3f6c9c 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -81,7 +81,7 @@ fn parse_args<'a>( } // accept trailing commas // Parse options - if p.eat(&token::Ident(sym::options, false)) { + if p.eat_keyword(sym::options) { parse_options(&mut p, &mut args)?; allow_templates = false; continue; @@ -101,19 +101,19 @@ fn parse_args<'a>( }; 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 expr = p.parse_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 expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; 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 expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; 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 expr = p.parse_expr()?; if p.eat(&token::FatArrow) { @@ -123,7 +123,7 @@ fn parse_args<'a>( } else { 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 expr = p.parse_expr()?; if p.eat(&token::FatArrow) { @@ -133,10 +133,10 @@ fn parse_args<'a>( } else { 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()?; 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()?; match expr.kind { ast::ExprKind::Path(..) => {} @@ -333,21 +333,22 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn p.expect(&token::OpenDelim(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); - } 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); - } 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); - } 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); - } 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); - } 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); - } else { - p.expect(&token::Ident(sym::att_syntax, false))?; + } else if p.eat_keyword(sym::att_syntax) { try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX); + } else { + return Err(p.expect_one_of(&[], &[]).unwrap_err()); } // Allow trailing commas diff --git a/src/test/ui/asm/interpolated-idents.rs b/src/test/ui/asm/interpolated-idents.rs new file mode 100644 index 00000000000..f4cb749307d --- /dev/null +++ b/src/test/ui/asm/interpolated-idents.rs @@ -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); +} diff --git a/src/test/ui/asm/interpolated-idents.stderr b/src/test/ui/asm/interpolated-idents.stderr new file mode 100644 index 00000000000..6ffe8d97b05 --- /dev/null +++ b/src/test/ui/asm/interpolated-idents.stderr @@ -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 + From 219c66c55c86db51a1a278c2d3cb7f8a1f4426e9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 6 Oct 2020 00:21:03 +0300 Subject: [PATCH 2/2] rustc_parse: Make `Parser::unexpected` public and use it in built-in macros --- compiler/rustc_builtin_macros/src/asm.rs | 4 ++-- compiler/rustc_builtin_macros/src/assert.rs | 3 +-- compiler/rustc_parse/src/parser/mod.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 2cdfc3f6c9c..36cd6c281b4 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -164,7 +164,7 @@ fn parse_args<'a>( args.templates.push(template); continue; } else { - return Err(p.expect_one_of(&[], &[]).unwrap_err()); + return p.unexpected(); }; allow_templates = false; @@ -348,7 +348,7 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn } else if p.eat_keyword(sym::att_syntax) { try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX); } else { - return Err(p.expect_one_of(&[], &[]).unwrap_err()); + return p.unexpected(); } // Allow trailing commas diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 25181715540..5bfd8a2bf56 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -120,8 +120,7 @@ fn parse_assert<'a>( }; if parser.token != token::Eof { - parser.expect_one_of(&[], &[])?; - unreachable!(); + return parser.unexpected(); } Ok(Assert { cond_expr, custom_message }) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 7340c574480..070fc140ec4 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -386,7 +386,7 @@ impl<'a> Parser<'a> { next } - crate fn unexpected(&mut self) -> PResult<'a, T> { + pub fn unexpected(&mut self) -> PResult<'a, T> { match self.expect_one_of(&[], &[]) { Err(e) => Err(e), // We can get `Ok(true)` from `recover_closing_delimiter`