Split MacArgs in two.

`MacArgs` is an enum with three variants: `Empty`, `Delimited`, and `Eq`. It's
used in two ways:
- For representing attribute macro arguments (e.g. in `AttrItem`), where all
  three variants are used.
- For representing function-like macros (e.g. in `MacCall` and `MacroDef`),
  where only the `Delimited` variant is used.

In other words, `MacArgs` is used in two quite different places due to them
having partial overlap. I find this makes the code hard to read. It also leads
to various unreachable code paths, and allows invalid values (such as
accidentally using `MacArgs::Empty` in a `MacCall`).

This commit splits `MacArgs` in two:
- `DelimArgs` is a new struct just for the "delimited arguments" case. It is
  now used in `MacCall` and `MacroDef`.
- `AttrArgs` is a renaming of the old `MacArgs` enum for the attribute macro
  case. Its `Delimited` variant now contains a `DelimArgs`.

Various other related things are renamed as well.

These changes make the code clearer, avoids several unreachable paths, and
disallows the invalid values.
This commit is contained in:
Nicholas Nethercote 2022-11-18 11:24:21 +11:00
parent 1cbc45942d
commit 3e3a4192d8
33 changed files with 252 additions and 248 deletions

View File

@ -1544,55 +1544,48 @@ pub enum ClosureBinder {
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub struct MacCall { pub struct MacCall {
pub path: Path, pub path: Path,
pub args: P<MacArgs>, pub args: P<DelimArgs>,
pub prior_type_ascription: Option<(Span, bool)>, pub prior_type_ascription: Option<(Span, bool)>,
} }
impl MacCall { impl MacCall {
pub fn span(&self) -> Span { pub fn span(&self) -> Span {
self.path.span.to(self.args.span().unwrap_or(self.path.span)) self.path.span.to(self.args.dspan.entire())
} }
} }
/// Arguments passed to an attribute or a function-like macro. /// Arguments passed to an attribute macro.
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub enum MacArgs { pub enum AttrArgs {
/// No arguments - `#[attr]`. /// No arguments: `#[attr]`.
Empty, Empty,
/// Delimited arguments - `#[attr()/[]/{}]` or `mac!()/[]/{}`. /// Delimited arguments: `#[attr()/[]/{}]`.
Delimited(DelimSpan, MacDelimiter, TokenStream), Delimited(DelimArgs),
/// Arguments of a key-value attribute - `#[attr = "value"]`. /// Arguments of a key-value attribute: `#[attr = "value"]`.
Eq( Eq(
/// Span of the `=` token. /// Span of the `=` token.
Span, Span,
/// The "value". /// The "value".
MacArgsEq, AttrArgsEq,
), ),
} }
// The RHS of a `MacArgs::Eq` starts out as an expression. Once macro expansion // The RHS of an `AttrArgs::Eq` starts out as an expression. Once macro
// is completed, all cases end up either as a literal, which is the form used // expansion is completed, all cases end up either as a literal, which is the
// after lowering to HIR, or as an error. // form used after lowering to HIR, or as an error.
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub enum MacArgsEq { pub enum AttrArgsEq {
Ast(P<Expr>), Ast(P<Expr>),
Hir(Lit), Hir(Lit),
} }
impl MacArgs { impl AttrArgs {
pub fn delim(&self) -> Option<Delimiter> {
match self {
MacArgs::Delimited(_, delim, _) => Some(delim.to_token()),
MacArgs::Empty | MacArgs::Eq(..) => None,
}
}
pub fn span(&self) -> Option<Span> { pub fn span(&self) -> Option<Span> {
match self { match self {
MacArgs::Empty => None, AttrArgs::Empty => None,
MacArgs::Delimited(dspan, ..) => Some(dspan.entire()), AttrArgs::Delimited(args) => Some(args.dspan.entire()),
MacArgs::Eq(eq_span, MacArgsEq::Ast(expr)) => Some(eq_span.to(expr.span)), AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => Some(eq_span.to(expr.span)),
MacArgs::Eq(_, MacArgsEq::Hir(lit)) => { AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => {
unreachable!("in literal form when getting span: {:?}", lit); unreachable!("in literal form when getting span: {:?}", lit);
} }
} }
@ -1602,39 +1595,29 @@ impl MacArgs {
/// Proc macros see these tokens, for example. /// Proc macros see these tokens, for example.
pub fn inner_tokens(&self) -> TokenStream { pub fn inner_tokens(&self) -> TokenStream {
match self { match self {
MacArgs::Empty => TokenStream::default(), AttrArgs::Empty => TokenStream::default(),
MacArgs::Delimited(.., tokens) => tokens.clone(), AttrArgs::Delimited(args) => args.tokens.clone(),
MacArgs::Eq(_, MacArgsEq::Ast(expr)) => TokenStream::from_ast(expr), AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => TokenStream::from_ast(expr),
MacArgs::Eq(_, MacArgsEq::Hir(lit)) => { AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => {
unreachable!("in literal form when getting inner tokens: {:?}", lit) unreachable!("in literal form when getting inner tokens: {:?}", lit)
} }
} }
} }
/// 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, _))
}
} }
impl<CTX> HashStable<CTX> for MacArgs impl<CTX> HashStable<CTX> for AttrArgs
where where
CTX: crate::HashStableContext, CTX: crate::HashStableContext,
{ {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
mem::discriminant(self).hash_stable(ctx, hasher); mem::discriminant(self).hash_stable(ctx, hasher);
match self { match self {
MacArgs::Empty => {} AttrArgs::Empty => {}
MacArgs::Delimited(dspan, delim, tokens) => { AttrArgs::Delimited(args) => args.hash_stable(ctx, hasher),
dspan.hash_stable(ctx, hasher); AttrArgs::Eq(_eq_span, AttrArgsEq::Ast(expr)) => {
delim.hash_stable(ctx, hasher);
tokens.hash_stable(ctx, hasher);
}
MacArgs::Eq(_eq_span, MacArgsEq::Ast(expr)) => {
unreachable!("hash_stable {:?}", expr); unreachable!("hash_stable {:?}", expr);
} }
MacArgs::Eq(eq_span, MacArgsEq::Hir(lit)) => { AttrArgs::Eq(eq_span, AttrArgsEq::Hir(lit)) => {
eq_span.hash_stable(ctx, hasher); eq_span.hash_stable(ctx, hasher);
lit.hash_stable(ctx, hasher); lit.hash_stable(ctx, hasher);
} }
@ -1642,6 +1625,34 @@ where
} }
} }
/// Delimited arguments, as used in `#[attr()/[]/{}]` or `mac!()/[]/{}`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct DelimArgs {
pub dspan: DelimSpan,
pub delim: MacDelimiter,
pub tokens: TokenStream,
}
impl DelimArgs {
/// 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, DelimArgs { delim: MacDelimiter::Brace, .. })
}
}
impl<CTX> HashStable<CTX> for DelimArgs
where
CTX: crate::HashStableContext,
{
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
let DelimArgs { dspan, delim, tokens } = self;
dspan.hash_stable(ctx, hasher);
delim.hash_stable(ctx, hasher);
tokens.hash_stable(ctx, hasher);
}
}
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum MacDelimiter { pub enum MacDelimiter {
Parenthesis, Parenthesis,
@ -1671,7 +1682,7 @@ impl MacDelimiter {
/// Represents a macro definition. /// Represents a macro definition.
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct MacroDef { pub struct MacroDef {
pub body: P<MacArgs>, pub body: P<DelimArgs>,
/// `true` if macro was defined with `macro_rules`. /// `true` if macro was defined with `macro_rules`.
pub macro_rules: bool, pub macro_rules: bool,
} }
@ -2534,7 +2545,7 @@ impl<D: Decoder> Decodable<D> for AttrId {
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct AttrItem { pub struct AttrItem {
pub path: Path, pub path: Path,
pub args: MacArgs, pub args: AttrArgs,
pub tokens: Option<LazyAttrTokenStream>, pub tokens: Option<LazyAttrTokenStream>,
} }

View File

@ -1,9 +1,9 @@
//! Functions dealing with attributes and meta items. //! Functions dealing with attributes and meta items.
use crate::ast; use crate::ast;
use crate::ast::{AttrId, AttrItem, AttrKind, AttrStyle, Attribute}; use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, Attribute};
use crate::ast::{Lit, LitKind}; use crate::ast::{DelimArgs, Lit, LitKind};
use crate::ast::{MacArgs, MacArgsEq, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem};
use crate::ast::{Path, PathSegment}; use crate::ast::{Path, PathSegment};
use crate::ptr::P; use crate::ptr::P;
use crate::token::{self, CommentKind, Delimiter, Token}; use crate::token::{self, CommentKind, Delimiter, Token};
@ -158,7 +158,7 @@ impl Attribute {
pub fn is_word(&self) -> bool { pub fn is_word(&self) -> bool {
if let AttrKind::Normal(normal) = &self.kind { if let AttrKind::Normal(normal) = &self.kind {
matches!(normal.item.args, MacArgs::Empty) matches!(normal.item.args, AttrArgs::Empty)
} else { } else {
false false
} }
@ -223,13 +223,13 @@ impl AttrItem {
pub fn meta(&self, span: Span) -> Option<MetaItem> { pub fn meta(&self, span: Span) -> Option<MetaItem> {
Some(MetaItem { Some(MetaItem {
path: self.path.clone(), path: self.path.clone(),
kind: MetaItemKind::from_mac_args(&self.args)?, kind: MetaItemKind::from_attr_args(&self.args)?,
span, span,
}) })
} }
pub fn meta_kind(&self) -> Option<MetaItemKind> { pub fn meta_kind(&self) -> Option<MetaItemKind> {
MetaItemKind::from_mac_args(&self.args) MetaItemKind::from_attr_args(&self.args)
} }
} }
@ -390,7 +390,7 @@ pub fn mk_attr(
g: &AttrIdGenerator, g: &AttrIdGenerator,
style: AttrStyle, style: AttrStyle,
path: Path, path: Path,
args: MacArgs, args: AttrArgs,
span: Span, span: Span,
) -> Attribute { ) -> Attribute {
mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span) mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span)
@ -413,12 +413,12 @@ pub fn mk_attr_from_item(
/// Returns an inner attribute with the given value and span. /// Returns an inner attribute with the given value and span.
pub fn mk_attr_inner(g: &AttrIdGenerator, item: MetaItem) -> Attribute { pub fn mk_attr_inner(g: &AttrIdGenerator, item: MetaItem) -> Attribute {
mk_attr(g, AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span) mk_attr(g, AttrStyle::Inner, item.path, item.kind.attr_args(item.span), item.span)
} }
/// Returns an outer attribute with the given value and span. /// Returns an outer attribute with the given value and span.
pub fn mk_attr_outer(g: &AttrIdGenerator, item: MetaItem) -> Attribute { pub fn mk_attr_outer(g: &AttrIdGenerator, item: MetaItem) -> Attribute {
mk_attr(g, AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span) mk_attr(g, AttrStyle::Outer, item.path, item.kind.attr_args(item.span), item.span)
} }
pub fn mk_doc_comment( pub fn mk_doc_comment(
@ -524,9 +524,9 @@ impl MetaItemKind {
} }
} }
pub fn mac_args(&self, span: Span) -> MacArgs { pub fn attr_args(&self, span: Span) -> AttrArgs {
match self { match self {
MetaItemKind::Word => MacArgs::Empty, MetaItemKind::Word => AttrArgs::Empty,
MetaItemKind::NameValue(lit) => { MetaItemKind::NameValue(lit) => {
let expr = P(ast::Expr { let expr = P(ast::Expr {
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
@ -535,7 +535,7 @@ impl MetaItemKind {
attrs: ast::AttrVec::new(), attrs: ast::AttrVec::new(),
tokens: None, tokens: None,
}); });
MacArgs::Eq(span, MacArgsEq::Ast(expr)) AttrArgs::Eq(span, AttrArgsEq::Ast(expr))
} }
MetaItemKind::List(list) => { MetaItemKind::List(list) => {
let mut tts = Vec::new(); let mut tts = Vec::new();
@ -545,11 +545,11 @@ impl MetaItemKind {
} }
tts.extend(item.token_trees()) tts.extend(item.token_trees())
} }
MacArgs::Delimited( AttrArgs::Delimited(DelimArgs {
DelimSpan::from_single(span), dspan: DelimSpan::from_single(span),
MacDelimiter::Parenthesis, delim: MacDelimiter::Parenthesis,
TokenStream::new(tts), tokens: TokenStream::new(tts),
) })
} }
} }
} }
@ -608,20 +608,22 @@ impl MetaItemKind {
} }
} }
fn from_mac_args(args: &MacArgs) -> Option<MetaItemKind> { fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
match args { match args {
MacArgs::Empty => Some(MetaItemKind::Word), AttrArgs::Empty => Some(MetaItemKind::Word),
MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) => { AttrArgs::Delimited(DelimArgs {
MetaItemKind::list_from_tokens(tokens.clone()) dspan: _,
} delim: MacDelimiter::Parenthesis,
MacArgs::Delimited(..) => None, tokens,
MacArgs::Eq(_, MacArgsEq::Ast(expr)) => match expr.kind { }) => MetaItemKind::list_from_tokens(tokens.clone()),
AttrArgs::Delimited(..) => None,
AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => match expr.kind {
ast::ExprKind::Lit(token_lit) => Some(MetaItemKind::NameValue( ast::ExprKind::Lit(token_lit) => Some(MetaItemKind::NameValue(
Lit::from_token_lit(token_lit, expr.span).expect("token_lit in from_mac_args"), Lit::from_token_lit(token_lit, expr.span).expect("token_lit in from_attr_args"),
)), )),
_ => None, _ => None,
}, },
MacArgs::Eq(_, MacArgsEq::Hir(lit)) => Some(MetaItemKind::NameValue(lit.clone())), AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => Some(MetaItemKind::NameValue(lit.clone())),
} }
} }

View File

@ -367,23 +367,27 @@ pub fn visit_fn_sig<T: MutVisitor>(FnSig { header, decl, span }: &mut FnSig, vis
} }
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
pub fn visit_mac_args<T: MutVisitor>(args: &mut MacArgs, vis: &mut T) { pub fn visit_attr_args<T: MutVisitor>(args: &mut AttrArgs, vis: &mut T) {
match args { match args {
MacArgs::Empty => {} AttrArgs::Empty => {}
MacArgs::Delimited(dspan, _delim, tokens) => { AttrArgs::Delimited(args) => visit_delim_args(args, vis),
visit_delim_span(dspan, vis); AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => {
visit_tts(tokens, vis);
}
MacArgs::Eq(eq_span, MacArgsEq::Ast(expr)) => {
vis.visit_span(eq_span); vis.visit_span(eq_span);
vis.visit_expr(expr); vis.visit_expr(expr);
} }
MacArgs::Eq(_, MacArgsEq::Hir(lit)) => { AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => {
unreachable!("in literal form when visiting mac args eq: {:?}", lit) unreachable!("in literal form when visiting mac args eq: {:?}", lit)
} }
} }
} }
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
pub fn visit_delim_args<T: MutVisitor>(args: &mut DelimArgs, vis: &mut T) {
let DelimArgs { dspan, delim: _, tokens } = args;
visit_delim_span(dspan, vis);
visit_tts(tokens, vis);
}
pub fn visit_delim_span<T: MutVisitor>(dspan: &mut DelimSpan, vis: &mut T) { pub fn visit_delim_span<T: MutVisitor>(dspan: &mut DelimSpan, vis: &mut T) {
vis.visit_span(&mut dspan.open); vis.visit_span(&mut dspan.open);
vis.visit_span(&mut dspan.close); vis.visit_span(&mut dspan.close);
@ -601,7 +605,7 @@ pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
let NormalAttr { item: AttrItem { path, args, tokens }, tokens: attr_tokens } = let NormalAttr { item: AttrItem { path, args, tokens }, tokens: attr_tokens } =
&mut **normal; &mut **normal;
vis.visit_path(path); vis.visit_path(path);
visit_mac_args(args, vis); visit_attr_args(args, vis);
visit_lazy_tts(tokens, vis); visit_lazy_tts(tokens, vis);
visit_lazy_tts(attr_tokens, vis); visit_lazy_tts(attr_tokens, vis);
} }
@ -613,12 +617,12 @@ pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
pub fn noop_visit_mac<T: MutVisitor>(mac: &mut MacCall, vis: &mut T) { pub fn noop_visit_mac<T: MutVisitor>(mac: &mut MacCall, vis: &mut T) {
let MacCall { path, args, prior_type_ascription: _ } = mac; let MacCall { path, args, prior_type_ascription: _ } = mac;
vis.visit_path(path); vis.visit_path(path);
visit_mac_args(args, vis); visit_delim_args(args, vis);
} }
pub fn noop_visit_macro_def<T: MutVisitor>(macro_def: &mut MacroDef, vis: &mut T) { pub fn noop_visit_macro_def<T: MutVisitor>(macro_def: &mut MacroDef, vis: &mut T) {
let MacroDef { body, macro_rules: _ } = macro_def; let MacroDef { body, macro_rules: _ } = macro_def;
visit_mac_args(body, vis); visit_delim_args(body, vis);
} }
pub fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T) { pub fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T) {
@ -792,7 +796,7 @@ pub fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T
token::NtMeta(item) => { token::NtMeta(item) => {
let AttrItem { path, args, tokens } = item.deref_mut(); let AttrItem { path, args, tokens } = item.deref_mut();
vis.visit_path(path); vis.visit_path(path);
visit_mac_args(args, vis); visit_attr_args(args, vis);
visit_lazy_tts(tokens, vis); visit_lazy_tts(tokens, vis);
} }
token::NtPath(path) => vis.visit_path(path), token::NtPath(path) => vis.visit_path(path),

View File

@ -926,17 +926,17 @@ 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) { pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) {
match &attr.kind { match &attr.kind {
AttrKind::Normal(normal) => walk_mac_args(visitor, &normal.item.args), AttrKind::Normal(normal) => walk_attr_args(visitor, &normal.item.args),
AttrKind::DocComment(..) => {} 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 { match args {
MacArgs::Empty => {} AttrArgs::Empty => {}
MacArgs::Delimited(_dspan, _delim, _tokens) => {} AttrArgs::Delimited(_) => {}
MacArgs::Eq(_eq_span, MacArgsEq::Ast(expr)) => visitor.visit_expr(expr), AttrArgs::Eq(_eq_span, AttrArgsEq::Ast(expr)) => visitor.visit_expr(expr),
MacArgs::Eq(_, MacArgsEq::Hir(lit)) => { AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => {
unreachable!("in literal form when walking mac args eq: {:?}", lit) unreachable!("in literal form when walking mac args eq: {:?}", lit)
} }
} }

View File

@ -671,7 +671,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
kind: AttrKind::Normal(ptr::P(NormalAttr { kind: AttrKind::Normal(ptr::P(NormalAttr {
item: AttrItem { item: AttrItem {
path: Path::from_ident(Ident::new(sym::track_caller, span)), path: Path::from_ident(Ident::new(sym::track_caller, span)),
args: MacArgs::Empty, args: AttrArgs::Empty,
tokens: None, tokens: None,
}, },
tokens: None, tokens: None,

View File

@ -470,7 +470,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ItemKind::TraitAlias(generics, bounds) hir::ItemKind::TraitAlias(generics, bounds)
} }
ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => { ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => {
let body = P(self.lower_mac_args(body)); let body = P(self.lower_delim_args(body));
let macro_kind = self.resolver.decl_macro_kind(self.local_def_id(id)); let macro_kind = self.resolver.decl_macro_kind(self.local_def_id(id));
hir::ItemKind::Macro(ast::MacroDef { body, macro_rules }, macro_kind) hir::ItemKind::Macro(ast::MacroDef { body, macro_rules }, macro_kind)
} }

View File

@ -911,7 +911,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr { AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr {
item: AttrItem { item: AttrItem {
path: normal.item.path.clone(), path: normal.item.path.clone(),
args: self.lower_mac_args(&normal.item.args), args: self.lower_attr_args(&normal.item.args),
tokens: None, tokens: None,
}, },
tokens: None, tokens: None,
@ -931,32 +931,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
} }
fn lower_mac_args(&self, args: &MacArgs) -> MacArgs { fn lower_attr_args(&self, args: &AttrArgs) -> AttrArgs {
match *args { match *args {
MacArgs::Empty => MacArgs::Empty, AttrArgs::Empty => AttrArgs::Empty,
MacArgs::Delimited(dspan, delim, ref tokens) => { AttrArgs::Delimited(ref args) => AttrArgs::Delimited(self.lower_delim_args(args)),
// 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(dspan, delim, tokens.flattened())
}
// This is an inert key-value attribute - it will never be visible to macros // This is an inert key-value attribute - it will never be visible to macros
// after it gets lowered to HIR. Therefore, we can extract literals to handle // after it gets lowered to HIR. Therefore, we can extract literals to handle
// nonterminals in `#[doc]` (e.g. `#[doc = $e]`). // nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
MacArgs::Eq(eq_span, MacArgsEq::Ast(ref expr)) => { AttrArgs::Eq(eq_span, AttrArgsEq::Ast(ref expr)) => {
// In valid code the value always ends up as a single literal. Otherwise, a dummy // In valid code the value always ends up as a single literal. Otherwise, a dummy
// literal suffices because the error is handled elsewhere. // literal suffices because the error is handled elsewhere.
let lit = if let ExprKind::Lit(token_lit) = expr.kind { let lit = if let ExprKind::Lit(token_lit) = expr.kind {
@ -975,14 +957,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: DUMMY_SP, span: DUMMY_SP,
} }
}; };
MacArgs::Eq(eq_span, MacArgsEq::Hir(lit)) AttrArgs::Eq(eq_span, AttrArgsEq::Hir(lit))
} }
MacArgs::Eq(_, MacArgsEq::Hir(ref lit)) => { AttrArgs::Eq(_, AttrArgsEq::Hir(ref lit)) => {
unreachable!("in literal form when lowering mac args eq: {:?}", lit) unreachable!("in literal form when lowering mac args eq: {:?}", lit)
} }
} }
} }
fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs {
DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.flattened() }
}
/// Given an associated type constraint like one of these: /// Given an associated type constraint like one of these:
/// ///
/// ```ignore (illustrative) /// ```ignore (illustrative)

View File

@ -11,10 +11,9 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::util::classify; use rustc_ast::util::classify;
use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle}; use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
use rustc_ast::util::parser; use rustc_ast::util::parser;
use rustc_ast::{self as ast, BlockCheckMode, Mutability, PatKind, RangeEnd, RangeSyntax}; use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, Mutability, PatKind};
use rustc_ast::{attr, BindingAnnotation, ByRef, Term}; use rustc_ast::{attr, BindingAnnotation, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
use rustc_ast::{GenericArg, MacArgs, MacArgsEq}; use rustc_ast::{GenericArg, GenericBound, SelfKind, TraitBoundModifier};
use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
@ -466,26 +465,26 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) { fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
self.ibox(0); self.ibox(0);
match &item.args { match &item.args {
MacArgs::Delimited(_, delim, tokens) => self.print_mac_common( AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common(
Some(MacHeader::Path(&item.path)), Some(MacHeader::Path(&item.path)),
false, false,
None, None,
Some(delim.to_token()), delim.to_token(),
tokens, tokens,
true, true,
span, span,
), ),
MacArgs::Empty => { AttrArgs::Empty => {
self.print_path(&item.path, false, 0); self.print_path(&item.path, false, 0);
} }
MacArgs::Eq(_, MacArgsEq::Ast(expr)) => { AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => {
self.print_path(&item.path, false, 0); self.print_path(&item.path, false, 0);
self.space(); self.space();
self.word_space("="); self.word_space("=");
let token_str = self.expr_to_string(expr); let token_str = self.expr_to_string(expr);
self.word(token_str); self.word(token_str);
} }
MacArgs::Eq(_, MacArgsEq::Hir(lit)) => { AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => {
self.print_path(&item.path, false, 0); self.print_path(&item.path, false, 0);
self.space(); self.space();
self.word_space("="); self.word_space("=");
@ -544,7 +543,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
None, None,
false, false,
None, None,
Some(*delim), *delim,
tts, tts,
convert_dollar_crate, convert_dollar_crate,
dspan.entire(), dspan.entire(),
@ -570,12 +569,12 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
header: Option<MacHeader<'_>>, header: Option<MacHeader<'_>>,
has_bang: bool, has_bang: bool,
ident: Option<Ident>, ident: Option<Ident>,
delim: Option<Delimiter>, delim: Delimiter,
tts: &TokenStream, tts: &TokenStream,
convert_dollar_crate: bool, convert_dollar_crate: bool,
span: Span, span: Span,
) { ) {
if delim == Some(Delimiter::Brace) { if delim == Delimiter::Brace {
self.cbox(INDENT_UNIT); self.cbox(INDENT_UNIT);
} }
match header { match header {
@ -591,7 +590,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
self.print_ident(ident); self.print_ident(ident);
} }
match delim { match delim {
Some(Delimiter::Brace) => { Delimiter::Brace => {
if header.is_some() || has_bang || ident.is_some() { if header.is_some() || has_bang || ident.is_some() {
self.nbsp(); self.nbsp();
} }
@ -605,7 +604,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
let empty = tts.is_empty(); let empty = tts.is_empty();
self.bclose(span, empty); self.bclose(span, empty);
} }
Some(delim) => { delim => {
let token_str = self.token_kind_to_string(&token::OpenDelim(delim)); let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
self.word(token_str); self.word(token_str);
self.ibox(0); self.ibox(0);
@ -614,11 +613,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
let token_str = self.token_kind_to_string(&token::CloseDelim(delim)); let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
self.word(token_str); self.word(token_str);
} }
None => {
self.ibox(0);
self.print_tts(tts, convert_dollar_crate);
self.end();
}
} }
} }
@ -639,8 +633,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
Some(MacHeader::Keyword(kw)), Some(MacHeader::Keyword(kw)),
has_bang, has_bang,
Some(*ident), Some(*ident),
macro_def.body.delim(), macro_def.body.delim.to_token(),
&macro_def.body.inner_tokens(), &macro_def.body.tokens.clone(),
true, true,
sp, sp,
); );
@ -1230,8 +1224,8 @@ impl<'a> State<'a> {
Some(MacHeader::Path(&m.path)), Some(MacHeader::Path(&m.path)),
true, true,
None, None,
m.args.delim(), m.args.delim.to_token(),
&m.args.inner_tokens(), &m.args.tokens.clone(),
true, true,
m.span(), m.span(),
); );

View File

@ -4,7 +4,7 @@ use crate::edition_panic::use_panic_2021;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token; use rustc_ast::token;
use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::tokenstream::{DelimSpan, TokenStream};
use rustc_ast::{Expr, ExprKind, MacArgs, MacCall, MacDelimiter, Path, PathSegment, UnOp}; use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, MacDelimiter, Path, PathSegment, UnOp};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, PResult}; use rustc_errors::{Applicability, PResult};
use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult}; use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult};
@ -54,11 +54,11 @@ pub fn expand_assert<'cx>(
call_site_span, call_site_span,
ExprKind::MacCall(P(MacCall { ExprKind::MacCall(P(MacCall {
path: panic_path(), path: panic_path(),
args: P(MacArgs::Delimited( args: P(DelimArgs {
DelimSpan::from_single(call_site_span), dspan: DelimSpan::from_single(call_site_span),
MacDelimiter::Parenthesis, delim: MacDelimiter::Parenthesis,
tokens, tokens,
)), }),
prior_type_ascription: None, prior_type_ascription: None,
})), })),
); );

