From 1adfdefca2e18b5d7c65f0d19a75b15534e45e6b Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 7 Aug 2018 10:10:05 -0500 Subject: [PATCH 01/18] rustdoc: collect trait impls as an early pass --- src/librustdoc/clean/inline.rs | 86 +++-------------- src/librustdoc/core.rs | 4 +- src/librustdoc/passes/collect_trait_impls.rs | 99 ++++++++++++++++++++ src/librustdoc/passes/mod.rs | 6 ++ src/librustdoc/visit_ast.rs | 6 +- src/test/rustdoc/traits-in-bodies.rs | 18 +++- 6 files changed, 137 insertions(+), 82 deletions(-) create mode 100644 src/librustdoc/passes/collect_trait_impls.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 75d7488d26a75..f9c631fcfcdb6 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -290,78 +290,12 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec = auto_impls.into_iter() - .chain(blanket_impls.into_iter()) - .filter(|i| renderinfo.inlined.insert(i.def_id)) - .collect(); - - impls.extend(new_impls); - } - } - impls } pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { if !cx.renderinfo.borrow_mut().inlined.insert(did) { + debug!("already inlined, bailing: {:?}", did); return } @@ -371,9 +305,12 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { // Only inline impl if the implemented trait is // reachable in rustdoc generated documentation - if let Some(traitref) = associated_trait { - if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) { - return + if !did.is_local() { + if let Some(traitref) = associated_trait { + if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) { + debug!("trait {:?} not reachable, bailing: {:?}", traitref.def_id, did); + return + } } } @@ -381,9 +318,12 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { // Only inline impl if the implementing type is // reachable in rustdoc generated documentation - if let Some(did) = for_.def_id() { - if !cx.access_levels.borrow().is_doc_reachable(did) { - return + if !did.is_local() { + if let Some(did) = for_.def_id() { + if !cx.access_levels.borrow().is_doc_reachable(did) { + debug!("impl type {:?} not accessible, bailing", did); + return + } } } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index a312913a69c17..623ff4c46e9fa 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -37,7 +37,7 @@ use syntax_pos::DUMMY_SP; use errors; use errors::emitter::{Emitter, EmitterWriter}; -use std::cell::{RefCell, Cell}; +use std::cell::RefCell; use std::mem; use rustc_data_structures::sync::{self, Lrc}; use std::rc::Rc; @@ -60,7 +60,6 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> { /// The stack of module NodeIds up till this point pub crate_name: Option, pub cstore: Rc, - pub populated_all_crate_impls: Cell, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing // the access levels from crateanalysis. @@ -511,7 +510,6 @@ pub fn run_core(search_paths: SearchPaths, resolver: &resolver, crate_name, cstore: cstore.clone(), - populated_all_crate_impls: Cell::new(false), access_levels: RefCell::new(access_levels), external_traits: Default::default(), active_extern_traits: Default::default(), diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs new file mode 100644 index 0000000000000..0be5ab07dea76 --- /dev/null +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -0,0 +1,99 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use clean::*; + +use super::Pass; +use core::DocContext; + +pub const COLLECT_TRAIT_IMPLS: Pass = + Pass::early("collect-trait-impls", collect_trait_impls, + "retrieves trait impls for items in the crate"); + +pub fn collect_trait_impls(mut krate: Crate, cx: &DocContext) -> Crate { + if let Some(ref mut it) = krate.module { + if let ModuleItem(Module { ref mut items, .. }) = it.inner { + for &cnum in cx.tcx.crates().iter() { + for &did in cx.tcx.all_trait_implementations(cnum).iter() { + inline::build_impl(cx, did, items); + } + } + + // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations` + // doesn't work with it anyway, so pull them from the HIR map instead + for &trait_did in cx.all_traits.iter() { + for &impl_node in cx.tcx.hir.trait_impls(trait_did) { + let impl_did = cx.tcx.hir.local_def_id(impl_node); + inline::build_impl(cx, impl_did, items); + } + } + + // Also try to inline primitive impls from other crates. + let lang_items = cx.tcx.lang_items(); + let primitive_impls = [ + lang_items.isize_impl(), + lang_items.i8_impl(), + lang_items.i16_impl(), + lang_items.i32_impl(), + lang_items.i64_impl(), + lang_items.i128_impl(), + lang_items.usize_impl(), + lang_items.u8_impl(), + lang_items.u16_impl(), + lang_items.u32_impl(), + lang_items.u64_impl(), + lang_items.u128_impl(), + lang_items.f32_impl(), + lang_items.f64_impl(), + lang_items.f32_runtime_impl(), + lang_items.f64_runtime_impl(), + lang_items.char_impl(), + lang_items.str_impl(), + lang_items.slice_impl(), + lang_items.slice_u8_impl(), + lang_items.str_alloc_impl(), + lang_items.slice_alloc_impl(), + lang_items.slice_u8_alloc_impl(), + lang_items.const_ptr_impl(), + lang_items.mut_ptr_impl(), + ]; + + for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) { + if !def_id.is_local() { + inline::build_impl(cx, def_id, items); + + let auto_impls = get_auto_traits_with_def_id(cx, def_id); + let blanket_impls = get_blanket_impls_with_def_id(cx, def_id); + let mut renderinfo = cx.renderinfo.borrow_mut(); + + let new_impls: Vec = auto_impls.into_iter() + .chain(blanket_impls.into_iter()) + .filter(|i| renderinfo.inlined.insert(i.def_id)) + .collect(); + + items.extend(new_impls); + } + } + } else { + panic!("collect-trait-impls can't run"); + } + } else { + panic!("collect-trait-impls can't run"); + } + + // pulling in the impls puts their trait info into the DocContext, but that's already been + // drained by now, so stuff that info into the Crate so the rendering can pick it up + let mut external_traits = cx.external_traits.borrow_mut(); + for (did, trait_) in external_traits.drain() { + krate.external_traits.entry(did).or_insert(trait_); + } + + krate +} diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 16251877bb106..09281aa7cfaf4 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -43,6 +43,9 @@ pub use self::propagate_doc_cfg::PROPAGATE_DOC_CFG; mod collect_intra_doc_links; pub use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS; +mod collect_trait_impls; +pub use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; + /// Represents a single pass. #[derive(Copy, Clone)] pub enum Pass { @@ -132,10 +135,12 @@ pub const PASSES: &'static [Pass] = &[ STRIP_PRIV_IMPORTS, PROPAGATE_DOC_CFG, COLLECT_INTRA_DOC_LINKS, + COLLECT_TRAIT_IMPLS, ]; /// The list of passes run by default. pub const DEFAULT_PASSES: &'static [&'static str] = &[ + "collect-trait-impls", "strip-hidden", "strip-private", "collect-intra-doc-links", @@ -146,6 +151,7 @@ pub const DEFAULT_PASSES: &'static [&'static str] = &[ /// The list of default passes run with `--document-private-items` is passed to rustdoc. pub const DEFAULT_PRIVATE_PASSES: &'static [&'static str] = &[ + "collect-trait-impls", "strip-priv-imports", "collect-intra-doc-links", "collapse-docs", diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 451e24d6c0dc9..ce438cd99a4b6 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -510,9 +510,9 @@ impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> { ref tr, ref ty, ref item_ids) => { - // Don't duplicate impls when inlining, we'll pick them up - // regardless of where they're located. - if !self.inlining { + // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick + // them up regardless of where they're located. + if !self.inlining && tr.is_none() { let items = item_ids.iter() .map(|ii| self.cx.tcx.hir.impl_item(ii.id).clone()) .collect(); diff --git a/src/test/rustdoc/traits-in-bodies.rs b/src/test/rustdoc/traits-in-bodies.rs index 3acf4af5fd247..26ed544412275 100644 --- a/src/test/rustdoc/traits-in-bodies.rs +++ b/src/test/rustdoc/traits-in-bodies.rs @@ -11,11 +11,10 @@ //prior to fixing `everybody_loops` to preserve items, rustdoc would crash on this file, as it //didn't see that `SomeStruct` implemented `Clone` -//FIXME(misdreavus): whenever rustdoc shows traits impl'd inside bodies, make sure this test -//reflects that - pub struct Bounded(T); +// @has traits_in_bodies/struct.SomeStruct.html +// @has - '//code' 'impl Clone for SomeStruct' pub struct SomeStruct; fn asdf() -> Bounded { @@ -27,3 +26,16 @@ fn asdf() -> Bounded { Bounded(SomeStruct) } + +// @has traits_in_bodies/struct.Point.html +// @has - '//code' 'impl Copy for Point' +#[derive(Clone)] +pub struct Point { + x: i32, + y: i32, +} + +const _FOO: () = { + impl Copy for Point {} + () +}; From f1566f7b0ff6943c329d06e9582d6344d8e21da5 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 7 Aug 2018 11:30:57 -0500 Subject: [PATCH 02/18] print local inlined consts via the HIR map --- src/librustdoc/clean/inline.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f9c631fcfcdb6..2c3714ee0c2ab 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -404,7 +404,11 @@ fn build_module(cx: &DocContext, did: DefId, visited: &mut FxHashSet) -> } pub fn print_inlined_const(cx: &DocContext, did: DefId) -> String { - cx.tcx.rendered_const(did) + if let Some(node_id) = cx.tcx.hir.as_local_node_id(did) { + cx.tcx.hir.node_to_pretty_string(node_id) + } else { + cx.tcx.rendered_const(did) + } } fn build_const(cx: &DocContext, did: DefId) -> clean::Constant { From c66547855806be71eba875af27aac1218b0ad90d Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 7 Aug 2018 15:17:27 -0500 Subject: [PATCH 03/18] ignore rustdoc/doc-proc-macro on stage1 --- src/test/rustdoc/doc-proc-macro.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/rustdoc/doc-proc-macro.rs b/src/test/rustdoc/doc-proc-macro.rs index b3b403a7b86aa..01a4a410b03fb 100644 --- a/src/test/rustdoc/doc-proc-macro.rs +++ b/src/test/rustdoc/doc-proc-macro.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-stage1 + // Issue #52129: ICE when trying to document the `quote` proc-macro from proc_macro // As of this writing, we don't currently attempt to document proc-macros. However, we shouldn't From ce5e4e57c754ddd9d11af0b8a245ef0b34cbaf1a Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Fri, 10 Aug 2018 17:24:40 -0500 Subject: [PATCH 04/18] only move access_levels/external_traits after early passes --- src/librustdoc/clean/mod.rs | 7 ++----- src/librustdoc/core.rs | 4 ++++ src/librustdoc/passes/collect_trait_impls.rs | 7 ------- src/librustdoc/passes/strip_private.rs | 4 ++-- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index da18e3e6b91b3..68d812762a96c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -209,9 +209,6 @@ impl<'a, 'tcx, 'rcx, 'cstore> Clean for visit_ast::RustdocVisitor<'a, 'tc })); } - let mut access_levels = cx.access_levels.borrow_mut(); - let mut external_traits = cx.external_traits.borrow_mut(); - Crate { name, version: None, @@ -219,8 +216,8 @@ impl<'a, 'tcx, 'rcx, 'cstore> Clean for visit_ast::RustdocVisitor<'a, 'tc module: Some(module), externs, primitives, - access_levels: Arc::new(mem::replace(&mut access_levels, Default::default())), - external_traits: mem::replace(&mut external_traits, Default::default()), + access_levels: Arc::new(Default::default()), + external_traits: Default::default(), masked_crates, } } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 623ff4c46e9fa..3a942aa6c8db1 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -41,6 +41,7 @@ use std::cell::RefCell; use std::mem; use rustc_data_structures::sync::{self, Lrc}; use std::rc::Rc; +use std::sync::Arc; use std::path::PathBuf; use visit_ast::RustdocVisitor; @@ -596,6 +597,9 @@ pub fn run_core(search_paths: SearchPaths, ctxt.sess().abort_if_errors(); + krate.access_levels = Arc::new(ctxt.access_levels.into_inner()); + krate.external_traits = ctxt.external_traits.into_inner(); + (krate, ctxt.renderinfo.into_inner(), passes) }), &sess) }) diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 0be5ab07dea76..0ee1657f21516 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -88,12 +88,5 @@ pub fn collect_trait_impls(mut krate: Crate, cx: &DocContext) -> Crate { panic!("collect-trait-impls can't run"); } - // pulling in the impls puts their trait info into the DocContext, but that's already been - // drained by now, so stuff that info into the Crate so the rendering can pick it up - let mut external_traits = cx.external_traits.borrow_mut(); - for (did, trait_) in external_traits.drain() { - krate.external_traits.entry(did).or_insert(trait_); - } - krate } diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 3b17a768ffdee..4fa5943faca07 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -22,10 +22,10 @@ pub const STRIP_PRIVATE: Pass = /// Strip private items from the point of view of a crate or externally from a /// crate, specified by the `xcrate` flag. -pub fn strip_private(mut krate: clean::Crate, _: &DocContext) -> clean::Crate { +pub fn strip_private(mut krate: clean::Crate, cx: &DocContext) -> clean::Crate { // This stripper collects all *retained* nodes. let mut retained = DefIdSet(); - let access_levels = krate.access_levels.clone(); + let access_levels = cx.access_levels.borrow().clone(); // strip all private items { From 033fd7a5e9bbdee292502a55083cfd7ac8b07c38 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 14 Aug 2018 12:08:12 -0500 Subject: [PATCH 05/18] don't record an external trait if it's not external --- src/librustdoc/clean/inline.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 2c3714ee0c2ab..20c5a9febed9e 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -519,6 +519,10 @@ fn separate_supertrait_bounds(mut g: clean::Generics) } pub fn record_extern_trait(cx: &DocContext, did: DefId) { + if did.is_local() { + return; + } + if cx.external_traits.borrow().contains_key(&did) || cx.active_extern_traits.borrow().contains(&did) { From dc3899ecf33f19db9a60e585c54daecac6a078ca Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 14 Aug 2018 14:41:07 -0500 Subject: [PATCH 06/18] undo some tweaks to build_impl --- src/librustdoc/clean/inline.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 20c5a9febed9e..1f5174f84359a 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -295,7 +295,6 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec) { if !cx.renderinfo.borrow_mut().inlined.insert(did) { - debug!("already inlined, bailing: {:?}", did); return } @@ -305,12 +304,9 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { // Only inline impl if the implemented trait is // reachable in rustdoc generated documentation - if !did.is_local() { - if let Some(traitref) = associated_trait { - if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) { - debug!("trait {:?} not reachable, bailing: {:?}", traitref.def_id, did); - return - } + if let Some(traitref) = associated_trait { + if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) { + return } } @@ -318,12 +314,9 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { // Only inline impl if the implementing type is // reachable in rustdoc generated documentation - if !did.is_local() { - if let Some(did) = for_.def_id() { - if !cx.access_levels.borrow().is_doc_reachable(did) { - debug!("impl type {:?} not accessible, bailing", did); - return - } + if let Some(did) = for_.def_id() { + if !cx.access_levels.borrow().is_doc_reachable(did) { + return } } @@ -356,6 +349,8 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { .collect() }).unwrap_or(FxHashSet()); + debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id()); + ret.push(clean::Item { inner: clean::ImplItem(clean::Impl { unsafety: hir::Unsafety::Normal, From 825126a599d5a42aa1fe6d73a66883a202492593 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 14 Aug 2018 14:43:03 -0500 Subject: [PATCH 07/18] add a bunch of debug prints --- src/librustdoc/clean/inline.rs | 1 + src/librustdoc/html/render.rs | 4 ++++ src/librustdoc/passes/mod.rs | 7 +++++++ 3 files changed, 12 insertions(+) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 1f5174f84359a..4d47ec8c84aed 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -526,6 +526,7 @@ pub fn record_extern_trait(cx: &DocContext, did: DefId) { cx.active_extern_traits.borrow_mut().push(did); + debug!("record_extern_trait: {:?}", did); let trait_ = build_external_trait(cx, did); cx.external_traits.borrow_mut().insert(did, trait_); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 368c056f021c1..9d6ea70ed6563 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1223,6 +1223,10 @@ impl<'a> SourceCollector<'a> { impl DocFolder for Cache { fn fold_item(&mut self, item: clean::Item) -> Option { + if item.def_id.is_local() { + debug!("folding item \"{:?}\", a {}", item.name, item.type_()); + } + // If this is a stripped module, // we don't want it or its children in the search index. let orig_stripped_mod = match item.inner { diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 09281aa7cfaf4..95c613cc14d11 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -195,6 +195,7 @@ impl<'a> fold::DocFolder for Stripper<'a> { // We need to recurse into stripped modules to strip things // like impl methods but when doing so we must not add any // items to the `retained` set. + debug!("Stripper: recursing into stripped {} {:?}", i.type_(), i.name); let old = mem::replace(&mut self.update_retained, false); let ret = self.fold_item_recur(i); self.update_retained = old; @@ -218,6 +219,7 @@ impl<'a> fold::DocFolder for Stripper<'a> { | clean::ForeignTypeItem => { if i.def_id.is_local() { if !self.access_levels.is_exported(i.def_id) { + debug!("Stripper: stripping {} {:?}", i.type_(), i.name); return None; } } @@ -231,6 +233,7 @@ impl<'a> fold::DocFolder for Stripper<'a> { clean::ModuleItem(..) => { if i.def_id.is_local() && i.visibility != Some(clean::Public) { + debug!("Stripper: stripping module {:?}", i.name); let old = mem::replace(&mut self.update_retained, false); let ret = StripItem(self.fold_item_recur(i).unwrap()).strip(); self.update_retained = old; @@ -302,11 +305,13 @@ impl<'a> fold::DocFolder for ImplStripper<'a> { } if let Some(did) = imp.for_.def_id() { if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did) { + debug!("ImplStripper: impl item for stripped type; removing"); return None; } } if let Some(did) = imp.trait_.def_id() { if did.is_local() && !self.retained.contains(&did) { + debug!("ImplStripper: impl item for stripped trait; removing"); return None; } } @@ -314,6 +319,8 @@ impl<'a> fold::DocFolder for ImplStripper<'a> { for typaram in generics { if let Some(did) = typaram.def_id() { if did.is_local() && !self.retained.contains(&did) { + debug!("ImplStripper: stripped item in trait's generics; \ + removing impl"); return None; } } From 5254548e597ecc8d34e379dbe59206fa61d66e47 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 14 Aug 2018 14:44:45 -0500 Subject: [PATCH 08/18] handle local names when registering FQNs --- src/librustdoc/clean/inline.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4d47ec8c84aed..17f1a8120abf1 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -158,12 +158,11 @@ pub fn load_attrs(cx: &DocContext, did: DefId) -> clean::Attributes { /// These names are used later on by HTML rendering to generate things like /// source links back to the original item. pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { + let mut crate_name = cx.tcx.crate_name(did.krate).to_string(); if did.is_local() { - debug!("record_extern_fqn(did={:?}, kind+{:?}): def_id is local, aborting", did, kind); - return; + crate_name = cx.crate_name.clone().unwrap_or(crate_name); } - let crate_name = cx.tcx.crate_name(did.krate).to_string(); let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| { // extern blocks have an empty name let s = elem.data.to_string(); @@ -178,7 +177,12 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { } else { once(crate_name).chain(relative).collect() }; - cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind)); + + if did.is_local() { + cx.renderinfo.borrow_mut().exact_paths.insert(did, fqn); + } else { + cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind)); + } } pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { From ca612863cd2cf6d11b6daf39188c97375767dfba Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 14 Aug 2018 15:19:15 -0500 Subject: [PATCH 09/18] pull local types from the HIR instead of tcx --- src/librustdoc/clean/inline.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 17f1a8120abf1..b773a59b16b1e 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -314,7 +314,16 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { } } - let for_ = tcx.type_of(did).clean(cx); + let for_ = if let Some(nodeid) = tcx.hir.as_local_node_id(did) { + match tcx.hir.expect_item(nodeid).node { + hir::ItemKind::Impl(.., ref t, _) => { + t.clean(cx) + } + _ => panic!("did given to build_impl was not an impl"), + } + } else { + tcx.type_of(did).clean(cx) + }; // Only inline impl if the implementing type is // reachable in rustdoc generated documentation From eaacf59681c85ddf6c60a14df9752db77ce907c0 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 14 Aug 2018 16:42:34 -0500 Subject: [PATCH 10/18] collect impl items from the HIR if available --- src/librustdoc/clean/inline.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index b773a59b16b1e..89516a1a7dc0f 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -334,13 +334,24 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { } let predicates = tcx.predicates_of(did); - let trait_items = tcx.associated_items(did).filter_map(|item| { - if associated_trait.is_some() || item.vis == ty::Visibility::Public { - Some(item.clean(cx)) - } else { - None + let trait_items = if let Some(nodeid) = tcx.hir.as_local_node_id(did) { + match tcx.hir.expect_item(nodeid).node { + hir::ItemKind::Impl(.., ref item_ids) => { + item_ids.iter() + .map(|ii| tcx.hir.impl_item(ii.id).clean(cx)) + .collect::>() + } + _ => panic!("did given to build_impl was not an impl"), } - }).collect::>(); + } else { + tcx.associated_items(did).filter_map(|item| { + if associated_trait.is_some() || item.vis == ty::Visibility::Public { + Some(item.clean(cx)) + } else { + None + } + }).collect::>() + }; let polarity = tcx.impl_polarity(did); let trait_ = associated_trait.clean(cx).map(|bound| { match bound { From 17d48343f5fb91f630c71a3bdf451e70cd0289ce Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 14 Aug 2018 17:38:41 -0500 Subject: [PATCH 11/18] pull impl generics from HIR if available --- src/librustdoc/clean/inline.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 89516a1a7dc0f..7e8d32f991ce7 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -334,23 +334,29 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { } let predicates = tcx.predicates_of(did); - let trait_items = if let Some(nodeid) = tcx.hir.as_local_node_id(did) { + let (trait_items, generics) = if let Some(nodeid) = tcx.hir.as_local_node_id(did) { match tcx.hir.expect_item(nodeid).node { - hir::ItemKind::Impl(.., ref item_ids) => { - item_ids.iter() - .map(|ii| tcx.hir.impl_item(ii.id).clean(cx)) - .collect::>() + hir::ItemKind::Impl(.., ref gen, _, _, ref item_ids) => { + ( + item_ids.iter() + .map(|ii| tcx.hir.impl_item(ii.id).clean(cx)) + .collect::>(), + gen.clean(cx), + ) } _ => panic!("did given to build_impl was not an impl"), } } else { - tcx.associated_items(did).filter_map(|item| { - if associated_trait.is_some() || item.vis == ty::Visibility::Public { - Some(item.clean(cx)) - } else { - None - } - }).collect::>() + ( + tcx.associated_items(did).filter_map(|item| { + if associated_trait.is_some() || item.vis == ty::Visibility::Public { + Some(item.clean(cx)) + } else { + None + } + }).collect::>(), + (tcx.generics_of(did), &predicates).clean(cx), + ) }; let polarity = tcx.impl_polarity(did); let trait_ = associated_trait.clean(cx).map(|bound| { @@ -378,7 +384,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { ret.push(clean::Item { inner: clean::ImplItem(clean::Impl { unsafety: hir::Unsafety::Normal, - generics: (tcx.generics_of(did), &predicates).clean(cx), + generics, provided_trait_methods: provided, trait_, for_, From 15dba89730c1826c2a6e602ffd24e45939584085 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 15 Aug 2018 10:41:15 -0500 Subject: [PATCH 12/18] swap external_traits into the crate before running strip_hidden --- src/librustdoc/passes/strip_hidden.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index cc0b6fb6d6705..eab4022a3389f 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -24,9 +24,13 @@ pub const STRIP_HIDDEN: Pass = "strips all doc(hidden) items from the output"); /// Strip items marked `#[doc(hidden)]` -pub fn strip_hidden(krate: clean::Crate, _: &DocContext) -> clean::Crate { +pub fn strip_hidden(mut krate: clean::Crate, cx: &DocContext) -> clean::Crate { let mut retained = DefIdSet(); + // as an early pass, the external traits haven't been swapped in, so we need to do that ahead + // of time + mem::swap(&mut krate.external_traits, &mut cx.external_traits.borrow_mut()); + // strip all #[doc(hidden)] items let krate = { let mut stripper = Stripper{ retained: &mut retained, update_retained: true }; @@ -35,7 +39,10 @@ pub fn strip_hidden(krate: clean::Crate, _: &DocContext) -> clean::Crate { // strip all impls referencing stripped items let mut stripper = ImplStripper { retained: &retained }; - stripper.fold_crate(krate) + let mut krate = stripper.fold_crate(krate); + mem::swap(&mut krate.external_traits, &mut cx.external_traits.borrow_mut()); + + krate } struct Stripper<'a> { @@ -46,7 +53,7 @@ struct Stripper<'a> { impl<'a> fold::DocFolder for Stripper<'a> { fn fold_item(&mut self, i: Item) -> Option { if i.attrs.lists("doc").has_word("hidden") { - debug!("found one in strip_hidden; removing"); + debug!("strip_hidden: stripping {} {:?}", i.type_(), i.name); // use a dedicated hidden item for given item type if any match i.inner { clean::StructFieldItem(..) | clean::ModuleItem(..) => { From c39de06fe10461a369eabeff51784a7d3b82ccb2 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 21 Aug 2018 16:22:20 -0500 Subject: [PATCH 13/18] don't check visibility when inlining local impls those get handled properly in strip-hidden anyway --- src/librustdoc/clean/inline.rs | 16 ++++++++----- src/test/rustdoc/inline_local/trait-vis.rs | 28 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 src/test/rustdoc/inline_local/trait-vis.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 7e8d32f991ce7..d248bb58fc599 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -308,9 +308,11 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { // Only inline impl if the implemented trait is // reachable in rustdoc generated documentation - if let Some(traitref) = associated_trait { - if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) { - return + if !did.is_local() { + if let Some(traitref) = associated_trait { + if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) { + return + } } } @@ -327,9 +329,11 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { // Only inline impl if the implementing type is // reachable in rustdoc generated documentation - if let Some(did) = for_.def_id() { - if !cx.access_levels.borrow().is_doc_reachable(did) { - return + if !did.is_local() { + if let Some(did) = for_.def_id() { + if !cx.access_levels.borrow().is_doc_reachable(did) { + return + } } } diff --git a/src/test/rustdoc/inline_local/trait-vis.rs b/src/test/rustdoc/inline_local/trait-vis.rs new file mode 100644 index 0000000000000..1035e357ef649 --- /dev/null +++ b/src/test/rustdoc/inline_local/trait-vis.rs @@ -0,0 +1,28 @@ +// Copyright 2012-2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait ThisTrait {} + +mod asdf { + use ThisTrait; + + pub struct SomeStruct; + + impl ThisTrait for SomeStruct {} + + trait PrivateTrait {} + + impl PrivateTrait for SomeStruct {} +} + +// @has trait_vis/struct.SomeStruct.html +// @has - '//code' 'impl ThisTrait for SomeStruct' +// !@has - '//code' 'impl PrivateTrait for SomeStruct' +pub use asdf::SomeStruct; From 810332f3673f362f97e3a911f3fec9e49eb8383a Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Mon, 27 Aug 2018 12:42:43 -0500 Subject: [PATCH 14/18] add more tests for traits-in-non-module-scope --- src/librustdoc/passes/mod.rs | 2 +- .../inline_cross/auxiliary/trait-vis.rs | 23 +++++++++++++++++++ src/test/rustdoc/inline_cross/trait-vis.rs | 17 ++++++++++++++ src/test/rustdoc/inline_local/trait-vis.rs | 2 +- src/test/rustdoc/primitive-generic-impl.rs | 3 --- src/test/rustdoc/traits-in-bodies.rs | 21 +++++++++++++++++ 6 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 src/test/rustdoc/inline_cross/auxiliary/trait-vis.rs create mode 100644 src/test/rustdoc/inline_cross/trait-vis.rs diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 95c613cc14d11..24fec62dd573a 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -320,7 +320,7 @@ impl<'a> fold::DocFolder for ImplStripper<'a> { if let Some(did) = typaram.def_id() { if did.is_local() && !self.retained.contains(&did) { debug!("ImplStripper: stripped item in trait's generics; \ - removing impl"); + removing impl"); return None; } } diff --git a/src/test/rustdoc/inline_cross/auxiliary/trait-vis.rs b/src/test/rustdoc/inline_cross/auxiliary/trait-vis.rs new file mode 100644 index 0000000000000..7457a5d4899fe --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/trait-vis.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "inner"] + +pub struct SomeStruct; + +fn asdf() { + const _FOO: () = { + impl Clone for SomeStruct { + fn clone(&self) -> Self { + SomeStruct + } + } + }; +} diff --git a/src/test/rustdoc/inline_cross/trait-vis.rs b/src/test/rustdoc/inline_cross/trait-vis.rs new file mode 100644 index 0000000000000..5b5410b1da44d --- /dev/null +++ b/src/test/rustdoc/inline_cross/trait-vis.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:trait-vis.rs + +extern crate inner; + +// @has trait_vis/struct.SomeStruct.html +// @has - '//code' 'impl Clone for SomeStruct' +pub use inner::SomeStruct; diff --git a/src/test/rustdoc/inline_local/trait-vis.rs b/src/test/rustdoc/inline_local/trait-vis.rs index 1035e357ef649..73b1cc2ce8f2d 100644 --- a/src/test/rustdoc/inline_local/trait-vis.rs +++ b/src/test/rustdoc/inline_local/trait-vis.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// 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. // diff --git a/src/test/rustdoc/primitive-generic-impl.rs b/src/test/rustdoc/primitive-generic-impl.rs index b4351b8268c8b..a771b1b15ce4d 100644 --- a/src/test/rustdoc/primitive-generic-impl.rs +++ b/src/test/rustdoc/primitive-generic-impl.rs @@ -10,9 +10,6 @@ #![crate_name = "foo"] -// we need to reexport something from libstd so that `all_trait_implementations` is called. -pub use std::string::String; - include!("primitive/primitive-generic-impl.rs"); // @has foo/primitive.i32.html '//h3[@id="impl-ToString"]//code' 'impl ToString for T' diff --git a/src/test/rustdoc/traits-in-bodies.rs b/src/test/rustdoc/traits-in-bodies.rs index 26ed544412275..a1d4019bba2bf 100644 --- a/src/test/rustdoc/traits-in-bodies.rs +++ b/src/test/rustdoc/traits-in-bodies.rs @@ -39,3 +39,24 @@ const _FOO: () = { impl Copy for Point {} () }; + +// @has traits_in_bodies/struct.Inception.html +// @has - '//code' 'impl Clone for Inception' +pub struct Inception; + +static _BAR: usize = { + trait HiddenTrait { + fn hidden_fn(&self) { + for _ in 0..5 { + impl Clone for Inception { + fn clone(&self) -> Self { + // we need to go deeper + Inception + } + } + } + } + } + + 5 +}; From 5fd1d8357ee94bc6b49ec975e1ab4f37ac4b487a Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 28 Aug 2018 11:33:45 -0500 Subject: [PATCH 15/18] don't index trait impls if the trait isn't also documented --- src/librustdoc/html/render.rs | 34 +++++++++++++++++--- src/librustdoc/lib.rs | 1 + src/test/rustdoc/traits-in-bodies-private.rs | 23 +++++++++++++ 3 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 src/test/rustdoc/traits-in-bodies-private.rs diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 9d6ea70ed6563..d052760724e67 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, 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>, @@ -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 { 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, @@ -1455,10 +1473,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 1acae86f0068f..11cf43dad4a92 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -25,6 +25,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 0000000000000..ac3be7e61e9a0 --- /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 or the MIT license +// , 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 {} +} From ce70d912c175520232e26d56b0e3d1ed93f408d2 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 30 Aug 2018 12:10:15 -0500 Subject: [PATCH 16/18] collect auto-/blanket-impls during collect-trait-impls --- src/librustdoc/clean/inline.rs | 28 +++------ src/librustdoc/clean/mod.rs | 60 +++++++------------- src/librustdoc/passes/collect_trait_impls.rs | 40 ++++++++++++- 3 files changed, 65 insertions(+), 63 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d248bb58fc599..a91336dced398 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -29,8 +29,6 @@ use clean::{ self, GetDefId, ToSource, - get_auto_traits_with_def_id, - get_blanket_impls_with_def_id, }; use super::Clean; @@ -56,7 +54,7 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHa let inner = match def { Def::Trait(did) => { record_extern_fqn(cx, did, clean::TypeKind::Trait); - ret.extend(build_impls(cx, did, false)); + ret.extend(build_impls(cx, did)); clean::TraitItem(build_external_trait(cx, did)) } Def::Fn(did) => { @@ -65,27 +63,27 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHa } Def::Struct(did) => { record_extern_fqn(cx, did, clean::TypeKind::Struct); - ret.extend(build_impls(cx, did, true)); + ret.extend(build_impls(cx, did)); clean::StructItem(build_struct(cx, did)) } Def::Union(did) => { record_extern_fqn(cx, did, clean::TypeKind::Union); - ret.extend(build_impls(cx, did, true)); + ret.extend(build_impls(cx, did)); clean::UnionItem(build_union(cx, did)) } Def::TyAlias(did) => { record_extern_fqn(cx, did, clean::TypeKind::Typedef); - ret.extend(build_impls(cx, did, false)); + ret.extend(build_impls(cx, did)); clean::TypedefItem(build_type_alias(cx, did), false) } Def::Enum(did) => { record_extern_fqn(cx, did, clean::TypeKind::Enum); - ret.extend(build_impls(cx, did, true)); + ret.extend(build_impls(cx, did)); clean::EnumItem(build_enum(cx, did)) } Def::ForeignTy(did) => { record_extern_fqn(cx, did, clean::TypeKind::Foreign); - ret.extend(build_impls(cx, did, false)); + ret.extend(build_impls(cx, did)); clean::ForeignTypeItem } // Never inline enum variants but leave them shown as re-exports. @@ -274,7 +272,7 @@ fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef { } } -pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec { +pub fn build_impls(cx: &DocContext, did: DefId) -> Vec { let tcx = cx.tcx; let mut impls = Vec::new(); @@ -282,18 +280,6 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec = auto_impls.into_iter() - .filter(|i| renderinfo.inlined.insert(i.def_id)).collect(); - - impls.extend(new_impls); - } - impls.extend(get_blanket_impls_with_def_id(cx, did)); - } - impls } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 68d812762a96c..20e1f3f3beae1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -576,9 +576,9 @@ impl Clean for doctree::Module { let mut items: Vec = vec![]; items.extend(self.extern_crates.iter().map(|x| x.clean(cx))); items.extend(self.imports.iter().flat_map(|x| x.clean(cx))); - items.extend(self.structs.iter().flat_map(|x| x.clean(cx))); - items.extend(self.unions.iter().flat_map(|x| x.clean(cx))); - items.extend(self.enums.iter().flat_map(|x| x.clean(cx))); + items.extend(self.structs.iter().map(|x| x.clean(cx))); + items.extend(self.unions.iter().map(|x| x.clean(cx))); + items.extend(self.enums.iter().map(|x| x.clean(cx))); items.extend(self.fns.iter().map(|x| x.clean(cx))); items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx))); items.extend(self.mods.iter().map(|x| x.clean(cx))); @@ -2813,14 +2813,10 @@ pub struct Union { pub fields_stripped: bool, } -impl Clean> for doctree::Struct { - fn clean(&self, cx: &DocContext) -> Vec { - let name = self.name.clean(cx); - let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone()); - ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone())); - - ret.push(Item { - name: Some(name), +impl Clean for doctree::Struct { + fn clean(&self, cx: &DocContext) -> Item { + Item { + name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), def_id: cx.tcx.hir.local_def_id(self.id), @@ -2833,20 +2829,14 @@ impl Clean> for doctree::Struct { fields: self.fields.clean(cx), fields_stripped: false, }), - }); - - ret + } } } -impl Clean> for doctree::Union { - fn clean(&self, cx: &DocContext) -> Vec { - let name = self.name.clean(cx); - let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone()); - ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone())); - - ret.push(Item { - name: Some(name), +impl Clean for doctree::Union { + fn clean(&self, cx: &DocContext) -> Item { + Item { + name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), def_id: cx.tcx.hir.local_def_id(self.id), @@ -2859,9 +2849,7 @@ impl Clean> for doctree::Union { fields: self.fields.clean(cx), fields_stripped: false, }), - }); - - ret + } } } @@ -2892,14 +2880,10 @@ pub struct Enum { pub variants_stripped: bool, } -impl Clean> for doctree::Enum { - fn clean(&self, cx: &DocContext) -> Vec { - let name = self.name.clean(cx); - let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone()); - ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone())); - - ret.push(Item { - name: Some(name), +impl Clean for doctree::Enum { + fn clean(&self, cx: &DocContext) -> Item { + Item { + name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), def_id: cx.tcx.hir.local_def_id(self.id), @@ -2911,9 +2895,7 @@ impl Clean> for doctree::Enum { generics: self.generics.clean(cx), variants_stripped: false, }), - }); - - ret + } } } @@ -3442,11 +3424,7 @@ fn build_deref_target_impls(cx: &DocContext, let primitive = match *target { ResolvedPath { did, .. } if did.is_local() => continue, ResolvedPath { did, .. } => { - // We set the last parameter to false to avoid looking for auto-impls for traits - // and therefore avoid an ICE. - // The reason behind this is that auto-traits don't propagate through Deref so - // we're not supposed to synthesise impls for them. - ret.extend(inline::build_impls(cx, did, false)); + ret.extend(inline::build_impls(cx, did)); continue } _ => match target.primitive_type() { diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 0ee1657f21516..56940483d7be2 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -12,14 +12,20 @@ use clean::*; use super::Pass; use core::DocContext; +use fold::DocFolder; pub const COLLECT_TRAIT_IMPLS: Pass = Pass::early("collect-trait-impls", collect_trait_impls, "retrieves trait impls for items in the crate"); -pub fn collect_trait_impls(mut krate: Crate, cx: &DocContext) -> Crate { +pub fn collect_trait_impls(krate: Crate, cx: &DocContext) -> Crate { + let mut synth = SyntheticImplCollector::new(cx); + let mut krate = synth.fold_crate(krate); + if let Some(ref mut it) = krate.module { if let ModuleItem(Module { ref mut items, .. }) = it.inner { + items.extend(synth.impls); + for &cnum in cx.tcx.crates().iter() { for &did in cx.tcx.all_trait_implementations(cnum).iter() { inline::build_impl(cx, did, items); @@ -90,3 +96,35 @@ pub fn collect_trait_impls(mut krate: Crate, cx: &DocContext) -> Crate { krate } + +struct SyntheticImplCollector<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> { + cx: &'a DocContext<'a, 'tcx, 'rcx, 'cstore>, + impls: Vec, +} + +impl<'a, 'tcx, 'rcx, 'cstore> SyntheticImplCollector<'a, 'tcx, 'rcx, 'cstore> { + fn new(cx: &'a DocContext<'a, 'tcx, 'rcx, 'cstore>) -> Self { + SyntheticImplCollector { + cx, + impls: Vec::new(), + } + } +} + +impl<'a, 'tcx, 'rcx, 'cstore> DocFolder for SyntheticImplCollector<'a, 'tcx, 'rcx, 'cstore> { + fn fold_item(&mut self, i: Item) -> Option { + if i.is_struct() || i.is_enum() || i.is_union() { + if let (Some(node_id), Some(name)) = + (self.cx.tcx.hir.as_local_node_id(i.def_id), i.name.clone()) + { + self.impls.extend(get_auto_traits_with_node_id(self.cx, node_id, name.clone())); + self.impls.extend(get_blanket_impls_with_node_id(self.cx, node_id, name)); + } else { + self.impls.extend(get_auto_traits_with_def_id(self.cx, i.def_id)); + self.impls.extend(get_blanket_impls_with_def_id(self.cx, i.def_id)); + } + } + + self.fold_item_recur(i) + } +} From 9e75db4da0af7347e36f892e706574d9d1a6b52f Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 30 Aug 2018 16:46:10 -0500 Subject: [PATCH 17/18] refactor: move `access_levels` into RenderInfo --- src/librustdoc/clean/blanket_impl.rs | 2 +- src/librustdoc/clean/inline.rs | 4 ++-- src/librustdoc/clean/mod.rs | 5 +---- src/librustdoc/core.rs | 10 ++++------ src/librustdoc/html/render.rs | 6 ++++-- src/librustdoc/passes/strip_private.rs | 2 +- src/librustdoc/visit_ast.rs | 7 +++++-- src/librustdoc/visit_lib.rs | 2 +- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index e7e371cd56785..34c4c70159f3a 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx, 'rcx, 'cstore> BlanketImplFinder <'a, 'tcx, 'rcx, 'cstore> { let real_name = name.clone().map(|name| Ident::from_str(&name)); let param_env = self.cx.tcx.param_env(def_id); for &trait_def_id in self.cx.all_traits.iter() { - if !self.cx.access_levels.borrow().is_doc_reachable(trait_def_id) || + if !self.cx.renderinfo.borrow().access_levels.is_doc_reachable(trait_def_id) || self.cx.generated_synthetics .borrow_mut() .get(&(def_id, trait_def_id)) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index a91336dced398..a29c62f474fa0 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -296,7 +296,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { // reachable in rustdoc generated documentation if !did.is_local() { if let Some(traitref) = associated_trait { - if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) { + if !cx.renderinfo.borrow().access_levels.is_doc_reachable(traitref.def_id) { return } } @@ -317,7 +317,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { // reachable in rustdoc generated documentation if !did.is_local() { if let Some(did) = for_.def_id() { - if !cx.access_levels.borrow().is_doc_reachable(did) { + if !cx.renderinfo.borrow().access_levels.is_doc_reachable(did) { return } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 20e1f3f3beae1..8ec4b7bcee8ee 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -28,7 +28,6 @@ use syntax::symbol::InternedString; use syntax_pos::{self, DUMMY_SP, Pos, FileName}; use rustc::mir::interpret::ConstValue; -use rustc::middle::privacy::AccessLevels; use rustc::middle::resolve_lifetime as rl; use rustc::ty::fold::TypeFolder; use rustc::middle::lang_items; @@ -135,7 +134,6 @@ pub struct Crate { pub module: Option, pub externs: Vec<(CrateNum, ExternalCrate)>, pub primitives: Vec<(DefId, PrimitiveType, Attributes)>, - pub access_levels: Arc>, // 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, @@ -216,7 +214,6 @@ impl<'a, 'tcx, 'rcx, 'cstore> Clean for visit_ast::RustdocVisitor<'a, 'tc module: Some(module), externs, primitives, - access_levels: Arc::new(Default::default()), external_traits: Default::default(), masked_crates, } @@ -2433,7 +2430,7 @@ impl Clean for hir::Ty { if let Def::TyAlias(def_id) = path.def { // Substitute private type aliases if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) { - if !cx.access_levels.borrow().is_exported(def_id) { + if !cx.renderinfo.borrow().access_levels.is_exported(def_id) { alias = Some(&cx.tcx.hir.expect_item(node_id).node); } } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 3a942aa6c8db1..08142a77471d7 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -41,7 +41,6 @@ use std::cell::RefCell; use std::mem; use rustc_data_structures::sync::{self, Lrc}; use std::rc::Rc; -use std::sync::Arc; use std::path::PathBuf; use visit_ast::RustdocVisitor; @@ -64,8 +63,6 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> { // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing // the access levels from crateanalysis. - /// Later on moved into `clean::Crate` - pub access_levels: RefCell>, /// Later on moved into `html::render::CACHE_KEY` pub renderinfo: RefCell, /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY` @@ -506,15 +503,17 @@ pub fn run_core(search_paths: SearchPaths, clean::path_to_def(&tcx, &["core", "marker", "Send"]) }; + let mut renderinfo = RenderInfo::default(); + renderinfo.access_levels = access_levels; + let ctxt = DocContext { tcx, resolver: &resolver, crate_name, cstore: cstore.clone(), - access_levels: RefCell::new(access_levels), external_traits: Default::default(), active_extern_traits: Default::default(), - renderinfo: Default::default(), + renderinfo: RefCell::new(renderinfo), ty_substs: Default::default(), lt_substs: Default::default(), impl_trait_bounds: Default::default(), @@ -597,7 +596,6 @@ pub fn run_core(search_paths: SearchPaths, ctxt.sess().abort_if_errors(); - krate.access_levels = Arc::new(ctxt.access_levels.into_inner()); krate.external_traits = ctxt.external_traits.into_inner(); (krate, ctxt.renderinfo.into_inner(), passes) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d052760724e67..f188fccdb3cbe 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -313,7 +313,7 @@ pub struct Cache { // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing // the access levels from crateanalysis. - pub access_levels: Arc>, + pub access_levels: AccessLevels, /// The version of the crate being documented, if given from the `--crate-version` flag. pub crate_version: Option, @@ -359,6 +359,7 @@ pub struct RenderInfo { pub external_paths: ::core::ExternalPaths, pub external_typarams: FxHashMap, pub exact_paths: FxHashMap>, + pub access_levels: AccessLevels, pub deref_trait_did: Option, pub deref_mut_trait_did: Option, pub owned_box_did: Option, @@ -578,6 +579,7 @@ pub fn run(mut krate: clean::Crate, external_paths, external_typarams, exact_paths, + access_levels, deref_trait_did, deref_mut_trait_did, owned_box_did, @@ -600,7 +602,7 @@ pub fn run(mut krate: clean::Crate, extern_locations: FxHashMap(), primitive_locations: FxHashMap(), stripped_mod: false, - access_levels: krate.access_levels.clone(), + access_levels, crate_version: krate.version.take(), orphan_impl_items: Vec::new(), orphan_trait_impls: Vec::new(), diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 4fa5943faca07..46d0034497e28 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -25,7 +25,7 @@ pub const STRIP_PRIVATE: Pass = pub fn strip_private(mut krate: clean::Crate, cx: &DocContext) -> clean::Crate { // This stripper collects all *retained* nodes. let mut retained = DefIdSet(); - let access_levels = cx.access_levels.borrow().clone(); + let access_levels = cx.renderinfo.borrow().access_levels.clone(); // strip all private items { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ce438cd99a4b6..3f8b13d145856 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -269,7 +269,10 @@ impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> { Def::Enum(did) | Def::ForeignTy(did) | Def::TyAlias(did) if !self_is_hidden => { - self.cx.access_levels.borrow_mut().map.insert(did, AccessLevel::Public); + self.cx.renderinfo + .borrow_mut() + .access_levels.map + .insert(did, AccessLevel::Public); }, Def::Mod(did) => if !self_is_hidden { ::visit_lib::LibEmbargoVisitor::new(self.cx).visit_mod(did); @@ -284,7 +287,7 @@ impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> { Some(n) => n, None => return false }; - let is_private = !self.cx.access_levels.borrow().is_public(def_did); + let is_private = !self.cx.renderinfo.borrow().access_levels.is_public(def_did); let is_hidden = inherits_doc_hidden(self.cx, def_node_id); // Only inline if requested or if the item would otherwise be stripped diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 10a4e69dcc6cd..fd81f937f30c7 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -38,7 +38,7 @@ impl<'a, 'tcx, 'rcx, 'cstore> LibEmbargoVisitor<'a, 'tcx, 'rcx, 'cstore> { ) -> LibEmbargoVisitor<'a, 'tcx, 'rcx, 'cstore> { LibEmbargoVisitor { cx, - access_levels: cx.access_levels.borrow_mut(), + access_levels: RefMut::map(cx.renderinfo.borrow_mut(), |ri| &mut ri.access_levels), prev_level: Some(AccessLevel::Public), visited_mods: FxHashSet() } From 8aba29a5cf25f9c84e4f753a7ea4b5c0d6446e32 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Sat, 1 Sep 2018 21:20:39 -0500 Subject: [PATCH 18/18] shuffle ownership of `external_traits` constraints: - clean/inline.rs needs this map to fill in traits when inlining - fold.rs needs this map to allow passes to fold trait items - html/render.rs needs this map to seed the Cache.traits map of all known traits The first two are the real problem, since `DocFolder` only operates on `clean::Crate` but `clean/inline.rs` only sees the `DocContext`. The introduction of early passes means that these two now exist at the same time, so they need to share ownership of the map. Even better, the use of `Crate` in a rustc thread pool means that it needs to be Sync, so it can't use `Lrc` to manually activate thread-safety. `parking_lot` is reused from elsewhere in the tree to allow use of its `ReentrantMutex`, as the relevant parts of rustdoc are still single-threaded and this allows for easier use in that context. --- src/Cargo.lock | 1 + src/librustdoc/Cargo.toml | 1 + src/librustdoc/clean/inline.rs | 14 ++++++++++---- src/librustdoc/clean/mod.rs | 6 ++++-- src/librustdoc/core.rs | 6 +++--- src/librustdoc/fold.rs | 15 ++++++++------- src/librustdoc/html/render.rs | 2 +- src/librustdoc/lib.rs | 1 + src/librustdoc/passes/strip_hidden.rs | 9 ++------- 9 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index a4f9082c284cd..56efe5c5fb499 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2417,6 +2417,7 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "minifier 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index e163fc68cbda7..845bfad7807d3 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -11,3 +11,4 @@ path = "lib.rs" pulldown-cmark = { version = "0.1.2", default-features = false } minifier = "0.0.19" tempfile = "3" +parking_lot = "0.6.4" diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index a29c62f474fa0..6e1c1d17d6e15 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -538,10 +538,13 @@ pub fn record_extern_trait(cx: &DocContext, did: DefId) { return; } - if cx.external_traits.borrow().contains_key(&did) || - cx.active_extern_traits.borrow().contains(&did) { - return; + let external_traits = cx.external_traits.lock(); + if external_traits.borrow().contains_key(&did) || + cx.active_extern_traits.borrow().contains(&did) + { + return; + } } cx.active_extern_traits.borrow_mut().push(did); @@ -549,6 +552,9 @@ pub fn record_extern_trait(cx: &DocContext, did: DefId) { debug!("record_extern_trait: {:?}", did); let trait_ = build_external_trait(cx, did); - cx.external_traits.borrow_mut().insert(did, trait_); + { + let external_traits = cx.external_traits.lock(); + external_traits.borrow_mut().insert(did, trait_); + } cx.active_extern_traits.borrow_mut().remove_item(&did); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8ec4b7bcee8ee..943bd2526c9c2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -55,6 +55,8 @@ use std::cell::RefCell; use std::sync::Arc; use std::u32; +use parking_lot::ReentrantMutex; + use core::{self, DocContext}; use doctree; use visit_ast; @@ -136,7 +138,7 @@ pub struct Crate { pub primitives: Vec<(DefId, PrimitiveType, Attributes)>, // 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, + pub external_traits: Arc>>>, pub masked_crates: FxHashSet, } @@ -214,7 +216,7 @@ impl<'a, 'tcx, 'rcx, 'cstore> Clean for visit_ast::RustdocVisitor<'a, 'tc module: Some(module), externs, primitives, - external_traits: Default::default(), + external_traits: cx.external_traits.clone(), masked_crates, } } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 08142a77471d7..253d8b93c667b 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -36,11 +36,13 @@ use syntax::symbol::keywords; use syntax_pos::DUMMY_SP; use errors; use errors::emitter::{Emitter, EmitterWriter}; +use parking_lot::ReentrantMutex; use std::cell::RefCell; use std::mem; use rustc_data_structures::sync::{self, Lrc}; use std::rc::Rc; +use std::sync::Arc; use std::path::PathBuf; use visit_ast::RustdocVisitor; @@ -66,7 +68,7 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> { /// Later on moved into `html::render::CACHE_KEY` pub renderinfo: RefCell, /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY` - pub external_traits: RefCell>, + pub external_traits: Arc>>>, /// Used while populating `external_traits` to ensure we don't process the same trait twice at /// the same time. pub active_extern_traits: RefCell>, @@ -596,8 +598,6 @@ pub fn run_core(search_paths: SearchPaths, ctxt.sess().abort_if_errors(); - krate.external_traits = ctxt.external_traits.into_inner(); - (krate, ctxt.renderinfo.into_inner(), passes) }), &sess) }) diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 6d96bc8e36038..b8e27c5317083 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::mem; - use clean::*; pub struct StripItem(pub Item); @@ -116,11 +114,14 @@ pub trait DocFolder : Sized { fn fold_crate(&mut self, mut c: Crate) -> Crate { c.module = c.module.take().and_then(|module| self.fold_item(module)); - let traits = mem::replace(&mut c.external_traits, Default::default()); - c.external_traits.extend(traits.into_iter().map(|(k, mut v)| { - v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); - (k, v) - })); + { + let guard = c.external_traits.lock(); + let traits = guard.replace(Default::default()); + guard.borrow_mut().extend(traits.into_iter().map(|(k, mut v)| { + v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); + (k, v) + })); + } c } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index f188fccdb3cbe..ed71d13009d63 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -606,7 +606,7 @@ pub fn run(mut krate: clean::Crate, crate_version: krate.version.take(), orphan_impl_items: Vec::new(), orphan_trait_impls: Vec::new(), - traits: mem::replace(&mut krate.external_traits, FxHashMap()), + traits: krate.external_traits.lock().replace(FxHashMap()), deref_trait_did, deref_mut_trait_did, owned_box_did, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 11cf43dad4a92..d0b00fd52ee77 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -50,6 +50,7 @@ extern crate rustc_errors as errors; extern crate pulldown_cmark; extern crate tempfile; extern crate minifier; +extern crate parking_lot; extern crate serialize as rustc_serialize; // used by deriving diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index eab4022a3389f..24dd4cc13bfe8 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -24,13 +24,9 @@ pub const STRIP_HIDDEN: Pass = "strips all doc(hidden) items from the output"); /// Strip items marked `#[doc(hidden)]` -pub fn strip_hidden(mut krate: clean::Crate, cx: &DocContext) -> clean::Crate { +pub fn strip_hidden(krate: clean::Crate, _: &DocContext) -> clean::Crate { let mut retained = DefIdSet(); - // as an early pass, the external traits haven't been swapped in, so we need to do that ahead - // of time - mem::swap(&mut krate.external_traits, &mut cx.external_traits.borrow_mut()); - // strip all #[doc(hidden)] items let krate = { let mut stripper = Stripper{ retained: &mut retained, update_retained: true }; @@ -39,8 +35,7 @@ pub fn strip_hidden(mut krate: clean::Crate, cx: &DocContext) -> clean::Crate { // strip all impls referencing stripped items let mut stripper = ImplStripper { retained: &retained }; - let mut krate = stripper.fold_crate(krate); - mem::swap(&mut krate.external_traits, &mut cx.external_traits.borrow_mut()); + let krate = stripper.fold_crate(krate); krate }