Skip to content

rustc_metadata: Encode the set of "rustdoc-reachable" def ids to metadata #107237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
}
}

fn get_rustdoc_reachable(self) -> impl Iterator<Item = DefId> + 'a {
self.root.rustdoc_reachable.decode(self)
}

fn get_native_libraries(self, sess: &'a Session) -> impl Iterator<Item = NativeLib> + 'a {
self.root.native_libraries.decode((self, sess))
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,10 @@ impl CStore {
self.get_crate_data(cnum).get_all_incoherent_impls()
}

pub fn rustdoc_reachable_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ {
self.get_crate_data(cnum).get_rustdoc_reachable()
}

pub fn associated_item_def_ids_untracked<'a>(
&'a self,
def_id: DefId,
Expand Down
136 changes: 107 additions & 29 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::rmeta::*;

use rustc_ast::Attribute;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_data_structures::memmap::{Mmap, MmapMut};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator};
Expand Down Expand Up @@ -598,6 +598,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {

let incoherent_impls = stat!("incoherent-impls", || self.encode_incoherent_impls());

let rustdoc_reachable = stat!("rustdoc-reachable", || self.encode_rustdoc_reachable());

_ = stat!("mir", || self.encode_mir());

_ = stat!("items", || {
Expand Down Expand Up @@ -698,6 +700,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
traits,
impls,
incoherent_impls,
rustdoc_reachable,
exported_symbols,
interpret_alloc_index,
tables,
Expand Down Expand Up @@ -1256,7 +1259,40 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
}

fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) {
fn module_children(
tcx: TyCtxt<'tcx>,
md: &'tcx hir::Mod<'tcx>,
) -> impl Iterator<Item = DefIndex> + 'tcx {
iter::from_generator(move || {
for item_id in md.item_ids {
match tcx.hir().item(*item_id).kind {
// Foreign items are planted into their parent modules
// from name resolution point of view.
hir::ItemKind::ForeignMod { items, .. } => {
for foreign_item in items {
yield foreign_item.id.owner_id.def_id.local_def_index;
}
}
// Only encode named non-reexport children, reexports are encoded
// separately and unnamed items are not used by name resolution.
hir::ItemKind::ExternCrate(..) => continue,
hir::ItemKind::Struct(ref vdata, _) => {
yield item_id.owner_id.def_id.local_def_index;
// Encode constructors which take a separate slot in value namespace.
if let Some(ctor_hir_id) = vdata.ctor_hir_id() {
yield tcx.hir().local_def_id(ctor_hir_id).local_def_index;
}
}
_ if tcx.def_key(item_id.owner_id.to_def_id()).get_opt_name().is_some() => {
yield item_id.owner_id.def_id.local_def_index;
}
_ => continue,
}
}
})
}

fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &'tcx hir::Mod<'tcx>) {
let tcx = self.tcx;
let def_id = local_def_id.to_def_id();
debug!("EncodeContext::encode_info_for_mod({:?})", def_id);
Expand All @@ -1270,33 +1306,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// Encode this here because we don't do it in encode_def_ids.
record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
} else {
record_array!(self.tables.children[def_id] <- iter::from_generator(|| {
for item_id in md.item_ids {
match tcx.hir().item(*item_id).kind {
// Foreign items are planted into their parent modules
// from name resolution point of view.
hir::ItemKind::ForeignMod { items, .. } => {
for foreign_item in items {
yield foreign_item.id.owner_id.def_id.local_def_index;
}
}
// Only encode named non-reexport children, reexports are encoded
// separately and unnamed items are not used by name resolution.
hir::ItemKind::ExternCrate(..) => continue,
hir::ItemKind::Struct(ref vdata, _) => {
yield item_id.owner_id.def_id.local_def_index;
// Encode constructors which take a separate slot in value namespace.
if let Some(ctor_hir_id) = vdata.ctor_hir_id() {
yield tcx.hir().local_def_id(ctor_hir_id).local_def_index;
}
}
_ if tcx.def_key(item_id.owner_id.to_def_id()).get_opt_name().is_some() => {
yield item_id.owner_id.def_id.local_def_index;
}
_ => continue,
}
}
}));
record_array!(self.tables.children[def_id] <- Self::module_children(tcx, md));

if let Some(reexports) = tcx.module_reexports(local_def_id) {
assert!(!reexports.is_empty());
Expand Down Expand Up @@ -1974,6 +1984,74 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
self.lazy_array(&all_impls)
}

fn encode_rustdoc_reachable(&mut self) -> LazyArray<DefId> {
struct LibEmbargoVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
extern_public: FxHashSet<DefId>,
visited_mods: FxHashSet<DefId>,
}

impl LibEmbargoVisitor<'_> {
fn visit_mod(&mut self, def_id: DefId) {
if !self.visited_mods.insert(def_id) {
return;
}

let tcx = self.tcx;
match def_id.as_local() {
Some(def_id) => {
let (md, ..) = tcx.hir().get_module(def_id);
for local_def_index in EncodeContext::module_children(tcx, md) {
let def_id = LocalDefId { local_def_index }.to_def_id();
if tcx.visibility(def_id).is_public() {
self.visit_item(def_id);
}
}
if let Some(reexports) = tcx.module_reexports(def_id) {
for item in reexports {
if let Some(def_id) = item.res.opt_def_id() {
if item.vis.is_public() {
self.visit_item(def_id);
}
}
}
}
}
None => {
for item in tcx.module_children(def_id).iter() {
if let Some(def_id) = item.res.opt_def_id() {
if item.vis.is_public() {
self.visit_item(def_id);
}
}
}
}
}
}

fn visit_item(&mut self, def_id: DefId) {
if !self.tcx.is_doc_hidden(def_id) {
self.extern_public.insert(def_id);
if self.tcx.def_kind(def_id) == DefKind::Mod {
self.visit_mod(def_id);
}
}
}
}

let mut visitor = LibEmbargoVisitor {
tcx: self.tcx,
extern_public: Default::default(),
visited_mods: Default::default(),
};
visitor.visit_item(CRATE_DEF_ID.to_def_id());

let mut rustdoc_reachable: Vec<_> = visitor.extern_public.into_iter().collect();
rustdoc_reachable.sort_by_cached_key(|&def_id| self.tcx.def_path_hash(def_id));

self.lazy_array(rustdoc_reachable)
}

