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:
commit
589d843bd0
33 changed files with 252 additions and 248 deletions
|
@ -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))
|
||||
|
|
|
@ -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())],
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue