diff --git a/src/eval_context.rs b/src/eval_context.rs index fe5beb2e5cfb..be745a805acc 100644 --- a/src/eval_context.rs +++ b/src/eval_context.rs @@ -517,10 +517,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let operand = &operands[0]; let value = self.eval_operand(operand)?; let value_ty = self.operand_ty(operand); - - // FIXME(solson) - let dest = self.force_allocation(dest)?; - self.write_value(value, dest, value_ty)?; } @@ -692,7 +688,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok((offset, ty)) } - fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> { + pub fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> { match ty.sty { ty::TyAdt(adt_def, substs) => { Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs)) @@ -1015,7 +1011,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok(()) } - pub(super) fn ty_to_primval_kind(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimValKind> { + pub fn ty_to_primval_kind(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimValKind> { use syntax::ast::FloatTy; let kind = match ty.sty { diff --git a/src/terminator/intrinsic.rs b/src/terminator/intrinsic.rs index a91a75454dd9..27d73fb66481 100644 --- a/src/terminator/intrinsic.rs +++ b/src/terminator/intrinsic.rs @@ -66,6 +66,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "atomic_store" | + "atomic_store_relaxed" | + "atomic_store_rel" | "volatile_store" => { let ty = substs.type_at(0); let dest = arg_vals[0].read_ptr(&self.memory)?; @@ -90,6 +92,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.write_primval(Lvalue::from_ptr(ptr), change, ty)?; } + "atomic_cxchg_relaxed" | "atomic_cxchg" => { let ty = substs.type_at(0); let ptr = arg_vals[0].read_ptr(&self.memory)?; @@ -108,6 +111,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.write_primval(Lvalue::from_ptr(ptr), change, ty)?; } + "atomic_xadd" | "atomic_xadd_relaxed" => { let ty = substs.type_at(0); let ptr = arg_vals[0].read_ptr(&self.memory)?; diff --git a/src/terminator/mod.rs b/src/terminator/mod.rs index 7107a99e8b5e..cbf9bbda2cf8 100644 --- a/src/terminator/mod.rs +++ b/src/terminator/mod.rs @@ -405,6 +405,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.write_primval(dest, PrimVal::Bytes(result as u128), dest_ty)?; } + "memrchr" => { + let ptr = args[0].read_ptr(&self.memory)?; + let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8; + let num = self.value_to_primval(args[2], usize)?.to_u64()?; + if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position(|&c| c == val) { + let new_ptr = ptr.offset(num - idx as u64 - 1); + self.write_value(Value::ByVal(PrimVal::Ptr(new_ptr)), dest, dest_ty)?; + } else { + self.write_value(Value::ByVal(PrimVal::Bytes(0)), dest, dest_ty)?; + } + } + "memchr" => { let ptr = args[0].read_ptr(&self.memory)?; let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8; diff --git a/tests/run-pass/union.rs b/tests/run-pass/union.rs new file mode 100644 index 000000000000..9e05a89a4ea3 --- /dev/null +++ b/tests/run-pass/union.rs @@ -0,0 +1,88 @@ +#![feature(untagged_unions)] +#![allow(dead_code, unused_variables)] + +fn main() { + a(); + b(); + c(); + d(); +} + +fn a() { + union U { + f1: u32, + f2: f32, + } + let mut u = U { f1: 1 }; + unsafe { + let b1 = &mut u.f1; + *b1 = 5; + } + assert_eq!(unsafe { u.f1 }, 5); +} + +fn b() { + struct S { + x: u32, + y: u32, + } + + union U { + s: S, + both: u64, + } + let mut u = U { s: S { x: 1, y: 2 } }; + unsafe { + let bx = &mut u.s.x; + let by = &mut u.s.y; + *bx = 5; + *by = 10; + } + assert_eq!(unsafe { u.s.x }, 5); + assert_eq!(unsafe { u.s.y }, 10); +} + +fn c() { + #[repr(u32)] + enum Tag { I, F } + + #[repr(C)] + union U { + i: i32, + f: f32, + } + + #[repr(C)] + struct Value { + tag: Tag, + u: U, + } + + fn is_zero(v: Value) -> bool { + unsafe { + match v { + Value { tag: Tag::I, u: U { i: 0 } } => true, + Value { tag: Tag::F, u: U { f: 0.0 } } => true, + _ => false, + } + } + } + assert!(is_zero(Value { tag: Tag::I, u: U { i: 0 }})); + assert!(is_zero(Value { tag: Tag::F, u: U { f: 0.0 }})); + assert!(!is_zero(Value { tag: Tag::I, u: U { i: 1 }})); + assert!(!is_zero(Value { tag: Tag::F, u: U { f: 42.0 }})); +} + +fn d() { + union MyUnion { + f1: u32, + f2: f32, + } + let u = MyUnion { f1: 10 }; + unsafe { + match u { + MyUnion { f1: 10 } => { } + MyUnion { f2 } => { panic!("foo"); } + } + } +}