summaryrefslogtreecommitdiffstats
path: root/src/test/ui/structs-enums
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/structs-enums')
-rw-r--r--src/test/ui/structs-enums/align-enum.rs54
-rw-r--r--src/test/ui/structs-enums/align-struct.rs245
-rw-r--r--src/test/ui/structs-enums/auxiliary/cci_class.rs14
-rw-r--r--src/test/ui/structs-enums/auxiliary/cci_class_2.rs19
-rw-r--r--src/test/ui/structs-enums/auxiliary/cci_class_3.rs19
-rw-r--r--src/test/ui/structs-enums/auxiliary/cci_class_4.rs41
-rw-r--r--src/test/ui/structs-enums/auxiliary/cci_class_6.rs25
-rw-r--r--src/test/ui/structs-enums/auxiliary/cci_class_cast.rs50
-rw-r--r--src/test/ui/structs-enums/auxiliary/cci_class_trait.rs5
-rw-r--r--src/test/ui/structs-enums/auxiliary/empty-struct.rs9
-rw-r--r--src/test/ui/structs-enums/auxiliary/namespaced_enum_emulate_flat.rs25
-rw-r--r--src/test/ui/structs-enums/auxiliary/namespaced_enums.rs10
-rw-r--r--src/test/ui/structs-enums/auxiliary/newtype_struct_xc.rs3
-rw-r--r--src/test/ui/structs-enums/auxiliary/struct_destructuring_cross_crate.rs6
-rw-r--r--src/test/ui/structs-enums/auxiliary/struct_variant_xc_aux.rs8
-rw-r--r--src/test/ui/structs-enums/auxiliary/xcrate_struct_aliases.rs6
-rw-r--r--src/test/ui/structs-enums/borrow-tuple-fields.rs38
-rw-r--r--src/test/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs18
-rw-r--r--src/test/ui/structs-enums/class-cast-to-trait-multiple-types.rs94
-rw-r--r--src/test/ui/structs-enums/class-cast-to-trait.rs60
-rw-r--r--src/test/ui/structs-enums/class-dtor.rs25
-rw-r--r--src/test/ui/structs-enums/class-exports.rs31
-rw-r--r--src/test/ui/structs-enums/class-impl-very-parameterized-trait.rs107
-rw-r--r--src/test/ui/structs-enums/class-implement-trait-cross-crate.rs59
-rw-r--r--src/test/ui/structs-enums/class-implement-traits.rs64
-rw-r--r--src/test/ui/structs-enums/class-method-cross-crate.rs13
-rw-r--r--src/test/ui/structs-enums/class-methods-cross-crate.rs14
-rw-r--r--src/test/ui/structs-enums/class-methods.rs30
-rw-r--r--src/test/ui/structs-enums/class-poly-methods-cross-crate.rs16
-rw-r--r--src/test/ui/structs-enums/class-poly-methods.rs37
-rw-r--r--src/test/ui/structs-enums/class-separate-impl.rs63
-rw-r--r--src/test/ui/structs-enums/class-str-field.rs21
-rw-r--r--src/test/ui/structs-enums/class-typarams.rs32
-rw-r--r--src/test/ui/structs-enums/classes-cross-crate.rs13
-rw-r--r--src/test/ui/structs-enums/classes-self-referential.rs20
-rw-r--r--src/test/ui/structs-enums/classes-simple-cross-crate.rs12
-rw-r--r--src/test/ui/structs-enums/classes-simple-method.rs28
-rw-r--r--src/test/ui/structs-enums/classes-simple.rs23
-rw-r--r--src/test/ui/structs-enums/classes.rs51
-rw-r--r--src/test/ui/structs-enums/codegen-tag-static-padding.rs59
-rw-r--r--src/test/ui/structs-enums/compare-generic-enums.rs16
-rw-r--r--src/test/ui/structs-enums/cross-crate-newtype-struct-pat.rs12
-rw-r--r--src/test/ui/structs-enums/discrim-explicit-23030.rs145
-rw-r--r--src/test/ui/structs-enums/empty-struct-braces.rs213
-rw-r--r--src/test/ui/structs-enums/empty-tag.rs22
-rw-r--r--src/test/ui/structs-enums/enum-alignment.rs24
-rw-r--r--src/test/ui/structs-enums/enum-clike-ffi-as-int.rs33
-rw-r--r--src/test/ui/structs-enums/enum-discr.rs23
-rw-r--r--src/test/ui/structs-enums/enum-discrim-autosizing.rs53
-rw-r--r--src/test/ui/structs-enums/enum-discrim-manual-sizing.rs111
-rw-r--r--src/test/ui/structs-enums/enum-discrim-range-overflow.rs26
-rw-r--r--src/test/ui/structs-enums/enum-discrim-width-stuff.rs44
-rw-r--r--src/test/ui/structs-enums/enum-disr-val-pretty.rs17
-rw-r--r--src/test/ui/structs-enums/enum-export-inheritance.rs15
-rw-r--r--src/test/ui/structs-enums/enum-layout-optimization.rs50
-rw-r--r--src/test/ui/structs-enums/enum-non-c-like-repr-c-and-int.rs173
-rw-r--r--src/test/ui/structs-enums/enum-non-c-like-repr-c.rs174
-rw-r--r--src/test/ui/structs-enums/enum-non-c-like-repr-int.rs169
-rw-r--r--src/test/ui/structs-enums/enum-null-pointer-opt.rs74
-rw-r--r--src/test/ui/structs-enums/enum-nullable-const-null-with-fields.rs13
-rw-r--r--src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs16
-rw-r--r--src/test/ui/structs-enums/enum-univariant-repr.rs51
-rw-r--r--src/test/ui/structs-enums/enum-variants.rs18
-rw-r--r--src/test/ui/structs-enums/enum-vec-initializer.rs17
-rw-r--r--src/test/ui/structs-enums/export-abstract-tag.rs15
-rw-r--r--src/test/ui/structs-enums/export-tag-variant.rs9
-rw-r--r--src/test/ui/structs-enums/expr-if-struct.rs32
-rw-r--r--src/test/ui/structs-enums/expr-match-struct.rs31
-rw-r--r--src/test/ui/structs-enums/field-destruction-order.rs47
-rw-r--r--src/test/ui/structs-enums/foreign-struct.rs19
-rw-r--r--src/test/ui/structs-enums/functional-struct-upd.rs15
-rw-r--r--src/test/ui/structs-enums/issue-1701.rs26
-rw-r--r--src/test/ui/structs-enums/issue-38002.rs35
-rw-r--r--src/test/ui/structs-enums/issue-50731.rs6
-rw-r--r--src/test/ui/structs-enums/ivec-tag.rs22
-rw-r--r--src/test/ui/structs-enums/module-qualified-struct-destructure.rs14
-rw-r--r--src/test/ui/structs-enums/multiple-reprs.rs82
-rw-r--r--src/test/ui/structs-enums/namespaced-enum-emulate-flat-xc.rs25
-rw-r--r--src/test/ui/structs-enums/namespaced-enum-emulate-flat.rs44
-rw-r--r--src/test/ui/structs-enums/namespaced-enum-glob-import-xcrate.rs26
-rw-r--r--src/test/ui/structs-enums/namespaced-enum-glob-import.rs35
-rw-r--r--src/test/ui/structs-enums/namespaced-enums-xcrate.rs16
-rw-r--r--src/test/ui/structs-enums/namespaced-enums.rs17
-rw-r--r--src/test/ui/structs-enums/nested-enum-same-names.rs27
-rw-r--r--src/test/ui/structs-enums/newtype-struct-drop-run.rs21
-rw-r--r--src/test/ui/structs-enums/newtype-struct-with-dtor.rs20
-rw-r--r--src/test/ui/structs-enums/newtype-struct-xc-2.rs15
-rw-r--r--src/test/ui/structs-enums/newtype-struct-xc.rs10
-rw-r--r--src/test/ui/structs-enums/nonzero-enum.rs30
-rw-r--r--src/test/ui/structs-enums/numeric-fields.rs12
-rw-r--r--src/test/ui/structs-enums/rec-align-u32.rs56
-rw-r--r--src/test/ui/structs-enums/rec-align-u64.rs96
-rw-r--r--src/test/ui/structs-enums/rec-auto.rs14
-rw-r--r--src/test/ui/structs-enums/rec-extend.rs18
-rw-r--r--src/test/ui/structs-enums/rec-tup.rs31
-rw-r--r--src/test/ui/structs-enums/rec.rs24
-rw-r--r--src/test/ui/structs-enums/record-pat.rs19
-rw-r--r--src/test/ui/structs-enums/resource-in-struct.rs37
-rw-r--r--src/test/ui/structs-enums/simple-generic-tag.rs11
-rw-r--r--src/test/ui/structs-enums/simple-match-generic-tag.rs13
-rw-r--r--src/test/ui/structs-enums/small-enum-range-edge.rs27
-rw-r--r--src/test/ui/structs-enums/small-enums-with-fields.rs33
-rw-r--r--src/test/ui/structs-enums/struct-aliases-xcrate.rs25
-rw-r--r--src/test/ui/structs-enums/struct-aliases.rs64
-rw-r--r--src/test/ui/structs-enums/struct-destructuring-cross-crate.rs12
-rw-r--r--src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs12
-rw-r--r--src/test/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr24
-rw-r--r--src/test/ui/structs-enums/struct-field-shorthand.rs26
-rw-r--r--src/test/ui/structs-enums/struct-like-variant-construct.rs18
-rw-r--r--src/test/ui/structs-enums/struct-like-variant-match.rs33
-rw-r--r--src/test/ui/structs-enums/struct-lit-functional-no-fields.rs26
-rw-r--r--src/test/ui/structs-enums/struct-literal-dtor.rs18
-rw-r--r--src/test/ui/structs-enums/struct-new-as-field-name.rs10
-rw-r--r--src/test/ui/structs-enums/struct-order-of-eval-1.rs16
-rw-r--r--src/test/ui/structs-enums/struct-order-of-eval-2.rs16
-rw-r--r--src/test/ui/structs-enums/struct-order-of-eval-3.rs37
-rw-r--r--src/test/ui/structs-enums/struct-order-of-eval-4.rs34
-rw-r--r--src/test/ui/structs-enums/struct-partial-move-1.rs21
-rw-r--r--src/test/ui/structs-enums/struct-partial-move-2.rs28
-rw-r--r--src/test/ui/structs-enums/struct-path-associated-type.rs27
-rw-r--r--src/test/ui/structs-enums/struct-path-self.rs45
-rw-r--r--src/test/ui/structs-enums/struct-pattern-matching.rs18
-rw-r--r--src/test/ui/structs-enums/struct-rec/issue-74224.rs11
-rw-r--r--src/test/ui/structs-enums/struct-rec/issue-74224.stderr17
-rw-r--r--src/test/ui/structs-enums/struct-rec/issue-84611.rs11
-rw-r--r--src/test/ui/structs-enums/struct-rec/issue-84611.stderr17
-rw-r--r--src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.rs23
-rw-r--r--src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr59
-rw-r--r--src/test/ui/structs-enums/struct-variant-field-visibility.rs17
-rw-r--r--src/test/ui/structs-enums/struct_variant_xc.rs11
-rw-r--r--src/test/ui/structs-enums/struct_variant_xc_match.rs14
-rw-r--r--src/test/ui/structs-enums/tag-align-dyn-u64.rs29
-rw-r--r--src/test/ui/structs-enums/tag-align-dyn-variants.rs67
-rw-r--r--src/test/ui/structs-enums/tag-align-shape.rs21
-rw-r--r--src/test/ui/structs-enums/tag-align-u64.rs29
-rw-r--r--src/test/ui/structs-enums/tag-disr-val-shape.rs20
-rw-r--r--src/test/ui/structs-enums/tag-exports.rs21
-rw-r--r--src/test/ui/structs-enums/tag-in-block.rs15
-rw-r--r--src/test/ui/structs-enums/tag-variant-disr-type-mismatch.rs12
-rw-r--r--src/test/ui/structs-enums/tag-variant-disr-val.rs66
-rw-r--r--src/test/ui/structs-enums/tag.rs30
-rw-r--r--src/test/ui/structs-enums/tuple-struct-construct.rs9
-rw-r--r--src/test/ui/structs-enums/tuple-struct-constructor-pointer.rs12
-rw-r--r--src/test/ui/structs-enums/tuple-struct-destructuring.rs10
-rw-r--r--src/test/ui/structs-enums/tuple-struct-matching.rs13
-rw-r--r--src/test/ui/structs-enums/tuple-struct-trivial.rs8
-rw-r--r--src/test/ui/structs-enums/type-sizes.rs173
-rw-r--r--src/test/ui/structs-enums/uninstantiable-struct.rs4
-rw-r--r--src/test/ui/structs-enums/unit-like-struct-drop-run.rs24
-rw-r--r--src/test/ui/structs-enums/unit-like-struct.rs9
-rw-r--r--src/test/ui/structs-enums/variant-structs-trivial.rs10
151 files changed, 5278 insertions, 0 deletions
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() { }