Skip to content

Commit eb8cd61

Browse files
committed
Allow #![doc(test(attr(..)))] doctests to be again merged together
1 parent 918e4da commit eb8cd61

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;
@@ -281,7 +282,7 @@ pub(crate) fn run_tests(
281282
rustdoc_options: &Arc<RustdocOptions>,
282283
unused_extern_reports: &Arc<Mutex<Vec<UnusedExterns>>>,
283284
mut standalone_tests: Vec<test::TestDescAndFn>,
284-
mergeable_tests: FxIndexMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>,
285+
mergeable_tests: FxIndexMap<MergeableTestKey, Vec<(DocTestBuilder, ScrapedDocTest)>>,
285286
// We pass this argument so we can drop it manually before using `exit`.
286287
mut temp_dir: Option<TempDir>,
287288
) {
@@ -296,7 +297,7 @@ pub(crate) fn run_tests(
296297
let mut ran_edition_tests = 0;
297298
let target_str = rustdoc_options.target.to_string();
298299

299-
for (edition, mut doctests) in mergeable_tests {
300+
for (MergeableTestKey { edition, global_crate_attrs_hash }, mut doctests) in mergeable_tests {
300301
if doctests.is_empty() {
301302
continue;
302303
}
@@ -306,8 +307,8 @@ pub(crate) fn run_tests(
306307

307308
let rustdoc_test_options = IndividualTestOptions::new(
308309
rustdoc_options,
309-
&Some(format!("merged_doctest_{edition}")),
310-
PathBuf::from(format!("doctest_{edition}.rs")),
310+
&Some(format!("merged_doctest_{edition}_{global_crate_attrs_hash}")),
311+
PathBuf::from(format!("doctest_{edition}_{global_crate_attrs_hash}.rs")),
311312
);
312313

313314
for (doctest, scraped_test) in &doctests {
@@ -885,9 +886,15 @@ pub(crate) trait DocTestVisitor {
885886
fn visit_header(&mut self, _name: &str, _level: u32) {}
886887
}
887888

889+
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
890+
pub(crate) struct MergeableTestKey {
891+
edition: Edition,
892+
global_crate_attrs_hash: u64,
893+
}
894+
888895
struct CreateRunnableDocTests {
889896
standalone_tests: Vec<test::TestDescAndFn>,
890-
mergeable_tests: FxIndexMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>,
897+
mergeable_tests: FxIndexMap<MergeableTestKey, Vec<(DocTestBuilder, ScrapedDocTest)>>,
891898

892899
rustdoc_options: Arc<RustdocOptions>,
893900
opts: GlobalTestOptions,
@@ -955,7 +962,17 @@ impl CreateRunnableDocTests {
955962
let test_desc = self.generate_test_desc_and_fn(doctest, scraped_test);
956963
self.standalone_tests.push(test_desc);
957964
} else {
958-
self.mergeable_tests.entry(edition).or_default().push((doctest, scraped_test));
965+
self.mergeable_tests
966+
.entry(MergeableTestKey {
967+
edition,
968+
global_crate_attrs_hash: {
969+
let mut hasher = FxHasher::default();
970+
scraped_test.global_crate_attrs.hash(&mut hasher);
971+
hasher.finish()
972+
},
973+
})
974+
.or_default()
975+
.push((doctest, scraped_test));
959976
}
960977
}
961978

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)