// Encodes all symbols exported from this crate into the metadata.
//
// This pass is seeded off the reachability list calculated in the
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ pub(crate) struct CrateRoot {
traits: LazyArray<DefIndex>,
impls: LazyArray<TraitImpls>,
incoherent_impls: LazyArray<IncoherentImpls>,
rustdoc_reachable: LazyArray<DefId>,
interpret_alloc_index: LazyArray<u32>,
proc_macro_data: Option<ProcMacroData>,

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/parameterized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ trivially_parameterized_over_tcx! {
rustc_hir::IsAsync,
rustc_hir::LangItem,
rustc_hir::def::DefKind,
rustc_hir::def_id::DefId,
rustc_hir::def_id::DefIndex,
rustc_hir::definitions::DefKey,
rustc_index::bit_set::BitSet<u32>,
Expand Down
8 changes: 6 additions & 2 deletions src/librustdoc/clean/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use rustc_ast::tokenstream::TokenTree;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_metadata::creader::CStore;
use rustc_middle::mir;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
Expand All @@ -29,9 +30,12 @@ mod tests;
pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
let module = crate::visit_ast::RustdocVisitor::new(cx).visit();

let cstore = CStore::from_tcx(cx.tcx);
for &cnum in cx.tcx.crates(()) {
// Analyze doc-reachability for extern items
crate::visit_lib::lib_embargo_visit_item(cx, cnum.as_def_id());
Extend::extend(
&mut cx.cache.effective_visibilities.extern_public,
cstore.rustdoc_reachable_untracked(cnum),
);
}

// Clean the crate, translating the entire librustc_ast AST to one that is
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/visit_lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_middle::ty::TyCtxt;

#[derive(Default)]
pub(crate) struct RustdocEffectiveVisibilities {
extern_public: DefIdSet,
pub extern_public: DefIdSet,
}

macro_rules! define_method {
Expand Down