From 5f0c54db4e595a6a77048f2b0605138ffa49a326 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Thu, 27 May 2021 16:06:30 +0200
Subject: [PATCH] Revert "Don't load all extern crates unconditionally"

---
 src/librustdoc/core.rs                        | 43 ++++++++++---
 src/librustdoc/lib.rs                         |  4 +-
 .../passes/collect_intra_doc_links.rs         |  3 -
 .../passes/collect_intra_doc_links/early.rs   | 63 -------------------
 src/librustdoc/passes/mod.rs                  |  2 +-
 src/test/rustdoc-ui/auxiliary/panic-item.rs   | 17 -----
 src/test/rustdoc-ui/unused-extern-crate.rs    |  3 -
 src/test/rustdoc/auxiliary/issue-66159-1.rs   |  2 +
 src/test/rustdoc/issue-66159.rs               | 10 +++
 9 files changed, 49 insertions(+), 98 deletions(-)
 delete mode 100644 src/librustdoc/passes/collect_intra_doc_links/early.rs
 delete mode 100644 src/test/rustdoc-ui/auxiliary/panic-item.rs
 delete mode 100644 src/test/rustdoc-ui/unused-extern-crate.rs
 create mode 100644 src/test/rustdoc/auxiliary/issue-66159-1.rs
 create mode 100644 src/test/rustdoc/issue-66159.rs

diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 71fcde8bca89f..66f4f48129269 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -1,12 +1,12 @@
-use rustc_ast as ast;
 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::Namespace::TypeNS;
 use rustc_hir::def::Res;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::HirId;
 use rustc_hir::{
     intravisit::{self, NestedVisitorMap, Visitor},
@@ -23,7 +23,7 @@ use rustc_session::DiagnosticOutput;
 use rustc_session::Session;
 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::mem;
@@ -300,16 +300,41 @@ 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();
-
-    let mut loader = crate::passes::collect_intra_doc_links::IntraLinkCrateLoader::new(resolver);
-    ast::visit::walk_crate(&mut loader, krate);
+    let extern_names: Vec<String> = externs
+        .iter()
+        .filter(|(_, entry)| entry.add_prelude)
+        .map(|(name, _)| name)
+        .cloned()
+        .collect();
+
+    let (_, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
+
+    // Before we actually clone it, let's force all the extern'd crates to
+    // actually be loaded, just in case they're only referred to inside
+    // intra-doc links
+    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)
+                  }
+            }
+        });
+    });
 
-    loader.resolver
+    // Now we're good to clone the resolver because everything should be loaded
+    resolver.clone()
 }
 
 crate fn run_global_ctxt(
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index ee7a716655bd2..64a9905b33f15 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -31,7 +31,6 @@ extern crate tracing;
 // Dependencies listed in Cargo.toml do not need `extern crate`.
 
 extern crate rustc_ast;
-extern crate rustc_ast_lowering;
 extern crate rustc_ast_pretty;
 extern crate rustc_attr;
 extern crate rustc_data_structures;
@@ -714,6 +713,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 config = core::create_config(options);
@@ -731,7 +731,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.has_errors() {
                 sess.fatal("Compilation failed, aborting rustdoc");
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index c7e2ce7401913..1113d61012852 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -37,9 +37,6 @@ use crate::html::markdown::{markdown_links, MarkdownLink};
 use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
 use crate::passes::Pass;
 
-mod early;
-crate use early::IntraLinkCrateLoader;
-
 crate const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
     name: "collect-intra-doc-links",
     run: collect_intra_doc_links,
diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs
deleted file mode 100644
index 7cba2523d1a3b..0000000000000
--- a/src/librustdoc/passes/collect_intra_doc_links/early.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-use rustc_ast as ast;
-use rustc_hir::def::Namespace::TypeNS;
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
-use rustc_interface::interface;
-
-use std::cell::RefCell;
-use std::mem;
-use std::rc::Rc;
-
-// 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 struct IntraLinkCrateLoader {
-    current_mod: DefId,
-    crate resolver: Rc<RefCell<interface::BoxedResolver>>,
-}
-
-impl IntraLinkCrateLoader {
-    crate fn new(resolver: Rc<RefCell<interface::BoxedResolver>>) -> Self {
-        let crate_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id();
-        Self { current_mod: crate_id, resolver }
-    }
-}
-
-impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
-    fn visit_attribute(&mut self, attr: &ast::Attribute) {
-        use crate::html::markdown::markdown_links;
-        use crate::passes::collect_intra_doc_links::preprocess_link;
-
-        if let Some(doc) = attr.doc_str() {
-            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(
-                        attr.span,
-                        &path_str,
-                        TypeNS,
-                        self.current_mod,
-                    );
-                });
-            }
-        }
-        ast::visit::walk_attribute(self, attr);
-    }
-
-    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.to_def_id());
-            ast::visit::walk_item(self, item);
-            self.current_mod = old_mod;
-        } else {
-            ast::visit::walk_item(self, item);
-        }
-    }
-}
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 0e86fe45640f8..390ab1694a05b 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -30,7 +30,7 @@ crate use self::unindent_comments::UNINDENT_COMMENTS;
 mod propagate_doc_cfg;
 crate use self::propagate_doc_cfg::PROPAGATE_DOC_CFG;
 
-crate mod collect_intra_doc_links;
+mod collect_intra_doc_links;
 crate use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS;
 
 mod doc_test_lints;
diff --git a/src/test/rustdoc-ui/auxiliary/panic-item.rs b/src/test/rustdoc-ui/auxiliary/panic-item.rs
deleted file mode 100644
index 17b26850d4d25..0000000000000
--- a/src/test/rustdoc-ui/auxiliary/panic-item.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// no-prefer-dynamic
-#![crate_type = "lib"]
-#![no_std]
-#![feature(lang_items)]
-
-use core::panic::PanicInfo;
-use core::sync::atomic::{self, Ordering};
-
-#[panic_handler]
-fn panic(_info: &PanicInfo) -> ! {
-    loop {
-        atomic::compiler_fence(Ordering::SeqCst);
-    }
-}
-
-#[lang = "eh_personality"]
-fn foo() {}
diff --git a/src/test/rustdoc-ui/unused-extern-crate.rs b/src/test/rustdoc-ui/unused-extern-crate.rs
deleted file mode 100644
index f703a18379074..0000000000000
--- a/src/test/rustdoc-ui/unused-extern-crate.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-// check-pass
-// aux-crate:panic_item=panic-item.rs
-// @has unused_extern_crate/index.html
diff --git a/src/test/rustdoc/auxiliary/issue-66159-1.rs b/src/test/rustdoc/auxiliary/issue-66159-1.rs
new file mode 100644
index 0000000000000..2f3d069bd51c3
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-66159-1.rs
@@ -0,0 +1,2 @@
+/// This will be referred to by the test docstring
+pub struct Something;
diff --git a/src/test/rustdoc/issue-66159.rs b/src/test/rustdoc/issue-66159.rs
new file mode 100644
index 0000000000000..003d079a470c0
--- /dev/null
+++ b/src/test/rustdoc/issue-66159.rs
@@ -0,0 +1,10 @@
+// aux-crate:priv:issue_66159_1=issue-66159-1.rs
+// compile-flags:-Z unstable-options
+
+// The issue was an ICE which meant that we never actually generated the docs
+// so if we have generated the docs, we're okay.
+// Since we don't generate the docs for the auxiliary files, we can't actually
+// verify that the struct is linked correctly.
+
+// @has issue_66159/index.html
+//! [issue_66159_1::Something]