Skip to content

Commit 6a84c99

Browse files
committed
Allow #![doc(test(attr(..)))] doctests to be again merged together
1 parent 4d90a9c commit 6a84c99

File tree

4 files changed

+48
-14
lines changed

4 files changed

+48
-14
lines changed

src/librustdoc/doctest.rs

+24-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod runner;
55
mod rust;
66

77
use std::fs::File;
8+
use std::hash::{Hash, Hasher};
89
use std::io::{self, Write};
910
use std::path::{Path, PathBuf};
1011
use std::process::{self, Command, Stdio};
@@ -14,7 +15,7 @@ use std::{panic, str};
1415

1516
pub(crate) use make::DocTestBuilder;
1617
pub(crate) use markdown::test as test_markdown;
17-
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
18+
use rustc_data_structures::fx::{FxHashMap, FxHasher, FxIndexMap, FxIndexSet};
1819
use rustc_errors::emitter::HumanReadableErrorType;
1920
use rustc_errors::{ColorConfig, DiagCtxtHandle};
2021
use rustc_hir as hir;
@@ -313,7 +314,7 @@ pub(crate) fn run_tests(
313314
rustdoc_options: &Arc<RustdocOptions>,
314315
unused_extern_reports: &Arc<Mutex<Vec<UnusedExterns>>>,
315316
mut standalone_tests: Vec<test::TestDescAndFn>,
316-
mergeable_tests: FxIndexMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>,
317+
mergeable_tests: FxIndexMap<MergeableTestKey, Vec<(DocTestBuilder, ScrapedDocTest)>>,
317318
) {
318319
let mut test_args = Vec::with_capacity(rustdoc_options.test_args.len() + 1);
319320
test_args.insert(0, "rustdoctest".to_string());
@@ -326,7 +327,7 @@ pub(crate) fn run_tests(
326327
let mut ran_edition_tests = 0;
327328
let target_str = rustdoc_options.target.to_string();
328329

329-
for (edition, mut doctests) in mergeable_tests {
330+
for (MergeableTestKey { edition, global_crate_attrs_hash }, mut doctests) in mergeable_tests {
330331
if doctests.is_empty() {
331332
continue;
332333
}
@@ -336,8 +337,8 @@ pub(crate) fn run_tests(
336337

337338
let rustdoc_test_options = IndividualTestOptions::new(
338339
rustdoc_options,
339-
&Some(format!("merged_doctest_{edition}")),
340-
PathBuf::from(format!("doctest_{edition}.rs")),
340+
&Some(format!("merged_doctest_{edition}_{global_crate_attrs_hash}")),
341+
PathBuf::from(format!("doctest_{edition}_{global_crate_attrs_hash}.rs")),
341342
);
342343

343344
for (doctest, scraped_test) in &doctests {
@@ -910,9 +911,15 @@ pub(crate) trait DocTestVisitor {
910911
fn visit_header(&mut self, _name: &str, _level: u32) {}
911912
}
912913

914+
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
915+
pub(crate) struct MergeableTestKey {
916+
edition: Edition,
917+
global_crate_attrs_hash: u64,
918+
}
919+
913920
struct CreateRunnableDocTests {
914921
standalone_tests: Vec<test::TestDescAndFn>,
915-
mergeable_tests: FxIndexMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>,
922+
mergeable_tests: FxIndexMap<MergeableTestKey, Vec<(DocTestBuilder, ScrapedDocTest)>>,
916923

917924
rustdoc_options: Arc<RustdocOptions>,
918925
opts: GlobalTestOptions,
@@ -980,7 +987,17 @@ impl CreateRunnableDocTests {
980987
let test_desc = self.generate_test_desc_and_fn(doctest, scraped_test);
981988
self.standalone_tests.push(test_desc);
982989
} else {
983-
self.mergeable_tests.entry(edition).or_default().push((doctest, scraped_test));
990+
self.mergeable_tests
991+
.entry(MergeableTestKey {
992+
edition,
993+
global_crate_attrs_hash: {
994+
let mut hasher = FxHasher::default();
995+
scraped_test.global_crate_attrs.hash(&mut hasher);
996+
hasher.finish()
997+
},
998+
})
999+
.or_default()
1000+
.push((doctest, scraped_test));
9841001
}
9851002
}
9861003

src/librustdoc/doctest/make.rs

-3
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,6 @@ impl DocTestBuilder {
107107
let can_be_merged = can_merge_doctests
108108
&& !has_global_allocator
109109
&& crate_attrs.is_empty()
110-
// FIXME: We can probably merge tests which have the same global crate attrs,
111-
// like we already do for the edition
112-
&& global_crate_attrs.is_empty()
113110
// If this is a merged doctest and a defined macro uses `$crate`, then the path will
114111
// not work, so better not put it into merged doctests.
115112
&& !(has_macro_def && everything_else.contains("$crate"));

tests/run-make/doctests-keep-binaries-2024/rmake.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,22 @@ fn setup_test_env<F: FnOnce(&Path, &Path)>(callback: F) {
1616
}
1717

1818
fn check_generated_binaries() {
19-
run("doctests/merged_doctest_2024/rust_out");
19+
let mut found_merged_doctest = false;
20+
rfs::read_dir_entries("doctests/", |path| {
21+
if path
22+
.file_name()
23+
.and_then(|name| name.to_str())
24+
.is_some_and(|name| name.starts_with("merged_doctest_2024"))
25+
{
26+
found_merged_doctest = true;
27+
let rust_out = path.join("rust_out");
28+
let rust_out = rust_out.to_string_lossy();
29+
run(&*rust_out);
30+
}
31+
});
32+
if !found_merged_doctest {
33+
panic!("no directory starting with `merged_doctest_2024` found under `doctests/`");
34+
}
2035
}
2136

2237
fn main() {

tests/rustdoc-ui/doctest/dead-code-module-2.stdout

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11

2-
running 2 tests
3-
test $DIR/dead-code-module-2.rs - my_mod::f (line 16) - compile ... FAILED
2+
running 1 test
43
test $DIR/dead-code-module-2.rs - g (line 24) - compile ... ok
54

5+
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
6+
7+
8+
running 1 test
9+
test $DIR/dead-code-module-2.rs - my_mod::f (line 16) - compile ... FAILED
10+
611
failures:
712

813
---- $DIR/dead-code-module-2.rs - my_mod::f (line 16) stdout ----
@@ -26,5 +31,5 @@ Couldn't compile the test.
2631
failures:
2732
$DIR/dead-code-module-2.rs - my_mod::f (line 16)
2833

29-
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
34+
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
3035

0 commit comments

Comments
 (0)