RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
};
use rustc_lint_defs::BuiltinLintDiagnostics;
-use rustc_parse::parser::Parser;
+use rustc_parse::parser::{Parser, Recovery};
use rustc_session::parse::ParseSess;
use rustc_session::Session;
use rustc_span::edition::Edition;
/// For tracing.
fn description() -> &'static str;
+
+ fn recovery() -> Recovery;
}
/// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to monomorphization.
fn description() -> &'static str {
"none"
}
+ fn recovery() -> Recovery {
+ Recovery::Forbidden
+ }
}
/// Expands the rules based macro defined by `lhses` and `rhses` for a given
let mut tracker = CollectTrackerAndEmitter::new(cx, sp);
let try_success_result = try_match_macro(sess, name, &arg, lhses, &mut tracker);
- assert!(try_success_result.is_err(), "Macro matching returned a success on the second try");
+
+ if try_success_result.is_ok() {
+ // Nonterminal parser recovery might turn failed matches into successful ones,
+ // but for that it must have emitted an error already
+ tracker.cx.sess.delay_span_bug(sp, "Macro matching returned a success on the second try");
+ }
if let Some(result) = tracker.result {
- // An irrecoverable error occured and has been emitted.
+ // An irrecoverable error occurred and has been emitted.
return result;
}
let Some((token, label, remaining_matcher)) = tracker.best_failure else {
- return tracker.result.expect("must have encountered Error or ErrorReported");
+ return DummyResult::any(sp);
};
let span = token.span.substitute_dummy(sp);
// Check whether there's a missing comma in this macro call, like `println!("{}" a);`
if let Some((arg, comma_span)) = arg.add_comma() {
for lhs in lhses {
- let parser = parser_from_cx(sess, arg.clone());
+ let parser = parser_from_cx(sess, arg.clone(), Recovery::Allowed);
let mut tt_parser = TtParser::new(name);
if let Success(_) =
fn after_arm(&mut self, result: &NamedParseResult) {
match result {
Success(_) => {
- unreachable!("should not collect detailed info for successful macro match");
+ // Nonterminal parser recovery might turn failed matches into successful ones,
+ // but for that it must have emitted an error already
+ self.cx.sess.delay_span_bug(
+ self.root_span,
+ "should not collect detailed info for successful macro match",
+ );
}
Failure(token, msg) => match self.best_failure {
Some((ref best_token, _, _)) if best_token.span.lo() >= token.span.lo() => {}
fn description() -> &'static str {
"detailed"
}
+
+ fn recovery() -> Recovery {
+ Recovery::Allowed
+ }
}
impl<'a, 'cx> CollectTrackerAndEmitter<'a, 'cx, '_> {
// 68836 suggests a more comprehensive but more complex change to deal with
// this situation.)
// FIXME(Nilstrieb): Stop recovery from happening on this parser and retry later with recovery if the macro failed to match.
- let parser = parser_from_cx(sess, arg.clone());
+ let parser = parser_from_cx(sess, arg.clone(), T::recovery());
// Try each arm's matchers.
let mut tt_parser = TtParser::new(name);
for (i, lhs) in lhses.iter().enumerate() {
}
}
-fn parser_from_cx(sess: &ParseSess, tts: TokenStream) -> Parser<'_> {
- Parser::new(sess, tts, true, rustc_parse::MACRO_ARGUMENTS)
+fn parser_from_cx(sess: &ParseSess, tts: TokenStream, recovery: Recovery) -> Parser<'_> {
+ Parser::new(sess, tts, true, rustc_parse::MACRO_ARGUMENTS).recovery(recovery)
}
/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For