about summary refs log tree commit diff
diff options
context:
space:
mode:
authorQuietMisdreavus <grey@quietmisdreavus.net>2018-08-28 11:33:45 -0500
committerQuietMisdreavus <grey@quietmisdreavus.net>2018-09-20 05:42:36 -0500
commite854d39929ffe1e9692be23ac8e7edbcf31b0f24 (patch)
treee4e836b1b7048870fa03fb66fa592eb4d56d6d16
parent7e70fee0c76422e986514306b3673f79f7e37ec7 (diff)
downloadrust-e854d39929ffe1e9692be23ac8e7edbcf31b0f24.tar.gz
rust-e854d39929ffe1e9692be23ac8e7edbcf31b0f24.zip
don't index trait impls if the trait isn't also documented
-rw-r--r--src/librustdoc/html/render.rs34
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/test/rustdoc/traits-in-bodies-private.rs23
3 files changed, 53 insertions, 5 deletions
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 22fcbf1728d..ac3dffa3511 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -337,6 +337,15 @@ pub struct Cache {
     // and their parent id here and indexes them at the end of crate parsing.
     orphan_impl_items: Vec<(DefId, clean::Item)>,
 
+    // Similarly to `orphan_impl_items`, sometimes trait impls are picked up
+    // even though the trait itself is not exported. This can happen if a trait
+    // was defined in function/expression scope, since the impl will be picked
+    // up by `collect-trait-impls` but the trait won't be scraped out in the HIR
+    // crawl. In order to prevent crashes when looking for spotlight traits or
+    // when gathering trait documentation on a type, hold impls here while
+    // folding and add them to the cache later on if we find the trait.
+    orphan_trait_impls: Vec<(DefId, FxHashSet<DefId>, Impl)>,
+
     /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
     /// we need the alias element to have an array of items.
     aliases: FxHashMap<String, Vec<IndexItem>>,
@@ -594,6 +603,7 @@ pub fn run(mut krate: clean::Crate,
         access_levels: krate.access_levels.clone(),
         crate_version: krate.version.take(),
         orphan_impl_items: Vec::new(),
+        orphan_trait_impls: Vec::new(),
         traits: mem::replace(&mut krate.external_traits, FxHashMap()),
         deref_trait_did,
         deref_mut_trait_did,
@@ -636,6 +646,14 @@ pub fn run(mut krate: clean::Crate,
     cache.stack.push(krate.name.clone());
     krate = cache.fold_crate(krate);
 
+    for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) {
+        if cache.traits.contains_key(&trait_did) {
+            for did in dids {
+                cache.impls.entry(did).or_insert(vec![]).push(impl_.clone());
+            }
+        }
+    }
+
     // Build our search index
     let index = build_index(&krate, &mut cache);
 
@@ -1224,7 +1242,7 @@ impl<'a> SourceCollector<'a> {
 impl DocFolder for Cache {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         if item.def_id.is_local() {
-            debug!("folding item \"{:?}\", a {}", item.name, item.type_());
+            debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.def_id);
         }
 
         // If this is a stripped module,
@@ -1457,10 +1475,16 @@ impl DocFolder for Cache {
                 } else {
                     unreachable!()
                 };
-                for did in dids {
-                    self.impls.entry(did).or_default().push(Impl {
-                        impl_item: item.clone(),
-                    });
+                let impl_item = Impl {
+                    impl_item: item,
+                };
+                if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) {
+                    for did in dids {
+                        self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
+                    }
+                } else {
+                    let trait_did = impl_item.trait_did().unwrap();
+                    self.orphan_trait_impls.push((trait_did, dids, impl_item));
                 }
                 None
             } else {
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 5f373a635dd..e7bf7fdf3f6 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -24,6 +24,7 @@
 #![feature(ptr_offset_from)]
 #![feature(crate_visibility_modifier)]
 #![feature(const_fn)]
+#![feature(drain_filter)]
 
 #![recursion_limit="256"]
 
diff --git a/src/test/rustdoc/traits-in-bodies-private.rs b/src/test/rustdoc/traits-in-bodies-private.rs
new file mode 100644
index 00000000000..ac3be7e61e9
--- /dev/null
+++ b/src/test/rustdoc/traits-in-bodies-private.rs
@@ -0,0 +1,23 @@
+// Copyright 2018 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.
+
+// when implementing the fix for traits-in-bodies, there was an ICE when documenting private items
+// and a trait was defined in non-module scope
+
+// compile-flags:--document-private-items
+
+// @has traits_in_bodies_private/struct.SomeStruct.html
+// @!has - '//code' 'impl HiddenTrait for SomeStruct'
+pub struct SomeStruct;
+
+fn __implementation_details() {
+    trait HiddenTrait {}
+    impl HiddenTrait for SomeStruct {}
+}