]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/src/bin/miri.rs
Rollup merge of #106618 - jmillikin:os-net-rustdoc-wasm32, r=JohnTitor
[rust.git] / src / tools / miri / src / bin / miri.rs
1 #![feature(rustc_private, stmt_expr_attributes)]
2 #![allow(
3     clippy::manual_range_contains,
4     clippy::useless_format,
5     clippy::field_reassign_with_default
6 )]
7
8 extern crate rustc_data_structures;
9 extern crate rustc_driver;
10 extern crate rustc_hir;
11 extern crate rustc_interface;
12 extern crate rustc_metadata;
13 extern crate rustc_middle;
14 extern crate rustc_session;
15
16 use std::env;
17 use std::num::NonZeroU64;
18 use std::path::PathBuf;
19 use std::str::FromStr;
20
21 use log::debug;
22
23 use rustc_data_structures::sync::Lrc;
24 use rustc_driver::Compilation;
25 use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node};
26 use rustc_interface::interface::Config;
27 use rustc_middle::{
28     middle::exported_symbols::{
29         ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
30     },
31     ty::{query::ExternProviders, TyCtxt},
32 };
33 use rustc_session::{config::CrateType, search_paths::PathKind, CtfeBacktrace};
34
35 use miri::{BacktraceStyle, ProvenanceMode, RetagFields};
36
37 struct MiriCompilerCalls {
38     miri_config: miri::MiriConfig,
39 }
40
41 impl rustc_driver::Callbacks for MiriCompilerCalls {
42     fn config(&mut self, config: &mut Config) {
43         config.override_queries = Some(|_, _, external_providers| {
44             external_providers.used_crate_source = |tcx, cnum| {
45                 let mut providers = ExternProviders::default();
46                 rustc_metadata::provide_extern(&mut providers);
47                 let mut crate_source = (providers.used_crate_source)(tcx, cnum);
48                 // HACK: rustc will emit "crate ... required to be available in rlib format, but
49                 // was not found in this form" errors once we use `tcx.dependency_formats()` if
50                 // there's no rlib provided, so setting a dummy path here to workaround those errors.
51                 Lrc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
52                 crate_source
53             };
54         });
55     }
56
57     fn after_analysis<'tcx>(
58         &mut self,
59         _: &rustc_interface::interface::Compiler,
60         queries: &'tcx rustc_interface::Queries<'tcx>,
61     ) -> Compilation {
62         queries.global_ctxt().unwrap().enter(|tcx| {
63             tcx.sess.abort_if_errors();
64
65             init_late_loggers(tcx);
66             if !tcx.sess.crate_types().contains(&CrateType::Executable) {
67                 tcx.sess.fatal("miri only makes sense on bin crates");
68             }
69
70             let (entry_def_id, entry_type) = if let Some(entry_def) = tcx.entry_fn(()) {
71                 entry_def
72             } else {
73                 tcx.sess.fatal("miri can only run programs that have a main function");
74             };
75             let mut config = self.miri_config.clone();
76
77             // Add filename to `miri` arguments.
78             config.args.insert(0, tcx.sess.io.input.filestem().to_string());
79
80             // Adjust working directory for interpretation.
81             if let Some(cwd) = env::var_os("MIRI_CWD") {
82                 env::set_current_dir(cwd).unwrap();
83             }
84
85             if let Some(return_code) = miri::eval_entry(tcx, entry_def_id, entry_type, config) {
86                 std::process::exit(
87                     i32::try_from(return_code).expect("Return value was too large!"),
88                 );
89             }
90             tcx.sess.abort_if_errors();
91         });
92
93         Compilation::Stop
94     }
95 }
96
97 struct MiriBeRustCompilerCalls {
98     target_crate: bool,
99 }
100
101 impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
102     #[allow(rustc::potential_query_instability)] // rustc_codegen_ssa (where this code is copied from) also allows this lint
103     fn config(&mut self, config: &mut Config) {
104         if config.opts.prints.is_empty() && self.target_crate {
105             // Queries overriden here affect the data stored in `rmeta` files of dependencies,
106             // which will be used later in non-`MIRI_BE_RUSTC` mode.
107             config.override_queries = Some(|_, local_providers, _| {
108                 // `exported_symbols` and `reachable_non_generics` provided by rustc always returns
109                 // an empty result if `tcx.sess.opts.output_types.should_codegen()` is false.
110                 local_providers.exported_symbols = |tcx, cnum| {
111                     assert_eq!(cnum, LOCAL_CRATE);
112                     tcx.arena.alloc_from_iter(
113                         // This is based on:
114                         // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63
115                         // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174
116                         tcx.reachable_set(()).iter().filter_map(|&local_def_id| {
117                             // Do the same filtering that rustc does:
118                             // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L84-L102
119                             // Otherwise it may cause unexpected behaviours and ICEs
120                             // (https://github.com/rust-lang/rust/issues/86261).
121                             let is_reachable_non_generic = matches!(
122                                 tcx.hir().get(tcx.hir().local_def_id_to_hir_id(local_def_id)),
123                                 Node::Item(&hir::Item {
124                                     kind: hir::ItemKind::Static(..) | hir::ItemKind::Fn(..),
125                                     ..
126                                 }) | Node::ImplItem(&hir::ImplItem {
127                                     kind: hir::ImplItemKind::Fn(..),
128                                     ..
129                                 })
130                                 if !tcx.generics_of(local_def_id).requires_monomorphization(tcx)
131                             );
132                             (is_reachable_non_generic
133                                 && tcx.codegen_fn_attrs(local_def_id).contains_extern_indicator())
134                             .then_some((
135                                 ExportedSymbol::NonGeneric(local_def_id.to_def_id()),
136                                 // Some dummy `SymbolExportInfo` here. We only use
137                                 // `exported_symbols` in shims/foreign_items.rs and the export info
138                                 // is ignored.
139                                 SymbolExportInfo {
140                                     level: SymbolExportLevel::C,
141                                     kind: SymbolExportKind::Text,
142                                     used: false,
143                                 },
144                             ))
145                         }),
146                     )
147                 }
148             });
149         }
150     }
151 }
152
153 fn show_error(msg: &impl std::fmt::Display) -> ! {
154     eprintln!("fatal error: {msg}");
155     std::process::exit(1)
156 }
157
158 macro_rules! show_error {
159     ($($tt:tt)*) => { show_error(&format_args!($($tt)*)) };
160 }
161
162 fn init_early_loggers() {
163     // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
164     // initialize them both, and we always initialize `miri`'s first.
165     let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
166     env_logger::init_from_env(env);
167     // Enable verbose entry/exit logging by default if MIRI_LOG is set.
168     if env::var_os("MIRI_LOG").is_some() && env::var_os("RUSTC_LOG_ENTRY_EXIT").is_none() {
169         env::set_var("RUSTC_LOG_ENTRY_EXIT", "1");
170     }
171     // We only initialize `rustc` if the env var is set (so the user asked for it).
172     // If it is not set, we avoid initializing now so that we can initialize
173     // later with our custom settings, and *not* log anything for what happens before
174     // `miri` gets started.
175     if env::var_os("RUSTC_LOG").is_some() {
176         rustc_driver::init_rustc_env_logger();
177     }
178 }
179
180 fn init_late_loggers(tcx: TyCtxt<'_>) {
181     // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG`
182     // env var if it is not set, control it based on `MIRI_LOG`.
183     // (FIXME: use `var_os`, but then we need to manually concatenate instead of `format!`.)
184     if let Ok(var) = env::var("MIRI_LOG") {
185         if env::var_os("RUSTC_LOG").is_none() {
186             // We try to be a bit clever here: if `MIRI_LOG` is just a single level
187             // used for everything, we only apply it to the parts of rustc that are
188             // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`.
189             // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
190             // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_const_eval::interpret=debug`.
191             if log::Level::from_str(&var).is_ok() {
192                 env::set_var(
193                     "RUSTC_LOG",
194                     format!("rustc_middle::mir::interpret={var},rustc_const_eval::interpret={var}"),
195                 );
196             } else {
197                 env::set_var("RUSTC_LOG", &var);
198             }
199             rustc_driver::init_rustc_env_logger();
200         }
201     }
202
203     // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`.
204     // Do this late, so we ideally only apply this to Miri's errors.
205     if let Some(val) = env::var_os("MIRI_BACKTRACE") {
206         let ctfe_backtrace = match &*val.to_string_lossy() {
207             "immediate" => CtfeBacktrace::Immediate,
208             "0" => CtfeBacktrace::Disabled,
209             _ => CtfeBacktrace::Capture,
210         };
211         *tcx.sess.ctfe_backtrace.borrow_mut() = ctfe_backtrace;
212     }
213 }
214
215 /// Execute a compiler with the given CLI arguments and callbacks.
216 fn run_compiler(
217     mut args: Vec<String>,
218     target_crate: bool,
219     callbacks: &mut (dyn rustc_driver::Callbacks + Send),
220 ) -> ! {
221     if target_crate {
222         // Miri needs a custom sysroot for target crates.
223         // If no `--sysroot` is given, the `MIRI_SYSROOT` env var is consulted to find where
224         // that sysroot lives, and that is passed to rustc.
225         let sysroot_flag = "--sysroot";
226         if !args.iter().any(|e| e == sysroot_flag) {
227             // Using the built-in default here would be plain wrong, so we *require*
228             // the env var to make sure things make sense.
229             let miri_sysroot = env::var("MIRI_SYSROOT").unwrap_or_else(|_| {
230                 show_error!(
231                     "Miri was invoked in 'target' mode without `MIRI_SYSROOT` or `--sysroot` being set"
232                     )
233             });
234
235             args.push(sysroot_flag.to_owned());
236             args.push(miri_sysroot);
237         }
238     }
239
240     // Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building
241     // a "host" crate. That may cause procedural macros (and probably build scripts) to
242     // depend on Miri-only symbols, such as `miri_resolve_frame`:
243     // https://github.com/rust-lang/miri/issues/1760
244     if target_crate {
245         // Some options have different defaults in Miri than in plain rustc; apply those by making
246         // them the first arguments after the binary name (but later arguments can overwrite them).
247         args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string));
248     }
249
250     // Invoke compiler, and handle return code.
251     let exit_code = rustc_driver::catch_with_exit_code(move || {
252         rustc_driver::RunCompiler::new(&args, callbacks).run()
253     });
254     std::process::exit(exit_code)
255 }
256
257 /// Parses a comma separated list of `T` from the given string:
258 ///
259 /// `<value1>,<value2>,<value3>,...`
260 fn parse_comma_list<T: FromStr>(input: &str) -> Result<Vec<T>, T::Err> {
261     input.split(',').map(str::parse::<T>).collect()
262 }
263
264 fn main() {
265     // Snapshot a copy of the environment before `rustc` starts messing with it.
266     // (`install_ice_hook` might change `RUST_BACKTRACE`.)
267     let env_snapshot = env::vars_os().collect::<Vec<_>>();
268
269     // Earliest rustc setup.
270     rustc_driver::install_ice_hook();
271
272     // If the environment asks us to actually be rustc, then do that.
273     if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
274         rustc_driver::init_rustc_env_logger();
275
276         let target_crate = if crate_kind == "target" {
277             true
278         } else if crate_kind == "host" {
279             false
280         } else {
281             panic!("invalid `MIRI_BE_RUSTC` value: {crate_kind:?}")
282         };
283
284         // We cannot use `rustc_driver::main` as we need to adjust the CLI arguments.
285         run_compiler(
286             env::args().collect(),
287             target_crate,
288             &mut MiriBeRustCompilerCalls { target_crate },
289         )
290     }
291
292     // Init loggers the Miri way.
293     init_early_loggers();
294
295     // Parse our arguments and split them across `rustc` and `miri`.
296     let mut miri_config = miri::MiriConfig::default();
297     miri_config.env = env_snapshot;
298
299     let mut rustc_args = vec![];
300     let mut after_dashdash = false;
301
302     // If user has explicitly enabled/disabled isolation
303     let mut isolation_enabled: Option<bool> = None;
304     for arg in env::args() {
305         if rustc_args.is_empty() {
306             // Very first arg: binary name.
307             rustc_args.push(arg);
308         } else if after_dashdash {
309             // Everything that comes after `--` is forwarded to the interpreted crate.
310             miri_config.args.push(arg);
311         } else if arg == "--" {
312             after_dashdash = true;
313         } else if arg == "-Zmiri-disable-validation" {
314             miri_config.validate = false;
315         } else if arg == "-Zmiri-disable-stacked-borrows" {
316             miri_config.borrow_tracker = None;
317         } else if arg == "-Zmiri-disable-data-race-detector" {
318             miri_config.data_race_detector = false;
319             miri_config.weak_memory_emulation = false;
320         } else if arg == "-Zmiri-disable-alignment-check" {
321             miri_config.check_alignment = miri::AlignmentCheck::None;
322         } else if arg == "-Zmiri-symbolic-alignment-check" {
323             miri_config.check_alignment = miri::AlignmentCheck::Symbolic;
324         } else if arg == "-Zmiri-check-number-validity" {
325             eprintln!(
326                 "WARNING: the flag `-Zmiri-check-number-validity` no longer has any effect \
327                         since it is now enabled by default"
328             );
329         } else if arg == "-Zmiri-disable-abi-check" {
330             miri_config.check_abi = false;
331         } else if arg == "-Zmiri-disable-isolation" {
332             if matches!(isolation_enabled, Some(true)) {
333                 show_error!(
334                     "-Zmiri-disable-isolation cannot be used along with -Zmiri-isolation-error"
335                 );
336             } else {
337                 isolation_enabled = Some(false);
338             }
339             miri_config.isolated_op = miri::IsolatedOp::Allow;
340         } else if arg == "-Zmiri-disable-weak-memory-emulation" {
341             miri_config.weak_memory_emulation = false;
342         } else if arg == "-Zmiri-track-weak-memory-loads" {
343             miri_config.track_outdated_loads = true;
344         } else if let Some(param) = arg.strip_prefix("-Zmiri-isolation-error=") {
345             if matches!(isolation_enabled, Some(false)) {
346                 show_error!(
347                     "-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation"
348                 );
349             } else {
350                 isolation_enabled = Some(true);
351             }
352
353             miri_config.isolated_op = match param {
354                 "abort" => miri::IsolatedOp::Reject(miri::RejectOpWith::Abort),
355                 "hide" => miri::IsolatedOp::Reject(miri::RejectOpWith::NoWarning),
356                 "warn" => miri::IsolatedOp::Reject(miri::RejectOpWith::Warning),
357                 "warn-nobacktrace" =>
358                     miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace),
359                 _ =>
360                     show_error!(
361                         "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`"
362                     ),
363             };
364         } else if arg == "-Zmiri-ignore-leaks" {
365             miri_config.ignore_leaks = true;
366         } else if arg == "-Zmiri-panic-on-unsupported" {
367             miri_config.panic_on_unsupported = true;
368         } else if arg == "-Zmiri-tag-raw-pointers" {
369             eprintln!("WARNING: `-Zmiri-tag-raw-pointers` has no effect; it is enabled by default");
370         } else if arg == "-Zmiri-strict-provenance" {
371             miri_config.provenance_mode = ProvenanceMode::Strict;
372         } else if arg == "-Zmiri-permissive-provenance" {
373             miri_config.provenance_mode = ProvenanceMode::Permissive;
374         } else if arg == "-Zmiri-mute-stdout-stderr" {
375             miri_config.mute_stdout_stderr = true;
376         } else if arg == "-Zmiri-retag-fields" {
377             miri_config.retag_fields = RetagFields::Yes;
378         } else if let Some(retag_fields) = arg.strip_prefix("-Zmiri-retag-fields=") {
379             miri_config.retag_fields = match retag_fields {
380                 "all" => RetagFields::Yes,
381                 "none" => RetagFields::No,
382                 "scalar" => RetagFields::OnlyScalar,
383                 _ => show_error!("`-Zmiri-retag-fields` can only be `all`, `none`, or `scalar`"),
384             };
385         } else if arg == "-Zmiri-track-raw-pointers" {
386             eprintln!(
387                 "WARNING: `-Zmiri-track-raw-pointers` has no effect; it is enabled by default"
388             );
389         } else if let Some(param) = arg.strip_prefix("-Zmiri-seed=") {
390             if miri_config.seed.is_some() {
391                 show_error!("Cannot specify -Zmiri-seed multiple times!");
392             }
393             let seed = param.parse::<u64>().unwrap_or_else(|_| {
394                 show_error!("-Zmiri-seed must be an integer that fits into u64")
395             });
396             miri_config.seed = Some(seed);
397         } else if let Some(_param) = arg.strip_prefix("-Zmiri-env-exclude=") {
398             show_error!(
399                 "`-Zmiri-env-exclude` has been removed; unset env vars before starting Miri instead"
400             );
401         } else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") {
402             miri_config.forwarded_env_vars.push(param.to_owned());
403         } else if let Some(param) = arg.strip_prefix("-Zmiri-track-pointer-tag=") {
404             let ids: Vec<u64> = match parse_comma_list(param) {
405                 Ok(ids) => ids,
406                 Err(err) =>
407                     show_error!(
408                         "-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {}",
409                         err
410                     ),
411             };
412             for id in ids.into_iter().map(miri::BorTag::new) {
413                 if let Some(id) = id {
414                     miri_config.tracked_pointer_tags.insert(id);
415                 } else {
416                     show_error!("-Zmiri-track-pointer-tag requires nonzero arguments");
417                 }
418             }
419         } else if let Some(param) = arg.strip_prefix("-Zmiri-track-call-id=") {
420             let ids: Vec<u64> = match parse_comma_list(param) {
421                 Ok(ids) => ids,
422                 Err(err) =>
423                     show_error!(
424                         "-Zmiri-track-call-id requires a comma separated list of valid `u64` arguments: {}",
425                         err
426                     ),
427             };
428             for id in ids.into_iter().map(miri::CallId::new) {
429                 if let Some(id) = id {
430                     miri_config.tracked_call_ids.insert(id);
431                 } else {
432                     show_error!("-Zmiri-track-call-id requires a nonzero argument");
433                 }
434             }
435         } else if let Some(param) = arg.strip_prefix("-Zmiri-track-alloc-id=") {
436             let ids: Vec<miri::AllocId> = match parse_comma_list::<NonZeroU64>(param) {
437                 Ok(ids) => ids.into_iter().map(miri::AllocId).collect(),
438                 Err(err) =>
439                     show_error!(
440                         "-Zmiri-track-alloc-id requires a comma separated list of valid non-zero `u64` arguments: {}",
441                         err
442                     ),
443             };
444             miri_config.tracked_alloc_ids.extend(ids);
445         } else if let Some(param) = arg.strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=") {
446             let rate = match param.parse::<f64>() {
447                 Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate,
448                 Ok(_) =>
449                     show_error!(
450                         "-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`"
451                     ),
452                 Err(err) =>
453                     show_error!(
454                         "-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}",
455                         err
456                     ),
457             };
458             miri_config.cmpxchg_weak_failure_rate = rate;
459         } else if let Some(param) = arg.strip_prefix("-Zmiri-preemption-rate=") {
460             let rate = match param.parse::<f64>() {
461                 Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate,
462                 Ok(_) => show_error!("-Zmiri-preemption-rate must be between `0.0` and `1.0`"),
463                 Err(err) =>
464                     show_error!(
465                         "-Zmiri-preemption-rate requires a `f64` between `0.0` and `1.0`: {}",
466                         err
467                     ),
468             };
469             miri_config.preemption_rate = rate;
470         } else if arg == "-Zmiri-report-progress" {
471             // This makes it take a few seconds between progress reports on my laptop.
472             miri_config.report_progress = Some(1_000_000);
473         } else if let Some(param) = arg.strip_prefix("-Zmiri-report-progress=") {
474             let interval = match param.parse::<u32>() {
475                 Ok(i) => i,
476                 Err(err) => show_error!("-Zmiri-report-progress requires a `u32`: {}", err),
477             };
478             miri_config.report_progress = Some(interval);
479         } else if let Some(param) = arg.strip_prefix("-Zmiri-tag-gc=") {
480             let interval = match param.parse::<u32>() {
481                 Ok(i) => i,
482                 Err(err) => show_error!("-Zmiri-tag-gc requires a `u32`: {}", err),
483             };
484             miri_config.gc_interval = interval;
485         } else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") {
486             miri_config.measureme_out = Some(param.to_string());
487         } else if let Some(param) = arg.strip_prefix("-Zmiri-backtrace=") {
488             miri_config.backtrace_style = match param {
489                 "0" => BacktraceStyle::Off,
490                 "1" => BacktraceStyle::Short,
491                 "full" => BacktraceStyle::Full,
492                 _ => show_error!("-Zmiri-backtrace may only be 0, 1, or full"),
493             };
494         } else if let Some(param) = arg.strip_prefix("-Zmiri-extern-so-file=") {
495             let filename = param.to_string();
496             if std::path::Path::new(&filename).exists() {
497                 if let Some(other_filename) = miri_config.external_so_file {
498                     show_error!(
499                         "-Zmiri-extern-so-file is already set to {}",
500                         other_filename.display()
501                     );
502                 }
503                 miri_config.external_so_file = Some(filename.into());
504             } else {
505                 show_error!("-Zmiri-extern-so-file `{}` does not exist", filename);
506             }
507         } else if let Some(param) = arg.strip_prefix("-Zmiri-num-cpus=") {
508             let num_cpus = match param.parse::<u32>() {
509                 Ok(i) => i,
510                 Err(err) => show_error!("-Zmiri-num-cpus requires a `u32`: {}", err),
511             };
512
513             miri_config.num_cpus = num_cpus;
514         } else if let Some(param) = arg.strip_prefix("-Zmiri-force-page-size=") {
515             let page_size = match param.parse::<u64>() {
516                 Ok(i) =>
517                     if i.is_power_of_two() {
518                         i * 1024
519                     } else {
520                         show_error!("-Zmiri-force-page-size requires a power of 2: {}", i)
521                     },
522                 Err(err) => show_error!("-Zmiri-force-page-size requires a `u64`: {}", err),
523             };
524
525             miri_config.page_size = Some(page_size);
526         } else {
527             // Forward to rustc.
528             rustc_args.push(arg);
529         }
530     }
531
532     debug!("rustc arguments: {:?}", rustc_args);
533     debug!("crate arguments: {:?}", miri_config.args);
534     run_compiler(rustc_args, /* target_crate: */ true, &mut MiriCompilerCalls { miri_config })
535 }