From a81804b4d5f222f94758139b504aa2570528f9f1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 1 Dec 2019 02:25:32 +0300 Subject: syntax: Introduce a struct `MacArgs` for macro arguments --- src/libsyntax_ext/assert.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'src/libsyntax_ext') diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs index c4f3c03813f..9b9b7fd386f 100644 --- a/src/libsyntax_ext/assert.rs +++ b/src/libsyntax_ext/assert.rs @@ -6,7 +6,7 @@ use syntax::token::{self, TokenKind}; use syntax::print::pprust; use syntax::ptr::P; use syntax::symbol::{sym, Symbol}; -use syntax::tokenstream::{TokenStream, TokenTree}; +use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree}; use syntax_expand::base::*; use syntax_pos::{Span, DUMMY_SP}; @@ -26,18 +26,19 @@ pub fn expand_assert<'cx>( // `core::panic` and `std::panic` are different macros, so we use call-site // context to pick up whichever is currently in scope. let sp = cx.with_call_site_ctxt(sp); + let tokens = custom_message.unwrap_or_else(|| { + TokenStream::from(TokenTree::token( + TokenKind::lit(token::Str, Symbol::intern(&format!( + "assertion failed: {}", + pprust::expr_to_string(&cond_expr).escape_debug() + )), None), + DUMMY_SP, + )) + }); + let args = P(MacArgs::Delimited(DelimSpan::from_single(sp), MacDelimiter::Parenthesis, tokens)); let panic_call = Mac { path: Path::from_ident(Ident::new(sym::panic, sp)), - tts: custom_message.unwrap_or_else(|| { - TokenStream::from(TokenTree::token( - TokenKind::lit(token::Str, Symbol::intern(&format!( - "assertion failed: {}", - pprust::expr_to_string(&cond_expr).escape_debug() - )), None), - DUMMY_SP, - )) - }).into(), - delim: MacDelimiter::Parenthesis, + args, span: sp, prior_type_ascription: None, }; -- cgit 1.4.1-3-g733a5 From 0fac56717a1bce4e362d91d8f4e71d65676d49a3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 1 Dec 2019 15:55:32 +0300 Subject: syntax: Remove redundant span from `ast::Mac` Also remove a couple of redundant `visit_mac` asserts --- src/librustc_parse/parser/expr.rs | 1 - src/librustc_parse/parser/item.rs | 5 ----- src/librustc_parse/parser/pat.rs | 5 ++--- src/librustc_parse/parser/stmt.rs | 3 +-- src/librustc_parse/parser/ty.rs | 1 - src/librustc_passes/ast_validation.rs | 8 -------- src/librustc_save_analysis/dump_visitor.rs | 8 -------- src/libsyntax/ast.rs | 21 ++++++++++++++------- src/libsyntax/mut_visit.rs | 3 +-- src/libsyntax/print/pprust.rs | 4 ++-- src/libsyntax/tokenstream.rs | 8 ++++++++ src/libsyntax_expand/expand.rs | 4 ++-- src/libsyntax_expand/parse/tests.rs | 2 +- src/libsyntax_expand/placeholders.rs | 1 - src/libsyntax_ext/assert.rs | 1 - src/libsyntax_ext/deriving/generic/mod.rs | 15 +++------------ 16 files changed, 34 insertions(+), 56 deletions(-) (limited to 'src/libsyntax_ext') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index a6629aef1ee..1112274dc46 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -927,7 +927,6 @@ impl<'a> Parser<'a> { ex = ExprKind::Mac(Mac { path, args, - span: lo.to(hi), prior_type_ascription: self.last_type_ascription, }); } else if self.check(&token::OpenDelim(token::Brace)) { diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 9bf5ae3cc5a..9f3f6414b3e 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -432,8 +432,6 @@ impl<'a> Parser<'a> { let prev_span = self.prev_span; self.complain_if_pub_macro(&visibility.node, prev_span); - let mac_lo = self.token.span; - // Item macro let path = self.parse_path(PathStyle::Mod)?; self.expect(&token::Not)?; @@ -446,7 +444,6 @@ impl<'a> Parser<'a> { let mac = Mac { path, args, - span: mac_lo.to(hi), prior_type_ascription: self.last_type_ascription, }; let item = @@ -499,7 +496,6 @@ impl<'a> Parser<'a> { if self.token.is_path_start() && !(self.is_async_fn() && self.token.span.rust_2015()) { let prev_span = self.prev_span; - let lo = self.token.span; let path = self.parse_path(PathStyle::Mod)?; if path.segments.len() == 1 { @@ -525,7 +521,6 @@ impl<'a> Parser<'a> { Ok(Some(Mac { path, args, - span: lo.to(self.prev_span), prior_type_ascription: self.last_type_ascription, })) } else { diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs index c16b5f5574a..1127c4b2d5f 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/src/librustc_parse/parser/pat.rs @@ -338,7 +338,7 @@ impl<'a> Parser<'a> { (None, self.parse_path(PathStyle::Expr)?) }; match self.token.kind { - token::Not if qself.is_none() => self.parse_pat_mac_invoc(lo, path)?, + token::Not if qself.is_none() => self.parse_pat_mac_invoc(path)?, token::DotDotDot | token::DotDotEq | token::DotDot => { self.parse_pat_range_starting_with_path(lo, qself, path)? } @@ -593,13 +593,12 @@ impl<'a> Parser<'a> { } /// Parse macro invocation - fn parse_pat_mac_invoc(&mut self, lo: Span, path: Path) -> PResult<'a, PatKind> { + fn parse_pat_mac_invoc(&mut self, path: Path) -> PResult<'a, PatKind> { self.bump(); let args = self.parse_mac_args()?; let mac = Mac { path, args, - span: lo.to(self.prev_span), prior_type_ascription: self.last_type_ascription, }; Ok(PatKind::Mac(mac)) diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index 68c85ad8abf..b952e8814a3 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -106,7 +106,6 @@ impl<'a> Parser<'a> { let mac = Mac { path, args, - span: lo.to(hi), prior_type_ascription: self.last_type_ascription, }; let kind = if delim == token::Brace || @@ -130,7 +129,7 @@ impl<'a> Parser<'a> { self.warn_missing_semicolon(); StmtKind::Mac(P((mac, style, attrs.into()))) } else { - let e = self.mk_expr(mac.span, ExprKind::Mac(mac), ThinVec::new()); + let e = self.mk_expr(lo.to(hi), ExprKind::Mac(mac), ThinVec::new()); let e = self.maybe_recover_from_bad_qpath(e, true)?; let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 802bef525db..32142796905 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -181,7 +181,6 @@ impl<'a> Parser<'a> { let mac = Mac { path, args, - span: lo.to(self.prev_span), prior_type_ascription: self.last_type_ascription, }; TyKind::Mac(mac) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 5a29a56ad54..29cfee8408f 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -737,14 +737,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { |this| visit::walk_enum_def(this, enum_definition, generics, item_id)) } - fn visit_mac(&mut self, mac: &Mac) { - // when a new macro kind is added but the author forgets to set it up for expansion - // because that's the only part that won't cause a compiler error - self.session.diagnostic() - .span_bug(mac.span, "macro invocation missed in expansion; did you forget to override \ - the relevant `fold_*()` method in `PlaceholderExpander`?"); - } - fn visit_impl_item(&mut self, ii: &'a ImplItem) { if let ImplItemKind::Method(ref sig, _) = ii.kind { self.check_fn_decl(&sig.decl); diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 5bec5b5eb6b..396d9484339 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1515,14 +1515,6 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { } } - fn visit_mac(&mut self, mac: &'l ast::Mac) { - // These shouldn't exist in the AST at this point, log a span bug. - span_bug!( - mac.span, - "macro invocation should have been expanded out of AST" - ); - } - fn visit_pat(&mut self, p: &'l ast::Pat) { self.process_macro_use(p.span); self.process_pat(p); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 21126f8301a..c537d43a4d6 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1379,10 +1379,15 @@ pub enum Movability { pub struct Mac { pub path: Path, pub args: P, - pub span: Span, pub prior_type_ascription: Option<(Span, bool)>, } +impl Mac { + pub fn span(&self) -> Span { + self.path.span.to(self.args.span().unwrap_or(self.path.span)) + } +} + /// Arguments passed to an attribute or a function-like macro. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum MacArgs { @@ -1403,6 +1408,14 @@ impl MacArgs { } } + pub fn span(&self) -> Option { + match *self { + MacArgs::Empty => None, + MacArgs::Delimited(dspan, ..) => Some(dspan.entire()), + MacArgs::Eq(eq_span, ref tokens) => Some(eq_span.to(tokens.span().unwrap_or(eq_span))), + } + } + /// Tokens inside the delimiters or after `=`. /// Proc macros see these tokens, for example. pub fn inner_tokens(&self) -> TokenStream { @@ -1432,12 +1445,6 @@ impl MacArgs { } } -impl Mac { - pub fn stream(&self) -> TokenStream { - self.args.inner_tokens() - } -} - #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] pub enum MacDelimiter { Parenthesis, diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 7c86fc5cba5..2651c467734 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -580,10 +580,9 @@ pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { } pub fn noop_visit_mac(mac: &mut Mac, vis: &mut T) { - let Mac { path, args, span, prior_type_ascription: _ } = mac; + let Mac { path, args, prior_type_ascription: _ } = mac; vis.visit_path(path); visit_mac_args(args, vis); - vis.visit_span(span); } pub fn noop_visit_macro_def(macro_def: &mut MacroDef, vis: &mut T) { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 416704e255e..cb68fe8f4ff 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1772,9 +1772,9 @@ impl<'a> State<'a> { true, None, m.args.delim(), - m.stream(), + m.args.inner_tokens(), true, - m.span, + m.span(), ); } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 6a0523dd655..491b9a9ade4 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -225,6 +225,14 @@ impl TokenStream { self.0.len() } + pub fn span(&self) -> Option { + match &**self.0 { + [] => None, + [(tt, _)] => Some(tt.span()), + [(tt_start, _), .., (tt_end, _)] => Some(tt_start.span().to(tt_end.span())), + } + } + pub fn from_streams(mut streams: SmallVec<[TokenStream; 2]>) -> TokenStream { match streams.len() { 0 => TokenStream::default(), diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index a6ced1439c5..f1071cea9ab 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -597,13 +597,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> { InvocationKind::Bang { mac, .. } => match ext { SyntaxExtensionKind::Bang(expander) => { self.gate_proc_macro_expansion_kind(span, fragment_kind); - let tok_result = expander.expand(self.cx, span, mac.stream()); + let tok_result = expander.expand(self.cx, span, mac.args.inner_tokens()); self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span) } SyntaxExtensionKind::LegacyBang(expander) => { let prev = self.cx.current_expansion.prior_type_ascription; self.cx.current_expansion.prior_type_ascription = mac.prior_type_ascription; - let tok_result = expander.expand(self.cx, span, mac.stream()); + let tok_result = expander.expand(self.cx, span, mac.args.inner_tokens()); let result = if let Some(result) = fragment_kind.make_from(tok_result) { result } else { diff --git a/src/libsyntax_expand/parse/tests.rs b/src/libsyntax_expand/parse/tests.rs index 08950ddefba..30e83c151e2 100644 --- a/src/libsyntax_expand/parse/tests.rs +++ b/src/libsyntax_expand/parse/tests.rs @@ -272,7 +272,7 @@ fn ttdelim_span() { "foo!( fn main() { body } )".to_string(), &sess).unwrap(); let tts: Vec<_> = match expr.kind { - ast::ExprKind::Mac(ref mac) => mac.stream().trees().collect(), + ast::ExprKind::Mac(ref mac) => mac.args.inner_tokens().trees().collect(), _ => panic!("not a macro"), }; diff --git a/src/libsyntax_expand/placeholders.rs b/src/libsyntax_expand/placeholders.rs index 11fe860fc81..74ade1de20e 100644 --- a/src/libsyntax_expand/placeholders.rs +++ b/src/libsyntax_expand/placeholders.rs @@ -17,7 +17,6 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId, vis: Option( let panic_call = Mac { path: Path::from_ident(Ident::new(sym::panic, sp)), args, - span: sp, prior_type_ascription: None, }; let if_expr = cx.expr_if( diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index b6bf2f88161..5bd84b43a78 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -340,14 +340,12 @@ pub fn combine_substructure(f: CombineSubstructureFunc<'_>) fn find_type_parameters( ty: &ast::Ty, ty_param_names: &[ast::Name], - span: Span, cx: &ExtCtxt<'_>, ) -> Vec> { use syntax::visit; struct Visitor<'a, 'b> { cx: &'a ExtCtxt<'b>, - span: Span, ty_param_names: &'a [ast::Name], types: Vec>, } @@ -366,18 +364,11 @@ fn find_type_parameters( } fn visit_mac(&mut self, mac: &ast::Mac) { - let span = mac.span.with_ctxt(self.span.ctxt()); - self.cx.span_err(span, "`derive` cannot be used on items with type macros"); + self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros"); } } - let mut visitor = Visitor { - ty_param_names, - types: Vec::new(), - span, - cx, - }; - + let mut visitor = Visitor { cx, ty_param_names, types: Vec::new() }; visit::Visitor::visit_ty(&mut visitor, ty); visitor.types @@ -605,7 +596,7 @@ impl<'a> TraitDef<'a> { .collect(); for field_ty in field_tys { - let tys = find_type_parameters(&field_ty, &ty_param_names, self.span, cx); + let tys = find_type_parameters(&field_ty, &ty_param_names, cx); for ty in tys { // if we have already handled this type, skip it -- cgit 1.4.1-3-g733a5 From 1a496f33796d848609e06604445e28056954f412 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 1 Dec 2019 17:07:38 +0300 Subject: syntax: Use `ast::MacArgs` for attributes --- src/librustc/hir/lowering.rs | 12 +++++++- src/librustc_parse/config.rs | 2 +- src/librustc_parse/lib.rs | 4 +-- src/librustc_parse/parser/attr.rs | 30 ++---------------- src/librustc_parse/parser/mod.rs | 11 +++---- src/librustc_parse/parser/path.rs | 7 +++-- src/librustc_parse/validate_attr.rs | 12 +++----- src/libsyntax/ast.rs | 8 ++--- src/libsyntax/attr/mod.rs | 42 +++++++++++++++++--------- src/libsyntax/mut_visit.rs | 8 ++--- src/libsyntax/print/pprust.rs | 25 +++++++++------ src/libsyntax/visit.rs | 10 +++++- src/libsyntax_expand/expand.rs | 28 +++++------------ src/libsyntax_expand/proc_macro.rs | 4 +-- src/libsyntax_ext/cmdline_attrs.rs | 4 +-- src/test/ui/proc-macro/proc-macro-gates.rs | 2 +- src/test/ui/proc-macro/proc-macro-gates.stderr | 2 +- 17 files changed, 102 insertions(+), 109 deletions(-) (limited to 'src/libsyntax_ext') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index ac8173f101a..e13f6cabb52 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1003,7 +1003,7 @@ impl<'a> LoweringContext<'a> { AttrKind::Normal(ref item) => { AttrKind::Normal(AttrItem { path: item.path.clone(), - tokens: self.lower_token_stream(item.tokens.clone()), + args: self.lower_mac_args(&item.args), }) } AttrKind::DocComment(comment) => AttrKind::DocComment(comment) @@ -1017,6 +1017,16 @@ impl<'a> LoweringContext<'a> { } } + fn lower_mac_args(&mut self, args: &MacArgs) -> MacArgs { + match *args { + MacArgs::Empty => MacArgs::Empty, + MacArgs::Delimited(dspan, delim, ref tokens) => + MacArgs::Delimited(dspan, delim, self.lower_token_stream(tokens.clone())), + MacArgs::Eq(eq_span, ref tokens) => + MacArgs::Eq(eq_span, self.lower_token_stream(tokens.clone())), + } + } + fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream { tokens .into_trees() diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs index 26e51e83d62..1bf6e9ecbc0 100644 --- a/src/librustc_parse/config.rs +++ b/src/librustc_parse/config.rs @@ -101,7 +101,7 @@ impl<'a> StripUnconfigured<'a> { if !attr.has_name(sym::cfg_attr) { return vec![attr]; } - if attr.get_normal_item().tokens.is_empty() { + if let ast::MacArgs::Empty = attr.get_normal_item().args { self.sess.span_diagnostic .struct_span_err( attr.span, diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 1215c7a199a..3924da5ca67 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -277,7 +277,7 @@ pub fn parse_in_attr<'a, T>( ) -> PResult<'a, T> { let mut parser = Parser::new( sess, - attr.get_normal_item().tokens.clone(), + attr.get_normal_item().args.outer_tokens(), None, false, false, @@ -409,7 +409,7 @@ fn prepend_attrs( brackets.push(stream); } - brackets.push(item.tokens.clone()); + brackets.push(item.args.outer_tokens()); // The span we list here for `#` and for `[ ... ]` are both wrong in // that it encompasses more than each token, but it hopefully is "good diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs index a0f535a4b95..c7261404f54 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/src/librustc_parse/parser/attr.rs @@ -2,8 +2,7 @@ use super::{SeqSep, Parser, TokenType, PathStyle}; use syntax::attr; use syntax::ast; use syntax::util::comments; -use syntax::token::{self, Nonterminal, DelimToken}; -use syntax::tokenstream::{TokenStream, TokenTree}; +use syntax::token::{self, Nonterminal}; use syntax_pos::{Span, Symbol}; use errors::PResult; @@ -181,31 +180,8 @@ impl<'a> Parser<'a> { item } else { let path = self.parse_path(PathStyle::Mod)?; - let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) || - self.check(&token::OpenDelim(DelimToken::Bracket)) || - self.check(&token::OpenDelim(DelimToken::Brace)) { - self.parse_token_tree().into() - } else if self.eat(&token::Eq) { - let eq = TokenTree::token(token::Eq, self.prev_span); - let mut is_interpolated_expr = false; - if let token::Interpolated(nt) = &self.token.kind { - if let token::NtExpr(..) = **nt { - is_interpolated_expr = true; - } - } - let token_tree = if is_interpolated_expr { - // We need to accept arbitrary interpolated expressions to continue - // supporting things like `doc = $expr` that work on stable. - // Non-literal interpolated expressions are rejected after expansion. - self.parse_token_tree() - } else { - self.parse_unsuffixed_lit()?.token_tree() - }; - TokenStream::new(vec![eq.into(), token_tree.into()]) - } else { - TokenStream::default() - }; - ast::AttrItem { path, tokens } + let args = self.parse_attr_args()?; + ast::AttrItem { path, args } }) } diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 77bbf8bb941..a5cacc110ce 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -1011,16 +1011,15 @@ impl<'a> Parser<'a> { } fn parse_mac_args(&mut self) -> PResult<'a, P> { - self.parse_mac_args_common(true) + self.parse_mac_args_common(true).map(P) } - #[allow(dead_code)] - fn parse_attr_args(&mut self) -> PResult<'a, P> { + fn parse_attr_args(&mut self) -> PResult<'a, MacArgs> { self.parse_mac_args_common(false) } - fn parse_mac_args_common(&mut self, delimited_only: bool) -> PResult<'a, P> { - Ok(P(if self.check(&token::OpenDelim(DelimToken::Paren)) || + fn parse_mac_args_common(&mut self, delimited_only: bool) -> PResult<'a, MacArgs> { + Ok(if self.check(&token::OpenDelim(DelimToken::Paren)) || self.check(&token::OpenDelim(DelimToken::Bracket)) || self.check(&token::OpenDelim(DelimToken::Brace)) { match self.parse_token_tree() { @@ -1052,7 +1051,7 @@ impl<'a> Parser<'a> { } } else { return self.unexpected(); - })) + }) } fn parse_or_use_outer_attributes( diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 68307440712..75bb67d47bc 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -2,6 +2,7 @@ use super::{Parser, TokenType}; use crate::maybe_whole; use syntax::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs}; use syntax::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode}; +use syntax::ast::MacArgs; use syntax::ThinVec; use syntax::token::{self, Token}; use syntax::source_map::{Span, BytePos}; @@ -114,9 +115,9 @@ impl<'a> Parser<'a> { 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 item) => match item.tokens.is_empty() { - true => Some(item.path.clone()), - false => None, + token::NtMeta(ref item) => match item.args { + MacArgs::Empty => Some(item.path.clone()), + _ => None, }, _ => None, }, diff --git a/src/librustc_parse/validate_attr.rs b/src/librustc_parse/validate_attr.rs index a3c9e266593..0fb348efece 100644 --- a/src/librustc_parse/validate_attr.rs +++ b/src/librustc_parse/validate_attr.rs @@ -2,11 +2,9 @@ use errors::{PResult, Applicability}; use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP}; -use syntax::ast::{self, Attribute, AttrKind, Ident, MetaItem, MetaItemKind}; +use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MetaItem, MetaItemKind}; use syntax::attr::mk_name_value_item_str; use syntax::early_buffered_lints::BufferedEarlyLintId; -use syntax::token; -use syntax::tokenstream::TokenTree; use syntax::sess::ParseSess; use syntax_pos::{Symbol, sym}; @@ -19,11 +17,9 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. Some((name, _, template, _)) if name != sym::rustc_dummy => check_builtin_attribute(sess, attr, name, template), - _ => if let Some(TokenTree::Token(token)) = attr.get_normal_item().tokens.trees().next() { - if token == token::Eq { - // All key-value attributes are restricted to meta-item syntax. - parse_meta(sess, attr).map_err(|mut err| err.emit()).ok(); - } + _ => if let MacArgs::Eq(..) = attr.get_normal_item().args { + // All key-value attributes are restricted to meta-item syntax. + parse_meta(sess, attr).map_err(|mut err| err.emit()).ok(); } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c537d43a4d6..045b66b1734 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1389,7 +1389,7 @@ impl Mac { } /// Arguments passed to an attribute or a function-like macro. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub enum MacArgs { /// No arguments - `#[attr]`. Empty, @@ -1427,7 +1427,7 @@ impl MacArgs { } /// Tokens together with the delimiters or `=`. - /// Use of this functions generally means that something suspicious or hacky is happening. + /// Use of this functions generally means that something suboptimal or hacky is happening. pub fn outer_tokens(&self) -> TokenStream { match *self { MacArgs::Empty => TokenStream::default(), @@ -1445,7 +1445,7 @@ impl MacArgs { } } -#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub enum MacDelimiter { Parenthesis, Bracket, @@ -2384,7 +2384,7 @@ impl rustc_serialize::Decodable for AttrId { #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub struct AttrItem { pub path: Path, - pub tokens: TokenStream, + pub args: MacArgs, } /// Metadata associated with an item. diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 29eff5c2981..080c7209d6b 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -10,7 +10,7 @@ pub use crate::ast::Attribute; use crate::ast; use crate::ast::{AttrItem, AttrId, AttrKind, AttrStyle, Name, Ident, Path, PathSegment}; -use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; +use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; use crate::source_map::{BytePos, Spanned}; @@ -198,7 +198,7 @@ impl Attribute { pub fn is_word(&self) -> bool { if let AttrKind::Normal(item) = &self.kind { - item.tokens.is_empty() + matches!(item.args, MacArgs::Empty) } else { false } @@ -278,7 +278,7 @@ impl MetaItem { impl AttrItem { pub fn meta(&self, span: Span) -> Option { - let mut tokens = self.tokens.trees().peekable(); + let mut tokens = self.args.outer_tokens().trees().peekable(); Some(MetaItem { path: self.path.clone(), kind: if let Some(kind) = MetaItemKind::from_tokens(&mut tokens) { @@ -362,8 +362,8 @@ crate fn mk_attr_id() -> AttrId { AttrId(id) } -pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute { - mk_attr_from_item(style, AttrItem { path, tokens }, span) +pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute { + mk_attr_from_item(style, AttrItem { path, args }, span) } pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attribute { @@ -377,12 +377,12 @@ pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attrib /// Returns an inner attribute with the given value and span. pub fn mk_attr_inner(item: MetaItem) -> Attribute { - mk_attr(AttrStyle::Inner, item.path, item.kind.tokens(item.span), item.span) + mk_attr(AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span) } /// Returns an outer attribute with the given value and span. pub fn mk_attr_outer(item: MetaItem) -> Attribute { - mk_attr(AttrStyle::Outer, item.path, item.kind.tokens(item.span), item.span) + mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span) } pub fn mk_doc_comment(style: AttrStyle, comment: Symbol, span: Span) -> Attribute { @@ -520,7 +520,26 @@ impl MetaItem { } impl MetaItemKind { - pub fn token_trees_and_joints(&self, span: Span) -> Vec { + pub fn mac_args(&self, span: Span) -> MacArgs { + match self { + MetaItemKind::Word => MacArgs::Empty, + MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.token_tree().into()), + MetaItemKind::List(list) => { + let mut tts = Vec::new(); + for (i, item) in list.iter().enumerate() { + if i > 0 { + tts.push(TokenTree::token(token::Comma, span).into()); + } + tts.extend(item.token_trees_and_joints()) + } + MacArgs::Delimited( + DelimSpan::from_single(span), MacDelimiter::Parenthesis, TokenStream::new(tts) + ) + } + } + } + + fn token_trees_and_joints(&self, span: Span) -> Vec { match *self { MetaItemKind::Word => vec![], MetaItemKind::NameValue(ref lit) => { @@ -548,13 +567,6 @@ impl MetaItemKind { } } - // Premature conversions of `TokenTree`s to `TokenStream`s can hurt - // performance. Do not use this function if `token_trees_and_joints()` can - // be used instead. - pub fn tokens(&self, span: Span) -> TokenStream { - TokenStream::new(self.token_trees_and_joints(span)) - } - fn from_tokens(tokens: &mut iter::Peekable) -> Option where I: Iterator, { diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 2651c467734..8d345ee883d 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -570,9 +570,9 @@ pub fn noop_visit_local(local: &mut P, vis: &mut T) { pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { let Attribute { kind, id: _, style: _, span } = attr; match kind { - AttrKind::Normal(AttrItem { path, tokens }) => { + AttrKind::Normal(AttrItem { path, args }) => { vis.visit_path(path); - vis.visit_tts(tokens); + visit_mac_args(args, vis); } AttrKind::DocComment(_) => {} } @@ -701,9 +701,9 @@ 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(AttrItem { path, tokens }) => { + token::NtMeta(AttrItem { path, args }) => { vis.visit_path(path); - vis.visit_tts(tokens); + visit_mac_args(args, vis); } token::NtPath(path) => vis.visit_path(path), token::NtTT(tt) => vis.visit_tt(tt), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index cb68fe8f4ff..5ffe593a8b5 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1,6 +1,6 @@ use crate::ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; use crate::ast::{SelfKind, GenericBound, TraitBoundModifier}; -use crate::ast::{Attribute, GenericArg}; +use crate::ast::{Attribute, GenericArg, MacArgs}; use crate::util::parser::{self, AssocOp, Fixity}; use crate::util::comments; use crate::attr; @@ -639,17 +639,22 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere 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 => { + match &item.args { + MacArgs::Delimited(_, delim, tokens) => self.print_mac_common( + Some(MacHeader::Path(&item.path)), + false, + None, + delim.to_token(), + tokens.clone(), + true, + span, + ), + MacArgs::Empty | MacArgs::Eq(..) => { self.print_path(&item.path, false, 0); - if tree.is_some() { + if let MacArgs::Eq(_, tokens) = &item.args { self.space(); - self.print_tts(item.tokens.clone(), true); + self.word_space("="); + self.print_tts(tokens.clone(), true); } } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 5ff337fb60e..4ee09b4b87a 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -841,11 +841,19 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) { match attr.kind { - AttrKind::Normal(ref item) => visitor.visit_tts(item.tokens.clone()), + AttrKind::Normal(ref item) => walk_mac_args(visitor, &item.args), AttrKind::DocComment(_) => {} } } +pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) { + match args { + MacArgs::Empty => {} + MacArgs::Delimited(_dspan, _delim, tokens) => visitor.visit_tts(tokens.clone()), + MacArgs::Eq(_eq_span, tokens) => visitor.visit_tts(tokens.clone()), + } +} + pub fn walk_tt<'a, V: Visitor<'a>>(visitor: &mut V, tt: TokenTree) { match tt { TokenTree::Token(token) => visitor.visit_token(token), diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index f1071cea9ab..9bfedb3b617 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -11,7 +11,7 @@ use rustc_parse::DirectoryOwnership; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; use syntax::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path}; -use syntax::ast::{MacStmtStyle, StmtKind, ItemKind}; +use syntax::ast::{MacArgs, MacStmtStyle, StmtKind, ItemKind}; use syntax::attr::{self, HasAttrs, is_builtin_attr}; use syntax::source_map::respan; use syntax::feature_gate::{self, feature_err}; @@ -642,8 +642,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { => panic!("unexpected annotatable"), })), DUMMY_SP).into(); let item = attr.unwrap_normal_item(); - let input = self.extract_proc_macro_attr_input(item.tokens, span); - let tok_result = expander.expand(self.cx, span, input, item_tok); + if let MacArgs::Eq(..) = item.args { + self.cx.span_err(span, "key-value macro attributes are not supported"); + } + let tok_result = + expander.expand(self.cx, span, item.args.inner_tokens(), item_tok); self.parse_ast_fragment(tok_result, fragment_kind, &item.path, span) } SyntaxExtensionKind::LegacyAttr(expander) => { @@ -687,23 +690,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - fn extract_proc_macro_attr_input(&self, tokens: TokenStream, span: Span) -> TokenStream { - let mut trees = tokens.trees(); - match trees.next() { - Some(TokenTree::Delimited(_, _, tts)) => { - if trees.next().is_none() { - return tts.into() - } - } - Some(TokenTree::Token(..)) => {} - None => return TokenStream::default(), - } - self.cx.span_err(span, "custom attribute invocations must be \ - of the form `#[foo]` or `#[foo(..)]`, the macro name must only be \ - followed by a delimiter token"); - TokenStream::default() - } - fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) { let kind = match item { Annotatable::Item(item) => match &item.kind { @@ -1560,7 +1546,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items); *at = attr::Attribute { kind: ast::AttrKind::Normal( - AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, + AttrItem { path: meta.path, args: meta.kind.mac_args(meta.span) }, ), span: at.span, id: at.id, diff --git a/src/libsyntax_expand/proc_macro.rs b/src/libsyntax_expand/proc_macro.rs index 099cf0a4be9..8e56e2bb00b 100644 --- a/src/libsyntax_expand/proc_macro.rs +++ b/src/libsyntax_expand/proc_macro.rs @@ -1,7 +1,7 @@ use crate::base::{self, *}; use crate::proc_macro_server; -use syntax::ast::{self, ItemKind}; +use syntax::ast::{self, ItemKind, MacArgs}; use syntax::errors::{Applicability, FatalError}; use syntax::symbol::sym; use syntax::token; @@ -183,7 +183,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) } let parse_derive_paths = |attr: &ast::Attribute| { - if attr.get_normal_item().tokens.is_empty() { + if let MacArgs::Empty = attr.get_normal_item().args { return Ok(Vec::new()); } rustc_parse::parse_in_attr(cx.parse_sess, attr, |p| p.parse_derive_paths()) diff --git a/src/libsyntax_ext/cmdline_attrs.rs b/src/libsyntax_ext/cmdline_attrs.rs index 5c3009c432c..98cf8a34742 100644 --- a/src/libsyntax_ext/cmdline_attrs.rs +++ b/src/libsyntax_ext/cmdline_attrs.rs @@ -16,7 +16,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - ); let start_span = parser.token.span; - let AttrItem { path, tokens } = panictry!(parser.parse_attr_item()); + let AttrItem { path, args } = panictry!(parser.parse_attr_item()); let end_span = parser.token.span; if parser.token != token::Eof { parse_sess.span_diagnostic @@ -24,7 +24,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - continue; } - krate.attrs.push(mk_attr(AttrStyle::Inner, path, tokens, start_span.to(end_span))); + krate.attrs.push(mk_attr(AttrStyle::Inner, path, args, start_span.to(end_span))); } krate diff --git a/src/test/ui/proc-macro/proc-macro-gates.rs b/src/test/ui/proc-macro/proc-macro-gates.rs index 0096a84f14c..591c1e039bd 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.rs +++ b/src/test/ui/proc-macro/proc-macro-gates.rs @@ -18,7 +18,7 @@ mod _test2_inner { //~| ERROR: non-builtin inner attributes are unstable } -#[empty_attr = "y"] //~ ERROR: must only be followed by a delimiter token +#[empty_attr = "y"] //~ ERROR: key-value macro attributes are not supported fn _test3() {} fn attrs() { diff --git a/src/test/ui/proc-macro/proc-macro-gates.stderr b/src/test/ui/proc-macro/proc-macro-gates.stderr index 14a4f8c0fbc..e939434243b 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.stderr +++ b/src/test/ui/proc-macro/proc-macro-gates.stderr @@ -34,7 +34,7 @@ LL | #![empty_attr] = 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: custom attribute invocations must be of the form `#[foo]` or `#[foo(..)]`, the macro name must only be followed by a delimiter token +error: key-value macro attributes are not supported --> $DIR/proc-macro-gates.rs:21:1 | LL | #[empty_attr = "y"] -- cgit 1.4.1-3-g733a5