Skip to content

Commit c1b07e9

Browse files
committed
Allow #![doc(test(attr(..)))] doctests to be again merged together
1 parent 8768fc7 commit c1b07e9

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;
@@ -323,7 +324,7 @@ pub(crate) fn run_tests(
323324
rustdoc_options: &Arc<RustdocOptions>,
324325
unused_extern_reports: &Arc<Mutex<Vec<UnusedExterns>>>,
325326
mut standalone_tests: Vec<test::TestDescAndFn>,
326-
mergeable_tests: FxIndexMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>,
327+
mergeable_tests: FxIndexMap<MergeableTestKey, Vec<(DocTestBuilder, ScrapedDocTest)>>,
327328
// We pass this argument so we can drop it manually before using `exit`.
328329
mut temp_dir: Option<TempDir>,
329330
) {
@@ -338,7 +339,7 @@ pub(crate) fn run_tests(
338339
let mut ran_edition_tests = 0;
339340
let target_str = rustdoc_options.target.to_string();
340341

341-
for (edition, mut doctests) in mergeable_tests {
342+
for (MergeableTestKey { edition, global_crate_attrs_hash }, mut doctests) in mergeable_tests {
342343
if doctests.is_empty() {
343344
continue;
344345
}
@@ -348,8 +349,8 @@ pub(crate) fn run_tests(
348349

349350
let rustdoc_test_options = IndividualTestOptions::new(
350351
rustdoc_options,
351-
&Some(format!("merged_doctest_{edition}")),
352-
PathBuf::from(format!("doctest_{edition}.rs")),
352+
&Some(format!("merged_doctest_{edition}_{global_crate_attrs_hash}")),
353+
PathBuf::from(format!("doctest_{edition}_{global_crate_attrs_hash}.rs")),
353354
);
354355

355356
for (doctest, scraped_test) in &doctests {
@@ -927,9 +928,15 @@ pub(crate) trait DocTestVisitor {
927928
fn visit_header(&mut self, _name: &str, _level: u32) {}
928929
}
929930

931+
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
932+
pub(crate) struct MergeableTestKey {
933+
edition: Edition,
934+
global_crate_attrs_hash: u64,
935+
}
936+
930937
struct CreateRunnableDocTests {
931938
standalone_tests: Vec<test::TestDescAndFn>,
932-
mergeable_tests: FxIndexMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>,
939+
mergeable_tests: FxIndexMap<MergeableTestKey, Vec<(DocTestBuilder, ScrapedDocTest)>>,
933940

934941
rustdoc_options: Arc<RustdocOptions>,
935942
opts: GlobalTestOptions,
@@ -997,7 +1004,17 @@ impl CreateRunnableDocTests {
9971004
let test_desc = self.generate_test_desc_and_fn(doctest, scraped_test);
9981005
self.standalone_tests.push(test_desc);
9991006
} else {
1000-
self.mergeable_tests.entry(edition).or_default().push((doctest, scraped_test));
1007+
self.mergeable_tests
1008+
.entry(MergeableTestKey {
1009+
edition,
1010+
global_crate_attrs_hash: {
1011+
let mut hasher = FxHasher::default();
1012+
scraped_test.global_crate_attrs.hash(&mut hasher);
1013+
hasher.finish()
1014+
},
1015+
})
1016+
.or_default()
1017+
.push((doctest, scraped_test));
10011018
}
10021019
}
10031020

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)