diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 77db2a5d93b..5d0c474140f 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -14,6 +14,8 @@ use rustc_parse::configure; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; use rustc_parse::DirectoryOwnership; +use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; +use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Symbol}; @@ -1087,6 +1089,16 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { .note("this may become a hard error in a future release") .emit(); } + + if attr.doc_str().is_some() { + self.cx.parse_sess.buffer_lint_with_diagnostic( + &UNUSED_DOC_COMMENTS, + attr.span, + ast::CRATE_NODE_ID, + "unused doc comment", + BuiltinLintDiagnostics::UnusedDocComment(attr.span), + ); + } } } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 73c5f386e65..5c601803a77 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -738,87 +738,56 @@ impl EarlyLintPass for DeprecatedAttr { } } -declare_lint! { - pub UNUSED_DOC_COMMENTS, - Warn, - "detects doc comments that aren't used by rustdoc" -} +fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) { + let mut attrs = attrs.into_iter().peekable(); -declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]); + // Accumulate a single span for sugared doc comments. + let mut sugared_span: Option = None; -impl UnusedDocComment { - fn warn_if_doc( - &self, - cx: &EarlyContext<'_>, - node_span: Span, - node_kind: &str, - is_macro_expansion: bool, - attrs: &[ast::Attribute], - ) { - let mut attrs = attrs.into_iter().peekable(); + while let Some(attr) = attrs.next() { + if attr.is_doc_comment() { + sugared_span = + Some(sugared_span.map_or_else(|| attr.span, |span| span.with_hi(attr.span.hi()))); + } - // Accumulate a single span for sugared doc comments. - let mut sugared_span: Option = None; + if attrs.peek().map(|next_attr| next_attr.is_doc_comment()).unwrap_or_default() { + continue; + } - while let Some(attr) = attrs.next() { - if attr.is_doc_comment() { - sugared_span = Some( - sugared_span.map_or_else(|| attr.span, |span| span.with_hi(attr.span.hi())), + let span = sugared_span.take().unwrap_or_else(|| attr.span); + + if attr.is_doc_comment() || attr.check_name(sym::doc) { + cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| { + let mut err = lint.build("unused doc comment"); + err.span_label( + node_span, + format!("rustdoc does not generate documentation for {}", node_kind), ); - } - - if attrs.peek().map(|next_attr| next_attr.is_doc_comment()).unwrap_or_default() { - continue; - } - - let span = sugared_span.take().unwrap_or_else(|| attr.span); - - if attr.is_doc_comment() || attr.check_name(sym::doc) { - cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| { - let mut err = lint.build("unused doc comment"); - err.span_label( - node_span, - format!("rustdoc does not generate documentation for {}", node_kind), - ); - if is_macro_expansion { - err.help( - "to document an item produced by a macro, \ - the macro must produce the documentation as part of its expansion", - ); - } - err.emit(); - }); - } + err.emit(); + }); } } } impl EarlyLintPass for UnusedDocComment { - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if let ast::ItemKind::Mac(..) = item.kind { - self.warn_if_doc(cx, item.span, "macro expansions", true, &item.attrs); - } - } - fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) { - let (kind, is_macro_expansion) = match stmt.kind { - ast::StmtKind::Local(..) => ("statements", false), - ast::StmtKind::Item(..) => ("inner items", false), - ast::StmtKind::Mac(..) => ("macro expansions", true), + let kind = match stmt.kind { + ast::StmtKind::Local(..) => "statements", + ast::StmtKind::Item(..) => "inner items", // expressions will be reported by `check_expr`. - ast::StmtKind::Semi(..) | ast::StmtKind::Expr(..) => return, + ast::StmtKind::Semi(..) | ast::StmtKind::Expr(..) | ast::StmtKind::Mac(..) => return, }; - self.warn_if_doc(cx, stmt.span, kind, is_macro_expansion, stmt.kind.attrs()); + warn_if_doc(cx, stmt.span, kind, stmt.kind.attrs()); } fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) { let arm_span = arm.pat.span.with_hi(arm.body.span.hi()); - self.warn_if_doc(cx, arm_span, "match arms", false, &arm.attrs); + warn_if_doc(cx, arm_span, "match arms", &arm.attrs); } fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { - self.warn_if_doc(cx, expr.span, "expressions", false, &expr.attrs); + warn_if_doc(cx, expr.span, "expressions", &expr.attrs); } } diff --git a/src/librustc_lint/context.rs b/src/librustc_lint/context.rs index 8e8beefa72f..adad1198b09 100644 --- a/src/librustc_lint/context.rs +++ b/src/librustc_lint/context.rs @@ -565,6 +565,11 @@ pub trait LintContext: Sized { BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => { stability::deprecation_suggestion(&mut db, suggestion, span) } + BuiltinLintDiagnostics::UnusedDocComment(span) => { + db.span_label(span, "rustdoc does not generate documentation for macros"); + db.help("to document an item produced by a macro, \ + the macro must produce the documentation as part of its expansion"); + } } // Rewrap `db`, and pass control to the user. decorate(LintDiagnosticBuilder::new(db)); diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 0e7625da30a..7b42cd0e4a2 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -94,7 +94,7 @@ fn lint_mod(tcx: TyCtxt<'_>, module_def_id: DefId) { macro_rules! pre_expansion_lint_passes { ($macro:path, $args:tt) => { - $macro!($args, [KeywordIdents: KeywordIdents, UnusedDocComment: UnusedDocComment,]); + $macro!($args, [KeywordIdents: KeywordIdents,]); }; } @@ -114,6 +114,7 @@ macro_rules! early_lint_passes { NonAsciiIdents: NonAsciiIdents, IncompleteFeatures: IncompleteFeatures, RedundantSemicolon: RedundantSemicolon, + UnusedDocComment: UnusedDocComment, ] ); }; diff --git a/src/librustc_session/lint.rs b/src/librustc_session/lint.rs index 983dfb19919..6d4f1ff5b48 100644 --- a/src/librustc_session/lint.rs +++ b/src/librustc_session/lint.rs @@ -190,6 +190,7 @@ pub enum BuiltinLintDiagnostics { UnusedImports(String, Vec<(Span, String)>), RedundantImport(Vec<(Span, bool)>, Ident), DeprecatedMacro(Option, Span), + UnusedDocComment(Span), } /// Lints that are buffered up early on in the `Session` before the diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index 603ed4640a0..f8a4e024605 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -564,3 +564,11 @@ declare_lint_pass! { INLINE_NO_SANITIZE, ] } + +declare_lint! { + pub UNUSED_DOC_COMMENTS, + Warn, + "detects doc comments that aren't used by rustdoc" +} + +declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]); diff --git a/src/librustc_session/parse.rs b/src/librustc_session/parse.rs index 6a4871b6da0..30888e343ed 100644 --- a/src/librustc_session/parse.rs +++ b/src/librustc_session/parse.rs @@ -176,6 +176,25 @@ impl ParseSess { }); } + pub fn buffer_lint_with_diagnostic( + &self, + lint: &'static Lint, + span: impl Into, + node_id: NodeId, + msg: &str, + diagnostic: BuiltinLintDiagnostics, + ) { + self.buffered_lints.with_lock(|buffered_lints| { + buffered_lints.push(BufferedEarlyLint { + span: span.into(), + node_id, + msg: msg.into(), + lint_id: LintId::of(lint), + diagnostic, + }); + }); + } + /// Extend an error with a suggestion to wrap an expression with parentheses to allow the /// parser to continue parsing the following operation as part of the same expression. pub fn expr_parentheses_needed( diff --git a/src/libstd/sys/wasi/fd.rs b/src/libstd/sys/wasi/fd.rs index 00327c1743c..8458ded5db0 100644 --- a/src/libstd/sys/wasi/fd.rs +++ b/src/libstd/sys/wasi/fd.rs @@ -13,19 +13,15 @@ pub struct WasiFd { fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] { assert_eq!(mem::size_of::>(), mem::size_of::()); assert_eq!(mem::align_of::>(), mem::align_of::()); - /// SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout - unsafe { - mem::transmute(a) - } + // SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout + unsafe { mem::transmute(a) } } fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] { assert_eq!(mem::size_of::>(), mem::size_of::()); assert_eq!(mem::align_of::>(), mem::align_of::()); - /// SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout - unsafe { - mem::transmute(a) - } + // SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout + unsafe { mem::transmute(a) } } impl WasiFd { diff --git a/src/test/ui/useless-comment.stderr b/src/test/ui/useless-comment.stderr index e5e4290d0e1..92817321a88 100644 --- a/src/test/ui/useless-comment.stderr +++ b/src/test/ui/useless-comment.stderr @@ -2,9 +2,7 @@ error: unused doc comment --> $DIR/useless-comment.rs:9:1 | LL | /// foo - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | mac!(); - | ------- rustdoc does not generate documentation for macro expansions + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macros | note: the lint level is defined here --> $DIR/useless-comment.rs:3:9 @@ -13,6 +11,14 @@ LL | #![deny(unused_doc_comments)] | ^^^^^^^^^^^^^^^^^^^ = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion +error: unused doc comment + --> $DIR/useless-comment.rs:32:5 + | +LL | /// bar + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macros + | + = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion + error: unused doc comment --> $DIR/useless-comment.rs:13:5 | @@ -68,16 +74,6 @@ LL | #[doc = "bar"] LL | 3; | - rustdoc does not generate documentation for expressions -error: unused doc comment - --> $DIR/useless-comment.rs:32:5 - | -LL | /// bar - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | mac!(); - | ------- rustdoc does not generate documentation for macro expansions - | - = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion - error: unused doc comment --> $DIR/useless-comment.rs:35:13 |