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