From 2a973e2abc2aaca790980032cc839183ef01d2c1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 4 Jul 2022 08:42:40 +0000 Subject: [PATCH 1/2] explain doc comments in macros a bit --- compiler/rustc_expand/src/mbe/macro_rules.rs | 24 ++++++++++++++++--- .../parser/macro/macro-doc-comments-1.stderr | 5 +++- .../parser/macro/macro-doc-comments-2.stderr | 5 +++- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index f40c365cbcc18..d2fae17a43bc3 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -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. diff --git a/src/test/ui/parser/macro/macro-doc-comments-1.stderr b/src/test/ui/parser/macro/macro-doc-comments-1.stderr index 96bdb9808eefd..0ebf3d52b6372 100644 --- a/src/test/ui/parser/macro/macro-doc-comments-1.stderr +++ b/src/test/ui/parser/macro/macro-doc-comments-1.stderr @@ -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 diff --git a/src/test/ui/parser/macro/macro-doc-comments-2.stderr b/src/test/ui/parser/macro/macro-doc-comments-2.stderr index 023d1a3e039f8..346d865868d99 100644 --- a/src/test/ui/parser/macro/macro-doc-comments-2.stderr +++ b/src/test/ui/parser/macro/macro-doc-comments-2.stderr @@ -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 From d2e5a929b99d8c26509ed638fb3b754c6603accf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 8 Jul 2022 03:21:49 +0000 Subject: [PATCH 2/2] use subdiagnostic for message --- .../locales/en-US/expand.ftl | 5 +++++ compiler/rustc_error_messages/src/lib.rs | 3 ++- compiler/rustc_expand/src/mbe/macro_rules.rs | 18 ++++++++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 compiler/rustc_error_messages/locales/en-US/expand.ftl diff --git a/compiler/rustc_error_messages/locales/en-US/expand.ftl b/compiler/rustc_error_messages/locales/en-US/expand.ftl new file mode 100644 index 0000000000000..8d506a3ea8bbc --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/expand.ftl @@ -0,0 +1,5 @@ +expand-explain-doc-comment-outer = + outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match + +expand-explain-doc-comment-inner = + inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 5a482bc5b2c39..d16171cb162d6 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -33,11 +33,12 @@ pub use unic_langid::{langid, LanguageIdentifier}; fluent_messages! { borrowck => "../locales/en-US/borrowck.ftl", builtin_macros => "../locales/en-US/builtin_macros.ftl", + const_eval => "../locales/en-US/const_eval.ftl", + expand => "../locales/en-US/expand.ftl", lint => "../locales/en-US/lint.ftl", parser => "../locales/en-US/parser.ftl", privacy => "../locales/en-US/privacy.ftl", typeck => "../locales/en-US/typeck.ftl", - const_eval => "../locales/en-US/const_eval.ftl", } pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES}; diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index d2fae17a43bc3..3e9ddd6aec075 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -594,6 +594,20 @@ pub fn compile_declarative_macro( (mk_syn_ext(expander), rule_spans) } +#[derive(SessionSubdiagnostic)] +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 DiagnosticBuilder<'_, ErrorGuaranteed>, sm: &SourceMap, @@ -601,9 +615,9 @@ fn annotate_doc_comment( ) { 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"); + err.subdiagnostic(ExplainDocComment::Outer { span }); } 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"); + err.subdiagnostic(ExplainDocComment::Inner { span }); } } }