diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b7da276fc7e1d..c370bde6d019f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -14,7 +14,7 @@ //! - [`Generics`], [`GenericParam`], [`WhereClause`]: Metadata associated with generic parameters. //! - [`EnumDef`] and [`Variant`]: Enum declaration. //! - [`Lit`] and [`LitKind`]: Literal expressions. -//! - [`MacroDef`], [`MacStmtStyle`], [`MacCall`], [`MacDelimiter`]: Macro definition and invocation. +//! - [`MacroDef`], [`MacStmtStyle`], [`MacCall`], [`AttrMacDelimiter`]: Macro definition and invocation. //! - [`Attribute`]: Metadata associated with item. //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators. @@ -1521,80 +1521,58 @@ pub struct MacCall { impl MacCall { pub fn span(&self) -> Span { - self.path.span.to(self.args.span().unwrap_or(self.path.span)) + self.path.span.to(self.args.span()) } } -/// Arguments passed to an attribute or a function-like macro. +/// Arguments passed to a function-like macro. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] -pub enum MacArgs { - /// No arguments - `#[attr]`. - Empty, - /// Delimited arguments - `#[attr()/[]/{}]` or `mac!()/[]/{}`. - Delimited(DelimSpan, MacDelimiter, TokenStream), - /// Arguments of a key-value attribute - `#[attr = "value"]`. - Eq( - /// Span of the `=` token. - Span, - /// "value" as a nonterminal token. - Token, - ), -} +pub struct MacArgs(pub DelimSpan, pub AttrMacDelimiter, pub TokenStream); impl MacArgs { - pub fn delim(&self) -> DelimToken { - match self { - MacArgs::Delimited(_, delim, _) => delim.to_token(), - MacArgs::Empty | MacArgs::Eq(..) => token::NoDelim, - } + pub fn span(&self) -> Span { + self.0.entire() } - pub fn span(&self) -> Option { - match self { - MacArgs::Empty => None, - MacArgs::Delimited(dspan, ..) => Some(dspan.entire()), - MacArgs::Eq(eq_span, token) => Some(eq_span.to(token.span)), - } + pub fn delim(&self) -> DelimToken { + self.1.to_token() } /// Tokens inside the delimiters or after `=`. /// Proc macros see these tokens, for example. pub fn inner_tokens(&self) -> TokenStream { - match self { - MacArgs::Empty => TokenStream::default(), - MacArgs::Delimited(.., tokens) => tokens.clone(), - MacArgs::Eq(.., token) => TokenTree::Token(token.clone()).into(), - } + self.2.clone() } /// Whether a macro with these arguments needs a semicolon /// when used as a standalone item or statement. pub fn need_semicolon(&self) -> bool { - !matches!(self, MacArgs::Delimited(_, MacDelimiter::Brace, _)) + !matches!(self, MacArgs(_, AttrMacDelimiter::Brace, _)) } } +// This is used in both attributes and macro calls, hence the name. #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] -pub enum MacDelimiter { +pub enum AttrMacDelimiter { Parenthesis, Bracket, Brace, } -impl MacDelimiter { +impl AttrMacDelimiter { pub fn to_token(self) -> DelimToken { match self { - MacDelimiter::Parenthesis => DelimToken::Paren, - MacDelimiter::Bracket => DelimToken::Bracket, - MacDelimiter::Brace => DelimToken::Brace, + AttrMacDelimiter::Parenthesis => DelimToken::Paren, + AttrMacDelimiter::Bracket => DelimToken::Bracket, + AttrMacDelimiter::Brace => DelimToken::Brace, } } - pub fn from_token(delim: DelimToken) -> Option { + pub fn from_token(delim: DelimToken) -> Option { match delim { - token::Paren => Some(MacDelimiter::Parenthesis), - token::Bracket => Some(MacDelimiter::Bracket), - token::Brace => Some(MacDelimiter::Brace), + token::Paren => Some(AttrMacDelimiter::Parenthesis), + token::Bracket => Some(AttrMacDelimiter::Bracket), + token::Brace => Some(AttrMacDelimiter::Brace), token::NoDelim => None, } } @@ -2454,10 +2432,46 @@ impl rustc_serialize::Decodable for AttrId { #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct AttrItem { pub path: Path, - pub args: MacArgs, + pub args: AttrArgs, pub tokens: Option, } +/// Arguments passed to an attribute. +#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] +pub enum AttrArgs { + /// No arguments - `#[attr]`. + Empty, + /// Delimited arguments - `#[attr()/[]/{}]`. + Delimited(DelimSpan, AttrMacDelimiter, TokenStream), + /// Arguments of a key-value attribute - `#[attr = "value"]`. + Eq( + /// Span of the `=` token. + Span, + /// "value" as a nonterminal token. + Token, + ), +} + +impl AttrArgs { + pub fn span(&self) -> Option { + match self { + AttrArgs::Empty => None, + AttrArgs::Delimited(dspan, ..) => Some(dspan.entire()), + AttrArgs::Eq(eq_span, token) => Some(eq_span.to(token.span)), + } + } + + /// Tokens inside the delimiters or after `=`. + /// Proc macros see these tokens, for example. + pub fn inner_tokens(&self) -> TokenStream { + match self { + AttrArgs::Empty => TokenStream::default(), + AttrArgs::Delimited(.., tokens) => tokens.clone(), + AttrArgs::Eq(.., token) => TokenTree::Token(token.clone()).into(), + } + } +} + /// A list of attributes. pub type AttrVec = ThinVec; diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 80caf37d7099d..a049ab67c12ad 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -1,9 +1,9 @@ //! Functions dealing with attributes and meta items. use crate::ast; -use crate::ast::{AttrId, AttrItem, AttrKind, AttrStyle, Attribute}; +use crate::ast::{AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, Attribute}; +use crate::ast::{AttrMacDelimiter, MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Lit, LitKind}; -use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Path, PathSegment}; use crate::token::{self, CommentKind, Token}; use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree}; @@ -152,7 +152,7 @@ impl Attribute { pub fn is_word(&self) -> bool { if let AttrKind::Normal(item, _) = &self.kind { - matches!(item.args, MacArgs::Empty) + matches!(item.args, AttrArgs::Empty) } else { false } @@ -223,13 +223,13 @@ impl AttrItem { pub fn meta(&self, span: Span) -> Option { Some(MetaItem { path: self.path.clone(), - kind: MetaItemKind::from_mac_args(&self.args)?, + kind: MetaItemKind::from_attr_args(&self.args)?, span, }) } pub fn meta_kind(&self) -> Option { - MetaItemKind::from_mac_args(&self.args) + MetaItemKind::from_attr_args(&self.args) } } @@ -344,7 +344,7 @@ crate fn mk_attr_id() -> AttrId { AttrId::from_u32(id) } -pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute { +pub fn mk_attr(style: AttrStyle, path: Path, args: AttrArgs, span: Span) -> Attribute { mk_attr_from_item(AttrItem { path, args, tokens: None }, None, style, span) } @@ -359,12 +359,12 @@ pub fn mk_attr_from_item( /// 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.mac_args(item.span), item.span) + mk_attr(AttrStyle::Inner, item.path, item.kind.attr_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.mac_args(item.span), item.span) + mk_attr(AttrStyle::Outer, item.path, item.kind.attr_args(item.span), item.span) } pub fn mk_doc_comment( @@ -467,10 +467,10 @@ impl MetaItemKind { } } - pub fn mac_args(&self, span: Span) -> MacArgs { + pub fn attr_args(&self, span: Span) -> AttrArgs { match self { - MetaItemKind::Word => MacArgs::Empty, - MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.to_token()), + MetaItemKind::Word => AttrArgs::Empty, + MetaItemKind::NameValue(lit) => AttrArgs::Eq(span, lit.to_token()), MetaItemKind::List(list) => { let mut tts = Vec::new(); for (i, item) in list.iter().enumerate() { @@ -479,9 +479,9 @@ impl MetaItemKind { } tts.extend(item.token_trees_and_spacings()) } - MacArgs::Delimited( + AttrArgs::Delimited( DelimSpan::from_single(span), - MacDelimiter::Parenthesis, + AttrMacDelimiter::Parenthesis, TokenStream::new(tts), ) } @@ -545,14 +545,14 @@ impl MetaItemKind { } } - fn from_mac_args(args: &MacArgs) -> Option { + fn from_attr_args(args: &AttrArgs) -> Option { match args { - MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) => { + AttrArgs::Delimited(_, AttrMacDelimiter::Parenthesis, tokens) => { MetaItemKind::list_from_tokens(tokens.clone()) } - MacArgs::Delimited(..) => None, - MacArgs::Eq(_, token) => Lit::from_token(token).ok().map(MetaItemKind::NameValue), - MacArgs::Empty => Some(MetaItemKind::Word), + AttrArgs::Delimited(..) => None, + AttrArgs::Eq(_, token) => Lit::from_token(token).ok().map(MetaItemKind::NameValue), + AttrArgs::Empty => Some(MetaItemKind::Word), } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index cba49835f69cb..1563e17f4986d 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -363,14 +363,14 @@ pub fn visit_fn_sig(FnSig { header, decl, span }: &mut FnSig, vis } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_mac_args(args: &mut MacArgs, vis: &mut T) { +pub fn visit_attr_args(args: &mut AttrArgs, vis: &mut T) { match args { - MacArgs::Empty => {} - MacArgs::Delimited(dspan, _delim, tokens) => { + AttrArgs::Empty => {} + AttrArgs::Delimited(dspan, _delim, tokens) => { visit_delim_span(dspan, vis); visit_tts(tokens, vis); } - MacArgs::Eq(eq_span, token) => { + AttrArgs::Eq(eq_span, token) => { vis.visit_span(eq_span); if T::VISIT_TOKENS { visit_token(token, vis); @@ -389,6 +389,13 @@ pub fn visit_mac_args(args: &mut MacArgs, vis: &mut T) { } } +// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. +pub fn visit_mac_args(args: &mut MacArgs, vis: &mut T) { + let MacArgs(dspan, _delim, tokens) = args; + visit_delim_span(dspan, vis); + visit_tts(tokens, vis); +} + pub fn visit_delim_span(dspan: &mut DelimSpan, vis: &mut T) { vis.visit_span(&mut dspan.open); vis.visit_span(&mut dspan.close); @@ -602,7 +609,7 @@ pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { match kind { AttrKind::Normal(AttrItem { path, args, tokens }, attr_tokens) => { vis.visit_path(path); - visit_mac_args(args, vis); + visit_attr_args(args, vis); visit_lazy_tts(tokens, vis); visit_lazy_tts(attr_tokens, vis); } @@ -793,7 +800,7 @@ pub fn visit_interpolated(nt: &mut token::Nonterminal, vis: &mut token::NtMeta(item) => { let AttrItem { path, args, tokens } = item.deref_mut(); vis.visit_path(path); - visit_mac_args(args, vis); + visit_attr_args(args, vis); visit_lazy_tts(tokens, vis); } token::NtPath(path) => vis.visit_path(path), diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d925c6dd3549a..834074b4fb972 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -906,18 +906,18 @@ 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, ref _tokens) => walk_mac_args(visitor, &item.args), + AttrKind::Normal(ref item, ref _tokens) => walk_attr_args(visitor, &item.args), AttrKind::DocComment(..) => {} } } -pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) { +pub fn walk_attr_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a AttrArgs) { match args { - MacArgs::Empty => {} - MacArgs::Delimited(_dspan, _delim, _tokens) => {} + AttrArgs::Empty => {} + AttrArgs::Delimited(_dspan, _delim, _tokens) => {} // The value in `#[key = VALUE]` must be visited as an expression for backward // compatibility, so that macros can be expanded in that position. - MacArgs::Eq(_eq_span, token) => match &token.kind { + AttrArgs::Eq(_eq_span, token) => match &token.kind { token::Interpolated(nt) => match &**nt { token::NtExpr(expr) => visitor.visit_expr(expr), t => panic!("unexpected token in key-value attribute: {:?}", t), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9cb205074e7ea..dfb2e754d3b34 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -906,7 +906,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { AttrKind::Normal(ref item, _) => AttrKind::Normal( AttrItem { path: item.path.clone(), - args: self.lower_mac_args(&item.args), + args: self.lower_attr_args(&item.args), tokens: None, }, None, @@ -926,27 +926,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_mac_args(&self, args: &MacArgs) -> MacArgs { + fn lower_attr_args(&self, args: &AttrArgs) -> AttrArgs { match *args { - MacArgs::Empty => MacArgs::Empty, - MacArgs::Delimited(dspan, delim, ref tokens) => { - // This is either a non-key-value attribute, or a `macro_rules!` body. - // We either not have any nonterminals present (in the case of an attribute), - // or have tokens available for all nonterminals in the case of a nested - // `macro_rules`: e.g: - // - // ```rust - // macro_rules! outer { - // ($e:expr) => { - // macro_rules! inner { - // () => { $e } - // } - // } - // } - // ``` - // - // In both cases, we don't want to synthesize any tokens - MacArgs::Delimited( + AttrArgs::Empty => AttrArgs::Empty, + AttrArgs::Delimited(dspan, delim, ref tokens) => { + // This is a non-key-value attribute. We have no nonterminals presen, so we don't + // want to synthesize any tokens. + AttrArgs::Delimited( dspan, delim, self.lower_token_stream(tokens.clone(), CanSynthesizeMissingTokens::No), @@ -955,7 +941,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // This is an inert key-value attribute - it will never be visible to macros // after it gets lowered to HIR. Therefore, we can synthesize tokens with fake // spans to handle nonterminals in `#[doc]` (e.g. `#[doc = $e]`). - MacArgs::Eq(eq_span, ref token) => { + AttrArgs::Eq(eq_span, ref token) => { // In valid code the value is always representable as a single literal token. fn unwrap_single_token(sess: &Session, tokens: TokenStream, span: Span) -> Token { if tokens.len() != 1 { @@ -983,11 +969,34 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { nt_to_tokenstream: self.nt_to_tokenstream, } .process_token(token.clone()); - MacArgs::Eq(eq_span, unwrap_single_token(self.sess, tokens, token.span)) + AttrArgs::Eq(eq_span, unwrap_single_token(self.sess, tokens, token.span)) } } } + fn lower_mac_args(&self, args: &MacArgs) -> MacArgs { + let MacArgs(dspan, delim, ref tokens) = *args; + // This is a `macro_rules!` body. We tokens available for all nonterminals in the case of a + // nested `macro_rules`: e.g: + // + // ```rust + // macro_rules! outer { + // ($e:expr) => { + // macro_rules! inner { + // () => { $e } + // } + // } + // } + // ``` + // + // We don't want to synthesize any tokens. + MacArgs( + dspan, + delim, + self.lower_token_stream(tokens.clone(), CanSynthesizeMissingTokens::No), + ) + } + fn lower_token_stream( &self, tokens: TokenStream, diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3c9bb81bedb1c..9e856f660be05 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -11,10 +11,9 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle}; use rustc_ast::util::parser; -use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; +use rustc_ast::{self as ast, AttrArgs, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; use rustc_ast::{attr, Term}; -use rustc_ast::{GenericArg, MacArgs}; -use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier}; +use rustc_ast::{GenericArg, GenericBound, SelfKind, TraitBoundModifier}; use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_span::edition::Edition; @@ -460,7 +459,7 @@ 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.args { - MacArgs::Delimited(_, delim, tokens) => self.print_mac_common( + AttrArgs::Delimited(_, delim, tokens) => self.print_mac_common( Some(MacHeader::Path(&item.path)), false, None, @@ -469,14 +468,15 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere true, span, ), - MacArgs::Empty | MacArgs::Eq(..) => { + AttrArgs::Empty => { self.print_path(&item.path, false, 0); - if let MacArgs::Eq(_, token) = &item.args { - self.space(); - self.word_space("="); - let token_str = self.token_to_string_ext(token, true); - self.word(token_str); - } + } + AttrArgs::Eq(_, token) => { + self.print_path(&item.path, false, 0); + self.space(); + self.word_space("="); + let token_str = self.token_to_string_ext(token, true); + self.word(token_str); } } self.end(); diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index a984980dea9bf..57ebf641ec793 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -49,11 +49,7 @@ pub fn expand_assert<'cx>( sp, ExprKind::MacCall(MacCall { path, - args: P(MacArgs::Delimited( - DelimSpan::from_single(sp), - MacDelimiter::Parenthesis, - tokens, - )), + args: P(MacArgs(DelimSpan::from_single(sp), AttrMacDelimiter::Parenthesis, tokens)), prior_type_ascription: None, }), ) diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index ea0e768a58f48..63ace2097e5f5 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -58,11 +58,7 @@ fn expand<'cx>( .collect(), tokens: None, }, - args: P(MacArgs::Delimited( - DelimSpan::from_single(sp), - MacDelimiter::Parenthesis, - tts, - )), + args: P(MacArgs(DelimSpan::from_single(sp), AttrMacDelimiter::Parenthesis, tts)), prior_type_ascription: None, }), ), diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 9b224a733568b..1bda500c73fef 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -11,8 +11,8 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; -use rustc_ast::{AssocItemKind, AstLike, AstLikeWrapper, AttrStyle, ExprKind, ForeignItemKind}; -use rustc_ast::{Inline, ItemKind, MacArgs, MacStmtStyle, MetaItemKind, ModKind}; +use rustc_ast::{AssocItemKind, AstLike, AstLikeWrapper, AttrArgs, AttrStyle, ExprKind}; +use rustc_ast::{ForeignItemKind, Inline, ItemKind, MacStmtStyle, MetaItemKind, ModKind}; use rustc_ast::{NestedMetaItem, NodeId, PatKind, StmtKind, TyKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::map_in_place::MapInPlace; @@ -686,7 +686,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => item.into_tokens(&self.cx.sess.parse_sess), }; let attr_item = attr.unwrap_normal_item(); - if let MacArgs::Eq(..) = attr_item.args { + if let AttrArgs::Eq(..) = attr_item.args { self.cx.span_err(span, "key-value macro attributes are not supported"); } let inner_tokens = attr_item.args.inner_tokens(); diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 15af5fdc5f8e2..6b79b19844a70 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -18,7 +18,11 @@ pub fn placeholder( fn mac_placeholder() -> ast::MacCall { ast::MacCall { path: ast::Path { span: DUMMY_SP, segments: Vec::new(), tokens: None }, - args: P(ast::MacArgs::Empty), + args: P(ast::MacArgs( + ast::tokenstream::DelimSpan::dummy(), + ast::AttrMacDelimiter::Parenthesis, + ast::tokenstream::TokenStream::default(), + )), prior_type_ascription: None, } } diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 28c2a63db27f8..2dcff93c82aa4 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -339,7 +339,7 @@ pub fn parse_cfg_attr( parse_sess: &ParseSess, ) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { match attr.get_normal_item().args { - ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => { + ast::AttrArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => { let msg = "wrong `cfg_attr` delimiters"; crate::validate_attr::check_meta_bad_delim(parse_sess, dspan, delim, msg); match parse_in(parse_sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index ca81921faedcc..11d93805a19bb 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -8,10 +8,10 @@ use rustc_ast::token::{self, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID}; use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind}; +use rustc_ast::{AttrMacDelimiter, MacArgs, MacCall}; use rustc_ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind}; use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, VariantData}; use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind}; -use rustc_ast::{MacArgs, MacCall, MacDelimiter}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, PResult, StashKey}; use rustc_span::edition::Edition; @@ -1650,7 +1650,7 @@ impl<'a> Parser<'a> { let arrow = TokenTree::token(token::FatArrow, pspan.between(bspan)); // `=>` let tokens = TokenStream::new(vec![params.into(), arrow.into(), body.into()]); let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi()); - P(MacArgs::Delimited(dspan, MacDelimiter::Brace, tokens)) + P(MacArgs(dspan, AttrMacDelimiter::Brace, tokens)) } else { return self.unexpected(); }; @@ -1757,15 +1757,15 @@ impl<'a> Parser<'a> { } fn report_invalid_macro_expansion_item(&self, args: &MacArgs) { - let span = args.span().expect("undelimited macro call"); + let span = args.span(); let mut err = self.struct_span_err( span, "macros that expand to items must be delimited with braces or followed by a semicolon", ); if self.unclosed_delims.is_empty() { - let DelimSpan { open, close } = match args { - MacArgs::Empty | MacArgs::Eq(..) => unreachable!(), - MacArgs::Delimited(dspan, ..) => *dspan, + let DelimSpan { open, close } = { + let MacArgs(dspan, ..) = args; + *dspan }; err.multipart_suggestion( "change the delimiters to curly braces", diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index cb6be8f412cf5..d72a8359b2f1c 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -26,8 +26,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::AttrId; use rustc_ast::DUMMY_NODE_ID; use rustc_ast::{self as ast, AnonConst, AstLike, AttrStyle, AttrVec, Const, CrateSugar, Extern}; -use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit, Unsafe}; -use rustc_ast::{Visibility, VisibilityKind}; +use rustc_ast::{Async, AttrMacDelimiter, Expr, ExprKind, MacArgs, Mutability, StrLit, Unsafe}; +use rustc_ast::{AttrArgs, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; @@ -1162,28 +1162,42 @@ impl<'a> Parser<'a> { } fn parse_mac_args(&mut self) -> PResult<'a, P> { - self.parse_mac_args_common(true).map(P) - } - - fn parse_attr_args(&mut self) -> PResult<'a, MacArgs> { - self.parse_mac_args_common(false) + Ok(P( + if self.check(&token::OpenDelim(DelimToken::Paren)) + || self.check(&token::OpenDelim(DelimToken::Bracket)) + || self.check(&token::OpenDelim(DelimToken::Brace)) + { + match self.parse_token_tree() { + TokenTree::Delimited(dspan, delim, tokens) => { + // We've confirmed above that there is a delimiter so unwrapping is OK. + MacArgs(dspan, AttrMacDelimiter::from_token(delim).unwrap(), tokens) + } + _ => unreachable!(), + } + } else { + return self.unexpected(); + }, + )) } - fn parse_mac_args_common(&mut self, delimited_only: bool) -> PResult<'a, MacArgs> { + fn parse_attr_args(&mut self) -> PResult<'a, AttrArgs> { 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() { - TokenTree::Delimited(dspan, delim, tokens) => - // We've confirmed above that there is a delimiter so unwrapping is OK. - { - MacArgs::Delimited(dspan, MacDelimiter::from_token(delim).unwrap(), tokens) + TokenTree::Delimited(dspan, delim, tokens) => { + // We've confirmed above that there is a delimiter so unwrapping is OK. + AttrArgs::Delimited( + dspan, + AttrMacDelimiter::from_token(delim).unwrap(), + tokens, + ) } _ => unreachable!(), } - } else if !delimited_only { + } else { if self.eat(&token::Eq) { let eq_span = self.prev_token.span; @@ -1192,12 +1206,10 @@ impl<'a> Parser<'a> { let span = expr.span; let token_kind = token::Interpolated(Lrc::new(token::NtExpr(expr))); - MacArgs::Eq(eq_span, Token::new(token_kind, span)) + AttrArgs::Eq(eq_span, Token::new(token_kind, span)) } else { - MacArgs::Empty + AttrArgs::Empty } - } else { - return self.unexpected(); }, ) } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 4781813ee8e56..eec14a4526257 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -3,7 +3,7 @@ use crate::parse_in; use rustc_ast::tokenstream::{DelimSpan, TokenTree}; -use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind}; +use rustc_ast::{self as ast, AttrArgs, AttrMacDelimiter, Attribute, MetaItem, MetaItemKind}; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; @@ -23,7 +23,7 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) { Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => { check_builtin_attribute(sess, attr, *name, *template) } - _ if let MacArgs::Eq(..) = attr.get_normal_item().args => { + _ if let AttrArgs::Eq(..) = attr.get_normal_item().args => { // All key-value attributes are restricted to meta-item syntax. parse_meta(sess, attr) .map_err(|mut err| { @@ -41,13 +41,13 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta span: attr.span, path: item.path.clone(), kind: match &item.args { - MacArgs::Empty => MetaItemKind::Word, - MacArgs::Eq(_, t) => { + AttrArgs::Empty => MetaItemKind::Word, + AttrArgs::Eq(_, t) => { let t = TokenTree::Token(t.clone()).into(); let v = parse_in(sess, t, "name value", |p| p.parse_unsuffixed_lit())?; MetaItemKind::NameValue(v) } - MacArgs::Delimited(dspan, delim, t) => { + AttrArgs::Delimited(dspan, delim, t) => { check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters"); let nmis = parse_in(sess, t.clone(), "meta list", |p| p.parse_meta_seq_top())?; MetaItemKind::List(nmis) @@ -56,8 +56,8 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta }) } -pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) { - if let ast::MacDelimiter::Parenthesis = delim { +pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: AttrMacDelimiter, msg: &str) { + if let ast::AttrMacDelimiter::Parenthesis = delim { return; } diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 3fce4987679ad..f1e2a0c539a8b 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -678,13 +678,13 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool { l.style == r.style && match (&l.kind, &r.kind) { (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2, - (Normal(l, _), Normal(r, _)) => eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args), + (Normal(l, _), Normal(r, _)) => eq_path(&l.path, &r.path) && eq_attr_args(&l.args, &r.args), _ => false, } } -pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool { - use MacArgs::*; +pub fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool { + use AttrArgs::*; match (l, r) { (Empty, Empty) => true, (Delimited(_, ld, lts), Delimited(_, rd, rts)) => ld == rd && lts.eq_unspanned(rts), @@ -692,3 +692,9 @@ pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool { _ => false, } } + +pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool { + let MacArgs(_, ld, lts) = l; + let MacArgs(_, rd, rts) = r; + ld == rd && lts.eq_unspanned(rts) +} diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 4f333cd27cefe..c900a31f88e02 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -1325,11 +1325,11 @@ pub(crate) fn can_be_overflowed_expr( } ast::ExprKind::MacCall(ref mac) => { match ( - rustc_ast::ast::MacDelimiter::from_token(mac.args.delim()), + rustc_ast::ast::AttrMacDelimiter::from_token(mac.args.delim()), context.config.overflow_delimited_expr(), ) { - (Some(ast::MacDelimiter::Bracket), true) - | (Some(ast::MacDelimiter::Brace), true) => true, + (Some(ast::AttrMacDelimiter::Bracket), true) + | (Some(ast::AttrMacDelimiter::Brace), true) => true, _ => context.use_block_indent() && args_len == 1, } }