Rollup merge of #104638 - Nilstrieb:macro-diagnostics, r=compiler-errors
Move macro_rules diagnostics to diagnostics module This will make it easier to add more diagnostics in the future in a centralized place.
This commit is contained in:
commit
9043dfd946
@ -1,7 +1,7 @@
|
||||
use crate::base::*;
|
||||
use crate::config::StripUnconfigured;
|
||||
use crate::hygiene::SyntaxContext;
|
||||
use crate::mbe::macro_rules::annotate_err_with_kind;
|
||||
use crate::mbe::diagnostics::annotate_err_with_kind;
|
||||
use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
|
||||
use crate::placeholders::{placeholder, PlaceholderExpander};
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
//! why we call this module `mbe`. For external documentation, prefer the
|
||||
//! official terminology: "declarative macros".
|
||||
|
||||
pub(crate) mod diagnostics;
|
||||
pub(crate) mod macro_check;
|
||||
pub(crate) mod macro_parser;
|
||||
pub(crate) mod macro_rules;
|
||||
|
257
compiler/rustc_expand/src/mbe/diagnostics.rs
Normal file
257
compiler/rustc_expand/src/mbe/diagnostics.rs
Normal file
@ -0,0 +1,257 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::base::{DummyResult, ExtCtxt, MacResult};
|
||||
use crate::expand::{parse_ast_fragment, AstFragmentKind};
|
||||
use crate::mbe::{
|
||||
macro_parser::{MatcherLoc, NamedParseResult, ParseResult::*, TtParser},
|
||||
macro_rules::{try_match_macro, Tracker},
|
||||
};
|
||||
use rustc_ast::token::{self, Token};
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage};
|
||||
use rustc_parse::parser::{Parser, Recovery};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::Span;
|
||||
|
||||
use super::macro_rules::{parser_from_cx, NoopTracker};
|
||||
|
||||
pub(super) fn failed_to_match_macro<'cx>(
|
||||
cx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
def_span: Span,
|
||||
name: Ident,
|
||||
arg: TokenStream,
|
||||
lhses: &[Vec<MatcherLoc>],
|
||||
) -> Box<dyn MacResult + 'cx> {
|
||||
let sess = &cx.sess.parse_sess;
|
||||
|
||||
// An error occurred, try the expansion again, tracking the expansion closely for better diagnostics.
|
||||
let mut tracker = CollectTrackerAndEmitter::new(cx, sp);
|
||||
|
||||
let try_success_result = try_match_macro(sess, name, &arg, lhses, &mut tracker);
|
||||
|
||||
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 occurred and has been emitted.
|
||||
return result;
|
||||
}
|
||||
|
||||
let Some((token, label, remaining_matcher)) = tracker.best_failure else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
|
||||
let span = token.span.substitute_dummy(sp);
|
||||
|
||||
let mut err = cx.struct_span_err(span, &parse_failure_msg(&token));
|
||||
err.span_label(span, label);
|
||||
if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
|
||||
err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
|
||||
}
|
||||
|
||||
annotate_doc_comment(&mut err, sess.source_map(), span);
|
||||
|
||||
if let Some(span) = remaining_matcher.span() {
|
||||
err.span_note(span, format!("while trying to match {remaining_matcher}"));
|
||||
} else {
|
||||
err.note(format!("while trying to match {remaining_matcher}"));
|
||||
}
|
||||
|
||||
// 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(), Recovery::Allowed);
|
||||
let mut tt_parser = TtParser::new(name);
|
||||
|
||||
if let Success(_) =
|
||||
tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker)
|
||||
{
|
||||
if comma_span.is_dummy() {
|
||||
err.note("you might be missing a comma");
|
||||
} else {
|
||||
err.span_suggestion_short(
|
||||
comma_span,
|
||||
"missing comma here",
|
||||
", ",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
cx.trace_macros_diag();
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
|
||||
/// The tracker used for the slow error path that collects useful info for diagnostics.
|
||||
struct CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
|
||||
cx: &'a mut ExtCtxt<'cx>,
|
||||
remaining_matcher: Option<&'matcher MatcherLoc>,
|
||||
/// Which arm's failure should we report? (the one furthest along)
|
||||
best_failure: Option<(Token, &'static str, MatcherLoc)>,
|
||||
root_span: Span,
|
||||
result: Option<Box<dyn MacResult + 'cx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
|
||||
fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc) {
|
||||
if self.remaining_matcher.is_none()
|
||||
|| (parser.has_no_remaining_items_for_step() && *matcher != MatcherLoc::Eof)
|
||||
{
|
||||
self.remaining_matcher = Some(matcher);
|
||||
}
|
||||
}
|
||||
|
||||
fn after_arm(&mut self, result: &NamedParseResult) {
|
||||
match result {
|
||||
Success(_) => {
|
||||
// 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() => {}
|
||||
_ => {
|
||||
self.best_failure = Some((
|
||||
token.clone(),
|
||||
msg,
|
||||
self.remaining_matcher
|
||||
.expect("must have collected matcher already")
|
||||
.clone(),
|
||||
))
|
||||
}
|
||||
},
|
||||
Error(err_sp, msg) => {
|
||||
let span = err_sp.substitute_dummy(self.root_span);
|
||||
self.cx.struct_span_err(span, msg).emit();
|
||||
self.result = Some(DummyResult::any(span));
|
||||
}
|
||||
ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)),
|
||||
}
|
||||
}
|
||||
|
||||
fn description() -> &'static str {
|
||||
"detailed"
|
||||
}
|
||||
|
||||
fn recovery() -> Recovery {
|
||||
Recovery::Allowed
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'cx> CollectTrackerAndEmitter<'a, 'cx, '_> {
|
||||
fn new(cx: &'a mut ExtCtxt<'cx>, root_span: Span) -> Self {
|
||||
Self { cx, remaining_matcher: None, best_failure: None, root_span, result: None }
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn emit_frag_parse_err(
|
||||
mut e: DiagnosticBuilder<'_, rustc_errors::ErrorGuaranteed>,
|
||||
parser: &Parser<'_>,
|
||||
orig_parser: &mut Parser<'_>,
|
||||
site_span: Span,
|
||||
arm_span: Span,
|
||||
kind: AstFragmentKind,
|
||||
) {
|
||||
// FIXME(davidtwco): avoid depending on the error message text
|
||||
if parser.token == token::Eof
|
||||
&& let DiagnosticMessage::Str(message) = &e.message[0].0
|
||||
&& message.ends_with(", found `<eof>`")
|
||||
{
|
||||
let msg = &e.message[0];
|
||||
e.message[0] = (
|
||||
DiagnosticMessage::Str(format!(
|
||||
"macro expansion ends with an incomplete expression: {}",
|
||||
message.replace(", found `<eof>`", ""),
|
||||
)),
|
||||
msg.1,
|
||||
);
|
||||
if !e.span.is_dummy() {
|
||||
// early end of macro arm (#52866)
|
||||
e.replace_span_with(parser.token.span.shrink_to_hi());
|
||||
}
|
||||
}
|
||||
if e.span.is_dummy() {
|
||||
// Get around lack of span in error (#30128)
|
||||
e.replace_span_with(site_span);
|
||||
if !parser.sess.source_map().is_imported(arm_span) {
|
||||
e.span_label(arm_span, "in this macro arm");
|
||||
}
|
||||
} else if parser.sess.source_map().is_imported(parser.token.span) {
|
||||
e.span_label(site_span, "in this macro invocation");
|
||||
}
|
||||
match kind {
|
||||
// Try a statement if an expression is wanted but failed and suggest adding `;` to call.
|
||||
AstFragmentKind::Expr => match parse_ast_fragment(orig_parser, AstFragmentKind::Stmts) {
|
||||
Err(err) => err.cancel(),
|
||||
Ok(_) => {
|
||||
e.note(
|
||||
"the macro call doesn't expand to an expression, but it can expand to a statement",
|
||||
);
|
||||
e.span_suggestion_verbose(
|
||||
site_span.shrink_to_hi(),
|
||||
"add `;` to interpret the expansion as a statement",
|
||||
";",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
},
|
||||
_ => annotate_err_with_kind(&mut e, kind, site_span),
|
||||
};
|
||||
e.emit();
|
||||
}
|
||||
|
||||
pub(crate) fn annotate_err_with_kind(err: &mut Diagnostic, kind: AstFragmentKind, span: Span) {
|
||||
match kind {
|
||||
AstFragmentKind::Ty => {
|
||||
err.span_label(span, "this macro call doesn't expand to a type");
|
||||
}
|
||||
AstFragmentKind::Pat => {
|
||||
err.span_label(span, "this macro call doesn't expand to a pattern");
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
enum ExplainDocComment {
|
||||
#[label(expand_explain_doc_comment_inner)]
|
||||
Inner {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(expand_explain_doc_comment_outer)]
|
||||
Outer {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
pub(super) fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: Span) {
|
||||
if let Ok(src) = sm.span_to_snippet(span) {
|
||||
if src.starts_with("///") || src.starts_with("/**") {
|
||||
err.subdiagnostic(ExplainDocComment::Outer { span });
|
||||
} else if src.starts_with("//!") || src.starts_with("/*!") {
|
||||
err.subdiagnostic(ExplainDocComment::Inner { span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
|
||||
/// other tokens, this is "unexpected token...".
|
||||
pub(super) fn parse_failure_msg(tok: &Token) -> String {
|
||||
match tok.kind {
|
||||
token::Eof => "unexpected end of macro invocation".to_string(),
|
||||
_ => format!("no rules expected the token `{}`", pprust::token_to_string(tok),),
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
use crate::base::{SyntaxExtension, SyntaxExtensionKind};
|
||||
use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind};
|
||||
use crate::mbe;
|
||||
use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
|
||||
use crate::mbe::macro_check;
|
||||
use crate::mbe::macro_parser::{Error, ErrorReported, Failure, Success, TtParser};
|
||||
use crate::mbe::macro_parser::{MatchedSeq, MatchedTokenTree, MatcherLoc};
|
||||
@ -14,9 +15,7 @@
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr::{self as attr, TransparencyError};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_errors::{
|
||||
Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed,
|
||||
};
|
||||
use rustc_errors::{Applicability, ErrorGuaranteed};
|
||||
use rustc_feature::Features;
|
||||
use rustc_lint_defs::builtin::{
|
||||
RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
|
||||
@ -27,7 +26,6 @@
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent};
|
||||
use rustc_span::Span;
|
||||
|
||||
@ -35,6 +33,7 @@
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::{mem, slice};
|
||||
|
||||
use super::diagnostics;
|
||||
use super::macro_parser::{NamedMatches, NamedParseResult};
|
||||
|
||||
pub(crate) struct ParserAnyMacro<'a> {
|
||||
@ -51,74 +50,6 @@ pub(crate) struct ParserAnyMacro<'a> {
|
||||
is_local: bool,
|
||||
}
|
||||
|
||||
pub(crate) fn annotate_err_with_kind(err: &mut Diagnostic, kind: AstFragmentKind, span: Span) {
|
||||
match kind {
|
||||
AstFragmentKind::Ty => {
|
||||
err.span_label(span, "this macro call doesn't expand to a type");
|
||||
}
|
||||
AstFragmentKind::Pat => {
|
||||
err.span_label(span, "this macro call doesn't expand to a pattern");
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
fn emit_frag_parse_err(
|
||||
mut e: DiagnosticBuilder<'_, rustc_errors::ErrorGuaranteed>,
|
||||
parser: &Parser<'_>,
|
||||
orig_parser: &mut Parser<'_>,
|
||||
site_span: Span,
|
||||
arm_span: Span,
|
||||
kind: AstFragmentKind,
|
||||
) {
|
||||
// FIXME(davidtwco): avoid depending on the error message text
|
||||
if parser.token == token::Eof
|
||||
&& let DiagnosticMessage::Str(message) = &e.message[0].0
|
||||
&& message.ends_with(", found `<eof>`")
|
||||
{
|
||||
let msg = &e.message[0];
|
||||
e.message[0] = (
|
||||
DiagnosticMessage::Str(format!(
|
||||
"macro expansion ends with an incomplete expression: {}",
|
||||
message.replace(", found `<eof>`", ""),
|
||||
)),
|
||||
msg.1,
|
||||
);
|
||||
if !e.span.is_dummy() {
|
||||
// early end of macro arm (#52866)
|
||||
e.replace_span_with(parser.token.span.shrink_to_hi());
|
||||
}
|
||||
}
|
||||
if e.span.is_dummy() {
|
||||
// Get around lack of span in error (#30128)
|
||||
e.replace_span_with(site_span);
|
||||
if !parser.sess.source_map().is_imported(arm_span) {
|
||||
e.span_label(arm_span, "in this macro arm");
|
||||
}
|
||||
} else if parser.sess.source_map().is_imported(parser.token.span) {
|
||||
e.span_label(site_span, "in this macro invocation");
|
||||
}
|
||||
match kind {
|
||||
// Try a statement if an expression is wanted but failed and suggest adding `;` to call.
|
||||
AstFragmentKind::Expr => match parse_ast_fragment(orig_parser, AstFragmentKind::Stmts) {
|
||||
Err(err) => err.cancel(),
|
||||
Ok(_) => {
|
||||
e.note(
|
||||
"the macro call doesn't expand to an expression, but it can expand to a statement",
|
||||
);
|
||||
e.span_suggestion_verbose(
|
||||
site_span.shrink_to_hi(),
|
||||
"add `;` to interpret the expansion as a statement",
|
||||
";",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
},
|
||||
_ => annotate_err_with_kind(&mut e, kind, site_span),
|
||||
};
|
||||
e.emit();
|
||||
}
|
||||
|
||||
impl<'a> ParserAnyMacro<'a> {
|
||||
pub(crate) fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
|
||||
let ParserAnyMacro {
|
||||
@ -134,7 +65,7 @@ pub(crate) fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) ->
|
||||
let fragment = match parse_ast_fragment(parser, kind) {
|
||||
Ok(f) => f,
|
||||
Err(err) => {
|
||||
emit_frag_parse_err(err, parser, snapshot, site_span, arm_span, kind);
|
||||
diagnostics::emit_frag_parse_err(err, parser, snapshot, site_span, arm_span, kind);
|
||||
return kind.dummy(site_span);
|
||||
}
|
||||
};
|
||||
@ -224,7 +155,7 @@ pub(super) trait Tracker<'matcher> {
|
||||
}
|
||||
|
||||
/// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to monomorphization.
|
||||
struct NoopTracker;
|
||||
pub(super) struct NoopTracker;
|
||||
|
||||
impl<'matcher> Tracker<'matcher> for NoopTracker {
|
||||
fn before_match_loc(&mut self, _: &TtParser, _: &'matcher MatcherLoc) {}
|
||||
@ -331,135 +262,10 @@ fn expand_macro<'cx>(
|
||||
}
|
||||
}
|
||||
|
||||
// An error occurred, try the expansion again, tracking the expansion closely for better diagnostics.
|
||||
let mut tracker = CollectTrackerAndEmitter::new(cx, sp);
|
||||
|
||||
let try_success_result = try_match_macro(sess, name, &arg, lhses, &mut tracker);
|
||||
|
||||
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");
|
||||
diagnostics::failed_to_match_macro(cx, sp, def_span, name, arg, lhses)
|
||||
}
|
||||
|
||||
if let Some(result) = tracker.result {
|
||||
// An irrecoverable error occurred and has been emitted.
|
||||
return result;
|
||||
}
|
||||
|
||||
let Some((token, label, remaining_matcher)) = tracker.best_failure else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
|
||||
let span = token.span.substitute_dummy(sp);
|
||||
|
||||
let mut err = cx.struct_span_err(span, &parse_failure_msg(&token));
|
||||
err.span_label(span, label);
|
||||
if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
|
||||
err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
|
||||
}
|
||||
|
||||
annotate_doc_comment(&mut err, sess.source_map(), span);
|
||||
|
||||
if let Some(span) = remaining_matcher.span() {
|
||||
err.span_note(span, format!("while trying to match {remaining_matcher}"));
|
||||
} else {
|
||||
err.note(format!("while trying to match {remaining_matcher}"));
|
||||
}
|
||||
|
||||
// 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(), Recovery::Allowed);
|
||||
let mut tt_parser = TtParser::new(name);
|
||||
|
||||
if let Success(_) =
|
||||
tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker)
|
||||
{
|
||||
if comma_span.is_dummy() {
|
||||
err.note("you might be missing a comma");
|
||||
} else {
|
||||
err.span_suggestion_short(
|
||||
comma_span,
|
||||
"missing comma here",
|
||||
", ",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
cx.trace_macros_diag();
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
|
||||
/// The tracker used for the slow error path that collects useful info for diagnostics.
|
||||
struct CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
|
||||
cx: &'a mut ExtCtxt<'cx>,
|
||||
remaining_matcher: Option<&'matcher MatcherLoc>,
|
||||
/// Which arm's failure should we report? (the one furthest along)
|
||||
best_failure: Option<(Token, &'static str, MatcherLoc)>,
|
||||
root_span: Span,
|
||||
result: Option<Box<dyn MacResult + 'cx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
|
||||
fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc) {
|
||||
if self.remaining_matcher.is_none()
|
||||
|| (parser.has_no_remaining_items_for_step() && *matcher != MatcherLoc::Eof)
|
||||
{
|
||||
self.remaining_matcher = Some(matcher);
|
||||
}
|
||||
}
|
||||
|
||||
fn after_arm(&mut self, result: &NamedParseResult) {
|
||||
match result {
|
||||
Success(_) => {
|
||||
// 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() => {}
|
||||
_ => {
|
||||
self.best_failure = Some((
|
||||
token.clone(),
|
||||
msg,
|
||||
self.remaining_matcher
|
||||
.expect("must have collected matcher already")
|
||||
.clone(),
|
||||
))
|
||||
}
|
||||
},
|
||||
Error(err_sp, msg) => {
|
||||
let span = err_sp.substitute_dummy(self.root_span);
|
||||
self.cx.struct_span_err(span, msg).emit();
|
||||
self.result = Some(DummyResult::any(span));
|
||||
}
|
||||
ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)),
|
||||
}
|
||||
}
|
||||
|
||||
fn description() -> &'static str {
|
||||
"detailed"
|
||||
}
|
||||
|
||||
fn recovery() -> Recovery {
|
||||
Recovery::Allowed
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'cx> CollectTrackerAndEmitter<'a, 'cx, '_> {
|
||||
fn new(cx: &'a mut ExtCtxt<'cx>, root_span: Span) -> Self {
|
||||
Self { cx, remaining_matcher: None, best_failure: None, root_span, result: None }
|
||||
}
|
||||
}
|
||||
|
||||
enum CanRetry {
|
||||
pub(super) enum CanRetry {
|
||||
Yes,
|
||||
/// We are not allowed to retry macro expansion as a fatal error has been emitted already.
|
||||
No(ErrorGuaranteed),
|
||||
@ -469,7 +275,7 @@ enum CanRetry {
|
||||
/// and nothing if it failed. On failure, it's the callers job to use `track` accordingly to record all errors
|
||||
/// correctly.
|
||||
#[instrument(level = "debug", skip(sess, arg, lhses, track), fields(tracking = %T::description()))]
|
||||
fn try_match_macro<'matcher, T: Tracker<'matcher>>(
|
||||
pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
|
||||
sess: &ParseSess,
|
||||
name: Ident,
|
||||
arg: &TokenStream,
|
||||
@ -769,30 +575,6 @@ pub fn compile_declarative_macro(
|
||||
(mk_syn_ext(expander), rule_spans)
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
enum ExplainDocComment {
|
||||
#[label(expand_explain_doc_comment_inner)]
|
||||
Inner {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(expand_explain_doc_comment_outer)]
|
||||
Outer {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: Span) {
|
||||
if let Ok(src) = sm.span_to_snippet(span) {
|
||||
if src.starts_with("///") || src.starts_with("/**") {
|
||||
err.subdiagnostic(ExplainDocComment::Outer { span });
|
||||
} else if src.starts_with("//!") || src.starts_with("/*!") {
|
||||
err.subdiagnostic(ExplainDocComment::Inner { span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree) -> bool {
|
||||
// lhs is going to be like TokenTree::Delimited(...), where the
|
||||
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
|
||||
@ -1577,15 +1359,6 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
fn parser_from_cx(sess: &ParseSess, tts: TokenStream, recovery: Recovery) -> Parser<'_> {
|
||||
pub(super) 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
|
||||
/// other tokens, this is "unexpected token...".
|
||||
fn parse_failure_msg(tok: &Token) -> String {
|
||||
match tok.kind {
|
||||
token::Eof => "unexpected end of macro invocation".to_string(),
|
||||
_ => format!("no rules expected the token `{}`", pprust::token_to_string(tok),),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user