Move the missing fragment identifier checking.

In #95555 this was moved out of `parse_tt_inner` and `nameize` into
`compute_locs`. But the next commit will be moving `compute_locs`
outwards to a place that isn't suitable for the missing fragment
identifier checking. So this reinstates the old checking.
This commit is contained in:
Nicholas Nethercote 2022-04-05 16:31:30 +10:00
parent 896d8f5905
commit 7300bd6a38

View file

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