diff options
Diffstat (limited to '')
234 files changed, 7212 insertions, 0 deletions
diff --git a/src/test/ui/str/str-array-assignment.rs b/src/test/ui/str/str-array-assignment.rs new file mode 100644 index 000000000..323eefb38 --- /dev/null +++ b/src/test/ui/str/str-array-assignment.rs @@ -0,0 +1,11 @@ +fn main() { + let s = "abc"; + let t = if true { s[..2] } else { s }; + //~^ ERROR `if` and `else` have incompatible types + let u: &str = if true { s[..2] } else { s }; + //~^ ERROR mismatched types + let v = s[..2]; + //~^ ERROR the size for values of type + let w: &str = s[..2]; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/str/str-array-assignment.stderr b/src/test/ui/str/str-array-assignment.stderr new file mode 100644 index 000000000..c23400a1d --- /dev/null +++ b/src/test/ui/str/str-array-assignment.stderr @@ -0,0 +1,45 @@ +error[E0308]: `if` and `else` have incompatible types + --> $DIR/str-array-assignment.rs:3:37 + | +LL | let t = if true { s[..2] } else { s }; + | ------ ^ expected `str`, found `&str` + | | + | expected because of this + +error[E0308]: mismatched types + --> $DIR/str-array-assignment.rs:5:27 + | +LL | let u: &str = if true { s[..2] } else { s }; + | ^^^^^^ + | | + | expected `&str`, found `str` + | help: consider borrowing here: `&s[..2]` + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/str-array-assignment.rs:7:7 + | +LL | let v = s[..2]; + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature +help: consider borrowing here + | +LL | let v = &s[..2]; + | + + +error[E0308]: mismatched types + --> $DIR/str-array-assignment.rs:9:17 + | +LL | let w: &str = s[..2]; + | ---- ^^^^^^ + | | | + | | expected `&str`, found `str` + | | help: consider borrowing here: `&s[..2]` + | expected due to this + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/str/str-as-char.fixed b/src/test/ui/str/str-as-char.fixed new file mode 100644 index 000000000..42bbef839 --- /dev/null +++ b/src/test/ui/str/str-as-char.fixed @@ -0,0 +1,5 @@ +// run-rustfix + +fn main() { + println!("●●"); //~ ERROR character literal may only contain one codepoint +} diff --git a/src/test/ui/str/str-as-char.rs b/src/test/ui/str/str-as-char.rs new file mode 100644 index 000000000..09b9dfc59 --- /dev/null +++ b/src/test/ui/str/str-as-char.rs @@ -0,0 +1,5 @@ +// run-rustfix + +fn main() { + println!('●●'); //~ ERROR character literal may only contain one codepoint +} diff --git a/src/test/ui/str/str-as-char.stderr b/src/test/ui/str/str-as-char.stderr new file mode 100644 index 000000000..c3cb488e3 --- /dev/null +++ b/src/test/ui/str/str-as-char.stderr @@ -0,0 +1,13 @@ +error: character literal may only contain one codepoint + --> $DIR/str-as-char.rs:4:14 + | +LL | println!('●●'); + | ^^^^ + | +help: if you meant to write a `str` literal, use double quotes + | +LL | println!("●●"); + | ~~~~ + +error: aborting due to previous error + diff --git a/src/test/ui/str/str-concat-on-double-ref.rs b/src/test/ui/str/str-concat-on-double-ref.rs new file mode 100644 index 000000000..e68210d53 --- /dev/null +++ b/src/test/ui/str/str-concat-on-double-ref.rs @@ -0,0 +1,7 @@ +fn main() { + let a: &String = &"1".to_owned(); + let b: &str = &"2"; + let c = a + b; + //~^ ERROR cannot add `&str` to `&String` + println!("{:?}", c); +} diff --git a/src/test/ui/str/str-concat-on-double-ref.stderr b/src/test/ui/str/str-concat-on-double-ref.stderr new file mode 100644 index 000000000..bd354679f --- /dev/null +++ b/src/test/ui/str/str-concat-on-double-ref.stderr @@ -0,0 +1,18 @@ +error[E0369]: cannot add `&str` to `&String` + --> $DIR/str-concat-on-double-ref.rs:4:15 + | +LL | let c = a + b; + | - ^ - &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &String + | + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + | +LL | let c = a.to_owned() + b; + | +++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/str/str-escape.rs b/src/test/ui/str/str-escape.rs new file mode 100644 index 000000000..0264632fd --- /dev/null +++ b/src/test/ui/str/str-escape.rs @@ -0,0 +1,11 @@ +// check-pass +fn main() { + let s = "\ + + "; + //~^^^ WARNING multiple lines skipped by escaped newline + let s = "foo\ + bar + "; + //~^^^ WARNING non-ASCII whitespace symbol '\u{a0}' is not skipped +} diff --git a/src/test/ui/str/str-escape.stderr b/src/test/ui/str/str-escape.stderr new file mode 100644 index 000000000..b2501f1a2 --- /dev/null +++ b/src/test/ui/str/str-escape.stderr @@ -0,0 +1,21 @@ +warning: multiple lines skipped by escaped newline + --> $DIR/str-escape.rs:3:14 + | +LL | let s = "\ + | ______________^ +LL | | +LL | | "; + | |_____________^ skipping everything up to and including this point + +warning: non-ASCII whitespace symbol '\u{a0}' is not skipped + --> $DIR/str-escape.rs:7:17 + | +LL | let s = "foo\ + | _________________^ +LL | | bar + | | ^ non-ASCII whitespace symbol '\u{a0}' is not skipped + | |___| + | + +warning: 2 warnings emitted + diff --git a/src/test/ui/str/str-idx.rs b/src/test/ui/str/str-idx.rs new file mode 100644 index 000000000..1b32ed553 --- /dev/null +++ b/src/test/ui/str/str-idx.rs @@ -0,0 +1,7 @@ +pub fn main() { + let s: &str = "hello"; + let _: u8 = s[4]; //~ ERROR the type `str` cannot be indexed by `{integer}` + let _ = s.get(4); //~ ERROR the type `str` cannot be indexed by `{integer}` + let _ = s.get_unchecked(4); //~ ERROR the type `str` cannot be indexed by `{integer}` + let _: u8 = s['c']; //~ ERROR the type `str` cannot be indexed by `char` +} diff --git a/src/test/ui/str/str-idx.stderr b/src/test/ui/str/str-idx.stderr new file mode 100644 index 000000000..9079a18d6 --- /dev/null +++ b/src/test/ui/str/str-idx.stderr @@ -0,0 +1,60 @@ +error[E0277]: the type `str` cannot be indexed by `{integer}` + --> $DIR/str-idx.rs:3:19 + | +LL | let _: u8 = s[4]; + | ^ string indices are ranges of `usize` + | + = help: the trait `SliceIndex<str>` is not implemented for `{integer}` + = note: you can use `.chars().nth()` or `.bytes().nth()` + for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> + = help: the trait `SliceIndex<[T]>` is implemented for `usize` + = note: required because of the requirements on the impl of `Index<{integer}>` for `str` + +error[E0277]: the type `str` cannot be indexed by `{integer}` + --> $DIR/str-idx.rs:4:19 + | +LL | let _ = s.get(4); + | --- ^ string indices are ranges of `usize` + | | + | required by a bound introduced by this call + | + = help: the trait `SliceIndex<str>` is not implemented for `{integer}` + = note: you can use `.chars().nth()` or `.bytes().nth()` + for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> + = help: the trait `SliceIndex<[T]>` is implemented for `usize` +note: required by a bound in `core::str::<impl str>::get` + --> $SRC_DIR/core/src/str/mod.rs:LL:COL + | +LL | pub const fn get<I: ~const SliceIndex<str>>(&self, i: I) -> Option<&I::Output> { + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get` + +error[E0277]: the type `str` cannot be indexed by `{integer}` + --> $DIR/str-idx.rs:5:29 + | +LL | let _ = s.get_unchecked(4); + | ------------- ^ string indices are ranges of `usize` + | | + | required by a bound introduced by this call + | + = help: the trait `SliceIndex<str>` is not implemented for `{integer}` + = note: you can use `.chars().nth()` or `.bytes().nth()` + for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> + = help: the trait `SliceIndex<[T]>` is implemented for `usize` +note: required by a bound in `core::str::<impl str>::get_unchecked` + --> $SRC_DIR/core/src/str/mod.rs:LL:COL + | +LL | pub const unsafe fn get_unchecked<I: ~const SliceIndex<str>>(&self, i: I) -> &I::Output { + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked` + +error[E0277]: the type `str` cannot be indexed by `char` + --> $DIR/str-idx.rs:6:19 + | +LL | let _: u8 = s['c']; + | ^^^ string indices are ranges of `usize` + | + = help: the trait `SliceIndex<str>` is not implemented for `char` + = note: required because of the requirements on the impl of `Index<char>` for `str` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/str/str-lit-type-mismatch.rs b/src/test/ui/str/str-lit-type-mismatch.rs new file mode 100644 index 000000000..12637c7b9 --- /dev/null +++ b/src/test/ui/str/str-lit-type-mismatch.rs @@ -0,0 +1,5 @@ +fn main() { + let x: &[u8] = "foo"; //~ ERROR mismatched types + let y: &[u8; 4] = "baaa"; //~ ERROR mismatched types + let z: &str = b"foo"; //~ ERROR mismatched types +} diff --git a/src/test/ui/str/str-lit-type-mismatch.stderr b/src/test/ui/str/str-lit-type-mismatch.stderr new file mode 100644 index 000000000..6b56cd6f3 --- /dev/null +++ b/src/test/ui/str/str-lit-type-mismatch.stderr @@ -0,0 +1,49 @@ +error[E0308]: mismatched types + --> $DIR/str-lit-type-mismatch.rs:2:20 + | +LL | let x: &[u8] = "foo"; + | ----- ^^^^^ expected slice `[u8]`, found `str` + | | + | expected due to this + | + = note: expected reference `&[u8]` + found reference `&'static str` +help: consider adding a leading `b` + | +LL | let x: &[u8] = b"foo"; + | + + +error[E0308]: mismatched types + --> $DIR/str-lit-type-mismatch.rs:3:23 + | +LL | let y: &[u8; 4] = "baaa"; + | -------- ^^^^^^ expected array `[u8; 4]`, found `str` + | | + | expected due to this + | + = note: expected reference `&[u8; 4]` + found reference `&'static str` +help: consider adding a leading `b` + | +LL | let y: &[u8; 4] = b"baaa"; + | + + +error[E0308]: mismatched types + --> $DIR/str-lit-type-mismatch.rs:4:19 + | +LL | let z: &str = b"foo"; + | ---- ^^^^^^ expected `str`, found array `[u8; 3]` + | | + | expected due to this + | + = note: expected reference `&str` + found reference `&'static [u8; 3]` +help: consider removing the leading `b` + | +LL - let z: &str = b"foo"; +LL + let z: &str = "foo"; + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/str/str-mut-idx.rs b/src/test/ui/str/str-mut-idx.rs new file mode 100644 index 000000000..575a9eae8 --- /dev/null +++ b/src/test/ui/str/str-mut-idx.rs @@ -0,0 +1,17 @@ +fn bot<T>() -> T { loop {} } + +fn mutate(s: &mut str) { + s[1..2] = bot(); + //~^ ERROR the size for values of type + //~| ERROR the size for values of type + s[1usize] = bot(); + //~^ ERROR the type `str` cannot be indexed by `usize` + s.get_mut(1); + //~^ ERROR the type `str` cannot be indexed by `{integer}` + s.get_unchecked_mut(1); + //~^ ERROR the type `str` cannot be indexed by `{integer}` + s['c']; + //~^ ERROR the type `str` cannot be indexed by `char` +} + +pub fn main() {} diff --git a/src/test/ui/str/str-mut-idx.stderr b/src/test/ui/str/str-mut-idx.stderr new file mode 100644 index 000000000..2d062e56a --- /dev/null +++ b/src/test/ui/str/str-mut-idx.stderr @@ -0,0 +1,84 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/str-mut-idx.rs:4:15 + | +LL | s[1..2] = bot(); + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` +note: required by a bound in `bot` + --> $DIR/str-mut-idx.rs:1:8 + | +LL | fn bot<T>() -> T { loop {} } + | ^ required by this bound in `bot` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn bot<T: ?Sized>() -> T { loop {} } + | ++++++++ + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/str-mut-idx.rs:4:5 + | +LL | s[1..2] = bot(); + | ^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: the left-hand-side of an assignment must have a statically known size + +error[E0277]: the type `str` cannot be indexed by `usize` + --> $DIR/str-mut-idx.rs:7:7 + | +LL | s[1usize] = bot(); + | ^^^^^^ string indices are ranges of `usize` + | + = help: the trait `SliceIndex<str>` is not implemented for `usize` + = help: the trait `SliceIndex<[T]>` is implemented for `usize` + = note: required because of the requirements on the impl of `Index<usize>` for `str` + +error[E0277]: the type `str` cannot be indexed by `{integer}` + --> $DIR/str-mut-idx.rs:9:15 + | +LL | s.get_mut(1); + | ------- ^ string indices are ranges of `usize` + | | + | required by a bound introduced by this call + | + = help: the trait `SliceIndex<str>` is not implemented for `{integer}` + = note: you can use `.chars().nth()` or `.bytes().nth()` + for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> + = help: the trait `SliceIndex<[T]>` is implemented for `usize` +note: required by a bound in `core::str::<impl str>::get_mut` + --> $SRC_DIR/core/src/str/mod.rs:LL:COL + | +LL | pub const fn get_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> { + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_mut` + +error[E0277]: the type `str` cannot be indexed by `{integer}` + --> $DIR/str-mut-idx.rs:11:25 + | +LL | s.get_unchecked_mut(1); + | ----------------- ^ string indices are ranges of `usize` + | | + | required by a bound introduced by this call + | + = help: the trait `SliceIndex<str>` is not implemented for `{integer}` + = note: you can use `.chars().nth()` or `.bytes().nth()` + for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> + = help: the trait `SliceIndex<[T]>` is implemented for `usize` +note: required by a bound in `core::str::<impl str>::get_unchecked_mut` + --> $SRC_DIR/core/src/str/mod.rs:LL:COL + | +LL | pub const unsafe fn get_unchecked_mut<I: ~const SliceIndex<str>>( + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked_mut` + +error[E0277]: the type `str` cannot be indexed by `char` + --> $DIR/str-mut-idx.rs:13:7 + | +LL | s['c']; + | ^^^ string indices are ranges of `usize` + | + = help: the trait `SliceIndex<str>` is not implemented for `char` + = note: required because of the requirements on the impl of `Index<char>` for `str` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/str/str-overrun.rs b/src/test/ui/str/str-overrun.rs new file mode 100644 index 000000000..a3ec89413 --- /dev/null +++ b/src/test/ui/str/str-overrun.rs @@ -0,0 +1,10 @@ +// run-fail +// error-pattern:index out of bounds: the len is 5 but the index is 5 +// ignore-emscripten no processes + +fn main() { + let s: String = "hello".to_string(); + + // Bounds-check panic. + assert_eq!(s.as_bytes()[5], 0x0 as u8); +} diff --git a/src/test/ui/string-box-error.rs b/src/test/ui/string-box-error.rs new file mode 100644 index 000000000..11a5bd07c --- /dev/null +++ b/src/test/ui/string-box-error.rs @@ -0,0 +1,12 @@ +// run-pass +// Ensure that both `Box<dyn Error + Send + Sync>` and `Box<dyn Error>` can be +// obtained from `String`. + +use std::error::Error; + +fn main() { + let _err1: Box<dyn Error + Send + Sync> = From::from("test".to_string()); + let _err2: Box<dyn Error> = From::from("test".to_string()); + let _err3: Box<dyn Error + Send + Sync + 'static> = From::from("test"); + let _err4: Box<dyn Error> = From::from("test"); +} diff --git a/src/test/ui/struct-ctor-mangling.rs b/src/test/ui/struct-ctor-mangling.rs new file mode 100644 index 000000000..ba6abbf03 --- /dev/null +++ b/src/test/ui/struct-ctor-mangling.rs @@ -0,0 +1,14 @@ +// run-pass + +fn size_of_val<T>(_: &T) -> usize { + std::mem::size_of::<T>() +} + +struct Foo(#[allow(unused_tuple_struct_fields)] i64); + +// Test that the (symbol) mangling of `Foo` (the `struct` type) and that of +// `typeof Foo` (the function type of the `struct` constructor) don't collide. +fn main() { + size_of_val(&Foo(0)); + size_of_val(&Foo); +} diff --git a/src/test/ui/structs-enums/align-enum.rs b/src/test/ui/structs-enums/align-enum.rs new file mode 100644 index 000000000..fa872caa3 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/align-struct.rs b/src/test/ui/structs-enums/align-struct.rs new file mode 100644 index 000000000..27ef990aa --- /dev/null +++ b/src/test/ui/structs-enums/align-struct.rs @@ -0,0 +1,245 @@ +// run-pass +#![allow(dead_code)] +#![feature(box_syntax)] + +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 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/src/test/ui/structs-enums/auxiliary/cci_class.rs b/src/test/ui/structs-enums/auxiliary/cci_class.rs new file mode 100644 index 000000000..de2945d74 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/auxiliary/cci_class_2.rs b/src/test/ui/structs-enums/auxiliary/cci_class_2.rs new file mode 100644 index 000000000..c3de3150e --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/auxiliary/cci_class_3.rs b/src/test/ui/structs-enums/auxiliary/cci_class_3.rs new file mode 100644 index 000000000..fb7fad0b5 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/auxiliary/cci_class_4.rs b/src/test/ui/structs-enums/auxiliary/cci_class_4.rs new file mode 100644 index 000000000..85aa3bc8c --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/auxiliary/cci_class_6.rs b/src/test/ui/structs-enums/auxiliary/cci_class_6.rs new file mode 100644 index 000000000..35f93d0c6 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/auxiliary/cci_class_cast.rs b/src/test/ui/structs-enums/auxiliary/cci_class_cast.rs new file mode 100644 index 000000000..dfc3c56dd --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/auxiliary/cci_class_trait.rs b/src/test/ui/structs-enums/auxiliary/cci_class_trait.rs new file mode 100644 index 000000000..2d02b591c --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/auxiliary/empty-struct.rs b/src/test/ui/structs-enums/auxiliary/empty-struct.rs new file mode 100644 index 000000000..93275e714 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/auxiliary/namespaced_enum_emulate_flat.rs b/src/test/ui/structs-enums/auxiliary/namespaced_enum_emulate_flat.rs new file mode 100644 index 000000000..55e6b34ac --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/auxiliary/namespaced_enums.rs b/src/test/ui/structs-enums/auxiliary/namespaced_enums.rs new file mode 100644 index 000000000..d3548c76c --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/auxiliary/newtype_struct_xc.rs b/src/test/ui/structs-enums/auxiliary/newtype_struct_xc.rs new file mode 100644 index 000000000..9d1e0742e --- /dev/null +++ b/src/test/ui/structs-enums/auxiliary/newtype_struct_xc.rs @@ -0,0 +1,3 @@ +#![crate_type="lib"] + +pub struct Au(pub isize); diff --git a/src/test/ui/structs-enums/auxiliary/struct_destructuring_cross_crate.rs b/src/test/ui/structs-enums/auxiliary/struct_destructuring_cross_crate.rs new file mode 100644 index 000000000..3665ae7e8 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/auxiliary/struct_variant_xc_aux.rs b/src/test/ui/structs-enums/auxiliary/struct_variant_xc_aux.rs new file mode 100644 index 000000000..e919df611 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/auxiliary/xcrate_struct_aliases.rs b/src/test/ui/structs-enums/auxiliary/xcrate_struct_aliases.rs new file mode 100644 index 000000000..bc8879aa3 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/borrow-tuple-fields.rs b/src/test/ui/structs-enums/borrow-tuple-fields.rs new file mode 100644 index 000000000..b1d8f9164 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs b/src/test/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs new file mode 100644 index 000000000..f870096fd --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-cast-to-trait-multiple-types.rs b/src/test/ui/structs-enums/class-cast-to-trait-multiple-types.rs new file mode 100644 index 000000000..ca35a615d --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-cast-to-trait.rs b/src/test/ui/structs-enums/class-cast-to-trait.rs new file mode 100644 index 000000000..1019bb300 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-dtor.rs b/src/test/ui/structs-enums/class-dtor.rs new file mode 100644 index 000000000..583a5e240 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-exports.rs b/src/test/ui/structs-enums/class-exports.rs new file mode 100644 index 000000000..ee20887cb --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-impl-very-parameterized-trait.rs b/src/test/ui/structs-enums/class-impl-very-parameterized-trait.rs new file mode 100644 index 000000000..5e7830296 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-implement-trait-cross-crate.rs b/src/test/ui/structs-enums/class-implement-trait-cross-crate.rs new file mode 100644 index 000000000..31b795175 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-implement-traits.rs b/src/test/ui/structs-enums/class-implement-traits.rs new file mode 100644 index 000000000..732aa146c --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-method-cross-crate.rs b/src/test/ui/structs-enums/class-method-cross-crate.rs new file mode 100644 index 000000000..519f0685f --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-methods-cross-crate.rs b/src/test/ui/structs-enums/class-methods-cross-crate.rs new file mode 100644 index 000000000..c342af313 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-methods.rs b/src/test/ui/structs-enums/class-methods.rs new file mode 100644 index 000000000..83f4a5fd3 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-poly-methods-cross-crate.rs b/src/test/ui/structs-enums/class-poly-methods-cross-crate.rs new file mode 100644 index 000000000..0307ba78d --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-poly-methods.rs b/src/test/ui/structs-enums/class-poly-methods.rs new file mode 100644 index 000000000..da2870b58 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-separate-impl.rs b/src/test/ui/structs-enums/class-separate-impl.rs new file mode 100644 index 000000000..3d6da1cc2 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-str-field.rs b/src/test/ui/structs-enums/class-str-field.rs new file mode 100644 index 000000000..a3dc66aab --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/class-typarams.rs b/src/test/ui/structs-enums/class-typarams.rs new file mode 100644 index 000000000..4b2d4b12e --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/classes-cross-crate.rs b/src/test/ui/structs-enums/classes-cross-crate.rs new file mode 100644 index 000000000..ca362c7a7 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/classes-self-referential.rs b/src/test/ui/structs-enums/classes-self-referential.rs new file mode 100644 index 000000000..27d6ebf2c --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/classes-simple-cross-crate.rs b/src/test/ui/structs-enums/classes-simple-cross-crate.rs new file mode 100644 index 000000000..6ff0970c0 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/classes-simple-method.rs b/src/test/ui/structs-enums/classes-simple-method.rs new file mode 100644 index 000000000..f3d98337d --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/classes-simple.rs b/src/test/ui/structs-enums/classes-simple.rs new file mode 100644 index 000000000..568fbb29f --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/classes.rs b/src/test/ui/structs-enums/classes.rs new file mode 100644 index 000000000..51d84b909 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/codegen-tag-static-padding.rs b/src/test/ui/structs-enums/codegen-tag-static-padding.rs new file mode 100644 index 000000000..8aa087c01 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/compare-generic-enums.rs b/src/test/ui/structs-enums/compare-generic-enums.rs new file mode 100644 index 000000000..84f953b1f --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/cross-crate-newtype-struct-pat.rs b/src/test/ui/structs-enums/cross-crate-newtype-struct-pat.rs new file mode 100644 index 000000000..eabffc161 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/discrim-explicit-23030.rs b/src/test/ui/structs-enums/discrim-explicit-23030.rs new file mode 100644 index 000000000..e17025e9e --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/empty-struct-braces.rs b/src/test/ui/structs-enums/empty-struct-braces.rs new file mode 100644 index 000000000..0663687c9 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/empty-tag.rs b/src/test/ui/structs-enums/empty-tag.rs new file mode 100644 index 000000000..271ab72c7 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-alignment.rs b/src/test/ui/structs-enums/enum-alignment.rs new file mode 100644 index 000000000..108dfe2e6 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-clike-ffi-as-int.rs b/src/test/ui/structs-enums/enum-clike-ffi-as-int.rs new file mode 100644 index 000000000..e2b2b43de --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-discr.rs b/src/test/ui/structs-enums/enum-discr.rs new file mode 100644 index 000000000..bdd6df82d --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-discrim-autosizing.rs b/src/test/ui/structs-enums/enum-discrim-autosizing.rs new file mode 100644 index 000000000..f68fdda60 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-discrim-manual-sizing.rs b/src/test/ui/structs-enums/enum-discrim-manual-sizing.rs new file mode 100644 index 000000000..c8b362c99 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-discrim-range-overflow.rs b/src/test/ui/structs-enums/enum-discrim-range-overflow.rs new file mode 100644 index 000000000..9c4c61e68 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-discrim-width-stuff.rs b/src/test/ui/structs-enums/enum-discrim-width-stuff.rs new file mode 100644 index 000000000..f278ae2d0 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-disr-val-pretty.rs b/src/test/ui/structs-enums/enum-disr-val-pretty.rs new file mode 100644 index 000000000..ef1333e0e --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-export-inheritance.rs b/src/test/ui/structs-enums/enum-export-inheritance.rs new file mode 100644 index 000000000..6a36a004a --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-layout-optimization.rs b/src/test/ui/structs-enums/enum-layout-optimization.rs new file mode 100644 index 000000000..05d297906 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-non-c-like-repr-c-and-int.rs b/src/test/ui/structs-enums/enum-non-c-like-repr-c-and-int.rs new file mode 100644 index 000000000..7d15d607d --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-non-c-like-repr-c.rs b/src/test/ui/structs-enums/enum-non-c-like-repr-c.rs new file mode 100644 index 000000000..fc9efdeca --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-non-c-like-repr-int.rs b/src/test/ui/structs-enums/enum-non-c-like-repr-int.rs new file mode 100644 index 000000000..f9e96c1a0 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-null-pointer-opt.rs b/src/test/ui/structs-enums/enum-null-pointer-opt.rs new file mode 100644 index 000000000..85fa1eac2 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-nullable-const-null-with-fields.rs b/src/test/ui/structs-enums/enum-nullable-const-null-with-fields.rs new file mode 100644 index 000000000..ae267e798 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs b/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs new file mode 100644 index 000000000..a05cf8b93 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-univariant-repr.rs b/src/test/ui/structs-enums/enum-univariant-repr.rs new file mode 100644 index 000000000..1e0f67887 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-variants.rs b/src/test/ui/structs-enums/enum-variants.rs new file mode 100644 index 000000000..9ac5aae72 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/enum-vec-initializer.rs b/src/test/ui/structs-enums/enum-vec-initializer.rs new file mode 100644 index 000000000..42ee8ba97 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/export-abstract-tag.rs b/src/test/ui/structs-enums/export-abstract-tag.rs new file mode 100644 index 000000000..76ac73321 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/export-tag-variant.rs b/src/test/ui/structs-enums/export-tag-variant.rs new file mode 100644 index 000000000..52e0aba09 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/expr-if-struct.rs b/src/test/ui/structs-enums/expr-if-struct.rs new file mode 100644 index 000000000..e62d47c6f --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/expr-match-struct.rs b/src/test/ui/structs-enums/expr-match-struct.rs new file mode 100644 index 000000000..f0e8d8972 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/field-destruction-order.rs b/src/test/ui/structs-enums/field-destruction-order.rs new file mode 100644 index 000000000..a75a742d9 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/foreign-struct.rs b/src/test/ui/structs-enums/foreign-struct.rs new file mode 100644 index 000000000..00a23b354 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/functional-struct-upd.rs b/src/test/ui/structs-enums/functional-struct-upd.rs new file mode 100644 index 000000000..68ff73a08 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/issue-1701.rs b/src/test/ui/structs-enums/issue-1701.rs new file mode 100644 index 000000000..bae32a777 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/issue-38002.rs b/src/test/ui/structs-enums/issue-38002.rs new file mode 100644 index 000000000..fdb31fc44 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/issue-50731.rs b/src/test/ui/structs-enums/issue-50731.rs new file mode 100644 index 000000000..209c1e127 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/ivec-tag.rs b/src/test/ui/structs-enums/ivec-tag.rs new file mode 100644 index 000000000..c39368a2b --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/module-qualified-struct-destructure.rs b/src/test/ui/structs-enums/module-qualified-struct-destructure.rs new file mode 100644 index 000000000..57be37cdf --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/multiple-reprs.rs b/src/test/ui/structs-enums/multiple-reprs.rs new file mode 100644 index 000000000..4be503a0e --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/namespaced-enum-emulate-flat-xc.rs b/src/test/ui/structs-enums/namespaced-enum-emulate-flat-xc.rs new file mode 100644 index 000000000..30cf64582 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/namespaced-enum-emulate-flat.rs b/src/test/ui/structs-enums/namespaced-enum-emulate-flat.rs new file mode 100644 index 000000000..f6c395059 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/namespaced-enum-glob-import-xcrate.rs b/src/test/ui/structs-enums/namespaced-enum-glob-import-xcrate.rs new file mode 100644 index 000000000..d2ccadea0 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/namespaced-enum-glob-import.rs b/src/test/ui/structs-enums/namespaced-enum-glob-import.rs new file mode 100644 index 000000000..f36ac69dc --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/namespaced-enums-xcrate.rs b/src/test/ui/structs-enums/namespaced-enums-xcrate.rs new file mode 100644 index 000000000..5e10c3ec1 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/namespaced-enums.rs b/src/test/ui/structs-enums/namespaced-enums.rs new file mode 100644 index 000000000..6a2602501 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/nested-enum-same-names.rs b/src/test/ui/structs-enums/nested-enum-same-names.rs new file mode 100644 index 000000000..111b9ba94 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/newtype-struct-drop-run.rs b/src/test/ui/structs-enums/newtype-struct-drop-run.rs new file mode 100644 index 000000000..0754f3187 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/newtype-struct-with-dtor.rs b/src/test/ui/structs-enums/newtype-struct-with-dtor.rs new file mode 100644 index 000000000..f73b492df --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/newtype-struct-xc-2.rs b/src/test/ui/structs-enums/newtype-struct-xc-2.rs new file mode 100644 index 000000000..40837321b --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/newtype-struct-xc.rs b/src/test/ui/structs-enums/newtype-struct-xc.rs new file mode 100644 index 000000000..0c6466d97 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/nonzero-enum.rs b/src/test/ui/structs-enums/nonzero-enum.rs new file mode 100644 index 000000000..15b571be5 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/numeric-fields.rs b/src/test/ui/structs-enums/numeric-fields.rs new file mode 100644 index 000000000..6ff3afc38 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/rec-align-u32.rs b/src/test/ui/structs-enums/rec-align-u32.rs new file mode 100644 index 000000000..889294daa --- /dev/null +++ b/src/test/ui/structs-enums/rec-align-u32.rs @@ -0,0 +1,56 @@ +// 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; + 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/src/test/ui/structs-enums/rec-align-u64.rs b/src/test/ui/structs-enums/rec-align-u64.rs new file mode 100644 index 000000000..3bc2d16cf --- /dev/null +++ b/src/test/ui/structs-enums/rec-align-u64.rs @@ -0,0 +1,96 @@ +// 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; + 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/src/test/ui/structs-enums/rec-auto.rs b/src/test/ui/structs-enums/rec-auto.rs new file mode 100644 index 000000000..c2ef13ede --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/rec-extend.rs b/src/test/ui/structs-enums/rec-extend.rs new file mode 100644 index 000000000..4c91cd185 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/rec-tup.rs b/src/test/ui/structs-enums/rec-tup.rs new file mode 100644 index 000000000..b85d28fdf --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/rec.rs b/src/test/ui/structs-enums/rec.rs new file mode 100644 index 000000000..82c84ebd6 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/record-pat.rs b/src/test/ui/structs-enums/record-pat.rs new file mode 100644 index 000000000..1acaf2a32 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/resource-in-struct.rs b/src/test/ui/structs-enums/resource-in-struct.rs new file mode 100644 index 000000000..9613ca62a --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/simple-generic-tag.rs b/src/test/ui/structs-enums/simple-generic-tag.rs new file mode 100644 index 000000000..dbd2834d4 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/simple-match-generic-tag.rs b/src/test/ui/structs-enums/simple-match-generic-tag.rs new file mode 100644 index 000000000..762fd49ad --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/small-enum-range-edge.rs b/src/test/ui/structs-enums/small-enum-range-edge.rs new file mode 100644 index 000000000..306129479 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/small-enums-with-fields.rs b/src/test/ui/structs-enums/small-enums-with-fields.rs new file mode 100644 index 000000000..565ec1bd4 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-aliases-xcrate.rs b/src/test/ui/structs-enums/struct-aliases-xcrate.rs new file mode 100644 index 000000000..ffe7b22f8 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-aliases.rs b/src/test/ui/structs-enums/struct-aliases.rs new file mode 100644 index 000000000..b7aeed7bc --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-destructuring-cross-crate.rs b/src/test/ui/structs-enums/struct-destructuring-cross-crate.rs new file mode 100644 index 000000000..19e0a0bbd --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs b/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs new file mode 100644 index 000000000..c30b8a1e1 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr b/src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr new file mode 100644 index 000000000..16f751444 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-field-shorthand.rs b/src/test/ui/structs-enums/struct-field-shorthand.rs new file mode 100644 index 000000000..ed650c683 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-like-variant-construct.rs b/src/test/ui/structs-enums/struct-like-variant-construct.rs new file mode 100644 index 000000000..60fc7ce39 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-like-variant-match.rs b/src/test/ui/structs-enums/struct-like-variant-match.rs new file mode 100644 index 000000000..ade1a6970 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-lit-functional-no-fields.rs b/src/test/ui/structs-enums/struct-lit-functional-no-fields.rs new file mode 100644 index 000000000..f19604e95 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-literal-dtor.rs b/src/test/ui/structs-enums/struct-literal-dtor.rs new file mode 100644 index 000000000..6d1b1dfb9 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-new-as-field-name.rs b/src/test/ui/structs-enums/struct-new-as-field-name.rs new file mode 100644 index 000000000..641fc3c58 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-order-of-eval-1.rs b/src/test/ui/structs-enums/struct-order-of-eval-1.rs new file mode 100644 index 000000000..f3fe99538 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-order-of-eval-2.rs b/src/test/ui/structs-enums/struct-order-of-eval-2.rs new file mode 100644 index 000000000..a4e0edc97 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-order-of-eval-3.rs b/src/test/ui/structs-enums/struct-order-of-eval-3.rs new file mode 100644 index 000000000..60887f8d0 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-order-of-eval-4.rs b/src/test/ui/structs-enums/struct-order-of-eval-4.rs new file mode 100644 index 000000000..547df6318 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-partial-move-1.rs b/src/test/ui/structs-enums/struct-partial-move-1.rs new file mode 100644 index 000000000..c15701593 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-partial-move-2.rs b/src/test/ui/structs-enums/struct-partial-move-2.rs new file mode 100644 index 000000000..4315e5c29 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-path-associated-type.rs b/src/test/ui/structs-enums/struct-path-associated-type.rs new file mode 100644 index 000000000..2235dfe4b --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-path-self.rs b/src/test/ui/structs-enums/struct-path-self.rs new file mode 100644 index 000000000..e7a59858f --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-pattern-matching.rs b/src/test/ui/structs-enums/struct-pattern-matching.rs new file mode 100644 index 000000000..89361bf24 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-rec/issue-74224.rs b/src/test/ui/structs-enums/struct-rec/issue-74224.rs new file mode 100644 index 000000000..f3b72c5df --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-rec/issue-74224.stderr b/src/test/ui/structs-enums/struct-rec/issue-74224.stderr new file mode 100644 index 000000000..619917846 --- /dev/null +++ b/src/test/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> { + | ^^^^^^^^^^^ recursive type has infinite size +... +LL | y: A<A<T>>, + | ------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `A` representable + | +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/src/test/ui/structs-enums/struct-rec/issue-84611.rs b/src/test/ui/structs-enums/struct-rec/issue-84611.rs new file mode 100644 index 000000000..4c356af3e --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct-rec/issue-84611.stderr b/src/test/ui/structs-enums/struct-rec/issue-84611.stderr new file mode 100644 index 000000000..2e99435e0 --- /dev/null +++ b/src/test/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> { + | ^^^^^^^^^^^^^ recursive type has infinite size +LL | +LL | x: Foo<[T; 1]>, + | ----------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable + | +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/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.rs b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.rs new file mode 100644 index 000000000..cca97f43e --- /dev/null +++ b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.rs @@ -0,0 +1,23 @@ +struct A<T> { +//~^ ERROR recursive type `A` has infinite size + x: T, + y: B<T>, +} + +struct B<T> { +//~^ ERROR recursive type `B` has infinite size + z: A<T> +} + +struct C<T> { +//~^ ERROR recursive type `C` has infinite size + x: T, + y: Option<Option<D<T>>>, +} + +struct D<T> { +//~^ ERROR recursive type `D` has infinite size + z: Option<Option<C<T>>>, +} + +fn main() {} diff --git a/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr new file mode 100644 index 000000000..80a494f3f --- /dev/null +++ b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr @@ -0,0 +1,59 @@ +error[E0072]: recursive type `A` has infinite size + --> $DIR/mutual-struct-recursion.rs:1:1 + | +LL | struct A<T> { + | ^^^^^^^^^^^ recursive type has infinite size +... +LL | y: B<T>, + | ---- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `A` representable + | +LL | y: Box<B<T>>, + | ++++ + + +error[E0072]: recursive type `B` has infinite size + --> $DIR/mutual-struct-recursion.rs:7:1 + | +LL | struct B<T> { + | ^^^^^^^^^^^ recursive type has infinite size +LL | +LL | z: A<T> + | ---- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `B` representable + | +LL | z: Box<A<T>> + | ++++ + + +error[E0072]: recursive type `C` has infinite size + --> $DIR/mutual-struct-recursion.rs:12:1 + | +LL | struct C<T> { + | ^^^^^^^^^^^ recursive type has infinite size +... +LL | y: Option<Option<D<T>>>, + | -------------------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `C` representable + | +LL | y: Option<Box<Option<D<T>>>>, + | ++++ + + +error[E0072]: recursive type `D` has infinite size + --> $DIR/mutual-struct-recursion.rs:18:1 + | +LL | struct D<T> { + | ^^^^^^^^^^^ recursive type has infinite size +LL | +LL | z: Option<Option<C<T>>>, + | -------------------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `D` representable + | +LL | z: Option<Box<Option<C<T>>>>, + | ++++ + + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/structs-enums/struct-variant-field-visibility.rs b/src/test/ui/structs-enums/struct-variant-field-visibility.rs new file mode 100644 index 000000000..7896c829a --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct_variant_xc.rs b/src/test/ui/structs-enums/struct_variant_xc.rs new file mode 100644 index 000000000..9c8d1a69a --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/struct_variant_xc_match.rs b/src/test/ui/structs-enums/struct_variant_xc_match.rs new file mode 100644 index 000000000..5358d13fa --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tag-align-dyn-u64.rs b/src/test/ui/structs-enums/tag-align-dyn-u64.rs new file mode 100644 index 000000000..3f7a5e3e5 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tag-align-dyn-variants.rs b/src/test/ui/structs-enums/tag-align-dyn-variants.rs new file mode 100644 index 000000000..4d075b04c --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tag-align-shape.rs b/src/test/ui/structs-enums/tag-align-shape.rs new file mode 100644 index 000000000..ce5995823 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tag-align-u64.rs b/src/test/ui/structs-enums/tag-align-u64.rs new file mode 100644 index 000000000..684b27cd0 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tag-disr-val-shape.rs b/src/test/ui/structs-enums/tag-disr-val-shape.rs new file mode 100644 index 000000000..51052626c --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tag-exports.rs b/src/test/ui/structs-enums/tag-exports.rs new file mode 100644 index 000000000..1bcb7d35d --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tag-in-block.rs b/src/test/ui/structs-enums/tag-in-block.rs new file mode 100644 index 000000000..03d4dd9b0 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tag-variant-disr-type-mismatch.rs b/src/test/ui/structs-enums/tag-variant-disr-type-mismatch.rs new file mode 100644 index 000000000..3f59db383 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tag-variant-disr-val.rs b/src/test/ui/structs-enums/tag-variant-disr-val.rs new file mode 100644 index 000000000..297d85c58 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tag.rs b/src/test/ui/structs-enums/tag.rs new file mode 100644 index 000000000..5fcd64b7c --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tuple-struct-construct.rs b/src/test/ui/structs-enums/tuple-struct-construct.rs new file mode 100644 index 000000000..fbf97e6b2 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tuple-struct-constructor-pointer.rs b/src/test/ui/structs-enums/tuple-struct-constructor-pointer.rs new file mode 100644 index 000000000..23f065163 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tuple-struct-destructuring.rs b/src/test/ui/structs-enums/tuple-struct-destructuring.rs new file mode 100644 index 000000000..dff87ead0 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tuple-struct-matching.rs b/src/test/ui/structs-enums/tuple-struct-matching.rs new file mode 100644 index 000000000..432be1d1f --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/tuple-struct-trivial.rs b/src/test/ui/structs-enums/tuple-struct-trivial.rs new file mode 100644 index 000000000..c8651fd29 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/type-sizes.rs b/src/test/ui/structs-enums/type-sizes.rs new file mode 100644 index 000000000..73a11a5e7 --- /dev/null +++ b/src/test/ui/structs-enums/type-sizes.rs @@ -0,0 +1,173 @@ +// run-pass + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(never_type)] + +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 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); +} diff --git a/src/test/ui/structs-enums/uninstantiable-struct.rs b/src/test/ui/structs-enums/uninstantiable-struct.rs new file mode 100644 index 000000000..b24effe5a --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/unit-like-struct-drop-run.rs b/src/test/ui/structs-enums/unit-like-struct-drop-run.rs new file mode 100644 index 000000000..1e9c269a4 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/unit-like-struct.rs b/src/test/ui/structs-enums/unit-like-struct.rs new file mode 100644 index 000000000..636ec9926 --- /dev/null +++ b/src/test/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/src/test/ui/structs-enums/variant-structs-trivial.rs b/src/test/ui/structs-enums/variant-structs-trivial.rs new file mode 100644 index 000000000..31fa610a6 --- /dev/null +++ b/src/test/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() { } diff --git a/src/test/ui/structs/auxiliary/struct_field_privacy.rs b/src/test/ui/structs/auxiliary/struct_field_privacy.rs new file mode 100644 index 000000000..9765af1a7 --- /dev/null +++ b/src/test/ui/structs/auxiliary/struct_field_privacy.rs @@ -0,0 +1,9 @@ +pub struct A { + a: isize, + pub b: isize, +} + +pub struct B { + pub a: isize, + b: isize, +} diff --git a/src/test/ui/structs/auxiliary/struct_variant_privacy.rs b/src/test/ui/structs/auxiliary/struct_variant_privacy.rs new file mode 100644 index 000000000..425ec0e96 --- /dev/null +++ b/src/test/ui/structs/auxiliary/struct_variant_privacy.rs @@ -0,0 +1,3 @@ +enum Bar { + Baz { a: isize } +} diff --git a/src/test/ui/structs/issue-80853.rs b/src/test/ui/structs/issue-80853.rs new file mode 100644 index 000000000..242d0af95 --- /dev/null +++ b/src/test/ui/structs/issue-80853.rs @@ -0,0 +1,7 @@ +struct S; + +fn repro_ref(thing: S) { + thing(); //~ ERROR expected function, found `S` +} + +fn main() {} diff --git a/src/test/ui/structs/issue-80853.stderr b/src/test/ui/structs/issue-80853.stderr new file mode 100644 index 000000000..1c7d52b6d --- /dev/null +++ b/src/test/ui/structs/issue-80853.stderr @@ -0,0 +1,13 @@ +error[E0618]: expected function, found `S` + --> $DIR/issue-80853.rs:4:5 + | +LL | fn repro_ref(thing: S) { + | ----- `thing` has type `S` +LL | thing(); + | ^^^^^-- + | | + | call expression requires function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0618`. diff --git a/src/test/ui/structs/large-records.rs b/src/test/ui/structs/large-records.rs new file mode 100644 index 000000000..7f850a94e --- /dev/null +++ b/src/test/ui/structs/large-records.rs @@ -0,0 +1,38 @@ +// run-pass + +#![allow(dead_code)] + + + + +// pretty-expanded FIXME #23616 + +struct Large {a: isize, + b: isize, + c: isize, + d: isize, + e: isize, + f: isize, + g: isize, + h: isize, + i: isize, + j: isize, + k: isize, + l: isize} +fn f() { + let _foo: Large = + Large {a: 0, + b: 0, + c: 0, + d: 0, + e: 0, + f: 0, + g: 0, + h: 0, + i: 0, + j: 0, + k: 0, + l: 0}; +} + +pub fn main() { f(); } diff --git a/src/test/ui/structs/rhs-type.rs b/src/test/ui/structs/rhs-type.rs new file mode 100644 index 000000000..c48e7c08e --- /dev/null +++ b/src/test/ui/structs/rhs-type.rs @@ -0,0 +1,18 @@ +// Tests that codegen treats the rhs of pth's decl +// as a _|_-typed thing, not a str-typed thing + +// run-fail +// error-pattern:bye +// ignore-emscripten no processes + +#![allow(unreachable_code)] +#![allow(unused_variables)] + +struct T { + t: String, +} + +fn main() { + let pth = panic!("bye"); + let _rs: T = T { t: pth }; +} diff --git a/src/test/ui/structs/struct-base-wrong-type.rs b/src/test/ui/structs/struct-base-wrong-type.rs new file mode 100644 index 000000000..b64c6b499 --- /dev/null +++ b/src/test/ui/structs/struct-base-wrong-type.rs @@ -0,0 +1,14 @@ +// Check that `base` in `Fru { field: expr, ..base }` must have right type. + +struct Foo { a: isize, b: isize } +struct Bar { x: isize } + +static bar: Bar = Bar { x: 5 }; +static foo: Foo = Foo { a: 2, ..bar }; //~ ERROR mismatched types +static foo_i: Foo = Foo { a: 2, ..4 }; //~ ERROR mismatched types + +fn main() { + let b = Bar { x: 5 }; + let f = Foo { a: 2, ..b }; //~ ERROR mismatched types + let f__isize = Foo { a: 2, ..4 }; //~ ERROR mismatched types +} diff --git a/src/test/ui/structs/struct-base-wrong-type.stderr b/src/test/ui/structs/struct-base-wrong-type.stderr new file mode 100644 index 000000000..b039ce2cc --- /dev/null +++ b/src/test/ui/structs/struct-base-wrong-type.stderr @@ -0,0 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/struct-base-wrong-type.rs:7:33 + | +LL | static foo: Foo = Foo { a: 2, ..bar }; + | ^^^ expected struct `Foo`, found struct `Bar` + +error[E0308]: mismatched types + --> $DIR/struct-base-wrong-type.rs:8:35 + | +LL | static foo_i: Foo = Foo { a: 2, ..4 }; + | ^ expected struct `Foo`, found integer + +error[E0308]: mismatched types + --> $DIR/struct-base-wrong-type.rs:12:27 + | +LL | let f = Foo { a: 2, ..b }; + | ^ expected struct `Foo`, found struct `Bar` + +error[E0308]: mismatched types + --> $DIR/struct-base-wrong-type.rs:13:34 + | +LL | let f__isize = Foo { a: 2, ..4 }; + | ^ expected struct `Foo`, found integer + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/structs/struct-duplicate-comma.fixed b/src/test/ui/structs/struct-duplicate-comma.fixed new file mode 100644 index 000000000..c804cf57a --- /dev/null +++ b/src/test/ui/structs/struct-duplicate-comma.fixed @@ -0,0 +1,15 @@ +// run-rustfix +// Issue #50974 + +pub struct Foo { + pub a: u8, + pub b: u8 +} + +fn main() { + let _ = Foo { + a: 0, + //~^ ERROR expected identifier + b: 42 + }; +} diff --git a/src/test/ui/structs/struct-duplicate-comma.rs b/src/test/ui/structs/struct-duplicate-comma.rs new file mode 100644 index 000000000..db2e7cb3d --- /dev/null +++ b/src/test/ui/structs/struct-duplicate-comma.rs @@ -0,0 +1,15 @@ +// run-rustfix +// Issue #50974 + +pub struct Foo { + pub a: u8, + pub b: u8 +} + +fn main() { + let _ = Foo { + a: 0,, + //~^ ERROR expected identifier + b: 42 + }; +} diff --git a/src/test/ui/structs/struct-duplicate-comma.stderr b/src/test/ui/structs/struct-duplicate-comma.stderr new file mode 100644 index 000000000..834b3c5c1 --- /dev/null +++ b/src/test/ui/structs/struct-duplicate-comma.stderr @@ -0,0 +1,13 @@ +error: expected identifier, found `,` + --> $DIR/struct-duplicate-comma.rs:11:14 + | +LL | let _ = Foo { + | --- while parsing this struct +LL | a: 0,, + | ^ + | | + | expected identifier + | help: remove this comma + +error: aborting due to previous error + diff --git a/src/test/ui/structs/struct-field-cfg.rs b/src/test/ui/structs/struct-field-cfg.rs new file mode 100644 index 000000000..42cab8ab9 --- /dev/null +++ b/src/test/ui/structs/struct-field-cfg.rs @@ -0,0 +1,18 @@ +struct Foo { + present: (), +} + +fn main() { + let foo = Foo { #[cfg(all())] present: () }; + let _ = Foo { #[cfg(any())] present: () }; + //~^ ERROR missing field `present` in initializer of `Foo` + let _ = Foo { present: (), #[cfg(any())] absent: () }; + let _ = Foo { present: (), #[cfg(all())] absent: () }; + //~^ ERROR struct `Foo` has no field named `absent` + let Foo { #[cfg(all())] present: () } = foo; + let Foo { #[cfg(any())] present: () } = foo; + //~^ ERROR pattern does not mention field `present` + let Foo { present: (), #[cfg(any())] absent: () } = foo; + let Foo { present: (), #[cfg(all())] absent: () } = foo; + //~^ ERROR struct `Foo` does not have a field named `absent` +} diff --git a/src/test/ui/structs/struct-field-cfg.stderr b/src/test/ui/structs/struct-field-cfg.stderr new file mode 100644 index 000000000..5ec47c093 --- /dev/null +++ b/src/test/ui/structs/struct-field-cfg.stderr @@ -0,0 +1,39 @@ +error[E0063]: missing field `present` in initializer of `Foo` + --> $DIR/struct-field-cfg.rs:7:13 + | +LL | let _ = Foo { #[cfg(any())] present: () }; + | ^^^ missing `present` + +error[E0560]: struct `Foo` has no field named `absent` + --> $DIR/struct-field-cfg.rs:10:46 + | +LL | let _ = Foo { present: (), #[cfg(all())] absent: () }; + | ^^^^^^ `Foo` does not have this field + | + = note: available fields are: `present` + +error[E0027]: pattern does not mention field `present` + --> $DIR/struct-field-cfg.rs:13:9 + | +LL | let Foo { #[cfg(any())] present: () } = foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `present` + | +help: include the missing field in the pattern + | +LL | let Foo { present } = foo; + | ~~~~~~~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | let Foo { .. } = foo; + | ~~~~~~ + +error[E0026]: struct `Foo` does not have a field named `absent` + --> $DIR/struct-field-cfg.rs:16:42 + | +LL | let Foo { present: (), #[cfg(all())] absent: () } = foo; + | ^^^^^^ struct `Foo` does not have this field + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0026, E0027, E0063, E0560. +For more information about an error, try `rustc --explain E0026`. diff --git a/src/test/ui/structs/struct-field-init-syntax.rs b/src/test/ui/structs/struct-field-init-syntax.rs new file mode 100644 index 000000000..161f7e93a --- /dev/null +++ b/src/test/ui/structs/struct-field-init-syntax.rs @@ -0,0 +1,20 @@ +// issue #41834 + +#[derive(Default)] +struct Foo { + one: u8, +} + +fn main() { + let foo = Foo { + one: 111, + ..Foo::default(), + //~^ ERROR cannot use a comma after the base struct + }; + + let foo = Foo { + ..Foo::default(), + //~^ ERROR cannot use a comma after the base struct + one: 111, + }; +} diff --git a/src/test/ui/structs/struct-field-init-syntax.stderr b/src/test/ui/structs/struct-field-init-syntax.stderr new file mode 100644 index 000000000..0b72c5cf7 --- /dev/null +++ b/src/test/ui/structs/struct-field-init-syntax.stderr @@ -0,0 +1,18 @@ +error: cannot use a comma after the base struct + --> $DIR/struct-field-init-syntax.rs:11:9 + | +LL | ..Foo::default(), + | ^^^^^^^^^^^^^^^^- help: remove this comma + | + = note: the base struct must always be the last field + +error: cannot use a comma after the base struct + --> $DIR/struct-field-init-syntax.rs:16:9 + | +LL | ..Foo::default(), + | ^^^^^^^^^^^^^^^^- help: remove this comma + | + = note: the base struct must always be the last field + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/structs/struct-field-privacy.rs b/src/test/ui/structs/struct-field-privacy.rs new file mode 100644 index 000000000..898ca475c --- /dev/null +++ b/src/test/ui/structs/struct-field-privacy.rs @@ -0,0 +1,38 @@ +// aux-build:struct_field_privacy.rs + +extern crate struct_field_privacy as xc; + +struct A { + a: isize, +} + +mod inner { + pub struct A { + a: isize, + pub b: isize, + } + pub struct B { + pub a: isize, + b: isize, + } + pub struct Z(pub isize, isize); +} + +fn test(a: A, b: inner::A, c: inner::B, d: xc::A, e: xc::B, z: inner::Z) { + a.a; + b.a; //~ ERROR: field `a` of struct `inner::A` is private + b.b; + c.a; + c.b; //~ ERROR: field `b` of struct `inner::B` is private + + d.a; //~ ERROR: field `a` of struct `xc::A` is private + d.b; + + e.a; + e.b; //~ ERROR: field `b` of struct `xc::B` is private + + z.0; + z.1; //~ ERROR: field `1` of struct `Z` is private +} + +fn main() {} diff --git a/src/test/ui/structs/struct-field-privacy.stderr b/src/test/ui/structs/struct-field-privacy.stderr new file mode 100644 index 000000000..ee83e0d6c --- /dev/null +++ b/src/test/ui/structs/struct-field-privacy.stderr @@ -0,0 +1,33 @@ +error[E0616]: field `a` of struct `inner::A` is private + --> $DIR/struct-field-privacy.rs:23:7 + | +LL | b.a; + | ^ private field + +error[E0616]: field `b` of struct `inner::B` is private + --> $DIR/struct-field-privacy.rs:26:7 + | +LL | c.b; + | ^ private field + +error[E0616]: field `a` of struct `xc::A` is private + --> $DIR/struct-field-privacy.rs:28:7 + | +LL | d.a; + | ^ private field + +error[E0616]: field `b` of struct `xc::B` is private + --> $DIR/struct-field-privacy.rs:32:7 + | +LL | e.b; + | ^ private field + +error[E0616]: field `1` of struct `Z` is private + --> $DIR/struct-field-privacy.rs:35:7 + | +LL | z.1; + | ^ private field + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0616`. diff --git a/src/test/ui/structs/struct-fields-decl-dupe.rs b/src/test/ui/structs/struct-fields-decl-dupe.rs new file mode 100644 index 000000000..6ddf3d976 --- /dev/null +++ b/src/test/ui/structs/struct-fields-decl-dupe.rs @@ -0,0 +1,8 @@ +struct BuildData { + foo: isize, + foo: isize, + //~^ ERROR field `foo` is already declared [E0124] +} + +fn main() { +} diff --git a/src/test/ui/structs/struct-fields-decl-dupe.stderr b/src/test/ui/structs/struct-fields-decl-dupe.stderr new file mode 100644 index 000000000..d7ce9bb89 --- /dev/null +++ b/src/test/ui/structs/struct-fields-decl-dupe.stderr @@ -0,0 +1,11 @@ +error[E0124]: field `foo` is already declared + --> $DIR/struct-fields-decl-dupe.rs:3:5 + | +LL | foo: isize, + | ---------- `foo` first declared here +LL | foo: isize, + | ^^^^^^^^^^ field already declared + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0124`. diff --git a/src/test/ui/structs/struct-fields-dupe.rs b/src/test/ui/structs/struct-fields-dupe.rs new file mode 100644 index 000000000..2fa25a335 --- /dev/null +++ b/src/test/ui/structs/struct-fields-dupe.rs @@ -0,0 +1,10 @@ +struct BuildData { + foo: isize, +} + +fn main() { + let foo = BuildData { + foo: 0, + foo: 0 //~ ERROR field `foo` specified more than once + }; +} diff --git a/src/test/ui/structs/struct-fields-dupe.stderr b/src/test/ui/structs/struct-fields-dupe.stderr new file mode 100644 index 000000000..aaf2533dc --- /dev/null +++ b/src/test/ui/structs/struct-fields-dupe.stderr @@ -0,0 +1,11 @@ +error[E0062]: field `foo` specified more than once + --> $DIR/struct-fields-dupe.rs:8:9 + | +LL | foo: 0, + | ------ first use of `foo` +LL | foo: 0 + | ^^^ used more than once + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0062`. diff --git a/src/test/ui/structs/struct-fields-hints-no-dupe.rs b/src/test/ui/structs/struct-fields-hints-no-dupe.rs new file mode 100644 index 000000000..987cf726f --- /dev/null +++ b/src/test/ui/structs/struct-fields-hints-no-dupe.rs @@ -0,0 +1,14 @@ +struct A { + foo : i32, + car : i32, + barr : i32 +} + +fn main() { + let a = A { + foo : 5, + bar : 42, + //~^ ERROR struct `A` has no field named `bar` + car : 9, + }; +} diff --git a/src/test/ui/structs/struct-fields-hints-no-dupe.stderr b/src/test/ui/structs/struct-fields-hints-no-dupe.stderr new file mode 100644 index 000000000..1a88f2693 --- /dev/null +++ b/src/test/ui/structs/struct-fields-hints-no-dupe.stderr @@ -0,0 +1,9 @@ +error[E0560]: struct `A` has no field named `bar` + --> $DIR/struct-fields-hints-no-dupe.rs:10:9 + | +LL | bar : 42, + | ^^^ help: a field with a similar name exists: `barr` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0560`. diff --git a/src/test/ui/structs/struct-fields-hints.rs b/src/test/ui/structs/struct-fields-hints.rs new file mode 100644 index 000000000..08df0930e --- /dev/null +++ b/src/test/ui/structs/struct-fields-hints.rs @@ -0,0 +1,13 @@ +struct A { + foo : i32, + car : i32, + barr : i32 +} + +fn main() { + let a = A { + foo : 5, + bar : 42, + //~^ ERROR struct `A` has no field named `bar` + }; +} diff --git a/src/test/ui/structs/struct-fields-hints.stderr b/src/test/ui/structs/struct-fields-hints.stderr new file mode 100644 index 000000000..3b8a2b5c7 --- /dev/null +++ b/src/test/ui/structs/struct-fields-hints.stderr @@ -0,0 +1,9 @@ +error[E0560]: struct `A` has no field named `bar` + --> $DIR/struct-fields-hints.rs:10:9 + | +LL | bar : 42, + | ^^^ help: a field with a similar name exists: `car` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0560`. diff --git a/src/test/ui/structs/struct-fields-missing.rs b/src/test/ui/structs/struct-fields-missing.rs new file mode 100644 index 000000000..0c7919d02 --- /dev/null +++ b/src/test/ui/structs/struct-fields-missing.rs @@ -0,0 +1,10 @@ +struct BuildData { + foo: isize, + bar: Box<isize>, +} + +fn main() { + let foo = BuildData { //~ ERROR missing field `bar` in initializer of `BuildData` + foo: 0 + }; +} diff --git a/src/test/ui/structs/struct-fields-missing.stderr b/src/test/ui/structs/struct-fields-missing.stderr new file mode 100644 index 000000000..b3e42a948 --- /dev/null +++ b/src/test/ui/structs/struct-fields-missing.stderr @@ -0,0 +1,9 @@ +error[E0063]: missing field `bar` in initializer of `BuildData` + --> $DIR/struct-fields-missing.rs:7:15 + | +LL | let foo = BuildData { + | ^^^^^^^^^ missing `bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0063`. diff --git a/src/test/ui/structs/struct-fields-shorthand-unresolved.rs b/src/test/ui/structs/struct-fields-shorthand-unresolved.rs new file mode 100644 index 000000000..caad14916 --- /dev/null +++ b/src/test/ui/structs/struct-fields-shorthand-unresolved.rs @@ -0,0 +1,12 @@ +struct Foo { + x: i32, + y: i32 +} + +fn main() { + let x = 0; + let foo = Foo { + x, + y //~ ERROR cannot find value `y` in this scope + }; +} diff --git a/src/test/ui/structs/struct-fields-shorthand-unresolved.stderr b/src/test/ui/structs/struct-fields-shorthand-unresolved.stderr new file mode 100644 index 000000000..09fc4f7ee --- /dev/null +++ b/src/test/ui/structs/struct-fields-shorthand-unresolved.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `y` in this scope + --> $DIR/struct-fields-shorthand-unresolved.rs:10:9 + | +LL | y + | ^ help: a local variable with a similar name exists: `x` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/structs/struct-fields-shorthand.rs b/src/test/ui/structs/struct-fields-shorthand.rs new file mode 100644 index 000000000..1bdcc8315 --- /dev/null +++ b/src/test/ui/structs/struct-fields-shorthand.rs @@ -0,0 +1,11 @@ +struct Foo { + x: i32, + y: i32 +} + +fn main() { + let (x, y, z) = (0, 1, 2); + let foo = Foo { + x, y, z //~ ERROR struct `Foo` has no field named `z` + }; +} diff --git a/src/test/ui/structs/struct-fields-shorthand.stderr b/src/test/ui/structs/struct-fields-shorthand.stderr new file mode 100644 index 000000000..a285a3921 --- /dev/null +++ b/src/test/ui/structs/struct-fields-shorthand.stderr @@ -0,0 +1,11 @@ +error[E0560]: struct `Foo` has no field named `z` + --> $DIR/struct-fields-shorthand.rs:9:15 + | +LL | x, y, z + | ^ `Foo` does not have this field + | + = note: available fields are: `x`, `y` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0560`. diff --git a/src/test/ui/structs/struct-fields-too-many.rs b/src/test/ui/structs/struct-fields-too-many.rs new file mode 100644 index 000000000..8be8dcbf1 --- /dev/null +++ b/src/test/ui/structs/struct-fields-too-many.rs @@ -0,0 +1,11 @@ +struct BuildData { + foo: isize, +} + +fn main() { + let foo = BuildData { + foo: 0, + bar: 0 + //~^ ERROR struct `BuildData` has no field named `bar` + }; +} diff --git a/src/test/ui/structs/struct-fields-too-many.stderr b/src/test/ui/structs/struct-fields-too-many.stderr new file mode 100644 index 000000000..a1b7a7a31 --- /dev/null +++ b/src/test/ui/structs/struct-fields-too-many.stderr @@ -0,0 +1,11 @@ +error[E0560]: struct `BuildData` has no field named `bar` + --> $DIR/struct-fields-too-many.rs:8:9 + | +LL | bar: 0 + | ^^^ `BuildData` does not have this field + | + = note: available fields are: `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0560`. diff --git a/src/test/ui/structs/struct-fields-typo.rs b/src/test/ui/structs/struct-fields-typo.rs new file mode 100644 index 000000000..0e9b2ae51 --- /dev/null +++ b/src/test/ui/structs/struct-fields-typo.rs @@ -0,0 +1,15 @@ +struct BuildData { + foo: isize, + bar: f32 +} + +fn main() { + let foo = BuildData { + foo: 0, + bar: 0.5, + }; + let x = foo.baa; //~ ERROR no field `baa` on type `BuildData` + //~| HELP a field with a similar name exists + //~| SUGGESTION bar + println!("{}", x); +} diff --git a/src/test/ui/structs/struct-fields-typo.stderr b/src/test/ui/structs/struct-fields-typo.stderr new file mode 100644 index 000000000..6949a0a4a --- /dev/null +++ b/src/test/ui/structs/struct-fields-typo.stderr @@ -0,0 +1,9 @@ +error[E0609]: no field `baa` on type `BuildData` + --> $DIR/struct-fields-typo.rs:11:17 + | +LL | let x = foo.baa; + | ^^^ help: a field with a similar name exists: `bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/ui/structs/struct-fn-in-definition.rs b/src/test/ui/structs/struct-fn-in-definition.rs new file mode 100644 index 000000000..5ae1b727d --- /dev/null +++ b/src/test/ui/structs/struct-fn-in-definition.rs @@ -0,0 +1,33 @@ +// It might be intuitive for a user coming from languages like Java +// to declare a method directly in a struct's definition. Make sure +// rustc can give a helpful suggestion. +// Suggested in issue #76421 + +struct S { + field: usize, + + fn foo() {} + //~^ ERROR functions are not allowed in struct definitions + //~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks + //~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information +} + +union U { + variant: usize, + + fn foo() {} + //~^ ERROR functions are not allowed in union definitions + //~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks + //~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information +} + +enum E { + Variant, + + fn foo() {} + //~^ ERROR functions are not allowed in enum definitions + //~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks + //~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information +} + +fn main() {} diff --git a/src/test/ui/structs/struct-fn-in-definition.stderr b/src/test/ui/structs/struct-fn-in-definition.stderr new file mode 100644 index 000000000..1d7cd5272 --- /dev/null +++ b/src/test/ui/structs/struct-fn-in-definition.stderr @@ -0,0 +1,29 @@ +error: functions are not allowed in struct definitions + --> $DIR/struct-fn-in-definition.rs:9:5 + | +LL | fn foo() {} + | ^^^^^^^^^^^ + | + = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks + = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information + +error: functions are not allowed in union definitions + --> $DIR/struct-fn-in-definition.rs:18:5 + | +LL | fn foo() {} + | ^^^^^^^^^^^ + | + = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks + = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information + +error: functions are not allowed in enum definitions + --> $DIR/struct-fn-in-definition.rs:27:5 + | +LL | fn foo() {} + | ^^^^^^^^^^^ + | + = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks + = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/structs/struct-missing-comma.fixed b/src/test/ui/structs/struct-missing-comma.fixed new file mode 100644 index 000000000..a28179ba2 --- /dev/null +++ b/src/test/ui/structs/struct-missing-comma.fixed @@ -0,0 +1,12 @@ +// Issue #50636 +// run-rustfix + +pub struct S { + pub foo: u32, //~ expected `,`, or `}`, found keyword `pub` + // ~^ HELP try adding a comma: ',' + pub bar: u32 +} + +fn main() { + let _ = S { foo: 5, bar: 6 }; +} diff --git a/src/test/ui/structs/struct-missing-comma.rs b/src/test/ui/structs/struct-missing-comma.rs new file mode 100644 index 000000000..b6d6c9b8f --- /dev/null +++ b/src/test/ui/structs/struct-missing-comma.rs @@ -0,0 +1,12 @@ +// Issue #50636 +// run-rustfix + +pub struct S { + pub foo: u32 //~ expected `,`, or `}`, found keyword `pub` + // ~^ HELP try adding a comma: ',' + pub bar: u32 +} + +fn main() { + let _ = S { foo: 5, bar: 6 }; +} diff --git a/src/test/ui/structs/struct-missing-comma.stderr b/src/test/ui/structs/struct-missing-comma.stderr new file mode 100644 index 000000000..eceec65e7 --- /dev/null +++ b/src/test/ui/structs/struct-missing-comma.stderr @@ -0,0 +1,8 @@ +error: expected `,`, or `}`, found keyword `pub` + --> $DIR/struct-missing-comma.rs:5:17 + | +LL | pub foo: u32 + | ^ help: try adding a comma: `,` + +error: aborting due to previous error + diff --git a/src/test/ui/structs/struct-pat-derived-error.rs b/src/test/ui/structs/struct-pat-derived-error.rs new file mode 100644 index 000000000..f49a8ff8b --- /dev/null +++ b/src/test/ui/structs/struct-pat-derived-error.rs @@ -0,0 +1,14 @@ +struct A { + b: usize, + c: usize +} + +impl A { + fn foo(&self) { + let A { x, y } = self.d; //~ ERROR no field `d` on type `&A` + //~^ ERROR struct `A` does not have fields named `x`, `y` + //~| ERROR pattern does not mention fields `b`, `c` + } +} + +fn main() {} diff --git a/src/test/ui/structs/struct-pat-derived-error.stderr b/src/test/ui/structs/struct-pat-derived-error.stderr new file mode 100644 index 000000000..a91e47657 --- /dev/null +++ b/src/test/ui/structs/struct-pat-derived-error.stderr @@ -0,0 +1,31 @@ +error[E0609]: no field `d` on type `&A` + --> $DIR/struct-pat-derived-error.rs:8:31 + | +LL | let A { x, y } = self.d; + | ^ help: a field with a similar name exists: `b` + +error[E0026]: struct `A` does not have fields named `x`, `y` + --> $DIR/struct-pat-derived-error.rs:8:17 + | +LL | let A { x, y } = self.d; + | ^ ^ struct `A` does not have these fields + +error[E0027]: pattern does not mention fields `b`, `c` + --> $DIR/struct-pat-derived-error.rs:8:13 + | +LL | let A { x, y } = self.d; + | ^^^^^^^^^^ missing fields `b`, `c` + | +help: include the missing fields in the pattern + | +LL | let A { x, y, b, c } = self.d; + | ~~~~~~~~ +help: if you don't care about these missing fields, you can explicitly ignore them + | +LL | let A { x, y, .. } = self.d; + | ~~~~~~ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0026, E0027, E0609. +For more information about an error, try `rustc --explain E0026`. diff --git a/src/test/ui/structs/struct-path-alias-bounds.rs b/src/test/ui/structs/struct-path-alias-bounds.rs new file mode 100644 index 000000000..1e2c4b836 --- /dev/null +++ b/src/test/ui/structs/struct-path-alias-bounds.rs @@ -0,0 +1,11 @@ +// issue #36286 + +struct S<T: Clone> { a: T } + +struct NoClone; +type A = S<NoClone>; + +fn main() { + let s = A { a: NoClone }; + //~^ ERROR the trait bound `NoClone: Clone` is not satisfied +} diff --git a/src/test/ui/structs/struct-path-alias-bounds.stderr b/src/test/ui/structs/struct-path-alias-bounds.stderr new file mode 100644 index 000000000..266291f62 --- /dev/null +++ b/src/test/ui/structs/struct-path-alias-bounds.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `NoClone: Clone` is not satisfied + --> $DIR/struct-path-alias-bounds.rs:9:13 + | +LL | let s = A { a: NoClone }; + | ^ the trait `Clone` is not implemented for `NoClone` + | +note: required by a bound in `S` + --> $DIR/struct-path-alias-bounds.rs:3:13 + | +LL | struct S<T: Clone> { a: T } + | ^^^^^ required by this bound in `S` +help: consider annotating `NoClone` with `#[derive(Clone)]` + | +LL | #[derive(Clone)] + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/structs/struct-path-associated-type.rs b/src/test/ui/structs/struct-path-associated-type.rs new file mode 100644 index 000000000..f88572f84 --- /dev/null +++ b/src/test/ui/structs/struct-path-associated-type.rs @@ -0,0 +1,37 @@ +struct S; + +trait Tr { + type A; +} + +impl Tr for S { + type A = S; +} + +fn f<T: Tr>() { + let s = T::A {}; + //~^ ERROR expected struct, variant or union type, found associated type + let z = T::A::<u8> {}; + //~^ ERROR expected struct, variant or union type, found associated type + //~| ERROR type arguments are not allowed on this type + match S { + T::A {} => {} + //~^ ERROR expected struct, variant or union type, found associated type + } +} + +fn g<T: Tr<A = S>>() { + let s = T::A {}; // OK + let z = T::A::<u8> {}; //~ ERROR type arguments are not allowed on this type + match S { + T::A {} => {} // OK + } +} + +fn main() { + let s = S::A {}; //~ ERROR ambiguous associated type + let z = S::A::<u8> {}; //~ ERROR ambiguous associated type + match S { + S::A {} => {} //~ ERROR ambiguous associated type + } +} diff --git a/src/test/ui/structs/struct-path-associated-type.stderr b/src/test/ui/structs/struct-path-associated-type.stderr new file mode 100644 index 000000000..bdce0e1b3 --- /dev/null +++ b/src/test/ui/structs/struct-path-associated-type.stderr @@ -0,0 +1,56 @@ +error[E0071]: expected struct, variant or union type, found associated type + --> $DIR/struct-path-associated-type.rs:12:13 + | +LL | let s = T::A {}; + | ^^^^ not a struct + +error[E0109]: type arguments are not allowed on this type + --> $DIR/struct-path-associated-type.rs:14:20 + | +LL | let z = T::A::<u8> {}; + | - ^^ type argument not allowed + | | + | not allowed on this type + +error[E0071]: expected struct, variant or union type, found associated type + --> $DIR/struct-path-associated-type.rs:14:13 + | +LL | let z = T::A::<u8> {}; + | ^^^^ not a struct + +error[E0071]: expected struct, variant or union type, found associated type + --> $DIR/struct-path-associated-type.rs:18:9 + | +LL | T::A {} => {} + | ^^^^ not a struct + +error[E0109]: type arguments are not allowed on this type + --> $DIR/struct-path-associated-type.rs:25:20 + | +LL | let z = T::A::<u8> {}; + | - ^^ type argument not allowed + | | + | not allowed on this type + +error[E0223]: ambiguous associated type + --> $DIR/struct-path-associated-type.rs:32:13 + | +LL | let s = S::A {}; + | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A` + +error[E0223]: ambiguous associated type + --> $DIR/struct-path-associated-type.rs:33:13 + | +LL | let z = S::A::<u8> {}; + | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A` + +error[E0223]: ambiguous associated type + --> $DIR/struct-path-associated-type.rs:35:9 + | +LL | S::A {} => {} + | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0071, E0109, E0223. +For more information about an error, try `rustc --explain E0071`. diff --git a/src/test/ui/structs/struct-path-self-type-mismatch.rs b/src/test/ui/structs/struct-path-self-type-mismatch.rs new file mode 100644 index 000000000..c0c557eca --- /dev/null +++ b/src/test/ui/structs/struct-path-self-type-mismatch.rs @@ -0,0 +1,21 @@ +struct Foo<A> { inner: A } + +trait Bar { fn bar(); } + +impl Bar for Foo<i32> { + fn bar() { + Self { inner: 1.5f32 }; //~ ERROR mismatched types + } +} + +impl<T> Foo<T> { + fn new<U>(u: U) -> Foo<U> { + Self { + //~^ ERROR mismatched types + inner: u + //~^ ERROR mismatched types + } + } +} + +fn main() {} diff --git a/src/test/ui/structs/struct-path-self-type-mismatch.stderr b/src/test/ui/structs/struct-path-self-type-mismatch.stderr new file mode 100644 index 000000000..b55a2cbf7 --- /dev/null +++ b/src/test/ui/structs/struct-path-self-type-mismatch.stderr @@ -0,0 +1,46 @@ +error[E0308]: mismatched types + --> $DIR/struct-path-self-type-mismatch.rs:7:23 + | +LL | Self { inner: 1.5f32 }; + | ^^^^^^ expected `i32`, found `f32` + +error[E0308]: mismatched types + --> $DIR/struct-path-self-type-mismatch.rs:15:20 + | +LL | impl<T> Foo<T> { + | - expected type parameter +LL | fn new<U>(u: U) -> Foo<U> { + | - found type parameter +... +LL | inner: u + | ^ expected type parameter `T`, found type parameter `U` + | + = note: expected type parameter `T` + found type parameter `U` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error[E0308]: mismatched types + --> $DIR/struct-path-self-type-mismatch.rs:13:9 + | +LL | impl<T> Foo<T> { + | - found type parameter +LL | fn new<U>(u: U) -> Foo<U> { + | - ------ expected `Foo<U>` because of return type + | | + | expected type parameter +LL | / Self { +LL | | +LL | | inner: u +LL | | +LL | | } + | |_________^ expected type parameter `U`, found type parameter `T` + | + = note: expected struct `Foo<U>` + found struct `Foo<T>` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/structs/struct-path-self.rs b/src/test/ui/structs/struct-path-self.rs new file mode 100644 index 000000000..6e529c7ed --- /dev/null +++ b/src/test/ui/structs/struct-path-self.rs @@ -0,0 +1,37 @@ +struct S; + +trait Tr { + fn f() { + let s = Self {}; + //~^ ERROR expected struct, variant or union type, found type parameter + let z = Self::<u8> {}; + //~^ ERROR expected struct, variant or union type, found type parameter + //~| ERROR type arguments are not allowed on self type + match s { + Self { .. } => {} + //~^ ERROR expected struct, variant or union type, found type parameter + } + } +} + +impl Tr for S { + fn f() { + let s = Self {}; // OK + let z = Self::<u8> {}; //~ ERROR type arguments are not allowed on self type + match s { + Self { .. } => {} // OK + } + } +} + +impl S { + fn g() { + let s = Self {}; // OK + let z = Self::<u8> {}; //~ ERROR type arguments are not allowed on self type + match s { + Self { .. } => {} // OK + } + } +} + +fn main() {} diff --git a/src/test/ui/structs/struct-path-self.stderr b/src/test/ui/structs/struct-path-self.stderr new file mode 100644 index 000000000..c2a8623f9 --- /dev/null +++ b/src/test/ui/structs/struct-path-self.stderr @@ -0,0 +1,80 @@ +error[E0071]: expected struct, variant or union type, found type parameter `Self` + --> $DIR/struct-path-self.rs:5:17 + | +LL | let s = Self {}; + | ^^^^ not a struct + +error[E0109]: type arguments are not allowed on self type + --> $DIR/struct-path-self.rs:7:24 + | +LL | let z = Self::<u8> {}; + | ---- ^^ type argument not allowed + | | + | not allowed on self type + | +help: the `Self` type doesn't accept type parameters + | +LL - let z = Self::<u8> {}; +LL + let z = Self {}; + | + +error[E0071]: expected struct, variant or union type, found type parameter `Self` + --> $DIR/struct-path-self.rs:7:17 + | +LL | let z = Self::<u8> {}; + | ^^^^^^^^^^ not a struct + +error[E0071]: expected struct, variant or union type, found type parameter `Self` + --> $DIR/struct-path-self.rs:11:13 + | +LL | Self { .. } => {} + | ^^^^ not a struct + +error[E0109]: type arguments are not allowed on self type + --> $DIR/struct-path-self.rs:20:24 + | +LL | let z = Self::<u8> {}; + | ---- ^^ type argument not allowed + | | + | not allowed on self type + | +note: `Self` is of type `S` + --> $DIR/struct-path-self.rs:1:8 + | +LL | struct S; + | ^ `Self` corresponds to this type, which doesn't have generic parameters +... +LL | impl Tr for S { + | ------------- `Self` is on type `S` in this `impl` +help: the `Self` type doesn't accept type parameters + | +LL - let z = Self::<u8> {}; +LL + let z = Self {}; + | + +error[E0109]: type arguments are not allowed on self type + --> $DIR/struct-path-self.rs:30:24 + | +LL | let z = Self::<u8> {}; + | ---- ^^ type argument not allowed + | | + | not allowed on self type + | +note: `Self` is of type `S` + --> $DIR/struct-path-self.rs:1:8 + | +LL | struct S; + | ^ `Self` corresponds to this type, which doesn't have generic parameters +... +LL | impl S { + | ------ `Self` is on type `S` in this `impl` +help: the `Self` type doesn't accept type parameters + | +LL - let z = Self::<u8> {}; +LL + let z = Self {}; + | + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0071, E0109. +For more information about an error, try `rustc --explain E0071`. diff --git a/src/test/ui/structs/struct-record-suggestion.fixed b/src/test/ui/structs/struct-record-suggestion.fixed new file mode 100644 index 000000000..48144cd1c --- /dev/null +++ b/src/test/ui/structs/struct-record-suggestion.fixed @@ -0,0 +1,16 @@ +// run-rustfix +#[derive(Debug, Default, Eq, PartialEq)] +struct A { + b: u32, + c: u64, + d: usize, +} + +fn main() { + let q = A { c: 5, .. Default::default() }; + //~^ ERROR mismatched types + //~| ERROR missing fields + //~| HELP separate the last named field with a comma + let r = A { c: 5, .. Default::default() }; + assert_eq!(q, r); +} diff --git a/src/test/ui/structs/struct-record-suggestion.rs b/src/test/ui/structs/struct-record-suggestion.rs new file mode 100644 index 000000000..6d169d5c6 --- /dev/null +++ b/src/test/ui/structs/struct-record-suggestion.rs @@ -0,0 +1,16 @@ +// run-rustfix +#[derive(Debug, Default, Eq, PartialEq)] +struct A { + b: u32, + c: u64, + d: usize, +} + +fn main() { + let q = A { c: 5 .. Default::default() }; + //~^ ERROR mismatched types + //~| ERROR missing fields + //~| HELP separate the last named field with a comma + let r = A { c: 5, .. Default::default() }; + assert_eq!(q, r); +} diff --git a/src/test/ui/structs/struct-record-suggestion.stderr b/src/test/ui/structs/struct-record-suggestion.stderr new file mode 100644 index 000000000..e5bd03117 --- /dev/null +++ b/src/test/ui/structs/struct-record-suggestion.stderr @@ -0,0 +1,24 @@ +error[E0308]: mismatched types + --> $DIR/struct-record-suggestion.rs:10:20 + | +LL | let q = A { c: 5 .. Default::default() }; + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found struct `std::ops::Range` + | + = note: expected type `u64` + found struct `std::ops::Range<{integer}>` + +error[E0063]: missing fields `b` and `d` in initializer of `A` + --> $DIR/struct-record-suggestion.rs:10:13 + | +LL | let q = A { c: 5 .. Default::default() }; + | ^ missing `b` and `d` + | +help: to set the remaining fields from `Default::default()`, separate the last named field with a comma + | +LL | let q = A { c: 5, .. Default::default() }; + | + + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0063, E0308. +For more information about an error, try `rustc --explain E0063`. diff --git a/src/test/ui/structs/struct-tuple-field-names.rs b/src/test/ui/structs/struct-tuple-field-names.rs new file mode 100644 index 000000000..7bd54af1d --- /dev/null +++ b/src/test/ui/structs/struct-tuple-field-names.rs @@ -0,0 +1,15 @@ +struct S(i32, f32); +enum E { + S(i32, f32), +} +fn main() { + let x = E::S(1, 2.2); + match x { + E::S { 0, 1 } => {} + //~^ ERROR tuple variant `E::S` written as struct variant [E0769] + } + let y = S(1, 2.2); + match y { + S { } => {} //~ ERROR: tuple variant `S` written as struct variant [E0769] + } +} diff --git a/src/test/ui/structs/struct-tuple-field-names.stderr b/src/test/ui/structs/struct-tuple-field-names.stderr new file mode 100644 index 000000000..5494c29a6 --- /dev/null +++ b/src/test/ui/structs/struct-tuple-field-names.stderr @@ -0,0 +1,25 @@ +error[E0769]: tuple variant `E::S` written as struct variant + --> $DIR/struct-tuple-field-names.rs:8:9 + | +LL | E::S { 0, 1 } => {} + | ^^^^^^^^^^^^^ + | +help: use the tuple variant pattern syntax instead + | +LL | E::S(_, _) => {} + | ~~~~~~ + +error[E0769]: tuple variant `S` written as struct variant + --> $DIR/struct-tuple-field-names.rs:13:9 + | +LL | S { } => {} + | ^^^^^ + | +help: use the tuple variant pattern syntax instead + | +LL | S(_, _) => {} + | ~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0769`. diff --git a/src/test/ui/structs/struct-variant-privacy-xc.rs b/src/test/ui/structs/struct-variant-privacy-xc.rs new file mode 100644 index 000000000..763ab9527 --- /dev/null +++ b/src/test/ui/structs/struct-variant-privacy-xc.rs @@ -0,0 +1,11 @@ +// aux-build:struct_variant_privacy.rs +extern crate struct_variant_privacy; + +fn f(b: struct_variant_privacy::Bar) { + //~^ ERROR enum `Bar` is private + match b { + struct_variant_privacy::Bar::Baz { a: _a } => {} //~ ERROR enum `Bar` is private + } +} + +fn main() {} diff --git a/src/test/ui/structs/struct-variant-privacy-xc.stderr b/src/test/ui/structs/struct-variant-privacy-xc.stderr new file mode 100644 index 000000000..1c1caaef8 --- /dev/null +++ b/src/test/ui/structs/struct-variant-privacy-xc.stderr @@ -0,0 +1,27 @@ +error[E0603]: enum `Bar` is private + --> $DIR/struct-variant-privacy-xc.rs:4:33 + | +LL | fn f(b: struct_variant_privacy::Bar) { + | ^^^ private enum + | +note: the enum `Bar` is defined here + --> $DIR/auxiliary/struct_variant_privacy.rs:1:1 + | +LL | enum Bar { + | ^^^^^^^^ + +error[E0603]: enum `Bar` is private + --> $DIR/struct-variant-privacy-xc.rs:7:33 + | +LL | struct_variant_privacy::Bar::Baz { a: _a } => {} + | ^^^ private enum + | +note: the enum `Bar` is defined here + --> $DIR/auxiliary/struct_variant_privacy.rs:1:1 + | +LL | enum Bar { + | ^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/src/test/ui/structs/struct-variant-privacy.rs b/src/test/ui/structs/struct-variant-privacy.rs new file mode 100644 index 000000000..fcdf9a22b --- /dev/null +++ b/src/test/ui/structs/struct-variant-privacy.rs @@ -0,0 +1,14 @@ +mod foo { + enum Bar { + Baz { a: isize }, + } +} + +fn f(b: foo::Bar) { + //~^ ERROR enum `Bar` is private + match b { + foo::Bar::Baz { a: _a } => {} //~ ERROR enum `Bar` is private + } +} + +fn main() {} diff --git a/src/test/ui/structs/struct-variant-privacy.stderr b/src/test/ui/structs/struct-variant-privacy.stderr new file mode 100644 index 000000000..eafd26c71 --- /dev/null +++ b/src/test/ui/structs/struct-variant-privacy.stderr @@ -0,0 +1,27 @@ +error[E0603]: enum `Bar` is private + --> $DIR/struct-variant-privacy.rs:7:14 + | +LL | fn f(b: foo::Bar) { + | ^^^ private enum + | +note: the enum `Bar` is defined here + --> $DIR/struct-variant-privacy.rs:2:5 + | +LL | enum Bar { + | ^^^^^^^^ + +error[E0603]: enum `Bar` is private + --> $DIR/struct-variant-privacy.rs:10:14 + | +LL | foo::Bar::Baz { a: _a } => {} + | ^^^ private enum + | +note: the enum `Bar` is defined here + --> $DIR/struct-variant-privacy.rs:2:5 + | +LL | enum Bar { + | ^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/src/test/ui/structs/structure-constructor-type-mismatch.rs b/src/test/ui/structs/structure-constructor-type-mismatch.rs new file mode 100644 index 000000000..a03ef590c --- /dev/null +++ b/src/test/ui/structs/structure-constructor-type-mismatch.rs @@ -0,0 +1,73 @@ +struct Point<T> { + x: T, + y: T, +} + +type PointF = Point<f32>; + +struct Pair<T,U> { + x: T, + y: U, +} + +type PairF<U> = Pair<f32,U>; + +fn main() { + let pt = PointF { + x: 1, + //~^ ERROR mismatched types + //~| expected `f32`, found integer + y: 2, + //~^ ERROR mismatched types + //~| expected `f32`, found integer + }; + + let pt2 = Point::<f32> { + x: 3, + //~^ ERROR mismatched types + //~| expected `f32`, found integer + y: 4, + //~^ ERROR mismatched types + //~| expected `f32`, found integer + }; + + let pair = PairF { + x: 5, + //~^ ERROR mismatched types + //~| expected `f32`, found integer + y: 6, + }; + + let pair2 = PairF::<i32> { + x: 7, + //~^ ERROR mismatched types + //~| expected `f32`, found integer + y: 8, + }; + + let pt3 = PointF::<i32> { //~ ERROR this type alias takes 0 generic arguments but 1 generic argument + x: 9, //~ ERROR mismatched types + y: 10, //~ ERROR mismatched types + }; + + match (Point { x: 1, y: 2 }) { + PointF::<u32> { .. } => {} //~ ERROR this type alias takes 0 generic arguments but 1 generic argument + //~^ ERROR mismatched types + } + + match (Point { x: 1, y: 2 }) { + PointF { .. } => {} //~ ERROR mismatched types + } + + match (Point { x: 1.0, y: 2.0 }) { + PointF { .. } => {} // ok + } + + match (Pair { x: 1, y: 2 }) { + PairF::<u32> { .. } => {} //~ ERROR mismatched types + } + + match (Pair { x: 1.0, y: 2 }) { + PairF::<u32> { .. } => {} // ok + } +} diff --git a/src/test/ui/structs/structure-constructor-type-mismatch.stderr b/src/test/ui/structs/structure-constructor-type-mismatch.stderr new file mode 100644 index 000000000..3d64fc601 --- /dev/null +++ b/src/test/ui/structs/structure-constructor-type-mismatch.stderr @@ -0,0 +1,137 @@ +error[E0308]: mismatched types + --> $DIR/structure-constructor-type-mismatch.rs:17:12 + | +LL | x: 1, + | ^ + | | + | expected `f32`, found integer + | help: use a float literal: `1.0` + +error[E0308]: mismatched types + --> $DIR/structure-constructor-type-mismatch.rs:20:12 + | +LL | y: 2, + | ^ + | | + | expected `f32`, found integer + | help: use a float literal: `2.0` + +error[E0308]: mismatched types + --> $DIR/structure-constructor-type-mismatch.rs:26:12 + | +LL | x: 3, + | ^ + | | + | expected `f32`, found integer + | help: use a float literal: `3.0` + +error[E0308]: mismatched types + --> $DIR/structure-constructor-type-mismatch.rs:29:12 + | +LL | y: 4, + | ^ + | | + | expected `f32`, found integer + | help: use a float literal: `4.0` + +error[E0308]: mismatched types + --> $DIR/structure-constructor-type-mismatch.rs:35:12 + | +LL | x: 5, + | ^ + | | + | expected `f32`, found integer + | help: use a float literal: `5.0` + +error[E0308]: mismatched types + --> $DIR/structure-constructor-type-mismatch.rs:42:12 + | +LL | x: 7, + | ^ + | | + | expected `f32`, found integer + | help: use a float literal: `7.0` + +error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/structure-constructor-type-mismatch.rs:48:15 + | +LL | let pt3 = PointF::<i32> { + | ^^^^^^------- help: remove these generics + | | + | expected 0 generic arguments + | +note: type alias defined here, with 0 generic parameters + --> $DIR/structure-constructor-type-mismatch.rs:6:6 + | +LL | type PointF = Point<f32>; + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/structure-constructor-type-mismatch.rs:49:12 + | +LL | x: 9, + | ^ + | | + | expected `f32`, found integer + | help: use a float literal: `9.0` + +error[E0308]: mismatched types + --> $DIR/structure-constructor-type-mismatch.rs:50:12 + | +LL | y: 10, + | ^^ + | | + | expected `f32`, found integer + | help: use a float literal: `10.0` + +error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/structure-constructor-type-mismatch.rs:54:9 + | +LL | PointF::<u32> { .. } => {} + | ^^^^^^------- help: remove these generics + | | + | expected 0 generic arguments + | +note: type alias defined here, with 0 generic parameters + --> $DIR/structure-constructor-type-mismatch.rs:6:6 + | +LL | type PointF = Point<f32>; + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/structure-constructor-type-mismatch.rs:54:9 + | +LL | match (Point { x: 1, y: 2 }) { + | ---------------------- this expression has type `Point<{integer}>` +LL | PointF::<u32> { .. } => {} + | ^^^^^^^^^^^^^^^^^^^^ expected integer, found `f32` + | + = note: expected struct `Point<{integer}>` + found struct `Point<f32>` + +error[E0308]: mismatched types + --> $DIR/structure-constructor-type-mismatch.rs:59:9 + | +LL | match (Point { x: 1, y: 2 }) { + | ---------------------- this expression has type `Point<{integer}>` +LL | PointF { .. } => {} + | ^^^^^^^^^^^^^ expected integer, found `f32` + | + = note: expected struct `Point<{integer}>` + found struct `Point<f32>` + +error[E0308]: mismatched types + --> $DIR/structure-constructor-type-mismatch.rs:67:9 + | +LL | match (Pair { x: 1, y: 2 }) { + | --------------------- this expression has type `Pair<{integer}, {integer}>` +LL | PairF::<u32> { .. } => {} + | ^^^^^^^^^^^^^^^^^^^ expected integer, found `f32` + | + = note: expected struct `Pair<{integer}, {integer}>` + found struct `Pair<f32, u32>` + +error: aborting due to 13 previous errors + +Some errors have detailed explanations: E0107, E0308. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/structs/suggest-private-fields.rs b/src/test/ui/structs/suggest-private-fields.rs new file mode 100644 index 000000000..8267a82fe --- /dev/null +++ b/src/test/ui/structs/suggest-private-fields.rs @@ -0,0 +1,27 @@ +// aux-build:struct_field_privacy.rs + +extern crate struct_field_privacy as xc; + +use xc::B; + +struct A { + pub a: u32, + b: u32, +} + +fn main () { + // external crate struct + let k = B { + aa: 20, + //~^ ERROR struct `B` has no field named `aa` + bb: 20, + //~^ ERROR struct `B` has no field named `bb` + }; + // local crate struct + let l = A { + aa: 20, + //~^ ERROR struct `A` has no field named `aa` + bb: 20, + //~^ ERROR struct `A` has no field named `bb` + }; +} diff --git a/src/test/ui/structs/suggest-private-fields.stderr b/src/test/ui/structs/suggest-private-fields.stderr new file mode 100644 index 000000000..d628bd162 --- /dev/null +++ b/src/test/ui/structs/suggest-private-fields.stderr @@ -0,0 +1,29 @@ +error[E0560]: struct `B` has no field named `aa` + --> $DIR/suggest-private-fields.rs:15:9 + | +LL | aa: 20, + | ^^ help: a field with a similar name exists: `a` + +error[E0560]: struct `B` has no field named `bb` + --> $DIR/suggest-private-fields.rs:17:9 + | +LL | bb: 20, + | ^^ `B` does not have this field + | + = note: available fields are: `a` + +error[E0560]: struct `A` has no field named `aa` + --> $DIR/suggest-private-fields.rs:22:9 + | +LL | aa: 20, + | ^^ help: a field with a similar name exists: `a` + +error[E0560]: struct `A` has no field named `bb` + --> $DIR/suggest-private-fields.rs:24:9 + | +LL | bb: 20, + | ^^ help: a field with a similar name exists: `b` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0560`. diff --git a/src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.rs b/src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.rs new file mode 100644 index 000000000..dd2fe7973 --- /dev/null +++ b/src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.rs @@ -0,0 +1,28 @@ +enum Foo { + Bar { a: u8, b: i8, c: u8 }, + Baz { a: f32 }, + None, +} + +fn main() { + let foo = Foo::None; + match foo { + Foo::Bar { a, aa: 1, c } => (), + //~^ ERROR variant `Foo::Bar` does not have a field named `aa` [E0026] + //~| ERROR pattern does not mention field `b` [E0027] + Foo::Baz { bb: 1.0 } => (), + //~^ ERROR variant `Foo::Baz` does not have a field named `bb` [E0026] + //~| ERROR pattern does not mention field `a` [E0027] + _ => (), + } + + match foo { + Foo::Bar { a, aa: "", c } => (), + //~^ ERROR variant `Foo::Bar` does not have a field named `aa` [E0026] + //~| ERROR pattern does not mention field `b` [E0027] + Foo::Baz { bb: "" } => (), + //~^ ERROR variant `Foo::Baz` does not have a field named `bb` [E0026] + //~| pattern does not mention field `a` [E0027] + _ => (), + } +} diff --git a/src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr b/src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr new file mode 100644 index 000000000..e8503f540 --- /dev/null +++ b/src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr @@ -0,0 +1,94 @@ +error[E0026]: variant `Foo::Bar` does not have a field named `aa` + --> $DIR/suggest-replacing-field-when-specifying-same-type.rs:10:23 + | +LL | Foo::Bar { a, aa: 1, c } => (), + | ^^ + | | + | variant `Foo::Bar` does not have this field + | help: `Foo::Bar` has a field named `b` + +error[E0027]: pattern does not mention field `b` + --> $DIR/suggest-replacing-field-when-specifying-same-type.rs:10:9 + | +LL | Foo::Bar { a, aa: 1, c } => (), + | ^^^^^^^^^^^^^^^^^^^^^^^^ missing field `b` + | +help: include the missing field in the pattern + | +LL | Foo::Bar { a, aa: 1, c, b } => (), + | ~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | Foo::Bar { a, aa: 1, c, .. } => (), + | ~~~~~~ + +error[E0026]: variant `Foo::Baz` does not have a field named `bb` + --> $DIR/suggest-replacing-field-when-specifying-same-type.rs:13:20 + | +LL | Foo::Baz { bb: 1.0 } => (), + | ^^ + | | + | variant `Foo::Baz` does not have this field + | help: `Foo::Baz` has a field named `a` + +error[E0027]: pattern does not mention field `a` + --> $DIR/suggest-replacing-field-when-specifying-same-type.rs:13:9 + | +LL | Foo::Baz { bb: 1.0 } => (), + | ^^^^^^^^^^^^^^^^^^^^ missing field `a` + | +help: include the missing field in the pattern + | +LL | Foo::Baz { bb: 1.0, a } => (), + | ~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | Foo::Baz { bb: 1.0, .. } => (), + | ~~~~~~ + +error[E0026]: variant `Foo::Bar` does not have a field named `aa` + --> $DIR/suggest-replacing-field-when-specifying-same-type.rs:20:23 + | +LL | Foo::Bar { a, aa: "", c } => (), + | ^^ variant `Foo::Bar` does not have this field + +error[E0027]: pattern does not mention field `b` + --> $DIR/suggest-replacing-field-when-specifying-same-type.rs:20:9 + | +LL | Foo::Bar { a, aa: "", c } => (), + | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `b` + | +help: include the missing field in the pattern + | +LL | Foo::Bar { a, aa: "", c, b } => (), + | ~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | Foo::Bar { a, aa: "", c, .. } => (), + | ~~~~~~ + +error[E0026]: variant `Foo::Baz` does not have a field named `bb` + --> $DIR/suggest-replacing-field-when-specifying-same-type.rs:23:20 + | +LL | Foo::Baz { bb: "" } => (), + | ^^ variant `Foo::Baz` does not have this field + +error[E0027]: pattern does not mention field `a` + --> $DIR/suggest-replacing-field-when-specifying-same-type.rs:23:9 + | +LL | Foo::Baz { bb: "" } => (), + | ^^^^^^^^^^^^^^^^^^^ missing field `a` + | +help: include the missing field in the pattern + | +LL | Foo::Baz { bb: "", a } => (), + | ~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | Foo::Baz { bb: "", .. } => (), + | ~~~~~~ + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0026, E0027. +For more information about an error, try `rustc --explain E0026`. |