diff --git a/appveyor.yml b/.appveyor.yml similarity index 100% rename from appveyor.yml rename to .appveyor.yml diff --git a/Cargo.toml b/Cargo.toml index 16b5b2361bd4..721ebe5cfd46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ directories = { version = "1.0", optional = true } rustc_version = { version = "0.2.3", optional = true } env_logger = "0.6" log = "0.4" +shell-escape = "0.1.4" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. diff --git a/README.md b/README.md index 1d97b61f43d5..21e9fa43a8f8 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,13 @@ Now you can run your project in Miri: 3. If you have a binary project, you can run it through Miri using `cargo +nightly miri run`. +You can pass arguments to Miri after the first `--`, and pass arguments to the +interpreted program or test suite after the second `--`. For example, `cargo ++nightly miri run -- -Zmiri-disable-validation` runs the program without +validation of basic type invariants and references. `cargo +nightly miri test +-- -- filter` passes `filter` to the test suite the same way `cargo test filter` +would. + When running code via `cargo miri`, the `miri` config flag is set. You can use this to exclude test cases that will fail under Miri because they do things Miri does not support: diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index a34e137694cb..404fe7ae9150 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -4,11 +4,13 @@ extern crate rustc; extern crate rustc_driver; extern crate test; -use self::miri::eval_main; -use self::rustc_driver::{driver, Compilation}; +use rustc_driver::{driver, Compilation}; use rustc::hir::def_id::LOCAL_CRATE; use std::cell::RefCell; use std::rc::Rc; + +use miri::{MiriConfig, eval_main}; + use crate::test::Bencher; pub struct MiriCompilerCalls<'a>(Rc>); @@ -50,7 +52,8 @@ pub fn run(filename: &str, bencher: &mut Bencher) { ); bencher.borrow_mut().iter(|| { - eval_main(tcx, entry_def_id, false); + let config = MiriConfig { validate: true, args: vec![] }; + eval_main(tcx, entry_def_id, config); }); state.session.abort_if_errors(); diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 9b97822b4754..93200f33a260 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -10,7 +10,7 @@ use std::fs::{self, File}; const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri Usage: - cargo miri [subcommand] [options] [--] [...] + cargo miri [subcommand] [options] [--] [...] [--] [...] Subcommands: run Run binaries (default) @@ -22,8 +22,9 @@ Common options: --features Features to compile for the package -V, --version Print version info and exit -Other [options] are the same as `cargo rustc`. Everything after the "--" is -passed verbatim to Miri. +Other [options] are the same as `cargo rustc`. Everything after the first "--" is +passed verbatim to Miri, which will pass everything after the second "--" verbatim +to the interpreted program. The config flag `miri` is automatically defined for convenience. You can use it to configure the resource limits @@ -355,11 +356,13 @@ fn in_cargo_miri() { } cmd.arg(arg); } - // add "--" "-Zcargo-miri-marker" and the remaining user flags + // Add "--" (to end the cargo flags), and then the user flags. We add markers around the user flags + // to be able to identify them later. cmd .arg("--") - .arg("cargo-miri-marker") - .args(args); + .arg("cargo-miri-marker-begin") + .args(args) + .arg("cargo-miri-marker-end"); let path = std::env::current_exe().expect("current executable path invalid"); cmd.env("RUSTC_WRAPPER", path); if verbose { @@ -413,10 +416,19 @@ fn inside_cargo_rustc() { }; args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); - // see if we have cargo-miri-marker, which means we want to interpret this crate in Miri - // (and remove the marker). - let needs_miri = if let Some(pos) = args.iter().position(|arg| arg == "cargo-miri-marker") { - args.remove(pos); + // See if we can find the cargo-miri markers. Those only get added to the binary we want to + // run. They also serve to mark the user-defined arguments, which we have to move all the way to the + // end (they get added somewhere in the middle). + let needs_miri = if let Some(begin) = args.iter().position(|arg| arg == "cargo-miri-marker-begin") { + let end = args.iter().position(|arg| arg == "cargo-miri-marker-end").expect("Cannot find end marker"); + // These mark the user arguments. We remove the first and last as they are the markers. + let mut user_args = args.drain(begin..=end); + assert_eq!(user_args.next().unwrap(), "cargo-miri-marker-begin"); + assert_eq!(user_args.next_back().unwrap(), "cargo-miri-marker-end"); + // Collect the rest and add it back at the end + let mut user_args = user_args.collect::>(); + args.append(&mut user_args); + // Run this in Miri true } else { false diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 45902dc6722f..3a70577cb7f2 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -25,6 +25,8 @@ use rustc::ty::TyCtxt; use syntax::ast; use rustc::hir::def_id::LOCAL_CRATE; +use miri::MiriConfig; + struct MiriCompilerCalls { default: Box, /// whether we are building for the host @@ -94,9 +96,10 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.name() == "test") { + let config = MiriConfig { validate: true, args: vec![] }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); - miri::eval_main(self.0, did, /*validate*/true); + miri::eval_main(self.0, did, config); self.1.session.abort_if_errors(); } } @@ -106,7 +109,8 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { } state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - miri::eval_main(tcx, entry_def_id, /*validate*/true); + let config = MiriConfig { validate: true, args: vec![] }; + miri::eval_main(tcx, entry_def_id, config); state.session.abort_if_errors(); } else { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index acfc429ed805..31bd1deb10f5 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -27,11 +27,11 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::hir::def_id::LOCAL_CRATE; use syntax::ast; +use miri::MiriConfig; + struct MiriCompilerCalls { default: Box, - - /// Whether to enforce the validity invariant. - validate: bool, + miri_config: MiriConfig, } impl<'a> CompilerCalls<'a> for MiriCompilerCalls { @@ -79,6 +79,8 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option, ofile: &Option, ) -> Compilation { + // Called *before* build_controller. Add filename to miri arguments. + self.miri_config.args.insert(0, input.filestem().to_string()); self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) } fn build_controller( @@ -89,9 +91,9 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { let this = *self; let mut control = this.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); - let validate = this.validate; + let miri_config = this.miri_config; control.after_analysis.callback = - Box::new(move |state| after_analysis(state, validate)); + Box::new(move |state| after_analysis(state, miri_config.clone())); control.after_analysis.stop = Compilation::Stop; control } @@ -107,7 +109,7 @@ fn after_hir_lowering(state: &mut CompileState) { fn after_analysis<'a, 'tcx>( state: &mut CompileState<'a, 'tcx>, - validate: bool, + miri_config: MiriConfig, ) { init_late_loggers(); state.session.abort_if_errors(); @@ -117,7 +119,7 @@ fn after_analysis<'a, 'tcx>( let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); - miri::eval_main(tcx, entry_def_id, validate); + miri::eval_main(tcx, entry_def_id, miri_config); state.session.abort_if_errors(); } @@ -188,34 +190,51 @@ fn find_sysroot() -> String { fn main() { init_early_loggers(); - let mut args: Vec = std::env::args().collect(); - // Parse our own -Z flags and remove them before rustc gets their hand on them. + // Parse our arguments and split them across rustc and miri let mut validate = true; - args.retain(|arg| { - match arg.as_str() { - "-Zmiri-disable-validation" => { - validate = false; - false - }, - _ => true + let mut rustc_args = vec![]; + let mut miri_args = vec![]; + let mut after_dashdash = false; + for arg in std::env::args() { + if rustc_args.is_empty() { + // Very first arg: for rustc + rustc_args.push(arg); } - }); + else if after_dashdash { + // Everything that comes is Miri args + miri_args.push(arg); + } else { + match arg.as_str() { + "-Zmiri-disable-validation" => { + validate = false; + }, + "--" => { + after_dashdash = true; + } + _ => { + rustc_args.push(arg); + } + } + } + } // Determine sysroot and let rustc know about it let sysroot_flag = String::from("--sysroot"); - if !args.contains(&sysroot_flag) { - args.push(sysroot_flag); - args.push(find_sysroot()); + if !rustc_args.contains(&sysroot_flag) { + rustc_args.push(sysroot_flag); + rustc_args.push(find_sysroot()); } // Finally, add the default flags all the way in the beginning, but after the binary name. - args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); + rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); - trace!("rustc arguments: {:?}", args); + debug!("rustc arguments: {:?}", rustc_args); + debug!("miri arguments: {:?}", miri_args); + let miri_config = MiriConfig { validate, args: miri_args }; let result = rustc_driver::run(move || { - rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { + rustc_driver::run_compiler(&rustc_args, Box::new(MiriCompilerCalls { default: Box::new(RustcDefaultCalls), - validate, + miri_config, }), None, None) }); std::process::exit(result as i32); diff --git a/src/intrinsic.rs b/src/intrinsic.rs index b7c5d8d07c25..09df91b3ab38 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -245,7 +245,13 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; }, - "likely" | "unlikely" | "forget" => {} + "forget" => {} + + "likely" | "unlikely" => { + // These just return their argument + let b = this.read_immediate(args[0])?; + this.write_immediate(*b, dest)?; + } "init" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, diff --git a/src/lib.rs b/src/lib.rs index 4ff3e011c6ae..f59a476ed94e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,16 +57,23 @@ pub fn miri_default_args() -> &'static [&'static str] { &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"] } +/// Configuration needed to spawn a Miri instance +#[derive(Clone)] +pub struct MiriConfig { + pub validate: bool, + pub args: Vec, +} + // Used by priroda pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, - validate: bool, + config: MiriConfig, ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = EvalContext::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new(validate), + Evaluator::new(config.validate), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); @@ -120,7 +127,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Second argument (argc): 1 let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let argc = Scalar::from_int(1, dest.layout.size); + let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); ecx.write_scalar(argc, dest)?; // Store argc for macOS _NSGetArgc { @@ -130,18 +137,38 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( } // FIXME: extract main source file path - // Third argument (argv): &[b"foo"] - const CMD: &str = "running-in-miri\0"; + // Third argument (argv): Created from config.args let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let cmd = ecx.memory_mut().allocate_static_bytes(CMD.as_bytes()).with_default_tag(); - let raw_str_layout = ecx.layout_of(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8))?; - let cmd_place = ecx.allocate(raw_str_layout, MiriMemoryKind::Env.into()); - ecx.write_scalar(Scalar::Ptr(cmd), cmd_place.into())?; - ecx.memory_mut().mark_immutable(cmd_place.to_ptr()?.alloc_id)?; + // For Windows, construct a command string with all the aguments + let mut cmd = String::new(); + for arg in config.args.iter() { + if !cmd.is_empty() { + cmd.push(' '); + } + cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); + } + cmd.push(std::char::from_u32(0).unwrap()); // don't forget 0 terminator + // Collect the pointers to the individual strings. + let mut argvs = Vec::>::new(); + for arg in config.args { + // Add 0 terminator + let mut arg = arg.into_bytes(); + arg.push(0); + argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice()).with_default_tag()); + } + // Make an array with all these pointers, in the Miri memory. + let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?; + let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); + for (idx, arg) in argvs.into_iter().enumerate() { + let place = ecx.mplace_field(argvs_place, idx as u64)?; + ecx.write_scalar(Scalar::Ptr(arg), place.into())?; + } + ecx.memory_mut().mark_immutable(argvs_place.to_ptr()?.alloc_id)?; + // Write a pointe to that place as the argument. + let argv = argvs_place.ptr; + ecx.write_scalar(argv, dest)?; // Store argv for macOS _NSGetArgv { - let argv = cmd_place.ptr; - ecx.write_scalar(argv, dest)?; let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argv, argv_place.into())?; ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); @@ -149,7 +176,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Store cmdline as UTF-16 for Windows GetCommandLineW { let tcx = &{ecx.tcx.tcx}; - let cmd_utf16: Vec = CMD.encode_utf16().collect(); + let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_ptr = ecx.memory_mut().allocate( Size::from_bytes(cmd_utf16.len() as u64 * 2), Align::from_bytes(2).unwrap(), @@ -179,9 +206,9 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, - validate: bool, + config: MiriConfig, ) { - let mut ecx = create_ecx(tcx, main_id, validate).expect("Couldn't create ecx"); + let mut ecx = create_ecx(tcx, main_id, config).expect("Couldn't create ecx"); // Run! The main execution. let res: EvalResult = (|| { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 1fc705c03bb5..a52e115323c6 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -21,19 +21,19 @@ pub type CallId = u64; pub enum Borrow { /// A unique (mutable) reference. Uniq(Timestamp), - /// A shared reference. This is also used by raw pointers, which do not track details + /// An aliasing reference. This is also used by raw pointers, which do not track details /// of how or when they were created, hence the timestamp is optional. /// Shr(Some(_)) does NOT mean that the destination of this reference is frozen; /// that depends on the type! Only those parts outside of an `UnsafeCell` are actually /// frozen. - Shr(Option), + Alias(Option), } impl Borrow { #[inline(always)] - pub fn is_shared(self) -> bool { + pub fn is_aliasing(self) -> bool { match self { - Borrow::Shr(_) => true, + Borrow::Alias(_) => true, _ => false, } } @@ -49,7 +49,7 @@ impl Borrow { impl Default for Borrow { fn default() -> Self { - Borrow::Shr(None) + Borrow::Alias(None) } } @@ -58,10 +58,9 @@ impl Default for Borrow { pub enum BorStackItem { /// Indicates the unique reference that may mutate. Uniq(Timestamp), - /// Indicates that the location has been shared. Used for raw pointers, but - /// also for shared references. The latter *additionally* get frozen - /// when there is no `UnsafeCell`. - Shr, + /// Indicates that the location has been mutably shared. Used for raw pointers as + /// well as for unfrozen shared references. + Raw, /// A barrier, tracking the function it belongs to by its index on the call stack FnBarrier(CallId) } @@ -186,19 +185,19 @@ impl<'tcx> Stack { kind: RefKind, ) -> Result, String> { // Exclude unique ref with frozen tag. - if let (RefKind::Unique, Borrow::Shr(Some(_))) = (kind, bor) { + if let (RefKind::Unique, Borrow::Alias(Some(_))) = (kind, bor) { return Err(format!("Encountered mutable reference with frozen tag ({:?})", bor)); } // Checks related to freezing match bor { - Borrow::Shr(Some(bor_t)) if kind == RefKind::Frozen => { + Borrow::Alias(Some(bor_t)) if kind == RefKind::Frozen => { // We need the location to be frozen. This ensures F3. let frozen = self.frozen_since.map_or(false, |itm_t| itm_t <= bor_t); return if frozen { Ok(None) } else { Err(format!("Location is not frozen long enough")) } } - Borrow::Shr(_) if self.frozen_since.is_some() => { + Borrow::Alias(_) if self.frozen_since.is_some() => { return Ok(None) // Shared deref to frozen location, looking good } _ => {} // Not sufficient, go on looking. @@ -210,8 +209,8 @@ impl<'tcx> Stack { // Found matching unique item. This satisfies U3. return Ok(Some(idx)) } - (BorStackItem::Shr, Borrow::Shr(_)) => { - // Found matching shared/raw item. + (BorStackItem::Raw, Borrow::Alias(_)) => { + // Found matching aliasing/raw item. return Ok(Some(idx)) } // Go on looking. We ignore barriers! When an `&mut` and an `&` alias, @@ -221,7 +220,7 @@ impl<'tcx> Stack { } } // If we got here, we did not find our item. We have to error to satisfy U3. - Err(format!("Borrow being dereferenced ({:?}) does not exist on the stack", bor)) + Err(format!("Borrow being dereferenced ({:?}) does not exist on the borrow stack", bor)) } /// Perform an actual memory access using `bor`. We do not know any types here @@ -258,14 +257,15 @@ impl<'tcx> Stack { (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { // Found matching unique item. Continue after the match. } - (BorStackItem::Shr, _) if kind == AccessKind::Read => { - // When reading, everything can use a shared item! + (BorStackItem::Raw, _) if kind == AccessKind::Read => { + // When reading, everything can use a raw item! // We do not want to do this when writing: Writing to an `&mut` // should reaffirm its exclusivity (i.e., make sure it is - // on top of the stack). Continue after the match. + // on top of the stack). + // Continue after the match. } - (BorStackItem::Shr, Borrow::Shr(_)) => { - // Found matching shared item. Continue after the match. + (BorStackItem::Raw, Borrow::Alias(_)) => { + // Found matching raw item. Continue after the match. } _ => { // Pop this, go on. This ensures U2. @@ -294,7 +294,7 @@ impl<'tcx> Stack { } // If we got here, we did not find our item. err!(MachineError(format!( - "Borrow being accessed ({:?}) does not exist on the stack", + "Borrow being accessed ({:?}) does not exist on the borrow stack", bor ))) } @@ -309,7 +309,7 @@ impl<'tcx> Stack { // of access (like writing through raw pointers) is permitted. if kind == RefKind::Frozen { let bor_t = match bor { - Borrow::Shr(Some(t)) => t, + Borrow::Alias(Some(t)) => t, _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), }; // It is possible that we already are frozen (e.g. if we just pushed a barrier, @@ -328,12 +328,12 @@ impl<'tcx> Stack { // Push new item to the stack. let itm = match bor { Borrow::Uniq(t) => BorStackItem::Uniq(t), - Borrow::Shr(_) => BorStackItem::Shr, + Borrow::Alias(_) => BorStackItem::Raw, }; if *self.borrows.last().unwrap() == itm { // This is just an optimization, no functional change: Avoid stacking // multiple `Shr` on top of each other. - assert!(bor.is_shared()); + assert!(bor.is_aliasing()); trace!("create: Sharing a shared location is a NOP"); } else { // This ensures U1. @@ -440,7 +440,7 @@ impl<'tcx> Stacks { _ => false, }; if bor_redundant { - assert!(new_bor.is_shared(), "A unique reborrow can never be redundant"); + assert!(new_bor.is_aliasing(), "A unique reborrow can never be redundant"); trace!("reborrow is redundant"); continue; } @@ -465,7 +465,7 @@ impl AllocationExtra for Stacks { #[inline(always)] fn memory_allocated<'tcx>(size: Size, extra: &MemoryState) -> Self { let stack = Stack { - borrows: vec![BorStackItem::Shr], + borrows: vec![BorStackItem::Raw], frozen_since: None, }; Stacks { @@ -511,7 +511,7 @@ impl<'tcx> Stacks { ) { for stack in self.stacks.get_mut().iter_mut(Size::ZERO, size) { assert!(stack.borrows.len() == 1); - assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Shr); + assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Raw); stack.borrows.push(itm); } } @@ -536,7 +536,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // Update the stacks. - if let Borrow::Shr(Some(_)) = new_bor { + if let Borrow::Alias(Some(_)) = new_bor { // Reference that cares about freezing. We need a frozen-sensitive reborrow. this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; @@ -574,7 +574,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let time = this.machine.stacked_borrows.increment_clock(); let new_bor = match mutbl { Some(MutMutable) => Borrow::Uniq(time), - Some(MutImmutable) => Borrow::Shr(Some(time)), + Some(MutImmutable) => Borrow::Alias(Some(time)), None => Borrow::default(), }; @@ -586,7 +586,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, assert!(mutbl == Some(MutMutable), "two-phase shared borrows make no sense"); // We immediately share it, to allow read accesses let two_phase_time = this.machine.stacked_borrows.increment_clock(); - let two_phase_bor = Borrow::Shr(Some(two_phase_time)); + let two_phase_bor = Borrow::Alias(Some(two_phase_time)); this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; } @@ -651,7 +651,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // If we got here, we do some checking, *but* we leave the tag unchanged. - if let Borrow::Shr(Some(_)) = ptr.tag { + if let Borrow::Alias(Some(_)) = ptr.tag { assert_eq!(mutability, Some(MutImmutable)); // We need a frozen-sensitive check this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 7f7f2660c062..8c59b6bcdead 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -37,10 +37,19 @@ def test(name, cmd, stdout_ref, stderr_ref): def test_cargo_miri_run(): test("cargo miri run", ["cargo", "miri", "run", "-q"], "stdout.ref", "stderr.ref") + test("cargo miri run (with arguments)", + ["cargo", "miri", "run", "-q", "--", "--", "hello world", '"hello world"'], + "stdout.ref", "stderr.ref2" + ) def test_cargo_miri_test(): test("cargo miri test", ["cargo", "miri", "test", "-q"], "test.stdout.ref", "test.stderr.ref") + test("cargo miri test (with filter)", + ["cargo", "miri", "test", "-q", "--", "--", "impl"], + "test.stdout.ref2", "test.stderr.ref" + ) test_cargo_miri_run() test_cargo_miri_test() +print("TEST SUCCESSFUL!") sys.exit(0) diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 25e2cfdfa036..32f1bac57d20 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -9,7 +9,9 @@ fn main() { let n = ::read_u32(buf); assert_eq!(n, 0x01020304); println!("{:#010x}", n); - eprintln!("standard error"); + for arg in std::env::args() { + eprintln!("{}", arg); + } } #[cfg(test)] diff --git a/test-cargo-miri/stderr.ref b/test-cargo-miri/stderr.ref index aa7d1a2bdec7..ba2906d0666c 100644 --- a/test-cargo-miri/stderr.ref +++ b/test-cargo-miri/stderr.ref @@ -1 +1 @@ -standard error +main diff --git a/test-cargo-miri/stderr.ref2 b/test-cargo-miri/stderr.ref2 new file mode 100644 index 000000000000..8226b1b7cdec --- /dev/null +++ b/test-cargo-miri/stderr.ref2 @@ -0,0 +1,3 @@ +main +hello world +"hello world" diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 new file mode 100644 index 000000000000..ce3506709d5a --- /dev/null +++ b/test-cargo-miri/test.stdout.ref2 @@ -0,0 +1,11 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out + + +running 1 test +test simple ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out + diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index db9ac93279f1..30f5921202c3 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -9,5 +9,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR does not exist on the stack + let _val = *target_alias; //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs index e564e878ddb1..e3c59d156614 100644 --- a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs +++ b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR does not exist on the stack +pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR does not exist on the borrow stack fn main() { let mut x = 0; diff --git a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs index bd0fec859d8f..481915faed04 100644 --- a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs @@ -8,7 +8,7 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { unknown_code_2(); // We know this will return 5 - *our //~ ERROR does not exist on the stack + *our //~ ERROR does not exist on the borrow stack } // Now comes the evil context diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index e08e3bba6840..98d4e6f22965 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -13,5 +13,5 @@ fn main() { let v1 = safe::as_mut_slice(&v); let _v2 = safe::as_mut_slice(&v); v1[1] = 5; - //~^ ERROR does not exist on the stack + //~^ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index 959c6314690d..42f345f55144 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -9,7 +9,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR does not exist on the stack + //~^ ERROR does not exist on the borrow stack from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs index dbaccae88272..0181f739a899 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read1.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: does not exist on the stack + //~^ ERROR: does not exist on the borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs index 2da755d9aabc..b55fe1c6c88a 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read2.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: does not exist on the stack + //~^ ERROR: does not exist on the borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/compile-fail/stacked_borrows/illegal_read3.rs index b0da0511dee3..9da4ca09606e 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read3.rs @@ -13,7 +13,7 @@ fn main() { let xref2 = &mut *xref1; // derived from xref1, so using raw is still okay... callee(xref1_sneaky); let _val = *xref2; // ...but any use of it will invalidate our ref. - //~^ ERROR: does not exist on the stack + //~^ ERROR: does not exist on the borrow stack } fn callee(xref1: usize) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.rs b/tests/compile-fail/stacked_borrows/illegal_read4.rs index c86ec1286daa..bb889de8f839 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read4.rs @@ -5,5 +5,5 @@ fn main() { let xraw = xref1 as *mut _; let xref2 = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs - let _illegal = *xref2; //~ ERROR does not exist on the stack + let _illegal = *xref2; //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/compile-fail/stacked_borrows/illegal_read5.rs index 863649a47b5e..5f800e754a5d 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read5.rs @@ -12,5 +12,5 @@ fn main() { let _val = *xref; // we can even still use our mutable reference mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref let _val = *xref; // the mutable one is dead and gone - //~^ ERROR does not exist on the stack + //~^ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index ba3b6686b84c..affa21c7625e 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -3,6 +3,6 @@ fn main() { let target2 = target as *mut _; drop(&mut *target); // reborrow // Now make sure our ref is still the only one. - unsafe { *target2 = 13; } //~ ERROR does not exist on the stack + unsafe { *target2 = 13; } //~ ERROR does not exist on the borrow stack let _val = *target; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs index a653aa5003f6..dc4edcc3a5b4 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } //~ ERROR does not exist on the stack + unsafe { *ptr = 42; } //~ ERROR does not exist on the borrow stack let _val = *r#ref; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs index 57b2ca87d810..af57221260ce 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write5.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: does not exist on the stack + //~^ ERROR: does not exist on the borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index 98b9451eda87..f2e4b36f85cc 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = unsafe { *xraw }; // invalidate xref - let _val = *xref_in_mem; //~ ERROR does not exist on the stack + let _val = *xref_in_mem; //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/outdated_local.rs b/tests/compile-fail/stacked_borrows/outdated_local.rs index 64a8ff69108e..ba36e43e0c5d 100644 --- a/tests/compile-fail/stacked_borrows/outdated_local.rs +++ b/tests/compile-fail/stacked_borrows/outdated_local.rs @@ -3,7 +3,7 @@ fn main() { let y: *const i32 = &x; x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local - assert_eq!(unsafe { *y }, 1); //~ ERROR does not exist on the stack + assert_eq!(unsafe { *y }, 1); //~ ERROR does not exist on the borrow stack assert_eq!(x, 1); } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs index 28288c6c6362..b239237f0199 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // invalidate xref - foo(xref); //~ ERROR does not exist on the stack + foo(xref); //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs index bd5e28b47e86..a8207d58e99b 100644 --- a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs +++ b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs @@ -8,7 +8,7 @@ fn fun1(x: &mut u8) { fn fun2() { // Now we use a pointer we are not allowed to use - let _x = unsafe { *PTR }; //~ ERROR does not exist on the stack + let _x = unsafe { *PTR }; //~ ERROR does not exist on the borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs index e7f0b9bc9ddd..31f8a4e33afd 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the stack + ret //~ ERROR does not exist on the borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs index 28a1f74c6ac2..750d507d6f66 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { let xraw = x as *mut (i32, i32); let ret = Some(unsafe { &mut (*xraw).1 }); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the stack + ret //~ ERROR does not exist on the borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs index 3357af68a841..bb712e9e486c 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> (&mut i32,) { let xraw = x as *mut (i32, i32); let ret = (unsafe { &mut (*xraw).1 },); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the stack + ret //~ ERROR does not exist on the borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs index 197c11197efa..45ada8897778 100644 --- a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs @@ -10,5 +10,5 @@ fn main() { let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); - unsafe { *raw = 13; } //~ ERROR does not exist on the stack + unsafe { *raw = 13; } //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.rs b/tests/compile-fail/stacked_borrows/unescaped_local.rs index 054697b04a09..1db14ea7eda5 100644 --- a/tests/compile-fail/stacked_borrows/unescaped_local.rs +++ b/tests/compile-fail/stacked_borrows/unescaped_local.rs @@ -4,5 +4,5 @@ fn main() { let mut x = 42; let raw = &mut x as *mut i32 as usize as *mut i32; let _ptr = &mut x; - unsafe { *raw = 13; } //~ ERROR does not exist on the stack + unsafe { *raw = 13; } //~ ERROR does not exist on the borrow stack } diff --git a/tests/run-pass/args.rs b/tests/run-pass/args.rs new file mode 100644 index 000000000000..0116dce4992d --- /dev/null +++ b/tests/run-pass/args.rs @@ -0,0 +1,5 @@ +fn main() { + for arg in std::env::args() { + println!("{}", arg); + } +} diff --git a/tests/run-pass/args.stdout b/tests/run-pass/args.stdout new file mode 100644 index 000000000000..9564f5a1aa05 --- /dev/null +++ b/tests/run-pass/args.stdout @@ -0,0 +1 @@ +args diff --git a/tests/run-pass/iter.rs b/tests/run-pass/iter.rs new file mode 100644 index 000000000000..1bef21d83bda --- /dev/null +++ b/tests/run-pass/iter.rs @@ -0,0 +1,40 @@ +fn iter_empty_and_zst() { + for _ in Vec::::new().iter() { // this iterates over a Unique::empty() + panic!("We should never be here."); + } + + // Iterate over a ZST (uses arith_offset internally) + let mut count = 0; + for _ in &[(), (), ()] { + count += 1; + } + assert_eq!(count, 3); +} + +fn test_iterator_step_by_nth() { + let mut it = (0..16).step_by(5); + assert_eq!(it.nth(0), Some(0)); + assert_eq!(it.nth(0), Some(5)); + assert_eq!(it.nth(0), Some(10)); + assert_eq!(it.nth(0), Some(15)); + assert_eq!(it.nth(0), None); +} + +fn iter_any() { + let f = |x: &u8| { 10u8 == *x }; + f(&1u8); + + let g = |(), x: &u8| { 10u8 == *x }; + g((), &1u8); + + let h = |(), (), x: &u8| { 10u8 == *x }; + h((), (), &1u8); + + [1, 2, 3u8].into_iter().any(|elt| 10 == *elt); +} + +fn main() { + test_iterator_step_by_nth(); + iter_any(); + iter_empty_and_zst(); +} diff --git a/tests/run-pass/iter_any.rs b/tests/run-pass/iter_any.rs deleted file mode 100644 index b14eb074488b..000000000000 --- a/tests/run-pass/iter_any.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub fn main() { - let f = |x: &u8| { 10u8 == *x }; - f(&1u8); - - let g = |(), x: &u8| { 10u8 == *x }; - g((), &1u8); - - let h = |(), (), x: &u8| { 10u8 == *x }; - h((), (), &1u8); - - [1, 2, 3u8].into_iter().any(|elt| 10 == *elt); -} diff --git a/tests/run-pass/iter_slice.rs b/tests/run-pass/iter_slice.rs deleted file mode 100644 index fd7229c3455e..000000000000 --- a/tests/run-pass/iter_slice.rs +++ /dev/null @@ -1,12 +0,0 @@ -fn main() { - for _ in Vec::::new().iter() { // this iterates over a Unique::empty() - panic!("We should never be here."); - } - - // Iterate over a ZST (uses arith_offset internally) - let mut count = 0; - for _ in &[(), (), ()] { - count += 1; - } - assert_eq!(count, 3); -}