@@ -14,7 +14,7 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID};
14
14
use rustc_ast_pretty::pprust;
15
15
use rustc_attr::{self as attr, TransparencyError};
16
16
use rustc_data_structures::fx::FxHashMap;
17
- use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder } ;
17
+ use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed };
18
18
use rustc_feature::Features;
19
19
use rustc_lint_defs::builtin::{
20
20
RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
@@ -25,6 +25,7 @@ use rustc_session::parse::ParseSess;
25
25
use rustc_session::Session;
26
26
use rustc_span::edition::Edition;
27
27
use rustc_span::hygiene::Transparency;
28
+ use rustc_span::source_map::SourceMap;
28
29
use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent};
29
30
use rustc_span::Span;
30
31
@@ -345,7 +346,7 @@ fn expand_macro<'cx>(
345
346
if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
346
347
err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
347
348
}
348
-
349
+ annotate_doc_comment(&mut err, sess.source_map(), span);
349
350
// Check whether there's a missing comma in this macro call, like `println!("{}" a);`
350
351
if let Some((arg, comma_span)) = arg.add_comma() {
351
352
for lhs in lhses {
@@ -453,7 +454,10 @@ pub fn compile_declarative_macro(
453
454
Failure(token, msg) => {
454
455
let s = parse_failure_msg(&token);
455
456
let sp = token.span.substitute_dummy(def.span);
456
- sess. parse_sess . span_diagnostic . struct_span_err ( sp, & s) . span_label ( sp, msg) . emit ( ) ;
457
+ let mut err = sess.parse_sess.span_diagnostic.struct_span_err(sp, &s);
458
+ err.span_label(sp, msg);
459
+ annotate_doc_comment(&mut err, sess.source_map(), sp);
460
+ err.emit();
457
461
return dummy_syn_ext();
458
462
}
459
463
Error(sp, msg) => {
@@ -590,6 +594,20 @@ pub fn compile_declarative_macro(
590
594
(mk_syn_ext(expander), rule_spans)
591
595
}
592
596
597
+ fn annotate_doc_comment(
598
+ err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
599
+ sm: &SourceMap,
600
+ span: Span,
601
+ ) {
602
+ if let Ok(src) = sm.span_to_snippet(span) {
603
+ if src.starts_with("///") || src.starts_with("/**") {
604
+ err.span_label(span, "outer doc comments expand to `#[doc = \"...\"]`, which is what this macro attempted to match");
605
+ } else if src.starts_with("//!") || src.starts_with("/*!") {
606
+ err.span_label(span, "inner doc comments expand to `#![doc = \"...\"]`, which is what this macro attempted to match");
607
+ }
608
+ }
609
+ }
610
+
593
611
fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree) -> bool {
594
612
// lhs is going to be like TokenTree::Delimited(...), where the
595
613
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
0 commit comments