diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /src/test/ui/packed | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/ui/packed')
25 files changed, 1142 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 000000000..cba166fac --- /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/issue-27060-2.rs b/src/test/ui/packed/issue-27060-2.rs new file mode 100644 index 000000000..a001ce1e0 --- /dev/null +++ b/src/test/ui/packed/issue-27060-2.rs @@ -0,0 +1,6 @@ +#[repr(packed)] +pub struct Bad<T: ?Sized> { + data: T, //~ ERROR the size for values of type +} + +fn main() {} diff --git a/src/test/ui/packed/issue-27060-2.stderr b/src/test/ui/packed/issue-27060-2.stderr new file mode 100644 index 000000000..0836ceaec --- /dev/null +++ b/src/test/ui/packed/issue-27060-2.stderr @@ -0,0 +1,27 @@ +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/issue-27060-2.rs:3:11 + | +LL | pub struct Bad<T: ?Sized> { + | - this type parameter needs to be `std::marker::Sized` +LL | data: T, + | ^ doesn't have a size known at compile-time + | + = note: the last field of a packed struct may only have a dynamically sized type if it does not need drop to be run + = help: change the field's type to have a statically known size +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - pub struct Bad<T: ?Sized> { +LL + pub struct Bad<T> { + | +help: borrowed types always have a statically known size + | +LL | data: &T, + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | data: Box<T>, + | ++++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/packed/issue-27060-rpass.rs b/src/test/ui/packed/issue-27060-rpass.rs new file mode 100644 index 000000000..d9159f666 --- /dev/null +++ b/src/test/ui/packed/issue-27060-rpass.rs @@ -0,0 +1,23 @@ +// run-pass +#![allow(dead_code)] +#[repr(packed)] +pub struct Good { + data: &'static u32, + data2: [&'static u32; 2], + aligned: [u8; 32], +} + +// kill this test when that turns to a hard error +#[allow(unaligned_references)] +fn main() { + let good = Good { data: &0, data2: [&0, &0], aligned: [0; 32] }; + + let _ = &good.data; // ok + let _ = &good.data2[0]; // ok + + let _ = &good.data; + let _ = &good.data2[0]; + let _ = &*good.data; // ok, behind a pointer + let _ = &good.aligned; // ok, has align 1 + let _ = &good.aligned[2]; // ok, has align 1 +} diff --git a/src/test/ui/packed/issue-27060-rpass.stderr b/src/test/ui/packed/issue-27060-rpass.stderr new file mode 100644 index 000000000..667b70afb --- /dev/null +++ b/src/test/ui/packed/issue-27060-rpass.stderr @@ -0,0 +1,68 @@ +Future incompatibility report: Future breakage diagnostic: +warning: reference to packed field is unaligned + --> $DIR/issue-27060-rpass.rs:15:13 + | +LL | let _ = &good.data; // ok + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-27060-rpass.rs:11:9 + | +LL | #[allow(unaligned_references)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +Future breakage diagnostic: +warning: reference to packed field is unaligned + --> $DIR/issue-27060-rpass.rs:16:13 + | +LL | let _ = &good.data2[0]; // ok + | ^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-27060-rpass.rs:11:9 + | +LL | #[allow(unaligned_references)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +Future breakage diagnostic: +warning: reference to packed field is unaligned + --> $DIR/issue-27060-rpass.rs:18:13 + | +LL | let _ = &good.data; + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-27060-rpass.rs:11:9 + | +LL | #[allow(unaligned_references)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +Future breakage diagnostic: +warning: reference to packed field is unaligned + --> $DIR/issue-27060-rpass.rs:19:13 + | +LL | let _ = &good.data2[0]; + | ^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-27060-rpass.rs:11:9 + | +LL | #[allow(unaligned_references)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + diff --git a/src/test/ui/packed/issue-27060.rs b/src/test/ui/packed/issue-27060.rs new file mode 100644 index 000000000..886a00239 --- /dev/null +++ b/src/test/ui/packed/issue-27060.rs @@ -0,0 +1,27 @@ +#[repr(packed)] +pub struct Good { + data: &'static u32, + data2: [&'static u32; 2], + aligned: [u8; 32], +} + +fn main() { + let good = Good { + data: &0, + data2: [&0, &0], + aligned: [0; 32] + }; + + let _ = &good.data; //~ ERROR reference to packed field + //~| hard error + let _ = &good.data2[0]; //~ ERROR reference to packed field + //~| hard error + + let _ = &good.data; //~ ERROR reference to packed field + //~| hard error + let _ = &good.data2[0]; //~ ERROR reference to packed field + //~| hard error + let _ = &*good.data; // ok, behind a pointer + let _ = &good.aligned; // ok, has align 1 + let _ = &good.aligned[2]; // ok, has align 1 +} diff --git a/src/test/ui/packed/issue-27060.stderr b/src/test/ui/packed/issue-27060.stderr new file mode 100644 index 000000000..1bab16e6d --- /dev/null +++ b/src/test/ui/packed/issue-27060.stderr @@ -0,0 +1,99 @@ +error: reference to packed field is unaligned + --> $DIR/issue-27060.rs:15:13 + | +LL | let _ = &good.data; + | ^^^^^^^^^^ + | + = note: `#[deny(unaligned_references)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +error: reference to packed field is unaligned + --> $DIR/issue-27060.rs:17:13 + | +LL | let _ = &good.data2[0]; + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +error: reference to packed field is unaligned + --> $DIR/issue-27060.rs:20:13 + | +LL | let _ = &good.data; + | ^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +error: reference to packed field is unaligned + --> $DIR/issue-27060.rs:22:13 + | +LL | let _ = &good.data2[0]; + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +error: aborting due to 4 previous errors + +Future incompatibility report: Future breakage diagnostic: +error: reference to packed field is unaligned + --> $DIR/issue-27060.rs:15:13 + | +LL | let _ = &good.data; + | ^^^^^^^^^^ + | + = note: `#[deny(unaligned_references)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +Future breakage diagnostic: +error: reference to packed field is unaligned + --> $DIR/issue-27060.rs:17:13 + | +LL | let _ = &good.data2[0]; + | ^^^^^^^^^^^^^^ + | + = note: `#[deny(unaligned_references)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +Future breakage diagnostic: +error: reference to packed field is unaligned + --> $DIR/issue-27060.rs:20:13 + | +LL | let _ = &good.data; + | ^^^^^^^^^^ + | + = note: `#[deny(unaligned_references)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +Future breakage diagnostic: +error: reference to packed field is unaligned + --> $DIR/issue-27060.rs:22:13 + | +LL | let _ = &good.data2[0]; + | ^^^^^^^^^^^^^^ + | + = note: `#[deny(unaligned_references)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + diff --git a/src/test/ui/packed/issue-46152.rs b/src/test/ui/packed/issue-46152.rs new file mode 100644 index 000000000..fb1c9fb78 --- /dev/null +++ b/src/test/ui/packed/issue-46152.rs @@ -0,0 +1,24 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] +#![feature(unsize, coerce_unsized)] + +#[repr(packed)] +struct UnalignedPtr<'a, T: ?Sized> + where T: 'a, +{ + data: &'a T, +} + +fn main() { + + impl<'a, T, U> std::ops::CoerceUnsized<UnalignedPtr<'a, U>> for UnalignedPtr<'a, T> + where + T: std::marker::Unsize<U> + ?Sized, + U: ?Sized, + { } + + let arr = [1, 2, 3]; + let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr }; + let arr_unaligned: UnalignedPtr<[i32]> = arr_unaligned; +} diff --git a/src/test/ui/packed/packed-struct-address-of-element.rs b/src/test/ui/packed/packed-struct-address-of-element.rs new file mode 100644 index 000000000..d86698cbf --- /dev/null +++ b/src/test/ui/packed/packed-struct-address-of-element.rs @@ -0,0 +1,36 @@ +// run-pass +#![allow(dead_code)] +#![feature(raw_ref_op)] +// 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 = &raw const foo.baz; + unsafe { assert_eq!(brw.read_unaligned(), 2); } + + let foo = Foo2 { bar: 1, baz: 2 }; + let brw = &raw const foo.baz; + unsafe { assert_eq!(brw.read_unaligned(), 2); } + + let mut foo = Foo4C { bar: 1, baz: 2 }; + let brw = &raw mut foo.baz; + unsafe { assert_eq!(brw.read_unaligned(), 2); } +} diff --git a/src/test/ui/packed/packed-struct-borrow-element-64bit.rs b/src/test/ui/packed/packed-struct-borrow-element-64bit.rs new file mode 100644 index 000000000..00bddfe40 --- /dev/null +++ b/src/test/ui/packed/packed-struct-borrow-element-64bit.rs @@ -0,0 +1,18 @@ +// run-pass (note: this is spec-UB, but it works for now) +// ignore-32bit (needs `usize` to be 8-aligned to reproduce all the errors below) +#![allow(dead_code)] +// ignore-emscripten weird assertion? + +#[repr(C, packed(4))] +struct Foo4C { + bar: u8, + baz: usize +} + +#[warn(unaligned_references)] +pub fn main() { + let foo = Foo4C { bar: 1, baz: 2 }; + let brw = &foo.baz; //~WARN reference to packed field is unaligned + //~^ previously accepted + assert_eq!(*brw, 2); +} diff --git a/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr b/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr new file mode 100644 index 000000000..dcd1c19fa --- /dev/null +++ b/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr @@ -0,0 +1,35 @@ +warning: reference to packed field is unaligned + --> $DIR/packed-struct-borrow-element-64bit.rs:15:15 + | +LL | let brw = &foo.baz; + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/packed-struct-borrow-element-64bit.rs:12:8 + | +LL | #[warn(unaligned_references)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +warning: 1 warning emitted + +Future incompatibility report: Future breakage diagnostic: +warning: reference to packed field is unaligned + --> $DIR/packed-struct-borrow-element-64bit.rs:15:15 + | +LL | let brw = &foo.baz; + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/packed-struct-borrow-element-64bit.rs:12:8 + | +LL | #[warn(unaligned_references)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + 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 000000000..a6ee90cef --- /dev/null +++ b/src/test/ui/packed/packed-struct-borrow-element.rs @@ -0,0 +1,34 @@ +// run-pass (note: this is spec-UB, but it works for now) +#![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 +} + +#[warn(unaligned_references)] +pub fn main() { + let foo = Foo1 { bar: 1, baz: 2 }; + let brw = &foo.baz; //~WARN reference to packed field is unaligned + //~^ previously accepted + assert_eq!(*brw, 2); + + let foo = Foo2 { bar: 1, baz: 2 }; + let brw = &foo.baz; //~WARN reference to packed field is unaligned + //~^ previously accepted + assert_eq!(*brw, 2); +} diff --git a/src/test/ui/packed/packed-struct-borrow-element.stderr b/src/test/ui/packed/packed-struct-borrow-element.stderr new file mode 100644 index 000000000..fb483227e --- /dev/null +++ b/src/test/ui/packed/packed-struct-borrow-element.stderr @@ -0,0 +1,63 @@ +warning: reference to packed field is unaligned + --> $DIR/packed-struct-borrow-element.rs:26:15 + | +LL | let brw = &foo.baz; + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/packed-struct-borrow-element.rs:23:8 + | +LL | #[warn(unaligned_references)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +warning: reference to packed field is unaligned + --> $DIR/packed-struct-borrow-element.rs:31:15 + | +LL | let brw = &foo.baz; + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +warning: 2 warnings emitted + +Future incompatibility report: Future breakage diagnostic: +warning: reference to packed field is unaligned + --> $DIR/packed-struct-borrow-element.rs:26:15 + | +LL | let brw = &foo.baz; + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/packed-struct-borrow-element.rs:23:8 + | +LL | #[warn(unaligned_references)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +Future breakage diagnostic: +warning: reference to packed field is unaligned + --> $DIR/packed-struct-borrow-element.rs:31:15 + | +LL | let brw = &foo.baz; + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/packed-struct-borrow-element.rs:23:8 + | +LL | #[warn(unaligned_references)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + 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 000000000..9f9f41e25 --- /dev/null +++ b/src/test/ui/packed/packed-struct-drop-aligned.rs @@ -0,0 +1,57 @@ +// run-pass +#![feature(generators)] +#![feature(generator_trait)] +use std::cell::Cell; +use std::mem; +use std::ops::Generator; +use std::pin::Pin; + +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(transparent)] +struct NotCopy(#[allow(unused_tuple_struct_fields)] u8); + +#[repr(packed)] +struct Packed<'a>(NotCopy, Aligned<'a>); + +fn main() { + let drop_count = &Cell::new(0); + { + let mut p = Packed(NotCopy(0), Aligned { drop_count }); + p.1 = Aligned { drop_count }; + assert_eq!(drop_count.get(), 1); + } + assert_eq!(drop_count.get(), 2); + + let drop_count = &Cell::new(0); + let mut g = || { + let mut p = Packed(NotCopy(0), Aligned { drop_count }); + let _ = &p; + p.1 = Aligned { drop_count }; + assert_eq!(drop_count.get(), 1); + // Test that a generator drop function moves a value from a packed + // struct to a separate local before dropping it. We move out the + // first field to generate and open drop for the second field. + drop(p.0); + yield; + }; + Pin::new(&mut g).resume(()); + assert_eq!(drop_count.get(), 1); + drop(g); + 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 000000000..e064eede4 --- /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 000000000..7c93e46c3 --- /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 000000000..d49c222e6 --- /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 000000000..9a572ced7 --- /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 000000000..5e1a1f518 --- /dev/null +++ b/src/test/ui/packed/packed-struct-optimized-enum.rs @@ -0,0 +1,36 @@ +// run-pass +#[repr(packed)] +struct Packed<T: Copy>(#[allow(unused_tuple_struct_fields)] 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 000000000..46112d51d --- /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 000000000..c832c7cfa --- /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 000000000..18676cfc2 --- /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 000000000..931be5b94 --- /dev/null +++ b/src/test/ui/packed/packed-tuple-struct-layout.rs @@ -0,0 +1,23 @@ +// run-pass +use std::mem; + +#[repr(packed)] +#[allow(unused_tuple_struct_fields)] +struct S4(u8,[u8; 3]); + +#[repr(packed)] +#[allow(unused_tuple_struct_fields)] +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 000000000..f7a3c903f --- /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 000000000..659864c1d --- /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!"); } |