summaryrefslogtreecommitdiffstats
path: root/src/test/ui/union
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /src/test/ui/union
parentInitial commit. (diff)
downloadrustc-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/union')
-rw-r--r--src/test/ui/union/auxiliary/union.rs4
-rw-r--r--src/test/ui/union/field_checks.rs65
-rw-r--r--src/test/ui/union/field_checks.stderr63
-rw-r--r--src/test/ui/union/issue-41073.rs22
-rw-r--r--src/test/ui/union/issue-41073.stderr15
-rw-r--r--src/test/ui/union/issue-81199.rs21
-rw-r--r--src/test/ui/union/issue-81199.stderr19
-rw-r--r--src/test/ui/union/issue-99375.rs21
-rw-r--r--src/test/ui/union/union-align.rs65
-rw-r--r--src/test/ui/union/union-backcomp.rs28
-rw-r--r--src/test/ui/union/union-basic.rs62
-rw-r--r--src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr80
-rw-r--r--src/test/ui/union/union-borrow-move-parent-sibling.rs96
-rw-r--r--src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr80
-rw-r--r--src/test/ui/union/union-const-codegen.rs19
-rw-r--r--src/test/ui/union/union-const-eval-field.rs45
-rw-r--r--src/test/ui/union/union-const-eval.rs15
-rw-r--r--src/test/ui/union/union-const-pat.rs13
-rw-r--r--src/test/ui/union/union-const-pat.stderr8
-rw-r--r--src/test/ui/union/union-copy.rs14
-rw-r--r--src/test/ui/union/union-copy.stderr18
-rw-r--r--src/test/ui/union/union-deref.mirunsafeck.stderr56
-rw-r--r--src/test/ui/union/union-deref.rs29
-rw-r--r--src/test/ui/union/union-deref.thirunsafeck.stderr56
-rw-r--r--src/test/ui/union/union-derive-clone.mirunsafeck.stderr49
-rw-r--r--src/test/ui/union/union-derive-clone.rs39
-rw-r--r--src/test/ui/union/union-derive-clone.thirunsafeck.stderr49
-rw-r--r--src/test/ui/union/union-derive-eq.mirunsafeck.stderr23
-rw-r--r--src/test/ui/union/union-derive-eq.rs21
-rw-r--r--src/test/ui/union/union-derive-eq.thirunsafeck.stderr23
-rw-r--r--src/test/ui/union/union-derive-rpass.rs42
-rw-r--r--src/test/ui/union/union-derive.rs16
-rw-r--r--src/test/ui/union/union-derive.stderr38
-rw-r--r--src/test/ui/union/union-drop-assign.rs37
-rw-r--r--src/test/ui/union/union-drop.rs60
-rw-r--r--src/test/ui/union/union-empty.rs3
-rw-r--r--src/test/ui/union/union-empty.stderr8
-rw-r--r--src/test/ui/union/union-fields-1.mirunsafeck.stderr42
-rw-r--r--src/test/ui/union/union-fields-1.rs35
-rw-r--r--src/test/ui/union/union-fields-1.thirunsafeck.stderr42
-rw-r--r--src/test/ui/union/union-fields-2.mirunsafeck.stderr84
-rw-r--r--src/test/ui/union/union-fields-2.rs26
-rw-r--r--src/test/ui/union/union-fields-2.thirunsafeck.stderr84
-rw-r--r--src/test/ui/union/union-generic-rpass.rs34
-rw-r--r--src/test/ui/union/union-generic.mirunsafeck.stderr27
-rw-r--r--src/test/ui/union/union-generic.rs15
-rw-r--r--src/test/ui/union/union-generic.thirunsafeck.stderr27
-rw-r--r--src/test/ui/union/union-inherent-method.rs16
-rw-r--r--src/test/ui/union/union-lint-dead-code.mirunsafeck.stderr17
-rw-r--r--src/test/ui/union/union-lint-dead-code.rs18
-rw-r--r--src/test/ui/union/union-lint-dead-code.thirunsafeck.stderr17
-rw-r--r--src/test/ui/union/union-macro.rs27
-rw-r--r--src/test/ui/union/union-manuallydrop-rpass.rs44
-rw-r--r--src/test/ui/union/union-move.mirunsafeck.stderr35
-rw-r--r--src/test/ui/union/union-move.rs56
-rw-r--r--src/test/ui/union/union-move.thirunsafeck.stderr35
-rw-r--r--src/test/ui/union/union-nodrop.rs62
-rw-r--r--src/test/ui/union/union-nonrepresentable.rs6
-rw-r--r--src/test/ui/union/union-nonrepresentable.stderr17
-rw-r--r--src/test/ui/union/union-nonzero.rs54
-rw-r--r--src/test/ui/union/union-overwrite.rs80
-rw-r--r--src/test/ui/union/union-packed.rs173
-rw-r--r--src/test/ui/union/union-pat-refutability.rs57
-rw-r--r--src/test/ui/union/union-repr-c.rs18
-rw-r--r--src/test/ui/union/union-repr-c.stderr21
-rw-r--r--src/test/ui/union/union-sized-field.rs19
-rw-r--r--src/test/ui/union/union-sized-field.stderr78
-rw-r--r--src/test/ui/union/union-suggest-field.mirunsafeck.stderr27
-rw-r--r--src/test/ui/union/union-suggest-field.rs24
-rw-r--r--src/test/ui/union/union-suggest-field.thirunsafeck.stderr27
-rw-r--r--src/test/ui/union/union-trait-impl.rs19
-rw-r--r--src/test/ui/union/union-transmute.rs27
-rw-r--r--src/test/ui/union/union-unsafe.mir.stderr75
-rw-r--r--src/test/ui/union/union-unsafe.rs78
-rw-r--r--src/test/ui/union/union-unsafe.thir.stderr75
-rw-r--r--src/test/ui/union/union-unsized.mirunsafeck.stderr39
-rw-r--r--src/test/ui/union/union-unsized.rs17
-rw-r--r--src/test/ui/union/union-unsized.thirunsafeck.stderr39
-rw-r--r--src/test/ui/union/union-with-drop-fields.mirunsafeck.stderr39
-rw-r--r--src/test/ui/union/union-with-drop-fields.rs31
-rw-r--r--src/test/ui/union/union-with-drop-fields.thirunsafeck.stderr39
81 files changed, 3144 insertions, 0 deletions
diff --git a/src/test/ui/union/auxiliary/union.rs b/src/test/ui/union/auxiliary/union.rs
new file mode 100644
index 000000000..e785e35ae
--- /dev/null
+++ b/src/test/ui/union/auxiliary/union.rs
@@ -0,0 +1,4 @@
+pub union U {
+ pub a: u8,
+ pub b: u16,
+}
diff --git a/src/test/ui/union/field_checks.rs b/src/test/ui/union/field_checks.rs
new file mode 100644
index 000000000..d5d1e44ac
--- /dev/null
+++ b/src/test/ui/union/field_checks.rs
@@ -0,0 +1,65 @@
+use std::mem::ManuallyDrop;
+
+union U1 { // OK
+ a: u8,
+}
+
+union U2<T: Copy> { // OK
+ a: T,
+}
+
+union U22<T> { // OK
+ a: ManuallyDrop<T>,
+}
+
+union U23<T> { // OK
+ a: (ManuallyDrop<T>, i32),
+}
+
+union U24<T> { // OK
+ a: [ManuallyDrop<T>; 2],
+}
+
+union U3 {
+ a: String, //~ ERROR unions cannot contain fields that may need dropping
+}
+
+union U32 { // field that does not drop but is not `Copy`, either
+ a: std::cell::RefCell<i32>, //~ ERROR unions cannot contain fields that may need dropping
+}
+
+union U4<T> {
+ a: T, //~ ERROR unions cannot contain fields that may need dropping
+}
+
+union U5 { // Having a drop impl is OK
+ a: u8,
+}
+
+impl Drop for U5 {
+ fn drop(&mut self) {}
+}
+
+union U5Nested { // a nested union that drops is NOT OK
+ nest: U5, //~ ERROR unions cannot contain fields that may need dropping
+}
+
+union U5Nested2 { // for now we don't special-case empty arrays
+ nest: [U5; 0], //~ ERROR unions cannot contain fields that may need dropping
+}
+
+union U6 { // OK
+ s: &'static i32,
+ m: &'static mut i32,
+}
+
+union U7<T> { // OK
+ f: (&'static mut i32, ManuallyDrop<T>, i32),
+}
+
+union U8<T> { // OK
+ f1: [(&'static mut i32, i32); 8],
+ f2: [ManuallyDrop<T>; 2],
+}
+
+fn main() {}
diff --git a/src/test/ui/union/field_checks.stderr b/src/test/ui/union/field_checks.stderr
new file mode 100644
index 000000000..1f97e97ac
--- /dev/null
+++ b/src/test/ui/union/field_checks.stderr
@@ -0,0 +1,63 @@
+error[E0740]: unions cannot contain fields that may need dropping
+ --> $DIR/field_checks.rs:24:5
+ |
+LL | a: String,
+ | ^^^^^^^^^
+ |
+ = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+ |
+LL | a: std::mem::ManuallyDrop<String>,
+ | +++++++++++++++++++++++ +
+
+error[E0740]: unions cannot contain fields that may need dropping
+ --> $DIR/field_checks.rs:28:5
+ |
+LL | a: std::cell::RefCell<i32>,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+ |
+LL | a: std::mem::ManuallyDrop<std::cell::RefCell<i32>>,
+ | +++++++++++++++++++++++ +
+
+error[E0740]: unions cannot contain fields that may need dropping
+ --> $DIR/field_checks.rs:32:5
+ |
+LL | a: T,
+ | ^^^^
+ |
+ = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+ |
+LL | a: std::mem::ManuallyDrop<T>,
+ | +++++++++++++++++++++++ +
+
+error[E0740]: unions cannot contain fields that may need dropping
+ --> $DIR/field_checks.rs:44:5
+ |
+LL | nest: U5,
+ | ^^^^^^^^
+ |
+ = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+ |
+LL | nest: std::mem::ManuallyDrop<U5>,
+ | +++++++++++++++++++++++ +
+
+error[E0740]: unions cannot contain fields that may need dropping
+ --> $DIR/field_checks.rs:48:5
+ |
+LL | nest: [U5; 0],
+ | ^^^^^^^^^^^^^
+ |
+ = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+ |
+LL | nest: std::mem::ManuallyDrop<[U5; 0]>,
+ | +++++++++++++++++++++++ +
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0740`.
diff --git a/src/test/ui/union/issue-41073.rs b/src/test/ui/union/issue-41073.rs
new file mode 100644
index 000000000..4dfdc606b
--- /dev/null
+++ b/src/test/ui/union/issue-41073.rs
@@ -0,0 +1,22 @@
+union Test {
+ a: A, //~ ERROR unions cannot contain fields that may need dropping
+ b: B
+}
+
+#[derive(Debug)]
+struct A(i32);
+impl Drop for A {
+ fn drop(&mut self) { println!("A"); }
+}
+
+#[derive(Debug)]
+struct B(f32);
+impl Drop for B {
+ fn drop(&mut self) { println!("B"); }
+}
+
+fn main() {
+ let mut test = Test { a: A(3) };
+ println!("{:?}", unsafe { test.b });
+ unsafe { test.b = B(0.5); }
+}
diff --git a/src/test/ui/union/issue-41073.stderr b/src/test/ui/union/issue-41073.stderr
new file mode 100644
index 000000000..b3887fa0f
--- /dev/null
+++ b/src/test/ui/union/issue-41073.stderr
@@ -0,0 +1,15 @@
+error[E0740]: unions cannot contain fields that may need dropping
+ --> $DIR/issue-41073.rs:2:5
+ |
+LL | a: A,
+ | ^^^^
+ |
+ = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+ |
+LL | a: std::mem::ManuallyDrop<A>,
+ | +++++++++++++++++++++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0740`.
diff --git a/src/test/ui/union/issue-81199.rs b/src/test/ui/union/issue-81199.rs
new file mode 100644
index 000000000..628e7c6ed
--- /dev/null
+++ b/src/test/ui/union/issue-81199.rs
@@ -0,0 +1,21 @@
+#[repr(C)]
+union PtrRepr<T: ?Sized> {
+ const_ptr: *const T,
+ mut_ptr: *mut T,
+ components: PtrComponents<T>,
+ //~^ ERROR the trait bound
+}
+
+#[repr(C)]
+struct PtrComponents<T: Pointee + ?Sized> {
+ data_address: *const (),
+ metadata: <T as Pointee>::Metadata,
+}
+
+
+
+pub trait Pointee {
+ type Metadata;
+}
+
+fn main() {}
diff --git a/src/test/ui/union/issue-81199.stderr b/src/test/ui/union/issue-81199.stderr
new file mode 100644
index 000000000..5bb986753
--- /dev/null
+++ b/src/test/ui/union/issue-81199.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `T: Pointee` is not satisfied
+ --> $DIR/issue-81199.rs:5:17
+ |
+LL | components: PtrComponents<T>,
+ | ^^^^^^^^^^^^^^^^ the trait `Pointee` is not implemented for `T`
+ |
+note: required by a bound in `PtrComponents`
+ --> $DIR/issue-81199.rs:10:25
+ |
+LL | struct PtrComponents<T: Pointee + ?Sized> {
+ | ^^^^^^^ required by this bound in `PtrComponents`
+help: consider further restricting this bound
+ |
+LL | union PtrRepr<T: ?Sized + Pointee> {
+ | +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/union/issue-99375.rs b/src/test/ui/union/issue-99375.rs
new file mode 100644
index 000000000..175018a7d
--- /dev/null
+++ b/src/test/ui/union/issue-99375.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+union URes<R: Copy> {
+ uninit: (),
+ init: R,
+}
+
+struct Params<F, R: Copy> {
+ function: F,
+ result: URes<R>,
+}
+
+unsafe extern "C" fn do_call<F, R>(params: *mut Params<F, R>)
+where
+ R: Copy,
+ F: Fn() -> R,
+{
+ (*params).result.init = ((*params).function)();
+}
+
+fn main() {}
diff --git a/src/test/ui/union/union-align.rs b/src/test/ui/union/union-align.rs
new file mode 100644
index 000000000..6a44f27db
--- /dev/null
+++ b/src/test/ui/union/union-align.rs
@@ -0,0 +1,65 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(dead_code)]
+
+use std::mem::{size_of, size_of_val, align_of, align_of_val};
+
+#[repr(align(16))]
+pub union U16 {
+ a: u8,
+ b: u32
+}
+
+fn main() {
+ assert_eq!(align_of::<U16>(), 16);
+ assert_eq!(size_of::<U16>(), 16);
+ let u = U16 { a: 10 };
+ unsafe {
+ assert_eq!(align_of_val(&u.a), 1);
+ assert_eq!(size_of_val(&u.a), 1);
+ assert_eq!(u.a, 10);
+ }
+
+ let u = U16 { b: 11 };
+ unsafe {
+ assert_eq!(align_of_val(&u.b), 4);
+ assert_eq!(size_of_val(&u.b), 4);
+ assert_eq!(u.b, 11);
+ }
+
+ hybrid::check_hybrid();
+}
+
+mod hybrid {
+ use std::mem::{size_of, align_of};
+
+ #[repr(align(16))]
+ #[derive(Copy, Clone)]
+ struct S1 {
+ a: u16,
+ b: u8,
+ }
+
+ #[repr(align(32))]
+ union U {
+ s: S1,
+ c: u16,
+ }
+
+ #[repr(align(64))]
+ struct S2 {
+ d: u8,
+ u: U,
+ }
+
+ pub fn check_hybrid() {
+ assert_eq!(align_of::<S1>(), 16);
+ assert_eq!(size_of::<S1>(), 16);
+ assert_eq!(align_of::<U>(), 32);
+ assert_eq!(size_of::<U>(), 32);
+ assert_eq!(align_of::<S2>(), 64);
+ assert_eq!(size_of::<S2>(), 64);
+ }
+}
diff --git a/src/test/ui/union/union-backcomp.rs b/src/test/ui/union/union-backcomp.rs
new file mode 100644
index 000000000..b19eab9f5
--- /dev/null
+++ b/src/test/ui/union/union-backcomp.rs
@@ -0,0 +1,28 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(path_statements)]
+#![allow(dead_code)]
+
+macro_rules! union {
+ () => (struct S;)
+}
+
+union!();
+
+fn union() {}
+
+fn main() {
+ union();
+
+ let union = 10;
+
+ union;
+
+ union as u8;
+
+ union U {
+ a: u8,
+ }
+}
diff --git a/src/test/ui/union/union-basic.rs b/src/test/ui/union/union-basic.rs
new file mode 100644
index 000000000..dcc552ac7
--- /dev/null
+++ b/src/test/ui/union/union-basic.rs
@@ -0,0 +1,62 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(unused_imports)]
+
+// aux-build:union.rs
+
+extern crate union;
+use std::mem::{size_of, align_of, zeroed};
+
+union U {
+ a: u8,
+ b: u16
+}
+
+fn local() {
+ assert_eq!(size_of::<U>(), 2);
+ assert_eq!(align_of::<U>(), 2);
+
+ let u = U { a: 10 };
+ unsafe {
+ assert_eq!(u.a, 10);
+ let U { a } = u;
+ assert_eq!(a, 10);
+ }
+
+ let mut w = U { b: 0 };
+ unsafe {
+ assert_eq!(w.a, 0);
+ assert_eq!(w.b, 0);
+ w.a = 1;
+ assert_eq!(w.a, 1);
+ assert_eq!(w.b.to_le(), 1);
+ }
+}
+
+fn xcrate() {
+ assert_eq!(size_of::<union::U>(), 2);
+ assert_eq!(align_of::<union::U>(), 2);
+
+ let u = union::U { a: 10 };
+ unsafe {
+ assert_eq!(u.a, 10);
+ let union::U { a } = u;
+ assert_eq!(a, 10);
+ }
+
+ let mut w = union::U { b: 0 };
+ unsafe {
+ assert_eq!(w.a, 0);
+ assert_eq!(w.b, 0);
+ w.a = 1;
+ assert_eq!(w.a, 1);
+ assert_eq!(w.b.to_le(), 1);
+ }
+}
+
+fn main() {
+ local();
+ xcrate();
+}
diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr
new file mode 100644
index 000000000..ca02de4c6
--- /dev/null
+++ b/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr
@@ -0,0 +1,80 @@
+error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`)
+ --> $DIR/union-borrow-move-parent-sibling.rs:56:13
+ |
+LL | let a = &mut (*u.x).0;
+ | --- mutable borrow occurs here (via `u.x`)
+LL | let b = &u.y;
+ | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here
+LL | use_borrow(a);
+ | - mutable borrow later used here
+ |
+ = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x`
+
+error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>`
+ --> $DIR/union-borrow-move-parent-sibling.rs:62:13
+ |
+LL | let a = u.x.0;
+ | ^^^^^
+ | |
+ | move occurs because value has type `(MockVec<u8>, MockVec<u8>)`, which does not implement the `Copy` trait
+ | help: consider borrowing here: `&u.x.0`
+
+error[E0382]: use of moved value: `u`
+ --> $DIR/union-borrow-move-parent-sibling.rs:64:13
+ |
+LL | let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
+ | - move occurs because `u` has type `U`, which does not implement the `Copy` trait
+LL | let a = u.x.0;
+LL | let a = u.x;
+ | --- value moved here
+LL | let b = u.y;
+ | ^^^ value used here after move
+
+error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`)
+ --> $DIR/union-borrow-move-parent-sibling.rs:70:13
+ |
+LL | let a = &mut ((*u.x).0).0;
+ | --- mutable borrow occurs here (via `u.x`)
+LL | let b = &u.y;
+ | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here
+LL | use_borrow(a);
+ | - mutable borrow later used here
+ |
+ = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x`
+
+error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>`
+ --> $DIR/union-borrow-move-parent-sibling.rs:76:13
+ |
+LL | let a = (u.x.0).0;
+ | ^^^^^^^^^
+ | |
+ | move occurs because value has type `MockVec<u8>`, which does not implement the `Copy` trait
+ | help: consider borrowing here: `&(u.x.0).0`
+
+error[E0382]: use of moved value: `u`
+ --> $DIR/union-borrow-move-parent-sibling.rs:78:13
+ |
+LL | let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
+ | - move occurs because `u` has type `U`, which does not implement the `Copy` trait
+LL | let a = (u.x.0).0;
+LL | let a = u.x;
+ | --- value moved here
+LL | let b = u.y;
+ | ^^^ value used here after move
+
+error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`)
+ --> $DIR/union-borrow-move-parent-sibling.rs:84:13
+ |
+LL | let a = &mut *u.y;
+ | --- mutable borrow occurs here (via `u.y`)
+LL | let b = &u.x;
+ | ^^^^ immutable borrow of `u.x` -- which overlaps with `u.y` -- occurs here
+LL | use_borrow(a);
+ | - mutable borrow later used here
+ |
+ = note: `u.x` is a field of the union `U`, so it overlaps the field `u.y`
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0382, E0502, E0507.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.rs b/src/test/ui/union/union-borrow-move-parent-sibling.rs
new file mode 100644
index 000000000..83781c5e5
--- /dev/null
+++ b/src/test/ui/union/union-borrow-move-parent-sibling.rs
@@ -0,0 +1,96 @@
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(unused)]
+
+use std::ops::{Deref, DerefMut};
+use std::mem::ManuallyDrop;
+
+#[derive(Default)]
+struct MockBox<T> {
+ value: [T; 1],
+}
+
+impl<T> MockBox<T> {
+ fn new(value: T) -> Self { MockBox { value: [value] } }
+}
+
+impl<T> Deref for MockBox<T> {
+ type Target = T;
+ fn deref(&self) -> &T { &self.value[0] }
+}
+
+impl<T> DerefMut for MockBox<T> {
+ fn deref_mut(&mut self) -> &mut T { &mut self.value[0] }
+}
+
+#[derive(Default)]
+struct MockVec<T> {
+ value: [T; 0],
+}
+
+impl<T> MockVec<T> {
+ fn new() -> Self { MockVec { value: [] } }
+}
+
+impl<T> Deref for MockVec<T> {
+ type Target = [T];
+ fn deref(&self) -> &[T] { &self.value }
+}
+
+impl<T> DerefMut for MockVec<T> {
+ fn deref_mut(&mut self) -> &mut [T] { &mut self.value }
+}
+
+
+union U {
+ x: ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>,
+ y: ManuallyDrop<MockBox<MockVec<u8>>>,
+}
+
+fn use_borrow<T>(_: &T) {}
+
+unsafe fn parent_sibling_borrow() {
+ let mut u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
+ let a = &mut (*u.x).0;
+ let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`)
+ use_borrow(a);
+}
+
+unsafe fn parent_sibling_move() {
+ let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
+ let a = u.x.0; //~ERROR cannot move out of dereference
+ let a = u.x;
+ let b = u.y; //~ ERROR use of moved value: `u`
+}
+
+unsafe fn grandparent_sibling_borrow() {
+ let mut u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
+ let a = &mut ((*u.x).0).0;
+ let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`)
+ use_borrow(a);
+}
+
+unsafe fn grandparent_sibling_move() {
+ let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
+ let a = (u.x.0).0; //~ERROR cannot move out of dereference
+ let a = u.x;
+ let b = u.y; //~ ERROR use of moved value: `u`
+}
+
+unsafe fn deref_sibling_borrow() {
+ let mut u = U { y: ManuallyDrop::new(MockBox::default()) };
+ let a = &mut *u.y;
+ let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`)
+ use_borrow(a);
+}
+
+unsafe fn deref_sibling_move() {
+ let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
+ // No way to test deref-move without Box in union
+ // let a = *u.y;
+ // let b = u.x; ERROR use of moved value: `u`
+}
+
+
+fn main() {}
diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr
new file mode 100644
index 000000000..ca02de4c6
--- /dev/null
+++ b/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr
@@ -0,0 +1,80 @@
+error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`)
+ --> $DIR/union-borrow-move-parent-sibling.rs:56:13
+ |
+LL | let a = &mut (*u.x).0;
+ | --- mutable borrow occurs here (via `u.x`)
+LL | let b = &u.y;
+ | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here
+LL | use_borrow(a);
+ | - mutable borrow later used here
+ |
+ = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x`
+
+error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>`
+ --> $DIR/union-borrow-move-parent-sibling.rs:62:13
+ |
+LL | let a = u.x.0;
+ | ^^^^^
+ | |
+ | move occurs because value has type `(MockVec<u8>, MockVec<u8>)`, which does not implement the `Copy` trait
+ | help: consider borrowing here: `&u.x.0`
+
+error[E0382]: use of moved value: `u`
+ --> $DIR/union-borrow-move-parent-sibling.rs:64:13
+ |
+LL | let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
+ | - move occurs because `u` has type `U`, which does not implement the `Copy` trait
+LL | let a = u.x.0;
+LL | let a = u.x;
+ | --- value moved here
+LL | let b = u.y;
+ | ^^^ value used here after move
+
+error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`)
+ --> $DIR/union-borrow-move-parent-sibling.rs:70:13
+ |
+LL | let a = &mut ((*u.x).0).0;
+ | --- mutable borrow occurs here (via `u.x`)
+LL | let b = &u.y;
+ | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here
+LL | use_borrow(a);
+ | - mutable borrow later used here
+ |
+ = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x`
+
+error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>`
+ --> $DIR/union-borrow-move-parent-sibling.rs:76:13
+ |
+LL | let a = (u.x.0).0;
+ | ^^^^^^^^^
+ | |
+ | move occurs because value has type `MockVec<u8>`, which does not implement the `Copy` trait
+ | help: consider borrowing here: `&(u.x.0).0`
+
+error[E0382]: use of moved value: `u`
+ --> $DIR/union-borrow-move-parent-sibling.rs:78:13
+ |
+LL | let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
+ | - move occurs because `u` has type `U`, which does not implement the `Copy` trait
+LL | let a = (u.x.0).0;
+LL | let a = u.x;
+ | --- value moved here
+LL | let b = u.y;
+ | ^^^ value used here after move
+
+error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`)
+ --> $DIR/union-borrow-move-parent-sibling.rs:84:13
+ |
+LL | let a = &mut *u.y;
+ | --- mutable borrow occurs here (via `u.y`)
+LL | let b = &u.x;
+ | ^^^^ immutable borrow of `u.x` -- which overlaps with `u.y` -- occurs here
+LL | use_borrow(a);
+ | - mutable borrow later used here
+ |
+ = note: `u.x` is a field of the union `U`, so it overlaps the field `u.y`
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0382, E0502, E0507.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/src/test/ui/union/union-const-codegen.rs b/src/test/ui/union/union-const-codegen.rs
new file mode 100644
index 000000000..32a546cf3
--- /dev/null
+++ b/src/test/ui/union/union-const-codegen.rs
@@ -0,0 +1,19 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+union U {
+ a: u64,
+ b: u64,
+}
+
+const C: U = U { b: 10 };
+
+fn main() {
+ unsafe {
+ let a = C.a;
+ let b = C.b;
+ assert_eq!(a, 10);
+ assert_eq!(b, 10);
+ }
+}
diff --git a/src/test/ui/union/union-const-eval-field.rs b/src/test/ui/union/union-const-eval-field.rs
new file mode 100644
index 000000000..ca48785cd
--- /dev/null
+++ b/src/test/ui/union/union-const-eval-field.rs
@@ -0,0 +1,45 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+type Field1 = (i32, u32);
+type Field2 = f32;
+type Field3 = i64;
+
+union DummyUnion {
+ field1: Field1,
+ field2: Field2,
+ field3: Field3,
+}
+
+const FLOAT1_AS_I32: i32 = 1065353216;
+const UNION: DummyUnion = DummyUnion { field1: (FLOAT1_AS_I32, 0) };
+
+const fn read_field1() -> Field1 {
+ const FIELD1: Field1 = unsafe { UNION.field1 };
+ FIELD1
+}
+
+const fn read_field2() -> Field2 {
+ const FIELD2: Field2 = unsafe { UNION.field2 };
+ FIELD2
+}
+
+const fn read_field3() -> Field3 {
+ const FIELD3: Field3 = unsafe { UNION.field3 };
+ FIELD3
+}
+
+fn main() {
+ let foo = FLOAT1_AS_I32;
+ assert_eq!(read_field1().0, foo);
+ assert_eq!(read_field1().0, FLOAT1_AS_I32);
+
+ let foo = 1.0;
+ assert_eq!(read_field2(), foo);
+ assert_eq!(read_field2(), 1.0);
+
+ assert_eq!(read_field3(), unsafe { UNION.field3 });
+ let foo = unsafe { UNION.field3 };
+ assert_eq!(read_field3(), foo);
+}
diff --git a/src/test/ui/union/union-const-eval.rs b/src/test/ui/union/union-const-eval.rs
new file mode 100644
index 000000000..32ee4a739
--- /dev/null
+++ b/src/test/ui/union/union-const-eval.rs
@@ -0,0 +1,15 @@
+// check-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+union U {
+ a: usize,
+ b: usize,
+}
+
+const C: U = U { a: 10 };
+
+fn main() {
+ let a: [u8; unsafe { C.a }];
+ let b: [u8; unsafe { C.b }];
+}
diff --git a/src/test/ui/union/union-const-pat.rs b/src/test/ui/union/union-const-pat.rs
new file mode 100644
index 000000000..e7cb248a2
--- /dev/null
+++ b/src/test/ui/union/union-const-pat.rs
@@ -0,0 +1,13 @@
+union U {
+ a: usize,
+ b: usize,
+}
+
+const C: U = U { a: 10 };
+
+fn main() {
+ match C {
+ C => {} //~ ERROR cannot use unions in constant patterns
+ _ => {}
+ }
+}
diff --git a/src/test/ui/union/union-const-pat.stderr b/src/test/ui/union/union-const-pat.stderr
new file mode 100644
index 000000000..dc87f4de5
--- /dev/null
+++ b/src/test/ui/union/union-const-pat.stderr
@@ -0,0 +1,8 @@
+error: cannot use unions in constant patterns
+ --> $DIR/union-const-pat.rs:10:9
+ |
+LL | C => {}
+ | ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/union/union-copy.rs b/src/test/ui/union/union-copy.rs
new file mode 100644
index 000000000..5c3f8d908
--- /dev/null
+++ b/src/test/ui/union/union-copy.rs
@@ -0,0 +1,14 @@
+#[derive(Clone)]
+union U {
+ a: u8
+}
+
+#[derive(Clone)]
+union W {
+ a: std::mem::ManuallyDrop<String>
+}
+
+impl Copy for U {} // OK
+impl Copy for W {} //~ ERROR the trait `Copy` may not be implemented for this type
+
+fn main() {}
diff --git a/src/test/ui/union/union-copy.stderr b/src/test/ui/union/union-copy.stderr
new file mode 100644
index 000000000..8ecdafdde
--- /dev/null
+++ b/src/test/ui/union/union-copy.stderr
@@ -0,0 +1,18 @@
+error[E0204]: the trait `Copy` may not be implemented for this type
+ --> $DIR/union-copy.rs:12:6
+ |
+LL | a: std::mem::ManuallyDrop<String>
+ | --------------------------------- this field does not implement `Copy`
+...
+LL | impl Copy for W {}
+ | ^^^^
+ |
+note: the `Copy` impl for `ManuallyDrop<String>` requires that `String: Copy`
+ --> $DIR/union-copy.rs:8:8
+ |
+LL | a: std::mem::ManuallyDrop<String>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0204`.
diff --git a/src/test/ui/union/union-deref.mirunsafeck.stderr b/src/test/ui/union/union-deref.mirunsafeck.stderr
new file mode 100644
index 000000000..be5e60ab8
--- /dev/null
+++ b/src/test/ui/union/union-deref.mirunsafeck.stderr
@@ -0,0 +1,56 @@
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:16:14
+ |
+LL | unsafe { u.f.0 = Vec::new() };
+ | ^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:18:19
+ |
+LL | unsafe { &mut u.f.0 };
+ | ^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:20:14
+ |
+LL | unsafe { u.f.0.push(0) };
+ | ^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:24:14
+ |
+LL | unsafe { u.f.0.0 = Vec::new() };
+ | ^^^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:26:19
+ |
+LL | unsafe { &mut u.f.0.0 };
+ | ^^^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:28:14
+ |
+LL | unsafe { u.f.0.0.push(0) };
+ | ^^^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/union/union-deref.rs b/src/test/ui/union/union-deref.rs
new file mode 100644
index 000000000..5aa28d93f
--- /dev/null
+++ b/src/test/ui/union/union-deref.rs
@@ -0,0 +1,29 @@
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+//! Test the part of RFC 2514 that is about not applying `DerefMut` coercions
+//! of union fields.
+
+use std::mem::ManuallyDrop;
+
+union U1<T> { x:(), f: ManuallyDrop<(T,)> }
+
+union U2<T> { x:(), f: (ManuallyDrop<(T,)>,) }
+
+fn main() {
+ let mut u : U1<Vec<i32>> = U1 { x: () };
+ unsafe { (*u.f).0 = Vec::new() }; // explicit deref, this compiles
+ unsafe { u.f.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
+ unsafe { &mut (*u.f).0 }; // explicit deref, this compiles
+ unsafe { &mut u.f.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
+ unsafe { (*u.f).0.push(0) }; // explicit deref, this compiles
+ unsafe { u.f.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
+
+ let mut u : U2<Vec<i32>> = U2 { x: () };
+ unsafe { (*u.f.0).0 = Vec::new() }; // explicit deref, this compiles
+ unsafe { u.f.0.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
+ unsafe { &mut (*u.f.0).0 }; // explicit deref, this compiles
+ unsafe { &mut u.f.0.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
+ unsafe { (*u.f.0).0.push(0) }; // explicit deref, this compiles
+ unsafe { u.f.0.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
+}
diff --git a/src/test/ui/union/union-deref.thirunsafeck.stderr b/src/test/ui/union/union-deref.thirunsafeck.stderr
new file mode 100644
index 000000000..be5e60ab8
--- /dev/null
+++ b/src/test/ui/union/union-deref.thirunsafeck.stderr
@@ -0,0 +1,56 @@
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:16:14
+ |
+LL | unsafe { u.f.0 = Vec::new() };
+ | ^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:18:19
+ |
+LL | unsafe { &mut u.f.0 };
+ | ^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:20:14
+ |
+LL | unsafe { u.f.0.push(0) };
+ | ^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:24:14
+ |
+LL | unsafe { u.f.0.0 = Vec::new() };
+ | ^^^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:26:19
+ |
+LL | unsafe { &mut u.f.0.0 };
+ | ^^^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: not automatically applying `DerefMut` on `ManuallyDrop` union field
+ --> $DIR/union-deref.rs:28:14
+ |
+LL | unsafe { u.f.0.0.push(0) };
+ | ^^^^^
+ |
+ = help: writing to this reference calls the destructor for the old value
+ = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr
new file mode 100644
index 000000000..148fb5046
--- /dev/null
+++ b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr
@@ -0,0 +1,49 @@
+error[E0277]: the trait bound `U1: Copy` is not satisfied
+ --> $DIR/union-derive-clone.rs:6:10
+ |
+LL | #[derive(Clone)]
+ | ^^^^^ the trait `Copy` is not implemented for `U1`
+ |
+note: required by a bound in `AssertParamIsCopy`
+ --> $SRC_DIR/core/src/clone.rs:LL:COL
+ |
+LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
+ | ^^^^ required by this bound in `AssertParamIsCopy`
+ = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `U1` with `#[derive(Copy)]`
+ |
+LL | #[derive(Copy)]
+ |
+
+error[E0599]: the method `clone` exists for union `U5<CloneNoCopy>`, but its trait bounds were not satisfied
+ --> $DIR/union-derive-clone.rs:38:15
+ |
+LL | union U5<T> {
+ | -----------
+ | |
+ | method `clone` not found for this union
+ | doesn't satisfy `U5<CloneNoCopy>: Clone`
+...
+LL | struct CloneNoCopy;
+ | ------------------ doesn't satisfy `CloneNoCopy: Copy`
+...
+LL | let w = u.clone();
+ | ^^^^^ method cannot be called on `U5<CloneNoCopy>` due to unsatisfied trait bounds
+ |
+note: trait bound `CloneNoCopy: Copy` was not satisfied
+ --> $DIR/union-derive-clone.rs:28:10
+ |
+LL | #[derive(Clone, Copy)]
+ | ^^^^^ unsatisfied trait bound introduced in this `derive` macro
+ = note: the following trait bounds were not satisfied:
+ `CloneNoCopy: Copy`
+ which is required by `U5<CloneNoCopy>: Clone`
+help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]`
+ |
+LL | #[derive(Clone, Copy)]
+ |
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0599.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/union/union-derive-clone.rs b/src/test/ui/union/union-derive-clone.rs
new file mode 100644
index 000000000..7aa62146e
--- /dev/null
+++ b/src/test/ui/union/union-derive-clone.rs
@@ -0,0 +1,39 @@
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+use std::mem::ManuallyDrop;
+
+#[derive(Clone)] //~ ERROR the trait bound `U1: Copy` is not satisfied
+union U1 {
+ a: u8,
+}
+
+#[derive(Clone)]
+union U2 {
+ a: u8, // OK
+}
+
+impl Copy for U2 {}
+
+#[derive(Clone, Copy)]
+union U3 {
+ a: u8, // OK
+}
+
+#[derive(Clone, Copy)]
+union U4<T: Copy> {
+ a: T, // OK
+}
+
+#[derive(Clone, Copy)]
+union U5<T> {
+ a: ManuallyDrop<T>, // OK
+}
+
+#[derive(Clone)]
+struct CloneNoCopy;
+
+fn main() {
+ let u = U5 { a: ManuallyDrop::new(CloneNoCopy) };
+ let w = u.clone(); //~ ERROR the method
+}
diff --git a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr
new file mode 100644
index 000000000..148fb5046
--- /dev/null
+++ b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr
@@ -0,0 +1,49 @@
+error[E0277]: the trait bound `U1: Copy` is not satisfied
+ --> $DIR/union-derive-clone.rs:6:10
+ |
+LL | #[derive(Clone)]
+ | ^^^^^ the trait `Copy` is not implemented for `U1`
+ |
+note: required by a bound in `AssertParamIsCopy`
+ --> $SRC_DIR/core/src/clone.rs:LL:COL
+ |
+LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
+ | ^^^^ required by this bound in `AssertParamIsCopy`
+ = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `U1` with `#[derive(Copy)]`
+ |
+LL | #[derive(Copy)]
+ |
+
+error[E0599]: the method `clone` exists for union `U5<CloneNoCopy>`, but its trait bounds were not satisfied
+ --> $DIR/union-derive-clone.rs:38:15
+ |
+LL | union U5<T> {
+ | -----------
+ | |
+ | method `clone` not found for this union
+ | doesn't satisfy `U5<CloneNoCopy>: Clone`
+...
+LL | struct CloneNoCopy;
+ | ------------------ doesn't satisfy `CloneNoCopy: Copy`
+...
+LL | let w = u.clone();
+ | ^^^^^ method cannot be called on `U5<CloneNoCopy>` due to unsatisfied trait bounds
+ |
+note: trait bound `CloneNoCopy: Copy` was not satisfied
+ --> $DIR/union-derive-clone.rs:28:10
+ |
+LL | #[derive(Clone, Copy)]
+ | ^^^^^ unsatisfied trait bound introduced in this `derive` macro
+ = note: the following trait bounds were not satisfied:
+ `CloneNoCopy: Copy`
+ which is required by `U5<CloneNoCopy>: Clone`
+help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]`
+ |
+LL | #[derive(Clone, Copy)]
+ |
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0599.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/union/union-derive-eq.mirunsafeck.stderr b/src/test/ui/union/union-derive-eq.mirunsafeck.stderr
new file mode 100644
index 000000000..99505f316
--- /dev/null
+++ b/src/test/ui/union/union-derive-eq.mirunsafeck.stderr
@@ -0,0 +1,23 @@
+error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied
+ --> $DIR/union-derive-eq.rs:16:5
+ |
+LL | #[derive(Eq)]
+ | -- in this derive macro expansion
+LL | union U2 {
+LL | a: PartialEqNotEq,
+ | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`
+ |
+note: required by a bound in `AssertParamIsEq`
+ --> $SRC_DIR/core/src/cmp.rs:LL:COL
+ |
+LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
+ | ^^ required by this bound in `AssertParamIsEq`
+ = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]`
+ |
+LL | #[derive(Eq)]
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/union/union-derive-eq.rs b/src/test/ui/union/union-derive-eq.rs
new file mode 100644
index 000000000..b7e7f343f
--- /dev/null
+++ b/src/test/ui/union/union-derive-eq.rs
@@ -0,0 +1,21 @@
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#[derive(Eq)] // OK
+union U1 {
+ a: u8,
+}
+
+impl PartialEq for U1 { fn eq(&self, rhs: &Self) -> bool { true } }
+
+#[derive(PartialEq, Copy, Clone)]
+struct PartialEqNotEq;
+
+#[derive(Eq)]
+union U2 {
+ a: PartialEqNotEq, //~ ERROR the trait bound `PartialEqNotEq: Eq` is not satisfied
+}
+
+impl PartialEq for U2 { fn eq(&self, rhs: &Self) -> bool { true } }
+
+fn main() {}
diff --git a/src/test/ui/union/union-derive-eq.thirunsafeck.stderr b/src/test/ui/union/union-derive-eq.thirunsafeck.stderr
new file mode 100644
index 000000000..99505f316
--- /dev/null
+++ b/src/test/ui/union/union-derive-eq.thirunsafeck.stderr
@@ -0,0 +1,23 @@
+error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied
+ --> $DIR/union-derive-eq.rs:16:5
+ |
+LL | #[derive(Eq)]
+ | -- in this derive macro expansion
+LL | union U2 {
+LL | a: PartialEqNotEq,
+ | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`
+ |
+note: required by a bound in `AssertParamIsEq`
+ --> $SRC_DIR/core/src/cmp.rs:LL:COL
+ |
+LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
+ | ^^ required by this bound in `AssertParamIsEq`
+ = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]`
+ |
+LL | #[derive(Eq)]
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/union/union-derive-rpass.rs b/src/test/ui/union/union-derive-rpass.rs
new file mode 100644
index 000000000..8276bc635
--- /dev/null
+++ b/src/test/ui/union/union-derive-rpass.rs
@@ -0,0 +1,42 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Some traits can be derived for unions.
+
+#[derive(
+ Copy,
+ Clone,
+ Eq,
+)]
+union U {
+ a: u8,
+ b: u16,
+}
+
+impl PartialEq for U { fn eq(&self, rhs: &Self) -> bool { true } }
+
+#[derive(
+ Clone,
+ Copy,
+ Eq
+)]
+union W<T: Copy> {
+ a: T,
+}
+
+impl<T: Copy> PartialEq for W<T> { fn eq(&self, rhs: &Self) -> bool { true } }
+
+fn main() {
+ let u = U { b: 0 };
+ let u1 = u;
+ let u2 = u.clone();
+ assert!(u1 == u2);
+
+ let w = W { a: 0 };
+ let w1 = w.clone();
+ assert!(w == w1);
+}
diff --git a/src/test/ui/union/union-derive.rs b/src/test/ui/union/union-derive.rs
new file mode 100644
index 000000000..652a6b24c
--- /dev/null
+++ b/src/test/ui/union/union-derive.rs
@@ -0,0 +1,16 @@
+// Most traits cannot be derived for unions.
+
+#[derive(
+ PartialEq, //~ ERROR this trait cannot be derived for unions
+ PartialOrd, //~ ERROR this trait cannot be derived for unions
+ Ord, //~ ERROR this trait cannot be derived for unions
+ Hash, //~ ERROR this trait cannot be derived for unions
+ Default, //~ ERROR this trait cannot be derived for unions
+ Debug, //~ ERROR this trait cannot be derived for unions
+)]
+union U {
+ a: u8,
+ b: u16,
+}
+
+fn main() {}
diff --git a/src/test/ui/union/union-derive.stderr b/src/test/ui/union/union-derive.stderr
new file mode 100644
index 000000000..6ef72c901
--- /dev/null
+++ b/src/test/ui/union/union-derive.stderr
@@ -0,0 +1,38 @@
+error: this trait cannot be derived for unions
+ --> $DIR/union-derive.rs:4:5
+ |
+LL | PartialEq,
+ | ^^^^^^^^^
+
+error: this trait cannot be derived for unions
+ --> $DIR/union-derive.rs:5:5
+ |
+LL | PartialOrd,
+ | ^^^^^^^^^^
+
+error: this trait cannot be derived for unions
+ --> $DIR/union-derive.rs:6:5
+ |
+LL | Ord,
+ | ^^^
+
+error: this trait cannot be derived for unions
+ --> $DIR/union-derive.rs:7:5
+ |
+LL | Hash,
+ | ^^^^
+
+error: this trait cannot be derived for unions
+ --> $DIR/union-derive.rs:8:5
+ |
+LL | Default,
+ | ^^^^^^^
+
+error: this trait cannot be derived for unions
+ --> $DIR/union-derive.rs:9:5
+ |
+LL | Debug,
+ | ^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/union/union-drop-assign.rs b/src/test/ui/union/union-drop-assign.rs
new file mode 100644
index 000000000..215666bdd
--- /dev/null
+++ b/src/test/ui/union/union-drop-assign.rs
@@ -0,0 +1,37 @@
+// run-pass
+#![allow(unused_assignments)]
+
+// Drop works for union itself.
+
+use std::mem::ManuallyDrop;
+
+struct S;
+
+union U {
+ a: ManuallyDrop<S>
+}
+
+impl Drop for S {
+ fn drop(&mut self) {
+ unsafe { CHECK += 10; }
+ }
+}
+
+impl Drop for U {
+ fn drop(&mut self) {
+ unsafe { CHECK += 1; }
+ }
+}
+
+static mut CHECK: u8 = 0;
+
+fn main() {
+ unsafe {
+ let mut u = U { a: ManuallyDrop::new(S) };
+ assert_eq!(CHECK, 0);
+ u = U { a: ManuallyDrop::new(S) };
+ assert_eq!(CHECK, 1); // union itself is assigned, union is dropped, field is not dropped
+ *u.a = S;
+ assert_eq!(CHECK, 11); // union field is assigned, field is dropped
+ }
+}
diff --git a/src/test/ui/union/union-drop.rs b/src/test/ui/union/union-drop.rs
new file mode 100644
index 000000000..c3d7d41ca
--- /dev/null
+++ b/src/test/ui/union/union-drop.rs
@@ -0,0 +1,60 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Drop works for union itself.
+
+#[derive(Copy, Clone)]
+struct S;
+
+union U {
+ a: u8
+}
+
+union W {
+ a: S,
+}
+
+union Y {
+ a: S,
+}
+
+impl Drop for U {
+ fn drop(&mut self) {
+ unsafe { CHECK += 1; }
+ }
+}
+
+impl Drop for W {
+ fn drop(&mut self) {
+ unsafe { CHECK += 1; }
+ }
+}
+
+static mut CHECK: u8 = 0;
+
+fn main() {
+ unsafe {
+ assert_eq!(CHECK, 0);
+ {
+ let u = U { a: 1 };
+ }
+ assert_eq!(CHECK, 1); // 1, dtor of U is called
+ {
+ let w = W { a: S };
+ }
+ assert_eq!(CHECK, 2); // 2, dtor of W is called
+ {
+ let y = Y { a: S };
+ }
+ assert_eq!(CHECK, 2); // 2, Y has no dtor
+ {
+ let u2 = U { a: 1 };
+ std::mem::forget(u2);
+ }
+ assert_eq!(CHECK, 2); // 2, dtor of U *not* called for u2
+ }
+}
diff --git a/src/test/ui/union/union-empty.rs b/src/test/ui/union/union-empty.rs
new file mode 100644
index 000000000..79b7e68ee
--- /dev/null
+++ b/src/test/ui/union/union-empty.rs
@@ -0,0 +1,3 @@
+union U {} //~ ERROR unions cannot have zero fields
+
+fn main() {}
diff --git a/src/test/ui/union/union-empty.stderr b/src/test/ui/union/union-empty.stderr
new file mode 100644
index 000000000..a80b27e6e
--- /dev/null
+++ b/src/test/ui/union/union-empty.stderr
@@ -0,0 +1,8 @@
+error: unions cannot have zero fields
+ --> $DIR/union-empty.rs:1:1
+ |
+LL | union U {}
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/union/union-fields-1.mirunsafeck.stderr b/src/test/ui/union/union-fields-1.mirunsafeck.stderr
new file mode 100644
index 000000000..0c9981c69
--- /dev/null
+++ b/src/test/ui/union/union-fields-1.mirunsafeck.stderr
@@ -0,0 +1,42 @@
+error: field `c` is never read
+ --> $DIR/union-fields-1.rs:9:5
+ |
+LL | union U1 {
+ | -- field in this union
+...
+LL | c: u8,
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/union-fields-1.rs:4:9
+ |
+LL | #![deny(dead_code)]
+ | ^^^^^^^^^
+
+error: field `a` is never read
+ --> $DIR/union-fields-1.rs:12:5
+ |
+LL | union U2 {
+ | -- field in this union
+LL | a: u8,
+ | ^
+
+error: field `a` is never read
+ --> $DIR/union-fields-1.rs:16:20
+ |
+LL | union NoDropLike { a: u8 }
+ | ---------- ^
+ | |
+ | field in this union
+
+error: field `c` is never read
+ --> $DIR/union-fields-1.rs:21:5
+ |
+LL | union U {
+ | - field in this union
+...
+LL | c: u8,
+ | ^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/union/union-fields-1.rs b/src/test/ui/union/union-fields-1.rs
new file mode 100644
index 000000000..cf2ef4c03
--- /dev/null
+++ b/src/test/ui/union/union-fields-1.rs
@@ -0,0 +1,35 @@
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![deny(dead_code)]
+
+union U1 {
+ a: u8, // should not be reported
+ b: u8, // should not be reported
+ c: u8, //~ ERROR field `c` is never read
+}
+union U2 {
+ a: u8, //~ ERROR field `a` is never read
+ b: u8, // should not be reported
+ c: u8, // should not be reported
+}
+union NoDropLike { a: u8 } //~ ERROR field `a` is never read
+
+union U {
+ a: u8, // should not be reported
+ b: u8, // should not be reported
+ c: u8, //~ ERROR field `c` is never read
+}
+type A = U;
+
+fn main() {
+ let u = U1 { a: 0 };
+ let _a = unsafe { u.b };
+
+ let u = U2 { c: 0 };
+ let _b = unsafe { u.b };
+
+ let _u = NoDropLike { a: 10 };
+ let u = A { a: 0 };
+ let _b = unsafe { u.b };
+}
diff --git a/src/test/ui/union/union-fields-1.thirunsafeck.stderr b/src/test/ui/union/union-fields-1.thirunsafeck.stderr
new file mode 100644
index 000000000..0c9981c69
--- /dev/null
+++ b/src/test/ui/union/union-fields-1.thirunsafeck.stderr
@@ -0,0 +1,42 @@
+error: field `c` is never read
+ --> $DIR/union-fields-1.rs:9:5
+ |
+LL | union U1 {
+ | -- field in this union
+...
+LL | c: u8,
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/union-fields-1.rs:4:9
+ |
+LL | #![deny(dead_code)]
+ | ^^^^^^^^^
+
+error: field `a` is never read
+ --> $DIR/union-fields-1.rs:12:5
+ |
+LL | union U2 {
+ | -- field in this union
+LL | a: u8,
+ | ^
+
+error: field `a` is never read
+ --> $DIR/union-fields-1.rs:16:20
+ |
+LL | union NoDropLike { a: u8 }
+ | ---------- ^
+ | |
+ | field in this union
+
+error: field `c` is never read
+ --> $DIR/union-fields-1.rs:21:5
+ |
+LL | union U {
+ | - field in this union
+...
+LL | c: u8,
+ | ^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/union/union-fields-2.mirunsafeck.stderr b/src/test/ui/union/union-fields-2.mirunsafeck.stderr
new file mode 100644
index 000000000..90ad16402
--- /dev/null
+++ b/src/test/ui/union/union-fields-2.mirunsafeck.stderr
@@ -0,0 +1,84 @@
+error[E0784]: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:10:13
+ |
+LL | let u = U {};
+ | ^
+
+error[E0784]: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:12:13
+ |
+LL | let u = U { a: 0, b: 1 };
+ | ^
+
+error[E0560]: union `U` has no field named `c`
+ --> $DIR/union-fields-2.rs:13:29
+ |
+LL | let u = U { a: 0, b: 1, c: 2 };
+ | ^ `U` does not have this field
+ |
+ = note: available fields are: `a`, `b`
+
+error[E0784]: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:13:13
+ |
+LL | let u = U { a: 0, b: 1, c: 2 };
+ | ^
+
+error[E0784]: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:15:13
+ |
+LL | let u = U { ..u };
+ | ^
+
+error[E0436]: functional record update syntax requires a struct
+ --> $DIR/union-fields-2.rs:15:19
+ |
+LL | let u = U { ..u };
+ | ^
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:18:9
+ |
+LL | let U {} = u;
+ | ^^^^
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:20:9
+ |
+LL | let U { a, b } = u;
+ | ^^^^^^^^^^
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:21:9
+ |
+LL | let U { a, b, c } = u;
+ | ^^^^^^^^^^^^^
+
+error[E0026]: union `U` does not have a field named `c`
+ --> $DIR/union-fields-2.rs:21:19
+ |
+LL | let U { a, b, c } = u;
+ | ^ union `U` does not have this field
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:23:9
+ |
+LL | let U { .. } = u;
+ | ^^^^^^^^
+
+error: `..` cannot be used in union patterns
+ --> $DIR/union-fields-2.rs:23:9
+ |
+LL | let U { .. } = u;
+ | ^^^^^^^^
+
+error: `..` cannot be used in union patterns
+ --> $DIR/union-fields-2.rs:25:9
+ |
+LL | let U { a, .. } = u;
+ | ^^^^^^^^^^^
+
+error: aborting due to 13 previous errors
+
+Some errors have detailed explanations: E0026, E0436, E0560, E0784.
+For more information about an error, try `rustc --explain E0026`.
diff --git a/src/test/ui/union/union-fields-2.rs b/src/test/ui/union/union-fields-2.rs
new file mode 100644
index 000000000..e738b1847
--- /dev/null
+++ b/src/test/ui/union/union-fields-2.rs
@@ -0,0 +1,26 @@
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+union U {
+ a: u8,
+ b: u16,
+}
+
+fn main() {
+ let u = U {}; //~ ERROR union expressions should have exactly one field
+ let u = U { a: 0 }; // OK
+ let u = U { a: 0, b: 1 }; //~ ERROR union expressions should have exactly one field
+ let u = U { a: 0, b: 1, c: 2 }; //~ ERROR union expressions should have exactly one field
+ //~^ ERROR union `U` has no field named `c`
+ let u = U { ..u }; //~ ERROR union expressions should have exactly one field
+ //~^ ERROR functional record update syntax requires a struct
+
+ let U {} = u; //~ ERROR union patterns should have exactly one field
+ let U { a } = u; // OK
+ let U { a, b } = u; //~ ERROR union patterns should have exactly one field
+ let U { a, b, c } = u; //~ ERROR union patterns should have exactly one field
+ //~^ ERROR union `U` does not have a field named `c`
+ let U { .. } = u; //~ ERROR union patterns should have exactly one field
+ //~^ ERROR `..` cannot be used in union patterns
+ let U { a, .. } = u; //~ ERROR `..` cannot be used in union patterns
+}
diff --git a/src/test/ui/union/union-fields-2.thirunsafeck.stderr b/src/test/ui/union/union-fields-2.thirunsafeck.stderr
new file mode 100644
index 000000000..90ad16402
--- /dev/null
+++ b/src/test/ui/union/union-fields-2.thirunsafeck.stderr
@@ -0,0 +1,84 @@
+error[E0784]: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:10:13
+ |
+LL | let u = U {};
+ | ^
+
+error[E0784]: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:12:13
+ |
+LL | let u = U { a: 0, b: 1 };
+ | ^
+
+error[E0560]: union `U` has no field named `c`
+ --> $DIR/union-fields-2.rs:13:29
+ |
+LL | let u = U { a: 0, b: 1, c: 2 };
+ | ^ `U` does not have this field
+ |
+ = note: available fields are: `a`, `b`
+
+error[E0784]: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:13:13
+ |
+LL | let u = U { a: 0, b: 1, c: 2 };
+ | ^
+
+error[E0784]: union expressions should have exactly one field
+ --> $DIR/union-fields-2.rs:15:13
+ |
+LL | let u = U { ..u };
+ | ^
+
+error[E0436]: functional record update syntax requires a struct
+ --> $DIR/union-fields-2.rs:15:19
+ |
+LL | let u = U { ..u };
+ | ^
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:18:9
+ |
+LL | let U {} = u;
+ | ^^^^
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:20:9
+ |
+LL | let U { a, b } = u;
+ | ^^^^^^^^^^
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:21:9
+ |
+LL | let U { a, b, c } = u;
+ | ^^^^^^^^^^^^^
+
+error[E0026]: union `U` does not have a field named `c`
+ --> $DIR/union-fields-2.rs:21:19
+ |
+LL | let U { a, b, c } = u;
+ | ^ union `U` does not have this field
+
+error: union patterns should have exactly one field
+ --> $DIR/union-fields-2.rs:23:9
+ |
+LL | let U { .. } = u;
+ | ^^^^^^^^
+
+error: `..` cannot be used in union patterns
+ --> $DIR/union-fields-2.rs:23:9
+ |
+LL | let U { .. } = u;
+ | ^^^^^^^^
+
+error: `..` cannot be used in union patterns
+ --> $DIR/union-fields-2.rs:25:9
+ |
+LL | let U { a, .. } = u;
+ | ^^^^^^^^^^^
+
+error: aborting due to 13 previous errors
+
+Some errors have detailed explanations: E0026, E0436, E0560, E0784.
+For more information about an error, try `rustc --explain E0026`.
diff --git a/src/test/ui/union/union-generic-rpass.rs b/src/test/ui/union/union-generic-rpass.rs
new file mode 100644
index 000000000..25f1f5050
--- /dev/null
+++ b/src/test/ui/union/union-generic-rpass.rs
@@ -0,0 +1,34 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(dead_code)]
+
+use std::mem::ManuallyDrop;
+
+union MaybeItem<T: Iterator> {
+ elem: ManuallyDrop<T::Item>,
+ none: (),
+}
+
+union U<A, B> where A: Copy, B: Copy {
+ a: A,
+ b: B,
+}
+
+unsafe fn union_transmute<A, B>(a: A) -> B where A: Copy, B: Copy {
+ U { a }.b
+}
+
+fn main() {
+ unsafe {
+ let b = union_transmute::<(u8, u8), u16>((1, 1));
+ assert_eq!(b, (1 << 8) + 1);
+
+ let v: Vec<u8> = vec![1, 2, 3];
+ let mut i = v.iter();
+ i.next();
+ let mi = MaybeItem::<std::slice::Iter<_>> { elem: ManuallyDrop::new(i.next().unwrap()) };
+ assert_eq!(**mi.elem, 2);
+ }
+}
diff --git a/src/test/ui/union/union-generic.mirunsafeck.stderr b/src/test/ui/union/union-generic.mirunsafeck.stderr
new file mode 100644
index 000000000..a4f0c400d
--- /dev/null
+++ b/src/test/ui/union/union-generic.mirunsafeck.stderr
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `Rc<u32>: Copy` is not satisfied
+ --> $DIR/union-generic.rs:11:13
+ |
+LL | let u = U { a: Rc::new(0u32) };
+ | ^ the trait `Copy` is not implemented for `Rc<u32>`
+ |
+note: required by a bound in `U`
+ --> $DIR/union-generic.rs:6:12
+ |
+LL | union U<T: Copy> {
+ | ^^^^ required by this bound in `U`
+
+error[E0277]: the trait bound `Rc<u32>: Copy` is not satisfied
+ --> $DIR/union-generic.rs:13:13
+ |
+LL | let u = U::<Rc<u32>> { a: Default::default() };
+ | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `Rc<u32>`
+ |
+note: required by a bound in `U`
+ --> $DIR/union-generic.rs:6:12
+ |
+LL | union U<T: Copy> {
+ | ^^^^ required by this bound in `U`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/union/union-generic.rs b/src/test/ui/union/union-generic.rs
new file mode 100644
index 000000000..3d68ecb87
--- /dev/null
+++ b/src/test/ui/union/union-generic.rs
@@ -0,0 +1,15 @@
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+use std::rc::Rc;
+
+union U<T: Copy> {
+ a: T
+}
+
+fn main() {
+ let u = U { a: Rc::new(0u32) };
+ //~^ ERROR the trait bound `Rc<u32>: Copy` is not satisfied
+ let u = U::<Rc<u32>> { a: Default::default() };
+ //~^ ERROR the trait bound `Rc<u32>: Copy` is not satisfied
+}
diff --git a/src/test/ui/union/union-generic.thirunsafeck.stderr b/src/test/ui/union/union-generic.thirunsafeck.stderr
new file mode 100644
index 000000000..a4f0c400d
--- /dev/null
+++ b/src/test/ui/union/union-generic.thirunsafeck.stderr
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `Rc<u32>: Copy` is not satisfied
+ --> $DIR/union-generic.rs:11:13
+ |
+LL | let u = U { a: Rc::new(0u32) };
+ | ^ the trait `Copy` is not implemented for `Rc<u32>`
+ |
+note: required by a bound in `U`
+ --> $DIR/union-generic.rs:6:12
+ |
+LL | union U<T: Copy> {
+ | ^^^^ required by this bound in `U`
+
+error[E0277]: the trait bound `Rc<u32>: Copy` is not satisfied
+ --> $DIR/union-generic.rs:13:13
+ |
+LL | let u = U::<Rc<u32>> { a: Default::default() };
+ | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `Rc<u32>`
+ |
+note: required by a bound in `U`
+ --> $DIR/union-generic.rs:6:12
+ |
+LL | union U<T: Copy> {
+ | ^^^^ required by this bound in `U`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/union/union-inherent-method.rs b/src/test/ui/union/union-inherent-method.rs
new file mode 100644
index 000000000..b0fd22da7
--- /dev/null
+++ b/src/test/ui/union/union-inherent-method.rs
@@ -0,0 +1,16 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+union U {
+ a: u8,
+}
+
+impl U {
+ fn method(&self) -> u8 { unsafe { self.a } }
+}
+
+fn main() {
+ let u = U { a: 10 };
+ assert_eq!(u.method(), 10);
+}
diff --git a/src/test/ui/union/union-lint-dead-code.mirunsafeck.stderr b/src/test/ui/union/union-lint-dead-code.mirunsafeck.stderr
new file mode 100644
index 000000000..6e21584c3
--- /dev/null
+++ b/src/test/ui/union/union-lint-dead-code.mirunsafeck.stderr
@@ -0,0 +1,17 @@
+error: field `b` is never read
+ --> $DIR/union-lint-dead-code.rs:8:5
+ |
+LL | union Foo {
+ | --- field in this union
+LL | x: usize,
+LL | b: bool,
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/union-lint-dead-code.rs:4:9
+ |
+LL | #![deny(dead_code)]
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/union/union-lint-dead-code.rs b/src/test/ui/union/union-lint-dead-code.rs
new file mode 100644
index 000000000..65aaf0a1d
--- /dev/null
+++ b/src/test/ui/union/union-lint-dead-code.rs
@@ -0,0 +1,18 @@
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![deny(dead_code)]
+
+union Foo {
+ x: usize,
+ b: bool, //~ ERROR: field `b` is never read
+ _unused: u16,
+}
+
+fn field_read(f: Foo) -> usize {
+ unsafe { f.x }
+}
+
+fn main() {
+ let _ = field_read(Foo { x: 2 });
+}
diff --git a/src/test/ui/union/union-lint-dead-code.thirunsafeck.stderr b/src/test/ui/union/union-lint-dead-code.thirunsafeck.stderr
new file mode 100644
index 000000000..6e21584c3
--- /dev/null
+++ b/src/test/ui/union/union-lint-dead-code.thirunsafeck.stderr
@@ -0,0 +1,17 @@
+error: field `b` is never read
+ --> $DIR/union-lint-dead-code.rs:8:5
+ |
+LL | union Foo {
+ | --- field in this union
+LL | x: usize,
+LL | b: bool,
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/union-lint-dead-code.rs:4:9
+ |
+LL | #![deny(dead_code)]
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/union/union-macro.rs b/src/test/ui/union/union-macro.rs
new file mode 100644
index 000000000..7fd9d8221
--- /dev/null
+++ b/src/test/ui/union/union-macro.rs
@@ -0,0 +1,27 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(unused_variables)]
+
+macro_rules! duplicate {
+ ($i: item) => {
+ mod m1 {
+ $i
+ }
+ mod m2 {
+ $i
+ }
+ }
+}
+
+duplicate! {
+ pub union U {
+ pub a: u8
+ }
+}
+
+fn main() {
+ let u1 = m1::U { a: 0 };
+ let u2 = m2::U { a: 0 };
+}
diff --git a/src/test/ui/union/union-manuallydrop-rpass.rs b/src/test/ui/union/union-manuallydrop-rpass.rs
new file mode 100644
index 000000000..826bdf07c
--- /dev/null
+++ b/src/test/ui/union/union-manuallydrop-rpass.rs
@@ -0,0 +1,44 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(dead_code)]
+
+use std::mem::needs_drop;
+use std::mem::ManuallyDrop;
+
+struct NeedDrop;
+
+impl Drop for NeedDrop {
+ fn drop(&mut self) {}
+}
+
+union UnionOk1<T> {
+ empty: (),
+ value: ManuallyDrop<T>,
+}
+
+union UnionOk2 {
+ value: ManuallyDrop<NeedDrop>,
+}
+
+#[allow(dead_code)]
+union UnionOk3<T: Copy> {
+ empty: (),
+ value: T,
+}
+
+trait Foo { }
+
+trait ImpliesCopy : Copy { }
+
+#[allow(dead_code)]
+union UnionOk4<T: ImpliesCopy> {
+ value: T,
+}
+
+fn main() {
+ // NeedDrop should not make needs_drop true
+ assert!(!needs_drop::<UnionOk1<NeedDrop>>());
+ assert!(!needs_drop::<UnionOk3<&dyn Foo>>());
+}
diff --git a/src/test/ui/union/union-move.mirunsafeck.stderr b/src/test/ui/union/union-move.mirunsafeck.stderr
new file mode 100644
index 000000000..53050cf53
--- /dev/null
+++ b/src/test/ui/union/union-move.mirunsafeck.stderr
@@ -0,0 +1,35 @@
+error[E0382]: use of moved value: `x`
+ --> $DIR/union-move.rs:29:18
+ |
+LL | fn test1(x: U1) {
+ | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
+...
+LL | move_out(x.f1_nocopy);
+ | ----------- value moved here
+LL | move_out(x.f2_nocopy);
+ | ^^^^^^^^^^^ value used here after move
+
+error[E0382]: use of moved value: `x`
+ --> $DIR/union-move.rs:45:18
+ |
+LL | fn test3(x: U1) {
+ | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
+...
+LL | move_out(x.f2_nocopy);
+ | ----------- value moved here
+LL | move_out(x.f3_copy);
+ | ^^^^^^^^^ value used here after move
+
+error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
+ --> $DIR/union-move.rs:52:18
+ |
+LL | move_out(x.f1_nocopy);
+ | ^^^^^^^^^^^
+ | |
+ | cannot move out of here
+ | move occurs because `x.f1_nocopy` has type `ManuallyDrop<RefCell<i32>>`, which does not implement the `Copy` trait
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0382, E0509.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/src/test/ui/union/union-move.rs b/src/test/ui/union/union-move.rs
new file mode 100644
index 000000000..b8b1ac804
--- /dev/null
+++ b/src/test/ui/union/union-move.rs
@@ -0,0 +1,56 @@
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+//! Test the behavior of moving out of non-`Copy` union fields.
+//! Avoid types that `Drop`, we want to focus on moving.
+
+use std::cell::RefCell;
+use std::mem::ManuallyDrop;
+
+fn move_out<T>(x: T) {}
+
+union U1 {
+ f1_nocopy: ManuallyDrop<RefCell<i32>>,
+ f2_nocopy: ManuallyDrop<RefCell<i32>>,
+ f3_copy: i32,
+}
+
+union U2 {
+ f1_nocopy: ManuallyDrop<RefCell<i32>>,
+}
+impl Drop for U2 {
+ fn drop(&mut self) {}
+}
+
+fn test1(x: U1) {
+ // Moving out of a nocopy field prevents accessing other nocopy field.
+ unsafe {
+ move_out(x.f1_nocopy);
+ move_out(x.f2_nocopy); //~ ERROR use of moved value: `x`
+ }
+}
+
+fn test2(x: U1) {
+ // "Moving" out of copy field doesn't prevent later field accesses.
+ unsafe {
+ move_out(x.f3_copy);
+ move_out(x.f2_nocopy); // no error
+ }
+}
+
+fn test3(x: U1) {
+ // Moving out of a nocopy field prevents accessing other copy field.
+ unsafe {
+ move_out(x.f2_nocopy);
+ move_out(x.f3_copy); //~ ERROR use of moved value: `x`
+ }
+}
+
+fn test4(x: U2) {
+ // Cannot move out of union that implements `Drop`.
+ unsafe {
+ move_out(x.f1_nocopy); //~ ERROR cannot move out of type `U2`, which implements the `Drop`
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/union/union-move.thirunsafeck.stderr b/src/test/ui/union/union-move.thirunsafeck.stderr
new file mode 100644
index 000000000..53050cf53
--- /dev/null
+++ b/src/test/ui/union/union-move.thirunsafeck.stderr
@@ -0,0 +1,35 @@
+error[E0382]: use of moved value: `x`
+ --> $DIR/union-move.rs:29:18
+ |
+LL | fn test1(x: U1) {
+ | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
+...
+LL | move_out(x.f1_nocopy);
+ | ----------- value moved here
+LL | move_out(x.f2_nocopy);
+ | ^^^^^^^^^^^ value used here after move
+
+error[E0382]: use of moved value: `x`
+ --> $DIR/union-move.rs:45:18
+ |
+LL | fn test3(x: U1) {
+ | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
+...
+LL | move_out(x.f2_nocopy);
+ | ----------- value moved here
+LL | move_out(x.f3_copy);
+ | ^^^^^^^^^ value used here after move
+
+error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
+ --> $DIR/union-move.rs:52:18
+ |
+LL | move_out(x.f1_nocopy);
+ | ^^^^^^^^^^^
+ | |
+ | cannot move out of here
+ | move occurs because `x.f1_nocopy` has type `ManuallyDrop<RefCell<i32>>`, which does not implement the `Copy` trait
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0382, E0509.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/src/test/ui/union/union-nodrop.rs b/src/test/ui/union/union-nodrop.rs
new file mode 100644
index 000000000..6e6b105a7
--- /dev/null
+++ b/src/test/ui/union/union-nodrop.rs
@@ -0,0 +1,62 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(dead_code)]
+
+use std::mem::needs_drop;
+use std::mem::ManuallyDrop;
+
+struct NeedDrop;
+
+impl Drop for NeedDrop {
+ fn drop(&mut self) {}
+}
+
+// Constant expressios allow `NoDrop` to go out of scope,
+// unlike a value of the interior type implementing `Drop`.
+static X: () = (NoDrop { inner: ManuallyDrop::new(NeedDrop) }, ()).1;
+
+const Y: () = (NoDrop { inner: ManuallyDrop::new(NeedDrop) }, ()).1;
+
+const fn _f() { (NoDrop { inner: ManuallyDrop::new(NeedDrop) }, ()).1 }
+
+// A union that scrubs the drop glue from its inner type
+union NoDrop<T> { inner: ManuallyDrop<T> }
+
+// Copy currently can't be implemented on drop-containing unions,
+// this may change later
+// https://github.com/rust-lang/rust/pull/38934#issuecomment-271219289
+
+// // We should be able to implement Copy for NoDrop
+// impl<T> Copy for NoDrop<T> {}
+// impl<T> Clone for NoDrop<T> {fn clone(&self) -> Self { *self }}
+
+// // We should be able to implement Copy for things using NoDrop
+// #[derive(Copy, Clone)]
+struct Foo {
+ x: NoDrop<Box<u8>>
+}
+
+struct Baz {
+ x: NoDrop<Box<u8>>,
+ y: Box<u8>,
+}
+
+union ActuallyDrop<T> { inner: ManuallyDrop<T> }
+
+impl<T> Drop for ActuallyDrop<T> {
+ fn drop(&mut self) {}
+}
+
+fn main() {
+ // NoDrop should not make needs_drop true
+ assert!(!needs_drop::<Foo>());
+ assert!(!needs_drop::<NoDrop<u8>>());
+ assert!(!needs_drop::<NoDrop<Box<u8>>>());
+ // presence of other drop types should still work
+ assert!(needs_drop::<Baz>());
+ // drop impl on union itself should work
+ assert!(needs_drop::<ActuallyDrop<u8>>());
+ assert!(needs_drop::<ActuallyDrop<Box<u8>>>());
+}
diff --git a/src/test/ui/union/union-nonrepresentable.rs b/src/test/ui/union/union-nonrepresentable.rs
new file mode 100644
index 000000000..4bdf7c687
--- /dev/null
+++ b/src/test/ui/union/union-nonrepresentable.rs
@@ -0,0 +1,6 @@
+union U { //~ ERROR recursive type `U` has infinite size
+ a: u8,
+ b: std::mem::ManuallyDrop<U>,
+}
+
+fn main() {}
diff --git a/src/test/ui/union/union-nonrepresentable.stderr b/src/test/ui/union/union-nonrepresentable.stderr
new file mode 100644
index 000000000..9804b1418
--- /dev/null
+++ b/src/test/ui/union/union-nonrepresentable.stderr
@@ -0,0 +1,17 @@
+error[E0072]: recursive type `U` has infinite size
+ --> $DIR/union-nonrepresentable.rs:1:1
+ |
+LL | union U {
+ | ^^^^^^^ recursive type has infinite size
+LL | a: u8,
+LL | b: std::mem::ManuallyDrop<U>,
+ | ------------------------- recursive without indirection
+ |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `U` representable
+ |
+LL | b: Box<std::mem::ManuallyDrop<U>>,
+ | ++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/ui/union/union-nonzero.rs b/src/test/ui/union/union-nonzero.rs
new file mode 100644
index 000000000..3f4f7ea1c
--- /dev/null
+++ b/src/test/ui/union/union-nonzero.rs
@@ -0,0 +1,54 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(dead_code)]
+
+// Tests that unions aren't subject to unsafe non-zero/niche-filling optimizations.
+//
+// For example, if a union `U` can contain both a `&T` and a `*const T`, there's definitely no
+// bit-value that an `Option<U>` could reuse as `None`; this test makes sure that isn't done.
+//
+// Secondly, this tests the status quo (not a guarantee; subject to change!) to not apply such
+// optimizations to types containing unions even if they're theoretically possible. (discussion:
+// https://github.com/rust-lang/rust/issues/36394)
+//
+// Notably this nails down part of the behavior that `MaybeUninit` assumes: that an
+// `Option<MaybeUninit<&u8>>` does not take advantage of non-zero optimization, and thus is a safe
+// construct.
+
+use std::mem::{size_of, transmute};
+
+union U1<A: Copy> {
+ a: A,
+}
+
+union U2<A: Copy, B: Copy> {
+ a: A,
+ b: B,
+}
+
+// Option<E> uses a value other than 0 and 1 as None
+#[derive(Clone,Copy)]
+enum E {
+ A = 0,
+ B = 1,
+}
+
+fn main() {
+ // Unions do not participate in niche-filling/non-zero optimization...
+ assert!(size_of::<Option<U2<&u8, u8>>>() > size_of::<U2<&u8, u8>>());
+ assert!(size_of::<Option<U2<&u8, ()>>>() > size_of::<U2<&u8, ()>>());
+ assert!(size_of::<Option<U2<u8, E>>>() > size_of::<U2<u8, E>>());
+
+ // ...even when theoretically possible:
+ assert!(size_of::<Option<U1<&u8>>>() > size_of::<U1<&u8>>());
+ assert!(size_of::<Option<U2<&u8, &u8>>>() > size_of::<U2<&u8, &u8>>());
+
+ // The unused bits of the () variant can have any value.
+ let zeroed: U2<&u8, ()> = unsafe { transmute(std::ptr::null::<u8>()) };
+
+ if let None = Some(zeroed) {
+ panic!()
+ }
+}
diff --git a/src/test/ui/union/union-overwrite.rs b/src/test/ui/union/union-overwrite.rs
new file mode 100644
index 000000000..0eea14d9d
--- /dev/null
+++ b/src/test/ui/union/union-overwrite.rs
@@ -0,0 +1,80 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct Pair<T, U>(T, U);
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct Triple<T>(T, T, T);
+
+#[repr(C)]
+union U<A, B>
+where
+ A: Copy, B: Copy
+{
+ a: Pair<A, A>,
+ b: B,
+}
+
+#[repr(C)]
+union W<A, B>
+where
+ A: Copy, B: Copy
+{
+ a: A,
+ b: B,
+}
+
+#[cfg(target_endian = "little")]
+unsafe fn check() {
+ let mut u = U::<u8, u16> { b: 0xDE_DE };
+ u.a.0 = 0xBE;
+ assert_eq!(u.b, 0xDE_BE);
+
+ let mut u = U::<u16, u32> { b: 0xDEAD_DEAD };
+ u.a.0 = 0xBEEF;
+ assert_eq!(u.b, 0xDEAD_BEEF);
+
+ let mut u = U::<u32, u64> { b: 0xDEADBEEF_DEADBEEF };
+ u.a.0 = 0xBAADF00D;
+ assert_eq!(u.b, 0xDEADBEEF_BAADF00D);
+
+ let mut w = W::<Pair<Triple<u8>, u8>, u32> { b: 0xDEAD_DEAD };
+ w.a.0 = Triple(0, 0, 0);
+ assert_eq!(w.b, 0xDE00_0000);
+
+ let mut w = W::<Pair<u8, Triple<u8>>, u32> { b: 0xDEAD_DEAD };
+ w.a.1 = Triple(0, 0, 0);
+ assert_eq!(w.b, 0x0000_00AD);
+}
+
+#[cfg(target_endian = "big")]
+unsafe fn check() {
+ let mut u = U::<u8, u16> { b: 0xDE_DE };
+ u.a.0 = 0xBE;
+ assert_eq!(u.b, 0xBE_DE);
+
+ let mut u = U::<u16, u32> { b: 0xDEAD_DEAD };
+ u.a.0 = 0xBEEF;
+ assert_eq!(u.b, 0xBEEF_DEAD);
+
+ let mut u = U::<u32, u64> { b: 0xDEADBEEF_DEADBEEF };
+ u.a.0 = 0xBAADF00D;
+ assert_eq!(u.b, 0xBAADF00D_DEADBEEF);
+
+ let mut w = W::<Pair<Triple<u8>, u8>, u32> { b: 0xDEAD_DEAD };
+ w.a.0 = Triple(0, 0, 0);
+ assert_eq!(w.b, 0x0000_00AD);
+
+ let mut w = W::<Pair<u8, Triple<u8>>, u32> { b: 0xDEAD_DEAD };
+ w.a.1 = Triple(0, 0, 0);
+ assert_eq!(w.b, 0xDE00_0000);
+}
+
+fn main() {
+ unsafe {
+ check();
+ }
+}
diff --git a/src/test/ui/union/union-packed.rs b/src/test/ui/union/union-packed.rs
new file mode 100644
index 000000000..9c6398bf5
--- /dev/null
+++ b/src/test/ui/union/union-packed.rs
@@ -0,0 +1,173 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(dead_code)]
+#![allow(non_snake_case)]
+
+use std::mem::{size_of, size_of_val, align_of, align_of_val};
+
+struct S {
+ a: u16,
+ b: [u8; 3],
+}
+
+#[repr(packed)]
+struct Sp1 {
+ a: u16,
+ b: [u8; 3],
+}
+
+#[repr(packed(2))]
+struct Sp2 {
+ a: u16,
+ b: [u8; 3],
+}
+
+union U {
+ a: u16,
+ b: [u8; 3],
+}
+
+#[repr(packed)]
+union Up1 {
+ a: u16,
+ b: [u8; 3],
+}
+
+#[repr(packed(2))]
+union Up2 {
+ a: u16,
+ b: [u8; 3],
+}
+
+#[repr(C, packed(4))]
+union Up4c {
+ a: u16,
+ b: [u8; 3],
+}
+
+const CS: S = S { a: 0, b: [0, 0, 0] };
+const CSP1: Sp1 = Sp1 { a: 0, b: [0, 0, 0] };
+const CSP2: Sp2 = Sp2 { a: 0, b: [0, 0, 0] };
+const CU: U = U { b: [0, 0, 0] };
+const CUP1: Up1 = Up1 { b: [0, 0, 0] };
+const CUP2: Up2 = Up2 { b: [0, 0, 0] };
+const CUP4C: Up4c = Up4c { b: [0, 0, 0] };
+
+fn main() {
+ let s = S { a: 0, b: [0, 0, 0] };
+ assert_eq!(size_of::<S>(), 6);
+ assert_eq!(size_of_val(&s), 6);
+ assert_eq!(size_of_val(&CS), 6);
+ assert_eq!(align_of::<S>(), 2);
+ assert_eq!(align_of_val(&s), 2);
+ assert_eq!(align_of_val(&CS), 2);
+
+ let sp1 = Sp1 { a: 0, b: [0, 0, 0] };
+ assert_eq!(size_of::<Sp1>(), 5);
+ assert_eq!(size_of_val(&sp1), 5);
+ assert_eq!(size_of_val(&CSP1), 5);
+ assert_eq!(align_of::<Sp1>(), 1);
+ assert_eq!(align_of_val(&sp1), 1);
+ assert_eq!(align_of_val(&CSP1), 1);
+
+ let sp2 = Sp2 { a: 0, b: [0, 0, 0] };
+ assert_eq!(size_of::<Sp2>(), 6);
+ assert_eq!(size_of_val(&sp2), 6);
+ assert_eq!(size_of_val(&CSP2), 6);
+ assert_eq!(align_of::<Sp2>(), 2);
+ assert_eq!(align_of_val(&sp2), 2);
+ assert_eq!(align_of_val(&CSP2), 2);
+
+ let u = U { b: [0, 0, 0] };
+ assert_eq!(size_of::<U>(), 4);
+ assert_eq!(size_of_val(&u), 4);
+ assert_eq!(size_of_val(&CU), 4);
+ assert_eq!(align_of::<U>(), 2);
+ assert_eq!(align_of_val(&u), 2);
+ assert_eq!(align_of_val(&CU), 2);
+
+ let Up1 = Up1 { b: [0, 0, 0] };
+ assert_eq!(size_of::<Up1>(), 3);
+ assert_eq!(size_of_val(&Up1), 3);
+ assert_eq!(size_of_val(&CUP1), 3);
+ assert_eq!(align_of::<Up1>(), 1);
+ assert_eq!(align_of_val(&Up1), 1);
+ assert_eq!(align_of_val(&CUP1), 1);
+
+ let up2 = Up2 { b: [0, 0, 0] };
+ assert_eq!(size_of::<Up2>(), 4);
+ assert_eq!(size_of_val(&up2), 4);
+ assert_eq!(size_of_val(&CUP2), 4);
+ assert_eq!(align_of::<Up2>(), 2);
+ assert_eq!(align_of_val(&up2), 2);
+ assert_eq!(align_of_val(&CUP2), 2);
+
+ let up4c = Up4c { b: [0, 0, 0] };
+ assert_eq!(size_of::<Up4c>(), 4);
+ assert_eq!(size_of_val(&up4c), 4);
+ assert_eq!(size_of_val(&CUP4C), 4);
+ assert_eq!(align_of::<Up4c>(), 2);
+ assert_eq!(align_of_val(&up4c), 2);
+ assert_eq!(align_of_val(&CUP4C), 2);
+
+ hybrid::check_hybrid();
+}
+
+mod hybrid {
+ use std::mem::{size_of, align_of};
+
+ #[repr(packed)]
+ #[derive(Copy, Clone)]
+ struct S1 {
+ a: u16,
+ b: u8,
+ }
+
+ #[repr(packed)]
+ union U {
+ s: S1,
+ c: u16,
+ }
+
+ #[repr(packed)]
+ struct S2 {
+ d: u8,
+ u: U,
+ }
+
+ #[repr(C, packed(2))]
+ struct S1C {
+ a: u16,
+ b: u8,
+ }
+
+ #[repr(C, packed(2))]
+ union UC {
+ s: S1,
+ c: u16,
+ }
+
+ #[repr(C, packed(2))]
+ struct S2C {
+ d: u8,
+ u: UC,
+ }
+
+ pub fn check_hybrid() {
+ assert_eq!(align_of::<S1>(), 1);
+ assert_eq!(size_of::<S1>(), 3);
+ assert_eq!(align_of::<U>(), 1);
+ assert_eq!(size_of::<U>(), 3);
+ assert_eq!(align_of::<S2>(), 1);
+ assert_eq!(size_of::<S2>(), 4);
+
+ assert_eq!(align_of::<S1C>(), 2);
+ assert_eq!(size_of::<S1C>(), 4);
+ assert_eq!(align_of::<UC>(), 2);
+ assert_eq!(size_of::<UC>(), 4);
+ assert_eq!(align_of::<S2C>(), 2);
+ assert_eq!(size_of::<S2C>(), 6);
+ }
+}
diff --git a/src/test/ui/union/union-pat-refutability.rs b/src/test/ui/union/union-pat-refutability.rs
new file mode 100644
index 000000000..d628a200a
--- /dev/null
+++ b/src/test/ui/union/union-pat-refutability.rs
@@ -0,0 +1,57 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(dead_code)]
+#![allow(illegal_floating_point_literal_pattern)]
+
+#[repr(u32)]
+enum Tag { I, F }
+
+#[repr(C)]
+union U {
+ i: i32,
+ f: f32,
+}
+
+#[repr(C)]
+struct Value {
+ tag: Tag,
+ u: U,
+}
+
+fn is_zero(v: Value) -> bool {
+ unsafe {
+ match v {
+ Value { tag: Tag::I, u: U { i: 0 } } => true,
+ Value { tag: Tag::F, u: U { f: 0.0 } } => true,
+ _ => false,
+ }
+ }
+}
+
+union W {
+ a: u8,
+ b: u8,
+}
+
+fn refut(w: W) {
+ unsafe {
+ match w {
+ W { a: 10 } => {
+ panic!();
+ }
+ W { b } => {
+ assert_eq!(b, 11);
+ }
+ }
+ }
+}
+
+fn main() {
+ let v = Value { tag: Tag::I, u: U { i: 1 } };
+ assert_eq!(is_zero(v), false);
+
+ let w = W { a: 11 };
+ refut(w);
+}
diff --git a/src/test/ui/union/union-repr-c.rs b/src/test/ui/union/union-repr-c.rs
new file mode 100644
index 000000000..1367835e6
--- /dev/null
+++ b/src/test/ui/union/union-repr-c.rs
@@ -0,0 +1,18 @@
+#![allow(unused)]
+#![deny(improper_ctypes)]
+
+#[repr(C)]
+union U {
+ a: u8,
+}
+
+union W {
+ a: u8,
+}
+
+extern "C" {
+ static FOREIGN1: U; // OK
+ static FOREIGN2: W; //~ ERROR `extern` block uses type `W`
+}
+
+fn main() {}
diff --git a/src/test/ui/union/union-repr-c.stderr b/src/test/ui/union/union-repr-c.stderr
new file mode 100644
index 000000000..9abf440f7
--- /dev/null
+++ b/src/test/ui/union/union-repr-c.stderr
@@ -0,0 +1,21 @@
+error: `extern` block uses type `W`, which is not FFI-safe
+ --> $DIR/union-repr-c.rs:15:22
+ |
+LL | static FOREIGN2: W;
+ | ^ not FFI-safe
+ |
+note: the lint level is defined here
+ --> $DIR/union-repr-c.rs:2:9
+ |
+LL | #![deny(improper_ctypes)]
+ | ^^^^^^^^^^^^^^^
+ = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union
+ = note: this union has unspecified layout
+note: the type is defined here
+ --> $DIR/union-repr-c.rs:9:1
+ |
+LL | union W {
+ | ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/union/union-sized-field.rs b/src/test/ui/union/union-sized-field.rs
new file mode 100644
index 000000000..cb852eff0
--- /dev/null
+++ b/src/test/ui/union/union-sized-field.rs
@@ -0,0 +1,19 @@
+use std::mem::ManuallyDrop;
+
+union Foo<T: ?Sized> {
+ value: ManuallyDrop<T>,
+ //~^ ERROR the size for values of type
+}
+
+struct Foo2<T: ?Sized> {
+ value: ManuallyDrop<T>,
+ //~^ ERROR the size for values of type
+ t: u32,
+}
+
+enum Foo3<T: ?Sized> {
+ Value(ManuallyDrop<T>),
+ //~^ ERROR the size for values of type
+}
+
+fn main() {}
diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr
new file mode 100644
index 000000000..771e8f261
--- /dev/null
+++ b/src/test/ui/union/union-sized-field.stderr
@@ -0,0 +1,78 @@
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+ --> $DIR/union-sized-field.rs:4:12
+ |
+LL | union Foo<T: ?Sized> {
+ | - this type parameter needs to be `std::marker::Sized`
+LL | value: ManuallyDrop<T>,
+ | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = note: required because it appears within the type `ManuallyDrop<T>`
+ = note: no field of a union may have a dynamically sized type
+ = 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 - union Foo<T: ?Sized> {
+LL + union Foo<T> {
+ |
+help: borrowed types always have a statically known size
+ |
+LL | value: &ManuallyDrop<T>,
+ | +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | value: Box<ManuallyDrop<T>>,
+ | ++++ +
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+ --> $DIR/union-sized-field.rs:9:12
+ |
+LL | struct Foo2<T: ?Sized> {
+ | - this type parameter needs to be `std::marker::Sized`
+LL | value: ManuallyDrop<T>,
+ | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = note: required because it appears within the type `ManuallyDrop<T>`
+ = note: only the last field of a struct may have a dynamically sized type
+ = 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 - struct Foo2<T: ?Sized> {
+LL + struct Foo2<T> {
+ |
+help: borrowed types always have a statically known size
+ |
+LL | value: &ManuallyDrop<T>,
+ | +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | value: Box<ManuallyDrop<T>>,
+ | ++++ +
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+ --> $DIR/union-sized-field.rs:15:11
+ |
+LL | enum Foo3<T: ?Sized> {
+ | - this type parameter needs to be `std::marker::Sized`
+LL | Value(ManuallyDrop<T>),
+ | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = note: required because it appears within the type `ManuallyDrop<T>`
+ = note: no field of an enum variant may have a dynamically sized type
+ = 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 - enum Foo3<T: ?Sized> {
+LL + enum Foo3<T> {
+ |
+help: borrowed types always have a statically known size
+ |
+LL | Value(&ManuallyDrop<T>),
+ | +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | Value(Box<ManuallyDrop<T>>),
+ | ++++ +
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/union/union-suggest-field.mirunsafeck.stderr b/src/test/ui/union/union-suggest-field.mirunsafeck.stderr
new file mode 100644
index 000000000..58b1f5cb0
--- /dev/null
+++ b/src/test/ui/union/union-suggest-field.mirunsafeck.stderr
@@ -0,0 +1,27 @@
+error[E0560]: union `U` has no field named `principle`
+ --> $DIR/union-suggest-field.rs:13:17
+ |
+LL | let u = U { principle: 0 };
+ | ^^^^^^^^^ help: a field with a similar name exists: `principal`
+
+error[E0609]: no field `principial` on type `U`
+ --> $DIR/union-suggest-field.rs:17:15
+ |
+LL | let w = u.principial;
+ | ^^^^^^^^^^ help: a field with a similar name exists: `principal`
+
+error[E0615]: attempted to take value of method `calculate` on type `U`
+ --> $DIR/union-suggest-field.rs:21:15
+ |
+LL | let y = u.calculate;
+ | ^^^^^^^^^ method, not a field
+ |
+help: use parentheses to call the method
+ |
+LL | let y = u.calculate();
+ | ++
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0560, E0609, E0615.
+For more information about an error, try `rustc --explain E0560`.
diff --git a/src/test/ui/union/union-suggest-field.rs b/src/test/ui/union/union-suggest-field.rs
new file mode 100644
index 000000000..601a22a06
--- /dev/null
+++ b/src/test/ui/union/union-suggest-field.rs
@@ -0,0 +1,24 @@
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+union U {
+ principal: u8,
+}
+
+impl U {
+ fn calculate(&self) {}
+}
+
+fn main() {
+ let u = U { principle: 0 };
+ //~^ ERROR union `U` has no field named `principle`
+ //~| HELP a field with a similar name exists
+ //~| SUGGESTION principal
+ let w = u.principial; //~ ERROR no field `principial` on type `U`
+ //~| HELP a field with a similar name exists
+ //~| SUGGESTION principal
+
+ let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U`
+ //~| HELP use parentheses to call the method
+ //~| SUGGESTION ()
+}
diff --git a/src/test/ui/union/union-suggest-field.thirunsafeck.stderr b/src/test/ui/union/union-suggest-field.thirunsafeck.stderr
new file mode 100644
index 000000000..58b1f5cb0
--- /dev/null
+++ b/src/test/ui/union/union-suggest-field.thirunsafeck.stderr
@@ -0,0 +1,27 @@
+error[E0560]: union `U` has no field named `principle`
+ --> $DIR/union-suggest-field.rs:13:17
+ |
+LL | let u = U { principle: 0 };
+ | ^^^^^^^^^ help: a field with a similar name exists: `principal`
+
+error[E0609]: no field `principial` on type `U`
+ --> $DIR/union-suggest-field.rs:17:15
+ |
+LL | let w = u.principial;
+ | ^^^^^^^^^^ help: a field with a similar name exists: `principal`
+
+error[E0615]: attempted to take value of method `calculate` on type `U`
+ --> $DIR/union-suggest-field.rs:21:15
+ |
+LL | let y = u.calculate;
+ | ^^^^^^^^^ method, not a field
+ |
+help: use parentheses to call the method
+ |
+LL | let y = u.calculate();
+ | ++
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0560, E0609, E0615.
+For more information about an error, try `rustc --explain E0560`.
diff --git a/src/test/ui/union/union-trait-impl.rs b/src/test/ui/union/union-trait-impl.rs
new file mode 100644
index 000000000..6134e91f3
--- /dev/null
+++ b/src/test/ui/union/union-trait-impl.rs
@@ -0,0 +1,19 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+use std::fmt;
+
+union U {
+ a: u8
+}
+
+impl fmt::Display for U {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ unsafe { write!(f, "Oh hai {}", self.a) }
+ }
+}
+
+fn main() {
+ assert_eq!(U { a: 2 }.to_string(), "Oh hai 2");
+}
diff --git a/src/test/ui/union/union-transmute.rs b/src/test/ui/union/union-transmute.rs
new file mode 100644
index 000000000..1a3b32d55
--- /dev/null
+++ b/src/test/ui/union/union-transmute.rs
@@ -0,0 +1,27 @@
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+union U {
+ a: (u8, u8),
+ b: u16,
+}
+
+union W {
+ a: u32,
+ b: f32,
+}
+
+fn main() {
+ unsafe {
+ let mut u = U { a: (1, 1) };
+ assert_eq!(u.b, (1 << 8) + 1);
+ u.b = (2 << 8) + 2;
+ assert_eq!(u.a, (2, 2));
+
+ let mut w = W { a: 0b0_11111111_00000000000000000000000 };
+ assert_eq!(w.b, f32::INFINITY);
+ w.b = f32::NEG_INFINITY;
+ assert_eq!(w.a, 0b1_11111111_00000000000000000000000);
+ }
+}
diff --git a/src/test/ui/union/union-unsafe.mir.stderr b/src/test/ui/union/union-unsafe.mir.stderr
new file mode 100644
index 000000000..544213dbc
--- /dev/null
+++ b/src/test/ui/union/union-unsafe.mir.stderr
@@ -0,0 +1,75 @@
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:33:5
+ |
+LL | *(u.p) = 13;
+ | ^^^^^^^^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:46:6
+ |
+LL | *u3.a = T::default();
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:52:6
+ |
+LL | *u3.a = T::default();
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:60:13
+ |
+LL | let a = u1.a;
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:63:14
+ |
+LL | let U1 { a } = u1;
+ | ^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:64:12
+ |
+LL | if let U1 { a: 12 } = u1 {}
+ | ^^^^^^^^^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:69:6
+ |
+LL | *u2.a = String::from("new");
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:73:6
+ |
+LL | *u3.a = 1;
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:77:6
+ |
+LL | *u3.a = String::from("new");
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs
new file mode 100644
index 000000000..5e1837a90
--- /dev/null
+++ b/src/test/ui/union/union-unsafe.rs
@@ -0,0 +1,78 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+use std::mem::ManuallyDrop;
+use std::cell::RefCell;
+
+union U1 {
+ a: u8
+}
+
+union U2 {
+ a: ManuallyDrop<String>
+}
+
+union U3<T> {
+ a: ManuallyDrop<T>
+}
+
+union U4<T: Copy> {
+ a: T
+}
+
+union URef {
+ p: &'static mut i32,
+}
+
+union URefCell { // field that does not drop but is not `Copy`, either
+ a: (ManuallyDrop<RefCell<i32>>, i32),
+}
+
+fn deref_union_field(mut u: URef) {
+ // Not an assignment but an access to the union field!
+ *(u.p) = 13; //~ ERROR access to union field is unsafe
+}
+
+fn assign_noncopy_union_field(mut u: URefCell) {
+ // FIXME(thir-unsafeck)
+ u.a = (ManuallyDrop::new(RefCell::new(0)), 1); // OK (assignment does not drop)
+ u.a.0 = ManuallyDrop::new(RefCell::new(0)); // OK (assignment does not drop)
+ u.a.1 = 1; // OK
+}
+
+fn generic_noncopy<T: Default>() {
+ let mut u3 = U3 { a: ManuallyDrop::new(T::default()) };
+ u3.a = ManuallyDrop::new(T::default()); // OK (assignment does not drop)
+ *u3.a = T::default(); //~ ERROR access to union field is unsafe
+}
+
+fn generic_copy<T: Copy + Default>() {
+ let mut u3 = U3 { a: ManuallyDrop::new(T::default()) };
+ u3.a = ManuallyDrop::new(T::default()); // OK
+ *u3.a = T::default(); //~ ERROR access to union field is unsafe
+
+ let mut u4 = U4 { a: T::default() };
+ u4.a = T::default(); // OK
+}
+
+fn main() {
+ let mut u1 = U1 { a: 10 }; // OK
+ let a = u1.a; //~ ERROR access to union field is unsafe
+ u1.a = 11; // OK
+
+ let U1 { a } = u1; //~ ERROR access to union field is unsafe
+ if let U1 { a: 12 } = u1 {} //~ ERROR access to union field is unsafe
+ // let U1 { .. } = u1; // OK
+
+ let mut u2 = U2 { a: ManuallyDrop::new(String::from("old")) }; // OK
+ u2.a = ManuallyDrop::new(String::from("new")); // OK (assignment does not drop)
+ *u2.a = String::from("new"); //~ ERROR access to union field is unsafe
+
+ let mut u3 = U3 { a: ManuallyDrop::new(0) }; // OK
+ u3.a = ManuallyDrop::new(1); // OK
+ *u3.a = 1; //~ ERROR access to union field is unsafe
+
+ let mut u3 = U3 { a: ManuallyDrop::new(String::from("old")) }; // OK
+ u3.a = ManuallyDrop::new(String::from("new")); // OK (assignment does not drop)
+ *u3.a = String::from("new"); //~ ERROR access to union field is unsafe
+}
diff --git a/src/test/ui/union/union-unsafe.thir.stderr b/src/test/ui/union/union-unsafe.thir.stderr
new file mode 100644
index 000000000..f959fe5bd
--- /dev/null
+++ b/src/test/ui/union/union-unsafe.thir.stderr
@@ -0,0 +1,75 @@
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:33:6
+ |
+LL | *(u.p) = 13;
+ | ^^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:46:6
+ |
+LL | *u3.a = T::default();
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:52:6
+ |
+LL | *u3.a = T::default();
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:60:13
+ |
+LL | let a = u1.a;
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:63:14
+ |
+LL | let U1 { a } = u1;
+ | ^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:64:8
+ |
+LL | if let U1 { a: 12 } = u1 {}
+ | ^^^^^^^^^^^^^^^^^^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:69:6
+ |
+LL | *u2.a = String::from("new");
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:73:6
+ |
+LL | *u3.a = 1;
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:77:6
+ |
+LL | *u3.a = String::from("new");
+ | ^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/union/union-unsized.mirunsafeck.stderr b/src/test/ui/union/union-unsized.mirunsafeck.stderr
new file mode 100644
index 000000000..59ab835fb
--- /dev/null
+++ b/src/test/ui/union/union-unsized.mirunsafeck.stderr
@@ -0,0 +1,39 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+ --> $DIR/union-unsized.rs:5:8
+ |
+LL | a: str,
+ | ^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `str`
+ = note: no field of a union may have a dynamically sized type
+ = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+ |
+LL | a: &str,
+ | +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | a: Box<str>,
+ | ++++ +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+ --> $DIR/union-unsized.rs:13:8
+ |
+LL | b: str,
+ | ^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `str`
+ = note: no field of a union may have a dynamically sized type
+ = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+ |
+LL | b: &str,
+ | +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | b: Box<str>,
+ | ++++ +
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/union/union-unsized.rs b/src/test/ui/union/union-unsized.rs
new file mode 100644
index 000000000..8e897d7d3
--- /dev/null
+++ b/src/test/ui/union/union-unsized.rs
@@ -0,0 +1,17 @@
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+union U {
+ a: str,
+ //~^ ERROR the size for values of type
+
+ b: u8,
+}
+
+union W {
+ a: u8,
+ b: str,
+ //~^ ERROR the size for values of type
+}
+
+fn main() {}
diff --git a/src/test/ui/union/union-unsized.thirunsafeck.stderr b/src/test/ui/union/union-unsized.thirunsafeck.stderr
new file mode 100644
index 000000000..59ab835fb
--- /dev/null
+++ b/src/test/ui/union/union-unsized.thirunsafeck.stderr
@@ -0,0 +1,39 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+ --> $DIR/union-unsized.rs:5:8
+ |
+LL | a: str,
+ | ^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `str`
+ = note: no field of a union may have a dynamically sized type
+ = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+ |
+LL | a: &str,
+ | +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | a: Box<str>,
+ | ++++ +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+ --> $DIR/union-unsized.rs:13:8
+ |
+LL | b: str,
+ | ^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `str`
+ = note: no field of a union may have a dynamically sized type
+ = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+ |
+LL | b: &str,
+ | +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | b: Box<str>,
+ | ++++ +
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/union/union-with-drop-fields.mirunsafeck.stderr b/src/test/ui/union/union-with-drop-fields.mirunsafeck.stderr
new file mode 100644
index 000000000..93fe996d2
--- /dev/null
+++ b/src/test/ui/union/union-with-drop-fields.mirunsafeck.stderr
@@ -0,0 +1,39 @@
+error[E0740]: unions cannot contain fields that may need dropping
+ --> $DIR/union-with-drop-fields.rs:11:5
+ |
+LL | a: String,
+ | ^^^^^^^^^
+ |
+ = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+ |
+LL | a: std::mem::ManuallyDrop<String>,
+ | +++++++++++++++++++++++ +
+
+error[E0740]: unions cannot contain fields that may need dropping
+ --> $DIR/union-with-drop-fields.rs:19:5
+ |
+LL | a: S,
+ | ^^^^
+ |
+ = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+ |
+LL | a: std::mem::ManuallyDrop<S>,
+ | +++++++++++++++++++++++ +
+
+error[E0740]: unions cannot contain fields that may need dropping
+ --> $DIR/union-with-drop-fields.rs:24:5
+ |
+LL | a: T,
+ | ^^^^
+ |
+ = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+ |
+LL | a: std::mem::ManuallyDrop<T>,
+ | +++++++++++++++++++++++ +
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0740`.
diff --git a/src/test/ui/union/union-with-drop-fields.rs b/src/test/ui/union/union-with-drop-fields.rs
new file mode 100644
index 000000000..a7a8b69e7
--- /dev/null
+++ b/src/test/ui/union/union-with-drop-fields.rs
@@ -0,0 +1,31 @@
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![allow(dead_code)]
+
+union U {
+ a: u8, // OK
+}
+
+union W {
+ a: String, //~ ERROR unions cannot contain fields that may need dropping
+ b: String, // OK, only one field is reported
+}
+
+struct S(String);
+
+// `S` doesn't implement `Drop` trait, but still has non-trivial destructor
+union Y {
+ a: S, //~ ERROR unions cannot contain fields that may need dropping
+}
+
+// We don't know if `T` is trivially-destructable or not until trans
+union J<T> {
+ a: T, //~ ERROR unions cannot contain fields that may need dropping
+}
+
+union H<T: Copy> {
+ a: T, // OK, `T` is `Copy`, no destructor
+}
+
+fn main() {}
diff --git a/src/test/ui/union/union-with-drop-fields.thirunsafeck.stderr b/src/test/ui/union/union-with-drop-fields.thirunsafeck.stderr
new file mode 100644
index 000000000..93fe996d2
--- /dev/null
+++ b/src/test/ui/union/union-with-drop-fields.thirunsafeck.stderr
@@ -0,0 +1,39 @@
+error[E0740]: unions cannot contain fields that may need dropping
+ --> $DIR/union-with-drop-fields.rs:11:5
+ |
+LL | a: String,
+ | ^^^^^^^^^
+ |
+ = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+ |
+LL | a: std::mem::ManuallyDrop<String>,
+ | +++++++++++++++++++++++ +
+
+error[E0740]: unions cannot contain fields that may need dropping
+ --> $DIR/union-with-drop-fields.rs:19:5
+ |
+LL | a: S,
+ | ^^^^
+ |
+ = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+ |
+LL | a: std::mem::ManuallyDrop<S>,
+ | +++++++++++++++++++++++ +
+
+error[E0740]: unions cannot contain fields that may need dropping
+ --> $DIR/union-with-drop-fields.rs:24:5
+ |
+LL | a: T,
+ | ^^^^
+ |
+ = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+ |
+LL | a: std::mem::ManuallyDrop<T>,
+ | +++++++++++++++++++++++ +
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0740`.