Repository: rust
Issue: rustdoc: Some items in `cache.paths` are non-local
Labels: T-rustdoc,E-mentor,C-bug,A-cross-crate-reexports

I tried this code:

```diff
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 1e1fc2436aa..2d3858d7b17 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -3,7 +3,7 @@
 use std::path::Path;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, LocalDefId, DefId, CRATE_DEF_INDEX};
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
@@ -16,6 +16,36 @@
 use crate::html::render::cache::{get_index_search_type, ExternalLocation};
 use crate::html::render::IndexItem;
 
+#[derive(Clone)]
+crate struct AssertLocalMap<V>(FxHashMap<LocalDefId, V>);
+
+impl<V> Default for AssertLocalMap<V> {
+    fn default() -> Self {
+        Self(FxHashMap::default())
+    }
+}
+
+impl<V> AssertLocalMap<V> {
+    crate fn get(&self, k: &DefId) -> Option<&V> {
+        self.0.get(&k.as_local().unwrap())
+    }
+
+    crate fn contains_key(&self, k: &DefId) -> bool {
+        k.as_local().map_or(false, |local| self.0.contains_key(&local))
+    }
+
+    fn insert(&mut self, k: DefId, v: V) -> Option<V> {
+        let local = k.as_local().unwrap_or_else(|| panic!(
+            "{:?} is not local", k
+        ));
+        self.0.insert(local, v)
+    }
+
+    crate fn into_iter(self) -> impl Iterator<Item = (DefId, V)> {
+        self.0.into_iter().map(|(k, v)| (k.to_def_id(), v))
+    }
+}
+
 /// This cache is used to store information about the [`clean::Crate`] being
 /// rendered in order to provide more useful documentation. This contains
 /// information like all implementors of a trait, all traits a type implements,
@@ -40,7 +70,7 @@
     /// URLs when a type is being linked to. External paths are not located in
     /// this map because the `External` type itself has all the information
     /// necessary.
-    crate paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
+    crate paths: AssertLocalMap<(Vec<String>, ItemType)>,
 
     /// Similar to `paths`, but only holds external paths. This is only used for
     /// generating explicit hyperlinks to other crates.
```

I expected to see this happen: No change in behavior; according to the comment, all items stored in `paths` are local.

Instead, this happened: Rustdoc panics on nearly every test case in `src/test/rustdoc`. Here is an example:

```
---- [rustdoc] rustdoc/intra-doc/trait-item.rs stdout ----

error: rustdoc failed!
status: exit status: 101

------------------------------------------
stderr:
------------------------------------------
thread 'rustc' panicked at 'DefId(2:2796 ~ core[87c3]::convert::{impl#7}::Error) is not local', src/librustdoc/formats/cache.rs:38:52
```

 ## Why is this bad?

Various parts of rustdoc depend on `paths` being local. For example, https://github.com/rust-lang/rust/blob/56dee7c49ecdec4c2c9eccc6ff966cf58847bda6/src/librustdoc/html/format.rs#L486-L492 only checks `external_paths` if `paths` is None. I don't know if this explictly leads to wrong behavior, but it does mean we can't distiguish between "not in extern_paths because it's local" and "not in extern_paths because of a bug".

Here are all the places paths is read (not written):
- https://github.com/rust-lang/rust/blob/56dee7c49ecdec4c2c9eccc6ff966cf58847bda6/src/librustdoc/html/render/context.rs#L233 - this one I think could lead to rustdoc writing to the documentation folders of other crates :sweat_smile: 
- https://github.com/rust-lang/rust/blob/56dee7c49ecdec4c2c9eccc6ff966cf58847bda6/src/librustdoc/formats/cache.rs#L265 - not sure of the impact of this one
- https://github.com/rust-lang/rust/blob/56dee7c49ecdec4c2c9eccc6ff966cf58847bda6/src/librustdoc/html/render/mod.rs#L2120 - this will result in some foreign impls not showing up in the sidebar
- https://github.com/rust-lang/rust/blob/56dee7c49ecdec4c2c9eccc6ff966cf58847bda6/src/librustdoc/html/render/write_shared.rs#L491 - no idea, that whole code looks very sketchy
- https://github.com/rust-lang/rust/blob/56dee7c49ecdec4c2c9eccc6ff966cf58847bda6/src/librustdoc/html/render/write_shared.rs#L531 - I think this will result in items duplicated in the JS sidebar file and the HTML (cc @jsha, I think you ran into this recently?)
- https://github.com/rust-lang/rust/blob/56dee7c49ecdec4c2c9eccc6ff966cf58847bda6/src/librustdoc/html/render/cache.rs#L36

