From f1c5bf2281d6fe39632d6c73a1bf682ee3c103cb Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 29 Sep 2016 15:58:26 +0200 Subject: [PATCH 1/6] fix intrinsics and implement more of them --- src/interpreter/terminator/intrinsics.rs | 52 ++++++++++- tests/run-pass/intrinsics-integer.rs | 105 +++++++++++++++++++++++ 2 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/intrinsics-integer.rs diff --git a/src/interpreter/terminator/intrinsics.rs b/src/interpreter/terminator/intrinsics.rs index c025852bc5e45..f07688202ef70 100644 --- a/src/interpreter/terminator/intrinsics.rs +++ b/src/interpreter/terminator/intrinsics.rs @@ -67,15 +67,61 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "ctpop" => { let elem_ty = substs.type_at(0); let elem_size = self.type_size(elem_ty); - let num = self.value_to_primval(args_ptrs[2], elem_ty)?.expect_int("ctpop second arg not integral"); - let num = num.count_ones(); + let num = self.value_to_primval(args_ptrs[0], elem_ty)?; + let num = match num { + PrimVal::I8(i) => i.count_ones(), + PrimVal::U8(i) => i.count_ones(), + PrimVal::I16(i) => i.count_ones(), + PrimVal::U16(i) => i.count_ones(), + PrimVal::I32(i) => i.count_ones(), + PrimVal::U32(i) => i.count_ones(), + PrimVal::I64(i) => i.count_ones(), + PrimVal::U64(i) => i.count_ones(), + _ => bug!("ctpop called with non-integer type"), + }; + self.memory.write_uint(dest, num.into(), elem_size)?; + } + + "bswap" => { + let elem_ty = substs.type_at(0); + let elem_size = self.type_size(elem_ty); + let num = self.value_to_primval(args_ptrs[0], elem_ty)?; + let num = match num { + PrimVal::I8(i) => i.swap_bytes() as u64, + PrimVal::U8(i) => i.swap_bytes() as u64, + PrimVal::I16(i) => i.swap_bytes() as u64, + PrimVal::U16(i) => i.swap_bytes() as u64, + PrimVal::I32(i) => i.swap_bytes() as u64, + PrimVal::U32(i) => i.swap_bytes() as u64, + PrimVal::I64(i) => i.swap_bytes() as u64, + PrimVal::U64(i) => i.swap_bytes(), + _ => bug!("bswap called with non-integer type"), + }; + self.memory.write_uint(dest, num, elem_size)?; + } + + "cttz" => { + let elem_ty = substs.type_at(0); + let elem_size = self.type_size(elem_ty); + let num = self.value_to_primval(args_ptrs[0], elem_ty)?; + let num = match num { + PrimVal::I8(i) => i.trailing_zeros(), + PrimVal::U8(i) => i.trailing_zeros(), + PrimVal::I16(i) => i.trailing_zeros(), + PrimVal::U16(i) => i.trailing_zeros(), + PrimVal::I32(i) => i.trailing_zeros(), + PrimVal::U32(i) => i.trailing_zeros(), + PrimVal::I64(i) => i.trailing_zeros(), + PrimVal::U64(i) => i.trailing_zeros(), + _ => bug!("cttz called with non-integer type"), + }; self.memory.write_uint(dest, num.into(), elem_size)?; } "ctlz" => { let elem_ty = substs.type_at(0); let elem_size = self.type_size(elem_ty); - let num = self.value_to_primval(args_ptrs[2], elem_ty)?; + let num = self.value_to_primval(args_ptrs[0], elem_ty)?; let num = match num { PrimVal::I8(i) => i.leading_zeros(), PrimVal::U8(i) => i.leading_zeros(), diff --git a/tests/run-pass/intrinsics-integer.rs b/tests/run-pass/intrinsics-integer.rs new file mode 100644 index 0000000000000..759dc515456de --- /dev/null +++ b/tests/run-pass/intrinsics-integer.rs @@ -0,0 +1,105 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(intrinsics)] + +mod rusti { + extern "rust-intrinsic" { + pub fn ctpop(x: T) -> T; + pub fn ctlz(x: T) -> T; + pub fn cttz(x: T) -> T; + pub fn bswap(x: T) -> T; + } +} + +pub fn main() { + unsafe { + use rusti::*; + + assert_eq!(ctpop(0u8), 0); assert_eq!(ctpop(0i8), 0); + assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0); + assert_eq!(ctpop(0u32), 0); assert_eq!(ctpop(0i32), 0); + assert_eq!(ctpop(0u64), 0); assert_eq!(ctpop(0i64), 0); + + assert_eq!(ctpop(1u8), 1); assert_eq!(ctpop(1i8), 1); + assert_eq!(ctpop(1u16), 1); assert_eq!(ctpop(1i16), 1); + assert_eq!(ctpop(1u32), 1); assert_eq!(ctpop(1i32), 1); + assert_eq!(ctpop(1u64), 1); assert_eq!(ctpop(1i64), 1); + + assert_eq!(ctpop(10u8), 2); assert_eq!(ctpop(10i8), 2); + assert_eq!(ctpop(10u16), 2); assert_eq!(ctpop(10i16), 2); + assert_eq!(ctpop(10u32), 2); assert_eq!(ctpop(10i32), 2); + assert_eq!(ctpop(10u64), 2); assert_eq!(ctpop(10i64), 2); + + assert_eq!(ctpop(100u8), 3); assert_eq!(ctpop(100i8), 3); + assert_eq!(ctpop(100u16), 3); assert_eq!(ctpop(100i16), 3); + assert_eq!(ctpop(100u32), 3); assert_eq!(ctpop(100i32), 3); + assert_eq!(ctpop(100u64), 3); assert_eq!(ctpop(100i64), 3); + + assert_eq!(ctpop(-1i8 as u8), 8); assert_eq!(ctpop(-1i8), 8); + assert_eq!(ctpop(-1i16 as u16), 16); assert_eq!(ctpop(-1i16), 16); + assert_eq!(ctpop(-1i32 as u32), 32); assert_eq!(ctpop(-1i32), 32); + assert_eq!(ctpop(-1i64 as u64), 64); assert_eq!(ctpop(-1i64), 64); + + assert_eq!(ctlz(0u8), 8); assert_eq!(ctlz(0i8), 8); + assert_eq!(ctlz(0u16), 16); assert_eq!(ctlz(0i16), 16); + assert_eq!(ctlz(0u32), 32); assert_eq!(ctlz(0i32), 32); + assert_eq!(ctlz(0u64), 64); assert_eq!(ctlz(0i64), 64); + + assert_eq!(ctlz(1u8), 7); assert_eq!(ctlz(1i8), 7); + assert_eq!(ctlz(1u16), 15); assert_eq!(ctlz(1i16), 15); + assert_eq!(ctlz(1u32), 31); assert_eq!(ctlz(1i32), 31); + assert_eq!(ctlz(1u64), 63); assert_eq!(ctlz(1i64), 63); + + assert_eq!(ctlz(10u8), 4); assert_eq!(ctlz(10i8), 4); + assert_eq!(ctlz(10u16), 12); assert_eq!(ctlz(10i16), 12); + assert_eq!(ctlz(10u32), 28); assert_eq!(ctlz(10i32), 28); + assert_eq!(ctlz(10u64), 60); assert_eq!(ctlz(10i64), 60); + + assert_eq!(ctlz(100u8), 1); assert_eq!(ctlz(100i8), 1); + assert_eq!(ctlz(100u16), 9); assert_eq!(ctlz(100i16), 9); + assert_eq!(ctlz(100u32), 25); assert_eq!(ctlz(100i32), 25); + assert_eq!(ctlz(100u64), 57); assert_eq!(ctlz(100i64), 57); + + assert_eq!(cttz(-1i8 as u8), 0); assert_eq!(cttz(-1i8), 0); + assert_eq!(cttz(-1i16 as u16), 0); assert_eq!(cttz(-1i16), 0); + assert_eq!(cttz(-1i32 as u32), 0); assert_eq!(cttz(-1i32), 0); + assert_eq!(cttz(-1i64 as u64), 0); assert_eq!(cttz(-1i64), 0); + + assert_eq!(cttz(0u8), 8); assert_eq!(cttz(0i8), 8); + assert_eq!(cttz(0u16), 16); assert_eq!(cttz(0i16), 16); + assert_eq!(cttz(0u32), 32); assert_eq!(cttz(0i32), 32); + assert_eq!(cttz(0u64), 64); assert_eq!(cttz(0i64), 64); + + assert_eq!(cttz(1u8), 0); assert_eq!(cttz(1i8), 0); + assert_eq!(cttz(1u16), 0); assert_eq!(cttz(1i16), 0); + assert_eq!(cttz(1u32), 0); assert_eq!(cttz(1i32), 0); + assert_eq!(cttz(1u64), 0); assert_eq!(cttz(1i64), 0); + + assert_eq!(cttz(10u8), 1); assert_eq!(cttz(10i8), 1); + assert_eq!(cttz(10u16), 1); assert_eq!(cttz(10i16), 1); + assert_eq!(cttz(10u32), 1); assert_eq!(cttz(10i32), 1); + assert_eq!(cttz(10u64), 1); assert_eq!(cttz(10i64), 1); + + assert_eq!(cttz(100u8), 2); assert_eq!(cttz(100i8), 2); + assert_eq!(cttz(100u16), 2); assert_eq!(cttz(100i16), 2); + assert_eq!(cttz(100u32), 2); assert_eq!(cttz(100i32), 2); + assert_eq!(cttz(100u64), 2); assert_eq!(cttz(100i64), 2); + + assert_eq!(bswap(0x0Au8), 0x0A); // no-op + assert_eq!(bswap(0x0Ai8), 0x0A); // no-op + assert_eq!(bswap(0x0A0Bu16), 0x0B0A); + assert_eq!(bswap(0x0A0Bi16), 0x0B0A); + assert_eq!(bswap(0x0ABBCC0Du32), 0x0DCCBB0A); + assert_eq!(bswap(0x0ABBCC0Di32), 0x0DCCBB0A); + assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201); + assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201); + } +} From 18c8c852e484dc0d16ba999438cd63b4f3a7883f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 29 Sep 2016 16:42:01 +0200 Subject: [PATCH 2/6] factor out shared code --- src/interpreter/terminator/intrinsics.rs | 126 +++++++++++------------ 1 file changed, 58 insertions(+), 68 deletions(-) diff --git a/src/interpreter/terminator/intrinsics.rs b/src/interpreter/terminator/intrinsics.rs index f07688202ef70..817ded7273d61 100644 --- a/src/interpreter/terminator/intrinsics.rs +++ b/src/interpreter/terminator/intrinsics.rs @@ -31,7 +31,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let f32 = self.tcx.types.f32; let f64 = self.tcx.types.f64; - match &self.tcx.item_name(def_id).as_str()[..] { + let intrinsic_name = &self.tcx.item_name(def_id).as_str()[..]; + match intrinsic_name { "add_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Add, &args[0], &args[1], dest, dest_layout)?, "sub_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Sub, &args[0], &args[1], dest, dest_layout)?, "mul_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Mul, &args[0], &args[1], dest, dest_layout)?, @@ -64,76 +65,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.memory.copy(src, dest, count as usize * elem_size, elem_align)?; } - "ctpop" => { - let elem_ty = substs.type_at(0); - let elem_size = self.type_size(elem_ty); - let num = self.value_to_primval(args_ptrs[0], elem_ty)?; - let num = match num { - PrimVal::I8(i) => i.count_ones(), - PrimVal::U8(i) => i.count_ones(), - PrimVal::I16(i) => i.count_ones(), - PrimVal::U16(i) => i.count_ones(), - PrimVal::I32(i) => i.count_ones(), - PrimVal::U32(i) => i.count_ones(), - PrimVal::I64(i) => i.count_ones(), - PrimVal::U64(i) => i.count_ones(), - _ => bug!("ctpop called with non-integer type"), - }; - self.memory.write_uint(dest, num.into(), elem_size)?; - } - + "ctpop" | + "cttz" | + "ctlz" | "bswap" => { let elem_ty = substs.type_at(0); - let elem_size = self.type_size(elem_ty); let num = self.value_to_primval(args_ptrs[0], elem_ty)?; - let num = match num { - PrimVal::I8(i) => i.swap_bytes() as u64, - PrimVal::U8(i) => i.swap_bytes() as u64, - PrimVal::I16(i) => i.swap_bytes() as u64, - PrimVal::U16(i) => i.swap_bytes() as u64, - PrimVal::I32(i) => i.swap_bytes() as u64, - PrimVal::U32(i) => i.swap_bytes() as u64, - PrimVal::I64(i) => i.swap_bytes() as u64, - PrimVal::U64(i) => i.swap_bytes(), - _ => bug!("bswap called with non-integer type"), - }; - self.memory.write_uint(dest, num, elem_size)?; - } - - "cttz" => { - let elem_ty = substs.type_at(0); - let elem_size = self.type_size(elem_ty); - let num = self.value_to_primval(args_ptrs[0], elem_ty)?; - let num = match num { - PrimVal::I8(i) => i.trailing_zeros(), - PrimVal::U8(i) => i.trailing_zeros(), - PrimVal::I16(i) => i.trailing_zeros(), - PrimVal::U16(i) => i.trailing_zeros(), - PrimVal::I32(i) => i.trailing_zeros(), - PrimVal::U32(i) => i.trailing_zeros(), - PrimVal::I64(i) => i.trailing_zeros(), - PrimVal::U64(i) => i.trailing_zeros(), - _ => bug!("cttz called with non-integer type"), - }; - self.memory.write_uint(dest, num.into(), elem_size)?; - } - - "ctlz" => { - let elem_ty = substs.type_at(0); - let elem_size = self.type_size(elem_ty); - let num = self.value_to_primval(args_ptrs[0], elem_ty)?; - let num = match num { - PrimVal::I8(i) => i.leading_zeros(), - PrimVal::U8(i) => i.leading_zeros(), - PrimVal::I16(i) => i.leading_zeros(), - PrimVal::U16(i) => i.leading_zeros(), - PrimVal::I32(i) => i.leading_zeros(), - PrimVal::U32(i) => i.leading_zeros(), - PrimVal::I64(i) => i.leading_zeros(), - PrimVal::U64(i) => i.leading_zeros(), - _ => bug!("ctlz called with non-integer type"), - }; - self.memory.write_uint(dest, num.into(), elem_size)?; + let num = numeric_intrinsic(intrinsic_name, num); + self.memory.write_primval(dest, num)?; } "discriminant_value" => { @@ -396,3 +335,54 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.tcx.normalize_associated_type(&f.ty(self.tcx, param_substs)) } } + +fn numeric_intrinsic(name: &str, val: PrimVal) -> PrimVal { + use primval::PrimVal::*; + match name { + "ctpop" => match val { + I8(i) => I8(i.count_ones() as i8), + U8(i) => U8(i.count_ones() as u8), + I16(i) => I16(i.count_ones() as i16), + U16(i) => U16(i.count_ones() as u16), + I32(i) => I32(i.count_ones() as i32), + U32(i) => U32(i.count_ones() as u32), + I64(i) => I64(i.count_ones() as i64), + U64(i) => U64(i.count_ones() as u64), + other => bug!("invalid `ctpop` argument: {:?}", other), + }, + "cttz" => match val { + I8(i) => I8(i.trailing_zeros() as i8), + U8(i) => U8(i.trailing_zeros() as u8), + I16(i) => I16(i.trailing_zeros() as i16), + U16(i) => U16(i.trailing_zeros() as u16), + I32(i) => I32(i.trailing_zeros() as i32), + U32(i) => U32(i.trailing_zeros() as u32), + I64(i) => I64(i.trailing_zeros() as i64), + U64(i) => U64(i.trailing_zeros() as u64), + other => bug!("invalid `cttz` argument: {:?}", other), + }, + "ctlz" => match val { + I8(i) => I8(i.leading_zeros() as i8), + U8(i) => U8(i.leading_zeros() as u8), + I16(i) => I16(i.leading_zeros() as i16), + U16(i) => U16(i.leading_zeros() as u16), + I32(i) => I32(i.leading_zeros() as i32), + U32(i) => U32(i.leading_zeros() as u32), + I64(i) => I64(i.leading_zeros() as i64), + U64(i) => U64(i.leading_zeros() as u64), + other => bug!("invalid `ctlz` argument: {:?}", other), + }, + "bswap" => match val { + I8(i) => I8(i.swap_bytes() as i8), + U8(i) => U8(i.swap_bytes() as u8), + I16(i) => I16(i.swap_bytes() as i16), + U16(i) => U16(i.swap_bytes() as u16), + I32(i) => I32(i.swap_bytes() as i32), + U32(i) => U32(i.swap_bytes() as u32), + I64(i) => I64(i.swap_bytes() as i64), + U64(i) => U64(i.swap_bytes() as u64), + other => bug!("invalid `bswap` argument: {:?}", other), + }, + _ => bug!("not a numeric intrinsic: {}", name), + } +} From 8c666b30edb36109d0f18fee9c589c220eaa7213 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 30 Sep 2016 10:45:13 +0200 Subject: [PATCH 3/6] remove some debug output --- src/interpreter/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 41dfa6806fb52..9a15e54bf60aa 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -838,8 +838,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let offset = variant.field_offset(field.index()).bytes(); let ptr = base.ptr.offset(offset as isize); - trace!("{:?}", base); - trace!("{:?}", field_ty); if self.type_is_sized(field_ty) { ptr } else { From c9914cd3aeaaeb59e1067205df9b33a3f1c1aa79 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 30 Sep 2016 10:45:52 +0200 Subject: [PATCH 4/6] fix enum variants with multiple fields --- src/interpreter/mod.rs | 17 +- tests/run-pass/deriving-associated-types.rs | 208 ++++++++++++++++++++ tests/run-pass/enums.rs | 34 ++++ 3 files changed, 251 insertions(+), 8 deletions(-) create mode 100644 tests/run-pass/deriving-associated-types.rs create mode 100644 tests/run-pass/enums.rs diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 9a15e54bf60aa..573b5c6f8490b 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -819,11 +819,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Field(field, field_ty) => { let field_ty = self.monomorphize(field_ty, self.substs()); use rustc::ty::layout::Layout::*; - let variant = match *base_layout { - Univariant { ref variant, .. } => variant, + let field = field.index(); + let offset = match *base_layout { + Univariant { ref variant, .. } => variant.field_offset(field), General { ref variants, .. } => { if let LvalueExtra::DowncastVariant(variant_idx) = base.extra { - &variants[variant_idx] + // +1 for the discriminant, which is field 0 + variants[variant_idx].field_offset(field + 1) } else { bug!("field access on enum had no variant index"); } @@ -832,12 +834,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { assert_eq!(field.index(), 0); return Ok(base); } - StructWrappedNullablePointer { ref nonnull, .. } => nonnull, + StructWrappedNullablePointer { ref nonnull, .. } => nonnull.field_offset(field), _ => bug!("field access on non-product type: {:?}", base_layout), }; - let offset = variant.field_offset(field.index()).bytes(); - let ptr = base.ptr.offset(offset as isize); + let ptr = base.ptr.offset(offset.bytes() as isize); if self.type_is_sized(field_ty) { ptr } else { @@ -857,9 +858,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Downcast(_, variant) => { use rustc::ty::layout::Layout::*; match *base_layout { - General { ref variants, .. } => { + General { .. } => { return Ok(Lvalue { - ptr: base.ptr.offset(variants[variant].field_offset(1).bytes() as isize), + ptr: base.ptr, extra: LvalueExtra::DowncastVariant(variant), }); } diff --git a/tests/run-pass/deriving-associated-types.rs b/tests/run-pass/deriving-associated-types.rs new file mode 100644 index 0000000000000..b67ef85acf62d --- /dev/null +++ b/tests/run-pass/deriving-associated-types.rs @@ -0,0 +1,208 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait DeclaredTrait { + type Type; +} + +impl DeclaredTrait for i32 { + type Type = i32; +} + +pub trait WhereTrait { + type Type; +} + +impl WhereTrait for i32 { + type Type = i32; +} + +// Make sure we don't add a bound that just shares a name with an associated +// type. +pub mod module { + pub type Type = i32; +} + +#[derive(PartialEq, Debug)] +struct PrivateStruct(T); + +#[derive(PartialEq, Debug)] +struct TupleStruct( + module::Type, + Option, + A, + PrivateStruct, + B, + B::Type, + Option, + ::Type, + Option<::Type>, + C, + C::Type, + Option, + ::Type, + Option<::Type>, + ::Type, +) where C: WhereTrait; + +#[derive(PartialEq, Debug)] +pub struct Struct where C: WhereTrait { + m1: module::Type, + m2: Option, + a1: A, + a2: PrivateStruct, + b: B, + b1: B::Type, + b2: Option, + b3: ::Type, + b4: Option<::Type>, + c: C, + c1: C::Type, + c2: Option, + c3: ::Type, + c4: Option<::Type>, + d: ::Type, +} + +#[derive(PartialEq, Debug)] +enum Enum where C: WhereTrait { + Unit, + Seq( + module::Type, + Option, + A, + PrivateStruct, + B, + B::Type, + Option, + ::Type, + Option<::Type>, + C, + C::Type, + Option, + ::Type, + Option<::Type>, + ::Type, + ), + Map { + m1: module::Type, + m2: Option, + a1: A, + a2: PrivateStruct, + b: B, + b1: B::Type, + b2: Option, + b3: ::Type, + b4: Option<::Type>, + c: C, + c1: C::Type, + c2: Option, + c3: ::Type, + c4: Option<::Type>, + d: ::Type, + }, +} + +fn main() { + + let e: Enum< + i32, + i32, + i32, + > = Enum::Seq( + 0, + None, + 0, + PrivateStruct(0), + 0, + 0, + None, + 0, + None, + 0, + 0, + None, + 0, + None, + 0, + ); + assert_eq!(e, e); + + let e: Enum< + i32, + i32, + i32, + > = Enum::Map { + m1: 0, + m2: None, + a1: 0, + a2: PrivateStruct(0), + b: 0, + b1: 0, + b2: None, + b3: 0, + b4: None, + c: 0, + c1: 0, + c2: None, + c3: 0, + c4: None, + d: 0, + }; + assert_eq!(e, e); + let e: TupleStruct< + i32, + i32, + i32, + > = TupleStruct( + 0, + None, + 0, + PrivateStruct(0), + 0, + 0, + None, + 0, + None, + 0, + 0, + None, + 0, + None, + 0, + ); + assert_eq!(e, e); + + let e: Struct< + i32, + i32, + i32, + > = Struct { + m1: 0, + m2: None, + a1: 0, + a2: PrivateStruct(0), + b: 0, + b1: 0, + b2: None, + b3: 0, + b4: None, + c: 0, + c1: 0, + c2: None, + c3: 0, + c4: None, + d: 0, + }; + assert_eq!(e, e); + + let e = Enum::Unit::; + assert_eq!(e, e); +} diff --git a/tests/run-pass/enums.rs b/tests/run-pass/enums.rs new file mode 100644 index 0000000000000..1f27292904f42 --- /dev/null +++ b/tests/run-pass/enums.rs @@ -0,0 +1,34 @@ +enum MyEnum { + MyEmptyVariant, + MyNewtypeVariant(i32), + MyTupleVariant(i32, i32), + MyStructVariant { + my_first_field: i32, + my_second_field: i32, + } +} + +fn test(me: MyEnum) { + match me { + MyEnum::MyEmptyVariant => {}, + MyEnum::MyNewtypeVariant(ref val) => assert_eq!(val, &42), + MyEnum::MyTupleVariant(ref a, ref b) => { + assert_eq!(a, &43); + assert_eq!(b, &44); + }, + MyEnum::MyStructVariant { ref my_first_field, ref my_second_field } => { + assert_eq!(my_first_field, &45); + assert_eq!(my_second_field, &46); + }, + } +} + +fn main() { + test(MyEnum::MyEmptyVariant); + test(MyEnum::MyNewtypeVariant(42)); + test(MyEnum::MyTupleVariant(43, 44)); + test(MyEnum::MyStructVariant{ + my_first_field: 45, + my_second_field: 46, + }); +} From d9680dbb100442c9bad2712972bb50097089023d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sat, 1 Oct 2016 15:30:29 +0200 Subject: [PATCH 5/6] bump compiletest --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d85ee67cf3e1f..906d7031214d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,7 +3,7 @@ name = "miri" version = "0.1.0" dependencies = [ "byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -24,7 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "compiletest_rs" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -137,7 +137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9" "checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304" -"checksum compiletest_rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0bcddebf582c5c035cce855a89596eb686cc40b9e77da1026fba735dcca2fbd3" +"checksum compiletest_rs 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0ac936b073036755b7d176f16d4c660f4d6f1390cbe556316af9cb9724117059" "checksum env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "82dcb9ceed3868a03b335657b85a159736c961900f7e7747d3b0b97b9ccb5ccb" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f" diff --git a/Cargo.toml b/Cargo.toml index fea568e244d43..a770bea069499 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,4 +21,4 @@ log = "0.3.6" log_settings = "0.1.1" [dev-dependencies] -compiletest_rs = "0.2" +compiletest_rs = "0.2.3" From de38015e47c3d0c12995e378436a04a92844a0b7 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sat, 1 Oct 2016 15:33:07 +0200 Subject: [PATCH 6/6] rustup --- src/bin/miri.rs | 2 +- src/interpreter/mod.rs | 53 ++++++++++--------------------- src/interpreter/step.rs | 4 +-- src/interpreter/terminator/mod.rs | 7 ++-- src/memory.rs | 17 +++++++--- 5 files changed, 35 insertions(+), 48 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index cc0132e4090d9..515b54e4bfd5f 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -138,5 +138,5 @@ fn main() { args.push(find_sysroot()); } - rustc_driver::run_compiler(&args, &mut MiriCompilerCalls); + rustc_driver::run_compiler(&args, &mut MiriCompilerCalls, None, None); } diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 573b5c6f8490b..722167a4175a0 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -73,23 +73,13 @@ pub struct Frame<'a, 'tcx: 'a> { // Return pointer and local allocations //////////////////////////////////////////////////////////////////////////////// - /// A pointer for writing the return value of the current call if it's not a diverging call. - pub return_ptr: Option, - /// The block to return to when returning from the current stack frame pub return_to_block: StackPopCleanup, /// The list of locals for the current function, stored in order as - /// `[arguments..., variables..., temporaries...]`. The variables begin at `self.var_offset` - /// and the temporaries at `self.temp_offset`. + /// `[return_ptr, arguments..., variables..., temporaries...]`. pub locals: Vec, - /// The offset of the first variable in `self.locals`. - pub var_offset: usize, - - /// The offset of the first temporary in `self.locals`. - pub temp_offset: usize, - //////////////////////////////////////////////////////////////////////////////// // Current position within the function //////////////////////////////////////////////////////////////////////////////// @@ -336,32 +326,26 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { span: codemap::Span, mir: CachedMir<'a, 'tcx>, substs: &'tcx Substs<'tcx>, - return_ptr: Option, + return_ptr: Pointer, return_to_block: StackPopCleanup, ) -> EvalResult<'tcx, ()> { - let arg_tys = mir.arg_decls.iter().map(|a| a.ty); - let var_tys = mir.var_decls.iter().map(|v| v.ty); - let temp_tys = mir.temp_decls.iter().map(|t| t.ty); - - let num_args = mir.arg_decls.len(); - let num_vars = mir.var_decls.len(); + let local_tys = mir.local_decls.iter().map(|a| a.ty); ::log_settings::settings().indentation += 1; - let locals: EvalResult<'tcx, Vec> = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| { + // directly change the first allocation (the return value) to *be* the allocation where the + // caller stores the result + let locals: EvalResult<'tcx, Vec> = iter::once(Ok(return_ptr)).chain(local_tys.skip(1).map(|ty| { let size = self.type_size_with_substs(ty, substs); let align = self.type_align_with_substs(ty, substs); self.memory.allocate(size, align) - }).collect(); + })).collect(); self.stack.push(Frame { mir: mir.clone(), block: mir::START_BLOCK, - return_ptr: return_ptr, return_to_block: return_to_block, locals: locals?, - var_offset: num_args, - temp_offset: num_args + num_vars, span: span, def_id: def_id, substs: substs, @@ -793,11 +777,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue> { use rustc::mir::repr::Lvalue::*; let ptr = match *lvalue { - ReturnPointer => self.frame().return_ptr - .expect("ReturnPointer used in a function with no return value"), - Arg(i) => self.frame().locals[i.index()], - Var(i) => self.frame().locals[self.frame().var_offset + i.index()], - Temp(i) => self.frame().locals[self.frame().temp_offset + i.index()], + Local(i) => self.frame().locals[i.index()], Static(def_id) => { let substs = subst::Substs::empty(self.tcx); @@ -1219,18 +1199,17 @@ pub fn eval_main<'a, 'tcx: 'a>( let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs) .expect("should at least be able to allocate space for the main function's return value"); - ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, Some(return_ptr), StackPopCleanup::None) + ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, return_ptr, StackPopCleanup::None) .expect("could not allocate first stack frame"); - if mir.arg_decls.len() == 2 { + // FIXME: this is a horrible and wrong way to detect the start function, but overwriting the first two locals shouldn't do much + if mir.local_decls.len() > 2 { // start function - let ptr_size = ecx.memory().pointer_size(); - let nargs = ecx.memory_mut().allocate(ptr_size, ptr_size).expect("can't allocate memory for nargs"); - ecx.memory_mut().write_usize(nargs, 0).unwrap(); - let args = ecx.memory_mut().allocate(ptr_size, ptr_size).expect("can't allocate memory for arg pointer"); - ecx.memory_mut().write_usize(args, 0).unwrap(); - ecx.frame_mut().locals[0] = nargs; - ecx.frame_mut().locals[1] = args; + let nargs = ecx.frame_mut().locals[1]; + let args = ecx.frame_mut().locals[2]; + // ignore errors, if the locals are too small this is not the start function + let _ = ecx.memory_mut().write_usize(nargs, 0); + let _ = ecx.memory_mut().write_usize(args, 0); } for _ in 0..step_limit { diff --git a/src/interpreter/step.rs b/src/interpreter/step.rs index fe386ea5fb606..77350504306b6 100644 --- a/src/interpreter/step.rs +++ b/src/interpreter/step.rs @@ -134,7 +134,7 @@ impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> { } else { StackPopCleanup::None }; - this.ecx.push_stack_frame(def_id, span, mir, substs, Some(ptr), cleanup) + this.ecx.push_stack_frame(def_id, span, mir, substs, ptr, cleanup) }); } fn try EvalResult<'tcx, ()>>(&mut self, f: F) { @@ -183,7 +183,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> { constant.span, mir, this.substs, - Some(return_ptr), + return_ptr, StackPopCleanup::Freeze(return_ptr.alloc_id)) }); } diff --git a/src/interpreter/terminator/mod.rs b/src/interpreter/terminator/mod.rs index cd024d4c007dc..e0e6e3996c400 100644 --- a/src/interpreter/terminator/mod.rs +++ b/src/interpreter/terminator/mod.rs @@ -186,13 +186,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let mir = self.load_mir(resolved_def_id)?; let (return_ptr, return_to_block) = match destination { - Some((ptr, block)) => (Some(ptr), StackPopCleanup::Goto(block)), - None => (None, StackPopCleanup::None), + Some((ptr, block)) => (ptr, StackPopCleanup::Goto(block)), + None => (Pointer::never_ptr(), StackPopCleanup::None), }; self.push_stack_frame(resolved_def_id, span, mir, resolved_substs, return_ptr, return_to_block)?; for (i, (arg_val, arg_ty)) in args.into_iter().enumerate() { - let dest = self.frame().locals[i]; + // argument start at index 1, since index 0 is reserved for the return allocation + let dest = self.frame().locals[i + 1]; self.write_value(arg_val, dest, arg_ty)?; } diff --git a/src/memory.rs b/src/memory.rs index eeae014c6da1c..da1214acfb8ad 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -56,10 +56,10 @@ impl Pointer { self.alloc_id == ZST_ALLOC_ID } pub fn to_int<'tcx>(&self) -> EvalResult<'tcx, usize> { - if self.points_to_zst() { - Ok(self.offset) - } else { - Err(EvalError::ReadPointerAsBytes) + match self.alloc_id { + NEVER_ALLOC_ID | + ZST_ALLOC_ID => Ok(self.offset), + _ => Err(EvalError::ReadPointerAsBytes), } } pub fn from_int(i: usize) -> Self { @@ -74,6 +74,12 @@ impl Pointer { offset: 0, } } + pub fn never_ptr() -> Self { + Pointer { + alloc_id: NEVER_ALLOC_ID, + offset: 0, + } + } } #[derive(Debug, Clone, Hash, Eq, PartialEq)] @@ -115,6 +121,7 @@ pub struct Memory<'a, 'tcx> { } const ZST_ALLOC_ID: AllocId = AllocId(0); +const NEVER_ALLOC_ID: AllocId = AllocId(1); impl<'a, 'tcx> Memory<'a, 'tcx> { pub fn new(layout: &'a TargetDataLayout, max_memory: usize) -> Self { @@ -122,7 +129,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { alloc_map: HashMap::new(), functions: HashMap::new(), function_alloc_cache: HashMap::new(), - next_id: AllocId(1), + next_id: AllocId(2), layout: layout, memory_size: max_memory, memory_usage: 0,