diff --git a/src/fn_call.rs b/src/fn_call.rs index 720737b5396..abb239ad7d6 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -39,12 +39,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, if this.tcx.is_foreign_item(instance.def_id()) { // An external function that we cannot find MIR for, but we can still run enough // of them to make miri viable. - this.emulate_foreign_item( - instance.def_id(), - args, - dest.unwrap(), - ret.unwrap(), - )?; + this.emulate_foreign_item(instance.def_id(), args, dest, ret)?; // `goto_block` already handled return Ok(None); } @@ -59,8 +54,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, &mut self, def_id: DefId, args: &[OpTy<'tcx, Borrow>], - dest: PlaceTy<'tcx, Borrow>, - ret: mir::BasicBlock, + dest: Option>, + ret: Option, ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); @@ -70,9 +65,23 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, }; // Strip linker suffixes (seen on 32bit macOS) let link_name = link_name.trim_end_matches("$UNIX2003"); - let tcx = &{this.tcx.tcx}; + // first: functions that could diverge + match &link_name[..] { + "__rust_start_panic" | "panic_impl" => { + return err!(MachineError("the evaluated program panicked".to_string())); + } + _ => if dest.is_none() { + return err!(Unimplemented( + format!("can't call diverging foreign function: {}", link_name), + )); + } + } + + // now: functions that assume a ret and dest + let dest = dest.expect("we already checked for a dest"); + let ret = ret.expect("dest is Some but ret is None"); match &link_name[..] { "malloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; @@ -245,9 +254,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, return Ok(()); } - "__rust_start_panic" => - return err!(MachineError("the evaluated program panicked".to_string())), - "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 0ef84723641..b7c5d8d07c2 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -108,6 +108,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "atomic_and_rel" | "atomic_and_acqrel" | "atomic_and_relaxed" | + "atomic_nand" | + "atomic_nand_acq" | + "atomic_nand_rel" | + "atomic_nand_acqrel" | + "atomic_nand_relaxed" | "atomic_xadd" | "atomic_xadd_acq" | "atomic_xadd_rel" | @@ -125,16 +130,23 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let rhs = this.read_immediate(args[1])?; let old = this.read_immediate(ptr.into())?; this.write_immediate(*old, dest)?; // old value is returned - let op = match intrinsic_name.split('_').nth(1).unwrap() { - "or" => mir::BinOp::BitOr, - "xor" => mir::BinOp::BitXor, - "and" => mir::BinOp::BitAnd, - "xadd" => mir::BinOp::Add, - "xsub" => mir::BinOp::Sub, + let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() { + "or" => (mir::BinOp::BitOr, false), + "xor" => (mir::BinOp::BitXor, false), + "and" => (mir::BinOp::BitAnd, false), + "xadd" => (mir::BinOp::Add, false), + "xsub" => (mir::BinOp::Sub, false), + "nand" => (mir::BinOp::BitAnd, true), _ => bug!(), }; // Atomics wrap around on overflow. - this.binop_ignore_overflow(op, old, rhs, ptr.into())?; + let (val, _overflowed) = this.binary_op_imm(op, old, rhs)?; + let val = if neg { + this.unary_op(mir::UnOp::Not, val, old.layout)? + } else { + val + }; + this.write_scalar(val, ptr.into())?; } "breakpoint" => unimplemented!(), // halt miri diff --git a/tests/compile-fail/panic.rs b/tests/compile-fail/panic1.rs similarity index 60% rename from tests/compile-fail/panic.rs rename to tests/compile-fail/panic1.rs index 0d594f9bd4c..1163c870828 100644 --- a/tests/compile-fail/panic.rs +++ b/tests/compile-fail/panic1.rs @@ -1,5 +1,5 @@ //error-pattern: the evaluated program panicked fn main() { - assert_eq!(5, 6); + std::panic!("panicking from libstd"); } diff --git a/tests/compile-fail/panic2.rs b/tests/compile-fail/panic2.rs new file mode 100644 index 00000000000..e643e692241 --- /dev/null +++ b/tests/compile-fail/panic2.rs @@ -0,0 +1,5 @@ +//error-pattern: the evaluated program panicked + +fn main() { + std::panic!("{}-panicking from libstd", 42); +} diff --git a/tests/compile-fail/panic3.rs b/tests/compile-fail/panic3.rs new file mode 100644 index 00000000000..b22f95d9c69 --- /dev/null +++ b/tests/compile-fail/panic3.rs @@ -0,0 +1,5 @@ +//error-pattern: the evaluated program panicked + +fn main() { + core::panic!("panicking from libcore"); +} diff --git a/tests/compile-fail/panic4.rs b/tests/compile-fail/panic4.rs new file mode 100644 index 00000000000..449e716e161 --- /dev/null +++ b/tests/compile-fail/panic4.rs @@ -0,0 +1,5 @@ +//error-pattern: the evaluated program panicked + +fn main() { + core::panic!("{}-panicking from libcore", 42); +}