From 3eba6c18d435fbbdbb46ebd1b2f9bd565daa190c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 29 Sep 2019 06:21:20 +0200 Subject: syntax: recover trailing `|` in or-patterns. --- src/libsyntax/parse/parser/pat.rs | 105 ++++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 26 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index de72f1c4d49..7eb2a73a11a 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -18,6 +18,8 @@ type Expected = Option<&'static str>; /// `Expected` for function and lambda parameter patterns. pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); +const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here"; + /// Whether or not an or-pattern should be gated when occurring in the current context. #[derive(PartialEq)] pub enum GateOr { Yes, No } @@ -40,7 +42,7 @@ impl<'a> Parser<'a> { /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). - let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; + let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes; let leading_vert_span = self.prev_span; // Parse the possibly-or-pattern. @@ -63,7 +65,7 @@ impl<'a> Parser<'a> { /// Parse the pattern for a function or function pointer parameter. /// Special recovery is provided for or-patterns and leading `|`. pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P> { - self.recover_leading_vert("not allowed in a parameter pattern"); + self.recover_leading_vert(None, "not allowed in a parameter pattern"); let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?; if let PatKind::Or(..) = &pat.kind { @@ -90,7 +92,7 @@ impl<'a> Parser<'a> { gate_or: GateOr, rc: RecoverComma, ) -> PResult<'a, P> { - // Parse the first pattern. + // Parse the first pattern (`p_0`). let first_pat = self.parse_pat(expected)?; self.maybe_recover_unexpected_comma(first_pat.span, rc)?; @@ -100,11 +102,12 @@ impl<'a> Parser<'a> { return Ok(first_pat) } + // Parse the patterns `p_1 | ... | p_n` where `n > 0`. let lo = first_pat.span; let mut pats = vec![first_pat]; - while self.eat_or_separator() { + while self.eat_or_separator(Some(lo)) { let pat = self.parse_pat(expected).map_err(|mut err| { - err.span_label(lo, "while parsing this or-pattern starting here"); + err.span_label(lo, WHILE_PARSING_OR_MSG); err })?; self.maybe_recover_unexpected_comma(pat.span, rc)?; @@ -122,11 +125,15 @@ impl<'a> Parser<'a> { /// Eat the or-pattern `|` separator. /// If instead a `||` token is encountered, recover and pretend we parsed `|`. - fn eat_or_separator(&mut self) -> bool { + fn eat_or_separator(&mut self, lo: Option) -> bool { + if self.recover_trailing_vert(lo) { + return false; + } + match self.token.kind { token::OrOr => { // Found `||`; Recover and pretend we parsed `|`. - self.ban_unexpected_or_or(); + self.ban_unexpected_or_or(lo); self.bump(); true } @@ -134,16 +141,49 @@ impl<'a> Parser<'a> { } } + /// Recover if `|` or `||` is the current token and we have one of the + /// tokens `=>`, `if`, `=`, `:`, `;`, `,`, `]`, `)`, or `}` ahead of us. + /// + /// These tokens all indicate that we reached the end of the or-pattern + /// list and can now reliably say that the `|` was an illegal trailing vert. + /// Note that there are more tokens such as `@` for which we know that the `|` + /// is an illegal parse. However, the user's intent is less clear in that case. + fn recover_trailing_vert(&mut self, lo: Option) -> bool { + let is_end_ahead = self.look_ahead(1, |token| match &token.kind { + token::FatArrow // e.g. `a | => 0,`. + | token::Ident(kw::If, false) // e.g. `a | if expr`. + | token::Eq // e.g. `let a | = 0`. + | token::Semi // e.g. `let a |;`. + | token::Colon // e.g. `let a | :`. + | token::Comma // e.g. `let (a |,)`. + | token::CloseDelim(token::Bracket) // e.g. `let [a | ]`. + | token::CloseDelim(token::Paren) // e.g. `let (a | )`. + | token::CloseDelim(token::Brace) => true, // e.g. `let A { f: a | }`. + _ => false, + }); + match (is_end_ahead, &self.token.kind) { + (true, token::BinOp(token::Or)) | (true, token::OrOr) => { + self.ban_illegal_vert(lo, "trailing", "not allowed in an or-pattern"); + self.bump(); + true + } + _ => false, + } + } + /// We have parsed `||` instead of `|`. Error and suggest `|` instead. - fn ban_unexpected_or_or(&mut self) { - self.struct_span_err(self.token.span, "unexpected token `||` after pattern") - .span_suggestion( - self.token.span, - "use a single `|` to separate multiple alternative patterns", - "|".to_owned(), - Applicability::MachineApplicable - ) - .emit(); + fn ban_unexpected_or_or(&mut self, lo: Option) { + let mut err = self.struct_span_err(self.token.span, "unexpected token `||` after pattern"); + err.span_suggestion( + self.token.span, + "use a single `|` to separate multiple alternative patterns", + "|".to_owned(), + Applicability::MachineApplicable + ); + if let Some(lo) = lo { + err.span_label(lo, WHILE_PARSING_OR_MSG); + } + err.emit(); } /// Some special error handling for the "top-level" patterns in a match arm, @@ -198,25 +238,38 @@ impl<'a> Parser<'a> { /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. /// See `parse_pat_with_or` for details on parsing or-patterns. fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P> { - self.recover_leading_vert("only allowed in a top-level pattern"); + self.recover_leading_vert(None, "only allowed in a top-level pattern"); self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No) } /// Recover if `|` or `||` is here. /// The user is thinking that a leading `|` is allowed in this position. - fn recover_leading_vert(&mut self, ctx: &str) { + fn recover_leading_vert(&mut self, lo: Option, ctx: &str) { if let token::BinOp(token::Or) | token::OrOr = self.token.kind { - let span = self.token.span; - let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token)); - - self.struct_span_err(span, &format!("a leading `|` is {}", ctx)) - .span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable) - .emit(); - + self.ban_illegal_vert(lo, "leading", ctx); self.bump(); } } + /// A `|` or possibly `||` token shouldn't be here. Ban it. + fn ban_illegal_vert(&mut self, lo: Option, pos: &str, ctx: &str) { + let span = self.token.span; + let mut err = self.struct_span_err(span, &format!("a {} `|` is {}", pos, ctx)); + err.span_suggestion( + span, + &format!("remove the `{}`", pprust::token_to_string(&self.token)), + String::new(), + Applicability::MachineApplicable, + ); + if let Some(lo) = lo { + err.span_label(lo, WHILE_PARSING_OR_MSG); + } + if let token::OrOr = self.token.kind { + err.note("alternatives in or-patterns are separated with `|`, not `||`"); + } + err.emit(); + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -259,7 +312,7 @@ impl<'a> Parser<'a> { self.bump(); self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")? } - // At this point, token != &, &&, (, [ + // At this point, token != `&`, `&&`, `(`, `[`, `..`, `..=`, or `...`. _ => if self.eat_keyword(kw::Underscore) { // Parse _ PatKind::Wild -- cgit 1.4.1-3-g733a5 From fdd1a62a453dd41b75bc1b3a992c35292b853877 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Mon, 30 Sep 2019 01:05:00 +0100 Subject: Added backticks for one diagnostic message. --- src/libsyntax/parse/lexer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 66add869359..ac3feadce3a 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -47,7 +47,7 @@ impl<'a> StringReader<'a> { source_file: Lrc, override_span: Option) -> Self { if source_file.src.is_none() { - sess.span_diagnostic.bug(&format!("Cannot lex source_file without source: {}", + sess.span_diagnostic.bug(&format!("cannot lex `source_file` without source: {}", source_file.name)); } -- cgit 1.4.1-3-g733a5 From 349259d55f9b006fe871a26eaa2481b4103dc9d7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 27 Aug 2019 02:07:26 +0300 Subject: Stabilize macros in `extern` blocks Add some tests for macros in extern blocks, remove duplicate tests --- src/libsyntax/ext/expand.rs | 13 +-- src/libsyntax/feature_gate/accepted.rs | 2 + src/libsyntax/feature_gate/active.rs | 3 - src/test/ui/abi/macros/macros-in-extern.rs | 32 ------ src/test/ui/abi/macros/macros-in-extern.stderr | 30 ------ .../ui/abi/proc-macro/auxiliary/test-macros.rs | 112 --------------------- src/test/ui/abi/proc-macro/macros-in-extern.rs | 24 ----- src/test/ui/abi/proc-macro/macros-in-extern.stderr | 30 ------ .../feature-gates/feature-gate-macros_in_extern.rs | 27 ----- .../feature-gate-macros_in_extern.stderr | 30 ------ src/test/ui/macros/issue-54441.rs | 2 - src/test/ui/macros/issue-54441.stderr | 2 +- src/test/ui/macros/macros-in-extern-rpass.rs | 30 ------ src/test/ui/macros/macros-in-extern.rs | 45 +++++++++ .../ui/proc-macro/auxiliary/test-macros-rpass.rs | 26 ----- src/test/ui/proc-macro/macros-in-extern-derive.rs | 6 ++ .../ui/proc-macro/macros-in-extern-derive.stderr | 8 ++ src/test/ui/proc-macro/macros-in-extern-rpass.rs | 25 ----- src/test/ui/proc-macro/macros-in-extern.rs | 22 ++++ 19 files changed, 85 insertions(+), 384 deletions(-) delete mode 100644 src/test/ui/abi/macros/macros-in-extern.rs delete mode 100644 src/test/ui/abi/macros/macros-in-extern.stderr delete mode 100644 src/test/ui/abi/proc-macro/auxiliary/test-macros.rs delete mode 100644 src/test/ui/abi/proc-macro/macros-in-extern.rs delete mode 100644 src/test/ui/abi/proc-macro/macros-in-extern.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-macros_in_extern.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr delete mode 100644 src/test/ui/macros/macros-in-extern-rpass.rs create mode 100644 src/test/ui/macros/macros-in-extern.rs delete mode 100644 src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs create mode 100644 src/test/ui/proc-macro/macros-in-extern-derive.rs create mode 100644 src/test/ui/proc-macro/macros-in-extern-derive.stderr delete mode 100644 src/test/ui/proc-macro/macros-in-extern-rpass.rs create mode 100644 src/test/ui/proc-macro/macros-in-extern.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 02e7c6775a4..cf8edf54673 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -555,15 +555,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstFragment { - let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); - if fragment_kind == AstFragmentKind::ForeignItems && !self.cx.ecfg.macros_in_extern() { - if let SyntaxExtensionKind::NonMacroAttr { .. } = ext {} else { - emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern, - span, GateIssue::Language, - "macro invocations in `extern {}` blocks are experimental"); - } - } - if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { let expn_data = self.cx.current_expansion.id.expn_data(); let suggested_limit = self.cx.ecfg.recursion_limit * 2; @@ -578,6 +569,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { FatalError.raise(); } + let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); match invoc.kind { InvocationKind::Bang { mac, .. } => match ext { SyntaxExtensionKind::Bang(expander) => { @@ -1578,9 +1570,6 @@ impl<'feat> ExpansionConfig<'feat> { } } - fn macros_in_extern(&self) -> bool { - self.features.map_or(false, |features| features.macros_in_extern) - } fn proc_macro_hygiene(&self) -> bool { self.features.map_or(false, |features| features.proc_macro_hygiene) } diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/libsyntax/feature_gate/accepted.rs index 5538daf388e..cda1ef1436c 100644 --- a/src/libsyntax/feature_gate/accepted.rs +++ b/src/libsyntax/feature_gate/accepted.rs @@ -245,6 +245,8 @@ declare_features! ( (accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None), /// Allows attributes in formal function parameters. (accepted, param_attrs, "1.39.0", Some(60406), None), + // Allows macro invocations in `extern {}` blocks. + (accepted, macros_in_extern, "1.40.0", Some(49476), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index 38c16dbac6a..47ee41f0adc 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -402,9 +402,6 @@ declare_features! ( /// Allows infering `'static` outlives requirements (RFC 2093). (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), - /// Allows macro invocations in `extern {}` blocks. - (active, macros_in_extern, "1.27.0", Some(49476), None), - /// Allows accessing fields of unions inside `const` functions. (active, const_fn_union, "1.27.0", Some(51909), None), diff --git a/src/test/ui/abi/macros/macros-in-extern.rs b/src/test/ui/abi/macros/macros-in-extern.rs deleted file mode 100644 index bba8b15cdb0..00000000000 --- a/src/test/ui/abi/macros/macros-in-extern.rs +++ /dev/null @@ -1,32 +0,0 @@ -// ignore-wasm32 - -#![feature(decl_macro)] - -macro_rules! returns_isize( - ($ident:ident) => ( - fn $ident() -> isize; - ) -); - -macro takes_u32_returns_u32($ident:ident) { - fn $ident (arg: u32) -> u32; -} - -macro_rules! emits_nothing( - () => () -); - -fn main() { - assert_eq!(unsafe { rust_get_test_int() }, 0isize); - assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32); -} - -#[link(name = "rust_test_helpers", kind = "static")] -extern { - returns_isize!(rust_get_test_int); - //~^ ERROR macro invocations in `extern {}` blocks are experimental - takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - //~^ ERROR macro invocations in `extern {}` blocks are experimental - emits_nothing!(); - //~^ ERROR macro invocations in `extern {}` blocks are experimental -} diff --git a/src/test/ui/abi/macros/macros-in-extern.stderr b/src/test/ui/abi/macros/macros-in-extern.stderr deleted file mode 100644 index 6ee33f4ab61..00000000000 --- a/src/test/ui/abi/macros/macros-in-extern.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/macros-in-extern.rs:26:5 - | -LL | returns_isize!(rust_get_test_int); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/macros-in-extern.rs:28:5 - | -LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/macros-in-extern.rs:30:5 - | -LL | emits_nothing!(); - | ^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/abi/proc-macro/auxiliary/test-macros.rs b/src/test/ui/abi/proc-macro/auxiliary/test-macros.rs deleted file mode 100644 index 27efa44f980..00000000000 --- a/src/test/ui/abi/proc-macro/auxiliary/test-macros.rs +++ /dev/null @@ -1,112 +0,0 @@ -// force-host -// no-prefer-dynamic - -// Proc macros commonly used by tests. -// `panic`/`print` -> `panic_bang`/`print_bang` to avoid conflicts with standard macros. - -#![crate_type = "proc-macro"] - -extern crate proc_macro; -use proc_macro::TokenStream; - -// Macro that return empty token stream. - -#[proc_macro] -pub fn empty(_: TokenStream) -> TokenStream { - TokenStream::new() -} - -#[proc_macro_attribute] -pub fn empty_attr(_: TokenStream, _: TokenStream) -> TokenStream { - TokenStream::new() -} - -#[proc_macro_derive(Empty, attributes(empty_helper))] -pub fn empty_derive(_: TokenStream) -> TokenStream { - TokenStream::new() -} - -// Macro that panics. - -#[proc_macro] -pub fn panic_bang(_: TokenStream) -> TokenStream { - panic!("panic-bang"); -} - -#[proc_macro_attribute] -pub fn panic_attr(_: TokenStream, _: TokenStream) -> TokenStream { - panic!("panic-attr"); -} - -#[proc_macro_derive(Panic, attributes(panic_helper))] -pub fn panic_derive(_: TokenStream) -> TokenStream { - panic!("panic-derive"); -} - -// Macros that return the input stream. - -#[proc_macro] -pub fn identity(input: TokenStream) -> TokenStream { - input -} - -#[proc_macro_attribute] -pub fn identity_attr(_: TokenStream, input: TokenStream) -> TokenStream { - input -} - -#[proc_macro_derive(Identity, attributes(identity_helper))] -pub fn identity_derive(input: TokenStream) -> TokenStream { - input -} - -// Macros that iterate and re-collect the input stream. - -#[proc_macro] -pub fn recollect(input: TokenStream) -> TokenStream { - input.into_iter().collect() -} - -#[proc_macro_attribute] -pub fn recollect_attr(_: TokenStream, input: TokenStream) -> TokenStream { - input.into_iter().collect() -} - -#[proc_macro_derive(Recollect, attributes(recollect_helper))] -pub fn recollect_derive(input: TokenStream) -> TokenStream { - input.into_iter().collect() -} - -// Macros that print their input in the original and re-collected forms (if they differ). - -fn print_helper(input: TokenStream, kind: &str) -> TokenStream { - let input_display = format!("{}", input); - let input_debug = format!("{:#?}", input); - let recollected = input.into_iter().collect(); - let recollected_display = format!("{}", recollected); - let recollected_debug = format!("{:#?}", recollected); - println!("PRINT-{} INPUT (DISPLAY): {}", kind, input_display); - if recollected_display != input_display { - println!("PRINT-{} RE-COLLECTED (DISPLAY): {}", kind, recollected_display); - } - println!("PRINT-{} INPUT (DEBUG): {}", kind, input_debug); - if recollected_debug != input_debug { - println!("PRINT-{} RE-COLLECTED (DEBUG): {}", kind, recollected_debug); - } - recollected -} - -#[proc_macro] -pub fn print_bang(input: TokenStream) -> TokenStream { - print_helper(input, "BANG") -} - -#[proc_macro_attribute] -pub fn print_attr(_: TokenStream, input: TokenStream) -> TokenStream { - print_helper(input, "ATTR") -} - -#[proc_macro_derive(Print, attributes(print_helper))] -pub fn print_derive(input: TokenStream) -> TokenStream { - print_helper(input, "DERIVE") -} diff --git a/src/test/ui/abi/proc-macro/macros-in-extern.rs b/src/test/ui/abi/proc-macro/macros-in-extern.rs deleted file mode 100644 index 0477b5c48ec..00000000000 --- a/src/test/ui/abi/proc-macro/macros-in-extern.rs +++ /dev/null @@ -1,24 +0,0 @@ -// aux-build:test-macros.rs -// ignore-wasm32 - -#[macro_use] -extern crate test_macros; - -fn main() { - assert_eq!(unsafe { rust_get_test_int() }, 0isize); - assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF); -} - -#[link(name = "rust_test_helpers", kind = "static")] -extern { - #[empty_attr] - //~^ ERROR macro invocations in `extern {}` blocks are experimental - fn some_definitely_unknown_symbol_which_should_be_removed(); - - #[identity_attr] - //~^ ERROR macro invocations in `extern {}` blocks are experimental - fn rust_get_test_int() -> isize; - - identity!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); - //~^ ERROR macro invocations in `extern {}` blocks are experimental -} diff --git a/src/test/ui/abi/proc-macro/macros-in-extern.stderr b/src/test/ui/abi/proc-macro/macros-in-extern.stderr deleted file mode 100644 index 6049c2aa448..00000000000 --- a/src/test/ui/abi/proc-macro/macros-in-extern.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/macros-in-extern.rs:14:5 - | -LL | #[empty_attr] - | ^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/macros-in-extern.rs:18:5 - | -LL | #[identity_attr] - | ^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/macros-in-extern.rs:22:5 - | -LL | identity!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs b/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs deleted file mode 100644 index 125af64fef0..00000000000 --- a/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![feature(decl_macro)] - -macro_rules! returns_isize( - ($ident:ident) => ( - fn $ident() -> isize; - ) -); - -macro takes_u32_returns_u32($ident:ident) { - fn $ident (arg: u32) -> u32; -} - -macro_rules! emits_nothing( - () => () -); - -#[link(name = "rust_test_helpers", kind = "static")] -extern { - returns_isize!(rust_get_test_int); - //~^ ERROR macro invocations in `extern {}` blocks are experimental - takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - //~^ ERROR macro invocations in `extern {}` blocks are experimental - emits_nothing!(); - //~^ ERROR macro invocations in `extern {}` blocks are experimental -} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr b/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr deleted file mode 100644 index e8b3ab5dda2..00000000000 --- a/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/feature-gate-macros_in_extern.rs:19:5 - | -LL | returns_isize!(rust_get_test_int); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/feature-gate-macros_in_extern.rs:21:5 - | -LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/feature-gate-macros_in_extern.rs:23:5 - | -LL | emits_nothing!(); - | ^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/macros/issue-54441.rs b/src/test/ui/macros/issue-54441.rs index b45aedb549e..afdf76b7b58 100644 --- a/src/test/ui/macros/issue-54441.rs +++ b/src/test/ui/macros/issue-54441.rs @@ -1,5 +1,3 @@ -#![feature(macros_in_extern)] - macro_rules! m { () => { let //~ ERROR expected diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr index b0fafdc3b63..af0ee3ae8ec 100644 --- a/src/test/ui/macros/issue-54441.stderr +++ b/src/test/ui/macros/issue-54441.stderr @@ -1,5 +1,5 @@ error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found `let` - --> $DIR/issue-54441.rs:5:9 + --> $DIR/issue-54441.rs:3:9 | LL | let | ^^^ unexpected token diff --git a/src/test/ui/macros/macros-in-extern-rpass.rs b/src/test/ui/macros/macros-in-extern-rpass.rs deleted file mode 100644 index 28abef5cf4e..00000000000 --- a/src/test/ui/macros/macros-in-extern-rpass.rs +++ /dev/null @@ -1,30 +0,0 @@ -// run-pass -// ignore-wasm32 - -#![feature(decl_macro, macros_in_extern)] - -macro_rules! returns_isize( - ($ident:ident) => ( - fn $ident() -> isize; - ) -); - -macro takes_u32_returns_u32($ident:ident) { - fn $ident (arg: u32) -> u32; -} - -macro_rules! emits_nothing( - () => () -); - -fn main() { - assert_eq!(unsafe { rust_get_test_int() }, 1isize); - assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32); -} - -#[link(name = "rust_test_helpers", kind = "static")] -extern { - returns_isize!(rust_get_test_int); - takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - emits_nothing!(); -} diff --git a/src/test/ui/macros/macros-in-extern.rs b/src/test/ui/macros/macros-in-extern.rs new file mode 100644 index 00000000000..05002ed72c7 --- /dev/null +++ b/src/test/ui/macros/macros-in-extern.rs @@ -0,0 +1,45 @@ +// run-pass +// ignore-wasm32 + +#![feature(decl_macro)] + +macro_rules! returns_isize( + ($ident:ident) => ( + fn $ident() -> isize; + ) +); + +macro takes_u32_returns_u32($ident:ident) { + fn $ident (arg: u32) -> u32; +} + +macro_rules! emits_nothing( + () => () +); + +macro_rules! emits_multiple( + () => { + fn f1() -> u32; + fn f2() -> u32; + } +); + +mod defs { + #[no_mangle] extern fn f1() -> u32 { 1 } + #[no_mangle] extern fn f2() -> u32 { 2 } +} + +fn main() { + assert_eq!(unsafe { rust_get_test_int() }, 1); + assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32); + assert_eq!(unsafe { f1() }, 1); + assert_eq!(unsafe { f2() }, 2); +} + +#[link(name = "rust_test_helpers", kind = "static")] +extern { + returns_isize!(rust_get_test_int); + takes_u32_returns_u32!(rust_dbg_extern_identity_u32); + emits_nothing!(); + emits_multiple!(); +} diff --git a/src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs b/src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs deleted file mode 100644 index 15fe3804f9b..00000000000 --- a/src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs +++ /dev/null @@ -1,26 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::TokenStream; - -#[proc_macro_attribute] -pub fn nop_attr(_attr: TokenStream, input: TokenStream) -> TokenStream { - assert!(_attr.to_string().is_empty()); - input -} - -#[proc_macro_attribute] -pub fn no_output(_attr: TokenStream, _input: TokenStream) -> TokenStream { - assert!(_attr.to_string().is_empty()); - assert!(!_input.to_string().is_empty()); - "".parse().unwrap() -} - -#[proc_macro] -pub fn emit_input(input: TokenStream) -> TokenStream { - input -} diff --git a/src/test/ui/proc-macro/macros-in-extern-derive.rs b/src/test/ui/proc-macro/macros-in-extern-derive.rs new file mode 100644 index 00000000000..d2751a353bd --- /dev/null +++ b/src/test/ui/proc-macro/macros-in-extern-derive.rs @@ -0,0 +1,6 @@ +extern { + #[derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions + fn f(); +} + +fn main() {} diff --git a/src/test/ui/proc-macro/macros-in-extern-derive.stderr b/src/test/ui/proc-macro/macros-in-extern-derive.stderr new file mode 100644 index 00000000000..e2afb7d34c1 --- /dev/null +++ b/src/test/ui/proc-macro/macros-in-extern-derive.stderr @@ -0,0 +1,8 @@ +error: `derive` may only be applied to structs, enums and unions + --> $DIR/macros-in-extern-derive.rs:2:5 + | +LL | #[derive(Copy)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/proc-macro/macros-in-extern-rpass.rs b/src/test/ui/proc-macro/macros-in-extern-rpass.rs deleted file mode 100644 index a30a287a101..00000000000 --- a/src/test/ui/proc-macro/macros-in-extern-rpass.rs +++ /dev/null @@ -1,25 +0,0 @@ -// run-pass -// aux-build:test-macros-rpass.rs -// ignore-wasm32 - -#![feature(macros_in_extern)] - -extern crate test_macros_rpass as test_macros; - -use test_macros::{nop_attr, no_output, emit_input}; - -fn main() { - assert_eq!(unsafe { rust_get_test_int() }, 1isize); - assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF); -} - -#[link(name = "rust_test_helpers", kind = "static")] -extern { - #[no_output] - fn some_definitely_unknown_symbol_which_should_be_removed(); - - #[nop_attr] - fn rust_get_test_int() -> isize; - - emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); -} diff --git a/src/test/ui/proc-macro/macros-in-extern.rs b/src/test/ui/proc-macro/macros-in-extern.rs new file mode 100644 index 00000000000..e2b1d55aedc --- /dev/null +++ b/src/test/ui/proc-macro/macros-in-extern.rs @@ -0,0 +1,22 @@ +// run-pass +// aux-build:test-macros.rs +// ignore-wasm32 + +#[macro_use] +extern crate test_macros; + +fn main() { + assert_eq!(unsafe { rust_get_test_int() }, 1); + assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF); +} + +#[link(name = "rust_test_helpers", kind = "static")] +extern { + #[empty_attr] + fn some_definitely_unknown_symbol_which_should_be_removed(); + + #[identity_attr] + fn rust_get_test_int() -> isize; + + identity!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); +} -- cgit 1.4.1-3-g733a5 From 5ae38bbc7c6c79c4bbdb2f098bf770c24087f403 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 27 Aug 2019 03:48:48 +0300 Subject: Stabilize proc macros in type positions --- src/librustc_macros/src/lib.rs | 1 - src/libsyntax/ext/expand.rs | 10 +++++----- src/test/ui/proc-macro/dollar-crate-issue-62325.rs | 2 -- src/test/ui/proc-macro/lifetimes.rs | 2 -- src/test/ui/proc-macro/lifetimes.stderr | 2 +- src/test/ui/proc-macro/macros-in-type.rs | 11 +++++++++++ src/test/ui/proc-macro/proc-macro-gates.rs | 1 - src/test/ui/proc-macro/proc-macro-gates.stderr | 21 ++++++--------------- 8 files changed, 23 insertions(+), 27 deletions(-) create mode 100644 src/test/ui/proc-macro/macros-in-type.rs (limited to 'src/libsyntax') diff --git a/src/librustc_macros/src/lib.rs b/src/librustc_macros/src/lib.rs index 3d3a020ef0c..0540c95d3de 100644 --- a/src/librustc_macros/src/lib.rs +++ b/src/librustc_macros/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(proc_macro_hygiene)] #![allow(rustc::default_hash_types)] #![recursion_limit="128"] diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index cf8edf54673..581ef5d4da9 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -749,14 +749,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) { let kind = match kind { - AstFragmentKind::Expr => "expressions", + AstFragmentKind::Expr | AstFragmentKind::OptExpr => "expressions", AstFragmentKind::Pat => "patterns", - AstFragmentKind::Ty => "types", AstFragmentKind::Stmts => "statements", - AstFragmentKind::Items => return, - AstFragmentKind::TraitItems => return, - AstFragmentKind::ImplItems => return, + AstFragmentKind::Ty | + AstFragmentKind::Items | + AstFragmentKind::TraitItems | + AstFragmentKind::ImplItems | AstFragmentKind::ForeignItems => return, AstFragmentKind::Arms | AstFragmentKind::Fields diff --git a/src/test/ui/proc-macro/dollar-crate-issue-62325.rs b/src/test/ui/proc-macro/dollar-crate-issue-62325.rs index b7b152e6692..223c4047cb2 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-62325.rs +++ b/src/test/ui/proc-macro/dollar-crate-issue-62325.rs @@ -7,8 +7,6 @@ // normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)" // normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)" -#![feature(proc_macro_hygiene)] - #[macro_use] extern crate test_macros; extern crate dollar_crate_external; diff --git a/src/test/ui/proc-macro/lifetimes.rs b/src/test/ui/proc-macro/lifetimes.rs index d0dd1b4603b..5605696715e 100644 --- a/src/test/ui/proc-macro/lifetimes.rs +++ b/src/test/ui/proc-macro/lifetimes.rs @@ -1,7 +1,5 @@ // aux-build:lifetimes.rs -#![feature(proc_macro_hygiene)] - extern crate lifetimes; use lifetimes::*; diff --git a/src/test/ui/proc-macro/lifetimes.stderr b/src/test/ui/proc-macro/lifetimes.stderr index 6e91201405c..10acd4304aa 100644 --- a/src/test/ui/proc-macro/lifetimes.stderr +++ b/src/test/ui/proc-macro/lifetimes.stderr @@ -1,5 +1,5 @@ error: expected type, found `'` - --> $DIR/lifetimes.rs:9:10 + --> $DIR/lifetimes.rs:7:10 | LL | type A = single_quote_alone!(); | ^^^^^^^^^^^^^^^^^^^^^ this macro call doesn't expand to a type diff --git a/src/test/ui/proc-macro/macros-in-type.rs b/src/test/ui/proc-macro/macros-in-type.rs new file mode 100644 index 00000000000..19ed58eceb9 --- /dev/null +++ b/src/test/ui/proc-macro/macros-in-type.rs @@ -0,0 +1,11 @@ +// check-pass +// aux-build:test-macros.rs + +#[macro_use] +extern crate test_macros; + +const C: identity!(u8) = 10; + +fn main() { + let c: u8 = C; +} diff --git a/src/test/ui/proc-macro/proc-macro-gates.rs b/src/test/ui/proc-macro/proc-macro-gates.rs index 678dc83b753..0096a84f14c 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.rs +++ b/src/test/ui/proc-macro/proc-macro-gates.rs @@ -50,7 +50,6 @@ fn attrs() { } fn main() { - let _x: identity!(u32) = 3; //~ ERROR: procedural macros cannot be expanded to types if let identity!(Some(_x)) = Some(3) {} //~^ ERROR: procedural macros cannot be expanded to patterns diff --git a/src/test/ui/proc-macro/proc-macro-gates.stderr b/src/test/ui/proc-macro/proc-macro-gates.stderr index 8462b564ec1..14a4f8c0fbc 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.stderr +++ b/src/test/ui/proc-macro/proc-macro-gates.stderr @@ -94,17 +94,8 @@ LL | let _x = #[identity_attr] println!(); = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to types - --> $DIR/proc-macro-gates.rs:53:13 - | -LL | let _x: identity!(u32) = 3; - | ^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/54727 - = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable - error[E0658]: procedural macros cannot be expanded to patterns - --> $DIR/proc-macro-gates.rs:54:12 + --> $DIR/proc-macro-gates.rs:53:12 | LL | if let identity!(Some(_x)) = Some(3) {} | ^^^^^^^^^^^^^^^^^^^ @@ -113,7 +104,7 @@ LL | if let identity!(Some(_x)) = Some(3) {} = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: procedural macros cannot be expanded to statements - --> $DIR/proc-macro-gates.rs:57:5 + --> $DIR/proc-macro-gates.rs:56:5 | LL | empty!(struct S;); | ^^^^^^^^^^^^^^^^^^ @@ -122,7 +113,7 @@ LL | empty!(struct S;); = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: procedural macros cannot be expanded to statements - --> $DIR/proc-macro-gates.rs:58:5 + --> $DIR/proc-macro-gates.rs:57:5 | LL | empty!(let _x = 3;); | ^^^^^^^^^^^^^^^^^^^^ @@ -131,7 +122,7 @@ LL | empty!(let _x = 3;); = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: procedural macros cannot be expanded to expressions - --> $DIR/proc-macro-gates.rs:60:14 + --> $DIR/proc-macro-gates.rs:59:14 | LL | let _x = identity!(3); | ^^^^^^^^^^^^ @@ -140,7 +131,7 @@ LL | let _x = identity!(3); = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: procedural macros cannot be expanded to expressions - --> $DIR/proc-macro-gates.rs:61:15 + --> $DIR/proc-macro-gates.rs:60:15 | LL | let _x = [empty!(3)]; | ^^^^^^^^^ @@ -148,6 +139,6 @@ LL | let _x = [empty!(3)]; = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable -error: aborting due to 17 previous errors +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0658`. -- cgit 1.4.1-3-g733a5 From 535d4743a4bc4807446cefbc2413e02d53aa0a85 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 17 Aug 2019 23:55:41 +0300 Subject: syntax: Split `ast::Attribute` into container and inner parts --- src/librustc/hir/lowering.rs | 6 ++++-- src/librustc/ich/impls_syntax.rs | 13 +++++++------ src/libsyntax/ast.rs | 14 ++++++++++++-- src/libsyntax/attr/mod.rs | 14 +++++++------- src/libsyntax/config.rs | 3 +-- src/libsyntax/ext/expand.rs | 10 +++++----- src/libsyntax/mut_visit.rs | 3 ++- src/libsyntax/parse/attr.rs | 3 +-- 8 files changed, 39 insertions(+), 27 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 4310bafd781..2238a56b29d 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -988,10 +988,12 @@ impl<'a> LoweringContext<'a> { // lower attributes (we use the AST version) there is nowhere to keep // the `HirId`s. We don't actually need HIR version of attributes anyway. Attribute { + item: AttrItem { + path: attr.path.clone(), + tokens: self.lower_token_stream(attr.tokens.clone()), + }, id: attr.id, style: attr.style, - path: attr.path.clone(), - tokens: self.lower_token_stream(attr.tokens.clone()), is_sugared_doc: attr.is_sugared_doc, span: attr.span, } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index bdcf9e42ac2..23a2f115e05 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -196,6 +196,11 @@ impl<'a> HashStable> for ast::Path { } } +impl_stable_hash_for!(struct ::syntax::ast::AttrItem { + path, + tokens, +}); + impl<'a> HashStable> for ast::Attribute { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { // Make sure that these have been filtered out. @@ -203,19 +208,15 @@ impl<'a> HashStable> for ast::Attribute { debug_assert!(!self.is_sugared_doc); let ast::Attribute { + ref item, id: _, style, - ref path, - ref tokens, is_sugared_doc: _, span, } = *self; + item.hash_stable(hcx, hasher); style.hash_stable(hcx, hasher); - path.hash_stable(hcx, hasher); - for tt in tokens.trees() { - tt.hash_stable(hcx, hasher); - } span.hash_stable(hcx, hasher); } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7a5c92167bc..e2c8e37e11c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2139,18 +2139,28 @@ impl rustc_serialize::Decodable for AttrId { } } +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct AttrItem { + pub path: Path, + pub tokens: TokenStream, +} + /// Metadata associated with an item. /// Doc-comments are promoted to attributes that have `is_sugared_doc = true`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Attribute { + pub item: AttrItem, pub id: AttrId, pub style: AttrStyle, - pub path: Path, - pub tokens: TokenStream, pub is_sugared_doc: bool, pub span: Span, } +impl std::ops::Deref for Attribute { + type Target = AttrItem; + fn deref(&self) -> &Self::Target { &self.item } +} + /// `TraitRef`s appear in impls. /// /// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 122cb7fb12b..009259352ba 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -9,7 +9,7 @@ pub use StabilityLevel::*; pub use crate::ast::Attribute; use crate::ast; -use crate::ast::{AttrId, AttrStyle, Name, Ident, Path, PathSegment}; +use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment}; use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; @@ -333,10 +333,9 @@ impl Attribute { DUMMY_SP, ); f(&Attribute { + item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, id: self.id, style: self.style, - path: meta.path, - tokens: meta.kind.tokens(meta.span), is_sugared_doc: true, span: self.span, }) @@ -384,10 +383,9 @@ crate fn mk_attr_id() -> AttrId { pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute { Attribute { + item: AttrItem { path, tokens }, id: mk_attr_id(), style, - path, - tokens, is_sugared_doc: false, span, } @@ -408,10 +406,12 @@ pub fn mk_sugared_doc_attr(text: Symbol, span: Span) -> Attribute { let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked); let lit = Lit::from_lit_kind(lit_kind, span); Attribute { + item: AttrItem { + path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)), + tokens: MetaItemKind::NameValue(lit).tokens(span), + }, id: mk_attr_id(), style, - path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)), - tokens: MetaItemKind::NameValue(lit).tokens(span), is_sugared_doc: true, span, } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 990358c674f..a9a5c3efd06 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -151,10 +151,9 @@ impl<'a> StripUnconfigured<'a> { // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. expanded_attrs.into_iter() .flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute { + item: ast::AttrItem { path, tokens }, id: attr::mk_attr_id(), style: attr.style, - path, - tokens, is_sugared_doc: false, span, })) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 02e7c6775a4..2b0fc5d3677 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1,4 +1,4 @@ -use crate::ast::{self, Block, Ident, LitKind, NodeId, PatKind, Path}; +use crate::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path}; use crate::ast::{MacStmtStyle, StmtKind, ItemKind}; use crate::attr::{self, HasAttrs}; use crate::source_map::respan; @@ -625,9 +625,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { | Annotatable::Variant(..) => panic!("unexpected annotatable"), })), DUMMY_SP).into(); - let input = self.extract_proc_macro_attr_input(attr.tokens, span); + let input = self.extract_proc_macro_attr_input(attr.item.tokens, span); let tok_result = expander.expand(self.cx, span, input, item_tok); - let res = self.parse_ast_fragment(tok_result, fragment_kind, &attr.path, span); + let res = + self.parse_ast_fragment(tok_result, fragment_kind, &attr.item.path, span); self.gate_proc_macro_expansion(span, &res); res } @@ -1530,11 +1531,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items); *at = attr::Attribute { + item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, span: at.span, id: at.id, style: at.style, - path: meta.path, - tokens: meta.kind.tokens(meta.span), is_sugared_doc: false, }; } else { diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 80dfe9e5be0..4b78282b787 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -550,7 +550,8 @@ pub fn noop_visit_local(local: &mut P, vis: &mut T) { } pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { - let Attribute { id: _, style: _, path, tokens, is_sugared_doc: _, span } = attr; + let Attribute { item: AttrItem { path, tokens }, id: _, style: _, is_sugared_doc: _, span } + = attr; vis.visit_path(path); vis.visit_tts(tokens); vis.visit_span(span); diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 44688bd36b5..707f903916c 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -151,10 +151,9 @@ impl<'a> Parser<'a> { }; Ok(ast::Attribute { + item: ast::AttrItem { path, tokens }, id: attr::mk_attr_id(), style, - path, - tokens, is_sugared_doc: false, span, }) -- cgit 1.4.1-3-g733a5 From 957986d05620238799ae7053d505f742a0c7d640 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 18 Aug 2019 01:10:56 +0300 Subject: syntax: Support modern attribute syntax in the `meta` matcher --- src/libsyntax/attr/mod.rs | 16 +++++++++----- src/libsyntax/config.rs | 8 +++---- src/libsyntax/ext/mbe/macro_parser.rs | 2 +- src/libsyntax/mut_visit.rs | 5 ++++- src/libsyntax/parse/attr.rs | 31 +++++++++++++++------------ src/libsyntax/parse/parser/path.rs | 6 +++--- src/libsyntax/parse/token.rs | 2 +- src/libsyntax/print/pprust.rs | 40 +++++++++++++++++++---------------- src/libsyntax_ext/cmdline_attrs.rs | 4 ++-- src/test/ui/cfg/cfg_stmt_expr.rs | 4 ++-- src/test/ui/macros/macro-first-set.rs | 6 ------ 11 files changed, 68 insertions(+), 56 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 009259352ba..7bef693a5be 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -255,9 +255,8 @@ impl MetaItem { } } -impl Attribute { - /// Extracts the `MetaItem` from inside this `Attribute`. - pub fn meta(&self) -> Option { +impl AttrItem { + crate fn meta(&self, span: Span) -> Option { let mut tokens = self.tokens.trees().peekable(); Some(MetaItem { path: self.path.clone(), @@ -269,9 +268,16 @@ impl Attribute { } else { return None; }, - span: self.span, + span, }) } +} + +impl Attribute { + /// Extracts the MetaItem from inside this Attribute. + pub fn meta(&self) -> Option { + self.item.meta(self.span) + } pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T> where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, @@ -524,7 +530,7 @@ impl MetaItem { } Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt { token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident), - token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()), + token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span), token::Nonterminal::NtPath(ref path) => path.clone(), _ => return None, }, diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index a9a5c3efd06..2923cc86ba0 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -122,8 +122,8 @@ impl<'a> StripUnconfigured<'a> { while !parser.check(&token::CloseDelim(token::Paren)) { let lo = parser.token.span.lo(); - let (path, tokens) = parser.parse_meta_item_unrestricted()?; - expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo))); + let item = parser.parse_attr_item()?; + expanded_attrs.push((item, parser.prev_span.with_lo(lo))); parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?; } @@ -150,8 +150,8 @@ impl<'a> StripUnconfigured<'a> { // `cfg_attr` inside of another `cfg_attr`. E.g. // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. expanded_attrs.into_iter() - .flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute { - item: ast::AttrItem { path, tokens }, + .flat_map(|(item, span)| self.process_cfg_attr(ast::Attribute { + item, id: attr::mk_attr_id(), style: attr.style, is_sugared_doc: false, diff --git a/src/libsyntax/ext/mbe/macro_parser.rs b/src/libsyntax/ext/mbe/macro_parser.rs index 8f49ba9572d..d1c50fd8594 100644 --- a/src/libsyntax/ext/mbe/macro_parser.rs +++ b/src/libsyntax/ext/mbe/macro_parser.rs @@ -924,7 +924,7 @@ fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Nonterminal { FatalError.raise() } sym::path => token::NtPath(panictry!(p.parse_path(PathStyle::Type))), - sym::meta => token::NtMeta(panictry!(p.parse_meta_item())), + sym::meta => token::NtMeta(panictry!(p.parse_attr_item())), sym::vis => token::NtVis(panictry!(p.parse_visibility(true))), sym::lifetime => if p.check_lifetime() { token::NtLifetime(p.expect_lifetime().ident) diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 4b78282b787..3923b9f297b 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -682,7 +682,10 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: token::NtIdent(ident, _is_raw) => vis.visit_ident(ident), token::NtLifetime(ident) => vis.visit_ident(ident), token::NtLiteral(expr) => vis.visit_expr(expr), - token::NtMeta(meta) => vis.visit_meta_item(meta), + token::NtMeta(AttrItem { path, tokens }) => { + vis.visit_path(path); + vis.visit_tts(tokens); + } token::NtPath(path) => vis.visit_path(path), token::NtTT(tt) => vis.visit_tt(tt), token::NtImplItem(item) => diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 707f903916c..f3298b6a65d 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -90,7 +90,7 @@ impl<'a> Parser<'a> { debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", inner_parse_policy, self.token); - let (span, path, tokens, style) = match self.token.kind { + let (span, item, style) = match self.token.kind { token::Pound => { let lo = self.token.span; self.bump(); @@ -107,7 +107,7 @@ impl<'a> Parser<'a> { }; self.expect(&token::OpenDelim(token::Bracket))?; - let (path, tokens) = self.parse_meta_item_unrestricted()?; + let item = self.parse_attr_item()?; self.expect(&token::CloseDelim(token::Bracket))?; let hi = self.prev_span; @@ -142,7 +142,7 @@ impl<'a> Parser<'a> { } } - (attr_sp, path, tokens, style) + (attr_sp, item, style) } _ => { let token_str = self.this_token_to_string(); @@ -151,7 +151,7 @@ impl<'a> Parser<'a> { }; Ok(ast::Attribute { - item: ast::AttrItem { path, tokens }, + item, id: attr::mk_attr_id(), style, is_sugared_doc: false, @@ -168,17 +168,17 @@ impl<'a> Parser<'a> { /// PATH /// PATH `=` TOKEN_TREE /// The delimiters or `=` are still put into the resulting token stream. - pub fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> { - let meta = match self.token.kind { + pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { + let item = match self.token.kind { token::Interpolated(ref nt) => match **nt { - Nonterminal::NtMeta(ref meta) => Some(meta.clone()), + Nonterminal::NtMeta(ref item) => Some(item.clone()), _ => None, }, _ => None, }; - Ok(if let Some(meta) = meta { + Ok(if let Some(item) = item { self.bump(); - (meta.path, meta.kind.tokens(meta.span)) + item } else { let path = self.parse_path(PathStyle::Mod)?; let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) || @@ -205,7 +205,7 @@ impl<'a> Parser<'a> { } else { TokenStream::empty() }; - (path, tokens) + ast::AttrItem { path, tokens } }) } @@ -273,9 +273,14 @@ impl<'a> Parser<'a> { _ => None, }; - if let Some(meta) = nt_meta { - self.bump(); - return Ok(meta); + if let Some(item) = nt_meta { + return match item.meta(item.path.span) { + Some(meta) => { + self.bump(); + Ok(meta) + } + None => self.unexpected(), + } } let lo = self.token.span; diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs index 463ae9124ca..ca823991a2e 100644 --- a/src/libsyntax/parse/parser/path.rs +++ b/src/libsyntax/parse/parser/path.rs @@ -114,9 +114,9 @@ impl<'a> Parser<'a> { pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> { let meta_ident = match self.token.kind { token::Interpolated(ref nt) => match **nt { - token::NtMeta(ref meta) => match meta.kind { - ast::MetaItemKind::Word => Some(meta.path.clone()), - _ => None, + token::NtMeta(ref item) => match item.tokens.is_empty() { + true => Some(item.path.clone()), + false => None, }, _ => None, }, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index fe3b51aa246..fd78a2bd534 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -687,7 +687,7 @@ pub enum Nonterminal { NtLifetime(ast::Ident), NtLiteral(P), /// Stuff inside brackets for attributes - NtMeta(ast::MetaItem), + NtMeta(ast::AttrItem), NtPath(ast::Path), NtVis(ast::Visibility), NtTT(TokenTree), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 4b9c2d13f26..7d4ffe493d7 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -324,7 +324,7 @@ fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String { crate fn nonterminal_to_string(nt: &Nonterminal) -> String { match *nt { token::NtExpr(ref e) => expr_to_string(e), - token::NtMeta(ref e) => meta_item_to_string(e), + token::NtMeta(ref e) => attr_item_to_string(e), token::NtTy(ref e) => ty_to_string(e), token::NtPath(ref e) => path_to_string(e), token::NtItem(ref e) => item_to_string(e), @@ -412,8 +412,8 @@ pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String { to_string(|s| s.print_meta_list_item(li)) } -pub fn meta_item_to_string(mi: &ast::MetaItem) -> String { - to_string(|s| s.print_meta_item(mi)) +fn attr_item_to_string(ai: &ast::AttrItem) -> String { + to_string(|s| s.print_attr_item(ai, ai.path.span)) } pub fn attribute_to_string(attr: &ast::Attribute) -> String { @@ -629,24 +629,28 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere ast::AttrStyle::Inner => self.word("#!["), ast::AttrStyle::Outer => self.word("#["), } - self.ibox(0); - match attr.tokens.trees().next() { - Some(TokenTree::Delimited(_, delim, tts)) => { - self.print_mac_common( - Some(MacHeader::Path(&attr.path)), false, None, delim, tts, true, attr.span - ); - } - tree => { - self.print_path(&attr.path, false, 0); - if tree.is_some() { - self.space(); - self.print_tts(attr.tokens.clone(), true); - } + self.print_attr_item(&attr.item, attr.span); + self.word("]"); + } + } + + fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) { + self.ibox(0); + match item.tokens.trees().next() { + Some(TokenTree::Delimited(_, delim, tts)) => { + self.print_mac_common( + Some(MacHeader::Path(&item.path)), false, None, delim, tts, true, span + ); + } + tree => { + self.print_path(&item.path, false, 0); + if tree.is_some() { + self.space(); + self.print_tts(item.tokens.clone(), true); } } - self.end(); - self.word("]"); } + self.end(); } fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) { diff --git a/src/libsyntax_ext/cmdline_attrs.rs b/src/libsyntax_ext/cmdline_attrs.rs index bb8e3df3db9..203c4a83489 100644 --- a/src/libsyntax_ext/cmdline_attrs.rs +++ b/src/libsyntax_ext/cmdline_attrs.rs @@ -1,6 +1,6 @@ //! Attributes injected into the crate root from command line using `-Z crate-attr`. -use syntax::ast::{self, AttrStyle}; +use syntax::ast::{self, AttrItem, AttrStyle}; use syntax::attr::mk_attr; use syntax::panictry; use syntax::parse::{self, token, ParseSess}; @@ -15,7 +15,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - ); let start_span = parser.token.span; - let (path, tokens) = panictry!(parser.parse_meta_item_unrestricted()); + let AttrItem { path, tokens } = panictry!(parser.parse_attr_item()); let end_span = parser.token.span; if parser.token != token::Eof { parse_sess.span_diagnostic diff --git a/src/test/ui/cfg/cfg_stmt_expr.rs b/src/test/ui/cfg/cfg_stmt_expr.rs index e466ad69f72..6381bb2d588 100644 --- a/src/test/ui/cfg/cfg_stmt_expr.rs +++ b/src/test/ui/cfg/cfg_stmt_expr.rs @@ -57,7 +57,7 @@ fn main() { // check that macro expanded code works macro_rules! if_cfg { - ($cfg:meta $ib:block else $eb:block) => { + ($cfg:meta? $ib:block else $eb:block) => { { let r; #[cfg($cfg)] @@ -69,7 +69,7 @@ fn main() { } } - let n = if_cfg!(unset { + let n = if_cfg!(unset? { 413 } else { 612 diff --git a/src/test/ui/macros/macro-first-set.rs b/src/test/ui/macros/macro-first-set.rs index 34529cdaa64..eb2504d4bfd 100644 --- a/src/test/ui/macros/macro-first-set.rs +++ b/src/test/ui/macros/macro-first-set.rs @@ -252,12 +252,6 @@ test_path!(::std); test_path!(std::u8,); test_path!(any, super, super::super::self::path, X::Z<'a, T=U>); -macro_rules! test_meta_block { - ($($m:meta)* $b:block) => {}; -} - -test_meta_block!(windows {}); - macro_rules! test_lifetime { (1. $($l:lifetime)* $($b:block)*) => {}; (2. $($b:block)* $($l:lifetime)*) => {}; -- cgit 1.4.1-3-g733a5 From 6ea4a52f47f3f66f9db9004d8ed55a819dd81523 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 1 Oct 2019 00:58:30 +0300 Subject: Address review comments --- src/libsyntax/ast.rs | 1 + src/libsyntax/parse/attr.rs | 4 ++-- src/test/ui/macros/macro-meta-items-modern.rs | 11 +++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/macros/macro-meta-items-modern.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e2c8e37e11c..023952042e6 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2156,6 +2156,7 @@ pub struct Attribute { pub span: Span, } +// Compatibility impl to avoid churn, consider removing. impl std::ops::Deref for Attribute { type Target = AttrItem; fn deref(&self) -> &Self::Target { &self.item } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index f3298b6a65d..e74f3045db8 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -166,7 +166,7 @@ impl<'a> Parser<'a> { /// PATH `[` TOKEN_STREAM `]` /// PATH `{` TOKEN_STREAM `}` /// PATH - /// PATH `=` TOKEN_TREE + /// PATH `=` UNSUFFIXED_LIT /// The delimiters or `=` are still put into the resulting token stream. pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { let item = match self.token.kind { @@ -262,7 +262,7 @@ impl<'a> Parser<'a> { /// Matches the following grammar (per RFC 1559). /// - /// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; + /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { let nt_meta = match self.token.kind { diff --git a/src/test/ui/macros/macro-meta-items-modern.rs b/src/test/ui/macros/macro-meta-items-modern.rs new file mode 100644 index 00000000000..bc6938d4a6c --- /dev/null +++ b/src/test/ui/macros/macro-meta-items-modern.rs @@ -0,0 +1,11 @@ +// check-pass + +macro_rules! check { ($meta:meta) => () } + +check!(meta(a b c d)); +check!(meta[a b c d]); +check!(meta { a b c d }); +check!(meta); +check!(meta = 0); + +fn main() {} -- cgit 1.4.1-3-g733a5