### Meta

HEAD is 0ce21126b295608ab4704f678d53ae8d2e9b60d1. I found this while reviewing https://github.com/rust-lang/rust/pull/86662.

<!--
Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
environment. E.g. `RUST_BACKTRACE=1 cargo build`.
-->
<details><summary>Backtrace</summary>
<p>

```
stack backtrace:
   0: rust_begin_unwind
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/std/src/panicking.rs:515:5
   1: std::panicking::begin_panic_fmt
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/std/src/panicking.rs:457:5
   2: rustdoc::formats::cache::AssertLocalMap<V>::insert::{{closure}}
             at ./src/librustdoc/formats/cache.rs:38:52
   3: core::option::Option<T>::unwrap_or_else
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/core/src/option.rs:429:21
   4: rustdoc::formats::cache::AssertLocalMap<V>::insert
             at ./src/librustdoc/formats/cache.rs:38:21
   5: <rustdoc::formats::cache::CacheBuilder as rustdoc::fold::DocFolder>::fold_item
             at ./src/librustdoc/formats/cache.rs:384:25
   6: rustdoc::fold::DocFolder::fold_inner_recur::{{closure}}
             at ./src/librustdoc/fold.rs:46:62
   7: core::iter::adapters::filter_map::filter_map_try_fold::{{closure}}
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/core/src/iter/adapters/filter_map.rs:46:28
   8: core::iter::traits::iterator::Iterator::try_fold
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/core/src/iter/traits/iterator.rs:1997:21
   9: <core::iter::adapters::filter_map::FilterMap<I,F> as core::iter::traits::iterator::Iterator>::try_fold
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/core/src/iter/adapters/filter_map.rs:77:9
  10: <I as alloc::vec::source_iter_marker::SpecInPlaceCollect<T,I>>::collect_in_place
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/alloc/src/vec/source_iter_marker.rs:119:13
  11: alloc::vec::source_iter_marker::<impl alloc::vec::spec_from_iter::SpecFromIter<T,I> for alloc::vec::Vec<T>>::from_iter
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/alloc/src/vec/source_iter_marker.rs:55:19
  12: <alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/alloc/src/vec/mod.rs:2461:9
  13: core::iter::traits::iterator::Iterator::collect
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/core/src/iter/traits/iterator.rs:1748:9
  14: rustdoc::fold::DocFolder::fold_inner_recur
             at ./src/librustdoc/fold.rs:46:27
  15: rustdoc::fold::DocFolder::fold_item_recur
             at ./src/librustdoc/fold.rs:70:18
  16: <rustdoc::formats::cache::CacheBuilder as rustdoc::fold::DocFolder>::fold_item
             at ./src/librustdoc/formats/cache.rs:463:20
  17: rustdoc::fold::DocFolder::fold_mod::{{closure}}
             at ./src/librustdoc/fold.rs:78:55
  18: core::iter::adapters::filter_map::filter_map_try_fold::{{closure}}
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/core/src/iter/adapters/filter_map.rs:46:28
  19: core::iter::traits::iterator::Iterator::try_fold
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/core/src/iter/traits/iterator.rs:1997:21
  20: <core::iter::adapters::filter_map::FilterMap<I,F> as core::iter::traits::iterator::Iterator>::try_fold
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/core/src/iter/adapters/filter_map.rs:77:9
  21: <I as alloc::vec::source_iter_marker::SpecInPlaceCollect<T,I>>::collect_in_place
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/alloc/src/vec/source_iter_marker.rs:119:13
  22: alloc::vec::source_iter_marker::<impl alloc::vec::spec_from_iter::SpecFromIter<T,I> for alloc::vec::Vec<T>>::from_iter
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/alloc/src/vec/source_iter_marker.rs:55:19
  23: <alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/alloc/src/vec/mod.rs:2461:9
  24: core::iter::traits::iterator::Iterator::collect
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/library/core/src/iter/traits/iterator.rs:1748:9
  25: rustdoc::fold::DocFolder::fold_mod
             at ./src/librustdoc/fold.rs:78:20
  26: rustdoc::fold::DocFolder::fold_inner_recur
             at ./src/librustdoc/fold.rs:19:41
  27: rustdoc::fold::DocFolder::fold_item_recur
             at ./src/librustdoc/fold.rs:70:18
  28: <rustdoc::formats::cache::CacheBuilder as rustdoc::fold::DocFolder>::fold_item
             at ./src/librustdoc/formats/cache.rs:463:20
  29: rustdoc::fold::DocFolder::fold_crate
             at ./src/librustdoc/fold.rs:83:20
  30: rustdoc::formats::cache::Cache::populate
             at ./src/librustdoc/formats/cache.rs:205:17
  31: rustdoc::core::run_global_ctxt::{{closure}}
             at ./src/librustdoc/core.rs:514:9
  32: rustc_data_structures::profiling::VerboseTimingGuard::run
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_data_structures/src/profiling.rs:573:9
  33: rustc_session::utils::<impl rustc_session::session::Session>::time
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_session/src/utils.rs:16:9
  34: rustdoc::core::run_global_ctxt
             at ./src/librustdoc/core.rs:513:13
  35: rustdoc::main_options::{{closure}}::{{closure}}::{{closure}}::{{closure}}
             at ./src/librustdoc/lib.rs:744:21
  36: rustc_data_structures::profiling::VerboseTimingGuard::run
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_data_structures/src/profiling.rs:573:9
  37: rustc_session::utils::<impl rustc_session::session::Session>::time
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_session/src/utils.rs:16:9
  38: rustdoc::main_options::{{closure}}::{{closure}}::{{closure}}
             at ./src/librustdoc/lib.rs:743:55
  39: rustc_interface::passes::QueryContext::enter::{{closure}}
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_interface/src/passes.rs:799:42
  40: rustc_middle::ty::context::tls::enter_context::{{closure}}
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_middle/src/ty/context.rs:1740:50
  41: rustc_middle::ty::context::tls::set_tlv
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_middle/src/ty/context.rs:1724:9
  42: rustc_middle::ty::context::tls::enter_context
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_middle/src/ty/context.rs:1740:9
  43: rustc_interface::passes::QueryContext::enter
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_interface/src/passes.rs:799:9
  44: rustdoc::main_options::{{closure}}::{{closure}}
             at ./src/librustdoc/lib.rs:742:13
  45: rustc_interface::queries::<impl rustc_interface::interface::Compiler>::enter
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_interface/src/queries.rs:431:19
  46: rustdoc::main_options::{{closure}}
             at ./src/librustdoc/lib.rs:722:9
  47: rustc_interface::interface::create_compiler_and_run::{{closure}}
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_interface/src/interface.rs:208:13
  48: rustc_span::with_source_map
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_span/src/lib.rs:873:5
  49: rustc_interface::interface::create_compiler_and_run
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_interface/src/interface.rs:202:5
  50: rustdoc::main_options
             at ./src/librustdoc/lib.rs:721:5
  51: rustdoc::main_args::{{closure}}
             at ./src/librustdoc/lib.rs:649:17
  52: rustc_interface::util::setup_callbacks_and_run_in_thread_pool_with_globals::{{closure}}::{{closure}}
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_interface/src/util.rs:158:13
  53: scoped_tls::ScopedKey<T>::set
             at /cargo/registry/src/github.com-1ecc6299db9ec823/scoped-tls-1.0.0/src/lib.rs:137:9
  54: rustc_span::with_session_globals
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_span/src/lib.rs:104:5
  55: rustc_interface::util::setup_callbacks_and_run_in_thread_pool_with_globals::{{closure}}
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_interface/src/util.rs:156:9
  56: rustc_interface::util::scoped_thread::{{closure}}
             at /rustc/0ce21126b295608ab4704f678d53ae8d2e9b60d1/compiler/rustc_interface/src/util.rs:131:24
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: rustc 1.55.0-nightly (0ce21126b 2021-06-29) running on x86_64-unknown-linux-gnu

query stack during panic:
end of query stack
```

</p>
</details>


<!-- TRIAGEBOT_START -->

<!-- TRIAGEBOT_ASSIGN_START -->

<!-- TRIAGEBOT_ASSIGN_DATA_START$${"user":"Stupremee"}$$TRIAGEBOT_ASSIGN_DATA_END -->

<!-- TRIAGEBOT_ASSIGN_END -->
<!-- TRIAGEBOT_END -->