Skip to content

Commit 46e9dbc

Browse files
committed
Add check builds to support compile_fail doc-tests
1 parent f7bfbe7 commit 46e9dbc

File tree

1 file changed

+67
-14
lines changed

1 file changed

+67
-14
lines changed

cargo-miri/bin.rs

+67-14
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,22 @@ fn exec(mut cmd: Command) {
157157
}
158158
}
159159

160+
/// Execute the command and pipe `input` into its stdin.
161+
/// If it fails, fail this process with the same exit code.
162+
/// Otherwise, continue.
163+
fn exec_with_pipe(mut cmd: Command, input: &[u8]) {
164+
cmd.stdin(std::process::Stdio::piped());
165+
let mut child = cmd.spawn().expect("failed to spawn process");
166+
{
167+
let stdin = child.stdin.as_mut().expect("failed to open stdin");
168+
stdin.write_all(input).expect("failed to write out test source");
169+
}
170+
let exit_status = child.wait().expect("failed to run command");
171+
if exit_status.success().not() {
172+
std::process::exit(exit_status.code().unwrap_or(-1))
173+
}
174+
}
175+
160176
fn xargo_version() -> Option<(u32, u32, u32)> {
161177
let out = xargo_check().arg("--version").output().ok()?;
162178
if !out.status.success() {
@@ -598,6 +614,34 @@ fn phase_cargo_rustc(args: env::Args) {
598614
// (Need to do this here as cargo moves that "binary" to a different place before running it.)
599615
info.store(&out_filename("", ".exe"));
600616

617+
// Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`,
618+
// so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build.
619+
if std::env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() {
620+
let mut cmd = miri();
621+
622+
// use our own sysroot
623+
if !has_arg_flag("--sysroot") {
624+
let sysroot = env::var_os("MIRI_SYSROOT")
625+
.expect("the wrapper should have set MIRI_SYSROOT");
626+
cmd.arg("--sysroot").arg(sysroot);
627+
}
628+
629+
// don't go into "code generation" (i.e. validation)
630+
if info.args.iter().position(|arg| arg.starts_with("--emit=")).is_none() {
631+
cmd.arg("--emit=dep-info,metadata");
632+
}
633+
634+
cmd.args(info.args);
635+
cmd.env("MIRI_BE_RUSTC", "1");
636+
637+
if verbose {
638+
eprintln!("[cargo-miri rustc] captured input:\n{}", std::str::from_utf8(&info.stdin).unwrap());
639+
eprintln!("[cargo-miri rustc] {:?}", cmd);
640+
}
641+
642+
exec_with_pipe(cmd, &info.stdin);
643+
}
644+
601645
return;
602646
}
603647

@@ -748,31 +792,40 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) {
748792
eprintln!("[cargo-miri runner] {:?}", cmd);
749793
}
750794

751-
cmd.stdin(std::process::Stdio::piped());
752-
let mut child = cmd.spawn().expect("failed to spawn miri process");
753-
{
754-
let stdin = child.stdin.as_mut().expect("failed to open stdin");
755-
stdin.write_all(&info.stdin).expect("failed to write out test source");
756-
}
757-
let exit_status = child.wait().expect("failed to run command");
758-
if exit_status.success().not() {
759-
std::process::exit(exit_status.code().unwrap_or(-1))
760-
}
795+
exec_with_pipe(cmd, &info.stdin)
761796
}
762797

763-
fn phase_cargo_rustdoc(fst_arg: &str, args: env::Args) {
798+
fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) {
764799
let verbose = std::env::var_os("MIRI_VERBOSE").is_some();
765800

766801
// phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here;
767802
// just default to a straight-forward invocation for now:
768803
let mut cmd = Command::new(OsString::from("rustdoc"));
769804

770-
// just pass everything through until we find a reason not to do that:
805+
let extern_flag = "--extern";
806+
assert!(fst_arg != extern_flag);
771807
cmd.arg(fst_arg);
772-
cmd.args(args);
773808

774-
cmd.arg("-Z").arg("unstable-options");
809+
// Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files.
810+
while let Some(arg) = args.next() {
811+
if arg == extern_flag {
812+
cmd.arg(extern_flag); // always forward flag, but adjust filename
813+
// `--extern` is always passed as a separate argument by cargo.
814+
let next_arg = args.next().expect("`--extern` should be followed by a filename");
815+
if let Some(next_lib) = next_arg.strip_suffix(".rlib") {
816+
// If this is an rlib, make it an rmeta.
817+
cmd.arg(format!("{}.rmeta", next_lib));
818+
} else {
819+
// Some other extern file (e.g., a `.so`). Forward unchanged.
820+
cmd.arg(next_arg);
821+
}
822+
} else {
823+
cmd.arg(arg);
824+
}
825+
}
775826

827+
cmd.arg("-Z").arg("unstable-options");
828+
776829
let cargo_miri_path = std::env::current_exe().expect("current executable path invalid");
777830
cmd.arg("--test-builder").arg(&cargo_miri_path);
778831
cmd.arg("--runtool").arg(&cargo_miri_path);

0 commit comments

Comments
 (0)