@@ -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,34 @@ pub fn compile_declarative_macro(
590
594
( mk_syn_ext ( expander) , rule_spans)
591
595
}
592
596
597
+ #[ derive( SessionSubdiagnostic ) ]
598
+ enum ExplainDocComment {
599
+ #[ label( expand:: explain_doc_comment_inner) ]
600
+ Inner {
601
+ #[ primary_span]
602
+ span : Span ,
603
+ } ,
604
+ #[ label( expand:: explain_doc_comment_outer) ]
605
+ Outer {
606
+ #[ primary_span]
607
+ span : Span ,
608
+ } ,
609
+ }
610
+
611
+ fn annotate_doc_comment (
612
+ err : & mut DiagnosticBuilder < ' _ , ErrorGuaranteed > ,
613
+ sm : & SourceMap ,
614
+ span : Span ,
615
+ ) {
616
+ if let Ok ( src) = sm. span_to_snippet ( span) {
617
+ if src. starts_with ( "///" ) || src. starts_with ( "/**" ) {
618
+ err. subdiagnostic ( ExplainDocComment :: Outer { span } ) ;
619
+ } else if src. starts_with ( "//!" ) || src. starts_with ( "/*!" ) {
620
+ err. subdiagnostic ( ExplainDocComment :: Inner { span } ) ;
621
+ }
622
+ }
623
+ }
624
+
593
625
fn check_lhs_nt_follows ( sess : & ParseSess , def : & ast:: Item , lhs : & mbe:: TokenTree ) -> bool {
594
626
// lhs is going to be like TokenTree::Delimited(...), where the
595
627
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
0 commit comments