about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-07-02 11:42:38 +0000
committerbors <bors@rust-lang.org>2021-07-02 11:42:38 +0000
commitce331ee6ee010438d1a58c7da8ced4f26d69a20e (patch)
treedbe87a9389300b43acff319a3b312623a0f8e921
parentf9fa13f705bb8b1c57c6b6fe95055ec4995a40f0 (diff)
parentcd3a48fdb650f6ce7c6c8a31d2136073fc3338f5 (diff)
downloadrust-ce331ee6ee010438d1a58c7da8ced4f26d69a20e.tar.gz
rust-ce331ee6ee010438d1a58c7da8ced4f26d69a20e.zip
Auto merge of #86806 - GuillaumeGomez:rollup-pr5r37w, r=GuillaumeGomez
Rollup of 5 pull requests

Successful merges:

 - #85749 (Revert "Don't load all extern crates unconditionally")
 - #86714 (Add linked list cursor end methods)
 - #86737 (Document rustfmt on nightly-rustc)
 - #86776 (Skip layout query when computing integer type size during mangling)
 - #86797 (Stabilize `Bound::cloned()`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs10
-rw-r--r--library/alloc/src/collections/linked_list.rs143
-rw-r--r--library/alloc/src/collections/linked_list/tests.rs47
-rw-r--r--library/core/src/ops/range.rs3
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/proc_macro/src/lib.rs1
-rw-r--r--src/bootstrap/builder.rs1
-rw-r--r--src/bootstrap/doc.rs147
-rw-r--r--src/librustdoc/core.rs43
-rw-r--r--src/librustdoc/lib.rs4
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs3
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links/early.rs63
-rw-r--r--src/librustdoc/passes/mod.rs2
-rw-r--r--src/test/rustdoc-ui/auxiliary/panic-item.rs17
-rw-r--r--src/test/rustdoc-ui/unused-extern-crate.rs3
-rw-r--r--src/test/rustdoc/auxiliary/issue-66159-1.rs2
-rw-r--r--src/test/rustdoc/issue-66159.rs10
-rw-r--r--src/tools/rustfmt/src/lib.rs1
18 files changed, 327 insertions, 174 deletions
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 828f1ac0a79..1a9d04a75ec 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -3,9 +3,11 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::print::{Print, Printer};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
 use rustc_middle::ty::{self, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
+use rustc_target::abi::Integer;
 use rustc_target::spec::abi::Abi;
 
 use std::fmt::Write;
@@ -553,11 +555,9 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
             ty::Uint(_) | ty::Bool | ty::Char => {
                 ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty)
             }
