diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index eb1b0b4400096..76a92d1f8a0c3 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -131,7 +131,7 @@ enum MatcherLoc { MetaVarDecl { span: Span, bind: Ident, - kind: NonterminalKind, + kind: Option, next_metavar: usize, seq_depth: usize, }, @@ -337,18 +337,14 @@ impl TtParser { /// recursive. This conversion is fairly cheap and the representation is sufficiently better /// for matching than `&[TokenTree]` that it's a clear performance win even with the overhead. /// But it might be possible to move the conversion outwards so it only occurs once per macro. - fn compute_locs( - &mut self, - sess: &ParseSess, - matcher: &[TokenTree], - ) -> Result { + fn compute_locs(&mut self, sess: &ParseSess, matcher: &[TokenTree]) -> usize { fn inner( sess: &ParseSess, tts: &[TokenTree], locs: &mut Vec, next_metavar: &mut usize, seq_depth: usize, - ) -> Result<(), (Span, String)> { + ) { for tt in tts { match tt { TokenTree::Token(token) => { @@ -356,7 +352,7 @@ impl TtParser { } TokenTree::Delimited(_, delimited) => { locs.push(MatcherLoc::Delimited); - inner(sess, &delimited.all_tts, locs, next_metavar, seq_depth)?; + inner(sess, &delimited.all_tts, locs, next_metavar, seq_depth); } TokenTree::Sequence(_, seq) => { // We can't determine `idx_first_after` and construct the final @@ -370,7 +366,7 @@ impl TtParser { let op = seq.kleene.op; let idx_first = locs.len(); let idx_seq = idx_first - 1; - inner(sess, &seq.tts, locs, next_metavar, seq_depth + 1)?; + inner(sess, &seq.tts, locs, next_metavar, seq_depth + 1); if let Some(separator) = &seq.separator { locs.push(MatcherLoc::SequenceSep { separator: separator.clone() }); @@ -389,40 +385,29 @@ impl TtParser { }; } &TokenTree::MetaVarDecl(span, bind, kind) => { - if let Some(kind) = kind { - locs.push(MatcherLoc::MetaVarDecl { - span, - bind, - kind, - next_metavar: *next_metavar, - seq_depth, - }); - *next_metavar += 1; - } else if sess - .missing_fragment_specifiers - .borrow_mut() - .remove(&span) - .is_some() - { - // E.g. `$e` instead of `$e:expr`. - return Err((span, "missing fragment specifier".to_string())); - } + locs.push(MatcherLoc::MetaVarDecl { + span, + bind, + kind, + next_metavar: *next_metavar, + seq_depth, + }); + *next_metavar += 1; } TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(), } } - Ok(()) } self.locs.clear(); let mut next_metavar = 0; - inner(sess, matcher, &mut self.locs, &mut next_metavar, /* seq_depth */ 0)?; + inner(sess, matcher, &mut self.locs, &mut next_metavar, /* seq_depth */ 0); // A final entry is needed for eof. self.locs.push(MatcherLoc::Eof); // This is the number of metavar decls. - Ok(next_metavar) + next_metavar } /// Process the matcher positions of `cur_mps` until it is empty. In the process, this will @@ -434,6 +419,7 @@ impl TtParser { /// track of through the mps generated. fn parse_tt_inner( &mut self, + sess: &ParseSess, num_metavar_decls: usize, token: &Token, ) -> Option { @@ -532,12 +518,20 @@ impl TtParser { mp.idx = idx_first; self.cur_mps.push(mp); } - MatcherLoc::MetaVarDecl { kind, .. } => { + &MatcherLoc::MetaVarDecl { span, kind, .. } => { // Built-in nonterminals never start with these tokens, so we can eliminate // them from consideration. We use the span of the metavariable declaration // to determine any edition-specific matching behavior for non-terminals. - if Parser::nonterminal_may_begin_with(*kind, token) { - self.bb_mps.push(mp); + if let Some(kind) = kind { + if Parser::nonterminal_may_begin_with(kind, token) { + self.bb_mps.push(mp); + } + } else { + // Both this check and the one in `nameize` are necessary, surprisingly. + if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() { + // E.g. `$e` instead of `$e:expr`. + return Some(Error(span, "missing fragment specifier".to_string())); + } } } MatcherLoc::Eof => { @@ -564,7 +558,7 @@ impl TtParser { // Need to take ownership of the matches from within the `Lrc`. Lrc::make_mut(&mut eof_mp.matches); let matches = Lrc::try_unwrap(eof_mp.matches).unwrap().into_iter(); - self.nameize(matches) + self.nameize(sess, matches) } EofMatcherPositions::Multiple => { Error(token.span, "ambiguity: multiple successful parses".to_string()) @@ -588,10 +582,7 @@ impl TtParser { parser: &mut Cow<'_, Parser<'_>>, matcher: &[TokenTree], ) -> NamedParseResult { - let num_metavar_decls = match self.compute_locs(parser.sess, matcher) { - Ok(num_metavar_decls) => num_metavar_decls, - Err((span, msg)) => return Error(span, msg), - }; + let num_metavar_decls = self.compute_locs(parser.sess, matcher); // A queue of possible matcher positions. We initialize it with the matcher position in // which the "dot" is before the first token of the first token tree in `matcher`. @@ -607,7 +598,7 @@ impl TtParser { // Process `cur_mps` until either we have finished the input or we need to get some // parsing from the black-box parser done. - if let Some(res) = self.parse_tt_inner(num_metavar_decls, &parser.token) { + if let Some(res) = self.parse_tt_inner(&parser.sess, num_metavar_decls, &parser.token) { return res; } @@ -637,7 +628,11 @@ impl TtParser { let mut mp = self.bb_mps.pop().unwrap(); let loc = &self.locs[mp.idx]; if let &MatcherLoc::MetaVarDecl { - span, kind, next_metavar, seq_depth, .. + span, + kind: Some(kind), + next_metavar, + seq_depth, + .. } = loc { // We use the span of the metavariable declaration to determine any @@ -682,7 +677,9 @@ impl TtParser { .bb_mps .iter() .map(|mp| match &self.locs[mp.idx] { - MatcherLoc::MetaVarDecl { bind, kind, .. } => format!("{} ('{}')", kind, bind), + MatcherLoc::MetaVarDecl { bind, kind: Some(kind), .. } => { + format!("{} ('{}')", kind, bind) + } _ => unreachable!(), }) .collect::>() @@ -702,16 +699,30 @@ impl TtParser { ) } - fn nameize>(&self, mut res: I) -> NamedParseResult { + fn nameize>( + &self, + sess: &ParseSess, + mut res: I, + ) -> NamedParseResult { // Make that each metavar has _exactly one_ binding. If so, insert the binding into the // `NamedParseResult`. Otherwise, it's an error. let mut ret_val = FxHashMap::default(); for loc in self.locs.iter() { - if let &MatcherLoc::MetaVarDecl { span, bind, .. } = loc { - match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) { - Vacant(spot) => spot.insert(res.next().unwrap()), - Occupied(..) => return Error(span, format!("duplicated bind name: {}", bind)), - }; + if let &MatcherLoc::MetaVarDecl { span, bind, kind, .. } = loc { + if kind.is_some() { + match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) { + Vacant(spot) => spot.insert(res.next().unwrap()), + Occupied(..) => { + return Error(span, format!("duplicated bind name: {}", bind)); + } + }; + } else { + // Both this check and the one in `parse_tt_inner` are necessary, surprisingly. + if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() { + // E.g. `$e` instead of `$e:expr`. + return Error(span, "missing fragment specifier".to_string()); + } + } } } Success(ret_val)