Skip to content

Commit b1f395d

Browse files
committed
Auto merge of #69084 - yaahc:delayed-doc-lint, r=petrochenkov
Split non macro portion of unused_doc_comment from macro part into two passes/lints ## Motivation This change is motivated by the needs of the [spandoc library](https://github.com/yaahc/spandoc). The specific use case is that my macro is removing doc comments when an attribute is applied to a fn with doc comments, but I would like the lint to still appear when I forget to add the `#[spandoc]` attribute to a fn, so I don't want to have to silence the lint globally. ## Approach This change splits the `unused _doc_comment` lint into two lints, `unused_macro_doc_comment` and `unused_doc_comment`. The non macro portion is moved into an `early_lint_pass` rather than a pre_expansion_pass. This allows proc macros to silence `unused_doc_comment` warnings by either adding an attribute to silence it or by removing the doc comment before the early_pass runs. The `unused_macro_doc_comment` lint however will still be impossible for proc-macros to silence, but the only alternative that I can see is to remove this lint entirely, which I don't think is acceptable / is a decision I'm not comfortable making personally, so instead I opted to split the macro portion of the check into a separate lint so that it can be silenced globally with an attribute if necessary without needing to globally silence the `unused_doc_comment` lint as well, which is still desireable. fixes #67838
2 parents 87b0d83 + 09bc5e3 commit b1f395d

File tree

9 files changed

+89
-82
lines changed

9 files changed

+89
-82
lines changed

src/librustc_expand/expand.rs

+12
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use rustc_parse::configure;
1414
use rustc_parse::parser::Parser;
1515
use rustc_parse::validate_attr;
1616
use rustc_parse::DirectoryOwnership;
17+
use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
18+
use rustc_session::lint::BuiltinLintDiagnostics;
1719
use rustc_session::parse::{feature_err, ParseSess};
1820
use rustc_span::source_map::respan;
1921
use rustc_span::symbol::{sym, Symbol};
@@ -1087,6 +1089,16 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
10871089
.note("this may become a hard error in a future release")
10881090
.emit();
10891091
}
1092+
1093+
if attr.doc_str().is_some() {
1094+
self.cx.parse_sess.buffer_lint_with_diagnostic(
1095+
&UNUSED_DOC_COMMENTS,
1096+
attr.span,
1097+
ast::CRATE_NODE_ID,
1098+
"unused doc comment",
1099+
BuiltinLintDiagnostics::UnusedDocComment(attr.span),
1100+
);
1101+
}
10901102
}
10911103
}
10921104
}

src/librustc_lint/builtin.rs

+29-60
Original file line numberDiff line numberDiff line change
@@ -738,87 +738,56 @@ impl EarlyLintPass for DeprecatedAttr {
738738
}
739739
}
740740

741-
declare_lint! {
742-
pub UNUSED_DOC_COMMENTS,
743-
Warn,
744-
"detects doc comments that aren't used by rustdoc"
745-
}
741+
fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) {
742+
let mut attrs = attrs.into_iter().peekable();
746743

747-
declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]);
744+
// Accumulate a single span for sugared doc comments.
745+
let mut sugared_span: Option<Span> = None;
748746

