diff options
| author | Nicholas Nethercote <n.nethercote@gmail.com> | 2022-11-18 11:24:21 +1100 |
|---|---|---|
| committer | Nicholas Nethercote <n.nethercote@gmail.com> | 2022-11-22 09:04:15 +1100 |
| commit | 3e3a4192d8cda0c308ea87b2e8f6f1e8dcc74739 (patch) | |
| tree | 5cbe2cba5da6a3eabde9d310eb7c0ac5aaa1d83c /compiler/rustc_parse/src | |
| parent | 1cbc45942d5c0f6eb5d94e3b10762ba541958035 (diff) | |
| download | rust-3e3a4192d8cda0c308ea87b2e8f6f1e8dcc74739.tar.gz rust-3e3a4192d8cda0c308ea87b2e8f6f1e8dcc74739.zip | |
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.
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/lib.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 63 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/pat.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/stmt.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/validate_attr.rs | 15 |
8 files changed, 61 insertions, 62 deletions
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index c78479b098b..b49a01d75ed 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -15,8 +15,7 @@ extern crate tracing; use rustc_ast as ast; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::Attribute; -use rustc_ast::{AttrItem, MetaItem}; +use rustc_ast::{AttrItem, Attribute, MetaItem}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult}; @@ -257,10 +256,12 @@ 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(ast::DelimArgs { dspan, delim, ref tokens }) + if !tokens.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()) { + match parse_in(parse_sess, tokens.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) { Ok(r) => return Some(r), Err(mut e) => { e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP)) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index fe7401786a0..ba73fbd3e12 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -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)) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index e5f58ca3894..20b01f554f2 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -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())], diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 13a38a17735..8878c404c58 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -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_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 { + AttrArgs::Empty + } + }) } - 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 - } - } else { - return self.unexpected(); - }, - ) + 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( diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 0e202645a39..bf52febb107 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -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)) } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 7820bbc1789..73de86820d8 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -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 }); diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index d6854f07025..fecf67cb596 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -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() { diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 8e7f8bfe0f5..e2f95d74a3d 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -3,7 +3,8 @@ use crate::parse_in; 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_errors::{Applicability, FatalError, PResult}; 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 => { 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| { @@ -42,13 +43,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::Delimited(dspan, delim, t) => { + AttrArgs::Empty => MetaItemKind::Word, + AttrArgs::Delimited(DelimArgs { dspan, delim, tokens }) => { 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) } - MacArgs::Eq(_, MacArgsEq::Ast(expr)) => { + AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => { if let ast::ExprKind::Lit(token_lit) = expr.kind && 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); } } - MacArgs::Eq(_, MacArgsEq::Hir(lit)) => MetaItemKind::NameValue(lit.clone()), + AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => MetaItemKind::NameValue(lit.clone()), }, }) } |