View File

@ -3,7 +3,7 @@ use rustc_ast::{
ptr::P, ptr::P,
token, token,
tokenstream::{DelimSpan, TokenStream, TokenTree}, tokenstream::{DelimSpan, TokenStream, TokenTree},
BinOpKind, BorrowKind, Expr, ExprKind, ItemKind, MacArgs, MacCall, MacDelimiter, MethodCall, BinOpKind, BorrowKind, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MacDelimiter, MethodCall,
Mutability, Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID, Mutability, Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID,
}; };
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
@ -181,11 +181,11 @@ impl<'cx, 'a> Context<'cx, 'a> {
self.span, self.span,
ExprKind::MacCall(P(MacCall { ExprKind::MacCall(P(MacCall {
path: panic_path, path: panic_path,
args: P(MacArgs::Delimited( args: P(DelimArgs {
DelimSpan::from_single(self.span), dspan: DelimSpan::from_single(self.span),
MacDelimiter::Parenthesis, delim: MacDelimiter::Parenthesis,
initial.into_iter().chain(captures).collect::<TokenStream>(), tokens: initial.into_iter().chain(captures).collect::<TokenStream>(),
)), }),
prior_type_ascription: None, prior_type_ascription: None,
})), })),
) )

View File

@ -58,11 +58,11 @@ fn expand<'cx>(
.collect(), .collect(),
tokens: None, tokens: None,
}, },
args: P(MacArgs::Delimited( args: P(DelimArgs {
DelimSpan::from_single(sp), dspan: DelimSpan::from_single(sp),
MacDelimiter::Parenthesis, delim: MacDelimiter::Parenthesis,
tts, tokens: tts,
)), }),
prior_type_ascription: None, prior_type_ascription: None,
})), })),
), ),