749-
impl UnusedDocComment {
750-
fn warn_if_doc(
751-
&self,
752-
cx: &EarlyContext<'_>,
753-
node_span: Span,
754-
node_kind: &str,
755-
is_macro_expansion: bool,
756-
attrs: &[ast::Attribute],
757-
) {
758-
let mut attrs = attrs.into_iter().peekable();
759-
760-
// Accumulate a single span for sugared doc comments.
761-
let mut sugared_span: Option<Span> = None;
762-
763-
while let Some(attr) = attrs.next() {
764-
if attr.is_doc_comment() {
765-
sugared_span = Some(
766-
sugared_span.map_or_else(|| attr.span, |span| span.with_hi(attr.span.hi())),
767-
);
768-
}
747+
while let Some(attr) = attrs.next() {
748+
if attr.is_doc_comment() {
749+
sugared_span =
750+
Some(sugared_span.map_or_else(|| attr.span, |span| span.with_hi(attr.span.hi())));
751+
}
769752

770-
if attrs.peek().map(|next_attr| next_attr.is_doc_comment()).unwrap_or_default() {
771-
continue;
772-
}
753+
if attrs.peek().map(|next_attr| next_attr.is_doc_comment()).unwrap_or_default() {
754+
continue;
755+
}
773756

774-
let span = sugared_span.take().unwrap_or_else(|| attr.span);
757+
let span = sugared_span.take().unwrap_or_else(|| attr.span);
775758

776-
if attr.is_doc_comment() || attr.check_name(sym::doc) {
777-
cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
778-
let mut err = lint.build("unused doc comment");
779-
err.span_label(
780-
node_span,
781-
format!("rustdoc does not generate documentation for {}", node_kind),
782-
);
783-
if is_macro_expansion {
784-
err.help(
785-
"to document an item produced by a macro, \
786-
the macro must produce the documentation as part of its expansion",
787-
);
788-
}
789-
err.emit();
790-
});
791-
}
759+
if attr.is_doc_comment() || attr.check_name(sym::doc) {
760+
cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
761+
let mut err = lint.build("unused doc comment");
762+
err.span_label(
763+
node_span,
764+
format!("rustdoc does not generate documentation for {}", node_kind),
765+
);
766+
err.emit();
767+
});
792768
}
793769
}
794770
}
795771

796772
impl EarlyLintPass for UnusedDocComment {
797-
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
798-
if let ast::ItemKind::Mac(..) = item.kind {
799-
self.warn_if_doc(cx, item.span, "macro expansions", true, &item.attrs);
800-
}
801-
}
802-
803773
fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
804-
let (kind, is_macro_expansion) = match stmt.kind {
805-
ast::StmtKind::Local(..) => ("statements", false),
806-
ast::StmtKind::Item(..) => ("inner items", false),
807-
ast::StmtKind::Mac(..) => ("macro expansions", true),
774+
let kind = match stmt.kind {
775+
ast::StmtKind::Local(..) => "statements",
776+
ast::StmtKind::Item(..) => "inner items",
808777
// expressions will be reported by `check_expr`.
809-
ast::StmtKind::Semi(..) | ast::StmtKind::Expr(..) => return,
778+
ast::StmtKind::Semi(..) | ast::StmtKind::Expr(..) | ast::StmtKind::Mac(..) => return,
810779
};
811780

812-
self.warn_if_doc(cx, stmt.span, kind, is_macro_expansion, stmt.kind.attrs());
781+
warn_if_doc(cx, stmt.span, kind, stmt.kind.attrs());
813782
}
814783

815784
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
816785
let arm_span = arm.pat.span.with_hi(arm.body.span.hi());
817-
self.warn_if_doc(cx, arm_span, "match arms", false, &arm.attrs);
786+
warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
818787
}
819788

820789
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
821-
self.warn_if_doc(cx, expr.span, "expressions", false, &expr.attrs);
790+
warn_if_doc(cx, expr.span, "expressions", &expr.attrs);
822791
}
823792
}
824793

src/librustc_lint/context.rs

+5
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,11 @@ pub trait LintContext: Sized {
565565
BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => {
566566
stability::deprecation_suggestion(&mut db, suggestion, span)
567567
}
568+
BuiltinLintDiagnostics::UnusedDocComment(span) => {
569+
db.span_label(span, "rustdoc does not generate documentation for macros");
570+
db.help("to document an item produced by a macro, \
571+
the macro must produce the documentation as part of its expansion");
572+
}
568573
}
569574
// Rewrap `db`, and pass control to the user.
570575
decorate(LintDiagnosticBuilder::new(db));

src/librustc_lint/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ fn lint_mod(tcx: TyCtxt<'_>, module_def_id: DefId) {
9494

9595
macro_rules! pre_expansion_lint_passes {
9696
($macro:path, $args:tt) => {
97-
$macro!($args, [KeywordIdents: KeywordIdents, UnusedDocComment: UnusedDocComment,]);
97+
$macro!($args, [KeywordIdents: KeywordIdents,]);
9898
};
9999
}
100100

@@ -114,6 +114,7 @@ macro_rules! early_lint_passes {
114114
NonAsciiIdents: NonAsciiIdents,
115115
IncompleteFeatures: IncompleteFeatures,
116116
RedundantSemicolon: RedundantSemicolon,
117+
UnusedDocComment: UnusedDocComment,
117118
]
118119
);
119120
};

