Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions src/librustdoc/doctest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,10 @@ fn add_exe_suffix(input: String, target: &TargetTuple) -> String {
input + &exe_suffix
}

fn wrapped_rustc_command(rustc_wrappers: &[PathBuf], rustc_binary: &Path) -> Command {
fn wrapped_rustc_command<'a>(
rustc_wrappers: &'a [PathBuf],
rustc_binary: &'a Path,
) -> (Command, &'a Path) {
let mut args = rustc_wrappers.iter().map(PathBuf::as_path).chain([rustc_binary]);

let exe = args.next().expect("unable to create rustc command");
Expand All @@ -510,7 +513,7 @@ fn wrapped_rustc_command(rustc_wrappers: &[PathBuf], rustc_binary: &Path) -> Com
command.arg(arg);
}

command
(command, rustc_wrappers.first().map(|p| &**p).unwrap_or(rustc_binary))
}

/// Information needed for running a bundle of doctests.
Expand Down Expand Up @@ -630,7 +633,8 @@ fn run_test(
.test_builder
.as_deref()
.unwrap_or_else(|| rustc_interface::util::rustc_path(sysroot).expect("found rustc"));
let mut compiler = wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary);
let (mut compiler, binary_path) =
wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary);

compiler.args(&compiler_args);

Expand Down Expand Up @@ -671,7 +675,13 @@ fn run_test(

debug!("compiler invocation for doctest: {compiler:?}");

let mut child = compiler.spawn().expect("Failed to spawn rustc process");
let mut child = match compiler.spawn() {
Ok(child) => child,
Err(error) => {
eprintln!("Failed to spawn {binary_path:?}: {error:?}");
return (Duration::default(), Err(TestFailure::CompileError));
}
};
let output = if let Some(merged_test_code) = &doctest.merged_test_code {
// compile-fail tests never get merged, so this should always pass
let status = child.wait().expect("Failed to wait");
Expand All @@ -680,7 +690,7 @@ fn run_test(
// build it now
let runner_input_file = doctest.path_for_merged_doctest_runner();

let mut runner_compiler =
let (mut runner_compiler, binary_path) =
wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary);
// the test runner does not contain any user-written code, so this doesn't allow
// the user to exploit nightly-only features on stable
Expand Down Expand Up @@ -733,7 +743,13 @@ fn run_test(
let status = if !status.success() {
status
} else {
let mut child_runner = runner_compiler.spawn().expect("Failed to spawn rustc process");
let mut child_runner = match runner_compiler.spawn() {
Ok(child) => child,
Err(error) => {
eprintln!("Failed to spawn {binary_path:?}: {error:?}");
return (Duration::default(), Err(TestFailure::CompileError));
}
};
child_runner.wait().expect("Failed to wait")
};

Expand Down
3 changes: 3 additions & 0 deletions tests/run-make/rustdoc-test-builder/foo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//! ```
//! let x = 12;
//! ```
22 changes: 22 additions & 0 deletions tests/run-make/rustdoc-test-builder/rmake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// This test ensures that if the rustdoc test binary is not executable, it will
// gracefully fail and not panic.

//@ needs-target-std

use run_make_support::{path, rfs, rustdoc};

fn main() {
let absolute_path = path("foo.rs").canonicalize().expect("failed to get absolute path");
let output = rustdoc()
.input("foo.rs")
.arg("--test")
.arg("-Zunstable-options")
.arg("--test-builder")
.arg(&absolute_path)
.run_fail();

output.assert_stdout_contains("Failed to spawn ");
output.assert_stderr_not_contains("the compiler unexpectedly panicked. this is a bug.");
// Just in case...
output.assert_stdout_not_contains("the compiler unexpectedly panicked. this is a bug.");
}
Loading