about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-11-11 22:00:53 +0000
committerbors <bors@rust-lang.org>2021-11-11 22:00:53 +0000
commit14a2fd640e0df9ee8cc1e04280b0c3aff93c42da (patch)
treeff33ab007794af4108e4a330702c16093cbd3a27
parent936238a92b2f9d6e7afe7dda69b4afd903f96399 (diff)
parent51345a83aaa99d1ec1a64e09c4e3280051e9cfa2 (diff)
downloadrust-14a2fd640e0df9ee8cc1e04280b0c3aff93c42da.tar.gz
rust-14a2fd640e0df9ee8cc1e04280b0c3aff93c42da.zip
Auto merge of #90489 - jyn514:load-all-extern-crates, r=petrochenkov
rustdoc: Go back to loading all external crates unconditionally

This *continues* to cause regressions. This code will be unnecessary
once access to the resolver happens fully before creating the tyctxt
(#83761), so load all crates unconditionally for now. To minimize churn, this leaves in the code for loading crates selectively.

"Fixes" https://github.com/rust-lang/rust/issues/84738. Previously: https://github.com/rust-lang/rust/pull/83738, https://github.com/rust-lang/rust/pull/85749, https://github.com/rust-lang/rust/pull/88215

r? `@petrochenkov` cc `@camelid` (this should fix the "index out of bounds" error you had while looking up `crate_name`).
-rw-r--r--src/librustdoc/core.rs36
-rw-r--r--src/librustdoc/lib.rs3
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links/early.rs31
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs1
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs1
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs1
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs1
-rw-r--r--src/test/rustdoc-ui/intra-doc/extern-crate-load.rs26
8 files changed, 93 insertions, 7 deletions
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 92278179a51..a331f4cf3e6 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -16,13 +16,15 @@ 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;
+use rustc_span::{Span, DUMMY_SP};
 
 use std::cell::RefCell;
 use std::lazy::SyncLazy;
@@ -283,13 +285,43 @@ crate fn create_config(
 }
 
 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();
 
-    crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate)
+    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(
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index fb252a9c739..1c12cc547e0 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -756,6 +756,7 @@ fn main_options(options: config::Options) -> MainResult {
     let default_passes = options.default_passes;
     let output_format = options.output_format;
     // FIXME: fix this clone (especially render_options)
+    let externs = options.externs.clone();
     let manual_passes = options.manual_passes.clone();
     let render_options = options.render_options.clone();
     let scrape_examples_options = options.scrape_examples_options.clone();
@@ -774,7 +775,7 @@ fn main_options(options: config::Options) -> MainResult {
             // 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(queries, sess);
+            let resolver = core::create_resolver(externs, queries, sess);
 
             if sess.diagnostic().has_errors_or_lint_errors() {
                 sess.fatal("Compilation failed, aborting rustdoc");
diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs
index 565bcb8bd13..4cebf741e20 100644
--- a/src/librustdoc/passes/collect_intra_doc_links/early.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs
@@ -1,3 +1,4 @@
+use ast::visit;
 use rustc_ast as ast;
 use rustc_hir::def::Namespace::TypeNS;
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@@ -16,7 +17,7 @@ crate fn load_intra_link_crates(resolver: Resolver, krate: &ast::Crate) -> Resol
     let mut loader = IntraLinkCrateLoader { current_mod: CRATE_DEF_ID, resolver };
     // `walk_crate` doesn't visit the crate itself for some reason.
     loader.load_links_in_attrs(&krate.attrs, krate.span);
-    ast::visit::walk_crate(&mut loader, krate);
+    visit::walk_crate(&mut loader, krate);
     loader.resolver
 }
 
@@ -54,7 +55,12 @@ impl IntraLinkCrateLoader {
     }
 }
 
-impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
+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)
+    }
+
     fn visit_item(&mut self, item: &ast::Item) {
         use rustc_ast_lowering::ResolverAstLowering;
 
@@ -64,12 +70,29 @@ impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
             let old_mod = mem::replace(&mut self.current_mod, new_mod);
 
             self.load_links_in_attrs(&item.attrs, item.span);
-            ast::visit::walk_item(self, item);
+            visit::walk_item(self, item);
 
             self.current_mod = old_mod;
         } else {
             self.load_links_in_attrs(&item.attrs, item.span);
-            ast::visit::walk_item(self, item);
+            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) {
+        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_variant(&mut self, v: &ast::Variant) {
+        self.load_links_in_attrs(&v.attrs, v.span);
+        visit::walk_variant(self, v)
+    }
 }
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs
new file mode 100644
index 00000000000..d11c69f812a
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs
new file mode 100644
index 00000000000..d11c69f812a
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs
new file mode 100644
index 00000000000..d11c69f812a
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs
new file mode 100644
index 00000000000..d11c69f812a
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs b/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs
new file mode 100644
index 00000000000..438c56aa516
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs
@@ -0,0 +1,26 @@
+// check-pass
+// aux-crate:dep1=dep1.rs
+// aux-crate:dep2=dep2.rs
+// aux-crate:dep3=dep3.rs
+// aux-crate:dep4=dep4.rs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub trait Trait {
+    /// [dep1]
+    type Item;
+}
+
+pub struct S {
+    /// [dep2]
+    pub x: usize,
+}
+
+extern "C" {
+    /// [dep3]
+    pub fn printf();
+}
+
+pub enum E {
+    /// [dep4]
+    A
+}