src/librustc_session/lint.rs

+1
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ pub enum BuiltinLintDiagnostics {
190190
UnusedImports(String, Vec<(Span, String)>),
191191
RedundantImport(Vec<(Span, bool)>, Ident),
192192
DeprecatedMacro(Option<Symbol>, Span),
193+
UnusedDocComment(Span),
193194
}
194195

195196
/// Lints that are buffered up early on in the `Session` before the

src/librustc_session/lint/builtin.rs

+8
Original file line numberDiff line numberDiff line change
@@ -564,3 +564,11 @@ declare_lint_pass! {
564564
INLINE_NO_SANITIZE,
565565
]
566566
}
567+
568+
declare_lint! {
569+
pub UNUSED_DOC_COMMENTS,
570+
Warn,
571+
"detects doc comments that aren't used by rustdoc"
572+
}
573+
574+
declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]);

src/librustc_session/parse.rs

+19
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,25 @@ impl ParseSess {
176176
});
177177
}
178178

179+
pub fn buffer_lint_with_diagnostic(
180+
&self,
181+
lint: &'static Lint,
182+
span: impl Into<MultiSpan>,
183+
node_id: NodeId,
184+
msg: &str,
185+
diagnostic: BuiltinLintDiagnostics,
186+
) {
187+
self.buffered_lints.with_lock(|buffered_lints| {
188+
buffered_lints.push(BufferedEarlyLint {
189+
span: span.into(),
190+
node_id,
191+
msg: msg.into(),
192+
lint_id: LintId::of(lint),
193+
diagnostic,
194+
});
195+
});
196+
}
197+
179198
/// Extend an error with a suggestion to wrap an expression with parentheses to allow the
180199
/// parser to continue parsing the following operation as part of the same expression.
181200
pub fn expr_parentheses_needed(

src/libstd/sys/wasi/fd.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,15 @@ pub struct WasiFd {
1313
fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] {
1414
assert_eq!(mem::size_of::<IoSliceMut<'_>>(), mem::size_of::<wasi::Iovec>());
1515
assert_eq!(mem::align_of::<IoSliceMut<'_>>(), mem::align_of::<wasi::Iovec>());
16-
/// SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout
17-
unsafe {
18-
mem::transmute(a)
19-
}
16+
// SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout
17+
unsafe { mem::transmute(a) }
2018
}
2119

2220
fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] {
2321
assert_eq!(mem::size_of::<IoSlice<'_>>(), mem::size_of::<wasi::Ciovec>());
2422
assert_eq!(mem::align_of::<IoSlice<'_>>(), mem::align_of::<wasi::Ciovec>());
25-
/// SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout
26-
unsafe {
27-
mem::transmute(a)
28-
}
23+
// SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout
24+
unsafe { mem::transmute(a) }
2925
}
3026

3127
impl WasiFd {

src/test/ui/useless-comment.stderr

+9-13
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ error: unused doc comment
22
--> $DIR/useless-comment.rs:9:1
33
|
44
LL | /// foo
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6-
LL | mac!();
7-
| ------- rustdoc does not generate documentation for macro expansions
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macros
86
|
97
note: the lint level is defined here
108
--> $DIR/useless-comment.rs:3:9
@@ -13,6 +11,14 @@ LL | #![deny(unused_doc_comments)]
1311
| ^^^^^^^^^^^^^^^^^^^
1412
= help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion
1513

14+
error: unused doc comment
15+
--> $DIR/useless-comment.rs:32:5
16+
|
17+
LL | /// bar
18+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macros
19+
|
20+
= help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion
21+
1622
error: unused doc comment
1723
--> $DIR/useless-comment.rs:13:5
1824
|
@@ -68,16 +74,6 @@ LL | #[doc = "bar"]
6874
LL | 3;
6975
| - rustdoc does not generate documentation for expressions
7076

71-
error: unused doc comment
72-
--> $DIR/useless-comment.rs:32:5
73-
|
74-
LL | /// bar
75-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
76-
LL | mac!();
77-
| ------- rustdoc does not generate documentation for macro expansions
78-
|
79-
= help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion
80-
8177
error: unused doc comment
8278
--> $DIR/useless-comment.rs:35:13
8379
|

0 commit comments

Comments
 (0)