use rustc_middle::hir::exports::Export;
use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::middle::stability::DeprecationEntry;
+use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule};
extra_filename => { cdata.root.extra_filename.clone() }
traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) }
- all_trait_implementations => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) }
-
implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }
visibility => { cdata.get_visibility(def_id.index) }
) -> Span {
self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
}
+
+ pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> Vec<DefId> {
+ self.get_crate_data(cnum).get_traits().collect()
+ }
+
+ pub fn trait_impls_in_crate_untracked(
+ &self,
+ cnum: CrateNum,
+ ) -> Vec<(DefId, Option<SimplifiedType>)> {
+ self.get_crate_data(cnum).get_trait_impls().collect()
+ }
}
impl CrateStore for CStore {
separate_provide_extern
}
- /// Given a crate, look up all trait impls in that crate.
- /// Return `(impl_id, self_ty)`.
- query all_trait_implementations(_: CrateNum) -> &'tcx [(DefId, Option<SimplifiedType>)] {
- desc { "looking up all (?) trait implementations" }
- separate_provide_extern
- }
-
query is_dllimport_foreign_item(def_id: DefId) -> bool {
desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
}
trace!("get_blanket_impls({:?})", ty);
let mut impls = Vec::new();
- for trait_def_id in self.cx.tcx.all_traits() {
- if !self.cx.cache.access_levels.is_public(trait_def_id)
- || self.cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
- {
- continue;
- }
- // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
- let trait_impls = self.cx.tcx.trait_impls_of(trait_def_id);
- for &impl_def_id in trait_impls.blanket_impls() {
- trace!(
- "get_blanket_impls: Considering impl for trait '{:?}' {:?}",
- trait_def_id,
- impl_def_id
- );
- let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap();
- let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_));
- let may_apply = is_param && self.cx.tcx.infer_ctxt().enter(|infcx| {
- let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
- let ty = ty.subst(infcx.tcx, substs);
- let param_env = param_env.subst(infcx.tcx, substs);
+ self.cx.with_all_traits(|cx, all_traits| {
+ for &trait_def_id in all_traits {
+ if !cx.cache.access_levels.is_public(trait_def_id)
+ || cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
+ {
+ continue;
+ }
+ // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
+ let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
+ for &impl_def_id in trait_impls.blanket_impls() {
+ trace!(
+ "get_blanket_impls: Considering impl for trait '{:?}' {:?}",
+ trait_def_id,
+ impl_def_id
+ );
+ let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();
+ let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_));
+ let may_apply = is_param && cx.tcx.infer_ctxt().enter(|infcx| {
+ let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
+ let ty = ty.subst(infcx.tcx, substs);
+ let param_env = param_env.subst(infcx.tcx, substs);
- let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
- let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
+ let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
+ let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
- // Require the type the impl is implemented on to match
- // our type, and ignore the impl if there was a mismatch.
- let cause = traits::ObligationCause::dummy();
- let eq_result = infcx.at(&cause, param_env).eq(trait_ref.self_ty(), ty);
- if let Ok(InferOk { value: (), obligations }) = eq_result {
- // FIXME(eddyb) ignoring `obligations` might cause false positives.
- drop(obligations);
+ // Require the type the impl is implemented on to match
+ // our type, and ignore the impl if there was a mismatch.
+ let cause = traits::ObligationCause::dummy();
+ let eq_result = infcx.at(&cause, param_env).eq(trait_ref.self_ty(), ty);
+ if let Ok(InferOk { value: (), obligations }) = eq_result {
+ // FIXME(eddyb) ignoring `obligations` might cause false positives.
+ drop(obligations);
- trace!(
- "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
- param_env,
- trait_ref,
- ty
- );
- let predicates = self
- .cx
- .tcx
- .predicates_of(impl_def_id)
- .instantiate(self.cx.tcx, impl_substs)
- .predicates
- .into_iter()
- .chain(Some(
- ty::Binder::dummy(trait_ref)
- .to_poly_trait_predicate()
- .map_bound(ty::PredicateKind::Trait)
- .to_predicate(infcx.tcx),
- ));
- for predicate in predicates {
- debug!("testing predicate {:?}", predicate);
- let obligation = traits::Obligation::new(
- traits::ObligationCause::dummy(),
+ trace!(
+ "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
param_env,
- predicate,
+ trait_ref,
+ ty
);
- match infcx.evaluate_obligation(&obligation) {
- Ok(eval_result) if eval_result.may_apply() => {}
- Err(traits::OverflowError::Canonical) => {}
- Err(traits::OverflowError::ErrorReporting) => {}
- _ => {
- return false;
+ let predicates = cx
+ .tcx
+ .predicates_of(impl_def_id)
+ .instantiate(cx.tcx, impl_substs)
+ .predicates
+ .into_iter()
+ .chain(Some(
+ ty::Binder::dummy(trait_ref)
+ .to_poly_trait_predicate()
+ .map_bound(ty::PredicateKind::Trait)
+ .to_predicate(infcx.tcx),
+ ));
+ for predicate in predicates {
+ debug!("testing predicate {:?}", predicate);
+ let obligation = traits::Obligation::new(
+ traits::ObligationCause::dummy(),
+ param_env,
+ predicate,
+ );
+ match infcx.evaluate_obligation(&obligation) {
+ Ok(eval_result) if eval_result.may_apply() => {}
+ Err(traits::OverflowError::Canonical) => {}
+ Err(traits::OverflowError::ErrorReporting) => {}
+ _ => {
+ return false;
+ }
}
}
+ true
+ } else {
+ false
}
- true
- } else {
- false
+ });
+ debug!(
+ "get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
+ may_apply, trait_ref, ty
+ );
+ if !may_apply {
+ continue;
}
- });
- debug!(
- "get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
- may_apply, trait_ref, ty
- );
- if !may_apply {
- continue;
- }
- self.cx.generated_synthetics.insert((ty, trait_def_id));
+ cx.generated_synthetics.insert((ty, trait_def_id));
- impls.push(Item {
- name: None,
- attrs: Default::default(),
- visibility: Inherited,
- def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
- kind: box ImplItem(Impl {
- unsafety: hir::Unsafety::Normal,
- generics: clean_ty_generics(
- self.cx,
- self.cx.tcx.generics_of(impl_def_id),
- self.cx.tcx.explicit_predicates_of(impl_def_id),
- ),
- // FIXME(eddyb) compute both `trait_` and `for_` from
- // the post-inference `trait_ref`, as it's more accurate.
- trait_: Some(trait_ref.clean(self.cx)),
- for_: ty.clean(self.cx),
- items: self
- .cx
- .tcx
- .associated_items(impl_def_id)
- .in_definition_order()
- .map(|x| x.clean(self.cx))
- .collect::<Vec<_>>(),
- polarity: ty::ImplPolarity::Positive,
- kind: ImplKind::Blanket(box trait_ref.self_ty().clean(self.cx)),
- }),
- cfg: None,
- });
+ impls.push(Item {
+ name: None,
+ attrs: Default::default(),
+ visibility: Inherited,
+ def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
+ kind: box ImplItem(Impl {
+ unsafety: hir::Unsafety::Normal,
+ generics: clean_ty_generics(
+ cx,
+ cx.tcx.generics_of(impl_def_id),
+ cx.tcx.explicit_predicates_of(impl_def_id),
+ ),
+ // FIXME(eddyb) compute both `trait_` and `for_` from
+ // the post-inference `trait_ref`, as it's more accurate.
+ trait_: Some(trait_ref.clean(cx)),
+ for_: ty.clean(cx),
+ items: cx
+ .tcx
+ .associated_items(impl_def_id)
+ .in_definition_order()
+ .map(|x| x.clean(cx))
+ .collect::<Vec<_>>(),
+ polarity: ty::ImplPolarity::Positive,
+ kind: ImplKind::Blanket(box trait_ref.self_ty().clean(cx)),
+ }),
+ cfg: None,
+ });
+ }
}
- }
+ });
+
impls
}
}
attrs: Option<Attrs<'_>>,
ret: &mut Vec<clean::Item>,
) {
+ let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls");
let tcx = cx.tcx;
// for each implementation of an item represented by `did`, build the clean::Item for that impl
return;
}
- let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impl");
+ let _prof_timer = cx.tcx.sess.prof.generic_activity("build_impl");
let tcx = cx.tcx;
let associated_trait = tcx.impl_trait_ref(did);
};
if let Some(prim) = target.primitive_type() {
+ let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls");
for &did in prim.impls(tcx).iter().filter(|did| !did.is_local()) {
inline::build_impl(cx, None, did, None, ret);
}
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{self, Lrc};
-use rustc_driver::abort_on_err;
use rustc_errors::emitter::{Emitter, EmitterWriter};
use rustc_errors::json::JsonEmitter;
use rustc_feature::UnstableFeatures;
use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::HirId;
-use rustc_hir::{
- intravisit::{self, NestedVisitorMap, Visitor},
- Path,
-};
-use rustc_interface::{interface, Queries};
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::{HirId, Path};
+use rustc_interface::interface;
use rustc_middle::hir::map::Map;
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_resolve as resolve;
-use rustc_resolve::Namespace::TypeNS;
use rustc_session::config::{self, CrateType, ErrorOutputType};
use rustc_session::lint;
use rustc_session::DiagnosticOutput;
use rustc_session::Session;
-use rustc_span::def_id::CRATE_DEF_INDEX;
-use rustc_span::source_map;
use rustc_span::symbol::sym;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{source_map, Span};
use std::cell::RefCell;
use std::lazy::SyncLazy;
crate use rustc_session::config::{DebuggingOptions, Input, Options};
+crate struct ResolverCaches {
+ pub all_traits: Option<Vec<DefId>>,
+ pub all_trait_impls: Option<Vec<DefId>>,
+}
+
crate struct DocContext<'tcx> {
crate tcx: TyCtxt<'tcx>,
/// Name resolver. Used for intra-doc links.
///
/// The `Rc<RefCell<...>>` wrapping is needed because that is what's returned by
- /// [`Queries::expansion()`].
+ /// [`rustc_interface::Queries::expansion()`].
// FIXME: see if we can get rid of this RefCell somehow
crate resolver: Rc<RefCell<interface::BoxedResolver>>,
+ crate resolver_caches: ResolverCaches,
/// Used for normalization.
///
/// Most of this logic is copied from rustc_lint::late.
_ => None,
}
}
+
+ crate fn with_all_traits(&mut self, f: impl FnOnce(&mut Self, &[DefId])) {
+ let all_traits = self.resolver_caches.all_traits.take();
+ f(self, all_traits.as_ref().expect("`all_traits` are already borrowed"));
+ self.resolver_caches.all_traits = all_traits;
+ }
+
+ crate fn with_all_trait_impls(&mut self, f: impl FnOnce(&mut Self, &[DefId])) {
+ let all_trait_impls = self.resolver_caches.all_trait_impls.take();
+ f(self, all_trait_impls.as_ref().expect("`all_trait_impls` are already borrowed"));
+ self.resolver_caches.all_trait_impls = all_trait_impls;
+ }
}
/// Creates a new diagnostic `Handler` that can be used to emit warnings and errors.
}
}
-crate fn create_resolver<'a>(
- externs: config::Externs,
- queries: &Queries<'a>,
- sess: &Session,
-) -> Rc<RefCell<interface::BoxedResolver>> {
- let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
- let resolver = resolver.clone();
-
- let resolver = crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate);
-
- // FIXME: somehow rustdoc is still missing crates even though we loaded all
- // the known necessary crates. Load them all unconditionally until we find a way to fix this.
- // DO NOT REMOVE THIS without first testing on the reproducer in
- // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
- let extern_names: Vec<String> = externs
- .iter()
- .filter(|(_, entry)| entry.add_prelude)
- .map(|(name, _)| name)
- .cloned()
- .collect();
- resolver.borrow_mut().access(|resolver| {
- sess.time("load_extern_crates", || {
- for extern_name in &extern_names {
- debug!("loading extern crate {}", extern_name);
- if let Err(()) = resolver
- .resolve_str_path_error(
- DUMMY_SP,
- extern_name,
- TypeNS,
- LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(),
- ) {
- warn!("unable to resolve external crate {} (do you have an unused `--extern` crate?)", extern_name)
- }
- }
- });
- });
-
- resolver
-}
-
crate fn run_global_ctxt(
tcx: TyCtxt<'_>,
resolver: Rc<RefCell<interface::BoxedResolver>>,
+ resolver_caches: ResolverCaches,
show_coverage: bool,
render_options: RenderOptions,
output_format: OutputFormat,
});
rustc_passes::stability::check_unused_or_stable_features(tcx);
+ let auto_traits = resolver_caches
+ .all_traits
+ .as_ref()
+ .expect("`all_traits` are already borrowed")
+ .iter()
+ .copied()
+ .filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id))
+ .collect();
let access_levels = AccessLevels {
map: tcx.privacy_access_levels(()).map.iter().map(|(k, v)| (k.to_def_id(), *v)).collect(),
};
let mut ctxt = DocContext {
tcx,
resolver,
+ resolver_caches,
param_env: ParamEnv::empty(),
external_traits: Default::default(),
active_extern_traits: Default::default(),
substs: Default::default(),
impl_trait_bounds: Default::default(),
generated_synthetics: Default::default(),
- auto_traits: tcx
- .all_traits()
- .filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id))
- .collect(),
+ auto_traits,
module_trait_cache: FxHashMap::default(),
cache: Cache::new(access_levels, render_options.document_private),
inlined: FxHashSet::default(),
use rustc_session::{early_error, early_warn};
use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL;
+use crate::passes::collect_intra_doc_links;
/// A macro to create a FxHashMap.
///
// We need to hold on to the complete resolver, so we cause everything to be
// cloned for the analysis passes to use. Suboptimal, but necessary in the
// current architecture.
- let resolver = core::create_resolver(externs, queries, sess);
+ // FIXME(#83761): Resolver cloning can lead to inconsistencies between data in the
+ // two copies because one of the copies can be modified after `TyCtxt` construction.
+ let (resolver, resolver_caches) = {
+ let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
+ let resolver_caches = resolver.borrow_mut().access(|resolver| {
+ collect_intra_doc_links::early_resolve_intra_doc_links(resolver, krate, externs)
+ });
+ (resolver.clone(), resolver_caches)
+ };
if sess.diagnostic().has_errors_or_lint_errors() {
sess.fatal("Compilation failed, aborting rustdoc");
core::run_global_ctxt(
tcx,
resolver,
+ resolver_caches,
show_coverage,
render_options,
output_format,
use crate::visit::DocVisitor;
mod early;
-crate use early::load_intra_link_crates;
+crate use early::early_resolve_intra_doc_links;
crate const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
name: "collect-intra-doc-links",
-use ast::visit;
-use rustc_ast as ast;
+use crate::clean;
+use crate::core::ResolverCaches;
+use crate::html::markdown::markdown_links;
+use crate::passes::collect_intra_doc_links::preprocess_link;
+
+use rustc_ast::visit::{self, AssocCtxt, Visitor};
+use rustc_ast::{self as ast, ItemKind};
+use rustc_ast_lowering::ResolverAstLowering;
use rustc_hir::def::Namespace::TypeNS;
-use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
-use rustc_interface::interface;
-use rustc_span::Span;
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_resolve::Resolver;
+use rustc_session::config::Externs;
+use rustc_span::{Span, DUMMY_SP};
-use std::cell::RefCell;
use std::mem;
-use std::rc::Rc;
-
-type Resolver = Rc<RefCell<interface::BoxedResolver>>;
-// Letting the resolver escape at the end of the function leads to inconsistencies between the
-// crates the TyCtxt sees and the resolver sees (because the resolver could load more crates
-// after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ...
-crate fn load_intra_link_crates(resolver: Resolver, krate: &ast::Crate) -> Resolver {
- let mut loader = IntraLinkCrateLoader { current_mod: CRATE_DEF_ID, resolver };
- // `walk_crate` doesn't visit the crate itself for some reason.
+
+crate fn early_resolve_intra_doc_links(
+ resolver: &mut Resolver<'_>,
+ krate: &ast::Crate,
+ externs: Externs,
+) -> ResolverCaches {
+ let mut loader = IntraLinkCrateLoader {
+ resolver,
+ current_mod: CRATE_DEF_ID,
+ all_traits: Default::default(),
+ all_trait_impls: Default::default(),
+ };
+
+ // Overridden `visit_item` below doesn't apply to the crate root,
+ // so we have to visit its attributes and exports separately.
loader.load_links_in_attrs(&krate.attrs, krate.span);
visit::walk_crate(&mut loader, krate);
- loader.resolver
+ loader.fill_resolver_caches();
+
+ // FIXME: somehow rustdoc is still missing crates even though we loaded all
+ // the known necessary crates. Load them all unconditionally until we find a way to fix this.
+ // DO NOT REMOVE THIS without first testing on the reproducer in
+ // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
+ for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) {
+ let _ = loader.resolver.resolve_str_path_error(
+ DUMMY_SP,
+ extern_name,
+ TypeNS,
+ CRATE_DEF_ID.to_def_id(),
+ );
+ }
+
+ ResolverCaches {
+ all_traits: Some(loader.all_traits),
+ all_trait_impls: Some(loader.all_trait_impls),
+ }
}
-struct IntraLinkCrateLoader {
+struct IntraLinkCrateLoader<'r, 'ra> {
+ resolver: &'r mut Resolver<'ra>,
current_mod: LocalDefId,
- resolver: Rc<RefCell<interface::BoxedResolver>>,
+ all_traits: Vec<DefId>,
+ all_trait_impls: Vec<DefId>,
}
-impl IntraLinkCrateLoader {
- fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
- use crate::html::markdown::markdown_links;
- use crate::passes::collect_intra_doc_links::preprocess_link;
+impl IntraLinkCrateLoader<'_, '_> {
+ fn fill_resolver_caches(&mut self) {
+ for cnum in self.resolver.cstore().crates_untracked() {
+ let all_traits = self.resolver.cstore().traits_in_crate_untracked(cnum);
+ let all_trait_impls = self.resolver.cstore().trait_impls_in_crate_untracked(cnum);
- // FIXME: this probably needs to consider inlining
- let attrs = crate::clean::Attributes::from_ast(attrs, None);
+ self.all_traits.extend(all_traits);
+ self.all_trait_impls.extend(all_trait_impls.into_iter().map(|(def_id, _)| def_id));
+ }
+ }
+
+ fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
+ // FIXME: this needs to consider export inlining.
+ let attrs = clean::Attributes::from_ast(attrs, None);
for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() {
- debug!(?doc);
- for link in markdown_links(doc.as_str()) {
- debug!(?link.link);
+ let module_id = parent_module.unwrap_or(self.current_mod.to_def_id());
+
+ for link in markdown_links(&doc.as_str()) {
let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
x.path_str
} else {
continue;
};
- self.resolver.borrow_mut().access(|resolver| {
- let _ = resolver.resolve_str_path_error(
- span,
- &path_str,
- TypeNS,
- parent_module.unwrap_or_else(|| self.current_mod.to_def_id()),
- );
- });
+ let _ = self.resolver.resolve_str_path_error(span, &path_str, TypeNS, module_id);
}
}
}
}
-impl visit::Visitor<'_> for IntraLinkCrateLoader {
- fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
- self.load_links_in_attrs(&item.attrs, item.span);
- visit::walk_foreign_item(self, item)
- }
-
+impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> {
fn visit_item(&mut self, item: &ast::Item) {
- use rustc_ast_lowering::ResolverAstLowering;
-
- if let ast::ItemKind::Mod(..) = item.kind {
- let new_mod =
- self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id));
- let old_mod = mem::replace(&mut self.current_mod, new_mod);
+ if let ItemKind::Mod(..) = item.kind {
+ let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id));
self.load_links_in_attrs(&item.attrs, item.span);
visit::walk_item(self, item);
self.current_mod = old_mod;
} else {
+ match item.kind {
+ ItemKind::Trait(..) => {
+ self.all_traits.push(self.resolver.local_def_id(item.id).to_def_id());
+ }
+ ItemKind::Impl(box ast::Impl { of_trait: Some(..), .. }) => {
+ self.all_trait_impls.push(self.resolver.local_def_id(item.id).to_def_id());
+ }
+ _ => {}
+ }
self.load_links_in_attrs(&item.attrs, item.span);
visit::walk_item(self, item);
}
}
- // NOTE: if doc-comments are ever allowed on function parameters, this will have to implement `visit_param` too.
-
- fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: visit::AssocCtxt) {
+ fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: AssocCtxt) {
self.load_links_in_attrs(&item.attrs, item.span);
visit::walk_assoc_item(self, item, ctxt)
}
- fn visit_field_def(&mut self, field: &ast::FieldDef) {
- self.load_links_in_attrs(&field.attrs, field.span);
- visit::walk_field_def(self, field)
+ fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
+ self.load_links_in_attrs(&item.attrs, item.span);
+ visit::walk_foreign_item(self, item)
}
fn visit_variant(&mut self, v: &ast::Variant) {
self.load_links_in_attrs(&v.attrs, v.span);
visit::walk_variant(self, v)
}
+
+ fn visit_field_def(&mut self, field: &ast::FieldDef) {
+ self.load_links_in_attrs(&field.attrs, field.span);
+ visit::walk_field_def(self, field)
+ }
+
+ // NOTE: if doc-comments are ever allowed on other nodes (e.g. function parameters),
+ // then this will have to implement other visitor methods too.
}
let mut new_items = Vec::new();
- for &cnum in cx.tcx.crates(()).iter() {
- for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() {
- inline::build_impl(cx, None, did, None, &mut new_items);
+ // External trait impls.
+ cx.with_all_trait_impls(|cx, all_trait_impls| {
+ let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls");
+ for &impl_def_id in all_trait_impls.iter().skip_while(|def_id| def_id.is_local()) {
+ inline::build_impl(cx, None, impl_def_id, None, &mut new_items);
}
- }
+ });
// Also try to inline primitive impls from other crates.
- for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
- if !def_id.is_local() {
- cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
+ cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
+ for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
+ if !def_id.is_local() {
inline::build_impl(cx, None, def_id, None, &mut new_items);
// FIXME(eddyb) is this `doc(hidden)` check needed?
let impls = get_auto_trait_and_blanket_impls(cx, def_id);
new_items.extend(impls.filter(|i| cx.inlined.insert(i.def_id)));
}
- });
+ }
}
- }
+ });
let mut cleaner = BadImplStripper { prims, items: crate_items };
let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
}
});
- // `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
- let mut extra_attrs = Vec::new();
- for trait_did in cx.tcx.all_traits() {
- for &impl_did in cx.tcx.hir().trait_impls(trait_did) {
- let impl_did = impl_did.to_def_id();
- cx.tcx.sess.prof.generic_activity("build_local_trait_impl").run(|| {
- let mut parent = cx.tcx.parent(impl_did);
- while let Some(did) = parent {
- extra_attrs.extend(
- cx.tcx
- .get_attrs(did)
- .iter()
- .filter(|attr| attr.has_name(sym::doc))
- .filter(|attr| {
- if let Some([attr]) = attr.meta_item_list().as_deref() {
- attr.has_name(sym::cfg)
- } else {
- false
- }
- })
- .cloned(),
- );
- parent = cx.tcx.parent(did);
- }
- inline::build_impl(cx, None, impl_did, Some(&extra_attrs), &mut new_items);
- extra_attrs.clear();
- });
+ // Local trait impls.
+ cx.with_all_trait_impls(|cx, all_trait_impls| {
+ let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls");
+ let mut attr_buf = Vec::new();
+ for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) {
+ let mut parent = cx.tcx.parent(impl_def_id);
+ while let Some(did) = parent {
+ attr_buf.extend(
+ cx.tcx
+ .get_attrs(did)
+ .iter()
+ .filter(|attr| attr.has_name(sym::doc))
+ .filter(|attr| {
+ if let Some([attr]) = attr.meta_item_list().as_deref() {
+ attr.has_name(sym::cfg)
+ } else {
+ false
+ }
+ })
+ .cloned(),
+ );
+ parent = cx.tcx.parent(did);
+ }
+ inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items);
+ attr_buf.clear();
}
- }
+ });
if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind {
items.extend(synth_impls);