summary refs log tree commit diff
path: root/src/test/ui/packed
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-07-27 01:33:01 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-07-27 18:56:16 +0300
commit9be35f82c1abf2ecbab489bca9eca138ea648312 (patch)
tree69888506e34af447d9748c0d542de3ba1dd76210 /src/test/ui/packed
parentca9faa52f5ada0054b1fa27d97aedf448afb059b (diff)
downloadrust-9be35f82c1abf2ecbab489bca9eca138ea648312.tar.gz
rust-9be35f82c1abf2ecbab489bca9eca138ea648312.zip
tests: Move run-pass tests without naming conflicts to ui
Diffstat (limited to 'src/test/ui/packed')
-rw-r--r--src/test/ui/packed/auxiliary/packed.rs19
-rw-r--r--src/test/ui/packed/packed-struct-borrow-element.rs35
-rw-r--r--src/test/ui/packed/packed-struct-drop-aligned.rs33
-rw-r--r--src/test/ui/packed/packed-struct-generic-layout.rs32
-rw-r--r--src/test/ui/packed/packed-struct-generic-size.rs44
-rw-r--r--src/test/ui/packed/packed-struct-layout.rs28
-rw-r--r--src/test/ui/packed/packed-struct-match.rs45
-rw-r--r--src/test/ui/packed/packed-struct-optimized-enum.rs36
-rw-r--r--src/test/ui/packed/packed-struct-size-xc.rs20
-rw-r--r--src/test/ui/packed/packed-struct-size.rs157
-rw-r--r--src/test/ui/packed/packed-struct-vec.rs120
-rw-r--r--src/test/ui/packed/packed-tuple-struct-layout.rs21
-rw-r--r--src/test/ui/packed/packed-tuple-struct-size.rs79
-rw-r--r--src/test/ui/packed/packed-with-inference-vars-issue-61402.rs22
14 files changed, 691 insertions, 0 deletions
diff --git a/src/test/ui/packed/auxiliary/packed.rs b/src/test/ui/packed/auxiliary/packed.rs
new file mode 100644
index 00000000000..cba166facf4
--- /dev/null
+++ b/src/test/ui/packed/auxiliary/packed.rs
@@ -0,0 +1,19 @@
+#[repr(packed)]
+pub struct P1S5 {
+    a: u8,
+    b: u32
+}
+
+#[repr(packed(2))]
+pub struct P2S6 {
+    a: u8,
+    b: u32,
+    c: u8
+}
+
+#[repr(C, packed(2))]
+pub struct P2CS8 {
+    a: u8,
+    b: u32,
+    c: u8
+}
diff --git a/src/test/ui/packed/packed-struct-borrow-element.rs b/src/test/ui/packed/packed-struct-borrow-element.rs
new file mode 100644
index 00000000000..6ac42ed0d47
--- /dev/null
+++ b/src/test/ui/packed/packed-struct-borrow-element.rs
@@ -0,0 +1,35 @@
+// run-pass
+#![allow(dead_code)]
+// ignore-emscripten weird assertion?
+
+#[repr(packed)]
+struct Foo1 {
+    bar: u8,
+    baz: usize
+}
+
+#[repr(packed(2))]
+struct Foo2 {
+    bar: u8,
+    baz: usize
+}
+
+#[repr(C, packed(4))]
+struct Foo4C {
+    bar: u8,
+    baz: usize
+}
+
+pub fn main() {
+    let foo = Foo1 { bar: 1, baz: 2 };
+    let brw = unsafe { &foo.baz };
+    assert_eq!(*brw, 2);
+
+    let foo = Foo2 { bar: 1, baz: 2 };
+    let brw = unsafe { &foo.baz };
+    assert_eq!(*brw, 2);
+
+    let foo = Foo4C { bar: 1, baz: 2 };
+    let brw = unsafe { &foo.baz };
+    assert_eq!(*brw, 2);
+}
diff --git a/src/test/ui/packed/packed-struct-drop-aligned.rs b/src/test/ui/packed/packed-struct-drop-aligned.rs
new file mode 100644
index 00000000000..fab3bbedac6
--- /dev/null
+++ b/src/test/ui/packed/packed-struct-drop-aligned.rs
@@ -0,0 +1,33 @@
+// run-pass
+use std::cell::Cell;
+use std::mem;
+
+struct Aligned<'a> {
+    drop_count: &'a Cell<usize>
+}
+
+#[inline(never)]
+fn check_align(ptr: *const Aligned) {
+    assert_eq!(ptr as usize % mem::align_of::<Aligned>(),
+               0);
+}
+
+impl<'a> Drop for Aligned<'a> {
+    fn drop(&mut self) {
+        check_align(self);
+        self.drop_count.set(self.drop_count.get() + 1);
+    }
+}
+
+#[repr(packed)]
+struct Packed<'a>(u8, Aligned<'a>);
+
+fn main() {
+    let drop_count = &Cell::new(0);
+    {
+        let mut p = Packed(0, Aligned { drop_count });
+        p.1 = Aligned { drop_count };
+        assert_eq!(drop_count.get(), 1);
+    }
+    assert_eq!(drop_count.get(), 2);
+}
diff --git a/src/test/ui/packed/packed-struct-generic-layout.rs b/src/test/ui/packed/packed-struct-generic-layout.rs
new file mode 100644
index 00000000000..e064eede4ce
--- /dev/null
+++ b/src/test/ui/packed/packed-struct-generic-layout.rs
@@ -0,0 +1,32 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(overflowing_literals)]
+
+
+use std::mem;
+
+#[repr(packed)]
+struct S<T, S> {
+    a: T,
+    b: u8,
+    c: S
+}
+
+pub fn main() {
+    unsafe {
+        let s = S { a: 0xff_ff_ff_ffu32, b: 1, c: 0xaa_aa_aa_aa as i32 };
+        let transd : [u8; 9] = mem::transmute(s);
+        // Don't worry about endianness, the numbers are palindromic.
+        assert_eq!(transd,
+                   [0xff, 0xff, 0xff, 0xff,
+                    1,
+                    0xaa, 0xaa, 0xaa, 0xaa]);
+
+
+        let s = S { a: 1u8, b: 2u8, c: 0b10000001_10000001 as i16};
+        let transd : [u8; 4] = mem::transmute(s);
+        // Again, no endianness problems.
+        assert_eq!(transd,
+                   [1, 2, 0b10000001, 0b10000001]);
+    }
+}
diff --git a/src/test/ui/packed/packed-struct-generic-size.rs b/src/test/ui/packed/packed-struct-generic-size.rs
new file mode 100644
index 00000000000..7c93e46c30c
--- /dev/null
+++ b/src/test/ui/packed/packed-struct-generic-size.rs
@@ -0,0 +1,44 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_comparisons)]
+
+use std::mem;
+
+#[repr(packed)]
+struct P1<T, S> {
+    a: T,
+    b: u8,
+    c: S
+}
+
+#[repr(packed(2))]
+struct P2<T, S> {
+    a: T,
+    b: u8,
+    c: S
+}
+
+#[repr(C, packed(4))]
+struct P4C<T, S> {
+    a: T,
+    b: u8,
+    c: S
+}
+
+macro_rules! check {
+    ($t:ty, $align:expr, $size:expr) => ({
+        assert_eq!(mem::align_of::<$t>(), $align);
+        assert_eq!(mem::size_of::<$t>(), $size);
+    });
+}
+
+pub fn main() {
+    check!(P1<u8, u8>, 1, 3);
+    check!(P1<u64, u16>, 1, 11);
+
+    check!(P2<u8, u8>, 1, 3);
+    check!(P2<u64, u16>, 2, 12);
+
+    check!(P4C<u8, u8>, 1, 3);
+    check!(P4C<u16, u64>, 4, 12);
+}
diff --git a/src/test/ui/packed/packed-struct-layout.rs b/src/test/ui/packed/packed-struct-layout.rs
new file mode 100644
index 00000000000..d49c222e648
--- /dev/null
+++ b/src/test/ui/packed/packed-struct-layout.rs
@@ -0,0 +1,28 @@
+// run-pass
+#![allow(dead_code)]
+use std::mem;
+
+#[repr(packed)]
+struct S4 {
+    a: u8,
+    b: [u8; 3],
+}
+
+#[repr(packed)]
+struct S5 {
+    a: u8,
+    b: u32
+}
+
+pub fn main() {
+    unsafe {
+        let s4 = S4 { a: 1, b: [2,3,4] };
+        let transd : [u8; 4] = mem::transmute(s4);
+        assert_eq!(transd, [1, 2, 3, 4]);
+
+        let s5 = S5 { a: 1, b: 0xff_00_00_ff };
+        let transd : [u8; 5] = mem::transmute(s5);
+        // Don't worry about endianness, the u32 is palindromic.
+        assert_eq!(transd, [1, 0xff, 0, 0, 0xff]);
+    }
+}
diff --git a/src/test/ui/packed/packed-struct-match.rs b/src/test/ui/packed/packed-struct-match.rs
new file mode 100644
index 00000000000..9a572ced717
--- /dev/null
+++ b/src/test/ui/packed/packed-struct-match.rs
@@ -0,0 +1,45 @@
+// run-pass
+
+#[repr(packed)]
+struct Foo1 {
+    bar: u8,
+    baz: usize
+}
+
+#[repr(packed(2))]
+struct Foo2 {
+    bar: u8,
+    baz: usize
+}
+
+#[repr(C, packed(4))]
+struct Foo4C {
+    bar: u8,
+    baz: usize
+}
+
+pub fn main() {
+    let foo1 = Foo1 { bar: 1, baz: 2 };
+    match foo1 {
+        Foo1 {bar, baz} => {
+            assert_eq!(bar, 1);
+            assert_eq!(baz, 2);
+        }
+    }
+
+    let foo2 = Foo2 { bar: 1, baz: 2 };
+    match foo2 {
+        Foo2 {bar, baz} => {
+            assert_eq!(bar, 1);
+            assert_eq!(baz, 2);
+        }
+    }
+
+    let foo4 = Foo4C { bar: 1, baz: 2 };
+    match foo4 {
+        Foo4C {bar, baz} => {
+            assert_eq!(bar, 1);
+            assert_eq!(baz, 2);
+        }
+    }
+}
diff --git a/src/test/ui/packed/packed-struct-optimized-enum.rs b/src/test/ui/packed/packed-struct-optimized-enum.rs
new file mode 100644
index 00000000000..7ce62464ef0
--- /dev/null
+++ b/src/test/ui/packed/packed-struct-optimized-enum.rs
@@ -0,0 +1,36 @@
+// run-pass
+#[repr(packed)]
+struct Packed<T: Copy>(T);
+
+impl<T: Copy> Copy for Packed<T> {}
+impl<T: Copy> Clone for Packed<T> {
+    fn clone(&self) -> Self { *self }
+}
+
+fn sanity_check_size<T: Copy>(one: T) {
+    let two = [one, one];
+    let stride = (&two[1] as *const _ as usize) - (&two[0] as *const _ as usize);
+    let (size, align) = (std::mem::size_of::<T>(), std::mem::align_of::<T>());
+    assert_eq!(stride, size);
+    assert_eq!(size % align, 0);
+}
+
+fn main() {
+    // This can fail if rustc and LLVM disagree on the size of a type.
+    // In this case, `Option<Packed<(&(), u32)>>` was erroneously not
+    // marked as packed despite needing alignment `1` and containing
+    // its `&()` discriminant, which has alignment larger than `1`.
+    sanity_check_size((Some(Packed((&(), 0))), true));
+
+    // In #46769, `Option<(Packed<&()>, bool)>` was found to have
+    // pointer alignment, without actually being aligned in size.
+    // e.g., on 64-bit platforms, it had alignment `8` but size `9`.
+    type PackedRefAndBool<'a> = (Packed<&'a ()>, bool);
+    sanity_check_size::<Option<PackedRefAndBool>>(Some((Packed(&()), true)));
+
+    // Make sure we don't pay for the enum optimization in size,
+    // e.g., we shouldn't need extra padding after the packed data.
+    assert_eq!(std::mem::align_of::<Option<PackedRefAndBool>>(), 1);
+    assert_eq!(std::mem::size_of::<Option<PackedRefAndBool>>(),
+               std::mem::size_of::<PackedRefAndBool>());
+}
diff --git a/src/test/ui/packed/packed-struct-size-xc.rs b/src/test/ui/packed/packed-struct-size-xc.rs
new file mode 100644
index 00000000000..46112d51d83
--- /dev/null
+++ b/src/test/ui/packed/packed-struct-size-xc.rs
@@ -0,0 +1,20 @@
+// run-pass
+// aux-build:packed.rs
+
+
+extern crate packed;
+
+use std::mem;
+
+macro_rules! check {
+    ($t:ty, $align:expr, $size:expr) => ({
+        assert_eq!(mem::align_of::<$t>(), $align);
+        assert_eq!(mem::size_of::<$t>(), $size);
+    });
+}
+
+pub fn main() {
+    check!(packed::P1S5, 1, 5);
+    check!(packed::P2S6, 2, 6);
+    check!(packed::P2CS8, 2, 8);
+}
diff --git a/src/test/ui/packed/packed-struct-size.rs b/src/test/ui/packed/packed-struct-size.rs
new file mode 100644
index 00000000000..c832c7cfad5
--- /dev/null
+++ b/src/test/ui/packed/packed-struct-size.rs
@@ -0,0 +1,157 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+#![allow(non_upper_case_globals)]
+
+use std::mem;
+
+#[repr(packed)]
+struct P1S4 {
+    a: u8,
+    b: [u8;  3],
+}
+
+#[repr(packed(2))]
+struct P2S4 {
+    a: u8,
+    b: [u8;  3],
+}
+
+#[repr(packed)]
+struct P1S5 {
+    a: u8,
+    b: u32
+}
+
+#[repr(packed(2))]
+struct P2S2 {
+    a: u8,
+    b: u8
+}
+
+#[repr(packed(2))]
+struct P2S6 {
+    a: u8,
+    b: u32
+}
+
+#[repr(packed(2))]
+struct P2S12 {
+    a: u32,
+    b: u64
+}
+
+#[repr(packed)]
+struct P1S13 {
+    a: i64,
+    b: f32,
+    c: u8,
+}
+
+#[repr(packed(2))]
+struct P2S14 {
+    a: i64,
+    b: f32,
+    c: u8,
+}
+
+#[repr(packed(4))]
+struct P4S16 {
+    a: u8,
+    b: f32,
+    c: i64,
+    d: u16,
+}
+
+#[repr(C, packed(4))]
+struct P4CS20 {
+    a: u8,
+    b: f32,
+    c: i64,
+    d: u16,
+}
+
+enum Foo {
+    Bar = 1,
+    Baz = 2
+}
+
+#[repr(packed)]
+struct P1S3_Foo {
+    a: u8,
+    b: u16,
+    c: Foo
+}
+
+#[repr(packed(2))]
+struct P2_Foo {
+    a: Foo,
+}
+
+#[repr(packed(2))]
+struct P2S3_Foo {
+    a: u8,
+    b: u16,
+    c: Foo
+}
+
+#[repr(packed)]
+struct P1S7_Option {
+    a: f32,
+    b: u8,
+    c: u16,
+    d: Option<Box<f64>>
+}
+
+#[repr(packed(2))]
+struct P2_Option {
+    a: Option<Box<f64>>
+}
+
+#[repr(packed(2))]
+struct P2S7_Option {
+    a: f32,
+    b: u8,
+    c: u16,
+    d: Option<Box<f64>>
+}
+
+// Placing packed structs in statics should work
+static TEST_P1S4: P1S4 = P1S4 { a: 1, b: [2, 3, 4] };
+static TEST_P1S5: P1S5 = P1S5 { a: 3, b: 67 };
+static TEST_P1S3_Foo: P1S3_Foo = P1S3_Foo { a: 1, b: 2, c: Foo::Baz };
+static TEST_P2S2: P2S2 = P2S2 { a: 1, b: 2 };
+static TEST_P2S4: P2S4 = P2S4 { a: 1, b: [2, 3, 4] };
+static TEST_P2S6: P2S6 = P2S6 { a: 1, b: 2 };
+static TEST_P2S12: P2S12 = P2S12 { a: 1, b: 2 };
+static TEST_P4S16: P4S16 = P4S16 { a: 1, b: 2.0, c: 3, d: 4 };
+static TEST_P4CS20: P4CS20 = P4CS20 { a: 1, b: 2.0, c: 3, d: 4 };
+
+fn align_to(value: usize, align: usize) -> usize {
+    (value + (align - 1)) & !(align - 1)
+}
+
+macro_rules! check {
+    ($t:ty, $align:expr, $size:expr) => ({
+        assert_eq!(mem::align_of::<$t>(), $align);
+        assert_eq!(mem::size_of::<$t>(), $size);
+    });
+}
+
+pub fn main() {
+    check!(P1S4, 1, 4);
+    check!(P1S5, 1, 5);
+    check!(P1S13, 1, 13);
+    check!(P1S3_Foo, 1, 3 + mem::size_of::<Foo>());
+    check!(P1S7_Option, 1, 7 + mem::size_of::<Option<Box<f64>>>());
+
+    check!(P2S2, 1, 2);
+    check!(P2S4, 1, 4);
+    check!(P2S6, 2, 6);
+    check!(P2S12, 2, 12);
+    check!(P2S14, 2, 14);
+    check!(P4S16, 4, 16);
+    check!(P4CS20, 4, 20);
+    check!(P2S3_Foo, 2, align_to(3 + mem::size_of::<P2_Foo>(), 2));
+    check!(P2S7_Option, 2, align_to(7 + mem::size_of::<P2_Option>(), 2));
+}
diff --git a/src/test/ui/packed/packed-struct-vec.rs b/src/test/ui/packed/packed-struct-vec.rs
new file mode 100644
index 00000000000..18676cfc22e
--- /dev/null
+++ b/src/test/ui/packed/packed-struct-vec.rs
@@ -0,0 +1,120 @@
+// run-pass
+
+use std::fmt;
+use std::mem;
+
+#[repr(packed)]
+#[derive(Copy, Clone)]
+struct Foo1 {
+    bar: u8,
+    baz: u64
+}
+
+impl PartialEq for Foo1 {
+    fn eq(&self, other: &Foo1) -> bool {
+        self.bar == other.bar && self.baz == other.baz
+    }
+}
+
+impl fmt::Debug for Foo1 {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let bar = self.bar;
+        let baz = self.baz;
+
+        f.debug_struct("Foo1")
+            .field("bar", &bar)
+            .field("baz", &baz)
+            .finish()
+    }
+}
+
+#[repr(packed(2))]
+#[derive(Copy, Clone)]
+struct Foo2 {
+    bar: u8,
+    baz: u64
+}
+
+impl PartialEq for Foo2 {
+    fn eq(&self, other: &Foo2) -> bool {
+        self.bar == other.bar && self.baz == other.baz
+    }
+}
+
+impl fmt::Debug for Foo2 {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let bar = self.bar;
+        let baz = self.baz;
+
+        f.debug_struct("Foo2")
+            .field("bar", &bar)
+            .field("baz", &baz)
+            .finish()
+    }
+}
+
+#[repr(C, packed(4))]
+#[derive(Copy, Clone)]
+struct Foo4C {
+    bar: u8,
+    baz: u64
+}
+
+impl PartialEq for Foo4C {
+    fn eq(&self, other: &Foo4C) -> bool {
+        self.bar == other.bar && self.baz == other.baz
+    }
+}
+
+impl fmt::Debug for Foo4C {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let bar = self.bar;
+        let baz = self.baz;
+
+        f.debug_struct("Foo4C")
+            .field("bar", &bar)
+            .field("baz", &baz)
+            .finish()
+    }
+}
+
+pub fn main() {
+    let foo1s = [Foo1 { bar: 1, baz: 2 }; 10];
+
+    assert_eq!(mem::align_of::<[Foo1; 10]>(), 1);
+    assert_eq!(mem::size_of::<[Foo1; 10]>(), 90);
+
+    for i in 0..10 {
+        assert_eq!(foo1s[i], Foo1 { bar: 1, baz: 2});
+    }
+
+    for &foo in &foo1s {
+        assert_eq!(foo, Foo1 { bar: 1, baz: 2 });
+    }
+
+    let foo2s = [Foo2 { bar: 1, baz: 2 }; 10];
+
+    assert_eq!(mem::align_of::<[Foo2; 10]>(), 2);
+    assert_eq!(mem::size_of::<[Foo2; 10]>(), 100);
+
+    for i in 0..10 {
+        assert_eq!(foo2s[i], Foo2 { bar: 1, baz: 2});
+    }
+
+    for &foo in &foo2s {
+        assert_eq!(foo, Foo2 { bar: 1, baz: 2 });
+    }
+
+    let foo4s = [Foo4C { bar: 1, baz: 2 }; 10];
+
+    assert_eq!(mem::align_of::<[Foo4C; 10]>(), 4);
+    assert_eq!(mem::size_of::<[Foo4C; 10]>(), 120);
+
+    for i in 0..10 {
+        assert_eq!(foo4s[i], Foo4C { bar: 1, baz: 2});
+    }
+
+    for &foo in &foo4s {
+        assert_eq!(foo, Foo4C { bar: 1, baz: 2 });
+    }
+}
diff --git a/src/test/ui/packed/packed-tuple-struct-layout.rs b/src/test/ui/packed/packed-tuple-struct-layout.rs
new file mode 100644
index 00000000000..b88637fbe56
--- /dev/null
+++ b/src/test/ui/packed/packed-tuple-struct-layout.rs
@@ -0,0 +1,21 @@
+// run-pass
+use std::mem;
+
+#[repr(packed)]
+struct S4(u8,[u8; 3]);
+
+#[repr(packed)]
+struct S5(u8,u32);
+
+pub fn main() {
+    unsafe {
+        let s4 = S4(1, [2,3,4]);
+        let transd : [u8; 4] = mem::transmute(s4);
+        assert_eq!(transd, [1, 2, 3, 4]);
+
+        let s5 = S5(1, 0xff_00_00_ff);
+        let transd : [u8; 5] = mem::transmute(s5);
+        // Don't worry about endianness, the u32 is palindromic.
+        assert_eq!(transd, [1, 0xff, 0, 0, 0xff]);
+    }
+}
diff --git a/src/test/ui/packed/packed-tuple-struct-size.rs b/src/test/ui/packed/packed-tuple-struct-size.rs
new file mode 100644
index 00000000000..f7a3c903fca
--- /dev/null
+++ b/src/test/ui/packed/packed-tuple-struct-size.rs
@@ -0,0 +1,79 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+
+use std::mem;
+
+#[repr(packed)]
+struct P1S4(u8,[u8;  3]);
+
+#[repr(packed(2))]
+struct P2S4(u8,[u8;  3]);
+
+#[repr(packed)]
+struct P1S5(u8, u32);
+
+#[repr(packed(2))]
+struct P2S6(u8, u32);
+
+#[repr(packed)]
+struct P1S13(i64, f32, u8);
+
+#[repr(packed(2))]
+struct P2S14(i64, f32, u8);
+
+#[repr(packed(4))]
+struct P4S16(u8, f32, i64, u16);
+
+#[repr(C, packed(4))]
+struct P4CS20(u8, f32, i64, u16);
+
+enum Foo {
+    Bar = 1,
+    Baz = 2
+}
+
+#[repr(packed)]
+struct P1S3_Foo(u8, u16, Foo);
+
+#[repr(packed(2))]
+struct P2_Foo(Foo);
+
+#[repr(packed(2))]
+struct P2S3_Foo(u8, u16, Foo);
+
+#[repr(packed)]
+struct P1S7_Option(f32, u8, u16, Option<Box<f64>>);
+
+#[repr(packed(2))]
+struct P2_Option(Option<Box<f64>>);
+
+#[repr(packed(2))]
+struct P2S7_Option(f32, u8, u16, Option<Box<f64>>);
+
+fn align_to(value: usize, align: usize) -> usize {
+    (value + (align - 1)) & !(align - 1)
+}
+
+macro_rules! check {
+    ($t:ty, $align:expr, $size:expr) => ({
+        assert_eq!(mem::align_of::<$t>(), $align);
+        assert_eq!(mem::size_of::<$t>(), $size);
+    });
+}
+
+pub fn main() {
+    check!(P1S4, 1, 4);
+    check!(P1S5, 1, 5);
+    check!(P1S13, 1, 13);
+    check!(P1S3_Foo, 1, 3 + mem::size_of::<Foo>());
+    check!(P1S7_Option, 1, 7 + mem::size_of::<Option<Box<f64>>>());
+
+    check!(P2S4, 1, 4);
+    check!(P2S6, 2, 6);
+    check!(P2S14, 2, 14);
+    check!(P4S16, 4, 16);
+    check!(P4CS20, 4, 20);
+    check!(P2S3_Foo, 2, align_to(3 + mem::size_of::<P2_Foo>(), 2));
+    check!(P2S7_Option, 2, align_to(7 + mem::size_of::<P2_Option>(), 2));
+}
diff --git a/src/test/ui/packed/packed-with-inference-vars-issue-61402.rs b/src/test/ui/packed/packed-with-inference-vars-issue-61402.rs
new file mode 100644
index 00000000000..659864c1d9b
--- /dev/null
+++ b/src/test/ui/packed/packed-with-inference-vars-issue-61402.rs
@@ -0,0 +1,22 @@
+// run-pass
+// If a struct is packed and its last field has drop glue, then that
+// field needs to be Sized (to allow it to be destroyed out-of-place).
+//
+// This is checked by the compiler during wfcheck. That check used
+// to have problems with associated types in the last field - test
+// that this doesn't ICE.
+
+#![allow(unused_imports, dead_code)]
+
+pub struct S;
+
+pub trait Trait<R> { type Assoc; }
+
+impl<X> Trait<X> for S { type Assoc = X; }
+
+#[repr(C, packed)]
+struct PackedAssocSized {
+    pos: Box<<S as Trait<usize>>::Assoc>,
+}
+
+fn main() { println!("Hello, world!"); }