From cf83387d2feefcb396f68b076d0210d764c9f733 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 5 Dec 2025 20:37:07 -0700 Subject: [PATCH 1/4] rustdoc: add test case for alias bug Reproduces --- .../rustdoc-merge-directory-alias/dep1.rs | 10 +++ .../rustdoc-merge-directory-alias/dep2.rs | 4 ++ .../rustdoc-merge-directory-alias/rmake.rs | 66 +++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 tests/run-make/rustdoc-merge-directory-alias/dep1.rs create mode 100644 tests/run-make/rustdoc-merge-directory-alias/dep2.rs create mode 100644 tests/run-make/rustdoc-merge-directory-alias/rmake.rs diff --git a/tests/run-make/rustdoc-merge-directory-alias/dep1.rs b/tests/run-make/rustdoc-merge-directory-alias/dep1.rs new file mode 100644 index 0000000000000..d1b32ccc69dec --- /dev/null +++ b/tests/run-make/rustdoc-merge-directory-alias/dep1.rs @@ -0,0 +1,10 @@ +pub struct Dep1; +pub struct Dep2; +pub struct Dep3; +pub struct Dep4; + +//@ hasraw crates.js 'dep1' +//@ hasraw search.index/name/*.js 'Dep1' +//@ has dep1/index.html +#[doc(alias="dep1_missing")] +pub struct Dep5; diff --git a/tests/run-make/rustdoc-merge-directory-alias/dep2.rs b/tests/run-make/rustdoc-merge-directory-alias/dep2.rs new file mode 100644 index 0000000000000..2df4452413c21 --- /dev/null +++ b/tests/run-make/rustdoc-merge-directory-alias/dep2.rs @@ -0,0 +1,4 @@ +//@ hasraw crates.js 'dep2' +//@ hasraw search.index/name/*.js 'Second' +//@ has dep2/index.html +pub struct Second; diff --git a/tests/run-make/rustdoc-merge-directory-alias/rmake.rs b/tests/run-make/rustdoc-merge-directory-alias/rmake.rs new file mode 100644 index 0000000000000..934e695826ace --- /dev/null +++ b/tests/run-make/rustdoc-merge-directory-alias/rmake.rs @@ -0,0 +1,66 @@ +// Running --merge=finalize without an input crate root should not trigger ICE. +// Issue: https://github.com/rust-lang/rust/issues/146646 + +//@ needs-target-std + +use run_make_support::{htmldocck, path, rustdoc}; + +fn main() { + let out_dir = path("out"); + let merged_dir = path("merged"); + let parts_out_dir = path("parts"); + + rustdoc() + .input("dep1.rs") + .out_dir(&out_dir) + .arg("-Zunstable-options") + .arg(format!("--parts-out-dir={}", parts_out_dir.display())) + .arg("--merge=none") + .run(); + assert!(parts_out_dir.join("dep1.json").exists()); + + let output = rustdoc() + .arg("-Zunstable-options") + .out_dir(&out_dir) + .arg(format!("--include-parts-dir={}", parts_out_dir.display())) + .arg("--merge=finalize") + .run(); + output.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug."); + + rustdoc() + .input("dep2.rs") + .out_dir(&out_dir) + .arg("-Zunstable-options") + .arg(format!("--parts-out-dir={}", parts_out_dir.display())) + .arg("--merge=none") + .run(); + assert!(parts_out_dir.join("dep2.json").exists()); + + let output2 = rustdoc() + .arg("-Zunstable-options") + .out_dir(&out_dir) + .arg(format!("--include-parts-dir={}", parts_out_dir.display())) + .arg("--merge=finalize") + .run(); + output2.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug."); + + rustdoc() + .input("dep1.rs") + .out_dir(&out_dir) + .arg("-Zunstable-options") + .arg(format!("--parts-out-dir={}", parts_out_dir.display())) + .arg("--merge=none") + .run(); + assert!(parts_out_dir.join("dep1.json").exists()); + + let output3 = rustdoc() + .arg("-Zunstable-options") + .out_dir(&out_dir) + .arg(format!("--include-parts-dir={}", parts_out_dir.display())) + .arg("--merge=finalize") + .run(); + output3.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug."); + + htmldocck().arg(&out_dir).arg("dep1.rs").run(); + htmldocck().arg(&out_dir).arg("dep2.rs").run(); +} From fb3a0895e0c806c57ca28e84d3aac9768696b940 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 5 Dec 2025 20:45:31 -0700 Subject: [PATCH 2/4] rustdoc: avoid dangling alias pointers after merge --- src/librustdoc/html/render/search_index.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index da6840c72f5b1..777a0a95fc837 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -721,7 +721,13 @@ impl SerializedSearchIndex { } }, ), - self.alias_pointers[id].and_then(|alias| map.get(&alias).copied()), + self.alias_pointers[id].and_then(|alias| { + if self.names[alias].is_empty() { + None + } else { + map.get(&alias).copied() + } + }), ); } new.generic_inverted_index = self From 38a2a3da3c9374eb11dbe63e68d57fb3315f869f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 5 Dec 2025 20:58:02 -0700 Subject: [PATCH 3/4] rustdoc: test for loading index when user said no Also mentioned, as a perf problem, in --- .../rustdoc-merge-directory-alias/dep1.rs | 2 +- .../dep_missing.rs | 4 ++++ .../rustdoc-merge-directory-alias/rmake.rs | 22 +++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/run-make/rustdoc-merge-directory-alias/dep_missing.rs diff --git a/tests/run-make/rustdoc-merge-directory-alias/dep1.rs b/tests/run-make/rustdoc-merge-directory-alias/dep1.rs index d1b32ccc69dec..b62f31c982b7f 100644 --- a/tests/run-make/rustdoc-merge-directory-alias/dep1.rs +++ b/tests/run-make/rustdoc-merge-directory-alias/dep1.rs @@ -6,5 +6,5 @@ pub struct Dep4; //@ hasraw crates.js 'dep1' //@ hasraw search.index/name/*.js 'Dep1' //@ has dep1/index.html -#[doc(alias="dep1_missing")] +#[doc(alias = "dep1_missing")] pub struct Dep5; diff --git a/tests/run-make/rustdoc-merge-directory-alias/dep_missing.rs b/tests/run-make/rustdoc-merge-directory-alias/dep_missing.rs new file mode 100644 index 0000000000000..74236aef47ea5 --- /dev/null +++ b/tests/run-make/rustdoc-merge-directory-alias/dep_missing.rs @@ -0,0 +1,4 @@ +//@ !hasraw crates.js 'dep_missing' +//@ !hasraw search.index/name/*.js 'DepMissing' +//@ has dep_missing/index.html +pub struct DepMissing; diff --git a/tests/run-make/rustdoc-merge-directory-alias/rmake.rs b/tests/run-make/rustdoc-merge-directory-alias/rmake.rs index 934e695826ace..096eb4a487c15 100644 --- a/tests/run-make/rustdoc-merge-directory-alias/rmake.rs +++ b/tests/run-make/rustdoc-merge-directory-alias/rmake.rs @@ -61,6 +61,28 @@ fn main() { .run(); output3.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug."); + // dep_missing is different, because --parts-out-dir is not supplied + rustdoc().input("dep_missing.rs").out_dir(&out_dir).run(); + assert!(parts_out_dir.join("dep2.json").exists()); + + rustdoc() + .input("dep1.rs") + .out_dir(&out_dir) + .arg("-Zunstable-options") + .arg(format!("--parts-out-dir={}", parts_out_dir.display())) + .arg("--merge=none") + .run(); + assert!(parts_out_dir.join("dep1.json").exists()); + + let output4 = rustdoc() + .arg("-Zunstable-options") + .out_dir(&out_dir) + .arg(format!("--include-parts-dir={}", parts_out_dir.display())) + .arg("--merge=finalize") + .run(); + output4.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug."); + htmldocck().arg(&out_dir).arg("dep1.rs").run(); htmldocck().arg(&out_dir).arg("dep2.rs").run(); + htmldocck().arg(&out_dir).arg("dep_missing.rs").run(); } From 6fb8d9fd92881ef06a49c253b0bb7f05c20431f4 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 5 Dec 2025 21:00:19 -0700 Subject: [PATCH 4/4] rustdoc: avoid loading index when user says no --- src/librustdoc/html/render/search_index.rs | 14 ++++++++------ src/librustdoc/html/render/write_shared.rs | 10 ++++++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 777a0a95fc837..a4cbef8c39177 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -24,6 +24,7 @@ use tracing::instrument; use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate}; use crate::clean::{self, utils}; +use crate::config::ShouldMerge; use crate::error::Error; use crate::formats::cache::{Cache, OrphanImplItem}; use crate::formats::item_type::ItemType; @@ -722,11 +723,7 @@ impl SerializedSearchIndex { }, ), self.alias_pointers[id].and_then(|alias| { - if self.names[alias].is_empty() { - None - } else { - map.get(&alias).copied() - } + if self.names[alias].is_empty() { None } else { map.get(&alias).copied() } }), ); } @@ -1254,6 +1251,7 @@ pub(crate) fn build_index( tcx: TyCtxt<'_>, doc_root: &Path, resource_suffix: &str, + should_merge: &ShouldMerge, ) -> Result { let mut search_index = std::mem::take(&mut cache.search_index); @@ -1304,7 +1302,11 @@ pub(crate) fn build_index( // // if there's already a search index, load it into memory and add the new entries to it // otherwise, do nothing - let mut serialized_index = SerializedSearchIndex::load(doc_root, resource_suffix)?; + let mut serialized_index = if should_merge.read_rendered_cci { + SerializedSearchIndex::load(doc_root, resource_suffix)? + } else { + SerializedSearchIndex::default() + }; // The crate always goes first in this list let crate_name = krate.name(tcx); diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 9a8df53931394..6bf116c3b75ad 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -66,8 +66,14 @@ pub(crate) fn write_shared( // Write shared runs within a flock; disable thread dispatching of IO temporarily. let _lock = try_err!(flock::Lock::new(&lock_file, true, true, true), &lock_file); - let search_index = - build_index(krate, &mut cx.shared.cache, tcx, &cx.dst, &cx.shared.resource_suffix)?; + let search_index = build_index( + krate, + &mut cx.shared.cache, + tcx, + &cx.dst, + &cx.shared.resource_suffix, + &opt.should_merge, + )?; let crate_name = krate.name(cx.tcx()); let crate_name = crate_name.as_str(); // rand