Skip to content

Commit fc90106

Browse files
Fix should_panic in doctest
1 parent 5b5e219 commit fc90106

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
@@ -406,7 +406,7 @@ pub(crate) fn run_tests(
406406
// We failed to compile all compatible tests as one so we push them into the
407407
// `standalone_tests` doctests.
408408
debug!("Failed to compile compatible doctests for edition {} all at once", edition);
409-
for (doctest, scraped_test) in doctests {
409+
for (pos, (doctest, scraped_test)) in doctests.into_iter().enumerate() {
410410
doctest.generate_unique_doctest(
411411
&scraped_test.text,
412412
scraped_test.langstr.test_harness,
@@ -419,6 +419,7 @@ pub(crate) fn run_tests(
419419
opts.clone(),
420420
Arc::clone(rustdoc_options),
421421
unused_extern_reports.clone(),
422+
pos,
422423
));
423424
}
424425
}
@@ -548,11 +549,21 @@ pub(crate) struct RunnableDocTest {
548549
}
549550

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

575587
// the actual test runner is a separate component, built with nightly-only features;
576588
// build it now
577-
let runner_input_file = doctest.path_for_merged_doctest_runner();
589+
let runner_input_file = doctest.path_for_merged_doctest_runner(id);
578590

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

591607
// Deduplicate passed -L directory paths, since usually all dependencies will be in the
592608
// same directory (e.g. target/debug/deps from Cargo).
@@ -605,11 +621,12 @@ fn compile_merged_doctest_and_caller_binary(
605621
}
606622
}
607623
}
608-
let output_bundle_file = doctest
609-
.test_opts
610-
.outdir
611-
.path()
612-
.join(format!("libdoctest_bundle_{edition}.rlib", edition = doctest.edition));
624+
let filename = if let Some(id) = id {
625+
format!("libdoctest_bundle_id_{id}.rlib")
626+
} else {
627+
format!("libdoctest_bundle_{edition}.rlib", edition = doctest.edition)
628+
};
629+
let output_bundle_file = doctest.test_opts.outdir.path().join(filename);
613630
extern_path.push(&output_bundle_file);
614631
runner_compiler.arg(extern_path);
615632
runner_compiler.arg(&runner_input_file);
@@ -647,6 +664,7 @@ fn run_test(
647664
rustdoc_options: &RustdocOptions,
648665
supports_color: bool,
649666
report_unused_externs: impl Fn(UnusedExterns),
667+
doctest_id: usize,
650668
) -> (Duration, Result<(), RustdocResult>) {
651669
let langstr = &doctest.langstr;
652670
// Make sure we emit well-formed executable names for our target.
@@ -727,12 +745,19 @@ fn run_test(
727745

728746
compiler.args(&compiler_args);
729747

748+
compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", &doctest.test_opts.path);
749+
compiler.env(
750+
"UNSTABLE_RUSTDOC_TEST_LINE",
751+
format!("{}", doctest.line as isize - doctest.full_test_line_offset as isize),
752+
);
730753
// If this is a merged doctest, we need to write it into a file instead of using stdin
731754
// because if the size of the merged doctests is too big, it'll simply break stdin.
732-
if doctest.is_multiple_tests() {
755+
if doctest.is_multiple_tests() || (!langstr.compile_fail && langstr.should_panic) {
733756
// It makes the compilation failure much faster if it is for a combined doctest.
734757
compiler.arg("--error-format=short");
735-
let input_file = doctest.path_for_merged_doctest_bundle();
758+
let input_file = doctest.path_for_merged_doctest_bundle(
759+
if !langstr.compile_fail && langstr.should_panic { Some(doctest_id) } else { None },
760+
);
736761
if std::fs::write(&input_file, &doctest.full_test_code).is_err() {
737762
// If we cannot write this file for any reason, we leave. All combined tests will be
738763
// tested as standalone tests.
@@ -751,11 +776,6 @@ fn run_test(
751776
.arg(input_file);
752777
} else {
753778
compiler.arg("--crate-type=bin").arg("-o").arg(&output_file);
754-
compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", &doctest.test_opts.path);
755-
compiler.env(
756-
"UNSTABLE_RUSTDOC_TEST_LINE",
757-
format!("{}", doctest.line as isize - doctest.full_test_line_offset as isize),
758-
);
759779
compiler.arg("-");
760780
compiler.stdin(Stdio::piped());
761781
compiler.stderr(Stdio::piped());
@@ -774,6 +794,37 @@ fn run_test(
774794
compiler_args,
775795
merged_test_code,
776796
instant,
797+
None,
798+
) {
799+
Ok(out) => out,
800+
Err(err) => return err,
801+
}
802+
} else if !langstr.compile_fail && langstr.should_panic {
803+
match compile_merged_doctest_and_caller_binary(
804+
child,
805+
&doctest,
806+
rustdoc_options,
807+
rustc_binary,
808+
&output_file,
809+
compiler_args,
810+
&format!(
811+
"\
812+
#![feature(test)]
813+
extern crate test;
814+
815+
use std::process::{{ExitCode, Termination}};
816+
817+
fn main() -> ExitCode {{
818+
if test::cannot_handle_should_panic() {{
819+
ExitCode::SUCCESS
820+
}} else {{
821+
extern crate doctest_bundle_id_{doctest_id} as doctest_bundle;
822+
doctest_bundle::main().report()
823+
}}
824+
}}"
825+
),
826+
instant,
827+
Some(doctest_id),
777828
) {
778829
Ok(out) => out,
779830
Err(err) => return err,
@@ -1087,6 +1138,7 @@ impl CreateRunnableDocTests {
10871138
self.opts.clone(),
10881139
Arc::clone(&self.rustdoc_options),
10891140
self.unused_extern_reports.clone(),
1141+
self.standalone_tests.len(),
10901142
)
10911143
}
10921144
}
@@ -1097,6 +1149,7 @@ fn generate_test_desc_and_fn(
10971149
opts: GlobalTestOptions,
10981150
rustdoc_options: Arc<RustdocOptions>,
10991151
unused_externs: Arc<Mutex<Vec<UnusedExterns>>>,
1152+
doctest_id: usize,
11001153
) -> test::TestDescAndFn {
11011154
let target_str = rustdoc_options.target.to_string();
11021155
let rustdoc_test_options =
@@ -1131,6 +1184,7 @@ fn generate_test_desc_and_fn(
11311184
scraped_test,
11321185
rustdoc_options,
11331186
unused_externs,
1187+
doctest_id,
11341188
)
11351189
})),
11361190
}
@@ -1143,6 +1197,7 @@ fn doctest_run_fn(
11431197
scraped_test: ScrapedDocTest,
11441198
rustdoc_options: Arc<RustdocOptions>,
11451199
unused_externs: Arc<Mutex<Vec<UnusedExterns>>>,
1200+
doctest_id: usize,
11461201
) -> Result<(), String> {
11471202
#[cfg(not(bootstrap))]
11481203
if scraped_test.langstr.should_panic && test::cannot_handle_should_panic() {
@@ -1168,8 +1223,13 @@ fn doctest_run_fn(
11681223
no_run: scraped_test.no_run(&rustdoc_options),
11691224
merged_test_code: None,
11701225
};
1171-
let (_, res) =
1172-
run_test(runnable_test, &rustdoc_options, doctest.supports_color, report_unused_externs);
1226+
let (_, res) = run_test(
1227+
runnable_test,
1228+
&rustdoc_options,
1229+
doctest.supports_color,
1230+
report_unused_externs,
1231+
doctest_id,
1232+
);
11731233

11741234
if let Err(err) = res {
11751235
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)