-            ty::Int(_) => {
-                let param_env = ty::ParamEnv::reveal_all();
-                ct.try_eval_bits(self.tcx, param_env, ct.ty).and_then(|b| {
-                    let sz = self.tcx.layout_of(param_env.and(ct.ty)).ok()?.size;
-                    let val = sz.sign_extend(b) as i128;
+            ty::Int(ity) => {
+                ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty).and_then(|b| {
+                    let val = Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(b) as i128;
                     if val < 0 {
                         neg = true;
                     }
diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs
index 1a58ad51f78..ea216786ea2 100644
--- a/library/alloc/src/collections/linked_list.rs
+++ b/library/alloc/src/collections/linked_list.rs
@@ -1243,6 +1243,20 @@ impl<'a, T> Cursor<'a, T> {
             prev.map(|prev| &(*prev.as_ptr()).element)
         }
     }
+
+    /// Provides a reference to the front element of the cursor's parent list,
+    /// or None if the list is empty.
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn front(&self) -> Option<&'a T> {
+        self.list.front()
+    }
+
+    /// Provides a reference to the back element of the cursor's parent list,
+    /// or None if the list is empty.
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn back(&self) -> Option<&'a T> {
+        self.list.back()
+    }
 }
 
 impl<'a, T> CursorMut<'a, T> {
@@ -1506,6 +1520,135 @@ impl<'a, T> CursorMut<'a, T> {
         self.index = 0;
         unsafe { self.list.split_off_before_node(self.current, split_off_idx) }
     }
+
+    /// Appends an element to the front of the cursor's parent list. The node
+    /// that the cursor points to is unchanged, even if it is the "ghost" node.
+    ///
+    /// This operation should compute in O(1) time.
+    // `push_front` continues to point to "ghost" when it addes a node to mimic
+    // the behavior of `insert_before` on an empty list.
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn push_front(&mut self, elt: T) {
+        // Safety: We know that `push_front` does not change the position in
+        // memory of other nodes. This ensures that `self.current` remains
+        // valid.
+        self.list.push_front(elt);
+        self.index += 1;
+    }
+
+    /// Appends an element to the back of the cursor's parent list. The node
+    /// that the cursor points to is unchanged, even if it is the "ghost" node.
+    ///
+    /// This operation should compute in O(1) time.
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn push_back(&mut self, elt: T) {
+        // Safety: We know that `push_back` does not change the position in
+        // memory of other nodes. This ensures that `self.current` remains
+        // valid.
+        self.list.push_back(elt);
+        if self.current().is_none() {
+            // The index of "ghost" is the length of the list, so we just need
+            // to increment self.index to reflect the new length of the list.
+            self.index += 1;
+        }
+    }
+
+    /// Removes the first element from the cursor's parent list and returns it,
+    /// or None if the list is empty. The element the cursor points to remains
+    /// unchanged, unless it was pointing to the front element. In that case, it
+    /// points to the new front element.
+    ///
+    /// This operation should compute in O(1) time.
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn pop_front(&mut self) -> Option<T> {
+        // We can't check if current is empty, we must check the list directly.
+        // It is possible for `self.current == None` and the list to be
+        // non-empty.
+        if self.list.is_empty() {
+            None
+        } else {
+            // We can't point to the node that we pop. Copying the behavior of
+            // `remove_current`, we move on the the next node in the sequence.
+            // If the list is of length 1 then we end pointing to the "ghost"
+            // node at index 0, which is expected.
+            if self.list.head == self.current {
+                self.move_next();
+            } else {
+                self.index -= 1;
+            }
+            self.list.pop_front()
+        }
+    }
+
+    /// Removes the last element from the cursor's parent list and returns it,
+    /// or None if the list is empty. The element the cursor points to remains
+    /// unchanged, unless it was pointing to the back element. In that case, it
+    /// points to the "ghost" element.
+    ///
+    /// This operation should compute in O(1) time.
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn pop_back(&mut self) -> Option<T> {
+        if self.list.is_empty() {
+            None
+        } else {
+            if self.list.tail == self.current {
+                // The index now reflects the length of the list. It was the
+                // length of the list minus 1, but now the list is 1 smaller. No
+                // change is needed for `index`.
+                self.current = None;
+            } else if self.current.is_none() {
+                self.index = self.list.len - 1;
+            }
+            self.list.pop_back()
+        }
+    }
+
+    /// Provides a reference to the front element of the cursor's parent list,
+    /// or None if the list is empty.
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn front(&self) -> Option<&T> {
+        self.list.front()
+    }
+
+    /// Provides a mutable reference to the front element of the cursor's
+    /// parent list, or None if the list is empty.
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn front_mut(&mut self) -> Option<&mut T> {
+        self.list.front_mut()
+    }
+
+    /// Provides a reference to the back element of the cursor's parent list,
+    /// or None if the list is empty.
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn back(&self) -> Option<&T> {
+        self.list.back()
+    }
+
+    /// Provides a mutable reference to back element of the cursor's parent
+    /// list, or `None` if the list is empty.
+    ///
+    /// # Examples
+    /// Building and mutating a list with a cursor, then getting the back element:
+    /// ```
+    /// #![feature(linked_list_cursors)]
+    /// use std::collections::LinkedList;
+    /// let mut dl = LinkedList::new();
+    /// dl.push_front(3);
+    /// dl.push_front(2);
+    /// dl.push_front(1);
+    /// let mut cursor = dl.cursor_front_mut();
+    /// *cursor.current().unwrap() = 99;
+    /// *cursor.back_mut().unwrap() = 0;
+    /// let mut contents = dl.into_iter();
+    /// assert_eq!(contents.next(), Some(99));
+    /// assert_eq!(contents.next(), Some(2));
+    /// assert_eq!(contents.next(), Some(0));
+    /// assert_eq!(contents.next(), None);
+    /// ```
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn back_mut(&mut self) -> Option<&mut T> {
+        self.list.back_mut()
+    }
 }
 
 /// An iterator produced by calling `drain_filter` on LinkedList.
diff --git a/library/alloc/src/collections/linked_list/tests.rs b/library/alloc/src/collections/linked_list/tests.rs
index ad643a7bdf1..5a65ed7a962 100644
--- a/library/alloc/src/collections/linked_list/tests.rs
+++ b/library/alloc/src/collections/linked_list/tests.rs
@@ -428,3 +428,50 @@ fn test_cursor_mut_insert() {
     check_links(&m);
     assert_eq!(m.iter().cloned().collect::<Vec<_>>(), &[200, 201, 202, 203, 1, 100, 101]);
 }
+
+#[test]
+fn test_cursor_push_front_back() {
+    let mut ll: LinkedList<u32> = LinkedList::new();
+    ll.extend(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+    let mut c = ll.cursor_front_mut();
+    assert_eq!(c.current(), Some(&mut 1));
+    assert_eq!(c.index(), Some(0));
+    c.push_front(0);
+    assert_eq!(c.current(), Some(&mut 1));
+    assert_eq!(c.peek_prev(), Some(&mut 0));
+    assert_eq!(c.index(), Some(1));
+    c.push_back(11);
+    drop(c);
+    let p = ll.cursor_back().front().unwrap();
+    assert_eq!(p, &0);
+    assert_eq!(ll, (0..12).collect());
+    check_links(&ll);
+}
+
+#[test]
+fn test_cursor_pop_front_back() {
+    let mut ll: LinkedList<u32> = LinkedList::new();
+    ll.extend(&[1, 2, 3, 4, 5, 6]);
+    let mut c = ll.cursor_back_mut();
+    assert_eq!(c.pop_front(), Some(1));
+    c.move_prev();
+    c.move_prev();
+    c.move_prev();
+    assert_eq!(c.pop_back(), Some(6));
+    let c = c.as_cursor();
+    assert_eq!(c.front(), Some(&2));
+    assert_eq!(c.back(), Some(&5));
+    assert_eq!(c.index(), Some(1));
+    drop(c);
+    assert_eq!(ll, (2..6).collect());
+    check_links(&ll);
+    let mut c = ll.cursor_back_mut();
+    assert_eq!(c.current(), Some(&mut 5));
+    assert_eq!(c.index, 3);
+    assert_eq!(c.pop_back(), Some(5));
+    assert_eq!(c.current(), None);
+    assert_eq!(c.index, 3);
+    assert_eq!(c.pop_back(), Some(4));
+    assert_eq!(c.current(), None);
+    assert_eq!(c.index, 2);
+}
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index bb948376bc7..9bf0382312e 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -737,14 +737,13 @@ impl<T: Clone> Bound<&T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(bound_cloned)]
     /// use std::ops::Bound::*;
     /// use std::ops::RangeBounds;
     ///
     /// assert_eq!((1..12).start_bound(), Included(&1));
     /// assert_eq!((1..12).start_bound().cloned(), Included(1));
     /// ```
-    #[unstable(feature = "bound_cloned", issue = "61356")]
+    #[stable(feature = "bound_cloned", since = "1.55.0")]
     pub fn cloned(self) -> Bound<T> {
         match self {
             Bound::Unbounded => Bound::Unbounded,
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 56af3848584..dee2478886d 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -4,7 +4,6 @@
 #![feature(array_map)]
 #![feature(array_windows)]
 #![feature(bool_to_option)]
-#![feature(bound_cloned)]
 #![feature(box_syntax)]
 #![feature(cell_update)]
 #![feature(cfg_panic)]
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 7586229504c..9b155db6d7b 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -31,7 +31,6 @@
 #![feature(restricted_std)]
 #![feature(rustc_attrs)]
 #![feature(min_specialization)]
-#![feature(bound_cloned)]
 #![recursion_limit = "256"]
 
 #[unstable(feature = "proc_macro_internals", issue = "27812")]
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index b4c5a2abc9c..56ecc6e68a9 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -465,6 +465,7 @@ impl<'a> Builder<'a> {
                 doc::Std,
                 doc::Rustc,
                 doc::Rustdoc,
+                doc::Rustfmt,
                 doc::ErrorIndex,
                 doc::Nomicon,
                 doc::Reference,
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 634332df863..8603361362c 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -593,84 +593,97 @@ impl Step for Rustc {
     }
 }
 
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub struct Rustdoc {
-    stage: u32,
-    target: TargetSelection,
-}
-
-impl Step for Rustdoc {
-    type Output = ();
-    const DEFAULT: bool = true;
-    const ONLY_HOSTS: bool = true;
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.krate("rustdoc-tool")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(Rustdoc { stage: run.builder.top_stage, target: run.target });
-    }
-
-    /// Generates compiler documentation.
-    ///
-    /// This will generate all documentation for compiler and dependencies.
-    /// Compiler documentation is distributed separately, so we make sure
-    /// we do not merge it with the other documentation from std, test and
-    /// proc_macros. This is largely just a wrapper around `cargo doc`.
-    fn run(self, builder: &Builder<'_>) {
-        let stage = self.stage;
-        let target = self.target;
-        builder.info(&format!("Documenting stage{} rustdoc ({})", stage, target));
-
-        // This is the intended out directory for compiler documentation.
-        let out = builder.compiler_doc_out(target);
-        t!(fs::create_dir_all(&out));
+macro_rules! tool_doc {
+    ($tool: ident, $should_run: literal, $path: literal, [$($krate: literal),+ $(,)?] $(, binary=$bin:expr)?) => {
+        #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+        pub struct $tool {
+            stage: u32,
+            target: TargetSelection,
+        }
 
-        let compiler = builder.compiler(stage, builder.config.build);
+        impl Step for $tool {
+            type Output = ();
+            const DEFAULT: bool = true;
+            const ONLY_HOSTS: bool = true;
 
-        if !builder.config.compiler_docs {
-            builder.info("\tskipping - compiler/librustdoc docs disabled");
-            return;
-        }
+            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+                run.krate($should_run)
+            }
 
-        // Build rustc docs so that we generate relative links.
-        builder.ensure(Rustc { stage, target });
+            fn make_run(run: RunConfig<'_>) {
+                run.builder.ensure($tool { stage: run.builder.top_stage, target: run.target });
+            }
 
-        // Build rustdoc.
-        builder.ensure(tool::Rustdoc { compiler });
+            /// Generates compiler documentation.
+            ///
+            /// This will generate all documentation for compiler and dependencies.
+            /// Compiler documentation is distributed separately, so we make sure
+            /// we do not merge it with the other documentation from std, test and
+            /// proc_macros. This is largely just a wrapper around `cargo doc`.
+            fn run(self, builder: &Builder<'_>) {
+                let stage = self.stage;
+                let target = self.target;
+                builder.info(&format!("Documenting stage{} {} ({})", stage, stringify!($tool).to_lowercase(), target));
 
-        // Symlink compiler docs to the output directory of rustdoc documentation.
-        let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target.triple).join("doc");
-        t!(fs::create_dir_all(&out_dir));
-        t!(symlink_dir_force(&builder.config, &out, &out_dir));
+                // This is the intended out directory for compiler documentation.
+                let out = builder.compiler_doc_out(target);
+                t!(fs::create_dir_all(&out));
 
-        // Build cargo command.
-        let mut cargo = prepare_tool_cargo(
-            builder,
-            compiler,
-            Mode::ToolRustc,
-            target,
-            "doc",
-            "src/tools/rustdoc",
-            SourceType::InTree,
-            &[],
-        );
+                let compiler = builder.compiler(stage, builder.config.build);
 
-        cargo.arg("-Zskip-rustdoc-fingerprint");
-        // Only include compiler crates, no dependencies of those, such as `libc`.
-        cargo.arg("--no-deps");
-        cargo.arg("-p").arg("rustdoc");
-        cargo.arg("-p").arg("rustdoc-json-types");
+                if !builder.config.compiler_docs {
+                    builder.info("\tskipping - compiler/tool docs disabled");
+                    return;
+                }
 
-        cargo.rustdocflag("--document-private-items");
-        cargo.rustdocflag("--enable-index-page");
-        cargo.rustdocflag("--show-type-layout");
-        cargo.rustdocflag("-Zunstable-options");
-        builder.run(&mut cargo.into());
+                // Build rustc docs so that we generate relative links.
+                builder.ensure(Rustc { stage, target });
+
+                // Symlink compiler docs to the output directory of rustdoc documentation.
+                let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target.triple).join("doc");
+                t!(fs::create_dir_all(&out_dir));
+                t!(symlink_dir_force(&builder.config, &out, &out_dir));
+
+                // Build cargo command.
+                let mut cargo = prepare_tool_cargo(
+                    builder,
+                    compiler,
+                    Mode::ToolRustc,
+                    target,
+                    "doc",
+                    $path,
+                    SourceType::InTree,
+                    &[],
+                );
+
+                cargo.arg("-Zskip-rustdoc-fingerprint");
+                // Only include compiler crates, no dependencies of those, such as `libc`.
+                cargo.arg("--no-deps");
+                $(
+                    cargo.arg("-p").arg($krate);
+                )+
+
+                $(if !$bin {
+                    cargo.rustdocflag("--document-private-items");
+                })?
+                cargo.rustdocflag("--enable-index-page");
+                cargo.rustdocflag("--show-type-layout");
+                cargo.rustdocflag("-Zunstable-options");
+                builder.run(&mut cargo.into());
+            }
+        }
     }
 }
 
