about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/config.rs43
-rw-r--r--src/librustdoc/core.rs26
-rw-r--r--src/librustdoc/lib.rs3
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs2
-rw-r--r--src/librustdoc/passes/check_code_block_syntax.rs2
-rw-r--r--src/librustdoc/passes/collapse_docs.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs2
-rw-r--r--src/librustdoc/passes/mod.rs87
-rw-r--r--src/librustdoc/passes/private_items_doc_tests.rs2
-rw-r--r--src/librustdoc/passes/propagate_doc_cfg.rs2
-rw-r--r--src/librustdoc/passes/strip_hidden.rs2
-rw-r--r--src/librustdoc/passes/strip_priv_imports.rs2
-rw-r--r--src/librustdoc/passes/strip_private.rs2
-rw-r--r--src/librustdoc/passes/unindent_comments.rs2
-rw-r--r--src/test/rustdoc/issue-46380.rs5
-rw-r--r--src/test/rustdoc/issue-67851-both.rs8
-rw-r--r--src/test/rustdoc/issue-67851-hidden.rs8
-rw-r--r--src/test/rustdoc/issue-67851-neither.rs6
-rw-r--r--src/test/rustdoc/issue-67851-private.rs8
20 files changed, 138 insertions, 78 deletions
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 4a65a9f431a..dbb67345ba0 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -24,7 +24,7 @@ use crate::html;
 use crate::html::markdown::IdMap;
 use crate::html::static_files;
 use crate::opts;
-use crate::passes::{self, DefaultPassOption};
+use crate::passes::{self, Condition, DefaultPassOption};
 use crate::theme;
 
 /// Configuration options for rustdoc.
