diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 97cc76d833e9e..929441125dd52 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use rustc_hir::attrs::Deprecation; use rustc_hir::def::{CtorKind, DefKind}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::bug; @@ -473,6 +473,9 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { // This is a rudimentary check that does not catch all cases, // just the easiest. let mut fallback_map: Vec<(DefId, DefId)> = Default::default(); + // hidden items never enter the map, so dedup here or every + // parent path re-enqueues the whole subtree (#160439) + let mut fallback_seen: DefIdSet = Default::default(); // Issue 46112: We want the map to prefer the shortest // paths when reporting the path to an item. Therefore we @@ -534,6 +537,10 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { } Entry::Vacant(entry) => { if fallback { + // seen already, skip this parent + if !fallback_seen.insert(def_id) { + return; + } // We do all of the same steps to fallback entries as to // preferred entries, except for recording them in a separate map. // It is important to not return early in the fallback cases to diff --git a/tests/run-make/rustdoc/visible-parent-map-hang/dep.rs b/tests/run-make/rustdoc/visible-parent-map-hang/dep.rs new file mode 100644 index 0000000000000..72dd66370c6fb --- /dev/null +++ b/tests/run-make/rustdoc/visible-parent-map-hang/dep.rs @@ -0,0 +1,437 @@ +#![crate_type = "lib"] +#![allow(dead_code)] + +pub trait Tr { + fn x(); +} +pub trait Tr2 { + fn x(); +} + +#[doc(hidden)] +pub mod outer { + #[doc(hidden)] + pub mod l0 { + #[doc(hidden)] + pub mod s0 { + pub use super::l1; + } + #[doc(hidden)] + pub mod s1 { + pub use super::l1; + } + #[doc(hidden)] + pub mod s2 { + pub use super::l1; + } + #[doc(hidden)] + pub mod s3 { + pub use super::l1; + } + #[doc(hidden)] + pub mod s4 { + pub use super::l1; + } + #[doc(hidden)] + pub mod s5 { + pub use super::l1; + } + #[doc(hidden)] + pub mod s6 { + pub use super::l1; + } + #[doc(hidden)] + pub mod s7 { + pub use super::l1; + } + #[doc(hidden)] + pub mod l1 { + #[doc(hidden)] + pub mod s0 { + pub use super::l2; + } + #[doc(hidden)] + pub mod s1 { + pub use super::l2; + } + #[doc(hidden)] + pub mod s2 { + pub use super::l2; + } + #[doc(hidden)] + pub mod s3 { + pub use super::l2; + } + #[doc(hidden)] + pub mod s4 { + pub use super::l2; + } + #[doc(hidden)] + pub mod s5 { + pub use super::l2; + } + #[doc(hidden)] + pub mod s6 { + pub use super::l2; + } + #[doc(hidden)] + pub mod s7 { + pub use super::l2; + } + #[doc(hidden)] + pub mod l2 { + #[doc(hidden)] + pub mod s0 { + pub use super::l3; + } + #[doc(hidden)] + pub mod s1 { + pub use super::l3; + } + #[doc(hidden)] + pub mod s2 { + pub use super::l3; + } + #[doc(hidden)] + pub mod s3 { + pub use super::l3; + } + #[doc(hidden)] + pub mod s4 { + pub use super::l3; + } + #[doc(hidden)] + pub mod s5 { + pub use super::l3; + } + #[doc(hidden)] + pub mod s6 { + pub use super::l3; + } + #[doc(hidden)] + pub mod s7 { + pub use super::l3; + } + #[doc(hidden)] + pub mod l3 { + #[doc(hidden)] + pub mod s0 { + pub use super::l4; + } + #[doc(hidden)] + pub mod s1 { + pub use super::l4; + } + #[doc(hidden)] + pub mod s2 { + pub use super::l4; + } + #[doc(hidden)] + pub mod s3 { + pub use super::l4; + } + #[doc(hidden)] + pub mod s4 { + pub use super::l4; + } + #[doc(hidden)] + pub mod s5 { + pub use super::l4; + } + #[doc(hidden)] + pub mod s6 { + pub use super::l4; + } + #[doc(hidden)] + pub mod s7 { + pub use super::l4; + } + #[doc(hidden)] + pub mod l4 { + #[doc(hidden)] + pub mod s0 { + pub use super::l5; + } + #[doc(hidden)] + pub mod s1 { + pub use super::l5; + } + #[doc(hidden)] + pub mod s2 { + pub use super::l5; + } + #[doc(hidden)] + pub mod s3 { + pub use super::l5; + } + #[doc(hidden)] + pub mod s4 { + pub use super::l5; + } + #[doc(hidden)] + pub mod s5 { + pub use super::l5; + } + #[doc(hidden)] + pub mod s6 { + pub use super::l5; + } + #[doc(hidden)] + pub mod s7 { + pub use super::l5; + } + #[doc(hidden)] + pub mod l5 { + #[doc(hidden)] + pub mod s0 { + pub use super::l6; + } + #[doc(hidden)] + pub mod s1 { + pub use super::l6; + } + #[doc(hidden)] + pub mod s2 { + pub use super::l6; + } + #[doc(hidden)] + pub mod s3 { + pub use super::l6; + } + #[doc(hidden)] + pub mod s4 { + pub use super::l6; + } + #[doc(hidden)] + pub mod s5 { + pub use super::l6; + } + #[doc(hidden)] + pub mod s6 { + pub use super::l6; + } + #[doc(hidden)] + pub mod s7 { + pub use super::l6; + } + #[doc(hidden)] + pub mod l6 { + #[doc(hidden)] + pub mod s0 { + pub use super::l7; + } + #[doc(hidden)] + pub mod s1 { + pub use super::l7; + } + #[doc(hidden)] + pub mod s2 { + pub use super::l7; + } + #[doc(hidden)] + pub mod s3 { + pub use super::l7; + } + #[doc(hidden)] + pub mod s4 { + pub use super::l7; + } + #[doc(hidden)] + pub mod s5 { + pub use super::l7; + } + #[doc(hidden)] + pub mod s6 { + pub use super::l7; + } + #[doc(hidden)] + pub mod s7 { + pub use super::l7; + } + #[doc(hidden)] + pub mod l7 { + #[doc(hidden)] + pub mod s0 { + pub use super::l8; + } + #[doc(hidden)] + pub mod s1 { + pub use super::l8; + } + #[doc(hidden)] + pub mod s2 { + pub use super::l8; + } + #[doc(hidden)] + pub mod s3 { + pub use super::l8; + } + #[doc(hidden)] + pub mod s4 { + pub use super::l8; + } + #[doc(hidden)] + pub mod s5 { + pub use super::l8; + } + #[doc(hidden)] + pub mod s6 { + pub use super::l8; + } + #[doc(hidden)] + pub mod s7 { + pub use super::l8; + } + #[doc(hidden)] + pub mod l8 { + #[doc(hidden)] + pub mod s0 { + pub use super::l9; + } + #[doc(hidden)] + pub mod s1 { + pub use super::l9; + } + #[doc(hidden)] + pub mod s2 { + pub use super::l9; + } + #[doc(hidden)] + pub mod s3 { + pub use super::l9; + } + #[doc(hidden)] + pub mod s4 { + pub use super::l9; + } + #[doc(hidden)] + pub mod s5 { + pub use super::l9; + } + #[doc(hidden)] + pub mod s6 { + pub use super::l9; + } + #[doc(hidden)] + pub mod s7 { + pub use super::l9; + } + #[doc(hidden)] + pub mod l9 { + #[doc(hidden)] + pub mod s0 { + pub use super::l10; + } + #[doc(hidden)] + pub mod s1 { + pub use super::l10; + } + #[doc(hidden)] + pub mod s2 { + pub use super::l10; + } + #[doc(hidden)] + pub mod s3 { + pub use super::l10; + } + #[doc(hidden)] + pub mod s4 { + pub use super::l10; + } + #[doc(hidden)] + pub mod s5 { + pub use super::l10; + } + #[doc(hidden)] + pub mod s6 { + pub use super::l10; + } + #[doc(hidden)] + pub mod s7 { + pub use super::l10; + } + #[doc(hidden)] + pub mod l10 { + #[doc(hidden)] + pub mod s0 { + pub use super::l11; + } + #[doc(hidden)] + pub mod s1 { + pub use super::l11; + } + #[doc(hidden)] + pub mod s2 { + pub use super::l11; + } + #[doc(hidden)] + pub mod s3 { + pub use super::l11; + } + #[doc(hidden)] + pub mod s4 { + pub use super::l11; + } + #[doc(hidden)] + pub mod s5 { + pub use super::l11; + } + #[doc(hidden)] + pub mod s6 { + pub use super::l11; + } + #[doc(hidden)] + pub mod s7 { + pub use super::l11; + } + #[doc(hidden)] + pub mod l11 { + #[doc(hidden)] + pub mod s0 { + pub use super::leaf::S; + } + #[doc(hidden)] + pub mod s1 { + pub use super::leaf::S; + } + #[doc(hidden)] + pub mod s2 { + pub use super::leaf::S; + } + #[doc(hidden)] + pub mod s3 { + pub use super::leaf::S; + } + #[doc(hidden)] + pub mod s4 { + pub use super::leaf::S; + } + #[doc(hidden)] + pub mod s5 { + pub use super::leaf::S; + } + #[doc(hidden)] + pub mod s6 { + pub use super::leaf::S; + } + #[doc(hidden)] + pub mod s7 { + pub use super::leaf::S; + } + #[doc(hidden)] + pub mod leaf { + pub struct S; + } + } + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/tests/run-make/rustdoc/visible-parent-map-hang/main.rs b/tests/run-make/rustdoc/visible-parent-map-hang/main.rs new file mode 100644 index 0000000000000..b866432f611e3 --- /dev/null +++ b/tests/run-make/rustdoc/visible-parent-map-hang/main.rs @@ -0,0 +1,24 @@ +// #160439: nested #[doc(hidden)] modules made rustdoc hang here. +#![crate_type = "lib"] + +use std::fmt; + +pub use dep::Tr; + +pub struct Local; +impl dep::Tr for Local { + fn x() {} +} +impl dep::Tr2 for Local { + fn x() {} +} +impl fmt::Display for Local { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "x") + } +} +impl Default for Local { + fn default() -> Self { + Local + } +} diff --git a/tests/run-make/rustdoc/visible-parent-map-hang/rmake.rs b/tests/run-make/rustdoc/visible-parent-map-hang/rmake.rs new file mode 100644 index 0000000000000..944da900dbf0d --- /dev/null +++ b/tests/run-make/rustdoc/visible-parent-map-hang/rmake.rs @@ -0,0 +1,33 @@ +// #160439: nested #[doc(hidden)] modules made the visible_parent_map BFS +// exponential. compiletest has no per-test timeout, so time it here. +use std::process::{Command, Stdio}; +use std::time::{Duration, Instant}; + +use run_make_support::{env_var, rust_lib_name, rustc}; + +fn main() { + rustc().input("dep.rs").edition("2021").crate_type("lib").run(); + + // the bug made rustdoc hang; kill it if it takes too long + let mut child = Command::new(env_var("RUSTDOC")) + .args(["--edition", "2021", "--crate-name", "main", "-o", "target"]) + .arg(format!("--extern=dep={}", rust_lib_name("dep"))) + .arg("main.rs") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .unwrap(); + + let deadline = Instant::now() + Duration::from_secs(60); + let status = loop { + if let Some(status) = child.try_wait().unwrap() { + break status; + } + if Instant::now() > deadline { + child.kill().unwrap(); + panic!("rustdoc timed out: visible_parent_map regression?"); + } + std::thread::sleep(Duration::from_millis(100)); + }; + assert!(status.success()); +}