diff options
Diffstat (limited to 'tests/ui/structs-enums')
153 files changed, 5393 insertions, 0 deletions
diff --git a/tests/ui/structs-enums/align-enum.rs b/tests/ui/structs-enums/align-enum.rs new file mode 100644 index 000000000..fa872caa3 --- /dev/null +++ b/tests/ui/structs-enums/align-enum.rs @@ -0,0 +1,54 @@ +// run-pass +#![allow(dead_code)] + +use std::mem; + +// Raising alignment +#[repr(align(16))] +enum Align16 { + Foo { foo: u32 }, + Bar { bar: u32 }, +} + +// Raise alignment by maximum +#[repr(align(1), align(16))] +#[repr(align(32))] +#[repr(align(4))] +enum Align32 { + Foo, + Bar, +} + +// Not reducing alignment +#[repr(align(4))] +enum AlsoAlign16 { + Foo { limb_with_align16: Align16 }, + Bar, +} + +// No niche for discriminant when used as limb +#[repr(align(16))] +struct NoNiche16(u64, u64); + +// Discriminant will require extra space, but enum needs to stay compatible +// with alignment 16 +#[repr(align(1))] +enum AnotherAlign16 { + Foo { limb_with_noniche16: NoNiche16 }, + Bar, + Baz, +} + +fn main() { + assert_eq!(mem::align_of::<Align16>(), 16); + assert_eq!(mem::size_of::<Align16>(), 16); + + assert_eq!(mem::align_of::<Align32>(), 32); + assert_eq!(mem::size_of::<Align32>(), 32); + + assert_eq!(mem::align_of::<AlsoAlign16>(), 16); + assert_eq!(mem::size_of::<AlsoAlign16>(), 16); + + assert_eq!(mem::align_of::<AnotherAlign16>(), 16); + assert_eq!(mem::size_of::<AnotherAlign16>(), 32); +} diff --git a/tests/ui/structs-enums/align-struct.rs b/tests/ui/structs-enums/align-struct.rs new file mode 100644 index 000000000..f5418e754 --- /dev/null +++ b/tests/ui/structs-enums/align-struct.rs @@ -0,0 +1,244 @@ +// run-pass +#![allow(dead_code)] + +use std::mem; + +// Raising alignment +#[repr(align(16))] +#[derive(Clone, Copy, Debug)] +struct Align16(i32); + +// Lowering has no effect +#[repr(align(1))] +struct Align1(i32); + +// Multiple attributes take the max +#[repr(align(4))] +#[repr(align(16))] +#[repr(align(8))] +struct AlignMany(i32); + +// Raising alignment may not alter size. +#[repr(align(8))] +#[allow(dead_code)] +struct Align8Many { + a: i32, + b: i32, + c: i32, + d: u8, +} + +enum Enum { + #[allow(dead_code)] + A(i32), + B(Align16) +} + +// Nested alignment - use `#[repr(C)]` to suppress field reordering for sizeof test +#[repr(C)] +struct Nested { + a: i32, + b: i32, + c: Align16, + d: i8, +} + +#[repr(packed)] +struct Packed(i32); + +#[repr(align(16))] +struct AlignContainsPacked { + a: Packed, + b: Packed, +} + +#[repr(C, packed(4))] +struct Packed4C { + a: u32, + b: u64, +} + +#[repr(align(16))] +struct AlignContainsPacked4C { + a: Packed4C, + b: u64, +} + +// The align limit was originally smaller (2^15). +// Check that it works with big numbers. +#[repr(align(0x10000))] +struct AlignLarge { + stuff: [u8; 0x10000], +} + +union UnionContainsAlign { + a: Align16, + b: f32 +} + +impl Align16 { + // return aligned type + pub fn new(i: i32) -> Align16 { + Align16(i) + } + // pass aligned type + pub fn consume(a: Align16) -> i32 { + a.0 + } +} + +const CONST_ALIGN16: Align16 = Align16(7); +static STATIC_ALIGN16: Align16 = Align16(8); + +// Check the actual address is aligned +fn is_aligned_to<T>(p: &T, align: usize) -> bool { + let addr = p as *const T as usize; + (addr & (align - 1)) == 0 +} + +pub fn main() { + // check alignment and size by type and value + assert_eq!(mem::align_of::<Align16>(), 16); + assert_eq!(mem::size_of::<Align16>(), 16); + + let a = Align16(7); + assert_eq!(a.0, 7); + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::size_of_val(&a), 16); + + assert!(is_aligned_to(&a, 16)); + + // lowering should have no effect + assert_eq!(mem::align_of::<Align1>(), 4); + assert_eq!(mem::size_of::<Align1>(), 4); + let a = Align1(7); + assert_eq!(a.0, 7); + assert_eq!(mem::align_of_val(&a), 4); + assert_eq!(mem::size_of_val(&a), 4); + assert!(is_aligned_to(&a, 4)); + + // when multiple attributes are specified the max should be used + assert_eq!(mem::align_of::<AlignMany>(), 16); + assert_eq!(mem::size_of::<AlignMany>(), 16); + let a = AlignMany(7); + assert_eq!(a.0, 7); + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::size_of_val(&a), 16); + assert!(is_aligned_to(&a, 16)); + + // raising alignment should not reduce size + assert_eq!(mem::align_of::<Align8Many>(), 8); + assert_eq!(mem::size_of::<Align8Many>(), 16); + let a = Align8Many { a: 1, b: 2, c: 3, d: 4 }; + assert_eq!(a.a, 1); + assert_eq!(mem::align_of_val(&a), 8); + assert_eq!(mem::size_of_val(&a), 16); + assert!(is_aligned_to(&a, 8)); + + // return type + let a = Align16::new(1); + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::size_of_val(&a), 16); + assert_eq!(a.0, 1); + assert!(is_aligned_to(&a, 16)); + assert_eq!(Align16::consume(a), 1); + + // check const alignment, size and value + assert_eq!(mem::align_of_val(&CONST_ALIGN16), 16); + assert_eq!(mem::size_of_val(&CONST_ALIGN16), 16); + assert_eq!(CONST_ALIGN16.0, 7); + assert!(is_aligned_to(&CONST_ALIGN16, 16)); + + // check global static alignment, size and value + assert_eq!(mem::align_of_val(&STATIC_ALIGN16), 16); + assert_eq!(mem::size_of_val(&STATIC_ALIGN16), 16); + assert_eq!(STATIC_ALIGN16.0, 8); + assert!(is_aligned_to(&STATIC_ALIGN16, 16)); + + // Note that the size of Nested may change if struct field re-ordering is enabled + assert_eq!(mem::align_of::<Nested>(), 16); + assert_eq!(mem::size_of::<Nested>(), 48); + let a = Nested{ a: 1, b: 2, c: Align16(3), d: 4}; + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::align_of_val(&a.b), 4); + assert_eq!(mem::align_of_val(&a.c), 16); + assert_eq!(mem::size_of_val(&a), 48); + assert!(is_aligned_to(&a, 16)); + // check the correct fields are indexed + assert_eq!(a.a, 1); + assert_eq!(a.b, 2); + assert_eq!(a.c.0, 3); + assert_eq!(a.d, 4); + + // enum should be aligned to max alignment + assert_eq!(mem::align_of::<Enum>(), 16); + assert_eq!(mem::align_of_val(&Enum::B(Align16(0))), 16); + let e = Enum::B(Align16(15)); + match e { + Enum::B(ref a) => { + assert_eq!(a.0, 15); + assert_eq!(mem::align_of_val(a), 16); + assert_eq!(mem::size_of_val(a), 16); + }, + _ => () + } + assert!(is_aligned_to(&e, 16)); + + // check union alignment + assert_eq!(mem::align_of::<UnionContainsAlign>(), 16); + assert_eq!(mem::size_of::<UnionContainsAlign>(), 16); + let u = UnionContainsAlign { a: Align16(10) }; + unsafe { + assert_eq!(mem::align_of_val(&u.a), 16); + assert_eq!(mem::size_of_val(&u.a), 16); + assert_eq!(u.a.0, 10); + let UnionContainsAlign { a } = u; + assert_eq!(a.0, 10); + } + + // arrays of aligned elements should also be aligned + assert_eq!(mem::align_of::<[Align16;2]>(), 16); + assert_eq!(mem::size_of::<[Align16;2]>(), 32); + + let a = [Align16(0), Align16(1)]; + assert_eq!(mem::align_of_val(&a[0]), 16); + assert_eq!(mem::align_of_val(&a[1]), 16); + assert!(is_aligned_to(&a, 16)); + + // check heap value is aligned + assert_eq!(mem::align_of_val(Box::new(Align16(0)).as_ref()), 16); + + // check heap array is aligned + let a = vec!(Align16(0), Align16(1)); + assert_eq!(mem::align_of_val(&a[0]), 16); + assert_eq!(mem::align_of_val(&a[1]), 16); + + assert_eq!(mem::align_of::<AlignContainsPacked>(), 16); + assert_eq!(mem::size_of::<AlignContainsPacked>(), 16); + let a = AlignContainsPacked { a: Packed(1), b: Packed(2) }; + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::align_of_val(&a.a), 1); + assert_eq!(mem::align_of_val(&a.b), 1); + assert_eq!(mem::size_of_val(&a), 16); + assert!(is_aligned_to(&a, 16)); + + assert_eq!(mem::align_of::<AlignContainsPacked4C>(), 16); + assert_eq!(mem::size_of::<AlignContainsPacked4C>(), 32); + let a = AlignContainsPacked4C { a: Packed4C{ a: 1, b: 2 }, b: 3 }; + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::align_of_val(&a.a), 4); + assert_eq!(mem::align_of_val(&a.b), mem::align_of::<u64>()); + assert_eq!(mem::size_of_val(&a), 32); + assert!(is_aligned_to(&a, 16)); + + let mut large = Box::new(AlignLarge { + stuff: [0; 0x10000], + }); + large.stuff[0] = 132; + *large.stuff.last_mut().unwrap() = 102; + assert_eq!(large.stuff[0], 132); + assert_eq!(large.stuff.last(), Some(&102)); + assert_eq!(mem::align_of::<AlignLarge>(), 0x10000); + assert_eq!(mem::align_of_val(&*large), 0x10000); + assert!(is_aligned_to(&*large, 0x10000)); +} diff --git a/tests/ui/structs-enums/auxiliary/cci_class.rs b/tests/ui/structs-enums/auxiliary/cci_class.rs new file mode 100644 index 000000000..de2945d74 --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/cci_class.rs @@ -0,0 +1,14 @@ +pub mod kitties { + pub struct cat { + meows : usize, + + pub how_hungry : isize, + } + + pub fn cat(in_x : usize, in_y : isize) -> cat { + cat { + meows: in_x, + how_hungry: in_y + } + } +} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_2.rs b/tests/ui/structs-enums/auxiliary/cci_class_2.rs new file mode 100644 index 000000000..c3de3150e --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/cci_class_2.rs @@ -0,0 +1,19 @@ +pub mod kitties { + pub struct cat { + meows : usize, + + pub how_hungry : isize, + + } + + impl cat { + pub fn speak(&self) {} + } + + pub fn cat(in_x : usize, in_y : isize) -> cat { + cat { + meows: in_x, + how_hungry: in_y + } + } +} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_3.rs b/tests/ui/structs-enums/auxiliary/cci_class_3.rs new file mode 100644 index 000000000..fb7fad0b5 --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/cci_class_3.rs @@ -0,0 +1,19 @@ +pub mod kitties { + pub struct cat { + meows : usize, + + pub how_hungry : isize, + } + + impl cat { + pub fn speak(&mut self) { self.meows += 1; } + pub fn meow_count(&mut self) -> usize { self.meows } + } + + pub fn cat(in_x : usize, in_y : isize) -> cat { + cat { + meows: in_x, + how_hungry: in_y + } + } +} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_4.rs b/tests/ui/structs-enums/auxiliary/cci_class_4.rs new file mode 100644 index 000000000..85aa3bc8c --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/cci_class_4.rs @@ -0,0 +1,41 @@ +pub mod kitties { + pub struct cat { + meows : usize, + + pub how_hungry : isize, + pub name : String, + } + + impl cat { + pub fn speak(&mut self) { self.meow(); } + + pub fn eat(&mut self) -> bool { + if self.how_hungry > 0 { + println!("OM NOM NOM"); + self.how_hungry -= 2; + return true; + } else { + println!("Not hungry!"); + return false; + } + } + } + + impl cat { + pub fn meow(&mut self) { + println!("Meow"); + self.meows += 1; + if self.meows % 5 == 0 { + self.how_hungry += 1; + } + } + } + + pub fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { + cat { + meows: in_x, + how_hungry: in_y, + name: in_name + } + } +} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_6.rs b/tests/ui/structs-enums/auxiliary/cci_class_6.rs new file mode 100644 index 000000000..35f93d0c6 --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/cci_class_6.rs @@ -0,0 +1,25 @@ +pub mod kitties { + + pub struct cat<U> { + info : Vec<U> , + meows : usize, + + pub how_hungry : isize, + } + + impl<U> cat<U> { + pub fn speak<T>(&mut self, stuff: Vec<T> ) { + self.meows += stuff.len(); + } + + pub fn meow_count(&mut self) -> usize { self.meows } + } + + pub fn cat<U>(in_x : usize, in_y : isize, in_info: Vec<U> ) -> cat<U> { + cat { + meows: in_x, + how_hungry: in_y, + info: in_info + } + } +} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_cast.rs b/tests/ui/structs-enums/auxiliary/cci_class_cast.rs new file mode 100644 index 000000000..dfc3c56dd --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/cci_class_cast.rs @@ -0,0 +1,50 @@ +pub mod kitty { + use std::fmt; + + pub struct cat { + meows : usize, + pub how_hungry : isize, + pub name : String, + } + + impl fmt::Display for cat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name) + } + } + + impl cat { + fn meow(&mut self) { + println!("Meow"); + self.meows += 1; + if self.meows % 5 == 0 { + self.how_hungry += 1; + } + } + + } + + impl cat { + pub fn speak(&mut self) { self.meow(); } + + pub fn eat(&mut self) -> bool { + if self.how_hungry > 0 { + println!("OM NOM NOM"); + self.how_hungry -= 2; + return true; + } + else { + println!("Not hungry!"); + return false; + } + } + } + + pub fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { + cat { + meows: in_x, + how_hungry: in_y, + name: in_name + } + } +} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_trait.rs b/tests/ui/structs-enums/auxiliary/cci_class_trait.rs new file mode 100644 index 000000000..2d02b591c --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/cci_class_trait.rs @@ -0,0 +1,5 @@ +pub mod animals { + pub trait noisy { + fn speak(&mut self); + } +} diff --git a/tests/ui/structs-enums/auxiliary/empty-struct.rs b/tests/ui/structs-enums/auxiliary/empty-struct.rs new file mode 100644 index 000000000..93275e714 --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/empty-struct.rs @@ -0,0 +1,9 @@ +pub struct XEmpty1 {} +pub struct XEmpty2; +pub struct XEmpty7(); + +pub enum XE { + XEmpty3 {}, + XEmpty4, + XEmpty6(), +} diff --git a/tests/ui/structs-enums/auxiliary/namespaced_enum_emulate_flat.rs b/tests/ui/structs-enums/auxiliary/namespaced_enum_emulate_flat.rs new file mode 100644 index 000000000..55e6b34ac --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/namespaced_enum_emulate_flat.rs @@ -0,0 +1,25 @@ +pub use Foo::*; + +pub enum Foo { + A, + B(isize), + C { a: isize }, +} + +impl Foo { + pub fn foo() {} +} + +pub mod nest { + pub use self::Bar::*; + + pub enum Bar { + D, + E(isize), + F { a: isize }, + } + + impl Bar { + pub fn foo() {} + } +} diff --git a/tests/ui/structs-enums/auxiliary/namespaced_enums.rs b/tests/ui/structs-enums/auxiliary/namespaced_enums.rs new file mode 100644 index 000000000..d3548c76c --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/namespaced_enums.rs @@ -0,0 +1,10 @@ +pub enum Foo { + A, + B(isize), + C { a: isize }, +} + +impl Foo { + pub fn foo() {} + pub fn bar(&self) {} +} diff --git a/tests/ui/structs-enums/auxiliary/newtype_struct_xc.rs b/tests/ui/structs-enums/auxiliary/newtype_struct_xc.rs new file mode 100644 index 000000000..9d1e0742e --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/newtype_struct_xc.rs @@ -0,0 +1,3 @@ +#![crate_type="lib"] + +pub struct Au(pub isize); diff --git a/tests/ui/structs-enums/auxiliary/struct_destructuring_cross_crate.rs b/tests/ui/structs-enums/auxiliary/struct_destructuring_cross_crate.rs new file mode 100644 index 000000000..3665ae7e8 --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/struct_destructuring_cross_crate.rs @@ -0,0 +1,6 @@ +#![crate_type="lib"] + +pub struct S { + pub x: isize, + pub y: isize, +} diff --git a/tests/ui/structs-enums/auxiliary/struct_variant_xc_aux.rs b/tests/ui/structs-enums/auxiliary/struct_variant_xc_aux.rs new file mode 100644 index 000000000..e919df611 --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/struct_variant_xc_aux.rs @@ -0,0 +1,8 @@ +#![crate_name="struct_variant_xc_aux"] +#![crate_type = "lib"] + +#[derive(Copy, Clone)] +pub enum Enum { + Variant(u8), + StructVariant { arg: u8 } +} diff --git a/tests/ui/structs-enums/auxiliary/xcrate_struct_aliases.rs b/tests/ui/structs-enums/auxiliary/xcrate_struct_aliases.rs new file mode 100644 index 000000000..bc8879aa3 --- /dev/null +++ b/tests/ui/structs-enums/auxiliary/xcrate_struct_aliases.rs @@ -0,0 +1,6 @@ +pub struct S { + pub x: isize, + pub y: isize, +} + +pub type S2 = S; diff --git a/tests/ui/structs-enums/borrow-tuple-fields.rs b/tests/ui/structs-enums/borrow-tuple-fields.rs new file mode 100644 index 000000000..b1d8f9164 --- /dev/null +++ b/tests/ui/structs-enums/borrow-tuple-fields.rs @@ -0,0 +1,38 @@ +// run-pass + +struct Foo(isize, isize); + +fn main() { + let x = (1, 2); + let a = &x.0; + let b = &x.0; + assert_eq!(*a, 1); + assert_eq!(*b, 1); + + let mut x = (1, 2); + { + let a = &x.0; + let b = &mut x.1; + *b = 5; + assert_eq!(*a, 1); + } + assert_eq!(x.0, 1); + assert_eq!(x.1, 5); + + + let x = Foo(1, 2); + let a = &x.0; + let b = &x.0; + assert_eq!(*a, 1); + assert_eq!(*b, 1); + + let mut x = Foo(1, 2); + { + let a = &x.0; + let b = &mut x.1; + *b = 5; + assert_eq!(*a, 1); + } + assert_eq!(x.0, 1); + assert_eq!(x.1, 5); +} diff --git a/tests/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs b/tests/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs new file mode 100644 index 000000000..f870096fd --- /dev/null +++ b/tests/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs @@ -0,0 +1,18 @@ +// run-pass +// aux-build:cci_class_cast.rs + +extern crate cci_class_cast; + +use std::string::ToString; +use cci_class_cast::kitty::cat; + +fn print_out(thing: Box<dyn ToString>, expected: String) { + let actual = (*thing).to_string(); + println!("{}", actual); + assert_eq!(actual.to_string(), expected); +} + +pub fn main() { + let nyan: Box<dyn ToString> = Box::new(cat(0, 2, "nyan".to_string())) as Box<dyn ToString>; + print_out(nyan, "nyan".to_string()); +} diff --git a/tests/ui/structs-enums/class-cast-to-trait-multiple-types.rs b/tests/ui/structs-enums/class-cast-to-trait-multiple-types.rs new file mode 100644 index 000000000..ca35a615d --- /dev/null +++ b/tests/ui/structs-enums/class-cast-to-trait-multiple-types.rs @@ -0,0 +1,94 @@ +// run-pass +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +trait noisy { + fn speak(&mut self) -> isize; +} + +struct dog { + barks: usize, + + volume: isize, +} + +impl dog { + fn bark(&mut self) -> isize { + println!("Woof {} {}", self.barks, self.volume); + self.barks += 1_usize; + if self.barks % 3_usize == 0_usize { + self.volume += 1; + } + if self.barks % 10_usize == 0_usize { + self.volume -= 2; + } + println!("Grrr {} {}", self.barks, self.volume); + self.volume + } +} + +impl noisy for dog { + fn speak(&mut self) -> isize { + self.bark() + } +} + +fn dog() -> dog { + dog { + volume: 0, + barks: 0_usize + } +} + +#[derive(Clone)] +struct cat { + meows: usize, + + how_hungry: isize, + name: String, +} + +impl noisy for cat { + fn speak(&mut self) -> isize { + self.meow() as isize + } +} + +impl cat { + pub fn meow_count(&self) -> usize { + self.meows + } +} + +impl cat { + fn meow(&mut self) -> usize { + println!("Meow"); + self.meows += 1_usize; + if self.meows % 5_usize == 0_usize { + self.how_hungry += 1; + } + self.meows + } +} + +fn cat(in_x: usize, in_y: isize, in_name: String) -> cat { + cat { + meows: in_x, + how_hungry: in_y, + name: in_name + } +} + + +fn annoy_neighbors(critter: &mut dyn noisy) { + for _i in 0_usize..10 { critter.speak(); } +} + +pub fn main() { + let mut nyan: cat = cat(0_usize, 2, "nyan".to_string()); + let mut whitefang: dog = dog(); + annoy_neighbors(&mut nyan); + annoy_neighbors(&mut whitefang); + assert_eq!(nyan.meow_count(), 10_usize); + assert_eq!(whitefang.volume, 1); +} diff --git a/tests/ui/structs-enums/class-cast-to-trait.rs b/tests/ui/structs-enums/class-cast-to-trait.rs new file mode 100644 index 000000000..1019bb300 --- /dev/null +++ b/tests/ui/structs-enums/class-cast-to-trait.rs @@ -0,0 +1,60 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_mut)] +#![allow(non_camel_case_types)] + +// ignore-freebsd FIXME fails on BSD + + +trait noisy { + fn speak(&mut self); +} + +struct cat { + meows: usize, + how_hungry: isize, + name: String, +} + +impl noisy for cat { + fn speak(&mut self) { self.meow(); } +} + +impl cat { + pub fn eat(&mut self) -> bool { + if self.how_hungry > 0 { + println!("OM NOM NOM"); + self.how_hungry -= 2; + return true; + } + else { + println!("Not hungry!"); + return false; + } + } +} + +impl cat { + fn meow(&mut self) { + println!("Meow"); + self.meows += 1; + if self.meows % 5 == 0 { + self.how_hungry += 1; + } + } +} + +fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { + cat { + meows: in_x, + how_hungry: in_y, + name: in_name + } +} + + +pub fn main() { + let mut nyan = cat(0, 2, "nyan".to_string()); + let mut nyan: &mut dyn noisy = &mut nyan; + nyan.speak(); +} diff --git a/tests/ui/structs-enums/class-dtor.rs b/tests/ui/structs-enums/class-dtor.rs new file mode 100644 index 000000000..583a5e240 --- /dev/null +++ b/tests/ui/structs-enums/class-dtor.rs @@ -0,0 +1,25 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +// pretty-expanded FIXME #23616 + +struct cat { + done : extern "C" fn(usize), + meows : usize, +} + +impl Drop for cat { + fn drop(&mut self) { + (self.done)(self.meows); + } +} + +fn cat(done: extern "C" fn(usize)) -> cat { + cat { + meows: 0, + done: done + } +} + +pub fn main() {} diff --git a/tests/ui/structs-enums/class-exports.rs b/tests/ui/structs-enums/class-exports.rs new file mode 100644 index 000000000..ee20887cb --- /dev/null +++ b/tests/ui/structs-enums/class-exports.rs @@ -0,0 +1,31 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +/* Test that exporting a class also exports its + public fields and methods */ + +use kitty::cat; + +mod kitty { + pub struct cat { + meows: usize, + name: String, + } + + impl cat { + pub fn get_name(&self) -> String { self.name.clone() } + } + + pub fn cat(in_name: String) -> cat { + cat { + name: in_name, + meows: 0 + } + } +} + +pub fn main() { + assert_eq!(cat("Spreckles".to_string()).get_name(), + "Spreckles".to_string()); +} diff --git a/tests/ui/structs-enums/class-impl-very-parameterized-trait.rs b/tests/ui/structs-enums/class-impl-very-parameterized-trait.rs new file mode 100644 index 000000000..5e7830296 --- /dev/null +++ b/tests/ui/structs-enums/class-impl-very-parameterized-trait.rs @@ -0,0 +1,107 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +use std::cmp; + +#[derive(Copy, Clone, Debug)] +enum cat_type { tuxedo, tabby, tortoiseshell } + +impl cmp::PartialEq for cat_type { + fn eq(&self, other: &cat_type) -> bool { + ((*self) as usize) == ((*other) as usize) + } + fn ne(&self, other: &cat_type) -> bool { !(*self).eq(other) } +} + +// Very silly -- this just returns the value of the name field +// for any isize value that's less than the meows field + +// ok: T should be in scope when resolving the trait ref for map +struct cat<T> { + // Yes, you can have negative meows + meows : isize, + + how_hungry : isize, + name : T, +} + +impl<T> cat<T> { + pub fn speak(&mut self) { self.meow(); } + + pub fn eat(&mut self) -> bool { + if self.how_hungry > 0 { + println!("OM NOM NOM"); + self.how_hungry -= 2; + return true; + } else { + println!("Not hungry!"); + return false; + } + } + fn len(&self) -> usize { self.meows as usize } + fn is_empty(&self) -> bool { self.meows == 0 } + fn clear(&mut self) {} + fn contains_key(&self, k: &isize) -> bool { *k <= self.meows } + + fn find(&self, k: &isize) -> Option<&T> { + if *k <= self.meows { + Some(&self.name) + } else { + None + } + } + fn insert(&mut self, k: isize, _: T) -> bool { + self.meows += k; + true + } + + fn find_mut(&mut self, _k: &isize) -> Option<&mut T> { panic!() } + + fn remove(&mut self, k: &isize) -> bool { + if self.find(k).is_some() { + self.meows -= *k; true + } else { + false + } + } + + fn pop(&mut self, _k: &isize) -> Option<T> { panic!() } + + fn swap(&mut self, _k: isize, _v: T) -> Option<T> { panic!() } +} + +impl<T> cat<T> { + pub fn get(&self, k: &isize) -> &T { + match self.find(k) { + Some(v) => { v } + None => { panic!("epic fail"); } + } + } + + pub fn new(in_x: isize, in_y: isize, in_name: T) -> cat<T> { + cat{meows: in_x, how_hungry: in_y, name: in_name } + } +} + +impl<T> cat<T> { + fn meow(&mut self) { + self.meows += 1; + println!("Meow {}", self.meows); + if self.meows % 5 == 0 { + self.how_hungry += 1; + } + } +} + +pub fn main() { + let mut nyan: cat<String> = cat::new(0, 2, "nyan".to_string()); + for _ in 1_usize..5 { nyan.speak(); } + assert_eq!(*nyan.find(&1).unwrap(), "nyan".to_string()); + assert_eq!(nyan.find(&10), None); + let mut spotty: cat<cat_type> = cat::new(2, 57, cat_type::tuxedo); + for _ in 0_usize..6 { spotty.speak(); } + assert_eq!(spotty.len(), 8); + assert!((spotty.contains_key(&2))); + assert_eq!(spotty.get(&3), &cat_type::tuxedo); +} diff --git a/tests/ui/structs-enums/class-implement-trait-cross-crate.rs b/tests/ui/structs-enums/class-implement-trait-cross-crate.rs new file mode 100644 index 000000000..31b795175 --- /dev/null +++ b/tests/ui/structs-enums/class-implement-trait-cross-crate.rs @@ -0,0 +1,59 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +// aux-build:cci_class_trait.rs +extern crate cci_class_trait; +use cci_class_trait::animals::noisy; + +struct cat { + meows: usize, + + how_hungry : isize, + name : String, +} + +impl cat { + pub fn eat(&mut self) -> bool { + if self.how_hungry > 0 { + println!("OM NOM NOM"); + self.how_hungry -= 2; + return true; + } + else { + println!("Not hungry!"); + return false; + } + } +} + +impl noisy for cat { + fn speak(&mut self) { self.meow(); } +} + +impl cat { + fn meow(&mut self) { + println!("Meow"); + self.meows += 1_usize; + if self.meows % 5_usize == 0_usize { + self.how_hungry += 1; + } + } +} + +fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { + cat { + meows: in_x, + how_hungry: in_y, + name: in_name + } +} + + +pub fn main() { + let mut nyan = cat(0_usize, 2, "nyan".to_string()); + nyan.eat(); + assert!((!nyan.eat())); + for _ in 1_usize..10_usize { nyan.speak(); }; + assert!((nyan.eat())); +} diff --git a/tests/ui/structs-enums/class-implement-traits.rs b/tests/ui/structs-enums/class-implement-traits.rs new file mode 100644 index 000000000..732aa146c --- /dev/null +++ b/tests/ui/structs-enums/class-implement-traits.rs @@ -0,0 +1,64 @@ +// run-pass +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +trait noisy { + fn speak(&mut self); +} + +#[derive(Clone)] +struct cat { + meows : usize, + + how_hungry : isize, + name : String, +} + +impl cat { + fn meow(&mut self) { + println!("Meow"); + self.meows += 1_usize; + if self.meows % 5_usize == 0_usize { + self.how_hungry += 1; + } + } +} + +impl cat { + pub fn eat(&mut self) -> bool { + if self.how_hungry > 0 { + println!("OM NOM NOM"); + self.how_hungry -= 2; + return true; + } else { + println!("Not hungry!"); + return false; + } + } +} + +impl noisy for cat { + fn speak(&mut self) { self.meow(); } +} + +fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { + cat { + meows: in_x, + how_hungry: in_y, + name: in_name.clone() + } +} + + +fn make_speak<C:noisy>(mut c: C) { + c.speak(); +} + +pub fn main() { + let mut nyan = cat(0_usize, 2, "nyan".to_string()); + nyan.eat(); + assert!((!nyan.eat())); + for _ in 1_usize..10_usize { + make_speak(nyan.clone()); + } +} diff --git a/tests/ui/structs-enums/class-method-cross-crate.rs b/tests/ui/structs-enums/class-method-cross-crate.rs new file mode 100644 index 000000000..519f0685f --- /dev/null +++ b/tests/ui/structs-enums/class-method-cross-crate.rs @@ -0,0 +1,13 @@ +// run-pass +// aux-build:cci_class_2.rs + +extern crate cci_class_2; +use cci_class_2::kitties::cat; + +pub fn main() { + let nyan : cat = cat(52, 99); + let kitty = cat(1000, 2); + assert_eq!(nyan.how_hungry, 99); + assert_eq!(kitty.how_hungry, 2); + nyan.speak(); +} diff --git a/tests/ui/structs-enums/class-methods-cross-crate.rs b/tests/ui/structs-enums/class-methods-cross-crate.rs new file mode 100644 index 000000000..c342af313 --- /dev/null +++ b/tests/ui/structs-enums/class-methods-cross-crate.rs @@ -0,0 +1,14 @@ +// run-pass +// aux-build:cci_class_3.rs + +extern crate cci_class_3; +use cci_class_3::kitties::cat; + +pub fn main() { + let mut nyan : cat = cat(52, 99); + let kitty = cat(1000, 2); + assert_eq!(nyan.how_hungry, 99); + assert_eq!(kitty.how_hungry, 2); + nyan.speak(); + assert_eq!(nyan.meow_count(), 53); +} diff --git a/tests/ui/structs-enums/class-methods.rs b/tests/ui/structs-enums/class-methods.rs new file mode 100644 index 000000000..83f4a5fd3 --- /dev/null +++ b/tests/ui/structs-enums/class-methods.rs @@ -0,0 +1,30 @@ +// run-pass +#![allow(non_camel_case_types)] + + +struct cat { + meows : usize, + + how_hungry : isize, +} + +impl cat { + pub fn speak(&mut self) { self.meows += 1; } + pub fn meow_count(&mut self) -> usize { self.meows } +} + +fn cat(in_x: usize, in_y: isize) -> cat { + cat { + meows: in_x, + how_hungry: in_y + } +} + +pub fn main() { + let mut nyan: cat = cat(52, 99); + let kitty = cat(1000, 2); + assert_eq!(nyan.how_hungry, 99); + assert_eq!(kitty.how_hungry, 2); + nyan.speak(); + assert_eq!(nyan.meow_count(), 53); +} diff --git a/tests/ui/structs-enums/class-poly-methods-cross-crate.rs b/tests/ui/structs-enums/class-poly-methods-cross-crate.rs new file mode 100644 index 000000000..0307ba78d --- /dev/null +++ b/tests/ui/structs-enums/class-poly-methods-cross-crate.rs @@ -0,0 +1,16 @@ +// run-pass +// aux-build:cci_class_6.rs + +extern crate cci_class_6; +use cci_class_6::kitties::cat; + +pub fn main() { + let mut nyan : cat<char> = cat::<char>(52_usize, 99, vec!['p']); + let mut kitty = cat(1000_usize, 2, vec!["tabby".to_string()]); + assert_eq!(nyan.how_hungry, 99); + assert_eq!(kitty.how_hungry, 2); + nyan.speak(vec![1_usize,2_usize,3_usize]); + assert_eq!(nyan.meow_count(), 55_usize); + kitty.speak(vec!["meow".to_string(), "mew".to_string(), "purr".to_string(), "chirp".to_string()]); + assert_eq!(kitty.meow_count(), 1004_usize); +} diff --git a/tests/ui/structs-enums/class-poly-methods.rs b/tests/ui/structs-enums/class-poly-methods.rs new file mode 100644 index 000000000..da2870b58 --- /dev/null +++ b/tests/ui/structs-enums/class-poly-methods.rs @@ -0,0 +1,37 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + + +struct cat<U> { + info : Vec<U> , + meows : usize, + + how_hungry : isize, +} + +impl<U> cat<U> { + pub fn speak<T>(&mut self, stuff: Vec<T> ) { + self.meows += stuff.len(); + } + pub fn meow_count(&mut self) -> usize { self.meows } +} + +fn cat<U>(in_x : usize, in_y : isize, in_info: Vec<U> ) -> cat<U> { + cat { + meows: in_x, + how_hungry: in_y, + info: in_info + } +} + +pub fn main() { + let mut nyan : cat<isize> = cat::<isize>(52, 99, vec![9]); + let mut kitty = cat(1000, 2, vec!["tabby".to_string()]); + assert_eq!(nyan.how_hungry, 99); + assert_eq!(kitty.how_hungry, 2); + nyan.speak(vec![1,2,3]); + assert_eq!(nyan.meow_count(), 55); + kitty.speak(vec!["meow".to_string(), "mew".to_string(), "purr".to_string(), "chirp".to_string()]); + assert_eq!(kitty.meow_count(), 1004); +} diff --git a/tests/ui/structs-enums/class-separate-impl.rs b/tests/ui/structs-enums/class-separate-impl.rs new file mode 100644 index 000000000..3d6da1cc2 --- /dev/null +++ b/tests/ui/structs-enums/class-separate-impl.rs @@ -0,0 +1,63 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +use std::fmt; + +struct cat { + meows : usize, + + how_hungry : isize, + name : String, +} + +impl cat { + pub fn speak(&mut self) { self.meow(); } + + pub fn eat(&mut self) -> bool { + if self.how_hungry > 0 { + println!("OM NOM NOM"); + self.how_hungry -= 2; + return true; + } + else { + println!("Not hungry!"); + return false; + } + } +} + +impl cat { + fn meow(&mut self) { + println!("Meow"); + self.meows += 1; + if self.meows % 5 == 0 { + self.how_hungry += 1; + } + } +} + +fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { + cat { + meows: in_x, + how_hungry: in_y, + name: in_name + } +} + +impl fmt::Display for cat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name) + } +} + +fn print_out(thing: Box<dyn ToString>, expected: String) { + let actual = (*thing).to_string(); + println!("{}", actual); + assert_eq!(actual.to_string(), expected); +} + +pub fn main() { + let nyan: Box<dyn ToString> = Box::new(cat(0, 2, "nyan".to_string())) as Box<dyn ToString>; + print_out(nyan, "nyan".to_string()); +} diff --git a/tests/ui/structs-enums/class-str-field.rs b/tests/ui/structs-enums/class-str-field.rs new file mode 100644 index 000000000..a3dc66aab --- /dev/null +++ b/tests/ui/structs-enums/class-str-field.rs @@ -0,0 +1,21 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +// pretty-expanded FIXME #23616 + +struct cat { + + name : String, + +} + +fn cat(in_name: String) -> cat { + cat { + name: in_name + } +} + +pub fn main() { + let _nyan = cat("nyan".to_string()); +} diff --git a/tests/ui/structs-enums/class-typarams.rs b/tests/ui/structs-enums/class-typarams.rs new file mode 100644 index 000000000..4b2d4b12e --- /dev/null +++ b/tests/ui/structs-enums/class-typarams.rs @@ -0,0 +1,32 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +// pretty-expanded FIXME #23616 + +use std::marker::PhantomData; + +struct cat<U> { + meows : usize, + how_hungry : isize, + m: PhantomData<U> +} + +impl<U> cat<U> { + pub fn speak(&mut self) { self.meows += 1; } + pub fn meow_count(&mut self) -> usize { self.meows } +} + +fn cat<U>(in_x : usize, in_y : isize) -> cat<U> { + cat { + meows: in_x, + how_hungry: in_y, + m: PhantomData + } +} + + +pub fn main() { + let _nyan : cat<isize> = cat::<isize>(52, 99); + // let mut kitty = cat(1000, 2); +} diff --git a/tests/ui/structs-enums/classes-cross-crate.rs b/tests/ui/structs-enums/classes-cross-crate.rs new file mode 100644 index 000000000..ca362c7a7 --- /dev/null +++ b/tests/ui/structs-enums/classes-cross-crate.rs @@ -0,0 +1,13 @@ +// run-pass +// aux-build:cci_class_4.rs + +extern crate cci_class_4; +use cci_class_4::kitties::cat; + +pub fn main() { + let mut nyan = cat(0_usize, 2, "nyan".to_string()); + nyan.eat(); + assert!((!nyan.eat())); + for _ in 1_usize..10_usize { nyan.speak(); }; + assert!((nyan.eat())); +} diff --git a/tests/ui/structs-enums/classes-self-referential.rs b/tests/ui/structs-enums/classes-self-referential.rs new file mode 100644 index 000000000..27d6ebf2c --- /dev/null +++ b/tests/ui/structs-enums/classes-self-referential.rs @@ -0,0 +1,20 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + + +// pretty-expanded FIXME #23616 + +struct kitten { + cat: Option<cat>, +} + +fn kitten(cat: Option<cat>) -> kitten { + kitten { + cat: cat + } +} + +type cat = Box<kitten>; + +pub fn main() {} diff --git a/tests/ui/structs-enums/classes-simple-cross-crate.rs b/tests/ui/structs-enums/classes-simple-cross-crate.rs new file mode 100644 index 000000000..6ff0970c0 --- /dev/null +++ b/tests/ui/structs-enums/classes-simple-cross-crate.rs @@ -0,0 +1,12 @@ +// run-pass +// aux-build:cci_class.rs + +extern crate cci_class; +use cci_class::kitties::cat; + +pub fn main() { + let nyan : cat = cat(52, 99); + let kitty = cat(1000, 2); + assert_eq!(nyan.how_hungry, 99); + assert_eq!(kitty.how_hungry, 2); +} diff --git a/tests/ui/structs-enums/classes-simple-method.rs b/tests/ui/structs-enums/classes-simple-method.rs new file mode 100644 index 000000000..f3d98337d --- /dev/null +++ b/tests/ui/structs-enums/classes-simple-method.rs @@ -0,0 +1,28 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +struct cat { + meows : usize, + + how_hungry : isize, +} + +impl cat { + pub fn speak(&mut self) {} +} + +fn cat(in_x : usize, in_y : isize) -> cat { + cat { + meows: in_x, + how_hungry: in_y + } +} + +pub fn main() { + let mut nyan : cat = cat(52, 99); + let kitty = cat(1000, 2); + assert_eq!(nyan.how_hungry, 99); + assert_eq!(kitty.how_hungry, 2); + nyan.speak(); +} diff --git a/tests/ui/structs-enums/classes-simple.rs b/tests/ui/structs-enums/classes-simple.rs new file mode 100644 index 000000000..568fbb29f --- /dev/null +++ b/tests/ui/structs-enums/classes-simple.rs @@ -0,0 +1,23 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +struct cat { + meows : usize, + + how_hungry : isize, +} + +fn cat(in_x : usize, in_y : isize) -> cat { + cat { + meows: in_x, + how_hungry: in_y + } +} + +pub fn main() { + let nyan : cat = cat(52, 99); + let kitty = cat(1000, 2); + assert_eq!(nyan.how_hungry, 99); + assert_eq!(kitty.how_hungry, 2); +} diff --git a/tests/ui/structs-enums/classes.rs b/tests/ui/structs-enums/classes.rs new file mode 100644 index 000000000..51d84b909 --- /dev/null +++ b/tests/ui/structs-enums/classes.rs @@ -0,0 +1,51 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +struct cat { + meows : usize, + + how_hungry : isize, + name : String, +} + +impl cat { + pub fn speak(&mut self) { self.meow(); } + + pub fn eat(&mut self) -> bool { + if self.how_hungry > 0 { + println!("OM NOM NOM"); + self.how_hungry -= 2; + return true; + } else { + println!("Not hungry!"); + return false; + } + } +} + +impl cat { + fn meow(&mut self) { + println!("Meow"); + self.meows += 1_usize; + if self.meows % 5_usize == 0_usize { + self.how_hungry += 1; + } + } +} + +fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { + cat { + meows: in_x, + how_hungry: in_y, + name: in_name + } +} + +pub fn main() { + let mut nyan = cat(0_usize, 2, "nyan".to_string()); + nyan.eat(); + assert!((!nyan.eat())); + for _ in 1_usize..10_usize { nyan.speak(); }; + assert!((nyan.eat())); +} diff --git a/tests/ui/structs-enums/codegen-tag-static-padding.rs b/tests/ui/structs-enums/codegen-tag-static-padding.rs new file mode 100644 index 000000000..8aa087c01 --- /dev/null +++ b/tests/ui/structs-enums/codegen-tag-static-padding.rs @@ -0,0 +1,59 @@ +// run-pass +#![allow(non_upper_case_globals)] + +// Issue #13186 + +// For simplicity of explanations assuming code is compiled for x86_64 +// Linux ABI. + +// Size of TestOption<u64> is 16, and alignment of TestOption<u64> is 8. +// Size of u8 is 1, and alignment of u8 is 1. +// So size of Request is 24, and alignment of Request must be 8: +// the maximum alignment of its fields. +// Last 7 bytes of Request struct are not occupied by any fields. + + + +enum TestOption<T> { + TestNone, + TestSome(T), +} + +pub struct Request { + foo: TestOption<u64>, + bar: u8, +} + +fn default_instance() -> &'static Request { + static instance: Request = Request { + // LLVM does not allow to specify alignment of expressions, thus + // alignment of `foo` in constant is 1, not 8. + foo: TestOption::TestNone, + bar: 17, + // Space after last field is not occupied by any data, but it is + // reserved to make struct aligned properly. If compiler does + // not insert padding after last field when emitting constant, + // size of struct may be not equal to size of struct, and + // compiler crashes in internal assertion check. + }; + &instance +} + +fn non_default_instance() -> &'static Request { + static instance: Request = Request { + foo: TestOption::TestSome(0x1020304050607080), + bar: 19, + }; + &instance +} + +pub fn main() { + match default_instance() { + &Request { foo: TestOption::TestNone, bar: 17 } => {}, + _ => panic!(), + }; + match non_default_instance() { + &Request { foo: TestOption::TestSome(0x1020304050607080), bar: 19 } => {}, + _ => panic!(), + }; +} diff --git a/tests/ui/structs-enums/compare-generic-enums.rs b/tests/ui/structs-enums/compare-generic-enums.rs new file mode 100644 index 000000000..84f953b1f --- /dev/null +++ b/tests/ui/structs-enums/compare-generic-enums.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(non_camel_case_types)] + + +type an_int = isize; + +fn cmp(x: Option<an_int>, y: Option<isize>) -> bool { + x == y +} + +pub fn main() { + assert!(!cmp(Some(3), None)); + assert!(!cmp(Some(3), Some(4))); + assert!(cmp(Some(3), Some(3))); + assert!(cmp(None, None)); +} diff --git a/tests/ui/structs-enums/cross-crate-newtype-struct-pat.rs b/tests/ui/structs-enums/cross-crate-newtype-struct-pat.rs new file mode 100644 index 000000000..eabffc161 --- /dev/null +++ b/tests/ui/structs-enums/cross-crate-newtype-struct-pat.rs @@ -0,0 +1,12 @@ +// run-pass +// aux-build:newtype_struct_xc.rs + + +extern crate newtype_struct_xc; + +pub fn main() { + let x = newtype_struct_xc::Au(21); + match x { + newtype_struct_xc::Au(n) => assert_eq!(n, 21) + } +} diff --git a/tests/ui/structs-enums/discrim-explicit-23030.rs b/tests/ui/structs-enums/discrim-explicit-23030.rs new file mode 100644 index 000000000..e17025e9e --- /dev/null +++ b/tests/ui/structs-enums/discrim-explicit-23030.rs @@ -0,0 +1,145 @@ +// run-pass +// Issue 23030: Workaround overflowing discriminant +// with explicit assignments. + +// See also ui/discrim/discrim-overflow.rs, which shows what +// happens if you leave the OhNo explicit cases out here. + +fn f_i8() { + #[repr(i8)] + enum A { + Ok = i8::MAX - 1, + Ok2, + OhNo = i8::MIN, + NotTheEnd = -1, + Zero, + } + + let _x = (A::Ok, A::Ok2, A::OhNo); + let z = (A::NotTheEnd, A::Zero).1 as i8; + assert_eq!(z, 0); +} + +fn f_u8() { + #[repr(u8)] + enum A { + Ok = u8::MAX - 1, + Ok2, + OhNo = u8::MIN, + } + + let _x = (A::Ok, A::Ok2, A::OhNo); +} + +fn f_i16() { + #[repr(i16)] + enum A { + Ok = i16::MAX - 1, + Ok2, + OhNo = i16::MIN, + NotTheEnd = -1, + Zero, + } + + let _x = (A::Ok, A::Ok2, A::OhNo); + let z = (A::NotTheEnd, A::Zero).1 as i16; + assert_eq!(z, 0); +} + +fn f_u16() { + #[repr(u16)] + enum A { + Ok = u16::MAX - 1, + Ok2, + OhNo = u16::MIN, + } + + let _x = (A::Ok, A::Ok2, A::OhNo); +} + +fn f_i32() { + #[repr(i32)] + enum A { + Ok = i32::MAX - 1, + Ok2, + OhNo = i32::MIN, + NotTheEnd = -1, + Zero, + } + + let _x = (A::Ok, A::Ok2, A::OhNo); + let z = (A::NotTheEnd, A::Zero).1 as i32; + assert_eq!(z, 0); +} + +fn f_u32() { + #[repr(u32)] + enum A { + Ok = u32::MAX - 1, + Ok2, + OhNo = u32::MIN, + } + + let _x = (A::Ok, A::Ok2, A::OhNo); +} + +fn f_i64() { + #[repr(i64)] + enum A { + Ok = i64::MAX - 1, + Ok2, + OhNo = i64::MIN, + NotTheEnd = -1, + Zero, + } + + let _x = (A::Ok, A::Ok2, A::OhNo); + let z = (A::NotTheEnd, A::Zero).1 as i64; + assert_eq!(z, 0); +} + +fn f_u64() { + #[repr(u64)] + enum A { + Ok = u64::MAX - 1, + Ok2, + OhNo = u64::MIN, + } + + let _x = (A::Ok, A::Ok2, A::OhNo); +} + +fn f_isize() { + #[repr(isize)] + enum A { + Ok = isize::MAX - 1, + Ok2, + OhNo = isize::MIN, + NotTheEnd = -1, + Zero, + } + + let _x = (A::Ok, A::Ok2, A::OhNo); + let z = (A::NotTheEnd, A::Zero).1 as isize; + assert_eq!(z, 0); +} + +fn f_usize() { + #[repr(usize)] + enum A { + Ok = usize::MAX - 1, + Ok2, + OhNo = usize::MIN, + } + + let _x = (A::Ok, A::Ok2, A::OhNo); +} + +fn main() { + f_i8(); f_u8(); + f_i16(); f_u16(); + f_i32(); f_u32(); + f_i64(); f_u64(); + + f_isize(); f_usize(); +} diff --git a/tests/ui/structs-enums/empty-struct-braces.rs b/tests/ui/structs-enums/empty-struct-braces.rs new file mode 100644 index 000000000..0663687c9 --- /dev/null +++ b/tests/ui/structs-enums/empty-struct-braces.rs @@ -0,0 +1,213 @@ +// run-pass +#![allow(unused_variables)] +#![allow(non_upper_case_globals)] + +// Empty struct defined with braces add names into type namespace +// Empty struct defined without braces add names into both type and value namespaces + +// aux-build:empty-struct.rs + +extern crate empty_struct; +use empty_struct::*; + +struct Empty1 {} +struct Empty2; +struct Empty7(); + +#[derive(PartialEq, Eq)] +struct Empty3 {} + +const Empty3: Empty3 = Empty3 {}; + +enum E { + Empty4 {}, + Empty5, + Empty6(), +} + +fn local() { + let e1: Empty1 = Empty1 {}; + let e2: Empty2 = Empty2 {}; + let e2: Empty2 = Empty2; + let e3: Empty3 = Empty3 {}; + let e3: Empty3 = Empty3; + let e4: E = E::Empty4 {}; + let e5: E = E::Empty5 {}; + let e5: E = E::Empty5; + let e6: E = E::Empty6 {}; + let e6: E = E::Empty6(); + let ctor6: fn() -> E = E::Empty6; + let e7: Empty7 = Empty7 {}; + let e7: Empty7 = Empty7(); + let ctor7: fn() -> Empty7 = Empty7; + + match e1 { + Empty1 {} => {} + } + match e2 { + Empty2 {} => {} + } + match e3 { + Empty3 {} => {} + } + match e4 { + E::Empty4 {} => {} + _ => {} + } + match e5 { + E::Empty5 {} => {} + _ => {} + } + match e6 { + E::Empty6 {} => {} + _ => {} + } + match e7 { + Empty7 {} => {} + } + + match e1 { + Empty1 { .. } => {} + } + match e2 { + Empty2 { .. } => {} + } + match e3 { + Empty3 { .. } => {} + } + match e4 { + E::Empty4 { .. } => {} + _ => {} + } + match e5 { + E::Empty5 { .. } => {} + _ => {} + } + match e6 { + E::Empty6 { .. } => {} + _ => {} + } + match e7 { + Empty7 { .. } => {} + } + + match e2 { + Empty2 => {} + } + match e3 { + Empty3 => {} + } + match e5 { + E::Empty5 => {} + _ => {} + } + match e6 { + E::Empty6() => {} + _ => {} + } + match e6 { + E::Empty6(..) => {} + _ => {} + } + match e7 { + Empty7() => {} + } + match e7 { + Empty7(..) => {} + } + + let e11: Empty1 = Empty1 { ..e1 }; + let e22: Empty2 = Empty2 { ..e2 }; + let e33: Empty3 = Empty3 { ..e3 }; + let e77: Empty7 = Empty7 { ..e7 }; +} + +fn xcrate() { + let e1: XEmpty1 = XEmpty1 {}; + let e2: XEmpty2 = XEmpty2 {}; + let e2: XEmpty2 = XEmpty2; + let e3: XE = XE::XEmpty3 {}; + let e4: XE = XE::XEmpty4 {}; + let e4: XE = XE::XEmpty4; + let e6: XE = XE::XEmpty6 {}; + let e6: XE = XE::XEmpty6(); + let ctor6: fn() -> XE = XE::XEmpty6; + let e7: XEmpty7 = XEmpty7 {}; + let e7: XEmpty7 = XEmpty7(); + let ctor7: fn() -> XEmpty7 = XEmpty7; + + match e1 { + XEmpty1 {} => {} + } + match e2 { + XEmpty2 {} => {} + } + match e3 { + XE::XEmpty3 {} => {} + _ => {} + } + match e4 { + XE::XEmpty4 {} => {} + _ => {} + } + match e6 { + XE::XEmpty6 {} => {} + _ => {} + } + match e7 { + XEmpty7 {} => {} + } + + match e1 { + XEmpty1 { .. } => {} + } + match e2 { + XEmpty2 { .. } => {} + } + match e3 { + XE::XEmpty3 { .. } => {} + _ => {} + } + match e4 { + XE::XEmpty4 { .. } => {} + _ => {} + } + match e6 { + XE::XEmpty6 { .. } => {} + _ => {} + } + match e7 { + XEmpty7 { .. } => {} + } + + match e2 { + XEmpty2 => {} + } + match e4 { + XE::XEmpty4 => {} + _ => {} + } + match e6 { + XE::XEmpty6() => {} + _ => {} + } + match e6 { + XE::XEmpty6(..) => {} + _ => {} + } + match e7 { + XEmpty7() => {} + } + match e7 { + XEmpty7(..) => {} + } + + let e11: XEmpty1 = XEmpty1 { ..e1 }; + let e22: XEmpty2 = XEmpty2 { ..e2 }; + let e77: XEmpty7 = XEmpty7 { ..e7 }; +} + +fn main() { + local(); + xcrate(); +} diff --git a/tests/ui/structs-enums/empty-tag.rs b/tests/ui/structs-enums/empty-tag.rs new file mode 100644 index 000000000..271ab72c7 --- /dev/null +++ b/tests/ui/structs-enums/empty-tag.rs @@ -0,0 +1,22 @@ +// run-pass +#![allow(unused_braces)] +#![allow(non_camel_case_types)] + +#[derive(Copy, Clone, Debug)] +enum chan { chan_t, } + +impl PartialEq for chan { + fn eq(&self, other: &chan) -> bool { + ((*self) as usize) == ((*other) as usize) + } + fn ne(&self, other: &chan) -> bool { !(*self).eq(other) } +} + +fn wrapper3(i: chan) { + assert_eq!(i, chan::chan_t); +} + +pub fn main() { + let wrapped = {||wrapper3(chan::chan_t)}; + wrapped(); +} diff --git a/tests/ui/structs-enums/enum-alignment.rs b/tests/ui/structs-enums/enum-alignment.rs new file mode 100644 index 000000000..108dfe2e6 --- /dev/null +++ b/tests/ui/structs-enums/enum-alignment.rs @@ -0,0 +1,24 @@ +// run-pass +#![allow(dead_code)] +#![allow(deprecated)] + +use std::mem; + +fn addr_of<T>(ptr: &T) -> usize { + ptr as *const T as usize +} + +fn is_aligned<T>(ptr: &T) -> bool { + unsafe { + let addr: usize = mem::transmute(ptr); + (addr % mem::min_align_of::<T>()) == 0 + } +} + +pub fn main() { + let x = Some(0u64); + match x { + None => panic!(), + Some(ref y) => assert!(is_aligned(y)) + } +} diff --git a/tests/ui/structs-enums/enum-clike-ffi-as-int.rs b/tests/ui/structs-enums/enum-clike-ffi-as-int.rs new file mode 100644 index 000000000..e2b2b43de --- /dev/null +++ b/tests/ui/structs-enums/enum-clike-ffi-as-int.rs @@ -0,0 +1,33 @@ +// run-pass +#![allow(dead_code)] + +/*! + * C-like enums have to be represented as LLVM ints, not wrapped in a + * struct, because it's important for the FFI that they interoperate + * with C integers/enums, and the ABI can treat structs differently. + * For example, on i686-linux-gnu, a struct return value is passed by + * storing to a hidden out parameter, whereas an integer would be + * returned in a register. + * + * This test just checks that the ABIs for the enum and the plain + * integer are compatible, rather than actually calling C code. + * The unused parameter to `foo` is to increase the likelihood of + * crashing if something goes wrong here. + */ + +#[repr(u32)] +enum Foo { + A = 0, + B = 23 +} + +#[inline(never)] +extern "C" fn foo(_x: usize) -> Foo { Foo::B } + +pub fn main() { + unsafe { + let f: extern "C" fn(usize) -> u32 = + ::std::mem::transmute(foo as extern "C" fn(usize) -> Foo); + assert_eq!(f(0xDEADBEEF), Foo::B as u32); + } +} diff --git a/tests/ui/structs-enums/enum-discr.rs b/tests/ui/structs-enums/enum-discr.rs new file mode 100644 index 000000000..bdd6df82d --- /dev/null +++ b/tests/ui/structs-enums/enum-discr.rs @@ -0,0 +1,23 @@ +// run-pass +#![allow(dead_code)] + +enum Animal { + Cat = 0, + Dog = 1, + Horse = 2, + Snake = 3, +} + +enum Hero { + Batman = -1, + Superman = -2, + Ironman = -3, + Spiderman = -4 +} + +pub fn main() { + let pet: Animal = Animal::Snake; + let hero: Hero = Hero::Superman; + assert_eq!(pet as usize, 3); + assert_eq!(hero as isize, -2); +} diff --git a/tests/ui/structs-enums/enum-discrim-autosizing.rs b/tests/ui/structs-enums/enum-discrim-autosizing.rs new file mode 100644 index 000000000..f68fdda60 --- /dev/null +++ b/tests/ui/structs-enums/enum-discrim-autosizing.rs @@ -0,0 +1,53 @@ +// run-pass +#![allow(dead_code)] +#![allow(overflowing_literals)] + +use std::mem::size_of; + +enum Ei8 { + Ai8 = -1, + Bi8 = 0 +} + +enum Eu8 { + Au8 = 0, + Bu8 = 0x80 +} + +enum Ei16 { + Ai16 = -1, + Bi16 = 0x80 +} + +enum Eu16 { + Au16 = 0, + Bu16 = 0x8000 +} + +enum Ei32 { + Ai32 = -1, + Bi32 = 0x8000 +} + +enum Eu32 { + Au32 = 0, + Bu32 = 0x8000_0000 +} + +enum Ei64 { + Ai64 = -1, + Bi64 = 0x8000_0000 +} + +pub fn main() { + assert_eq!(size_of::<Ei8>(), 1); + assert_eq!(size_of::<Eu8>(), 1); + assert_eq!(size_of::<Ei16>(), 2); + assert_eq!(size_of::<Eu16>(), 2); + assert_eq!(size_of::<Ei32>(), 4); + assert_eq!(size_of::<Eu32>(), 4); + #[cfg(target_pointer_width = "64")] + assert_eq!(size_of::<Ei64>(), 8); + #[cfg(target_pointer_width = "32")] + assert_eq!(size_of::<Ei64>(), 4); +} diff --git a/tests/ui/structs-enums/enum-discrim-manual-sizing.rs b/tests/ui/structs-enums/enum-discrim-manual-sizing.rs new file mode 100644 index 000000000..c8b362c99 --- /dev/null +++ b/tests/ui/structs-enums/enum-discrim-manual-sizing.rs @@ -0,0 +1,111 @@ +// run-pass +#![allow(dead_code)] + +use std::mem::{size_of, align_of}; + +#[repr(i8)] +enum Ei8 { + Ai8 = 0, + Bi8 = 1 +} + +#[repr(u8)] +enum Eu8 { + Au8 = 0, + Bu8 = 1 +} + +#[repr(i16)] +enum Ei16 { + Ai16 = 0, + Bi16 = 1 +} + +#[repr(u16)] +enum Eu16 { + Au16 = 0, + Bu16 = 1 +} + +#[repr(i32)] +enum Ei32 { + Ai32 = 0, + Bi32 = 1 +} + +#[repr(u32)] +enum Eu32 { + Au32 = 0, + Bu32 = 1 +} + +#[repr(i64)] +enum Ei64 { + Ai64 = 0, + Bi64 = 1 +} + +#[repr(u64)] +enum Eu64 { + Au64 = 0, + Bu64 = 1 +} + +#[repr(isize)] +enum Eint { + Aint = 0, + Bint = 1 +} + +#[repr(usize)] +enum Euint { + Auint = 0, + Buint = 1 +} + +#[repr(u8)] +enum Eu8NonCLike<T> { + _None, + _Some(T), +} + +#[repr(i64)] +enum Ei64NonCLike<T> { + _None, + _Some(T), +} + +#[repr(u64)] +enum Eu64NonCLike<T> { + _None, + _Some(T), +} + +pub fn main() { + assert_eq!(size_of::<Ei8>(), 1); + assert_eq!(size_of::<Eu8>(), 1); + assert_eq!(size_of::<Ei16>(), 2); + assert_eq!(size_of::<Eu16>(), 2); + assert_eq!(size_of::<Ei32>(), 4); + assert_eq!(size_of::<Eu32>(), 4); + assert_eq!(size_of::<Ei64>(), 8); + assert_eq!(size_of::<Eu64>(), 8); + assert_eq!(size_of::<Eint>(), size_of::<isize>()); + assert_eq!(size_of::<Euint>(), size_of::<usize>()); + assert_eq!(size_of::<Eu8NonCLike<()>>(), 1); + assert_eq!(size_of::<Ei64NonCLike<()>>(), 8); + assert_eq!(size_of::<Eu64NonCLike<()>>(), 8); + let u8_expected_size = round_up(9, align_of::<Eu64NonCLike<u8>>()); + assert_eq!(size_of::<Eu64NonCLike<u8>>(), u8_expected_size); + let array_expected_size = round_up(28, align_of::<Eu64NonCLike<[u32; 5]>>()); + assert_eq!(size_of::<Eu64NonCLike<[u32; 5]>>(), array_expected_size); + assert_eq!(size_of::<Eu64NonCLike<[u32; 6]>>(), 32); + + assert_eq!(align_of::<Eu32>(), align_of::<u32>()); + assert_eq!(align_of::<Eu64NonCLike<u8>>(), align_of::<u64>()); +} + +// Rounds x up to the next multiple of a +fn round_up(x: usize, a: usize) -> usize { + ((x + (a - 1)) / a) * a +} diff --git a/tests/ui/structs-enums/enum-discrim-range-overflow.rs b/tests/ui/structs-enums/enum-discrim-range-overflow.rs new file mode 100644 index 000000000..9c4c61e68 --- /dev/null +++ b/tests/ui/structs-enums/enum-discrim-range-overflow.rs @@ -0,0 +1,26 @@ +// run-pass +#![allow(overflowing_literals)] + +// pretty-expanded FIXME #23616 + +pub enum E64 { + H64 = 0x7FFF_FFFF_FFFF_FFFF, + L64 = 0x8000_0000_0000_0000 +} +pub enum E32 { + H32 = 0x7FFF_FFFF, + L32 = 0x8000_0000 +} + +pub fn f(e64: E64, e32: E32) -> (bool,bool) { + (match e64 { + E64::H64 => true, + E64::L64 => false + }, + match e32 { + E32::H32 => true, + E32::L32 => false + }) +} + +pub fn main() { } diff --git a/tests/ui/structs-enums/enum-discrim-width-stuff.rs b/tests/ui/structs-enums/enum-discrim-width-stuff.rs new file mode 100644 index 000000000..f278ae2d0 --- /dev/null +++ b/tests/ui/structs-enums/enum-discrim-width-stuff.rs @@ -0,0 +1,44 @@ +// run-pass +#![allow(overflowing_literals)] +#![allow(dead_code)] + +macro_rules! check { + ($m:ident, $t:ty, $v:expr) => {{ + mod $m { + use std::mem::size_of; + #[derive(Copy, Clone, Debug)] + enum E { + V = $v, + A = 0 + } + static C: E = E::V; + pub fn check() { + assert_eq!(size_of::<E>(), size_of::<$t>()); + assert_eq!(E::V as $t, $v as $t); + assert_eq!(C as $t, $v as $t); + assert_eq!(format!("{:?}", E::V), "V".to_string()); + assert_eq!(format!("{:?}", C), "V".to_string()); + } + } + $m::check(); + }} +} + +pub fn main() { + check!(a, u8, 0x17); + check!(b, u8, 0xe8); + check!(c, u16, 0x1727); + check!(d, u16, 0xe8d8); + check!(e, u32, 0x17273747); + check!(f, u32, 0xe8d8c8b8); + + check!(z, i8, 0x17); + check!(y, i8, -0x17); + check!(x, i16, 0x1727); + check!(w, i16, -0x1727); + check!(v, i32, 0x17273747); + check!(u, i32, -0x17273747); + + enum Simple { A, B } + assert_eq!(::std::mem::size_of::<Simple>(), 1); +} diff --git a/tests/ui/structs-enums/enum-disr-val-pretty.rs b/tests/ui/structs-enums/enum-disr-val-pretty.rs new file mode 100644 index 000000000..ef1333e0e --- /dev/null +++ b/tests/ui/structs-enums/enum-disr-val-pretty.rs @@ -0,0 +1,17 @@ +// run-pass +#![allow(non_camel_case_types)] +// pp-exact + + +enum color { red = 1, green, blue, imaginary = -1, } + +pub fn main() { + test_color(color::red, 1, "red".to_string()); + test_color(color::green, 2, "green".to_string()); + test_color(color::blue, 3, "blue".to_string()); + test_color(color::imaginary, -1, "imaginary".to_string()); +} + +fn test_color(color: color, val: isize, _name: String) { + assert_eq!(color as isize , val); +} diff --git a/tests/ui/structs-enums/enum-export-inheritance.rs b/tests/ui/structs-enums/enum-export-inheritance.rs new file mode 100644 index 000000000..6a36a004a --- /dev/null +++ b/tests/ui/structs-enums/enum-export-inheritance.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +mod a { + pub enum Foo { + Bar, + Baz, + Boo + } +} + +pub fn main() { + let _x = a::Foo::Bar; +} diff --git a/tests/ui/structs-enums/enum-layout-optimization.rs b/tests/ui/structs-enums/enum-layout-optimization.rs new file mode 100644 index 000000000..05d297906 --- /dev/null +++ b/tests/ui/structs-enums/enum-layout-optimization.rs @@ -0,0 +1,50 @@ +// run-pass +// Test that we will do various size optimizations to enum layout, but +// *not* if `#[repr(u8)]` or `#[repr(C)]` is passed. See also #40029. + +#![allow(dead_code)] + +use std::mem; + +enum Nullable<T> { + Alive(T), + Dropped, +} + +#[repr(u8)] +enum NullableU8<T> { + Alive(T), + Dropped, +} + +#[repr(C)] +enum NullableC<T> { + Alive(T), + Dropped, +} + +struct StructNewtype<T>(T); + +#[repr(C)] +struct StructNewtypeC<T>(T); + +enum EnumNewtype<T> { Variant(T) } + +#[repr(u8)] +enum EnumNewtypeU8<T> { Variant(T) } + +#[repr(C)] +enum EnumNewtypeC<T> { Variant(T) } + +fn main() { + assert!(mem::size_of::<Box<i32>>() == mem::size_of::<Nullable<Box<i32>>>()); + assert!(mem::size_of::<Box<i32>>() < mem::size_of::<NullableU8<Box<i32>>>()); + assert!(mem::size_of::<Box<i32>>() < mem::size_of::<NullableC<Box<i32>>>()); + + assert!(mem::size_of::<i32>() == mem::size_of::<StructNewtype<i32>>()); + assert!(mem::size_of::<i32>() == mem::size_of::<StructNewtypeC<i32>>()); + + assert!(mem::size_of::<i32>() == mem::size_of::<EnumNewtype<i32>>()); + assert!(mem::size_of::<i32>() < mem::size_of::<EnumNewtypeU8<i32>>()); + assert!(mem::size_of::<i32>() < mem::size_of::<EnumNewtypeC<i32>>()); +} diff --git a/tests/ui/structs-enums/enum-non-c-like-repr-c-and-int.rs b/tests/ui/structs-enums/enum-non-c-like-repr-c-and-int.rs new file mode 100644 index 000000000..7d15d607d --- /dev/null +++ b/tests/ui/structs-enums/enum-non-c-like-repr-c-and-int.rs @@ -0,0 +1,173 @@ +// run-pass +// This test deserializes an enum in-place by transmuting to a union that +// should have the same layout, and manipulating the tag and payloads +// independently. This verifies that `repr(some_int)` has a stable representation, +// and that we don't miscompile these kinds of manipulations. + +use std::time::Duration; +use std::mem; + +#[repr(C, u8)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +enum MyEnum { + A(u32), // Single primitive value + B { x: u8, y: i16, z: u8 }, // Composite, and the offsets of `y` and `z` + // depend on tag being internal + C, // Empty + D(Option<u32>), // Contains an enum + E(Duration), // Contains a struct +} + +#[repr(C)] +struct MyEnumRepr { + tag: MyEnumTag, + payload: MyEnumPayload, +} + +#[repr(C)] +#[allow(non_snake_case)] +union MyEnumPayload { + A: MyEnumVariantA, + B: MyEnumVariantB, + D: MyEnumVariantD, + E: MyEnumVariantE, +} + +#[repr(u8)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E } +#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(u32); +#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB {x: u8, y: i16, z: u8 } +#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(Option<u32>); +#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(Duration); + +fn main() { + let result: Vec<Result<MyEnum, ()>> = vec![ + Ok(MyEnum::A(17)), + Ok(MyEnum::B { x: 206, y: 1145, z: 78 }), + Ok(MyEnum::C), + Err(()), + Ok(MyEnum::D(Some(407))), + Ok(MyEnum::D(None)), + Ok(MyEnum::E(Duration::from_secs(100))), + Err(()), + ]; + + // Binary serialized version of the above (little-endian) + let input: Vec<u8> = vec![ + 0, 17, 0, 0, 0, + 1, 206, 121, 4, 78, + 2, + 8, /* invalid tag value */ + 3, 0, 151, 1, 0, 0, + 3, 1, + 4, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* incomplete value */ + ]; + + let mut output = vec![]; + let mut buf = &input[..]; + + unsafe { + // This should be safe, because we don't match on it unless it's fully formed, + // and it doesn't have a destructor. + // + // MyEnum is repr(C, u8) so it is guaranteed to have a separate discriminant and each + // variant can be zero initialized. + let mut dest: MyEnum = mem::zeroed(); + while buf.len() > 0 { + match parse_my_enum(&mut dest, &mut buf) { + Ok(()) => output.push(Ok(dest)), + Err(()) => output.push(Err(())), + } + } + } + + assert_eq!(output, result); +} + +fn parse_my_enum<'a>(dest: &'a mut MyEnum, buf: &mut &[u8]) -> Result<(), ()> { + unsafe { + // Should be correct to do this transmute. + let dest: &'a mut MyEnumRepr = mem::transmute(dest); + let tag = read_u8(buf)?; + + dest.tag = match tag { + 0 => MyEnumTag::A, + 1 => MyEnumTag::B, + 2 => MyEnumTag::C, + 3 => MyEnumTag::D, + 4 => MyEnumTag::E, + _ => return Err(()), + }; + + match dest.tag { + MyEnumTag::A => { + dest.payload.A.0 = read_u32_le(buf)?; + } + MyEnumTag::B => { + dest.payload.B.x = read_u8(buf)?; + dest.payload.B.y = read_u16_le(buf)? as i16; + dest.payload.B.z = read_u8(buf)?; + } + MyEnumTag::C => { + /* do nothing */ + } + MyEnumTag::D => { + let is_some = read_u8(buf)? == 0; + if is_some { + dest.payload.D.0 = Some(read_u32_le(buf)?); + } else { + dest.payload.D.0 = None; + } + } + MyEnumTag::E => { + let secs = read_u64_le(buf)?; + let nanos = read_u32_le(buf)?; + dest.payload.E.0 = Duration::new(secs, nanos); + } + } + Ok(()) + } +} + + + +// reader helpers + +fn read_u64_le(buf: &mut &[u8]) -> Result<u64, ()> { + if buf.len() < 8 { return Err(()) } + let val = (buf[0] as u64) << 0 + | (buf[1] as u64) << 8 + | (buf[2] as u64) << 16 + | (buf[3] as u64) << 24 + | (buf[4] as u64) << 32 + | (buf[5] as u64) << 40 + | (buf[6] as u64) << 48 + | (buf[7] as u64) << 56; + *buf = &buf[8..]; + Ok(val) +} + +fn read_u32_le(buf: &mut &[u8]) -> Result<u32, ()> { + if buf.len() < 4 { return Err(()) } + let val = (buf[0] as u32) << 0 + | (buf[1] as u32) << 8 + | (buf[2] as u32) << 16 + | (buf[3] as u32) << 24; + *buf = &buf[4..]; + Ok(val) +} + +fn read_u16_le(buf: &mut &[u8]) -> Result<u16, ()> { + if buf.len() < 2 { return Err(()) } + let val = (buf[0] as u16) << 0 + | (buf[1] as u16) << 8; + *buf = &buf[2..]; + Ok(val) +} + +fn read_u8(buf: &mut &[u8]) -> Result<u8, ()> { + if buf.len() < 1 { return Err(()) } + let val = buf[0]; + *buf = &buf[1..]; + Ok(val) +} diff --git a/tests/ui/structs-enums/enum-non-c-like-repr-c.rs b/tests/ui/structs-enums/enum-non-c-like-repr-c.rs new file mode 100644 index 000000000..fc9efdeca --- /dev/null +++ b/tests/ui/structs-enums/enum-non-c-like-repr-c.rs @@ -0,0 +1,174 @@ +// run-pass +// This test deserializes an enum in-place by transmuting to a union that +// should have the same layout, and manipulating the tag and payloads +// independently. This verifies that `repr(some_int)` has a stable representation, +// and that we don't miscompile these kinds of manipulations. + +use std::time::Duration; +use std::mem; + +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +enum MyEnum { + A(u32), // Single primitive value + B { x: u8, y: i16, z: u8 }, // Composite, and the offset of `y` and `z` + // depend on tag being internal + C, // Empty + D(Option<u32>), // Contains an enum + E(Duration), // Contains a struct +} + +#[repr(C)] +struct MyEnumRepr { + tag: MyEnumTag, + payload: MyEnumPayload, +} + +#[repr(C)] +#[allow(non_snake_case)] +union MyEnumPayload { + A: MyEnumVariantA, + B: MyEnumVariantB, + D: MyEnumVariantD, + E: MyEnumVariantE, +} + +#[repr(C)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E } +#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(u32); +#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB {x: u8, y: i16, z: u8 } +#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(Option<u32>); +#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(Duration); + +fn main() { + let result: Vec<Result<MyEnum, ()>> = vec![ + Ok(MyEnum::A(17)), + Ok(MyEnum::B { x: 206, y: 1145, z: 78 }), + Ok(MyEnum::C), + Err(()), + Ok(MyEnum::D(Some(407))), + Ok(MyEnum::D(None)), + Ok(MyEnum::E(Duration::from_secs(100))), + Err(()), + ]; + + // Binary serialized version of the above (little-endian) + let input: Vec<u8> = vec![ + 0, 17, 0, 0, 0, + 1, 206, 121, 4, 78, + 2, + 8, /* invalid tag value */ + 3, 0, 151, 1, 0, 0, + 3, 1, + 4, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* incomplete value */ + ]; + + let mut output = vec![]; + let mut buf = &input[..]; + + unsafe { + // This should be safe, because we don't match on it unless it's fully formed, + // and it doesn't have a destructor. + // + // Furthermore, there are no types within MyEnum which cannot be initialized with zero, + // specifically, though padding and such are present, there are no references or similar + // types. + let mut dest: MyEnum = mem::zeroed(); + while buf.len() > 0 { + match parse_my_enum(&mut dest, &mut buf) { + Ok(()) => output.push(Ok(dest)), + Err(()) => output.push(Err(())), + } + } + } + + assert_eq!(output, result); +} + +fn parse_my_enum<'a>(dest: &'a mut MyEnum, buf: &mut &[u8]) -> Result<(), ()> { + unsafe { + // Should be correct to do this transmute. + let dest: &'a mut MyEnumRepr = mem::transmute(dest); + let tag = read_u8(buf)?; + + dest.tag = match tag { + 0 => MyEnumTag::A, + 1 => MyEnumTag::B, + 2 => MyEnumTag::C, + 3 => MyEnumTag::D, + 4 => MyEnumTag::E, + _ => return Err(()), + }; + + match dest.tag { + MyEnumTag::A => { + dest.payload.A.0 = read_u32_le(buf)?; + } + MyEnumTag::B => { + dest.payload.B.x = read_u8(buf)?; + dest.payload.B.y = read_u16_le(buf)? as i16; + dest.payload.B.z = read_u8(buf)?; + } + MyEnumTag::C => { + /* do nothing */ + } + MyEnumTag::D => { + let is_some = read_u8(buf)? == 0; + if is_some { + dest.payload.D.0 = Some(read_u32_le(buf)?); + } else { + dest.payload.D.0 = None; + } + } + MyEnumTag::E => { + let secs = read_u64_le(buf)?; + let nanos = read_u32_le(buf)?; + dest.payload.E.0 = Duration::new(secs, nanos); + } + } + Ok(()) + } +} + + + +// reader helpers + +fn read_u64_le(buf: &mut &[u8]) -> Result<u64, ()> { + if buf.len() < 8 { return Err(()) } + let val = (buf[0] as u64) << 0 + | (buf[1] as u64) << 8 + | (buf[2] as u64) << 16 + | (buf[3] as u64) << 24 + | (buf[4] as u64) << 32 + | (buf[5] as u64) << 40 + | (buf[6] as u64) << 48 + | (buf[7] as u64) << 56; + *buf = &buf[8..]; + Ok(val) +} + +fn read_u32_le(buf: &mut &[u8]) -> Result<u32, ()> { + if buf.len() < 4 { return Err(()) } + let val = (buf[0] as u32) << 0 + | (buf[1] as u32) << 8 + | (buf[2] as u32) << 16 + | (buf[3] as u32) << 24; + *buf = &buf[4..]; + Ok(val) +} + +fn read_u16_le(buf: &mut &[u8]) -> Result<u16, ()> { + if buf.len() < 2 { return Err(()) } + let val = (buf[0] as u16) << 0 + | (buf[1] as u16) << 8; + *buf = &buf[2..]; + Ok(val) +} + +fn read_u8(buf: &mut &[u8]) -> Result<u8, ()> { + if buf.len() < 1 { return Err(()) } + let val = buf[0]; + *buf = &buf[1..]; + Ok(val) +} diff --git a/tests/ui/structs-enums/enum-non-c-like-repr-int.rs b/tests/ui/structs-enums/enum-non-c-like-repr-int.rs new file mode 100644 index 000000000..f9e96c1a0 --- /dev/null +++ b/tests/ui/structs-enums/enum-non-c-like-repr-int.rs @@ -0,0 +1,169 @@ +// run-pass +// This test deserializes an enum in-place by transmuting to a union that +// should have the same layout, and manipulating the tag and payloads +// independently. This verifies that `repr(some_int)` has a stable representation, +// and that we don't miscompile these kinds of manipulations. + +use std::time::Duration; +use std::mem; + +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +enum MyEnum { + A(u32), // Single primitive value + B { x: u8, y: i16, z: u8 }, // Composite, and the offset of `y` and `z` + // depend on tag being internal + C, // Empty + D(Option<u32>), // Contains an enum + E(Duration), // Contains a struct +} + +#[allow(non_snake_case)] +#[repr(C)] +union MyEnumRepr { + A: MyEnumVariantA, + B: MyEnumVariantB, + C: MyEnumVariantC, + D: MyEnumVariantD, + E: MyEnumVariantE, +} + +#[repr(u8)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E } +#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(MyEnumTag, u32); +#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB { tag: MyEnumTag, x: u8, y: i16, z: u8 } +#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantC(MyEnumTag); +#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(MyEnumTag, Option<u32>); +#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(MyEnumTag, Duration); + +fn main() { + let result: Vec<Result<MyEnum, ()>> = vec![ + Ok(MyEnum::A(17)), + Ok(MyEnum::B { x: 206, y: 1145, z: 78 }), + Ok(MyEnum::C), + Err(()), + Ok(MyEnum::D(Some(407))), + Ok(MyEnum::D(None)), + Ok(MyEnum::E(Duration::from_secs(100))), + Err(()), + ]; + + // Binary serialized version of the above (little-endian) + let input: Vec<u8> = vec![ + 0, 17, 0, 0, 0, + 1, 206, 121, 4, 78, + 2, + 8, /* invalid tag value */ + 3, 0, 151, 1, 0, 0, + 3, 1, + 4, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* incomplete value */ + ]; + + let mut output = vec![]; + let mut buf = &input[..]; + + unsafe { + // This should be safe, because we don't match on it unless it's fully formed, + // and it doesn't have a destructor. + // + // MyEnum is repr(u8) so it is guaranteed to have a separate discriminant and each variant + // can be zero initialized. + let mut dest: MyEnum = mem::zeroed(); + while buf.len() > 0 { + match parse_my_enum(&mut dest, &mut buf) { + Ok(()) => output.push(Ok(dest)), + Err(()) => output.push(Err(())), + } + } + } + + assert_eq!(output, result); +} + +fn parse_my_enum<'a>(dest: &'a mut MyEnum, buf: &mut &[u8]) -> Result<(), ()> { + unsafe { + // Should be correct to do this transmute. + let dest: &'a mut MyEnumRepr = mem::transmute(dest); + let tag = read_u8(buf)?; + + dest.A.0 = match tag { + 0 => MyEnumTag::A, + 1 => MyEnumTag::B, + 2 => MyEnumTag::C, + 3 => MyEnumTag::D, + 4 => MyEnumTag::E, + _ => return Err(()), + }; + + match dest.B.tag { + MyEnumTag::A => { + dest.A.1 = read_u32_le(buf)?; + } + MyEnumTag::B => { + dest.B.x = read_u8(buf)?; + dest.B.y = read_u16_le(buf)? as i16; + dest.B.z = read_u8(buf)?; + } + MyEnumTag::C => { + /* do nothing */ + } + MyEnumTag::D => { + let is_some = read_u8(buf)? == 0; + if is_some { + dest.D.1 = Some(read_u32_le(buf)?); + } else { + dest.D.1 = None; + } + } + MyEnumTag::E => { + let secs = read_u64_le(buf)?; + let nanos = read_u32_le(buf)?; + dest.E.1 = Duration::new(secs, nanos); + } + } + Ok(()) + } +} + + + +// reader helpers + +fn read_u64_le(buf: &mut &[u8]) -> Result<u64, ()> { + if buf.len() < 8 { return Err(()) } + let val = (buf[0] as u64) << 0 + | (buf[1] as u64) << 8 + | (buf[2] as u64) << 16 + | (buf[3] as u64) << 24 + | (buf[4] as u64) << 32 + | (buf[5] as u64) << 40 + | (buf[6] as u64) << 48 + | (buf[7] as u64) << 56; + *buf = &buf[8..]; + Ok(val) +} + +fn read_u32_le(buf: &mut &[u8]) -> Result<u32, ()> { + if buf.len() < 4 { return Err(()) } + let val = (buf[0] as u32) << 0 + | (buf[1] as u32) << 8 + | (buf[2] as u32) << 16 + | (buf[3] as u32) << 24; + *buf = &buf[4..]; + Ok(val) +} + +fn read_u16_le(buf: &mut &[u8]) -> Result<u16, ()> { + if buf.len() < 2 { return Err(()) } + let val = (buf[0] as u16) << 0 + | (buf[1] as u16) << 8; + *buf = &buf[2..]; + Ok(val) +} + +fn read_u8(buf: &mut &[u8]) -> Result<u8, ()> { + if buf.len() < 1 { return Err(()) } + let val = buf[0]; + *buf = &buf[1..]; + Ok(val) +} diff --git a/tests/ui/structs-enums/enum-null-pointer-opt.rs b/tests/ui/structs-enums/enum-null-pointer-opt.rs new file mode 100644 index 000000000..85fa1eac2 --- /dev/null +++ b/tests/ui/structs-enums/enum-null-pointer-opt.rs @@ -0,0 +1,74 @@ +// run-pass +#![feature(transparent_unions)] + +use std::mem::size_of; +use std::num::NonZeroUsize; +use std::ptr::NonNull; +use std::rc::Rc; +use std::sync::Arc; + +trait Trait { fn dummy(&self) { } } +trait Mirror { type Image; } +impl<T> Mirror for T { type Image = T; } +struct ParamTypeStruct<T>(#[allow(unused_tuple_struct_fields)] T); +struct AssocTypeStruct<T>(#[allow(unused_tuple_struct_fields)] <T as Mirror>::Image); +#[repr(transparent)] +union MaybeUninitUnion<T: Copy> { + _value: T, + _uninit: (), +} + +fn main() { + // Functions + assert_eq!(size_of::<fn(isize)>(), size_of::<Option<fn(isize)>>()); + assert_eq!(size_of::<extern "C" fn(isize)>(), size_of::<Option<extern "C" fn(isize)>>()); + + // Slices - &str / &[T] / &mut [T] + assert_eq!(size_of::<&str>(), size_of::<Option<&str>>()); + assert_eq!(size_of::<&[isize]>(), size_of::<Option<&[isize]>>()); + assert_eq!(size_of::<&mut [isize]>(), size_of::<Option<&mut [isize]>>()); + + // Traits - Box<Trait> / &Trait / &mut Trait + assert_eq!(size_of::<Box<dyn Trait>>(), size_of::<Option<Box<dyn Trait>>>()); + assert_eq!(size_of::<&dyn Trait>(), size_of::<Option<&dyn Trait>>()); + assert_eq!(size_of::<&mut dyn Trait>(), size_of::<Option<&mut dyn Trait>>()); + + // Pointers - Box<T> + assert_eq!(size_of::<Box<isize>>(), size_of::<Option<Box<isize>>>()); + + // The optimization can't apply to raw pointers or unions with a ZST field. + assert!(size_of::<Option<*const isize>>() != size_of::<*const isize>()); + assert!(Some(std::ptr::null::<isize>()).is_some()); // Can't collapse None to null + assert_ne!(size_of::<fn(isize)>(), size_of::<Option<MaybeUninitUnion<fn(isize)>>>()); + assert_ne!(size_of::<&str>(), size_of::<Option<MaybeUninitUnion<&str>>>()); + assert_ne!(size_of::<NonNull<isize>>(), size_of::<Option<MaybeUninitUnion<NonNull<isize>>>>()); + + struct Foo { + _a: Box<isize> + } + struct Bar(#[allow(unused_tuple_struct_fields)] Box<isize>); + + // Should apply through structs + assert_eq!(size_of::<Foo>(), size_of::<Option<Foo>>()); + assert_eq!(size_of::<Bar>(), size_of::<Option<Bar>>()); + // and tuples + assert_eq!(size_of::<(u8, Box<isize>)>(), size_of::<Option<(u8, Box<isize>)>>()); + // and fixed-size arrays + assert_eq!(size_of::<[Box<isize>; 1]>(), size_of::<Option<[Box<isize>; 1]>>()); + + // Should apply to NonZero + assert_eq!(size_of::<NonZeroUsize>(), size_of::<Option<NonZeroUsize>>()); + assert_eq!(size_of::<NonNull<i8>>(), size_of::<Option<NonNull<i8>>>()); + + // Should apply to types that use NonZero internally + assert_eq!(size_of::<Vec<isize>>(), size_of::<Option<Vec<isize>>>()); + assert_eq!(size_of::<Arc<isize>>(), size_of::<Option<Arc<isize>>>()); + assert_eq!(size_of::<Rc<isize>>(), size_of::<Option<Rc<isize>>>()); + + // Should apply to types that have NonZero transitively + assert_eq!(size_of::<String>(), size_of::<Option<String>>()); + + // Should apply to types where the pointer is substituted + assert_eq!(size_of::<&u8>(), size_of::<Option<ParamTypeStruct<&u8>>>()); + assert_eq!(size_of::<&u8>(), size_of::<Option<AssocTypeStruct<&u8>>>()); +} diff --git a/tests/ui/structs-enums/enum-nullable-const-null-with-fields.rs b/tests/ui/structs-enums/enum-nullable-const-null-with-fields.rs new file mode 100644 index 000000000..ae267e798 --- /dev/null +++ b/tests/ui/structs-enums/enum-nullable-const-null-with-fields.rs @@ -0,0 +1,13 @@ +// run-pass + +use std::result::Result; +use std::result::Result::Ok; + +static C: Result<(), Box<isize>> = Ok(()); + +// This is because of yet another bad assertion (ICE) about the null side of a nullable enum. +// So we won't actually compile if the bug is present, but we check the value in main anyway. + +pub fn main() { + assert!(C.is_ok()); +} diff --git a/tests/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs b/tests/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs new file mode 100644 index 000000000..a05cf8b93 --- /dev/null +++ b/tests/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs @@ -0,0 +1,16 @@ +// run-pass + +/*! + * This is a regression test for a bug in LLVM, fixed in upstream r179587, + * where the switch instructions generated for destructuring enums + * represented with nullable pointers could be misoptimized in some cases. + */ + +enum List<X> { Nil, Cons(X, #[allow(unused_tuple_struct_fields)] Box<List<X>>) } +pub fn main() { + match List::Cons(10, Box::new(List::Nil)) { + List::Cons(10, _) => {} + List::Nil => {} + _ => panic!() + } +} diff --git a/tests/ui/structs-enums/enum-univariant-repr.rs b/tests/ui/structs-enums/enum-univariant-repr.rs new file mode 100644 index 000000000..1e0f67887 --- /dev/null +++ b/tests/ui/structs-enums/enum-univariant-repr.rs @@ -0,0 +1,51 @@ +// run-pass + +use std::mem; + +// Univariant C-like enum +#[repr(i32)] +enum Univariant { + X = 17 +} + +#[repr(u16)] +enum UnivariantWithoutDescr { + Y +} + +#[repr(u8)] +enum UnivariantWithData { + Z(u8), +} + +pub fn main() { + { + assert_eq!(4, mem::size_of::<Univariant>()); + assert_eq!(17, Univariant::X as i32); + + let enums: &[Univariant] = + &[Univariant::X, Univariant::X, Univariant::X]; + let ints: &[i32] = unsafe { mem::transmute(enums) }; + // check it has the same memory layout as i32 + assert_eq!(&[17, 17, 17], ints); + } + + { + assert_eq!(2, mem::size_of::<UnivariantWithoutDescr>()); + let descr = UnivariantWithoutDescr::Y as u16; + + let enums: &[UnivariantWithoutDescr] = + &[UnivariantWithoutDescr::Y, UnivariantWithoutDescr::Y, UnivariantWithoutDescr::Y]; + let ints: &[u16] = unsafe { mem::transmute(enums) }; + // check it has the same memory layout as u16 + assert_eq!(&[descr, descr, descr], ints); + } + + { + assert_eq!(2, mem::size_of::<UnivariantWithData>()); + + match UnivariantWithData::Z(4) { + UnivariantWithData::Z(x) => assert_eq!(x, 4), + } + } +} diff --git a/tests/ui/structs-enums/enum-variants.rs b/tests/ui/structs-enums/enum-variants.rs new file mode 100644 index 000000000..9ac5aae72 --- /dev/null +++ b/tests/ui/structs-enums/enum-variants.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_assignments)] +// pretty-expanded FIXME #23616 + +#![allow(unused_variables)] + +enum Animal { + Dog (String, f64), + Cat { name: String, weight: f64 } +} + +pub fn main() { + let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2); + a = Animal::Cat{ name: "Spotty".to_string(), weight: 2.7 }; + // permuting the fields should work too + let _c = Animal::Cat { weight: 3.1, name: "Spreckles".to_string() }; +} diff --git a/tests/ui/structs-enums/enum-vec-initializer.rs b/tests/ui/structs-enums/enum-vec-initializer.rs new file mode 100644 index 000000000..42ee8ba97 --- /dev/null +++ b/tests/ui/structs-enums/enum-vec-initializer.rs @@ -0,0 +1,17 @@ +// run-pass +// pretty-expanded FIXME #23616 + +enum Flopsy { + Bunny = 2 +} + +const BAR:usize = Flopsy::Bunny as usize; +const BAR2:usize = BAR; + +pub fn main() { + let _v = [0; Flopsy::Bunny as usize]; + let _v = [0; BAR]; + let _v = [0; BAR2]; + const BAR3:usize = BAR2; + let _v = [0; BAR3]; +} diff --git a/tests/ui/structs-enums/export-abstract-tag.rs b/tests/ui/structs-enums/export-abstract-tag.rs new file mode 100644 index 000000000..76ac73321 --- /dev/null +++ b/tests/ui/structs-enums/export-abstract-tag.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(non_camel_case_types)] + +// We can export tags without exporting the variants to create a simple +// sort of ADT. + +// pretty-expanded FIXME #23616 + +mod foo { + pub enum t { t1, } + + pub fn f() -> t { return t::t1; } +} + +pub fn main() { let _v: foo::t = foo::f(); } diff --git a/tests/ui/structs-enums/export-tag-variant.rs b/tests/ui/structs-enums/export-tag-variant.rs new file mode 100644 index 000000000..52e0aba09 --- /dev/null +++ b/tests/ui/structs-enums/export-tag-variant.rs @@ -0,0 +1,9 @@ +// run-pass +#![allow(non_camel_case_types)] +// pretty-expanded FIXME #23616 + +mod foo { + pub enum t { t1, } +} + +pub fn main() { let _v = foo::t::t1; } diff --git a/tests/ui/structs-enums/expr-if-struct.rs b/tests/ui/structs-enums/expr-if-struct.rs new file mode 100644 index 000000000..e62d47c6f --- /dev/null +++ b/tests/ui/structs-enums/expr-if-struct.rs @@ -0,0 +1,32 @@ +// run-pass +#![allow(non_camel_case_types)] + + + + +// Tests for if as expressions returning nominal types + +#[derive(Copy, Clone)] +struct I { i: isize } + +fn test_rec() { + let rs = if true { I {i: 100} } else { I {i: 101} }; + assert_eq!(rs.i, 100); +} + +#[derive(Copy, Clone, Debug)] +enum mood { happy, sad, } + +impl PartialEq for mood { + fn eq(&self, other: &mood) -> bool { + ((*self) as usize) == ((*other) as usize) + } + fn ne(&self, other: &mood) -> bool { !(*self).eq(other) } +} + +fn test_tag() { + let rs = if true { mood::happy } else { mood::sad }; + assert_eq!(rs, mood::happy); +} + +pub fn main() { test_rec(); test_tag(); } diff --git a/tests/ui/structs-enums/expr-match-struct.rs b/tests/ui/structs-enums/expr-match-struct.rs new file mode 100644 index 000000000..f0e8d8972 --- /dev/null +++ b/tests/ui/structs-enums/expr-match-struct.rs @@ -0,0 +1,31 @@ +// run-pass +#![allow(non_camel_case_types)] + + + + +// Tests for match as expressions resulting in struct types +#[derive(Copy, Clone)] +struct R { i: isize } + +fn test_rec() { + let rs = match true { true => R {i: 100}, _ => panic!() }; + assert_eq!(rs.i, 100); +} + +#[derive(Copy, Clone, Debug)] +enum mood { happy, sad, } + +impl PartialEq for mood { + fn eq(&self, other: &mood) -> bool { + ((*self) as usize) == ((*other) as usize) + } + fn ne(&self, other: &mood) -> bool { !(*self).eq(other) } +} + +fn test_tag() { + let rs = match true { true => { mood::happy } false => { mood::sad } }; + assert_eq!(rs, mood::happy); +} + +pub fn main() { test_rec(); test_tag(); } diff --git a/tests/ui/structs-enums/field-destruction-order.rs b/tests/ui/structs-enums/field-destruction-order.rs new file mode 100644 index 000000000..a75a742d9 --- /dev/null +++ b/tests/ui/structs-enums/field-destruction-order.rs @@ -0,0 +1,47 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_upper_case_globals)] + +// In theory, it doesn't matter what order destructors are run in for rust +// because we have explicit ownership of values meaning that there's no need to +// run one before another. With unsafe code, however, there may be a safe +// interface which relies on fields having their destructors run in a particular +// order. At the time of this writing, std::rt::sched::Scheduler is an example +// of a structure which contains unsafe handles to FFI-like types, and the +// destruction order of the fields matters in the sense that some handles need +// to get destroyed before others. +// +// In C++, destruction order happens bottom-to-top in order of field +// declarations, but we currently run them top-to-bottom. I don't think the +// order really matters that much as long as we define what it is. + + +struct A; +struct B; +struct C { + a: A, + b: B, +} + +static mut hit: bool = false; + +impl Drop for A { + fn drop(&mut self) { + unsafe { + assert!(!hit); + hit = true; + } + } +} + +impl Drop for B { + fn drop(&mut self) { + unsafe { + assert!(hit); + } + } +} + +pub fn main() { + let _c = C { a: A, b: B }; +} diff --git a/tests/ui/structs-enums/foreign-struct.rs b/tests/ui/structs-enums/foreign-struct.rs new file mode 100644 index 000000000..00a23b354 --- /dev/null +++ b/tests/ui/structs-enums/foreign-struct.rs @@ -0,0 +1,19 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +// Passing enums by value + +// pretty-expanded FIXME #23616 + +pub enum void {} + +mod bindgen { + use super::void; + + extern "C" { + pub fn printf(v: void); + } +} + +pub fn main() {} diff --git a/tests/ui/structs-enums/functional-struct-upd.rs b/tests/ui/structs-enums/functional-struct-upd.rs new file mode 100644 index 000000000..68ff73a08 --- /dev/null +++ b/tests/ui/structs-enums/functional-struct-upd.rs @@ -0,0 +1,15 @@ +// run-pass + +#![allow(dead_code)] + +#[derive(Debug)] +struct Foo { + x: isize, + y: isize +} + +pub fn main() { + let a = Foo { x: 1, y: 2 }; + let c = Foo { x: 4, .. a}; + println!("{:?}", c); +} diff --git a/tests/ui/structs-enums/issue-1701.rs b/tests/ui/structs-enums/issue-1701.rs new file mode 100644 index 000000000..bae32a777 --- /dev/null +++ b/tests/ui/structs-enums/issue-1701.rs @@ -0,0 +1,26 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + + +enum pattern { tabby, tortoiseshell, calico } +enum breed { beagle, rottweiler, pug } +type name = String; +enum ear_kind { lop, upright } +enum animal { cat(pattern), dog(breed), rabbit(name, ear_kind), tiger } + +fn noise(a: animal) -> Option<String> { + match a { + animal::cat(..) => { Some("meow".to_string()) } + animal::dog(..) => { Some("woof".to_string()) } + animal::rabbit(..) => { None } + animal::tiger => { Some("roar".to_string()) } + } +} + +pub fn main() { + assert_eq!(noise(animal::cat(pattern::tabby)), Some("meow".to_string())); + assert_eq!(noise(animal::dog(breed::pug)), Some("woof".to_string())); + assert_eq!(noise(animal::rabbit("Hilbert".to_string(), ear_kind::upright)), None); + assert_eq!(noise(animal::tiger), Some("roar".to_string())); +} diff --git a/tests/ui/structs-enums/issue-2718-a.rs b/tests/ui/structs-enums/issue-2718-a.rs new file mode 100644 index 000000000..6c4915845 --- /dev/null +++ b/tests/ui/structs-enums/issue-2718-a.rs @@ -0,0 +1,12 @@ +pub struct SendPacket<T> { + p: T +} + +mod pingpong { + use SendPacket; + pub type Ping = SendPacket<Pong>; + pub struct Pong(SendPacket<Ping>); + //~^ ERROR recursive type `Pong` has infinite size +} + +fn main() {} diff --git a/tests/ui/structs-enums/issue-2718-a.stderr b/tests/ui/structs-enums/issue-2718-a.stderr new file mode 100644 index 000000000..7ea620f38 --- /dev/null +++ b/tests/ui/structs-enums/issue-2718-a.stderr @@ -0,0 +1,14 @@ +error[E0072]: recursive type `Pong` has infinite size + --> $DIR/issue-2718-a.rs:8:5 + | +LL | pub struct Pong(SendPacket<Ping>); + | ^^^^^^^^^^^^^^^ ---------------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL | pub struct Pong(Box<SendPacket<Ping>>); + | ++++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/structs-enums/issue-38002.rs b/tests/ui/structs-enums/issue-38002.rs new file mode 100644 index 000000000..fdb31fc44 --- /dev/null +++ b/tests/ui/structs-enums/issue-38002.rs @@ -0,0 +1,35 @@ +// run-pass +#![allow(dead_code)] +// Check that constant ADTs are codegened OK, part k of N. + +enum Bar { + C +} + +enum Foo { + A {}, + B { + y: usize, + z: Bar + }, +} + +const LIST: [(usize, Foo); 2] = [ + (51, Foo::B { y: 42, z: Bar::C }), + (52, Foo::B { y: 45, z: Bar::C }), +]; + +pub fn main() { + match LIST { + [ + (51, Foo::B { y: 42, z: Bar::C }), + (52, Foo::B { y: 45, z: Bar::C }) + ] => {} + _ => { + // I would want to print the enum here, but if + // the discriminant is garbage this causes an + // `unreachable` and silent process exit. + panic!("trivial match failed") + } + } +} diff --git a/tests/ui/structs-enums/issue-50731.rs b/tests/ui/structs-enums/issue-50731.rs new file mode 100644 index 000000000..209c1e127 --- /dev/null +++ b/tests/ui/structs-enums/issue-50731.rs @@ -0,0 +1,6 @@ +// run-pass +enum Void {} +fn foo(_: Result<(Void, u32), (Void, String)>) {} +fn main() { + let _: fn(_) = foo; +} diff --git a/tests/ui/structs-enums/ivec-tag.rs b/tests/ui/structs-enums/ivec-tag.rs new file mode 100644 index 000000000..c39368a2b --- /dev/null +++ b/tests/ui/structs-enums/ivec-tag.rs @@ -0,0 +1,22 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support + +use std::thread; +use std::sync::mpsc::{channel, Sender}; + +fn producer(tx: &Sender<Vec<u8>>) { + tx.send( + vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13]).unwrap(); +} + +pub fn main() { + let (tx, rx) = channel::<Vec<u8>>(); + let prod = thread::spawn(move|| { + producer(&tx) + }); + + let _data: Vec<u8> = rx.recv().unwrap(); + prod.join(); +} diff --git a/tests/ui/structs-enums/module-qualified-struct-destructure.rs b/tests/ui/structs-enums/module-qualified-struct-destructure.rs new file mode 100644 index 000000000..57be37cdf --- /dev/null +++ b/tests/ui/structs-enums/module-qualified-struct-destructure.rs @@ -0,0 +1,14 @@ +// run-pass +// pretty-expanded FIXME #23616 + +mod m { + pub struct S { + pub x: isize, + pub y: isize + } +} + +pub fn main() { + let x = m::S { x: 1, y: 2 }; + let m::S { x: _a, y: _b } = x; +} diff --git a/tests/ui/structs-enums/multiple-reprs.rs b/tests/ui/structs-enums/multiple-reprs.rs new file mode 100644 index 000000000..4be503a0e --- /dev/null +++ b/tests/ui/structs-enums/multiple-reprs.rs @@ -0,0 +1,82 @@ +// run-pass + +#![allow(dead_code)] + +use std::mem::{size_of, align_of}; +use std::os::raw::c_int; + +// The two enums that follow are designed so that bugs trigger layout optimization. +// Specifically, if either of the following reprs used here is not detected by the compiler, +// then the sizes will be wrong. + +#[repr(C, u8)] +enum E1 { + A(u8, u16, u8), + B(u8, u16, u8) +} + +#[repr(u8, C)] +enum E2 { + A(u8, u16, u8), + B(u8, u16, u8) +} + +// Check that repr(int) and repr(C) are in fact different from the above + +#[repr(u8)] +enum E3 { + A(u8, u16, u8), + B(u8, u16, u8) +} + +#[repr(u16)] +enum E4 { + A(u8, u16, u8), + B(u8, u16, u8) +} + +#[repr(u32)] +enum E5 { + A(u8, u16, u8), + B(u8, u16, u8) +} + +#[repr(u64)] +enum E6 { + A(u8, u16, u8), + B(u8, u16, u8) +} + +#[repr(C)] +enum E7 { + A(u8, u16, u8), + B(u8, u16, u8) +} + +// From pr 37429 + +#[repr(C,packed)] +pub struct p0f_api_query { + pub magic: u32, + pub addr_type: u8, + pub addr: [u8; 16], +} + +pub fn main() { + assert_eq!(size_of::<E1>(), 8); + assert_eq!(size_of::<E2>(), 8); + assert_eq!(size_of::<E3>(), 6); + assert_eq!(size_of::<E4>(), 8); + assert_eq!(size_of::<E5>(), align_size(10, align_of::<u32>())); + assert_eq!(size_of::<E6>(), align_size(14, align_of::<u64>())); + assert_eq!(size_of::<E7>(), align_size(6 + size_of::<c_int>(), align_of::<c_int>())); + assert_eq!(size_of::<p0f_api_query>(), 21); +} + +fn align_size(size: usize, align: usize) -> usize { + if size % align != 0 { + size + (align - (size % align)) + } else { + size + } +} diff --git a/tests/ui/structs-enums/namespaced-enum-emulate-flat-xc.rs b/tests/ui/structs-enums/namespaced-enum-emulate-flat-xc.rs new file mode 100644 index 000000000..30cf64582 --- /dev/null +++ b/tests/ui/structs-enums/namespaced-enum-emulate-flat-xc.rs @@ -0,0 +1,25 @@ +// run-pass +#![allow(non_camel_case_types)] + +// aux-build:namespaced_enum_emulate_flat.rs + +// pretty-expanded FIXME #23616 + +extern crate namespaced_enum_emulate_flat; + +use namespaced_enum_emulate_flat::{Foo, A, B, C}; +use namespaced_enum_emulate_flat::nest::{Bar, D, E, F}; + +fn _f(f: Foo) { + match f { + A | B(_) | C { .. } => {} + } +} + +fn _f2(f: Bar) { + match f { + D | E(_) | F { .. } => {} + } +} + +pub fn main() {} diff --git a/tests/ui/structs-enums/namespaced-enum-emulate-flat.rs b/tests/ui/structs-enums/namespaced-enum-emulate-flat.rs new file mode 100644 index 000000000..f6c395059 --- /dev/null +++ b/tests/ui/structs-enums/namespaced-enum-emulate-flat.rs @@ -0,0 +1,44 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +pub use Foo::*; +use nest::{Bar, D, E, F}; + +pub enum Foo { + A, + B(isize), + C { a: isize }, +} + +impl Foo { + pub fn foo() {} +} + +fn _f(f: Foo) { + match f { + A | B(_) | C { .. } => {} + } +} + +mod nest { + pub use self::Bar::*; + + pub enum Bar { + D, + E(isize), + F { a: isize }, + } + + impl Bar { + pub fn foo() {} + } +} + +fn _f2(f: Bar) { + match f { + D | E(_) | F { .. } => {} + } +} + +fn main() {} diff --git a/tests/ui/structs-enums/namespaced-enum-glob-import-xcrate.rs b/tests/ui/structs-enums/namespaced-enum-glob-import-xcrate.rs new file mode 100644 index 000000000..d2ccadea0 --- /dev/null +++ b/tests/ui/structs-enums/namespaced-enum-glob-import-xcrate.rs @@ -0,0 +1,26 @@ +// run-pass +// aux-build:namespaced_enums.rs + +// pretty-expanded FIXME #23616 + +extern crate namespaced_enums; + +fn _f(f: namespaced_enums::Foo) { + use namespaced_enums::Foo::*; + + match f { + A | B(_) | C { .. } => {} + } +} + +mod m { + pub use namespaced_enums::Foo::*; +} + +fn _f2(f: namespaced_enums::Foo) { + match f { + m::A | m::B(_) | m::C { .. } => {} + } +} + +pub fn main() {} diff --git a/tests/ui/structs-enums/namespaced-enum-glob-import.rs b/tests/ui/structs-enums/namespaced-enum-glob-import.rs new file mode 100644 index 000000000..f36ac69dc --- /dev/null +++ b/tests/ui/structs-enums/namespaced-enum-glob-import.rs @@ -0,0 +1,35 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +mod m2 { + pub enum Foo { + A, + B(isize), + C { a: isize }, + } + + impl Foo { + pub fn foo() {} + } +} + +mod m { + pub use m2::Foo::*; +} + +fn _f(f: m2::Foo) { + use m2::Foo::*; + + match f { + A | B(_) | C { .. } => {} + } +} + +fn _f2(f: m2::Foo) { + match f { + m::A | m::B(_) | m::C { .. } => {} + } +} + +pub fn main() {} diff --git a/tests/ui/structs-enums/namespaced-enums-xcrate.rs b/tests/ui/structs-enums/namespaced-enums-xcrate.rs new file mode 100644 index 000000000..5e10c3ec1 --- /dev/null +++ b/tests/ui/structs-enums/namespaced-enums-xcrate.rs @@ -0,0 +1,16 @@ +// run-pass +// aux-build:namespaced_enums.rs + +// pretty-expanded FIXME #23616 + +extern crate namespaced_enums; + +use namespaced_enums::Foo; + +fn _foo (f: Foo) { + match f { + Foo::A | Foo::B(_) | Foo::C { .. } => {} + } +} + +pub fn main() {} diff --git a/tests/ui/structs-enums/namespaced-enums.rs b/tests/ui/structs-enums/namespaced-enums.rs new file mode 100644 index 000000000..6a2602501 --- /dev/null +++ b/tests/ui/structs-enums/namespaced-enums.rs @@ -0,0 +1,17 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +enum Foo { + A, + B(isize), + C { a: isize }, +} + +fn _foo (f: Foo) { + match f { + Foo::A | Foo::B(_) | Foo::C { .. } => {} + } +} + +pub fn main() {} diff --git a/tests/ui/structs-enums/nested-enum-same-names.rs b/tests/ui/structs-enums/nested-enum-same-names.rs new file mode 100644 index 000000000..111b9ba94 --- /dev/null +++ b/tests/ui/structs-enums/nested-enum-same-names.rs @@ -0,0 +1,27 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +/* + +#7770 ICE with sibling methods containing same-name-enum containing + same-name-member + +If you have two methods in an impl block, each containing an enum +(with the same name), each containing at least one value with the same +name, rustc gives the same LLVM symbol for the two of them and fails, +as it does not include the method name in the symbol name. + +*/ + +pub struct Foo; +impl Foo { + pub fn foo() { + enum Panic { Common } + } + pub fn bar() { + enum Panic { Common } + } +} + +pub fn main() {} diff --git a/tests/ui/structs-enums/newtype-struct-drop-run.rs b/tests/ui/structs-enums/newtype-struct-drop-run.rs new file mode 100644 index 000000000..0754f3187 --- /dev/null +++ b/tests/ui/structs-enums/newtype-struct-drop-run.rs @@ -0,0 +1,21 @@ +// run-pass +// Make sure the destructor is run for newtype structs. + +use std::cell::Cell; + +struct Foo<'a>(&'a Cell<isize>); + +impl<'a> Drop for Foo<'a> { + fn drop(&mut self) { + let Foo(i) = *self; + i.set(23); + } +} + +pub fn main() { + let y = &Cell::new(32); + { + let _x = Foo(y); + } + assert_eq!(y.get(), 23); +} diff --git a/tests/ui/structs-enums/newtype-struct-with-dtor.rs b/tests/ui/structs-enums/newtype-struct-with-dtor.rs new file mode 100644 index 000000000..f73b492df --- /dev/null +++ b/tests/ui/structs-enums/newtype-struct-with-dtor.rs @@ -0,0 +1,20 @@ +// run-pass +#![allow(unused_unsafe)] +#![allow(unused_variables)] +// pretty-expanded FIXME #23616 + +pub struct Fd(u32); + +fn foo(a: u32) {} + +impl Drop for Fd { + fn drop(&mut self) { + unsafe { + let Fd(s) = *self; + foo(s); + } + } +} + +pub fn main() { +} diff --git a/tests/ui/structs-enums/newtype-struct-xc-2.rs b/tests/ui/structs-enums/newtype-struct-xc-2.rs new file mode 100644 index 000000000..40837321b --- /dev/null +++ b/tests/ui/structs-enums/newtype-struct-xc-2.rs @@ -0,0 +1,15 @@ +// run-pass +// aux-build:newtype_struct_xc.rs + +// pretty-expanded FIXME #23616 + +extern crate newtype_struct_xc; +use newtype_struct_xc::Au; + +fn f() -> Au { + Au(2) +} + +pub fn main() { + let _ = f(); +} diff --git a/tests/ui/structs-enums/newtype-struct-xc.rs b/tests/ui/structs-enums/newtype-struct-xc.rs new file mode 100644 index 000000000..0c6466d97 --- /dev/null +++ b/tests/ui/structs-enums/newtype-struct-xc.rs @@ -0,0 +1,10 @@ +// run-pass +// aux-build:newtype_struct_xc.rs + +// pretty-expanded FIXME #23616 + +extern crate newtype_struct_xc; + +pub fn main() { + let _ = newtype_struct_xc::Au(2); +} diff --git a/tests/ui/structs-enums/nonzero-enum.rs b/tests/ui/structs-enums/nonzero-enum.rs new file mode 100644 index 000000000..15b571be5 --- /dev/null +++ b/tests/ui/structs-enums/nonzero-enum.rs @@ -0,0 +1,30 @@ +// run-pass +#![allow(dead_code)] +use std::mem::size_of; + +enum E { + A = 1, + B = 2, + C = 3, +} + +struct S { + a: u16, + b: u8, + e: E, +} + +fn main() { + assert_eq!(size_of::<E>(), 1); + assert_eq!(size_of::<Option<E>>(), 1); + assert_eq!(size_of::<Result<E, ()>>(), 1); + assert_eq!(size_of::<Option<S>>(), size_of::<S>()); + let enone = None::<E>; + let esome = Some(E::A); + if let Some(..) = enone { + panic!(); + } + if let None = esome { + panic!(); + } +} diff --git a/tests/ui/structs-enums/numeric-fields.rs b/tests/ui/structs-enums/numeric-fields.rs new file mode 100644 index 000000000..6ff3afc38 --- /dev/null +++ b/tests/ui/structs-enums/numeric-fields.rs @@ -0,0 +1,12 @@ +// run-pass +struct S(u8, u16); + +fn main() { + let s = S{1: 10, 0: 11}; + match s { + S{0: a, 1: b, ..} => { + assert_eq!(a, 11); + assert_eq!(b, 10); + } + } +} diff --git a/tests/ui/structs-enums/rec-align-u32.rs b/tests/ui/structs-enums/rec-align-u32.rs new file mode 100644 index 000000000..ee704198d --- /dev/null +++ b/tests/ui/structs-enums/rec-align-u32.rs @@ -0,0 +1,57 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_unsafe)] +// Issue #2303 + +#![feature(intrinsics)] + +use std::mem; + +mod rusti { + extern "rust-intrinsic" { + pub fn pref_align_of<T>() -> usize; + #[rustc_safe_intrinsic] + pub fn min_align_of<T>() -> usize; + } +} + +// This is the type with the questionable alignment +#[derive(Debug)] +struct Inner { + c64: u32 +} + +// This is the type that contains the type with the +// questionable alignment, for testing +#[derive(Debug)] +struct Outer { + c8: u8, + t: Inner +} + +mod m { + pub fn align() -> usize { 4 } + pub fn size() -> usize { 8 } +} + +pub fn main() { + unsafe { + let x = Outer {c8: 22, t: Inner {c64: 44}}; + + // Send it through the shape code + let y = format!("{:?}", x); + + println!("align inner = {:?}", rusti::min_align_of::<Inner>()); + println!("size outer = {:?}", mem::size_of::<Outer>()); + println!("y = {:?}", y); + + // per clang/gcc the alignment of `inner` is 4 on x86. + assert_eq!(rusti::min_align_of::<Inner>(), m::align()); + + // per clang/gcc the size of `outer` should be 12 + // because `inner`s alignment was 4. + assert_eq!(mem::size_of::<Outer>(), m::size()); + + assert_eq!(y, "Outer { c8: 22, t: Inner { c64: 44 } }".to_string()); + } +} diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs new file mode 100644 index 000000000..40ede9705 --- /dev/null +++ b/tests/ui/structs-enums/rec-align-u64.rs @@ -0,0 +1,97 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_unsafe)] +// ignore-wasm32-bare seems unimportant to test + +// Issue #2303 + +#![feature(intrinsics)] + +use std::mem; + +mod rusti { + extern "rust-intrinsic" { + pub fn pref_align_of<T>() -> usize; + #[rustc_safe_intrinsic] + pub fn min_align_of<T>() -> usize; + } +} + +// This is the type with the questionable alignment +#[derive(Debug)] +struct Inner { + c64: u64 +} + +// This is the type that contains the type with the +// questionable alignment, for testing +#[derive(Debug)] +struct Outer { + c8: u8, + t: Inner +} + + +#[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "vxworks"))] +mod m { + #[cfg(target_arch = "x86")] + pub mod m { + pub fn align() -> usize { 4 } + pub fn size() -> usize { 12 } + } + + #[cfg(not(target_arch = "x86"))] + pub mod m { + pub fn align() -> usize { 8 } + pub fn size() -> usize { 16 } + } +} + +#[cfg(target_env = "sgx")] +mod m { + #[cfg(target_arch = "x86_64")] + pub mod m { + pub fn align() -> usize { 8 } + pub fn size() -> usize { 16 } + } +} + +#[cfg(target_os = "windows")] +mod m { + pub mod m { + pub fn align() -> usize { 8 } + pub fn size() -> usize { 16 } + } +} + +pub fn main() { + unsafe { + let x = Outer {c8: 22, t: Inner {c64: 44}}; + + let y = format!("{:?}", x); + + println!("align inner = {:?}", rusti::min_align_of::<Inner>()); + println!("size outer = {:?}", mem::size_of::<Outer>()); + println!("y = {:?}", y); + + // per clang/gcc the alignment of `Inner` is 4 on x86. + assert_eq!(rusti::min_align_of::<Inner>(), m::m::align()); + + // per clang/gcc the size of `Outer` should be 12 + // because `Inner`s alignment was 4. + assert_eq!(mem::size_of::<Outer>(), m::m::size()); + + assert_eq!(y, "Outer { c8: 22, t: Inner { c64: 44 } }".to_string()); + } +} diff --git a/tests/ui/structs-enums/rec-auto.rs b/tests/ui/structs-enums/rec-auto.rs new file mode 100644 index 000000000..c2ef13ede --- /dev/null +++ b/tests/ui/structs-enums/rec-auto.rs @@ -0,0 +1,14 @@ +// run-pass + + + + +// Issue #50. + +struct X { foo: String, bar: String } + +pub fn main() { + let x = X {foo: "hello".to_string(), bar: "world".to_string()}; + println!("{}", x.foo.clone()); + println!("{}", x.bar.clone()); +} diff --git a/tests/ui/structs-enums/rec-extend.rs b/tests/ui/structs-enums/rec-extend.rs new file mode 100644 index 000000000..4c91cd185 --- /dev/null +++ b/tests/ui/structs-enums/rec-extend.rs @@ -0,0 +1,18 @@ +// run-pass + + + + +struct Point {x: isize, y: isize} + +pub fn main() { + let origin: Point = Point {x: 0, y: 0}; + let right: Point = Point {x: origin.x + 10,.. origin}; + let up: Point = Point {y: origin.y + 10,.. origin}; + assert_eq!(origin.x, 0); + assert_eq!(origin.y, 0); + assert_eq!(right.x, 10); + assert_eq!(right.y, 0); + assert_eq!(up.x, 0); + assert_eq!(up.y, 10); +} diff --git a/tests/ui/structs-enums/rec-tup.rs b/tests/ui/structs-enums/rec-tup.rs new file mode 100644 index 000000000..b85d28fdf --- /dev/null +++ b/tests/ui/structs-enums/rec-tup.rs @@ -0,0 +1,31 @@ +// run-pass +#![allow(non_camel_case_types)] + + +#[derive(Copy, Clone)] +struct Point {x: isize, y: isize} + +type rect = (Point, Point); + +fn fst(r: rect) -> Point { let (fst, _) = r; return fst; } +fn snd(r: rect) -> Point { let (_, snd) = r; return snd; } + +fn f(r: rect, x1: isize, y1: isize, x2: isize, y2: isize) { + assert_eq!(fst(r).x, x1); + assert_eq!(fst(r).y, y1); + assert_eq!(snd(r).x, x2); + assert_eq!(snd(r).y, y2); +} + +pub fn main() { + let r: rect = (Point {x: 10, y: 20}, Point {x: 11, y: 22}); + assert_eq!(fst(r).x, 10); + assert_eq!(fst(r).y, 20); + assert_eq!(snd(r).x, 11); + assert_eq!(snd(r).y, 22); + let r2 = r; + let x: isize = fst(r2).x; + assert_eq!(x, 10); + f(r, 10, 20, 11, 22); + f(r2, 10, 20, 11, 22); +} diff --git a/tests/ui/structs-enums/rec.rs b/tests/ui/structs-enums/rec.rs new file mode 100644 index 000000000..82c84ebd6 --- /dev/null +++ b/tests/ui/structs-enums/rec.rs @@ -0,0 +1,24 @@ +// run-pass + +#[derive(Copy, Clone)] +struct Rect {x: isize, y: isize, w: isize, h: isize} + +fn f(r: Rect, x: isize, y: isize, w: isize, h: isize) { + assert_eq!(r.x, x); + assert_eq!(r.y, y); + assert_eq!(r.w, w); + assert_eq!(r.h, h); +} + +pub fn main() { + let r: Rect = Rect {x: 10, y: 20, w: 100, h: 200}; + assert_eq!(r.x, 10); + assert_eq!(r.y, 20); + assert_eq!(r.w, 100); + assert_eq!(r.h, 200); + let r2: Rect = r; + let x: isize = r2.x; + assert_eq!(x, 10); + f(r, 10, 20, 100, 200); + f(r2, 10, 20, 100, 200); +} diff --git a/tests/ui/structs-enums/record-pat.rs b/tests/ui/structs-enums/record-pat.rs new file mode 100644 index 000000000..1acaf2a32 --- /dev/null +++ b/tests/ui/structs-enums/record-pat.rs @@ -0,0 +1,19 @@ +// run-pass +#![allow(non_camel_case_types)] +#![allow(non_shorthand_field_patterns)] + +enum t1 { a(isize), b(usize), } +struct T2 {x: t1, y: isize} +enum t3 { c(T2, usize), } + +fn m(input: t3) -> isize { + match input { + t3::c(T2 {x: t1::a(m), ..}, _) => { return m; } + t3::c(T2 {x: t1::b(m), y: y}, z) => { return ((m + z) as isize) + y; } + } +} + +pub fn main() { + assert_eq!(m(t3::c(T2 {x: t1::a(10), y: 5}, 4)), 10); + assert_eq!(m(t3::c(T2 {x: t1::b(10), y: 5}, 4)), 19); +} diff --git a/tests/ui/structs-enums/resource-in-struct.rs b/tests/ui/structs-enums/resource-in-struct.rs new file mode 100644 index 000000000..9613ca62a --- /dev/null +++ b/tests/ui/structs-enums/resource-in-struct.rs @@ -0,0 +1,37 @@ +// run-pass +#![allow(non_camel_case_types)] + +// Ensures that class dtors run if the object is inside an enum +// variant + +use std::cell::Cell; + +type closable<'a> = &'a Cell<bool>; + +struct close_res<'a> { + i: closable<'a>, + +} + +impl<'a> Drop for close_res<'a> { + fn drop(&mut self) { + self.i.set(false); + } +} + +fn close_res(i: closable) -> close_res { + close_res { + i: i + } +} + +enum option<T> { none, some(#[allow(unused_tuple_struct_fields)] T), } + +fn sink(_res: option<close_res>) { } + +pub fn main() { + let c = &Cell::new(true); + sink(option::none); + sink(option::some(close_res(c))); + assert!(!c.get()); +} diff --git a/tests/ui/structs-enums/simple-generic-tag.rs b/tests/ui/structs-enums/simple-generic-tag.rs new file mode 100644 index 000000000..dbd2834d4 --- /dev/null +++ b/tests/ui/structs-enums/simple-generic-tag.rs @@ -0,0 +1,11 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + + + +// pretty-expanded FIXME #23616 + +enum clam<T> { a(T), } + +pub fn main() { } diff --git a/tests/ui/structs-enums/simple-match-generic-tag.rs b/tests/ui/structs-enums/simple-match-generic-tag.rs new file mode 100644 index 000000000..762fd49ad --- /dev/null +++ b/tests/ui/structs-enums/simple-match-generic-tag.rs @@ -0,0 +1,13 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +enum opt<T> { none, some(T) } + +pub fn main() { + let x = opt::none::<isize>; + match x { + opt::none::<isize> => { println!("hello world"); } + opt::some(_) => { } + } +} diff --git a/tests/ui/structs-enums/small-enum-range-edge.rs b/tests/ui/structs-enums/small-enum-range-edge.rs new file mode 100644 index 000000000..306129479 --- /dev/null +++ b/tests/ui/structs-enums/small-enum-range-edge.rs @@ -0,0 +1,27 @@ +// run-pass +#![allow(non_upper_case_globals)] + +// Tests the range assertion wraparound case when reading discriminants. + +#[repr(u8)] +#[derive(Copy, Clone)] +enum Eu { Lu = 0, Hu = 255 } + +static CLu: Eu = Eu::Lu; +static CHu: Eu = Eu::Hu; + +#[repr(i8)] +#[derive(Copy, Clone)] +enum Es { Ls = -128, Hs = 127 } + +static CLs: Es = Es::Ls; +static CHs: Es = Es::Hs; + +pub fn main() { + assert_eq!((Eu::Hu as u8).wrapping_add(1), Eu::Lu as u8); + assert_eq!((Es::Hs as i8).wrapping_add(1), Es::Ls as i8); + assert_eq!(CLu as u8, Eu::Lu as u8); + assert_eq!(CHu as u8, Eu::Hu as u8); + assert_eq!(CLs as i8, Es::Ls as i8); + assert_eq!(CHs as i8, Es::Hs as i8); +} diff --git a/tests/ui/structs-enums/small-enums-with-fields.rs b/tests/ui/structs-enums/small-enums-with-fields.rs new file mode 100644 index 000000000..565ec1bd4 --- /dev/null +++ b/tests/ui/structs-enums/small-enums-with-fields.rs @@ -0,0 +1,33 @@ +// run-pass +use std::mem::size_of; + +#[derive(PartialEq, Debug)] +enum Either<T, U> { Left(T), Right(U) } + +macro_rules! check { + ($t:ty, $sz:expr, $($e:expr, $s:expr),*) => {{ + assert_eq!(size_of::<$t>(), $sz); + $({ + static S: $t = $e; + let v: $t = $e; + assert_eq!(S, v); + assert_eq!(format!("{:?}", v), $s); + assert_eq!(format!("{:?}", S), $s); + });* + }} +} + +pub fn main() { + check!(Option<u8>, 2, + None, "None", + Some(129), "Some(129)"); + check!(Option<i16>, 4, + None, "None", + Some(-20000), "Some(-20000)"); + check!(Either<u8, i8>, 2, + Either::Left(132), "Left(132)", + Either::Right(-32), "Right(-32)"); + check!(Either<u8, i16>, 4, + Either::Left(132), "Left(132)", + Either::Right(-20000), "Right(-20000)"); +} diff --git a/tests/ui/structs-enums/struct-aliases-xcrate.rs b/tests/ui/structs-enums/struct-aliases-xcrate.rs new file mode 100644 index 000000000..ffe7b22f8 --- /dev/null +++ b/tests/ui/structs-enums/struct-aliases-xcrate.rs @@ -0,0 +1,25 @@ +// run-pass +#![allow(unused_imports)] +#![allow(non_shorthand_field_patterns)] + +// aux-build:xcrate_struct_aliases.rs + +extern crate xcrate_struct_aliases; + +use xcrate_struct_aliases::{S, S2}; + +fn main() { + let s = S2 { + x: 1, + y: 2, + }; + match s { + S2 { + x: x, + y: y + } => { + assert_eq!(x, 1); + assert_eq!(y, 2); + } + } +} diff --git a/tests/ui/structs-enums/struct-aliases.rs b/tests/ui/structs-enums/struct-aliases.rs new file mode 100644 index 000000000..b7aeed7bc --- /dev/null +++ b/tests/ui/structs-enums/struct-aliases.rs @@ -0,0 +1,64 @@ +// run-pass +#![allow(non_shorthand_field_patterns)] + +use std::mem; + +struct S { + x: isize, + y: isize, +} + +type S2 = S; + +struct S3<U,V> { + x: U, + y: V +} + +type S4<U> = S3<U, char>; + +fn main() { + let s = S2 { + x: 1, + y: 2, + }; + match s { + S2 { + x: x, + y: y + } => { + assert_eq!(x, 1); + assert_eq!(y, 2); + } + } + // check that generics can be specified from the pattern + let s = S4 { + x: 4, + y: 'a' + }; + match s { + S4::<u8> { + x: x, + y: y + } => { + assert_eq!(x, 4); + assert_eq!(y, 'a'); + assert_eq!(mem::size_of_val(&x), 1); + } + }; + // check that generics can be specified from the constructor + let s = S4::<u16> { + x: 5, + y: 'b' + }; + match s { + S4 { + x: x, + y: y + } => { + assert_eq!(x, 5); + assert_eq!(y, 'b'); + assert_eq!(mem::size_of_val(&x), 2); + } + }; +} diff --git a/tests/ui/structs-enums/struct-destructuring-cross-crate.rs b/tests/ui/structs-enums/struct-destructuring-cross-crate.rs new file mode 100644 index 000000000..19e0a0bbd --- /dev/null +++ b/tests/ui/structs-enums/struct-destructuring-cross-crate.rs @@ -0,0 +1,12 @@ +// run-pass +// aux-build:struct_destructuring_cross_crate.rs + + +extern crate struct_destructuring_cross_crate; + +pub fn main() { + let x = struct_destructuring_cross_crate::S { x: 1, y: 2 }; + let struct_destructuring_cross_crate::S { x: a, y: b } = x; + assert_eq!(a, 1); + assert_eq!(b, 2); +} diff --git a/tests/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs b/tests/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs new file mode 100644 index 000000000..c30b8a1e1 --- /dev/null +++ b/tests/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs @@ -0,0 +1,12 @@ +enum Foo { + Bar { bar: bool }, + Other, +} + +fn main() { + let foo = Some(Foo::Other); + + if let Some(Foo::Bar {_}) = foo {} + //~^ ERROR expected identifier, found reserved identifier `_` + //~| ERROR pattern does not mention field `bar` [E0027] +} diff --git a/tests/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr b/tests/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr new file mode 100644 index 000000000..16f751444 --- /dev/null +++ b/tests/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr @@ -0,0 +1,24 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/struct-enum-ignoring-field-with-underscore.rs:9:27 + | +LL | if let Some(Foo::Bar {_}) = foo {} + | ^ expected identifier, found reserved identifier + +error[E0027]: pattern does not mention field `bar` + --> $DIR/struct-enum-ignoring-field-with-underscore.rs:9:17 + | +LL | if let Some(Foo::Bar {_}) = foo {} + | ^^^^^^^^^^^^ missing field `bar` + | +help: include the missing field in the pattern + | +LL | if let Some(Foo::Bar {_, bar }) = foo {} + | ~~~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | if let Some(Foo::Bar {_, .. }) = foo {} + | ~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0027`. diff --git a/tests/ui/structs-enums/struct-field-shorthand.rs b/tests/ui/structs-enums/struct-field-shorthand.rs new file mode 100644 index 000000000..ed650c683 --- /dev/null +++ b/tests/ui/structs-enums/struct-field-shorthand.rs @@ -0,0 +1,26 @@ +// run-pass +struct Foo { + x: i32, + y: bool, + z: i32 +} + +struct Bar { + x: i32 +} + +pub fn main() { + let (x, y, z) = (1, true, 2); + let a = Foo { x, y: y, z }; + assert_eq!(a.x, x); + assert_eq!(a.y, y); + assert_eq!(a.z, z); + + let b = Bar { x, }; + assert_eq!(b.x, x); + + let c = Foo { z, y, x }; + assert_eq!(c.x, x); + assert_eq!(c.y, y); + assert_eq!(c.z, z); +} diff --git a/tests/ui/structs-enums/struct-like-variant-construct.rs b/tests/ui/structs-enums/struct-like-variant-construct.rs new file mode 100644 index 000000000..60fc7ce39 --- /dev/null +++ b/tests/ui/structs-enums/struct-like-variant-construct.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +enum Foo { + Bar { + a: isize, + b: isize + }, + Baz { + c: f64, + d: f64 + } +} + +pub fn main() { + let _x = Foo::Bar { a: 2, b: 3 }; +} diff --git a/tests/ui/structs-enums/struct-like-variant-match.rs b/tests/ui/structs-enums/struct-like-variant-match.rs new file mode 100644 index 000000000..ade1a6970 --- /dev/null +++ b/tests/ui/structs-enums/struct-like-variant-match.rs @@ -0,0 +1,33 @@ +// run-pass +#![allow(non_shorthand_field_patterns)] + +enum Foo { + Bar { + x: isize, + y: isize + }, + Baz { + x: f64, + y: f64 + } +} + +fn f(x: &Foo) { + match *x { + Foo::Baz { x: x, y: y } => { + assert_eq!(x, 1.0); + assert_eq!(y, 2.0); + } + Foo::Bar { y: y, x: x } => { + assert_eq!(x, 1); + assert_eq!(y, 2); + } + } +} + +pub fn main() { + let x = Foo::Bar { x: 1, y: 2 }; + f(&x); + let y = Foo::Baz { x: 1.0, y: 2.0 }; + f(&y); +} diff --git a/tests/ui/structs-enums/struct-lit-functional-no-fields.rs b/tests/ui/structs-enums/struct-lit-functional-no-fields.rs new file mode 100644 index 000000000..f19604e95 --- /dev/null +++ b/tests/ui/structs-enums/struct-lit-functional-no-fields.rs @@ -0,0 +1,26 @@ +// run-pass +#[derive(Debug,PartialEq,Clone)] +struct Foo<T> { + bar: T, + baz: T +} + +pub fn main() { + let foo = Foo { + bar: 0, + baz: 1 + }; + + let foo_ = foo.clone(); + let foo = Foo { ..foo }; + assert_eq!(foo, foo_); + + let foo = Foo { + bar: "one".to_string(), + baz: "two".to_string() + }; + + let foo_ = foo.clone(); + let foo = Foo { ..foo }; + assert_eq!(foo, foo_); +} diff --git a/tests/ui/structs-enums/struct-literal-dtor.rs b/tests/ui/structs-enums/struct-literal-dtor.rs new file mode 100644 index 000000000..6d1b1dfb9 --- /dev/null +++ b/tests/ui/structs-enums/struct-literal-dtor.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(non_camel_case_types)] + +struct foo { + x: String, +} + +impl Drop for foo { + fn drop(&mut self) { + println!("{}", self.x); + } +} + +pub fn main() { + let _z = foo { + x: "Hello".to_string() + }; +} diff --git a/tests/ui/structs-enums/struct-new-as-field-name.rs b/tests/ui/structs-enums/struct-new-as-field-name.rs new file mode 100644 index 000000000..641fc3c58 --- /dev/null +++ b/tests/ui/structs-enums/struct-new-as-field-name.rs @@ -0,0 +1,10 @@ +// run-pass + +struct Foo { + new: isize, +} + +pub fn main() { + let foo = Foo{ new: 3 }; + assert_eq!(foo.new, 3); +} diff --git a/tests/ui/structs-enums/struct-order-of-eval-1.rs b/tests/ui/structs-enums/struct-order-of-eval-1.rs new file mode 100644 index 000000000..f3fe99538 --- /dev/null +++ b/tests/ui/structs-enums/struct-order-of-eval-1.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(dead_code)] + +struct S { f0: String, f1: isize } + +pub fn main() { + let s = "Hello, world!".to_string(); + let s = S { + f0: s.to_string(), + ..S { + f0: s, + f1: 23 + } + }; + assert_eq!(s.f0, "Hello, world!"); +} diff --git a/tests/ui/structs-enums/struct-order-of-eval-2.rs b/tests/ui/structs-enums/struct-order-of-eval-2.rs new file mode 100644 index 000000000..a4e0edc97 --- /dev/null +++ b/tests/ui/structs-enums/struct-order-of-eval-2.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(dead_code)] + +struct S { + f0: String, + f1: String, +} + +pub fn main() { + let s = "Hello, world!".to_string(); + let s = S { + f1: s.to_string(), + f0: s + }; + assert_eq!(s.f0, "Hello, world!"); +} diff --git a/tests/ui/structs-enums/struct-order-of-eval-3.rs b/tests/ui/structs-enums/struct-order-of-eval-3.rs new file mode 100644 index 000000000..60887f8d0 --- /dev/null +++ b/tests/ui/structs-enums/struct-order-of-eval-3.rs @@ -0,0 +1,37 @@ +// run-pass +// Checks that functional-record-update order-of-eval is as expected +// even when no Drop-implementations are involved. + +use std::sync::atomic::{Ordering, AtomicUsize}; + +struct W { wrapped: u32 } +struct S { f0: W, _f1: i32 } + +pub fn main() { + const VAL: u32 = 0x89AB_CDEF; + let w = W { wrapped: VAL }; + let s = S { + f0: { event(0x01); W { wrapped: w.wrapped + 1 } }, + ..S { + f0: { event(0x02); w}, + _f1: 23 + } + }; + assert_eq!(s.f0.wrapped, VAL + 1); + let actual = event_log(); + let expect = 0x01_02; + assert!(expect == actual, + "expect: 0x{:x} actual: 0x{:x}", expect, actual); +} + +static LOG: AtomicUsize = AtomicUsize::new(0); + +fn event_log() -> usize { + LOG.load(Ordering::SeqCst) +} + +fn event(tag: u8) { + let old_log = LOG.load(Ordering::SeqCst); + let new_log = (old_log << 8) + tag as usize; + LOG.store(new_log, Ordering::SeqCst); +} diff --git a/tests/ui/structs-enums/struct-order-of-eval-4.rs b/tests/ui/structs-enums/struct-order-of-eval-4.rs new file mode 100644 index 000000000..547df6318 --- /dev/null +++ b/tests/ui/structs-enums/struct-order-of-eval-4.rs @@ -0,0 +1,34 @@ +// run-pass +// Checks that struct-literal expression order-of-eval is as expected +// even when no Drop-implementations are involved. + +use std::sync::atomic::{Ordering, AtomicUsize}; + +struct W { wrapped: u32 } +struct S { f0: W, _f1: i32 } + +pub fn main() { + const VAL: u32 = 0x89AB_CDEF; + let w = W { wrapped: VAL }; + let s = S { + _f1: { event(0x01); 23 }, + f0: { event(0x02); w }, + }; + assert_eq!(s.f0.wrapped, VAL); + let actual = event_log(); + let expect = 0x01_02; + assert!(expect == actual, + "expect: 0x{:x} actual: 0x{:x}", expect, actual); +} + +static LOG: AtomicUsize = AtomicUsize::new(0); + +fn event_log() -> usize { + LOG.load(Ordering::SeqCst) +} + +fn event(tag: u8) { + let old_log = LOG.load(Ordering::SeqCst); + let new_log = (old_log << 8) + tag as usize; + LOG.store(new_log, Ordering::SeqCst); +} diff --git a/tests/ui/structs-enums/struct-partial-move-1.rs b/tests/ui/structs-enums/struct-partial-move-1.rs new file mode 100644 index 000000000..c15701593 --- /dev/null +++ b/tests/ui/structs-enums/struct-partial-move-1.rs @@ -0,0 +1,21 @@ +// run-pass +#[derive(PartialEq, Debug)] +pub struct Partial<T> { x: T, y: T } + +#[derive(PartialEq, Debug)] +struct S { val: isize } +impl S { fn new(v: isize) -> S { S { val: v } } } +impl Drop for S { fn drop(&mut self) { } } + +pub fn f<T, F>((b1, b2): (T, T), mut f: F) -> Partial<T> where F: FnMut(T) -> T { + let p = Partial { x: b1, y: b2 }; + + // Move of `p` is legal even though we are also moving `p.y`; the + // `..p` moves all fields *except* `p.y` in this context. + Partial { y: f(p.y), ..p } +} + +pub fn main() { + let p = f((S::new(3), S::new(4)), |S { val: z }| S::new(z+1)); + assert_eq!(p, Partial { x: S::new(3), y: S::new(5) }); +} diff --git a/tests/ui/structs-enums/struct-partial-move-2.rs b/tests/ui/structs-enums/struct-partial-move-2.rs new file mode 100644 index 000000000..4315e5c29 --- /dev/null +++ b/tests/ui/structs-enums/struct-partial-move-2.rs @@ -0,0 +1,28 @@ +// run-pass +#[derive(PartialEq, Debug)] +pub struct Partial<T> { x: T, y: T } + +#[derive(PartialEq, Debug)] +struct S { val: isize } +impl S { fn new(v: isize) -> S { S { val: v } } } +impl Drop for S { fn drop(&mut self) { } } + +pub type Two<T> = (Partial<T>, Partial<T>); + +pub fn f<T, F>((b1, b2): (T, T), (b3, b4): (T, T), mut f: F) -> Two<T> where F: FnMut(T) -> T { + let p = Partial { x: b1, y: b2 }; + let q = Partial { x: b3, y: b4 }; + + // Move of `q` is legal even though we have already moved `q.y`; + // the `..q` moves all fields *except* `q.y` in this context. + // Likewise, the move of `p.x` is legal for similar reasons. + (Partial { x: f(q.y), ..p }, Partial { y: f(p.x), ..q }) +} + +pub fn main() { + let two = f((S::new(1), S::new(3)), + (S::new(5), S::new(7)), + |S { val: z }| S::new(z+1)); + assert_eq!(two, (Partial { x: S::new(8), y: S::new(3) }, + Partial { x: S::new(5), y: S::new(2) })); +} diff --git a/tests/ui/structs-enums/struct-path-associated-type.rs b/tests/ui/structs-enums/struct-path-associated-type.rs new file mode 100644 index 000000000..2235dfe4b --- /dev/null +++ b/tests/ui/structs-enums/struct-path-associated-type.rs @@ -0,0 +1,27 @@ +// run-pass +#![allow(dead_code)] +struct S<T, U = u16> { + a: T, + b: U, +} + +trait Tr { + type A; +} +impl Tr for u8 { + type A = S<u8, u16>; +} + +fn f<T: Tr<A = S<u8>>>() { + let s = T::A { a: 0, b: 1 }; + match s { + T::A { a, b } => { + assert_eq!(a, 0); + assert_eq!(b, 1); + } + } +} + +fn main() { + f::<u8>(); +} diff --git a/tests/ui/structs-enums/struct-path-self.rs b/tests/ui/structs-enums/struct-path-self.rs new file mode 100644 index 000000000..e7a59858f --- /dev/null +++ b/tests/ui/structs-enums/struct-path-self.rs @@ -0,0 +1,45 @@ +// run-pass +use std::ops::Add; + +struct S<T, U = u16> { + a: T, + b: U, +} + +trait Tr { + fn f(&self) -> Self; +} + +impl<T: Default + Add<u8, Output = T>, U: Default> Tr for S<T, U> { + fn f(&self) -> Self { + let s = Self { a: Default::default(), b: Default::default() }; + match s { + Self { a, b } => Self { a: a + 1, b: b } + } + } +} + +impl<T: Default, U: Default + Add<u16, Output = U>> S<T, U> { + fn g(&self) -> Self { + let s = Self { a: Default::default(), b: Default::default() }; + match s { + Self { a, b } => Self { a: a, b: b + 1 } + } + } +} + +impl S<u8> { + fn new() -> Self { + Self { a: 0, b: 1 } + } +} + +fn main() { + let s0 = S::new(); + let s1 = s0.f(); + assert_eq!(s1.a, 1); + assert_eq!(s1.b, 0); + let s2 = s0.g(); + assert_eq!(s2.a, 0); + assert_eq!(s2.b, 1); +} diff --git a/tests/ui/structs-enums/struct-pattern-matching.rs b/tests/ui/structs-enums/struct-pattern-matching.rs new file mode 100644 index 000000000..89361bf24 --- /dev/null +++ b/tests/ui/structs-enums/struct-pattern-matching.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(non_shorthand_field_patterns)] + +struct Foo { + x: isize, + y: isize, +} + +pub fn main() { + let a = Foo { x: 1, y: 2 }; + match a { + Foo { x: x, y: y } => println!("yes, {}, {}", x, y) + } + + match a { + Foo { .. } => () + } +} diff --git a/tests/ui/structs-enums/struct-rec/issue-74224.rs b/tests/ui/structs-enums/struct-rec/issue-74224.rs new file mode 100644 index 000000000..f3b72c5df --- /dev/null +++ b/tests/ui/structs-enums/struct-rec/issue-74224.rs @@ -0,0 +1,11 @@ +struct A<T> { +//~^ ERROR recursive type `A` has infinite size + x: T, + y: A<A<T>>, +} + +struct B { + z: A<usize> +} + +fn main() {} diff --git a/tests/ui/structs-enums/struct-rec/issue-74224.stderr b/tests/ui/structs-enums/struct-rec/issue-74224.stderr new file mode 100644 index 000000000..f1d50bc8a --- /dev/null +++ b/tests/ui/structs-enums/struct-rec/issue-74224.stderr @@ -0,0 +1,17 @@ +error[E0072]: recursive type `A` has infinite size + --> $DIR/issue-74224.rs:1:1 + | +LL | struct A<T> { + | ^^^^^^^^^^^ +... +LL | y: A<A<T>>, + | ------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL | y: Box<A<A<T>>>, + | ++++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/structs-enums/struct-rec/issue-84611.rs b/tests/ui/structs-enums/struct-rec/issue-84611.rs new file mode 100644 index 000000000..4c356af3e --- /dev/null +++ b/tests/ui/structs-enums/struct-rec/issue-84611.rs @@ -0,0 +1,11 @@ +struct Foo<T> { +//~^ ERROR recursive type `Foo` has infinite size + x: Foo<[T; 1]>, + y: T, +} + +struct Bar { + x: Foo<Bar>, +} + +fn main() {} diff --git a/tests/ui/structs-enums/struct-rec/issue-84611.stderr b/tests/ui/structs-enums/struct-rec/issue-84611.stderr new file mode 100644 index 000000000..536f54e3e --- /dev/null +++ b/tests/ui/structs-enums/struct-rec/issue-84611.stderr @@ -0,0 +1,17 @@ +error[E0072]: recursive type `Foo` has infinite size + --> $DIR/issue-84611.rs:1:1 + | +LL | struct Foo<T> { + | ^^^^^^^^^^^^^ +LL | +LL | x: Foo<[T; 1]>, + | ----------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL | x: Box<Foo<[T; 1]>>, + | ++++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/structs-enums/struct-rec/mutual-struct-recursion.rs b/tests/ui/structs-enums/struct-rec/mutual-struct-recursion.rs new file mode 100644 index 000000000..3bfce8b4f --- /dev/null +++ b/tests/ui/structs-enums/struct-rec/mutual-struct-recursion.rs @@ -0,0 +1,21 @@ +struct A<T> { +//~^ ERROR recursive types `A` and `B` have infinite size + x: T, + y: B<T>, +} + +struct B<T> { + z: A<T> +} + +struct C<T> { +//~^ ERROR recursive types `C` and `D` have infinite size + x: T, + y: Option<Option<D<T>>>, +} + +struct D<T> { + z: Option<Option<C<T>>>, +} + +fn main() {} diff --git a/tests/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr b/tests/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr new file mode 100644 index 000000000..881bc2819 --- /dev/null +++ b/tests/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr @@ -0,0 +1,49 @@ +error[E0072]: recursive types `A` and `B` have infinite size + --> $DIR/mutual-struct-recursion.rs:1:1 + | +LL | struct A<T> { + | ^^^^^^^^^^^ +... +LL | y: B<T>, + | ---- recursive without indirection +... +LL | struct B<T> { + | ^^^^^^^^^^^ +LL | z: A<T> + | ---- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL ~ y: Box<B<T>>, +LL | } +LL | +LL | struct B<T> { +LL ~ z: Box<A<T>> + | + +error[E0072]: recursive types `C` and `D` have infinite size + --> $DIR/mutual-struct-recursion.rs:11:1 + | +LL | struct C<T> { + | ^^^^^^^^^^^ +... +LL | y: Option<Option<D<T>>>, + | ---- recursive without indirection +... +LL | struct D<T> { + | ^^^^^^^^^^^ +LL | z: Option<Option<C<T>>>, + | ---- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL ~ y: Option<Option<Box<D<T>>>>, +LL | } +LL | +LL | struct D<T> { +LL ~ z: Option<Option<Box<C<T>>>>, + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/structs-enums/struct-variant-field-visibility.rs b/tests/ui/structs-enums/struct-variant-field-visibility.rs new file mode 100644 index 000000000..7896c829a --- /dev/null +++ b/tests/ui/structs-enums/struct-variant-field-visibility.rs @@ -0,0 +1,17 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +mod foo { + pub enum Foo { + Bar { a: isize } + } +} + +fn f(f: foo::Foo) { + match f { + foo::Foo::Bar { a: _a } => {} + } +} + +pub fn main() {} diff --git a/tests/ui/structs-enums/struct_variant_xc.rs b/tests/ui/structs-enums/struct_variant_xc.rs new file mode 100644 index 000000000..9c8d1a69a --- /dev/null +++ b/tests/ui/structs-enums/struct_variant_xc.rs @@ -0,0 +1,11 @@ +// run-pass +// aux-build:struct_variant_xc_aux.rs +// pretty-expanded FIXME #23616 + +extern crate struct_variant_xc_aux; + +use struct_variant_xc_aux::Enum::StructVariant; + +pub fn main() { + let _ = StructVariant { arg: 1 }; +} diff --git a/tests/ui/structs-enums/struct_variant_xc_match.rs b/tests/ui/structs-enums/struct_variant_xc_match.rs new file mode 100644 index 000000000..5358d13fa --- /dev/null +++ b/tests/ui/structs-enums/struct_variant_xc_match.rs @@ -0,0 +1,14 @@ +// run-pass +// aux-build:struct_variant_xc_aux.rs + +extern crate struct_variant_xc_aux; + +use struct_variant_xc_aux::Enum::{StructVariant, Variant}; + +pub fn main() { + let arg = match (StructVariant { arg: 42 }) { + Variant(_) => unreachable!(), + StructVariant { arg } => arg + }; + assert_eq!(arg, 42); +} diff --git a/tests/ui/structs-enums/tag-align-dyn-u64.rs b/tests/ui/structs-enums/tag-align-dyn-u64.rs new file mode 100644 index 000000000..3f7a5e3e5 --- /dev/null +++ b/tests/ui/structs-enums/tag-align-dyn-u64.rs @@ -0,0 +1,29 @@ +// run-pass +#![allow(dead_code)] +#![allow(deprecated)] + +use std::mem; + +enum Tag<A> { + Tag2(A) +} + +struct Rec { + c8: u8, + t: Tag<u64> +} + +fn mk_rec() -> Rec { + return Rec { c8:0, t:Tag::Tag2(0) }; +} + +fn is_u64_aligned(u: &Tag<u64>) -> bool { + let p: usize = unsafe { mem::transmute(u) }; + let u64_align = std::mem::min_align_of::<u64>(); + return (p & (u64_align - 1)) == 0; +} + +pub fn main() { + let x = mk_rec(); + assert!(is_u64_aligned(&x.t)); +} diff --git a/tests/ui/structs-enums/tag-align-dyn-variants.rs b/tests/ui/structs-enums/tag-align-dyn-variants.rs new file mode 100644 index 000000000..4d075b04c --- /dev/null +++ b/tests/ui/structs-enums/tag-align-dyn-variants.rs @@ -0,0 +1,67 @@ +// run-pass +#![allow(dead_code)] +#![allow(deprecated)] +#![allow(non_snake_case)] + +use std::mem; + +enum Tag<A,B> { + VarA(A), + VarB(B), +} + +struct Rec<A,B> { + chA: u8, + tA: Tag<A,B>, + chB: u8, + tB: Tag<A,B>, +} + +fn mk_rec<A,B>(a: A, b: B) -> Rec<A,B> { + Rec { chA:0, tA:Tag::VarA(a), chB:1, tB:Tag::VarB(b) } +} + +fn is_aligned<A>(amnt: usize, u: &A) -> bool { + let p: usize = unsafe { mem::transmute(u) }; + return (p & (amnt-1)) == 0; +} + +fn variant_data_is_aligned<A,B>(amnt: usize, u: &Tag<A,B>) -> bool { + match u { + &Tag::VarA(ref a) => is_aligned(amnt, a), + &Tag::VarB(ref b) => is_aligned(amnt, b) + } +} + +pub fn main() { + let u64_align = std::mem::min_align_of::<u64>(); + let x = mk_rec(22u64, 23u64); + assert!(is_aligned(u64_align, &x.tA)); + assert!(variant_data_is_aligned(u64_align, &x.tA)); + assert!(is_aligned(u64_align, &x.tB)); + assert!(variant_data_is_aligned(u64_align, &x.tB)); + + let x = mk_rec(22u64, 23u32); + assert!(is_aligned(u64_align, &x.tA)); + assert!(variant_data_is_aligned(u64_align, &x.tA)); + assert!(is_aligned(u64_align, &x.tB)); + assert!(variant_data_is_aligned(4, &x.tB)); + + let x = mk_rec(22u32, 23u64); + assert!(is_aligned(u64_align, &x.tA)); + assert!(variant_data_is_aligned(4, &x.tA)); + assert!(is_aligned(u64_align, &x.tB)); + assert!(variant_data_is_aligned(u64_align, &x.tB)); + + let x = mk_rec(22u32, 23u32); + assert!(is_aligned(4, &x.tA)); + assert!(variant_data_is_aligned(4, &x.tA)); + assert!(is_aligned(4, &x.tB)); + assert!(variant_data_is_aligned(4, &x.tB)); + + let x = mk_rec(22f64, 23f64); + assert!(is_aligned(u64_align, &x.tA)); + assert!(variant_data_is_aligned(u64_align, &x.tA)); + assert!(is_aligned(u64_align, &x.tB)); + assert!(variant_data_is_aligned(u64_align, &x.tB)); +} diff --git a/tests/ui/structs-enums/tag-align-shape.rs b/tests/ui/structs-enums/tag-align-shape.rs new file mode 100644 index 000000000..ce5995823 --- /dev/null +++ b/tests/ui/structs-enums/tag-align-shape.rs @@ -0,0 +1,21 @@ +// run-pass +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +#[derive(Debug)] +enum a_tag { + a_tag_var(u64) +} + +#[derive(Debug)] +struct t_rec { + c8: u8, + t: a_tag +} + +pub fn main() { + let x = t_rec {c8: 22, t: a_tag::a_tag_var(44)}; + let y = format!("{:?}", x); + println!("y = {:?}", y); + assert_eq!(y, "t_rec { c8: 22, t: a_tag_var(44) }".to_string()); +} diff --git a/tests/ui/structs-enums/tag-align-u64.rs b/tests/ui/structs-enums/tag-align-u64.rs new file mode 100644 index 000000000..684b27cd0 --- /dev/null +++ b/tests/ui/structs-enums/tag-align-u64.rs @@ -0,0 +1,29 @@ +// run-pass +#![allow(dead_code)] +#![allow(deprecated)] + +use std::mem; + +enum Tag { + TagInner(u64) +} + +struct Rec { + c8: u8, + t: Tag +} + +fn mk_rec() -> Rec { + return Rec { c8:0, t:Tag::TagInner(0) }; +} + +fn is_u64_aligned(u: &Tag) -> bool { + let p: usize = unsafe { mem::transmute(u) }; + let u64_align = std::mem::min_align_of::<u64>(); + return (p & (u64_align - 1)) == 0; +} + +pub fn main() { + let x = mk_rec(); + assert!(is_u64_aligned(&x.t)); +} diff --git a/tests/ui/structs-enums/tag-disr-val-shape.rs b/tests/ui/structs-enums/tag-disr-val-shape.rs new file mode 100644 index 000000000..51052626c --- /dev/null +++ b/tests/ui/structs-enums/tag-disr-val-shape.rs @@ -0,0 +1,20 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +#[derive(Debug)] +enum color { + red = 0xff0000, + green = 0x00ff00, + blue = 0x0000ff, + black = 0x000000, + white = 0xFFFFFF, +} + +pub fn main() { + let act = format!("{:?}", color::red); + println!("{}", act); + assert_eq!("red".to_string(), act); + assert_eq!("green".to_string(), format!("{:?}", color::green)); + assert_eq!("white".to_string(), format!("{:?}", color::white)); +} diff --git a/tests/ui/structs-enums/tag-exports.rs b/tests/ui/structs-enums/tag-exports.rs new file mode 100644 index 000000000..1bcb7d35d --- /dev/null +++ b/tests/ui/structs-enums/tag-exports.rs @@ -0,0 +1,21 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +// pretty-expanded FIXME #23616 + +use alder::*; + +mod alder { + pub enum burnside { couch, davis } + pub enum everett { flanders, glisan, hoyt } + pub enum irving { johnson, kearney, lovejoy } + pub enum marshall { northrup, overton } +} + +pub fn main() { + let _pettygrove: burnside = burnside::couch; + let _quimby: everett = everett::flanders; + let _raleigh: irving = irving::johnson; + let _savier: marshall; +} diff --git a/tests/ui/structs-enums/tag-in-block.rs b/tests/ui/structs-enums/tag-in-block.rs new file mode 100644 index 000000000..03d4dd9b0 --- /dev/null +++ b/tests/ui/structs-enums/tag-in-block.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + + + +// pretty-expanded FIXME #23616 + +fn foo() { + fn zed(_z: bar) { } + enum bar { nil, } + fn baz() { zed(bar::nil); } +} + +pub fn main() { } diff --git a/tests/ui/structs-enums/tag-variant-disr-type-mismatch.rs b/tests/ui/structs-enums/tag-variant-disr-type-mismatch.rs new file mode 100644 index 000000000..3f59db383 --- /dev/null +++ b/tests/ui/structs-enums/tag-variant-disr-type-mismatch.rs @@ -0,0 +1,12 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +// pretty-expanded FIXME #23616 + +enum color { + red = 1, + blue = 2, +} + +pub fn main() {} diff --git a/tests/ui/structs-enums/tag-variant-disr-val.rs b/tests/ui/structs-enums/tag-variant-disr-val.rs new file mode 100644 index 000000000..297d85c58 --- /dev/null +++ b/tests/ui/structs-enums/tag-variant-disr-val.rs @@ -0,0 +1,66 @@ +// run-pass +#![allow(non_camel_case_types)] + +use color::{red, green, blue, black, white, imaginary, purple, orange}; + +#[derive(Copy, Clone)] +enum color { + red = 0xff0000, + green = 0x00ff00, + blue = 0x0000ff, + black = 0x000000, + white = 0xFFFFFF, + imaginary = -1, + purple = 1 << 1, + orange = 8 >> 1 +} + +impl PartialEq for color { + fn eq(&self, other: &color) -> bool { + ((*self) as usize) == ((*other) as usize) + } + fn ne(&self, other: &color) -> bool { !(*self).eq(other) } +} + +pub fn main() { + test_color(red, 0xff0000, "red".to_string()); + test_color(green, 0x00ff00, "green".to_string()); + test_color(blue, 0x0000ff, "blue".to_string()); + test_color(black, 0x000000, "black".to_string()); + test_color(white, 0xFFFFFF, "white".to_string()); + test_color(imaginary, -1, "imaginary".to_string()); + test_color(purple, 2, "purple".to_string()); + test_color(orange, 4, "orange".to_string()); +} + +fn test_color(color: color, val: isize, name: String) { + //assert_eq!(unsafe::transmute(color), val); + assert_eq!(color as isize, val); + assert_eq!(get_color_alt(color), name); + assert_eq!(get_color_if(color), name); +} + +fn get_color_alt(color: color) -> String { + match color { + red => {"red".to_string()} + green => {"green".to_string()} + blue => {"blue".to_string()} + black => {"black".to_string()} + white => {"white".to_string()} + imaginary => {"imaginary".to_string()} + purple => {"purple".to_string()} + orange => {"orange".to_string()} + } +} + +fn get_color_if(color: color) -> String { + if color == red {"red".to_string()} + else if color == green {"green".to_string()} + else if color == blue {"blue".to_string()} + else if color == black {"black".to_string()} + else if color == white {"white".to_string()} + else if color == imaginary {"imaginary".to_string()} + else if color == purple {"purple".to_string()} + else if color == orange {"orange".to_string()} + else {"unknown".to_string()} +} diff --git a/tests/ui/structs-enums/tag.rs b/tests/ui/structs-enums/tag.rs new file mode 100644 index 000000000..5fcd64b7c --- /dev/null +++ b/tests/ui/structs-enums/tag.rs @@ -0,0 +1,30 @@ +// run-pass +#![allow(unused_parens)] +#![allow(non_camel_case_types)] + + +enum colour { red(isize, isize), green, } + +impl PartialEq for colour { + fn eq(&self, other: &colour) -> bool { + match *self { + colour::red(a0, b0) => { + match (*other) { + colour::red(a1, b1) => a0 == a1 && b0 == b1, + colour::green => false, + } + } + colour::green => { + match (*other) { + colour::red(..) => false, + colour::green => true + } + } + } + } + fn ne(&self, other: &colour) -> bool { !(*self).eq(other) } +} + +fn f() { let x = colour::red(1, 2); let y = colour::green; assert!((x != y)); } + +pub fn main() { f(); } diff --git a/tests/ui/structs-enums/tuple-struct-construct.rs b/tests/ui/structs-enums/tuple-struct-construct.rs new file mode 100644 index 000000000..fbf97e6b2 --- /dev/null +++ b/tests/ui/structs-enums/tuple-struct-construct.rs @@ -0,0 +1,9 @@ +// run-pass +#[allow(unused_tuple_struct_fields)] +#[derive(Debug)] +struct Foo(isize, isize); + +pub fn main() { + let x = Foo(1, 2); + println!("{:?}", x); +} diff --git a/tests/ui/structs-enums/tuple-struct-constructor-pointer.rs b/tests/ui/structs-enums/tuple-struct-constructor-pointer.rs new file mode 100644 index 000000000..23f065163 --- /dev/null +++ b/tests/ui/structs-enums/tuple-struct-constructor-pointer.rs @@ -0,0 +1,12 @@ +// run-pass +#[derive(PartialEq, Debug)] +struct Foo(isize); +#[derive(PartialEq, Debug)] +struct Bar(isize, isize); + +pub fn main() { + let f: fn(isize) -> Foo = Foo; + let g: fn(isize, isize) -> Bar = Bar; + assert_eq!(f(42), Foo(42)); + assert_eq!(g(4, 7), Bar(4, 7)); +} diff --git a/tests/ui/structs-enums/tuple-struct-destructuring.rs b/tests/ui/structs-enums/tuple-struct-destructuring.rs new file mode 100644 index 000000000..dff87ead0 --- /dev/null +++ b/tests/ui/structs-enums/tuple-struct-destructuring.rs @@ -0,0 +1,10 @@ +// run-pass +struct Foo(isize, isize); + +pub fn main() { + let x = Foo(1, 2); + let Foo(y, z) = x; + println!("{} {}", y, z); + assert_eq!(y, 1); + assert_eq!(z, 2); +} diff --git a/tests/ui/structs-enums/tuple-struct-matching.rs b/tests/ui/structs-enums/tuple-struct-matching.rs new file mode 100644 index 000000000..432be1d1f --- /dev/null +++ b/tests/ui/structs-enums/tuple-struct-matching.rs @@ -0,0 +1,13 @@ +// run-pass +struct Foo(isize, isize); + +pub fn main() { + let x = Foo(1, 2); + match x { + Foo(a, b) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + println!("{} {}", a, b); + } + } +} diff --git a/tests/ui/structs-enums/tuple-struct-trivial.rs b/tests/ui/structs-enums/tuple-struct-trivial.rs new file mode 100644 index 000000000..c8651fd29 --- /dev/null +++ b/tests/ui/structs-enums/tuple-struct-trivial.rs @@ -0,0 +1,8 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +struct Foo(isize, isize, isize); + +pub fn main() { +} diff --git a/tests/ui/structs-enums/type-sizes.rs b/tests/ui/structs-enums/type-sizes.rs new file mode 100644 index 000000000..63e2f3150 --- /dev/null +++ b/tests/ui/structs-enums/type-sizes.rs @@ -0,0 +1,273 @@ +// run-pass + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(never_type)] +#![feature(pointer_is_aligned)] + +use std::mem::size_of; +use std::num::NonZeroU8; + +struct t {a: u8, b: i8} +struct u {a: u8, b: i8, c: u8} +struct v {a: u8, b: i8, c: v2, d: u32} +struct v2 {u: char, v: u8} +struct w {a: isize, b: ()} +struct x {a: isize, b: (), c: ()} +struct y {x: isize} + +enum e1 { + a(u8, u32), b(u32), c +} +enum e2 { + a(u32), b +} + +#[repr(C, u8)] +enum e3 { + a([u16; 0], u8), b +} + +struct ReorderedStruct { + a: u8, + b: u16, + c: u8 +} + +enum ReorderedEnum { + A(u8, u16, u8), + B(u8, u16, u8), +} + +enum ReorderedEnum2 { + A(u8, u32, u8), + B(u16, u8, u16, u8), + + // 0x100 niche variants. + _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0A, _0B, _0C, _0D, _0E, _0F, + _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1A, _1B, _1C, _1D, _1E, _1F, + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2A, _2B, _2C, _2D, _2E, _2F, + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3A, _3B, _3C, _3D, _3E, _3F, + _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4A, _4B, _4C, _4D, _4E, _4F, + _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5A, _5B, _5C, _5D, _5E, _5F, + _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6A, _6B, _6C, _6D, _6E, _6F, + _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7A, _7B, _7C, _7D, _7E, _7F, + _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8A, _8B, _8C, _8D, _8E, _8F, + _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9A, _9B, _9C, _9D, _9E, _9F, + _A0, _A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8, _A9, _AA, _AB, _AC, _AD, _AE, _AF, + _B0, _B1, _B2, _B3, _B4, _B5, _B6, _B7, _B8, _B9, _BA, _BB, _BC, _BD, _BE, _BF, + _C0, _C1, _C2, _C3, _C4, _C5, _C6, _C7, _C8, _C9, _CA, _CB, _CC, _CD, _CE, _CF, + _D0, _D1, _D2, _D3, _D4, _D5, _D6, _D7, _D8, _D9, _DA, _DB, _DC, _DD, _DE, _DF, + _E0, _E1, _E2, _E3, _E4, _E5, _E6, _E7, _E8, _E9, _EA, _EB, _EC, _ED, _EE, _EF, + _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF, +} + +enum EnumEmpty {} + +enum EnumSingle1 { + A, +} + +enum EnumSingle2 { + A = 42 as isize, +} + +enum EnumSingle3 { + A, + B(!), +} + +#[repr(u8)] +enum EnumSingle4 { + A, +} + +#[repr(u8)] +enum EnumSingle5 { + A = 42 as u8, +} + +enum EnumWithMaybeUninhabitedVariant<T> { + A(&'static ()), + B(&'static (), T), + C, +} + +enum NicheFilledEnumWithAbsentVariant { + A(&'static ()), + B((), !), + C, +} + +enum Option2<A, B> { + Some(A, B), + None +} + +// Two layouts are considered for `CanBeNicheFilledButShouldnt`: +// Niche-filling: +// { u32 (4 bytes), NonZeroU8 + tag in niche (1 byte), padding (3 bytes) } +// Tagged: +// { tag (1 byte), NonZeroU8 (1 byte), padding (2 bytes), u32 (4 bytes) } +// Both are the same size (due to padding), +// but the tagged layout is better as the tag creates a niche with 254 invalid values, +// allowing types like `Option<Option<CanBeNicheFilledButShouldnt>>` to fit into 8 bytes. +pub enum CanBeNicheFilledButShouldnt { + A(NonZeroU8, u32), + B +} +pub enum AlwaysTaggedBecauseItHasNoNiche { + A(u8, u32), + B +} + +pub enum NicheFilledMultipleFields { + A(bool, u8), + B(u8), + C(u8), + D(bool), + E, + F, + G, +} + +struct BoolInTheMiddle(std::num::NonZeroU16, bool, u8); + +enum NicheWithData { + A, + B([u16; 5]), + Largest { a1: u32, a2: BoolInTheMiddle, a3: u32 }, + C, + D(u32, u32), +} + +// A type with almost 2^16 invalid values. +#[repr(u16)] +pub enum NicheU16 { + _0, +} + +pub enum EnumManyVariant<X> { + Dataful(u8, X), + + // 0x100 niche variants. + _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0A, _0B, _0C, _0D, _0E, _0F, + _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1A, _1B, _1C, _1D, _1E, _1F, + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2A, _2B, _2C, _2D, _2E, _2F, + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3A, _3B, _3C, _3D, _3E, _3F, + _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4A, _4B, _4C, _4D, _4E, _4F, + _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5A, _5B, _5C, _5D, _5E, _5F, + _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6A, _6B, _6C, _6D, _6E, _6F, + _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7A, _7B, _7C, _7D, _7E, _7F, + _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8A, _8B, _8C, _8D, _8E, _8F, + _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9A, _9B, _9C, _9D, _9E, _9F, + _A0, _A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8, _A9, _AA, _AB, _AC, _AD, _AE, _AF, + _B0, _B1, _B2, _B3, _B4, _B5, _B6, _B7, _B8, _B9, _BA, _BB, _BC, _BD, _BE, _BF, + _C0, _C1, _C2, _C3, _C4, _C5, _C6, _C7, _C8, _C9, _CA, _CB, _CC, _CD, _CE, _CF, + _D0, _D1, _D2, _D3, _D4, _D5, _D6, _D7, _D8, _D9, _DA, _DB, _DC, _DD, _DE, _DF, + _E0, _E1, _E2, _E3, _E4, _E5, _E6, _E7, _E8, _E9, _EA, _EB, _EC, _ED, _EE, _EF, + _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF, +} + +struct Reorder4 { + a: u32, + b: u8, + ary: [u8; 4], +} + +struct Reorder2 { + a: u16, + b: u8, + ary: [u8; 6], +} + +pub fn main() { + assert_eq!(size_of::<u8>(), 1 as usize); + assert_eq!(size_of::<u32>(), 4 as usize); + assert_eq!(size_of::<char>(), 4 as usize); + assert_eq!(size_of::<i8>(), 1 as usize); + assert_eq!(size_of::<i32>(), 4 as usize); + assert_eq!(size_of::<t>(), 2 as usize); + assert_eq!(size_of::<u>(), 3 as usize); + // Alignment causes padding before the char and the u32. + + assert_eq!(size_of::<v>(), + 16 as usize); + assert_eq!(size_of::<isize>(), size_of::<usize>()); + assert_eq!(size_of::<w>(), size_of::<isize>()); + assert_eq!(size_of::<x>(), size_of::<isize>()); + assert_eq!(size_of::<isize>(), size_of::<y>()); + + // Make sure enum types are the appropriate size, mostly + // around ensuring alignment is handled properly + + assert_eq!(size_of::<e1>(), 8 as usize); + assert_eq!(size_of::<e2>(), 8 as usize); + assert_eq!(size_of::<e3>(), 4 as usize); + assert_eq!(size_of::<ReorderedStruct>(), 4); + assert_eq!(size_of::<ReorderedEnum>(), 6); + assert_eq!(size_of::<ReorderedEnum2>(), 8); + + + assert_eq!(size_of::<EnumEmpty>(), 0); + assert_eq!(size_of::<EnumSingle1>(), 0); + assert_eq!(size_of::<EnumSingle2>(), 0); + assert_eq!(size_of::<EnumSingle3>(), 0); + assert_eq!(size_of::<EnumSingle4>(), 1); + assert_eq!(size_of::<EnumSingle5>(), 1); + + assert_eq!(size_of::<EnumWithMaybeUninhabitedVariant<!>>(), + size_of::<EnumWithMaybeUninhabitedVariant<()>>()); + assert_eq!(size_of::<NicheFilledEnumWithAbsentVariant>(), size_of::<&'static ()>()); + + assert_eq!(size_of::<Option<Option<(bool, &())>>>(), size_of::<(bool, &())>()); + assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>()); + assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>()); + assert_eq!(size_of::<Option<Option2<&(), bool>>>(), size_of::<(bool, &())>()); + + assert_eq!(size_of::<CanBeNicheFilledButShouldnt>(), 8); + assert_eq!(size_of::<Option<CanBeNicheFilledButShouldnt>>(), 8); + assert_eq!(size_of::<Option<Option<CanBeNicheFilledButShouldnt>>>(), 8); + assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8); + assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8); + assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8); + + assert_eq!(size_of::<NicheFilledMultipleFields>(), 2); + assert_eq!(size_of::<Option<NicheFilledMultipleFields>>(), 2); + assert_eq!(size_of::<Option<Option<NicheFilledMultipleFields>>>(), 2); + + struct S1{ a: u16, b: std::num::NonZeroU16, c: u16, d: u8, e: u32, f: u64, g:[u8;2] } + assert_eq!(size_of::<S1>(), 24); + assert_eq!(size_of::<Option<S1>>(), 24); + + assert_eq!(size_of::<NicheWithData>(), 12); + assert_eq!(size_of::<Option<NicheWithData>>(), 12); + assert_eq!(size_of::<Option<Option<NicheWithData>>>(), 12); + assert_eq!( + size_of::<Option<Option2<&(), Option<NicheWithData>>>>(), + size_of::<(&(), NicheWithData)>() + ); + + pub enum FillPadding { A(std::num::NonZeroU8, u32), B } + assert_eq!(size_of::<FillPadding>(), 8); + assert_eq!(size_of::<Option<FillPadding>>(), 8); + assert_eq!(size_of::<Option<Option<FillPadding>>>(), 8); + + assert_eq!(size_of::<Result<(std::num::NonZeroU8, u8, u8), u16>>(), 4); + assert_eq!(size_of::<Option<Result<(std::num::NonZeroU8, u8, u8), u16>>>(), 4); + assert_eq!(size_of::<Result<(std::num::NonZeroU8, u8, u8, u8), u16>>(), 4); + + assert_eq!(size_of::<EnumManyVariant<u16>>(), 6); + assert_eq!(size_of::<EnumManyVariant<NicheU16>>(), 4); + assert_eq!(size_of::<EnumManyVariant<Option<NicheU16>>>(), 4); + assert_eq!(size_of::<EnumManyVariant<Option2<NicheU16,u8>>>(), 6); + assert_eq!(size_of::<EnumManyVariant<Option<(NicheU16,u8)>>>(), 6); + + + let v = Reorder4 {a: 0, b: 0, ary: [0; 4]}; + assert_eq!(size_of::<Reorder4>(), 12); + assert!((&v.ary).as_ptr().is_aligned_to(4), "[u8; 4] should group with align-4 fields"); + let v = Reorder2 {a: 0, b: 0, ary: [0; 6]}; + assert_eq!(size_of::<Reorder2>(), 10); + assert!((&v.ary).as_ptr().is_aligned_to(2), "[u8; 6] should group with align-2 fields"); +} diff --git a/tests/ui/structs-enums/uninstantiable-struct.rs b/tests/ui/structs-enums/uninstantiable-struct.rs new file mode 100644 index 000000000..b24effe5a --- /dev/null +++ b/tests/ui/structs-enums/uninstantiable-struct.rs @@ -0,0 +1,4 @@ +// run-pass +pub struct Z(#[allow(unused_tuple_struct_fields)] &'static Z); + +pub fn main() {} diff --git a/tests/ui/structs-enums/unit-like-struct-drop-run.rs b/tests/ui/structs-enums/unit-like-struct-drop-run.rs new file mode 100644 index 000000000..1e9c269a4 --- /dev/null +++ b/tests/ui/structs-enums/unit-like-struct-drop-run.rs @@ -0,0 +1,24 @@ +// run-pass +// needs-unwind +// ignore-emscripten no threads support + +// Make sure the destructor is run for unit-like structs. + +use std::thread; + +struct Foo; + +impl Drop for Foo { + fn drop(&mut self) { + panic!("This panic should happen."); + } +} + +pub fn main() { + let x = thread::spawn(move|| { + let _b = Foo; + }).join(); + + let s = x.unwrap_err().downcast::<&'static str>().unwrap(); + assert_eq!(&**s, "This panic should happen."); +} diff --git a/tests/ui/structs-enums/unit-like-struct.rs b/tests/ui/structs-enums/unit-like-struct.rs new file mode 100644 index 000000000..636ec9926 --- /dev/null +++ b/tests/ui/structs-enums/unit-like-struct.rs @@ -0,0 +1,9 @@ +// run-pass +struct Foo; + +pub fn main() { + let x: Foo = Foo; + match x { + Foo => { println!("hi"); } + } +} diff --git a/tests/ui/structs-enums/variant-structs-trivial.rs b/tests/ui/structs-enums/variant-structs-trivial.rs new file mode 100644 index 000000000..31fa610a6 --- /dev/null +++ b/tests/ui/structs-enums/variant-structs-trivial.rs @@ -0,0 +1,10 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +enum Foo { + Bar { x: isize }, + Baz { y: isize } +} + +pub fn main() { } |