View File

@ -11,9 +11,9 @@ use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter}; use rustc_ast::token::{self, Delimiter};
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{AssocItemKind, AstNodeWrapper, AttrStyle, AttrVec, ExprKind, ForeignItemKind}; use rustc_ast::{AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, ExprKind};
use rustc_ast::{HasAttrs, HasNodeId}; use rustc_ast::{ForeignItemKind, HasAttrs, HasNodeId};
use rustc_ast::{Inline, ItemKind, MacArgs, MacStmtStyle, MetaItemKind, ModKind}; use rustc_ast::{Inline, ItemKind, MacStmtStyle, MetaItemKind, ModKind};
use rustc_ast::{NestedMetaItem, NodeId, PatKind, StmtKind, TyKind}; use rustc_ast::{NestedMetaItem, NodeId, PatKind, StmtKind, TyKind};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::map_in_place::MapInPlace;
@ -654,7 +654,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
ExpandResult::Ready(match invoc.kind { ExpandResult::Ready(match invoc.kind {
InvocationKind::Bang { mac, .. } => match ext { InvocationKind::Bang { mac, .. } => match ext {
SyntaxExtensionKind::Bang(expander) => { SyntaxExtensionKind::Bang(expander) => {
let Ok(tok_result) = expander.expand(self.cx, span, mac.args.inner_tokens()) else { let Ok(tok_result) = expander.expand(self.cx, span, mac.args.tokens.clone()) else {
return ExpandResult::Ready(fragment_kind.dummy(span)); return ExpandResult::Ready(fragment_kind.dummy(span));
}; };
self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span) self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span)
@ -662,7 +662,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
SyntaxExtensionKind::LegacyBang(expander) => { SyntaxExtensionKind::LegacyBang(expander) => {
let prev = self.cx.current_expansion.prior_type_ascription; let prev = self.cx.current_expansion.prior_type_ascription;
self.cx.current_expansion.prior_type_ascription = mac.prior_type_ascription; self.cx.current_expansion.prior_type_ascription = mac.prior_type_ascription;
let tok_result = expander.expand(self.cx, span, mac.args.inner_tokens()); let tok_result = expander.expand(self.cx, span, mac.args.tokens.clone());
let result = if let Some(result) = fragment_kind.make_from(tok_result) { let result = if let Some(result) = fragment_kind.make_from(tok_result) {
result result
} else { } else {
@ -706,7 +706,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
_ => item.to_tokens(), _ => item.to_tokens(),
}; };
let attr_item = attr.unwrap_normal_item(); 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"); self.cx.span_err(span, "key-value macro attributes are not supported");
} }
let inner_tokens = attr_item.args.inner_tokens(); let inner_tokens = attr_item.args.inner_tokens();

View File

@ -577,7 +577,7 @@ pub fn compile_declarative_macro(
// Parse the macro_rules! invocation // Parse the macro_rules! invocation
let (macro_rules, body) = match &def.kind { let (macro_rules, body) = match &def.kind {
ast::ItemKind::MacroDef(def) => (def.macro_rules, def.body.inner_tokens()), ast::ItemKind::MacroDef(def) => (def.macro_rules, def.body.tokens.clone()),
_ => unreachable!(), _ => unreachable!(),
}; };

View File

@ -291,7 +291,7 @@ fn ttdelim_span() {
.unwrap(); .unwrap();
let tts: Vec<_> = match expr.kind { let tts: Vec<_> = match expr.kind {
ast::ExprKind::MacCall(ref mac) => mac.args.inner_tokens().into_trees().collect(), ast::ExprKind::MacCall(ref mac) => mac.args.tokens.clone().into_trees().collect(),
_ => panic!("not a macro"), _ => panic!("not a macro"),
}; };

View File

@ -16,7 +16,11 @@ pub fn placeholder(
fn mac_placeholder() -> P<ast::MacCall> { fn mac_placeholder() -> P<ast::MacCall> {
P(ast::MacCall { P(ast::MacCall {
path: ast::Path { span: DUMMY_SP, segments: ThinVec::new(), tokens: None }, path: ast::Path { span: DUMMY_SP, segments: ThinVec::new(), tokens: None },
args: P(ast::MacArgs::Empty), args: P(ast::DelimArgs {
dspan: ast::tokenstream::DelimSpan::dummy(),
delim: ast::MacDelimiter::Parenthesis,
tokens: ast::tokenstream::TokenStream::new(Vec::new()),
}),
prior_type_ascription: None, prior_type_ascription: None,
}) })
} }

View File

@ -2030,10 +2030,10 @@ impl KeywordIdents {
impl EarlyLintPass for KeywordIdents { impl EarlyLintPass for KeywordIdents {
fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef) { fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef) {
self.check_tokens(cx, mac_def.body.inner_tokens()); self.check_tokens(cx, mac_def.body.tokens.clone());
} }
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) { fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
self.check_tokens(cx, mac.args.inner_tokens()); self.check_tokens(cx, mac.args.tokens.clone());
} }
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
self.check_ident_token(cx, UnderMacro(false), ident); self.check_ident_token(cx, UnderMacro(false), ident);

View File

@ -400,7 +400,7 @@ define_tables! {
assoc_container: Table<DefIndex, ty::AssocItemContainer>, assoc_container: Table<DefIndex, ty::AssocItemContainer>,
// Slot is full when macro is macro_rules. // Slot is full when macro is macro_rules.
macro_rules: Table<DefIndex, ()>, macro_rules: Table<DefIndex, ()>,
macro_definition: Table<DefIndex, LazyValue<ast::MacArgs>>, macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>,
proc_macro: Table<DefIndex, MacroKind>, proc_macro: Table<DefIndex, MacroKind>,
module_reexports: Table<DefIndex, LazyArray<ModChild>>, module_reexports: Table<DefIndex, LazyArray<ModChild>>,
deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>, deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>,

View File

@ -70,7 +70,7 @@ trivially_parameterized_over_tcx! {
ty::adjustment::CoerceUnsizedInfo, ty::adjustment::CoerceUnsizedInfo,
ty::fast_reject::SimplifiedTypeGen<DefId>, ty::fast_reject::SimplifiedTypeGen<DefId>,
rustc_ast::Attribute, rustc_ast::Attribute,
rustc_ast::MacArgs, rustc_ast::DelimArgs,
rustc_attr::ConstStability, rustc_attr::ConstStability,
rustc_attr::DefaultBodyStability, rustc_attr::DefaultBodyStability,
rustc_attr::Deprecation, rustc_attr::Deprecation,

View File

@ -15,8 +15,7 @@ extern crate tracing;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::token; use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_ast::Attribute; use rustc_ast::{AttrItem, Attribute, MetaItem};
use rustc_ast::{AttrItem, MetaItem};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult}; use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult};
@ -257,10 +256,12 @@ pub fn parse_cfg_attr(
parse_sess: &ParseSess, parse_sess: &ParseSess,
) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { ) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
match attr.get_normal_item().args { match attr.get_normal_item().args {
ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => { ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
if !tokens.is_empty() =>
{
let msg = "wrong `cfg_attr` delimiters"; let msg = "wrong `cfg_attr` delimiters";
crate::validate_attr::check_meta_bad_delim(parse_sess, dspan, delim, msg); 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()) { match parse_in(parse_sess, tokens.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
Ok(r) => return Some(r), Ok(r) => return Some(r),
Err(mut e) => { Err(mut e) => {
e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP)) e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))

View File

@ -1501,7 +1501,7 @@ impl<'a> Parser<'a> {
let lo = path.span; let lo = path.span;
let mac = P(MacCall { let mac = P(MacCall {
path, path,
args: self.parse_mac_args()?, args: self.parse_delim_args()?,
prior_type_ascription: self.last_type_ascription, prior_type_ascription: self.last_type_ascription,
}); });
(lo.to(self.prev_token.span), ExprKind::MacCall(mac)) (lo.to(self.prev_token.span), ExprKind::MacCall(mac))

View File

@ -13,7 +13,7 @@ use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree,
use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind}; use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind};
use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, VariantData}; use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, VariantData};
use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind}; use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
use rustc_ast::{MacArgs, MacCall, MacDelimiter}; use rustc_ast::{MacCall, MacDelimiter};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, IntoDiagnostic, PResult, StashKey}; use rustc_errors::{struct_span_err, Applicability, IntoDiagnostic, PResult, StashKey};
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
@ -471,7 +471,7 @@ impl<'a> Parser<'a> {
fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> { fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> {
let path = self.parse_path(PathStyle::Mod)?; // `foo::bar` let path = self.parse_path(PathStyle::Mod)?; // `foo::bar`
self.expect(&token::Not)?; // `!` self.expect(&token::Not)?; // `!`
match self.parse_mac_args() { match self.parse_delim_args() {
// `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`. // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`.
Ok(args) => { Ok(args) => {
self.eat_semi_for_macro_if_needed(&args); self.eat_semi_for_macro_if_needed(&args);
@ -1867,7 +1867,7 @@ impl<'a> Parser<'a> {
fn parse_item_decl_macro(&mut self, lo: Span) -> PResult<'a, ItemInfo> { fn parse_item_decl_macro(&mut self, lo: Span) -> PResult<'a, ItemInfo> {
let ident = self.parse_ident()?; let ident = self.parse_ident()?;
let body = if self.check(&token::OpenDelim(Delimiter::Brace)) { let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
self.parse_mac_args()? // `MacBody` self.parse_delim_args()? // `MacBody`
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
let params = self.parse_token_tree(); // `MacParams` let params = self.parse_token_tree(); // `MacParams`
let pspan = params.span(); let pspan = params.span();
@ -1880,7 +1880,7 @@ impl<'a> Parser<'a> {
let arrow = TokenTree::token_alone(token::FatArrow, pspan.between(bspan)); // `=>` let arrow = TokenTree::token_alone(token::FatArrow, pspan.between(bspan)); // `=>`
let tokens = TokenStream::new(vec![params, arrow, body]); let tokens = TokenStream::new(vec![params, arrow, body]);
let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi()); let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi());
P(MacArgs::Delimited(dspan, MacDelimiter::Brace, tokens)) P(DelimArgs { dspan, delim: MacDelimiter::Brace, tokens })
} else { } else {
return self.unexpected(); return self.unexpected();
}; };
@ -1935,7 +1935,7 @@ impl<'a> Parser<'a> {
.emit(); .emit();
} }
let body = self.parse_mac_args()?; let body = self.parse_delim_args()?;
self.eat_semi_for_macro_if_needed(&body); self.eat_semi_for_macro_if_needed(&body);
self.complain_if_pub_macro(vis, true); self.complain_if_pub_macro(vis, true);
@ -1974,14 +1974,14 @@ impl<'a> Parser<'a> {
} }
} }
fn eat_semi_for_macro_if_needed(&mut self, args: &MacArgs) { fn eat_semi_for_macro_if_needed(&mut self, args: &DelimArgs) {
if args.need_semicolon() && !self.eat(&token::Semi) { if args.need_semicolon() && !self.eat(&token::Semi) {
self.report_invalid_macro_expansion_item(args); self.report_invalid_macro_expansion_item(args);
} }
} }
fn report_invalid_macro_expansion_item(&self, args: &MacArgs) { fn report_invalid_macro_expansion_item(&self, args: &DelimArgs) {
let span = args.span().expect("undelimited macro call"); let span = args.dspan.entire();
let mut err = self.struct_span_err( let mut err = self.struct_span_err(
span, span,
"macros that expand to items must be delimited with braces or followed by a semicolon", "macros that expand to items must be delimited with braces or followed by a semicolon",
@ -1990,10 +1990,7 @@ impl<'a> Parser<'a> {
// macros within the same crate (that we can fix), which is sad. // macros within the same crate (that we can fix), which is sad.
if !span.from_expansion() { if !span.from_expansion() {
if self.unclosed_delims.is_empty() { if self.unclosed_delims.is_empty() {
let DelimSpan { open, close } = match args { let DelimSpan { open, close } = args.dspan;
MacArgs::Empty | MacArgs::Eq(..) => unreachable!(),
MacArgs::Delimited(dspan, ..) => *dspan,
};
err.multipart_suggestion( err.multipart_suggestion(
"change the delimiters to curly braces", "change the delimiters to curly braces",
vec![(open, "{".to_string()), (close, '}'.to_string())], vec![(open, "{".to_string()), (close, '}'.to_string())],

View File

@ -25,8 +25,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::util::case::Case; use rustc_ast::util::case::Case;
use rustc_ast::AttrId; use rustc_ast::AttrId;
use rustc_ast::DUMMY_NODE_ID; use rustc_ast::DUMMY_NODE_ID;
use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, Extern}; use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, DelimArgs, Extern};
use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacArgsEq, MacDelimiter, Mutability, StrLit}; use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutability, StrLit};
use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind}; use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
@ -1249,39 +1249,40 @@ impl<'a> Parser<'a> {
} }
} }
fn parse_mac_args(&mut self) -> PResult<'a, P<MacArgs>> { fn parse_delim_args(&mut self) -> PResult<'a, P<DelimArgs>> {
self.parse_mac_args_common(true).map(P) if let Some(args) = self.parse_delim_args_inner() { Ok(P(args)) } else { self.unexpected() }
} }
fn parse_attr_args(&mut self) -> PResult<'a, MacArgs> { fn parse_attr_args(&mut self) -> PResult<'a, AttrArgs> {
self.parse_mac_args_common(false) Ok(if let Some(args) = self.parse_delim_args_inner() {
} AttrArgs::Delimited(args)
} else {
fn parse_mac_args_common(&mut self, delimited_only: bool) -> PResult<'a, MacArgs> { if self.eat(&token::Eq) {
Ok( let eq_span = self.prev_token.span;
if self.check(&token::OpenDelim(Delimiter::Parenthesis)) AttrArgs::Eq(eq_span, AttrArgsEq::Ast(self.parse_expr_force_collect()?))
|| self.check(&token::OpenDelim(Delimiter::Bracket))
|| self.check(&token::OpenDelim(Delimiter::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)
}
_ => unreachable!(),
}
} else if !delimited_only {
if self.eat(&token::Eq) {
let eq_span = self.prev_token.span;
MacArgs::Eq(eq_span, MacArgsEq::Ast(self.parse_expr_force_collect()?))
} else {
MacArgs::Empty
}
} else { } else {
return self.unexpected(); AttrArgs::Empty
}, }
) })
}
fn parse_delim_args_inner(&mut self) -> Option<DelimArgs> {
if self.check(&token::OpenDelim(Delimiter::Parenthesis))
|| self.check(&token::OpenDelim(Delimiter::Bracket))
|| self.check(&token::OpenDelim(Delimiter::Brace))
{
match self.parse_token_tree() {
// We've confirmed above that there is a delimiter so unwrapping is OK.
TokenTree::Delimited(dspan, delim, tokens) => Some(DelimArgs {
dspan,
delim: MacDelimiter::from_token(delim).unwrap(),
tokens,
}),
_ => unreachable!(),
}
} else {
None
}
} }
fn parse_or_use_outer_attributes( fn parse_or_use_outer_attributes(

View File

@ -693,7 +693,7 @@ impl<'a> Parser<'a> {
/// Parse macro invocation /// Parse macro invocation
fn parse_pat_mac_invoc(&mut self, path: Path) -> PResult<'a, PatKind> { fn parse_pat_mac_invoc(&mut self, path: Path) -> PResult<'a, PatKind> {
self.bump(); self.bump();
let args = self.parse_mac_args()?; let args = self.parse_delim_args()?;
let mac = P(MacCall { path, args, prior_type_ascription: self.last_type_ascription }); let mac = P(MacCall { path, args, prior_type_ascription: self.last_type_ascription });
Ok(PatKind::MacCall(mac)) Ok(PatKind::MacCall(mac))
} }

View File

@ -167,14 +167,13 @@ impl<'a> Parser<'a> {
/// Parses a statement macro `mac!(args)` provided a `path` representing `mac`. /// Parses a statement macro `mac!(args)` provided a `path` representing `mac`.
/// At this point, the `!` token after the path has already been eaten. /// At this point, the `!` token after the path has already been eaten.
fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResult<'a, Stmt> { fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResult<'a, Stmt> {
let args = self.parse_mac_args()?; let args = self.parse_delim_args()?;
let delim = args.delim(); let delim = args.delim.to_token();
let hi = self.prev_token.span; let hi = self.prev_token.span;
let style = match delim { let style = match delim {
Some(Delimiter::Brace) => MacStmtStyle::Braces, Delimiter::Brace => MacStmtStyle::Braces,
Some(_) => MacStmtStyle::NoBraces, _ => MacStmtStyle::NoBraces,
None => unreachable!(),
}; };
let mac = P(MacCall { path, args, prior_type_ascription: self.last_type_ascription }); let mac = P(MacCall { path, args, prior_type_ascription: self.last_type_ascription });

View File

@ -665,7 +665,7 @@ impl<'a> Parser<'a> {
// Macro invocation in type position // Macro invocation in type position
Ok(TyKind::MacCall(P(MacCall { Ok(TyKind::MacCall(P(MacCall {
path, path,
args: self.parse_mac_args()?, args: self.parse_delim_args()?,
prior_type_ascription: self.last_type_ascription, prior_type_ascription: self.last_type_ascription,
}))) })))
} else if allow_plus == AllowPlus::Yes && self.check_plus() { } else if allow_plus == AllowPlus::Yes && self.check_plus() {

View File

@ -3,7 +3,8 @@
use crate::parse_in; use crate::parse_in;
use rustc_ast::tokenstream::DelimSpan; use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::{self as ast, Attribute, MacArgs, MacArgsEq, MacDelimiter, MetaItem, MetaItemKind}; use rustc_ast::MetaItemKind;
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MacDelimiter, MetaItem};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, FatalError, PResult}; use rustc_errors::{Applicability, FatalError, PResult};
use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
@ -24,7 +25,7 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) {
Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => { Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
check_builtin_attribute(sess, attr, *name, *template) 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. // All key-value attributes are restricted to meta-item syntax.
parse_meta(sess, attr) parse_meta(sess, attr)
.map_err(|mut err| { .map_err(|mut err| {
@ -42,13 +43,13 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
span: attr.span, span: attr.span,
path: item.path.clone(), path: item.path.clone(),
kind: match &item.args { kind: match &item.args {
MacArgs::Empty => MetaItemKind::Word, AttrArgs::Empty => MetaItemKind::Word,
MacArgs::Delimited(dspan, delim, t) => { AttrArgs::Delimited(DelimArgs { dspan, delim, tokens }) => {
check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters"); 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())?; let nmis = parse_in(sess, tokens.clone(), "meta list", |p| p.parse_meta_seq_top())?;
MetaItemKind::List(nmis) MetaItemKind::List(nmis)
} }
MacArgs::Eq(_, MacArgsEq::Ast(expr)) => { AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => {
if let ast::ExprKind::Lit(token_lit) = expr.kind if let ast::ExprKind::Lit(token_lit) = expr.kind
&& let Ok(lit) = ast::Lit::from_token_lit(token_lit, expr.span) && let Ok(lit) = ast::Lit::from_token_lit(token_lit, expr.span)
{ {
@ -78,7 +79,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
return Err(err); return Err(err);
} }
} }
MacArgs::Eq(_, MacArgsEq::Hir(lit)) => MetaItemKind::NameValue(lit.clone()), AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => MetaItemKind::NameValue(lit.clone()),
}, },
}) })
} }

View File

@ -580,7 +580,7 @@ pub(super) fn display_macro_source(
def_id: DefId, def_id: DefId,
vis: ty::Visibility<DefId>, vis: ty::Visibility<DefId>,
) -> String { ) -> String {
let tts: Vec<_> = def.body.inner_tokens().into_trees().collect(); let tts: Vec<_> = def.body.tokens.clone().into_trees().collect();
// Extract the spans of all matchers. They represent the "interface" of the macro. // Extract the spans of all matchers. They represent the "interface" of the macro.
let matchers = tts.chunks(4).map(|arm| &arm[0]); let matchers = tts.chunks(4).map(|arm| &arm[0]);

View File

@ -55,7 +55,7 @@ impl EarlyLintPass for CrateInMacroDef {
if_chain! { if_chain! {
if item.attrs.iter().any(is_macro_export); if item.attrs.iter().any(is_macro_export);
if let ItemKind::MacroDef(macro_def) = &item.kind; if let ItemKind::MacroDef(macro_def) = &item.kind;
let tts = macro_def.body.inner_tokens(); let tts = macro_def.body.tokens.clone();
if let Some(span) = contains_unhygienic_crate_reference(&tts); if let Some(span) = contains_unhygienic_crate_reference(&tts);
then { then {
span_lint_and_sugg( span_lint_and_sugg(

View File

@ -388,7 +388,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
&& over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind)) && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
}, },
(MacCall(l), MacCall(r)) => eq_mac_call(l, r), (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
(MacroDef(l), MacroDef(r)) => l.macro_rules == r.macro_rules && eq_mac_args(&l.body, &r.body), (MacroDef(l), MacroDef(r)) => l.macro_rules == r.macro_rules && eq_delim_args(&l.body, &r.body),
_ => false, _ => false,
} }
} }
@ -709,7 +709,7 @@ pub fn eq_assoc_constraint(l: &AssocConstraint, r: &AssocConstraint) -> bool {
} }
pub fn eq_mac_call(l: &MacCall, r: &MacCall) -> bool { pub fn eq_mac_call(l: &MacCall, r: &MacCall) -> bool {
eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args) eq_path(&l.path, &r.path) && eq_delim_args(&l.args, &r.args)
} }
pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool { pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool {
@ -717,18 +717,22 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool {
l.style == r.style l.style == r.style
&& match (&l.kind, &r.kind) { && match (&l.kind, &r.kind) {
(DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2, (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2,
(Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_mac_args(&l.item.args, &r.item.args), (Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_attr_args(&l.item.args, &r.item.args),
_ => false, _ => false,
} }
} }
pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool { pub fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool {
use MacArgs::*; use AttrArgs::*;
match (l, r) { match (l, r) {
(Empty, Empty) => true, (Empty, Empty) => true,
(Delimited(_, ld, lts), Delimited(_, rd, rts)) => ld == rd && lts.eq_unspanned(rts), (Delimited(la), Delimited(ra)) => eq_delim_args(la, ra),
(Eq(_, MacArgsEq::Ast(le)), Eq(_, MacArgsEq::Ast(re))) => eq_expr(le, re), (Eq(_, AttrArgsEq::Ast(le)), Eq(_, AttrArgsEq::Ast(re))) => eq_expr(le, re),
(Eq(_, MacArgsEq::Hir(ll)), Eq(_, MacArgsEq::Hir(rl))) => ll.kind == rl.kind, (Eq(_, AttrArgsEq::Hir(ll)), Eq(_, AttrArgsEq::Hir(rl))) => ll.kind == rl.kind,
_ => false, _ => false,
} }
} }
pub fn eq_delim_args(l: &DelimArgs, r: &DelimArgs) -> bool {
l.delim == r.delim && l.tokens.eq_unspanned(&r.tokens)
}

View File

@ -1341,7 +1341,7 @@ pub(crate) fn can_be_overflowed_expr(
} }
ast::ExprKind::MacCall(ref mac) => { ast::ExprKind::MacCall(ref mac) => {
match ( match (
rustc_ast::ast::MacDelimiter::from_token(mac.args.delim().unwrap()), rustc_ast::ast::MacDelimiter::from_token(mac.args.delim.to_token()),
context.config.overflow_delimited_expr(), context.config.overflow_delimited_expr(),
) { ) {
(Some(ast::MacDelimiter::Bracket), true) (Some(ast::MacDelimiter::Bracket), true)

View File

@ -208,7 +208,7 @@ fn rewrite_macro_inner(
original_style original_style
}; };
let ts = mac.args.inner_tokens(); let ts = mac.args.tokens.clone();
let has_comment = contains_comment(context.snippet(mac.span())); let has_comment = contains_comment(context.snippet(mac.span()));
if ts.is_empty() && !has_comment { if ts.is_empty() && !has_comment {
return match style { return match style {
@ -392,7 +392,7 @@ pub(crate) fn rewrite_macro_def(
return snippet; return snippet;
} }
let ts = def.body.inner_tokens(); let ts = def.body.tokens.clone();
let mut parser = MacroParser::new(ts.into_trees()); let mut parser = MacroParser::new(ts.into_trees());
let parsed_def = match parser.parse() { let parsed_def = match parser.parse() {
Some(def) => def, Some(def) => def,
@ -1087,7 +1087,7 @@ pub(crate) fn convert_try_mac(
) -> Option<ast::Expr> { ) -> Option<ast::Expr> {
let path = &pprust::path_to_string(&mac.path); let path = &pprust::path_to_string(&mac.path);
if path == "try" || path == "r#try" { if path == "try" || path == "r#try" {
let ts = mac.args.inner_tokens(); let ts = mac.args.tokens.clone();
Some(ast::Expr { Some(ast::Expr {
id: ast::NodeId::root(), // dummy value id: ast::NodeId::root(), // dummy value

View File

@ -5,7 +5,7 @@ use crate::rewrite::RewriteContext;
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option<AsmArgs> { pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option<AsmArgs> {
let ts = mac.args.inner_tokens(); let ts = mac.args.tokens.clone();
let mut parser = super::build_parser(context, ts); let mut parser = super::build_parser(context, ts);
parse_asm_args(&mut parser, context.parse_sess.inner(), mac.span(), false).ok() parse_asm_args(&mut parser, context.parse_sess.inner(), mac.span(), false).ok()
} }

View File

@ -23,7 +23,7 @@ fn parse_cfg_if_inner<'a>(
sess: &'a ParseSess, sess: &'a ParseSess,
mac: &'a ast::MacCall, mac: &'a ast::MacCall,
) -> Result<Vec<ast::Item>, &'static str> { ) -> Result<Vec<ast::Item>, &'static str> {
let ts = mac.args.inner_tokens(); let ts = mac.args.tokens.clone();
let mut parser = build_stream_parser(sess.inner(), ts); let mut parser = build_stream_parser(sess.inner(), ts);
let mut items = vec![]; let mut items = vec![];