Skip to content

Commit 5e9a025

Browse files
committed
Auto merge of #3409 - RalfJung:rustup, r=RalfJung
Rustup, fix rustdoc sysroot issue This uses a different approach to resolve #3404: we entirely move the responsibility of setting miri-sysroot to whatever *invokes* the Miri driver. cargo-miri knows whether it is inside rustdoc or not and can adjust accordingly. I previously avoided doing that because there are a bunch of places that are invoking the driver (cargo-miri, the ui test suite, `./miri run`, `./x.py run miri`) and they all need to be adjusted now. But it is also somewhat less fragile as we usually have more information there -- and we can just decide that `./miri run file.rs --sysroot path` is not supported.
2 parents 6a72dc6 + d23df54 commit 5e9a025

File tree

8 files changed

+85
-90
lines changed

8 files changed

+85
-90
lines changed

README.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -464,10 +464,9 @@ Moreover, Miri recognizes some environment variables:
464464
standard library that it will build and use for interpretation. This directory
465465
must point to the `library` subdirectory of a `rust-lang/rust` repository
466466
checkout.
467-
* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When
467+
* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) indicates the sysroot to use. When
468468
using `cargo miri`, this skips the automatic setup -- only set this if you do not want to use the
469-
automatically created sysroot. For directly invoking the Miri driver, this variable (or a
470-
`--sysroot` flag) is mandatory. When invoking `cargo miri setup`, this indicates where the sysroot
469+
automatically created sysroot. When invoking `cargo miri setup`, this indicates where the sysroot
471470
will be put.
472471
* `MIRI_TEST_TARGET` (recognized by the test suite and the `./miri` script) indicates which target
473472
architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same

cargo-miri/src/phases.rs

+33-26
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,6 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
168168
// Forward all further arguments (not consumed by `ArgSplitFlagValue`) to cargo.
169169
cmd.args(args);
170170

171-
// Let it know where the Miri sysroot lives.
172-
cmd.env("MIRI_SYSROOT", miri_sysroot);
173171
// Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation,
174172
// i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish
175173
// the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.)
@@ -204,6 +202,8 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
204202
// Set rustdoc to us as well, so we can run doctests.
205203
cmd.env("RUSTDOC", &cargo_miri_path);
206204

