1
Fork 0

Rollup merge of #104559 - nnethercote:split-MacArgs, r=petrochenkov

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.

r? `@petrochenkov`
This commit is contained in:
Matthias Krüger 2022-11-22 00:01:09 +01:00 committed by GitHub
commit 589d843bd0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 252 additions and 248 deletions

View file

@ -1501,7 +1501,7 @@ impl<'a> Parser<'a> {
let lo = path.span;
let mac = P(MacCall {
path,
args: self.parse_mac_args()?,
args: self.parse_delim_args()?,
prior_type_ascription: self.last_type_ascription,
});
(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::{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::{MacCall, MacDelimiter};
use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, IntoDiagnostic, PResult, StashKey};
use rustc_span::edition::Edition;
@ -471,7 +471,7 @@ impl<'a> Parser<'a> {
fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> {
let path = self.parse_path(PathStyle::Mod)?; // `foo::bar`
self.expect(&token::Not)?; // `!`
match self.parse_mac_args() {
match self.parse_delim_args() {
// `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`.
Ok(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> {
let ident = self.parse_ident()?;
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)) {
let params = self.parse_token_tree(); // `MacParams`
let pspan = params.span();
@ -1880,7 +1880,7 @@ impl<'a> Parser<'a> {
let arrow = TokenTree::token_alone(token::FatArrow, pspan.between(bspan)); // `=>`
let tokens = TokenStream::new(vec![params, arrow, body]);
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 {
return self.unexpected();
};
@ -1935,7 +1935,7 @@ impl<'a> Parser<'a> {
.emit();
}
let body = self.parse_mac_args()?;
let body = self.parse_delim_args()?;
self.eat_semi_for_macro_if_needed(&body);
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) {
self.report_invalid_macro_expansion_item(args);
}
}
fn report_invalid_macro_expansion_item(&self, args: &MacArgs) {
let span = args.span().expect("undelimited macro call");
fn report_invalid_macro_expansion_item(&self, args: &DelimArgs) {
let span = args.dspan.entire();
let mut err = self.struct_span_err(
span,
"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.
if !span.from_expansion() {
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 } = args.dspan;
err.multipart_suggestion(
"change the delimiters to curly braces",
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::AttrId;
use rustc_ast::DUMMY_NODE_ID;
use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, Extern};
use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacArgsEq, MacDelimiter, Mutability, StrLit};
use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, DelimArgs, Extern};
use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutability, StrLit};
use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
@ -1249,39 +1249,40 @@ impl<'a> Parser<'a> {
}
}
fn parse_mac_args(&mut self) -> PResult<'a, P<MacArgs>> {
self.parse_mac_args_common(true).map(P)
fn parse_delim_args(&mut self) -> PResult<'a, P<DelimArgs>> {
if let Some(args) = self.parse_delim_args_inner() { Ok(P(args)) } else { self.unexpected() }
}
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, MacArgs> {
Ok(
if self.check(&token::OpenDelim(Delimiter::Parenthesis))
|| 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
}
fn parse_attr_args(&mut self) -> PResult<'a, AttrArgs> {
Ok(if let Some(args) = self.parse_delim_args_inner() {
AttrArgs::Delimited(args)
} else {
if self.eat(&token::Eq) {
let eq_span = self.prev_token.span;
AttrArgs::Eq(eq_span, AttrArgsEq::Ast(self.parse_expr_force_collect()?))
} 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(

View file

@ -693,7 +693,7 @@ impl<'a> Parser<'a> {
/// Parse macro invocation
fn parse_pat_mac_invoc(&mut self, path: Path) -> PResult<'a, PatKind> {
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 });
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`.
/// 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> {
let args = self.parse_mac_args()?;
let delim = args.delim();
let args = self.parse_delim_args()?;
let delim = args.delim.to_token();
let hi = self.prev_token.span;
let style = match delim {
Some(Delimiter::Brace) => MacStmtStyle::Braces,
Some(_) => MacStmtStyle::NoBraces,
None => unreachable!(),
Delimiter::Brace => MacStmtStyle::Braces,
_ => MacStmtStyle::NoBraces,
};
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
Ok(TyKind::MacCall(P(MacCall {
path,
args: self.parse_mac_args()?,
args: self.parse_delim_args()?,
prior_type_ascription: self.last_type_ascription,
})))
} else if allow_plus == AllowPlus::Yes && self.check_plus() {