@@ -98,6 +98,10 @@ pub struct Options {
     ///
     /// Be aware: This option can come both from the CLI and from crate attributes!
     pub default_passes: DefaultPassOption,
+    /// Document items that have lower than `pub` visibility.
+    pub document_private: bool,
+    /// Document items that have `doc(hidden)`.
+    pub document_hidden: bool,
     /// Any passes manually selected by the user.
     ///
     /// Be aware: This option can come both from the CLI and from crate attributes!
@@ -146,6 +150,8 @@ impl fmt::Debug for Options {
             .field("test_args", &self.test_args)
             .field("persist_doctests", &self.persist_doctests)
             .field("default_passes", &self.default_passes)
+            .field("document_private", &self.document_private)
+            .field("document_hidden", &self.document_hidden)
             .field("manual_passes", &self.manual_passes)
             .field("display_warnings", &self.display_warnings)
             .field("show_coverage", &self.show_coverage)
@@ -240,22 +246,26 @@ impl Options {
                 println!("{:>20} - {}", pass.name, pass.description);
             }
             println!("\nDefault passes for rustdoc:");
-            for pass in passes::DEFAULT_PASSES {
-                println!("{:>20}", pass.name);
-            }
-            println!("\nPasses run with `--document-private-items`:");
-            for pass in passes::DEFAULT_PRIVATE_PASSES {
-                println!("{:>20}", pass.name);
+            for p in passes::DEFAULT_PASSES {
+                print!("{:>20}", p.pass.name);
+                println_condition(p.condition);
             }
 
             if nightly_options::is_nightly_build() {
                 println!("\nPasses run with `--show-coverage`:");
-                for pass in passes::DEFAULT_COVERAGE_PASSES {
-                    println!("{:>20}", pass.name);
+                for p in passes::COVERAGE_PASSES {
+                    print!("{:>20}", p.pass.name);
+                    println_condition(p.condition);
                 }
-                println!("\nPasses run with `--show-coverage --document-private-items`:");
-                for pass in passes::PRIVATE_COVERAGE_PASSES {
-                    println!("{:>20}", pass.name);
+            }
+
+            fn println_condition(condition: Condition) {
+                use Condition::*;
+                match condition {
+                    Always => println!(),
+                    WhenDocumentPrivate => println!("  (when --document-private-items)"),
+                    WhenNotDocumentPrivate => println!("  (when not --document-private-items)"),
+                    WhenNotDocumentHidden => println!("  (when not --document-hidden-items)"),
                 }
             }
 
@@ -449,16 +459,11 @@ impl Options {
             });
 
         let show_coverage = matches.opt_present("show-coverage");
-        let document_private = matches.opt_present("document-private-items");
 
         let default_passes = if matches.opt_present("no-defaults") {
             passes::DefaultPassOption::None
-        } else if show_coverage && document_private {
-            passes::DefaultPassOption::PrivateCoverage
         } else if show_coverage {
             passes::DefaultPassOption::Coverage
-        } else if document_private {
-            passes::DefaultPassOption::Private
         } else {
             passes::DefaultPassOption::Default
         };
@@ -497,6 +502,8 @@ impl Options {
         let runtool = matches.opt_str("runtool");
         let runtool_args = matches.opt_strs("runtool-arg");
         let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores");
+        let document_private = matches.opt_present("document-private-items");
+        let document_hidden = matches.opt_present("document-hidden-items");
 
         let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
 
@@ -523,6 +530,8 @@ impl Options {
             should_test,
             test_args,
             default_passes,
+            document_private,
+            document_hidden,
             manual_passes,
             display_warnings,
             show_coverage,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index cb22039327e..64c2a28de83 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -33,7 +33,7 @@ use crate::clean::{AttributesExt, MAX_DEF_ID};
 use crate::config::{Options as RustdocOptions, RenderOptions};
 use crate::html::render::RenderInfo;
 
-use crate::passes;
+use crate::passes::{self, Condition::*, ConditionalPass};
 
 pub use rustc::session::config::{CodegenOptions, Input, Options};
 pub use rustc::session::search_paths::SearchPath;
@@ -234,6 +234,8 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
         describe_lints,
         lint_cap,
         mut default_passes,
+        mut document_private,
+        document_hidden,
         mut manual_passes,
         display_warnings,
         render_options,
@@ -470,16 +472,14 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
                     }
 
                     if attr.is_word() && name == sym::document_private_items {
-                        if default_passes == passes::DefaultPassOption::Default {
-                            default_passes = passes::DefaultPassOption::Private;
-                        }
+                        document_private = true;
                     }
                 }
 
-                let passes = passes::defaults(default_passes).iter().chain(
+                let passes = passes::defaults(default_passes).iter().copied().chain(
                     manual_passes.into_iter().flat_map(|name| {
                         if let Some(pass) = passes::find_pass(&name) {
-                            Some(pass)
+                            Some(ConditionalPass::always(pass))
                         } else {
                             error!("unknown pass {}, skipping", name);
                             None
@@ -489,9 +489,17 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
 
                 info!("Executing passes");
 
-                for pass in passes {
-                    debug!("running pass {}", pass.name);
-                    krate = (pass.pass)(krate, &ctxt);
+                for p in passes {
+                    let run = match p.condition {
+                        Always => true,
+                        WhenDocumentPrivate => document_private,
+                        WhenNotDocumentPrivate => !document_private,
+                        WhenNotDocumentHidden => !document_hidden,
+                    };
+                    if run {
+                        debug!("running pass {}", p.pass.name);
+                        krate = (p.pass.run)(krate, &ctxt);
+                    }
                 }
 
                 ctxt.sess().abort_if_errors();
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 998b28b8807..281e78a692a 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -173,6 +173,9 @@ fn opts() -> Vec<RustcOptGroup> {
         stable("document-private-items", |o| {
             o.optflag("", "document-private-items", "document private items")
         }),
+        unstable("document-hidden-items", |o| {
+            o.optflag("", "document-hidden-items", "document items that have doc(hidden)")
+        }),
         stable("test", |o| o.optflag("", "test", "run code examples as tests")),
         stable("test-args", |o| {
             o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS")
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 803bcc2cfdf..7ed531c9206 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -12,7 +12,7 @@ use std::ops;
 
 pub const CALCULATE_DOC_COVERAGE: Pass = Pass {
     name: "calculate-doc-coverage",
-    pass: calculate_doc_coverage,
+    run: calculate_doc_coverage,
     description: "counts the number of items with and without documentation",
 };
 
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index b568d034d89..476c4a0a9c0 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -13,7 +13,7 @@ use crate::passes::Pass;
 
 pub const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
     name: "check-code-block-syntax",
-    pass: check_code_block_syntax,
+    run: check_code_block_syntax,
     description: "validates syntax inside Rust code blocks",
 };
 
diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs
index c6b22883e97..c2185592d14 100644
--- a/src/librustdoc/passes/collapse_docs.rs
+++ b/src/librustdoc/passes/collapse_docs.rs
@@ -8,7 +8,7 @@ use std::mem::take;
 
 pub const COLLAPSE_DOCS: Pass = Pass {
     name: "collapse-docs",
-    pass: collapse_docs,
+    run: collapse_docs,
     description: "concatenates all document attributes into one document attribute",
 };
 
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index a8bb40a06b9..26d49cf3485 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -28,7 +28,7 @@ use super::span_of_attrs;
 
 pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
     name: "collect-intra-doc-links",
-    pass: collect_intra_doc_links,
+    run: collect_intra_doc_links,
     description: "reads a crate's documentation to resolve intra-doc-links",
 };
 
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 63ad9a66a48..473e683df01 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -9,7 +9,7 @@ use rustc_span::symbol::sym;
 
 pub const COLLECT_TRAIT_IMPLS: Pass = Pass {
     name: "collect-trait-impls",
-    pass: collect_trait_impls,
+    run: collect_trait_impls,
     description: "retrieves trait impls for items in the crate",
 };
 
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 7ac3009d827..6fa226433fc 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -9,6 +9,7 @@ use rustc_span::{InnerSpan, Span, DUMMY_SP};
 use std::mem;
 use std::ops::Range;
 
+use self::Condition::*;
 use crate::clean::{self, GetDefId, Item};
 use crate::core::DocContext;
 use crate::fold::{DocFolder, StripItem};
@@ -53,10 +54,29 @@ pub use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE;
 #[derive(Copy, Clone)]
 pub struct Pass {
     pub name: &'static str,
-    pub pass: fn(clean::Crate, &DocContext<'_>) -> clean::Crate,
+    pub run: fn(clean::Crate, &DocContext<'_>) -> clean::Crate,
     pub description: &'static str,
 }
 
+/// In a list of passes, a pass that may or may not need to be run depending on options.
+#[derive(Copy, Clone)]
+pub struct ConditionalPass {
+    pub pass: Pass,
+    pub condition: Condition,
+}
+
+/// How to decide whether to run a conditional pass.
+#[derive(Copy, Clone)]
+pub enum Condition {
+    Always,
+    /// When `--document-private-items` is passed.
+    WhenDocumentPrivate,
+    /// When `--document-private-items` is not passed.
+    WhenNotDocumentPrivate,
+    /// When `--document-hidden-items` is not passed.
+    WhenNotDocumentHidden,
+}
+
 /// The full list of passes.
 pub const PASSES: &[Pass] = &[
     CHECK_PRIVATE_ITEMS_DOC_TESTS,
@@ -73,63 +93,58 @@ pub const PASSES: &[Pass] = &[
 ];
 
 /// The list of passes run by default.
-pub const DEFAULT_PASSES: &[Pass] = &[
-    COLLECT_TRAIT_IMPLS,
-    COLLAPSE_DOCS,
-    UNINDENT_COMMENTS,
-    CHECK_PRIVATE_ITEMS_DOC_TESTS,
-    STRIP_HIDDEN,
-    STRIP_PRIVATE,
-    COLLECT_INTRA_DOC_LINKS,
-    CHECK_CODE_BLOCK_SYNTAX,
-    PROPAGATE_DOC_CFG,
+pub const DEFAULT_PASSES: &[ConditionalPass] = &[
+    ConditionalPass::always(COLLECT_TRAIT_IMPLS),
+    ConditionalPass::always(COLLAPSE_DOCS),
+    ConditionalPass::always(UNINDENT_COMMENTS),
+    ConditionalPass::always(CHECK_PRIVATE_ITEMS_DOC_TESTS),
+    ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
+    ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
+    ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate),
+    ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
+    ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX),
+    ConditionalPass::always(PROPAGATE_DOC_CFG),
 ];
 
-/// The list of default passes run with `--document-private-items` is passed to rustdoc.
-pub const DEFAULT_PRIVATE_PASSES: &[Pass] = &[
-    COLLECT_TRAIT_IMPLS,
-    COLLAPSE_DOCS,
-    UNINDENT_COMMENTS,
-    CHECK_PRIVATE_ITEMS_DOC_TESTS,
-    STRIP_PRIV_IMPORTS,
-    COLLECT_INTRA_DOC_LINKS,
-    CHECK_CODE_BLOCK_SYNTAX,
-    PROPAGATE_DOC_CFG,
+/// The list of default passes run when `--doc-coverage` is passed to rustdoc.
+pub const COVERAGE_PASSES: &[ConditionalPass] = &[
+    ConditionalPass::always(COLLECT_TRAIT_IMPLS),
+    ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
+    ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
+    ConditionalPass::always(CALCULATE_DOC_COVERAGE),
 ];
 
-/// The list of default passes run when `--doc-coverage` is passed to rustdoc.
-pub const DEFAULT_COVERAGE_PASSES: &[Pass] =
-    &[COLLECT_TRAIT_IMPLS, STRIP_HIDDEN, STRIP_PRIVATE, CALCULATE_DOC_COVERAGE];
+impl ConditionalPass {
+    pub const fn always(pass: Pass) -> Self {
+        Self::new(pass, Always)
+    }
 
-/// The list of default passes run when `--doc-coverage --document-private-items` is passed to
-/// rustdoc.
-pub const PRIVATE_COVERAGE_PASSES: &[Pass] = &[COLLECT_TRAIT_IMPLS, CALCULATE_DOC_COVERAGE];
+    pub const fn new(pass: Pass, condition: Condition) -> Self {
+        ConditionalPass { pass, condition }
+    }
+}
 
 /// A shorthand way to refer to which set of passes to use, based on the presence of
-/// `--no-defaults` or `--document-private-items`.
+/// `--no-defaults` and `--show-coverage`.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum DefaultPassOption {
     Default,
-    Private,
     Coverage,
-    PrivateCoverage,
     None,
 }
 
 /// Returns the given default set of passes.
-pub fn defaults(default_set: DefaultPassOption) -> &'static [Pass] {
+pub fn defaults(default_set: DefaultPassOption) -> &'static [ConditionalPass] {
     match default_set {
         DefaultPassOption::Default => DEFAULT_PASSES,
-        DefaultPassOption::Private => DEFAULT_PRIVATE_PASSES,
-        DefaultPassOption::Coverage => DEFAULT_COVERAGE_PASSES,
-        DefaultPassOption::PrivateCoverage => PRIVATE_COVERAGE_PASSES,
+        DefaultPassOption::Coverage => COVERAGE_PASSES,
         DefaultPassOption::None => &[],
     }
 }
 
 /// If the given name matches a known pass, returns its information.
-pub fn find_pass(pass_name: &str) -> Option<&'static Pass> {
-    PASSES.iter().find(|p| p.name == pass_name)
+pub fn find_pass(pass_name: &str) -> Option<Pass> {
+    PASSES.iter().find(|p| p.name == pass_name).copied()
 }
 
 struct Stripper<'a> {
diff --git a/src/librustdoc/passes/private_items_doc_tests.rs b/src/librustdoc/passes/private_items_doc_tests.rs
index 23e27270970..aec5a6bd4e2 100644
--- a/src/librustdoc/passes/private_items_doc_tests.rs
+++ b/src/librustdoc/passes/private_items_doc_tests.rs
@@ -5,7 +5,7 @@ use crate::passes::{look_for_tests, Pass};
 
 pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
     name: "check-private-items-doc-tests",
-    pass: check_private_items_doc_tests,
+    run: check_private_items_doc_tests,
     description: "check private items doc tests",
 };
 
diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs
index a296e73e3b5..64b0c45ba65 100644
--- a/src/librustdoc/passes/propagate_doc_cfg.rs
+++ b/src/librustdoc/passes/propagate_doc_cfg.rs
@@ -8,7 +8,7 @@ use crate::passes::Pass;
 
 pub const PROPAGATE_DOC_CFG: Pass = Pass {
     name: "propagate-doc-cfg",
-    pass: propagate_doc_cfg,
+    run: propagate_doc_cfg,
     description: "propagates `#[doc(cfg(...))]` to child items",
 };
 
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index 9698ad1d231..47f43958ed5 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -10,7 +10,7 @@ use crate::passes::{ImplStripper, Pass};
 
 pub const STRIP_HIDDEN: Pass = Pass {
     name: "strip-hidden",
-    pass: strip_hidden,
+    run: strip_hidden,
     description: "strips all doc(hidden) items from the output",
 };
 
diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs
index af34842ad0f..35b26fb8ab0 100644
--- a/src/librustdoc/passes/strip_priv_imports.rs
+++ b/src/librustdoc/passes/strip_priv_imports.rs
@@ -5,7 +5,7 @@ use crate::passes::{ImportStripper, Pass};
 
 pub const STRIP_PRIV_IMPORTS: Pass = Pass {
     name: "strip-priv-imports",
-    pass: strip_priv_imports,
+    run: strip_priv_imports,
     description: "strips all private import statements (`use`, `extern crate`) from a crate",
 };
 
diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs
index 5113afa4840..e0379d7ffe2 100644
--- a/src/librustdoc/passes/strip_private.rs
+++ b/src/librustdoc/passes/strip_private.rs
@@ -7,7 +7,7 @@ use crate::passes::{ImplStripper, ImportStripper, Pass, Stripper};
 
 pub const STRIP_PRIVATE: Pass = Pass {
     name: "strip-private",
-    pass: strip_private,
+    run: strip_private,
     description: "strips all private items from a crate which cannot be seen externally, \
         implies strip-priv-imports",
 };
diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs
index 3212af055ef..d4e09ce47a3 100644
--- a/src/librustdoc/passes/unindent_comments.rs
+++ b/src/librustdoc/passes/unindent_comments.rs
@@ -12,7 +12,7 @@ mod tests;
 
 pub const UNINDENT_COMMENTS: Pass = Pass {
     name: "unindent-comments",
-    pass: unindent_comments,
+    run: unindent_comments,
     description: "removes excess indentation on comments in order for markdown to like it",
 };
 
diff --git a/src/test/rustdoc/issue-46380.rs b/src/test/rustdoc/issue-46380.rs
deleted file mode 100644
index 8837a6b463e..00000000000
--- a/src/test/rustdoc/issue-46380.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-// compile-flags: --document-private-items
-
-// @has issue_46380/struct.Hidden.html
-#[doc(hidden)]
-pub struct Hidden;
diff --git a/src/test/rustdoc/issue-67851-both.rs b/src/test/rustdoc/issue-67851-both.rs
new file mode 100644
index 00000000000..d69b9431734
--- /dev/null
+++ b/src/test/rustdoc/issue-67851-both.rs
@@ -0,0 +1,8 @@
+// compile-flags: -Zunstable-options --document-private-items --document-hidden-items
+
+// @has issue_67851_both/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @has issue_67851_both/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/issue-67851-hidden.rs b/src/test/rustdoc/issue-67851-hidden.rs
new file mode 100644
index 00000000000..8a3cafe4c3d
--- /dev/null
+++ b/src/test/rustdoc/issue-67851-hidden.rs
@@ -0,0 +1,8 @@
+// compile-flags: -Zunstable-options --document-hidden-items
+
+// @has issue_67851_hidden/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @!has issue_67851_hidden/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/issue-67851-neither.rs b/src/test/rustdoc/issue-67851-neither.rs
new file mode 100644
index 00000000000..4e3cd832853
--- /dev/null
+++ b/src/test/rustdoc/issue-67851-neither.rs
@@ -0,0 +1,6 @@
+// @!has issue_67851_neither/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @!has issue_67851_neither/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/issue-67851-private.rs b/src/test/rustdoc/issue-67851-private.rs
new file mode 100644
index 00000000000..8addc7f3e4b
--- /dev/null
+++ b/src/test/rustdoc/issue-67851-private.rs
@@ -0,0 +1,8 @@
+// compile-flags: --document-private-items
+
+// @!has issue_67851_private/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @has issue_67851_private/struct.Private.html
+struct Private;