205+
// Forward some crucial information to our own re-invocations.
206+
cmd.env("MIRI_SYSROOT", miri_sysroot);
207207
cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata));
208208
if verbose > 0 {
209209
cmd.env("MIRI_VERBOSE", verbose.to_string()); // This makes the other phases verbose.
@@ -244,6 +244,16 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
244244
/// Cargo does not give us this information directly, so we need to check
245245
/// various command-line flags.
246246
fn is_runnable_crate() -> bool {
247+
// Determine whether this is cargo invoking rustc to get some infos. Ideally we'd check "is
248+
// there a filename passed to rustc", but that's very hard as we would have to know whether
249+
// e.g. `--print foo` is a booolean flag `--print` followed by filename `foo` or equivalent
250+
// to `--print=foo`. So instead we use this more fragile approach of detecting the presence
251+
// of a "query" flag rather than the absence of a filename.
252+
let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV");
253+
if info_query {
254+
// Nothing to run.
255+
return false;
256+
}
247257
let is_bin = get_arg_flag_value("--crate-type").as_deref().unwrap_or("bin") == "bin";
248258
let is_test = has_arg_flag("--test");
249259
is_bin || is_test
@@ -290,8 +300,6 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
290300
let verbose = std::env::var("MIRI_VERBOSE")
291301
.map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer"));
292302
let target_crate = is_target_crate();
293-
// Determine whether this is cargo invoking rustc to get some infos.
294-
let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV");
295303

296304
let store_json = |info: CrateRunInfo| {
297305
if get_arg_flag_value("--emit").unwrap_or_default().split(',').any(|e| e == "dep-info") {
@@ -318,7 +326,7 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
318326
}
319327
};
320328

321-
let runnable_crate = !info_query && is_runnable_crate();
329+
let runnable_crate = is_runnable_crate();
322330

323331
if runnable_crate && target_crate {
324332
assert!(
@@ -392,7 +400,9 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
392400
let mut emit_link_hack = false;
393401
// Arguments are treated very differently depending on whether this crate is
394402
// for interpretation by Miri, or for use by a build script / proc macro.
395-
if !info_query && target_crate {
403+
if target_crate {
404+
// Set the sysroot.
405+
cmd.arg("--sysroot").arg(env::var_os("MIRI_SYSROOT").unwrap());
396406
// Forward arguments, but remove "link" from "--emit" to make this a check-only build.
397407
let emit_flag = "--emit";
398408
while let Some(arg) = args.next() {
@@ -426,17 +436,14 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
426436
cmd.arg("-C").arg("panic=abort");
427437
}
428438
} else {
429-
// For host crates (but not when we are just printing some info),
430-
// we might still have to set the sysroot.
431-
if !info_query {
432-
// When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly
433-
// due to bootstrap complications.
434-
if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") {
435-
cmd.arg("--sysroot").arg(sysroot);
436-
}
439+
// This is a host crate.
440+
// When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly
441+
// due to bootstrap complications.
442+
if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") {
443+
cmd.arg("--sysroot").arg(sysroot);
437444
}
438445

439-
// For host crates or when we are printing, just forward everything.
446+
// Forward everything.
440447
cmd.args(args);
441448
}
442449

@@ -448,9 +455,7 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
448455

449456
// Run it.
450457
if verbose > 0 {
451-
eprintln!(
452-
"[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} info_query={info_query}"
453-
);
458+
eprintln!("[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate}");
454459
}
455460

456461
// Create a stub .rlib file if "link" was requested by cargo.
@@ -531,6 +536,12 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
531536
cmd.env(name, val);
532537
}
533538

539+
if phase != RunnerPhase::Rustdoc {
540+
// Set the sysroot. Not necessary in rustdoc, where we already set the sysroot when invoking
541+
// rustdoc itself, which will forward that flag when invoking rustc (i.e., us), so the flag
542+
// is present in `info.args`.
543+
cmd.arg("--sysroot").arg(env::var_os("MIRI_SYSROOT").unwrap());
544+
}
534545
// Forward rustc arguments.
535546
// We need to patch "--extern" filenames because we forced a check-only
536547
// build without cargo knowing about that: replace `.rlib` suffix by
@@ -539,15 +550,13 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
539550
// but when we run here, cargo does not interpret the JSON any more. `--json`
540551
// then also needs to be dropped.
541552
let mut args = info.args.into_iter();
542-
let error_format_flag = "--error-format";
543-
let json_flag = "--json";
544553
while let Some(arg) = args.next() {
545554
if arg == "--extern" {
546555
forward_patched_extern_arg(&mut args, &mut cmd);
547-
} else if let Some(suffix) = arg.strip_prefix(error_format_flag) {
556+
} else if let Some(suffix) = arg.strip_prefix("--error-format") {
548557
assert!(suffix.starts_with('='));
549558
// Drop this argument.
550-
} else if let Some(suffix) = arg.strip_prefix(json_flag) {
559+
} else if let Some(suffix) = arg.strip_prefix("--json") {
551560
assert!(suffix.starts_with('='));
552561
// Drop this argument.
553562
} else {
@@ -585,13 +594,11 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) {
585594
// just default to a straight-forward invocation for now:
586595
let mut cmd = Command::new("rustdoc");
587596

588-
let extern_flag = "--extern";
589-
let runtool_flag = "--runtool";
590597
while let Some(arg) = args.next() {
591-
if arg == extern_flag {
598+
if arg == "--extern" {
592599
// Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files.
593600
forward_patched_extern_arg(&mut args, &mut cmd);
594-
} else if arg == runtool_flag {
601+
} else if arg == "--runtool" {
595602
// An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support.
596603
// Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag;
597604
// otherwise, we won't be called as rustdoc at all.

miri-script/src/commands.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::env;
22
use std::ffi::OsString;
33
use std::io::Write;
44
use std::ops::Not;
5+
use std::path::PathBuf;
56
use std::process;
67
use std::thread;
78
use std::time;
@@ -20,10 +21,11 @@ const JOSH_FILTER: &str =
2021
const JOSH_PORT: &str = "42042";
2122

2223
impl MiriEnv {
23-
fn build_miri_sysroot(&mut self, quiet: bool) -> Result<()> {
24-
if self.sh.var("MIRI_SYSROOT").is_ok() {
24+
/// Returns the location of the sysroot.
25+
fn build_miri_sysroot(&mut self, quiet: bool) -> Result<PathBuf> {
26+
if let Some(miri_sysroot) = self.sh.var_os("MIRI_SYSROOT") {
2527
// Sysroot already set, use that.
26-
return Ok(());
28+
return Ok(miri_sysroot.into());
2729
}
2830
let manifest_path = path!(self.miri_dir / "cargo-miri" / "Cargo.toml");
2931
let Self { toolchain, cargo_extra_flags, .. } = &self;
@@ -57,8 +59,8 @@ impl MiriEnv {
5759
.with_context(|| "`cargo miri setup` failed")?;
5860
panic!("`cargo miri setup` didn't fail again the 2nd time?");
5961
};
60-
self.sh.set_var("MIRI_SYSROOT", output);
61-
Ok(())
62+
self.sh.set_var("MIRI_SYSROOT", &output);
63+
Ok(output.into())
6264
}
6365
}
6466

@@ -502,7 +504,7 @@ impl Command {
502504
flags.iter().take_while(|arg| *arg != "--").any(|arg| *arg == "--edition");
503505

504506
// Prepare a sysroot.
505-
e.build_miri_sysroot(/* quiet */ true)?;
507+
let miri_sysroot = e.build_miri_sysroot(/* quiet */ true)?;
506508

507509
// Then run the actual command.
508510
let miri_manifest = path!(e.miri_dir / "Cargo.toml");
@@ -514,12 +516,12 @@ impl Command {
514516
if dep {
515517
cmd!(
516518
e.sh,
517-
"cargo +{toolchain} --quiet test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode {miri_flags...} {edition_flags...} {flags...}"
519+
"cargo +{toolchain} --quiet test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode --sysroot {miri_sysroot} {miri_flags...} {edition_flags...} {flags...}"
518520
).quiet().run()?;
519521
} else {
520522
cmd!(
521523
e.sh,
522-
"cargo +{toolchain} --quiet run {extra_flags...} --manifest-path {miri_manifest} -- {miri_flags...} {edition_flags...} {flags...}"
524+
"cargo +{toolchain} --quiet run {extra_flags...} --manifest-path {miri_manifest} -- --sysroot {miri_sysroot} {miri_flags...} {edition_flags...} {flags...}"
523525
).quiet().run()?;
524526
}
525527
Ok(())

rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
9b8d12cf4c2311203aea83315552b15993bd4f81
1+
42198bf562b548015e3eae3926c175c4aabb3a7b

src/bin/miri.rs

-19
Original file line numberDiff line numberDiff line change
@@ -271,25 +271,6 @@ fn run_compiler(
271271
callbacks: &mut (dyn rustc_driver::Callbacks + Send),
272272
using_internal_features: std::sync::Arc<std::sync::atomic::AtomicBool>,
273273
) -> ! {
274-
if target_crate {
275-
// Miri needs a custom sysroot for target crates.
276-
// If no `--sysroot` is given, the `MIRI_SYSROOT` env var is consulted to find where
277-
// that sysroot lives, and that is passed to rustc.
278-
let sysroot_flag = "--sysroot";
279-
if !args.iter().any(|e| e == sysroot_flag) {
280-
// Using the built-in default here would be plain wrong, so we *require*
281-
// the env var to make sure things make sense.
282-
let miri_sysroot = env::var("MIRI_SYSROOT").unwrap_or_else(|_| {
283-
show_error!(
284-
"Miri was invoked in 'target' mode without `MIRI_SYSROOT` or `--sysroot` being set"
285-
)
286-
});
287-
288-
args.push(sysroot_flag.to_owned());
289-
args.push(miri_sysroot);
290-
}
291-
}
292-
293274
// Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building
294275
// a "host" crate. That may cause procedural macros (and probably build scripts) to
295276
// depend on Miri-only symbols, such as `miri_resolve_frame`:

src/shims/intrinsics/simd.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
457457
let bitmask_len = u32::try_from(bitmask_len).unwrap();
458458

459459
// To read the mask, we transmute it to an integer.
460-
// That does the right thing wrt endianess.
460+
// That does the right thing wrt endianness.
461461
let mask_ty = this.machine.layouts.uint(mask.layout.size).unwrap();
462462
let mask = mask.transmute(mask_ty, this)?;
463463
let mask: u64 = this.read_scalar(&mask)?.to_bits(mask_ty.size)?.try_into().unwrap();
@@ -509,7 +509,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
509509
}
510510
}
511511
// We have to change the type of the place to be able to write `res` into it. This
512-
// transmutes the integer to an array, which does the right thing wrt endianess.
512+
// transmutes the integer to an array, which does the right thing wrt endianness.
513513
let dest =
514514
dest.transmute(this.machine.layouts.uint(dest.layout.size).unwrap(), this)?;
515515
this.write_int(res, &dest)?;

src/shims/unix/linux/fd/event.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl FileDescriptor for Event {
3838
}
3939

4040
/// A write call adds the 8-byte integer value supplied in
41-
/// its buffer (in native endianess) to the counter. The maximum value that may be
41+
/// its buffer (in native endianness) to the counter. The maximum value that may be
4242
/// stored in the counter is the largest unsigned 64-bit value
4343
/// minus 1 (i.e., 0xfffffffffffffffe). If the addition would
4444
/// cause the counter's value to exceed the maximum, then the
@@ -57,7 +57,7 @@ impl FileDescriptor for Event {
5757
) -> InterpResult<'tcx, io::Result<usize>> {
5858
let v1 = self.val.get();
5959
let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size
60-
// Convert from target endianess to host endianess.
60+
// Convert from target endianness to host endianness.
6161
let num = match tcx.sess.target.endian {
6262
Endian::Little => u64::from_le_bytes(bytes),
6363
Endian::Big => u64::from_be_bytes(bytes),

tests/ui.rs

+35-29
Original file line numberDiff line numberDiff line change
@@ -54,34 +54,13 @@ fn build_so_for_c_ffi_tests() -> PathBuf {
5454
so_file_path
5555
}
5656

57-
fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> Config {
57+
/// Does *not* set any args or env vars, since it is shared between the test runner and
58+
/// run_dep_mode.
59+
fn miri_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> Config {
5860
// Miri is rustc-like, so we create a default builder for rustc and modify it
5961
let mut program = CommandBuilder::rustc();
6062
program.program = miri_path();
6163

62-
// Add some flags we always want.
63-
program.args.push("-Dwarnings".into());
64-
program.args.push("-Dunused".into());
65-
program.args.push("-Ainternal_features".into());
66-
if let Ok(extra_flags) = env::var("MIRIFLAGS") {
67-
for flag in extra_flags.split_whitespace() {
68-
program.args.push(flag.into());
69-
}
70-
}
71-
program.args.push("-Zui-testing".into());
72-
program.args.push("--target".into());
73-
program.args.push(target.into());
74-
75-
// If we're on linux, and we're testing the extern-so functionality,
76-
// then build the shared object file for testing external C function calls
77-
// and push the relevant compiler flag.
78-
if cfg!(target_os = "linux") && path.starts_with("tests/extern-so/") {
79-
let so_file_path = build_so_for_c_ffi_tests();
80-
let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file=");
81-
flag.push(so_file_path.into_os_string());
82-
program.args.push(flag);
83-
}
84-
8564
let mut config = Config {
8665
target: Some(target.to_owned()),
8766
stderr_filters: STDERR.clone(),
@@ -119,17 +98,45 @@ fn run_tests(
11998
with_dependencies: bool,
12099
tmpdir: &Path,
121100
) -> Result<()> {
122-
let mut config = test_config(target, path, mode, with_dependencies);
101+
let mut config = miri_config(target, path, mode, with_dependencies);
123102

124103
// Add a test env var to do environment communication tests.
125104
config.program.envs.push(("MIRI_ENV_VAR_TEST".into(), Some("0".into())));
126-
127105
// Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
128106
config.program.envs.push(("MIRI_TEMP".into(), Some(tmpdir.to_owned().into())));
129-
130107
// If a test ICEs, we want to see a backtrace.
131108
config.program.envs.push(("RUST_BACKTRACE".into(), Some("1".into())));
132109

110+
// Add some flags we always want.
111+
config.program.args.push(
112+
format!(
113+
"--sysroot={}",
114+
env::var("MIRI_SYSROOT").expect("MIRI_SYSROOT must be set to run the ui test suite")
115+
)
116+
.into(),
117+
);
118+
config.program.args.push("-Dwarnings".into());
119+
config.program.args.push("-Dunused".into());
120+
config.program.args.push("-Ainternal_features".into());
121+
if let Ok(extra_flags) = env::var("MIRIFLAGS") {
122+
for flag in extra_flags.split_whitespace() {
123+
config.program.args.push(flag.into());
124+
}
125+
}
126+
config.program.args.push("-Zui-testing".into());
127+
config.program.args.push("--target".into());
128+
config.program.args.push(target.into());
129+
130+
// If we're on linux, and we're testing the extern-so functionality,
131+
// then build the shared object file for testing external C function calls
132+
// and push the relevant compiler flag.
133+
if cfg!(target_os = "linux") && path.starts_with("tests/extern-so/") {
134+
let so_file_path = build_so_for_c_ffi_tests();
135+
let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file=");
136+
flag.push(so_file_path.into_os_string());
137+
config.program.args.push(flag);
138+
}
139+
133140
// Handle command-line arguments.
134141
let args = ui_test::Args::test()?;
135142
let default_bless = env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
@@ -292,13 +299,12 @@ fn main() -> Result<()> {
292299

293300
fn run_dep_mode(target: String, mut args: impl Iterator<Item = OsString>) -> Result<()> {
294301
let path = args.next().expect("./miri run-dep must be followed by a file name");
295-
let mut config = test_config(
302+
let config = miri_config(
296303
&target,
297304
"",
298305
Mode::Yolo { rustfix: RustfixMode::Disabled },
299306
/* with dependencies */ true,
300307
);
301-
config.program.args.clear(); // We want to give the user full control over flags
302308
let dep_args = config.build_dependencies()?;
303309

304310
let mut cmd = config.program.build(&config.out_dir);

0 commit comments

Comments
 (0)