+tool_doc!(Rustdoc, "rustdoc-tool", "src/tools/rustdoc", ["rustdoc", "rustdoc-json-types"]);
+tool_doc!(
+    Rustfmt,
+    "rustfmt-nightly",
+    "src/tools/rustfmt",
+    ["rustfmt-nightly", "rustfmt-config_proc_macro"],
+    binary = true
+);
+
 #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct ErrorIndex {
     pub target: TargetSelection,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 71fcde8bca8..66f4f481292 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 ee7a716655b..64a9905b33f 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 c7e2ce74019..1113d610128 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 7cba2523d1a..00000000000
--- 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 0e86fe45640..390ab1694a0 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 17b26850d4d..00000000000
--- 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 f703a183790..00000000000
--- 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 00000000000..2f3d069bd51
--- /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 00000000000..003d079a470
--- /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]
diff --git a/src/tools/rustfmt/src/lib.rs b/src/tools/rustfmt/src/lib.rs
index cde5d390cf2..ce8a45eea65 100644
--- a/src/tools/rustfmt/src/lib.rs
+++ b/src/tools/rustfmt/src/lib.rs
@@ -1,6 +1,7 @@
 #![feature(rustc_private)]
 #![deny(rust_2018_idioms)]
 #![warn(unreachable_pub)]
+#![recursion_limit = "256"]
 
 #[macro_use]
 extern crate derive_new;