diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 9258b59f79be8..f15e626c2783b 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{self, Attribute, Name, NodeId, PatKind}; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::ptr::P; use rustc_ast::token; -use rustc_ast::tokenstream::{self, TokenStream}; +use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability}; use rustc_data_structures::fx::FxHashMap; @@ -118,6 +118,31 @@ impl Annotatable { } } + crate fn into_tokens(self) -> TokenStream { + // `Annotatable` can be converted into tokens directly, but we + // are packing it into a nonterminal as a piece of AST to make + // the produced token stream look nicer in pretty-printed form. + let nt = match self { + Annotatable::Item(item) => token::NtItem(item), + Annotatable::TraitItem(item) | Annotatable::ImplItem(item) => { + token::NtItem(P(item.and_then(ast::AssocItem::into_item))) + } + Annotatable::ForeignItem(item) => { + token::NtItem(P(item.and_then(ast::ForeignItem::into_item))) + } + Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), + Annotatable::Expr(expr) => token::NtExpr(expr), + Annotatable::Arm(..) + | Annotatable::Field(..) + | Annotatable::FieldPat(..) + | Annotatable::GenericParam(..) + | Annotatable::Param(..) + | Annotatable::StructField(..) + | Annotatable::Variant(..) => panic!("unexpected annotatable"), + }; + TokenTree::token(token::Interpolated(Lrc::new(nt)), DUMMY_SP).into() + } + pub fn expect_item(self) -> P { match self { Annotatable::Item(i) => i, diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index b16659725db73..effa89e8bfb21 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -10,12 +10,11 @@ use rustc_ast::ast::{ItemKind, MacArgs, MacStmtStyle, StmtKind}; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::token; -use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::map_in_place::MapInPlace; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; -use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; use rustc_parse::configure; @@ -668,38 +667,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { SyntaxExtensionKind::Attr(expander) => { self.gate_proc_macro_input(&item); self.gate_proc_macro_attr_item(span, &item); - // `Annotatable` can be converted into tokens directly, but we are packing it - // into a nonterminal as a piece of AST to make the produced token stream - // look nicer in pretty-printed form. This may be no longer necessary. - let item_tok = TokenTree::token( - token::Interpolated(Lrc::new(match item { - Annotatable::Item(item) => token::NtItem(item), - Annotatable::TraitItem(item) | Annotatable::ImplItem(item) => { - token::NtItem(P(item.and_then(ast::AssocItem::into_item))) - } - Annotatable::ForeignItem(item) => { - token::NtItem(P(item.and_then(ast::ForeignItem::into_item))) - } - Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), - Annotatable::Expr(expr) => token::NtExpr(expr), - Annotatable::Arm(..) - | Annotatable::Field(..) - | Annotatable::FieldPat(..) - | Annotatable::GenericParam(..) - | Annotatable::Param(..) - | Annotatable::StructField(..) - | Annotatable::Variant(..) => panic!("unexpected annotatable"), - })), - DUMMY_SP, - ) - .into(); - let item = attr.unwrap_normal_item(); - if let MacArgs::Eq(..) = item.args { + let tokens = item.into_tokens(); + let attr_item = attr.unwrap_normal_item(); + if let MacArgs::Eq(..) = attr_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) + expander.expand(self.cx, span, attr_item.args.inner_tokens(), tokens); + self.parse_ast_fragment(tok_result, fragment_kind, &attr_item.path, span) } SyntaxExtensionKind::LegacyAttr(expander) => { match validate_attr::parse_meta(self.cx.parse_sess, &attr) {