about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/doc/unstable-book/src/language-features/doc-masked.md24
-rw-r--r--src/librustdoc/clean/mod.rs31
-rw-r--r--src/librustdoc/html/render.rs46
-rw-r--r--src/libstd/lib.rs8
-rw-r--r--src/libsyntax/feature_gate.rs6
-rw-r--r--src/test/compile-fail/feature-gate-doc_masked.rs14
6 files changed, 111 insertions, 18 deletions
diff --git a/src/doc/unstable-book/src/language-features/doc-masked.md b/src/doc/unstable-book/src/language-features/doc-masked.md
new file mode 100644
index 00000000000..609939bfc22
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/doc-masked.md
@@ -0,0 +1,24 @@
+# `doc_masked`
+
+The tracking issue for this feature is: [#44027]
+
+-----
+
+The `doc_masked` feature allows a crate to exclude types from a given crate from appearing in lists
+of trait implementations. The specifics of the feature are as follows:
+
+1. When rustdoc encounters an `extern crate` statement annotated with a `#[doc(masked)]` attribute,
+   it marks the crate as being masked.
+
+2. When listing traits a given type implements, rustdoc ensures that traits from masked crates are
+   not emitted into the documentation.
+
+3. When listing types that implement a given trait, rustdoc ensures that types from masked crates
+   are not emitted into the documentation.
+
+This feature was introduced in PR [#44026] to ensure that compiler-internal and
+implementation-specific types and traits were not included in the standard library's documentation.
+Such types would introduce broken links into the documentation.
+
+[#44026]: https://github.com/rust-lang/rust/pull/44026
+[#44027]: https://github.com/rust-lang/rust/pull/44027
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 73ab286f185..095eb7797d4 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -120,6 +120,7 @@ pub struct Crate {
     // These are later on moved into `CACHEKEY`, leaving the map empty.
     // Only here so that they can be filtered through the rustdoc passes.
     pub external_traits: FxHashMap<DefId, Trait>,
+    pub masked_crates: FxHashSet<CrateNum>,
 }
 
 impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
@@ -144,6 +145,18 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
         // Clean the crate, translating the entire libsyntax AST to one that is
         // understood by rustdoc.
         let mut module = self.module.clean(cx);
+        let mut masked_crates = FxHashSet();
+
+        match module.inner {
+            ModuleItem(ref module) => {
+                for it in &module.items {
+                    if it.is_extern_crate() && it.attrs.has_doc_masked() {
+                        masked_crates.insert(it.def_id.krate);
+                    }
+                }
+            }
+            _ => unreachable!(),
+        }
 
         let ExternalCrate { name, src, primitives, .. } = LOCAL_CRATE.clean(cx);
         {
@@ -176,6 +189,7 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
             primitives,
             access_levels: Arc::new(mem::replace(&mut access_levels, Default::default())),
             external_traits: mem::replace(&mut external_traits, Default::default()),
+            masked_crates,
         }
     }
 }
@@ -329,6 +343,9 @@ impl Item {
     pub fn is_import(&self) -> bool {
         self.type_() == ItemType::Import
     }
+    pub fn is_extern_crate(&self) -> bool {
+        self.type_() == ItemType::ExternCrate
+    }
 
     pub fn is_stripped(&self) -> bool {
         match self.inner { StrippedItem(..) => true, _ => false }
@@ -574,6 +591,20 @@ impl Attributes {
         None
     }
 
+    pub fn has_doc_masked(&self) -> bool {
+        for attr in &self.other_attrs {
+            if !attr.check_name("doc") { continue; }
+
+            if let Some(items) = attr.meta_item_list() {
+                if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name("masked")) {
+                    return true;
+                }
+            }
+        }
+
+        false
+    }
+
     pub fn from_ast(diagnostic: &::errors::Handler, attrs: &[ast::Attribute]) -> Attributes {
         let mut doc_strings = vec![];
         let mut sp = None;
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index bf0fe5f6e9d..bac847590e2 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -266,6 +266,7 @@ pub struct Cache {
     deref_trait_did: Option<DefId>,
     deref_mut_trait_did: Option<DefId>,
     owned_box_did: Option<DefId>,
+    masked_crates: FxHashSet<CrateNum>,
 
     // In rare case where a structure is defined in one module but implemented
     // in another, if the implementing module is parsed before defining module,
@@ -538,6 +539,7 @@ pub fn run(mut krate: clean::Crate,
         deref_trait_did,
         deref_mut_trait_did,
         owned_box_did,
+        masked_crates: mem::replace(&mut krate.masked_crates, FxHashSet()),
         typarams: external_typarams,
     };
 
@@ -1114,12 +1116,16 @@ impl DocFolder for Cache {
 
         // Collect all the implementors of traits.
         if let clean::ImplItem(ref i) = item.inner {
-            if let Some(did) = i.trait_.def_id() {
-                self.implementors.entry(did).or_insert(vec![]).push(Implementor {
-                    def_id: item.def_id,
-                    stability: item.stability.clone(),
-                    impl_: i.clone(),
-                });
+            if !self.masked_crates.contains(&item.def_id.krate) {
+                if let Some(did) = i.trait_.def_id() {
+                    if i.for_.def_id().map_or(true, |d| !self.masked_crates.contains(&d.krate)) {
+                        self.implementors.entry(did).or_insert(vec![]).push(Implementor {
+                            def_id: item.def_id,
+                            stability: item.stability.clone(),
+                            impl_: i.clone(),
+                        });
+                    }
+                }
             }
         }
 
@@ -1281,18 +1287,24 @@ impl DocFolder for Cache {
                 // primitive rather than always to a struct/enum.
                 // Note: matching twice to restrict the lifetime of the `i` borrow.
                 let did = if let clean::Item { inner: clean::ImplItem(ref i), .. } = item {
-                    match i.for_ {
-                        clean::ResolvedPath { did, .. } |
-                        clean::BorrowedRef {
-                            type_: box clean::ResolvedPath { did, .. }, ..
-                        } => {
-                            Some(did)
-                        }
-                        ref t => {
-                            t.primitive_type().and_then(|t| {
-                                self.primitive_locations.get(&t).cloned()
-                            })
+                    let masked_trait = i.trait_.def_id().map_or(false,
+                        |d| self.masked_crates.contains(&d.krate));
+                    if !masked_trait {
+                        match i.for_ {
+                            clean::ResolvedPath { did, .. } |
+                            clean::BorrowedRef {
+                                type_: box clean::ResolvedPath { did, .. }, ..
+                            } => {
+                                Some(did)
+                            }
+                            ref t => {
+                                t.primitive_type().and_then(|t| {
+                                    self.primitive_locations.get(&t).cloned()
+                                })
+                            }
                         }
+                    } else {
+                        None
                     }
                 } else {
                     unreachable!()
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index a3eecd46e90..9fc7e2c01aa 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -314,6 +314,7 @@
 #![feature(unwind_attributes)]
 #![feature(vec_push_all)]
 #![feature(doc_cfg)]
+#![feature(doc_masked)]
 #![cfg_attr(test, feature(update_panic_count))]
 
 #![cfg_attr(not(stage0), feature(const_max_value))]
@@ -359,19 +360,24 @@ use prelude::v1::*;
                  debug_assert_ne, unreachable, unimplemented, write, writeln, try)]
 extern crate core as __core;
 
-#[allow(deprecated)] extern crate rand as core_rand;
+#[doc(masked)]
+#[allow(deprecated)]
+extern crate rand as core_rand;
 #[macro_use]
 #[macro_reexport(vec, format)]
 extern crate alloc;
 extern crate alloc_system;
 extern crate std_unicode;
+#[doc(masked)]
 extern crate libc;
 
 // We always need an unwinder currently for backtraces
+#[doc(masked)]
 #[allow(unused_extern_crates)]
 extern crate unwind;
 
 // compiler-rt intrinsics
+#[doc(masked)]
 extern crate compiler_builtins;
 
 // During testing, this crate is not actually the "real" std library, but rather
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 38e20b9fe40..ae0dd872963 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -377,6 +377,8 @@ declare_features! (
 
     // #[doc(cfg(...))]
     (active, doc_cfg, "1.21.0", Some(43781)),
+    // #[doc(masked)]
+    (active, doc_masked, "1.21.0", None),
 
     // allow `#[must_use]` on functions (RFC 1940)
     (active, fn_must_use, "1.21.0", Some(43302)),
@@ -1237,6 +1239,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                     gate_feature_post!(&self, doc_cfg, attr.span,
                         "#[doc(cfg(...))] is experimental"
                     );
+                } else if content.iter().any(|c| c.check_name("masked")) {
+                    gate_feature_post!(&self, doc_masked, attr.span,
+                        "#[doc(masked)] is experimental"
+                    );
                 }
             }
         }
diff --git a/src/test/compile-fail/feature-gate-doc_masked.rs b/src/test/compile-fail/feature-gate-doc_masked.rs
new file mode 100644
index 00000000000..bb5be9d6971
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-doc_masked.rs
@@ -0,0 +1,14 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[doc(masked)] //~ ERROR: #[doc(masked)] is experimental
+extern crate std as realstd;
+
+fn main() {}