explain doc comments in macros a bit

This commit is contained in:
Michael Goulet 2022-07-04 08:42:40 +00:00
parent c396bb3b8a
commit 2a973e2abc
3 changed files with 29 additions and 5 deletions

View File

@ -14,7 +14,7 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID};
use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, TransparencyError};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_feature::Features;
use rustc_lint_defs::builtin::{
RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
@ -25,6 +25,7 @@ use rustc_session::parse::ParseSess;
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;
@ -345,7 +346,7 @@ fn expand_macro<'cx>(
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);
// 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 {
@ -453,7 +454,10 @@ pub fn compile_declarative_macro(
Failure(token, msg) => {
let s = parse_failure_msg(&token);
let sp = token.span.substitute_dummy(def.span);
sess.parse_sess.span_diagnostic.struct_span_err(sp, &s).span_label(sp, msg).emit();
let mut err = sess.parse_sess.span_diagnostic.struct_span_err(sp, &s);
err.span_label(sp, msg);
annotate_doc_comment(&mut err, sess.source_map(), sp);
err.emit();
return dummy_syn_ext();
}
Error(sp, msg) => {
@ -590,6 +594,20 @@ pub fn compile_declarative_macro(
(mk_syn_ext(expander), rule_spans)
}
fn annotate_doc_comment(
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
sm: &SourceMap,
span: Span,
) {
if let Ok(src) = sm.span_to_snippet(span) {
if src.starts_with("///") || src.starts_with("/**") {
err.span_label(span, "outer doc comments expand to `#[doc = \"...\"]`, which is what this macro attempted to match");
} else if src.starts_with("//!") || src.starts_with("/*!") {
err.span_label(span, "inner doc comments expand to `#![doc = \"...\"]`, which is what this macro attempted to match");
}
}
}
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.

View File

@ -5,7 +5,10 @@ LL | macro_rules! outer {
| ------------------ when calling this macro
...
LL | //! Inner
| ^^^^^^^^^ no rules expected this token in macro call
| ^^^^^^^^^
| |
| no rules expected this token in macro call
| inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match
error: aborting due to previous error

View File

@ -5,7 +5,10 @@ LL | macro_rules! inner {
| ------------------ when calling this macro
...
LL | /// Outer
| ^^^^^^^^^ no rules expected this token in macro call
| ^^^^^^^^^
| |
| no rules expected this token in macro call
| outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match
error: aborting due to previous error