Skip to content

Commit 0ae80cc

Browse files
Fix should_panic in doctest
1 parent 1d719a4 commit 0ae80cc

File tree

3 files changed

+88
-28
lines changed

3 files changed

+88
-28
lines changed

src/librustdoc/doctest.rs

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ pub(crate) fn run_tests(
407407
// We failed to compile all compatible tests as one so we push them into the
408408
// `standalone_tests` doctests.
409409
debug!("Failed to compile compatible doctests for edition {} all at once", edition);
410-
for (doctest, scraped_test) in doctests {
410+
for (pos, (doctest, scraped_test)) in doctests.into_iter().enumerate() {
411411
doctest.generate_unique_doctest(
412412
&scraped_test.text,
413413
scraped_test.langstr.test_harness,
@@ -420,6 +420,7 @@ pub(crate) fn run_tests(
420420
opts.clone(),
421421
Arc::clone(rustdoc_options),
422422
unused_extern_reports.clone(),
423+
pos,
423424
));
424425
}
425426
}
@@ -549,11 +550,21 @@ pub(crate) struct RunnableDocTest {
549550
}
550551

551552
impl RunnableDocTest {
552-
fn path_for_merged_doctest_bundle(&self) -> PathBuf {
553-
self.test_opts.outdir.path().join(format!("doctest_bundle_{}.rs", self.edition))
553+
fn path_for_merged_doctest_bundle(&self, id: Option<usize>) -> PathBuf {
554+
let name = if let Some(id) = id {
555+
format!("doctest_bundle_id_{id}.rs")
556+
} else {
557+
format!("doctest_bundle_{}.rs", self.edition)
558+
};
559+
self.test_opts.outdir.path().join(name)
554560
}
555-
fn path_for_merged_doctest_runner(&self) -> PathBuf {
556-
self.test_opts.outdir.path().join(format!("doctest_runner_{}.rs", self.edition))
561+
fn path_for_merged_doctest_runner(&self, id: Option<usize>) -> PathBuf {
562+
let name = if let Some(id) = id {
563+
format!("doctest_runner_id_{id}.rs")
564+
} else {
565+
format!("doctest_runner_{}.rs", self.edition)
566+
};
567+
self.test_opts.outdir.path().join(name)
557568
}
558569
fn is_multiple_tests(&self) -> bool {
559570
self.merged_test_code.is_some()
@@ -569,13 +580,14 @@ fn compile_merged_doctest_and_caller_binary(
569580
compiler_args: Vec<String>,
570581
test_code: &str,
571582
instant: Instant,
583+
id: Option<usize>,
572584
) -> Result<process::Output, (Duration, Result<(), RustdocResult>)> {
573585
// compile-fail tests never get merged, so this should always pass
574586
let status = child.wait().expect("Failed to wait");
575587

576588
// the actual test runner is a separate component, built with nightly-only features;
577589
// build it now
578-
let runner_input_file = doctest.path_for_merged_doctest_runner();
590+
let runner_input_file = doctest.path_for_merged_doctest_runner(id);
579591

580592
let mut runner_compiler =
581593
wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary);
@@ -584,10 +596,14 @@ fn compile_merged_doctest_and_caller_binary(
584596
runner_compiler.env("RUSTC_BOOTSTRAP", "1");
585597
runner_compiler.args(compiler_args);
586598
runner_compiler.args(["--crate-type=bin", "-o"]).arg(output_file);
587-
let mut extern_path = std::ffi::OsString::from(format!(
588-
"--extern=doctest_bundle_{edition}=",
589-
edition = doctest.edition
590-
));
599+
let mut extern_path = if let Some(id) = id {
600+
std::ffi::OsString::from(format!("--extern=doctest_bundle_id_{id}="))
601+
} else {
602+
std::ffi::OsString::from(format!(
603+
"--extern=doctest_bundle_{edition}=",
604+
edition = doctest.edition
605+
))
606+
};
591607

592608
// Deduplicate passed -L directory paths, since usually all dependencies will be in the
593609
// same directory (e.g. target/debug/deps from Cargo).
@@ -606,11 +622,12 @@ fn compile_merged_doctest_and_caller_binary(
606622
}
607623
}
608624
}
609-
let output_bundle_file = doctest
610-
.test_opts
611-
.outdir
612-
.path()
613-
.join(format!("libdoctest_bundle_{edition}.rlib", edition = doctest.edition));
625+
let filename = if let Some(id) = id {
626+
format!("libdoctest_bundle_id_{id}.rlib")
627+
} else {
628+
format!("libdoctest_bundle_{edition}.rlib", edition = doctest.edition)
629+
};
630+
let output_bundle_file = doctest.test_opts.outdir.path().join(filename);
614631
extern_path.push(&output_bundle_file);
615632
runner_compiler.arg(extern_path);
616633
runner_compiler.arg(&runner_input_file);
@@ -648,6 +665,7 @@ fn run_test(
648665
rustdoc_options: &RustdocOptions,
649666
supports_color: bool,
650667
report_unused_externs: impl Fn(UnusedExterns),
668+
doctest_id: usize,
651669
) -> (Duration, Result<(), RustdocResult>) {
652670
let langstr = &doctest.langstr;
653671
// Make sure we emit well-formed executable names for our target.
@@ -728,12 +746,19 @@ fn run_test(
728746

729747
compiler.args(&compiler_args);
730748

749+
compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", &doctest.test_opts.path);
750+
compiler.env(
751+
"UNSTABLE_RUSTDOC_TEST_LINE",
752+
format!("{}", doctest.line as isize - doctest.full_test_line_offset as isize),
753+
);
731754
// If this is a merged doctest, we need to write it into a file instead of using stdin
732755
// because if the size of the merged doctests is too big, it'll simply break stdin.
733-
if doctest.is_multiple_tests() {
756+
if doctest.is_multiple_tests() || (!langstr.compile_fail && langstr.should_panic) {
734757
// It makes the compilation failure much faster if it is for a combined doctest.
735758
compiler.arg("--error-format=short");
736-
let input_file = doctest.path_for_merged_doctest_bundle();
759+
let input_file = doctest.path_for_merged_doctest_bundle(
760+
if !langstr.compile_fail && langstr.should_panic { Some(doctest_id) } else { None },
761+
);
737762
if std::fs::write(&input_file, &doctest.full_test_code).is_err() {
738763
// If we cannot write this file for any reason, we leave. All combined tests will be
739764
// tested as standalone tests.
@@ -752,11 +777,6 @@ fn run_test(
752777
.arg(input_file);
753778
} else {
754779
compiler.arg("--crate-type=bin").arg("-o").arg(&output_file);
755-
compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", &doctest.test_opts.path);
756-
compiler.env(
757-
"UNSTABLE_RUSTDOC_TEST_LINE",
758-
format!("{}", doctest.line as isize - doctest.full_test_line_offset as isize),
759-
);
760780
compiler.arg("-");
761781
compiler.stdin(Stdio::piped());
762782
compiler.stderr(Stdio::piped());
@@ -775,6 +795,37 @@ fn run_test(
775795
compiler_args,
776796
merged_test_code,
777797
instant,
798+
None,
799+
) {
800+
Ok(out) => out,
801+
Err(err) => return err,
802+
}
803+
} else if !langstr.compile_fail && langstr.should_panic {
804+
match compile_merged_doctest_and_caller_binary(
805+
child,
806+
&doctest,
807+
rustdoc_options,
808+
rustc_binary,
809+
&output_file,
810+
compiler_args,
811+
&format!(
812+
"\
813+
#![feature(test)]
814+
extern crate test;
815+
816+
use std::process::{{ExitCode, Termination}};
817+
818+
fn main() -> ExitCode {{
819+
if test::cannot_handle_should_panic() {{
820+
ExitCode::SUCCESS
821+
}} else {{
822+
extern crate doctest_bundle_id_{doctest_id} as doctest_bundle;
823+
doctest_bundle::main().report()
824+
}}
825+
}}"
826+
),
827+
instant,
828+
Some(doctest_id),
778829
) {
779830
Ok(out) => out,
780831
Err(err) => return err,
@@ -1091,6 +1142,7 @@ impl CreateRunnableDocTests {
10911142
self.opts.clone(),
10921143
Arc::clone(&self.rustdoc_options),
10931144
self.unused_extern_reports.clone(),
1145+
self.standalone_tests.len(),
10941146
)
10951147
}
10961148
}
@@ -1101,6 +1153,7 @@ fn generate_test_desc_and_fn(
11011153
opts: GlobalTestOptions,
11021154
rustdoc_options: Arc<RustdocOptions>,
11031155
unused_externs: Arc<Mutex<Vec<UnusedExterns>>>,
1156+
doctest_id: usize,
11041157
) -> test::TestDescAndFn {
11051158
let target_str = rustdoc_options.target.to_string();
11061159
let rustdoc_test_options =
@@ -1135,6 +1188,7 @@ fn generate_test_desc_and_fn(
11351188
scraped_test,
11361189
rustdoc_options,
11371190
unused_externs,
1191+
doctest_id,
11381192
)
11391193
})),
11401194
}
@@ -1147,6 +1201,7 @@ fn doctest_run_fn(
11471201
scraped_test: ScrapedDocTest,
11481202
rustdoc_options: Arc<RustdocOptions>,
11491203
unused_externs: Arc<Mutex<Vec<UnusedExterns>>>,
1204+
doctest_id: usize,
11501205
) -> Result<(), String> {
11511206
#[cfg(not(bootstrap))]
11521207
if scraped_test.langstr.should_panic && test::cannot_handle_should_panic() {
@@ -1172,8 +1227,13 @@ fn doctest_run_fn(
11721227
no_run: scraped_test.no_run(&rustdoc_options),
11731228
merged_test_code: None,
11741229
};
1175-
let (_, res) =
1176-
run_test(runnable_test, &rustdoc_options, doctest.supports_color, report_unused_externs);
1230+
let (_, res) = run_test(
1231+
runnable_test,
1232+
&rustdoc_options,
1233+
doctest.supports_color,
1234+
report_unused_externs,
1235+
doctest_id,
1236+
);
11771237

11781238
if let Err(err) = res {
11791239
eprint!("{err}");

src/librustdoc/doctest/make.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -388,17 +388,17 @@ impl DocTestBuilder {
388388
let (main_pre, main_post) = if returns_result {
389389
(
390390
format!(
391-
"fn main() {{ {inner_attr}fn {inner_fn_name}() -> core::result::Result<(), impl core::fmt::Debug> {{\n",
391+
"pub fn main() {{ {inner_attr}fn {inner_fn_name}() -> core::result::Result<(), impl core::fmt::Debug> {{\n",
392392
),
393393
format!("\n}} {inner_fn_name}().unwrap() }}"),
394394
)
395395
} else if self.test_id.is_some() {
396396
(
397-
format!("fn main() {{ {inner_attr}fn {inner_fn_name}() {{\n",),
397+
format!("pub fn main() {{ {inner_attr}fn {inner_fn_name}() {{\n",),
398398
format!("\n}} {inner_fn_name}() }}"),
399399
)
400400
} else {
401-
("fn main() {\n".into(), "\n}".into())
401+
("pub fn main() {\n".into(), "\n}".into())
402402
};
403403
// Note on newlines: We insert a line/newline *before*, and *after*
404404
// the doctest and adjust the `line_offset` accordingly.

src/librustdoc/doctest/runner.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ std::process::Termination::report(test::test_main(test_args, tests, None))
197197
merged_test_code: Some(code),
198198
};
199199
let (duration, ret) =
200-
run_test(runnable_test, rustdoc_options, self.supports_color, |_: UnusedExterns| {});
200+
run_test(runnable_test, rustdoc_options, self.supports_color, |_: UnusedExterns| {}, 0);
201201
(
202202
duration,
203203
if let Err(RustdocResult::CompileError) = ret { Err(()) } else { Ok(ret.is_ok()) },

0 commit comments

Comments
 (0)