Rollup merge of #62330 - SimonSapin:no-drop-in-union-fields, r=RalfJung

Change untagged_unions to not allow union fields with drop

This is a rebase of #56440, massaged to solve merge conflicts and make the test suite pass.

Change untagged_unions to not allow union fields with drop

Union fields may now never have a type with attached destructor. This for example allows unions to use arbitrary field types only by wrapping them in `ManuallyDrop` (or similar).

The stable rule remains, that union fields must be `Copy`. We use the new rule for the `untagged_union` feature.

Tracking issue: https://github.com/rust-lang/rust/issues/55149
This commit is contained in:
Mazdak Farrokhzad 2019-10-21 22:00:45 +02:00 committed by GitHub
commit aba84894d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 454 additions and 265 deletions

View File

@ -596,30 +596,6 @@ warning: function cannot return without recursing
|
```
## unions-with-drop-fields
This lint detects use of unions that contain fields with possibly non-trivial drop code. Some
example code that triggers this lint:
```rust
#![feature(untagged_unions)]
union U {
s: String,
}
```
This will produce:
```text
warning: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union
--> src/main.rs:4:5
|
4 | s: String,
| ^^^^^^^^^
|
```
## unknown-lints
This lint detects unrecognized lint attribute. Some

View File

@ -36,5 +36,5 @@ parking_lot = "0.9"
byteorder = { version = "1.3" }
chalk-engine = { version = "0.9.0", default-features=false }
rustc_fs_util = { path = "../librustc_fs_util" }
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
smallvec = { version = "0.6.8", features = ["union", "may_dangle"] }
measureme = "0.3"

View File

@ -818,6 +818,8 @@ impl<'tcx> ty::TyS<'tcx> {
///
/// (Note that this implies that if `ty` has a destructor attached,
/// then `needs_drop` will definitely return `true` for `ty`.)
///
/// Note that this method is used to check eligible types in unions.
#[inline]
pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
tcx.needs_drop_raw(param_env.and(self)).0

View File

@ -980,35 +980,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures {
}
}
declare_lint! {
UNIONS_WITH_DROP_FIELDS,
Warn,
"use of unions that contain fields with possibly non-trivial drop code"
}
declare_lint_pass!(
/// Lint for unions that contain fields with possibly non-trivial destructors.
UnionsWithDropFields => [UNIONS_WITH_DROP_FIELDS]
);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields {
fn check_item(&mut self, ctx: &LateContext<'_, '_>, item: &hir::Item) {
if let hir::ItemKind::Union(ref vdata, _) = item.kind {
for field in vdata.fields() {
let field_ty = ctx.tcx.type_of(
ctx.tcx.hir().local_def_id(field.hir_id));
if field_ty.needs_drop(ctx.tcx, ctx.param_env) {
ctx.span_lint(UNIONS_WITH_DROP_FIELDS,
field.span,
"union contains a field with possibly non-trivial drop code, \
drop code of union fields is ignored when dropping the union");
return;
}
}
}
}
}
declare_lint! {
pub UNREACHABLE_PUB,
Allow,
@ -1288,7 +1259,6 @@ declare_lint_pass!(
NO_MANGLE_GENERIC_ITEMS,
MUTABLE_TRANSMUTES,
UNSTABLE_FEATURES,
UNIONS_WITH_DROP_FIELDS,
UNREACHABLE_PUB,
TYPE_ALIAS_BOUNDS,
TRIVIAL_BOUNDS

View File

@ -164,9 +164,6 @@ macro_rules! late_lint_mod_passes {
// Depends on referenced function signatures in expressions
MutableTransmutes: MutableTransmutes,
// Depends on types of fields, checks if they implement Drop
UnionsWithDropFields: UnionsWithDropFields,
TypeAliasBounds: TypeAliasBounds,
TrivialConstraints: TrivialConstraints,

View File

@ -1387,9 +1387,37 @@ fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
def.destructor(tcx); // force the destructor to be evaluated
check_representable(tcx, span, def_id);
check_transparent(tcx, span, def_id);
check_union_fields(tcx, span, def_id);
check_packed(tcx, span, def_id);
}
/// When the `#![feature(untagged_unions)]` gate is active,
/// check that the fields of the `union` does not contain fields that need dropping.
fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: DefId) -> bool {
let item_type = tcx.type_of(item_def_id);
if let ty::Adt(def, substs) = item_type.kind {
assert!(def.is_union());
let fields = &def.non_enum_variant().fields;
for field in fields {
let field_ty = field.ty(tcx, substs);
// We are currently checking the type this field came from, so it must be local.
let field_span = tcx.hir().span_if_local(field.did).unwrap();
let param_env = tcx.param_env(field.did);
if field_ty.needs_drop(tcx, param_env) {
struct_span_err!(tcx.sess, field_span, E0740,
"unions may not contain fields that need dropping")
.span_note(field_span,
"`std::mem::ManuallyDrop` can be used to wrap the type")
.emit();
return false;
}
}
} else {
span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind);
}
return true;
}
/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
/// projections that would result in "inheriting lifetimes".
fn check_opaque<'tcx>(

View File

@ -4863,6 +4863,10 @@ assert_eq!(1, discriminant(&Enum::Struct{a: 7, b: 11}));
```
"##,
E0740: r##"
A `union` cannot have fields with destructors.
"##,
E0733: r##"
Recursion in an `async fn` requires boxing. For example, this will not compile:

View File

@ -275,6 +275,7 @@
#![feature(link_args)]
#![feature(linkage)]
#![feature(log_syntax)]
#![feature(manually_drop_take)]
#![feature(maybe_uninit_ref)]
#![feature(maybe_uninit_slice)]
#![feature(needs_panic_runtime)]

View File

@ -12,8 +12,7 @@ use core::panic::{BoxMeUp, PanicInfo, Location};
use crate::any::Any;
use crate::fmt;
use crate::intrinsics;
use crate::mem;
use crate::ptr;
use crate::mem::{self, ManuallyDrop};
use crate::raw;
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sys::stdio::panic_output;
@ -227,10 +226,9 @@ pub use realstd::rt::update_panic_count;
/// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
#[allow(unions_with_drop_fields)]
union Data<F, R> {
f: F,
r: R,
f: ManuallyDrop<F>,
r: ManuallyDrop<R>,
}
// We do some sketchy operations with ownership here for the sake of
@ -261,7 +259,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
let mut any_data = 0;
let mut any_vtable = 0;
let mut data = Data {
f,
f: ManuallyDrop::new(f)
};
let r = __rust_maybe_catch_panic(do_call::<F, R>,
@ -271,7 +269,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
return if r == 0 {
debug_assert!(update_panic_count(0) == 0);
Ok(data.r)
Ok(ManuallyDrop::into_inner(data.r))
} else {
update_panic_count(-1);
debug_assert!(update_panic_count(0) == 0);
@ -284,8 +282,9 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
unsafe {
let data = data as *mut Data<F, R>;
let f = ptr::read(&mut (*data).f);
ptr::write(&mut (*data).r, f());
let data = &mut (*data);
let f = ManuallyDrop::take(&mut data.f);
data.r = ManuallyDrop::new(f());
}
}
}

View File

@ -3,13 +3,13 @@
#![feature(associated_type_bounds)]
#![feature(untagged_unions)]
#![allow(unions_with_drop_fields, unused_assignments)]
#![allow(unused_assignments)]
trait Tr1 { type As1; }
trait Tr2 { type As2; }
trait Tr3 { type As3; }
trait Tr4<'a> { type As4; }
trait Tr5 { type As5; }
trait Tr1: Copy { type As1: Copy; }
trait Tr2: Copy { type As2: Copy; }
trait Tr3: Copy { type As3: Copy; }
trait Tr4<'a>: Copy { type As4: Copy; }
trait Tr5: Copy { type As5: Copy; }
impl Tr1 for &str { type As1 = bool; }
impl Tr2 for bool { type As2 = u8; }
@ -71,7 +71,8 @@ where
let _: &'a T = &x.f0;
}
union UnSelf<T> where Self: Tr1<As1: Tr2> {
#[derive(Copy, Clone)]
union UnSelf<T> where Self: Tr1<As1: Tr2>, T: Copy {
f0: T,
f1: <Self as Tr1>::As1,
f2: <<Self as Tr1>::As1 as Tr2>::As2,

View File

@ -8,6 +8,7 @@
#![feature(slice_patterns)]
use std::cell::{Cell, RefCell};
use std::mem::ManuallyDrop;
use std::ops::Generator;
use std::panic;
use std::pin::Pin;
@ -152,17 +153,16 @@ fn assignment1(a: &Allocator, c0: bool) {
_v = _w;
}
#[allow(unions_with_drop_fields)]
union Boxy<T> {
a: T,
b: T,
a: ManuallyDrop<T>,
b: ManuallyDrop<T>,
}
fn union1(a: &Allocator) {
unsafe {
let mut u = Boxy { a: a.alloc() };
u.b = a.alloc();
drop(u.a);
let mut u = Boxy { a: ManuallyDrop::new(a.alloc()) };
*u.b = a.alloc(); // drops first alloc
drop(ManuallyDrop::into_inner(u.a));
}
}

View File

@ -1,7 +1,7 @@
#![feature(untagged_unions)]
trait Tr1 { type As1; }
trait Tr2 { type As2; }
trait Tr1 { type As1: Copy; }
trait Tr2 { type As2: Copy; }
struct S1;
#[derive(Copy, Clone)]
@ -32,7 +32,7 @@ enum _En1<T: Tr1<As1: Tr2>> {
union _Un1<T: Tr1<As1: Tr2>> {
//~^ ERROR associated type bounds are unstable
outest: T,
outest: std::mem::ManuallyDrop<T>,
outer: T::As1,
inner: <T::As1 as Tr2>::As2,
}

View File

@ -7,11 +7,11 @@ union U2<T: Copy> { // OK
}
union U3 { //~ ERROR unions with non-`Copy` fields are unstable
a: String,
a: String, //~ ERROR unions may not contain fields that need dropping
}
union U4<T> { //~ ERROR unions with non-`Copy` fields are unstable
a: T,
a: T, //~ ERROR unions may not contain fields that need dropping
}
union U5 { //~ ERROR unions with `Drop` implementations are unstable

View File

@ -31,6 +31,31 @@ LL | | }
= note: for more information, see https://github.com/rust-lang/rust/issues/32836
= help: add `#![feature(untagged_unions)]` to the crate attributes to enable
error: aborting due to 3 previous errors
error[E0740]: unions may not contain fields that need dropping
--> $DIR/feature-gate-untagged_unions.rs:10:5
|
LL | a: String,
| ^^^^^^^^^
|
note: `std::mem::ManuallyDrop` can be used to wrap the type
--> $DIR/feature-gate-untagged_unions.rs:10:5
|
LL | a: String,
| ^^^^^^^^^
For more information about this error, try `rustc --explain E0658`.
error[E0740]: unions may not contain fields that need dropping
--> $DIR/feature-gate-untagged_unions.rs:14:5
|
LL | a: T,
| ^^^^
|
note: `std::mem::ManuallyDrop` can be used to wrap the type
--> $DIR/feature-gate-untagged_unions.rs:14:5
|
LL | a: T,
| ^^^^
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0658, E0740.
For more information about an error, try `rustc --explain E0658`.

View File

@ -1,13 +1,12 @@
#![feature(rustc_attrs)]
#![feature(untagged_unions)]
#![allow(unions_with_drop_fields)]
#[rustc_outlives]
union Foo<'b, U> { //~ ERROR rustc_outlives
union Foo<'b, U: Copy> { //~ ERROR rustc_outlives
bar: Bar<'b, U>
}
union Bar<'a, T> where T: 'a {
union Bar<'a, T: Copy> where T: 'a {
x: &'a (),
y: T,
}

View File

@ -1,7 +1,7 @@
error: rustc_outlives
--> $DIR/explicit-union.rs:6:1
--> $DIR/explicit-union.rs:5:1
|
LL | / union Foo<'b, U> {
LL | / union Foo<'b, U: Copy> {
LL | | bar: Bar<'b, U>
LL | | }
| |_^

View File

@ -1,14 +1,13 @@
#![feature(rustc_attrs)]
#![feature(untagged_unions)]
#![allow(unions_with_drop_fields)]
#[rustc_outlives]
union Foo<'a, T> { //~ ERROR rustc_outlives
union Foo<'a, T: Copy> { //~ ERROR rustc_outlives
field1: Bar<'a, T>
}
// Type U needs to outlive lifetime 'b
union Bar<'b, U> {
union Bar<'b, U: Copy> {
field2: &'b U
}

View File

@ -1,7 +1,7 @@
error: rustc_outlives
--> $DIR/nested-union.rs:6:1
--> $DIR/nested-union.rs:5:1
|
LL | / union Foo<'a, T> {
LL | / union Foo<'a, T: Copy> {
LL | | field1: Bar<'a, T>
LL | | }
| |_^

View File

@ -3,7 +3,8 @@
#![feature(untagged_unions)]
#![allow(dead_code)]
#![allow(unions_with_drop_fields)]
use std::mem::ManuallyDrop;
enum A<'a, T: 'a>
where
@ -24,6 +25,14 @@ where
union C<'a, T: 'a>
where
Self: Send, T: PartialEq<Self>
{
foo: &'a Self,
bar: ManuallyDrop<T>,
}
union D<'a, T: 'a>
where
Self: Send, T: PartialEq<Self> + Copy
{
foo: &'a Self,
bar: T,

View File

@ -0,0 +1,24 @@
#![feature(untagged_unions)]
union Test {
a: A, //~ ERROR unions may not contain fields that 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); }
}

View File

@ -0,0 +1,15 @@
error[E0740]: unions may not contain fields that need dropping
--> $DIR/issue-41073.rs:4:5
|
LL | a: A,
| ^^^^
|
note: `std::mem::ManuallyDrop` can be used to wrap the type
--> $DIR/issue-41073.rs:4:5
|
LL | a: A,
| ^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0740`.

View File

@ -1,51 +1,90 @@
#![feature(untagged_unions)]
#![allow(unused)]
#[allow(unions_with_drop_fields)]
use std::ops::{Deref, DerefMut};
#[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: ((Vec<u8>, Vec<u8>), Vec<u8>),
y: Box<Vec<u8>>,
x: ((MockVec<u8>, MockVec<u8>), MockVec<u8>),
y: MockBox<MockVec<u8>>,
}
fn use_borrow<T>(_: &T) {}
unsafe fn parent_sibling_borrow() {
let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
let mut u = U { x: ((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: ((Vec::new(), Vec::new()), Vec::new()) };
let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
let a = u.x.0;
let b = u.y; //~ ERROR use of moved value: `u`
}
unsafe fn grandparent_sibling_borrow() {
let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
let mut u = U { x: ((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: ((Vec::new(), Vec::new()), Vec::new()) };
let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
let a = (u.x.0).0;
let b = u.y; //~ ERROR use of moved value: `u`
}
unsafe fn deref_sibling_borrow() {
let mut u = U { y: Box::default() };
let mut u = U { y: 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: ((Vec::new(), Vec::new()), Vec::new()) };
let a = *u.y;
let b = u.x; //~ ERROR use of moved value: `u`
let u = U { x: ((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`
}

View File

@ -1,5 +1,5 @@
error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`)
--> $DIR/union-borrow-move-parent-sibling.rs:15:13
--> $DIR/union-borrow-move-parent-sibling.rs:53:13
|
LL | let a = &mut u.x.0;
| ---------- mutable borrow occurs here (via `u.x.0`)
@ -11,9 +11,9 @@ LL | use_borrow(a);
= note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0`
error[E0382]: use of moved value: `u`
--> $DIR/union-borrow-move-parent-sibling.rs:22:13
--> $DIR/union-borrow-move-parent-sibling.rs:60:13
|
LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
LL | let u = U { x: ((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;
| ----- value moved here
@ -21,7 +21,7 @@ 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.0.0`)
--> $DIR/union-borrow-move-parent-sibling.rs:28:13
--> $DIR/union-borrow-move-parent-sibling.rs:66:13
|
LL | let a = &mut (u.x.0).0;
| -------------- mutable borrow occurs here (via `u.x.0.0`)
@ -33,38 +33,28 @@ LL | use_borrow(a);
= note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0`
error[E0382]: use of moved value: `u`
--> $DIR/union-borrow-move-parent-sibling.rs:35:13
--> $DIR/union-borrow-move-parent-sibling.rs:73:13
|
LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
LL | let u = U { x: ((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;
| --------- 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:41:13
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:79:13
|
LL | let a = &mut *u.y;
| --------- mutable borrow occurs here (via `*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
| ^^^^ 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`
= note: `u.x` is a field of the union `U`, so it overlaps the field `u.y`
error[E0382]: use of moved value: `u`
--> $DIR/union-borrow-move-parent-sibling.rs:48:13
|
LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
| - move occurs because `u` has type `U`, which does not implement the `Copy` trait
LL | let a = *u.y;
| ---- value moved here
LL | let b = u.x;
| ^^^ value used here after move
error: aborting due to 6 previous errors
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0382, E0502.
For more information about an error, try `rustc --explain E0382`.

View File

@ -0,0 +1,19 @@
// test for a union with a field that's a union with a manual impl Drop
// Ensures we do not treat all unions as not having any drop glue.
#![feature(untagged_unions)]
union Foo {
bar: Bar, //~ ERROR unions may not contain fields that need dropping
}
union Bar {
a: i32,
b: u32,
}
impl Drop for Bar {
fn drop(&mut self) {}
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0740]: unions may not contain fields that need dropping
--> $DIR/union-custom-drop.rs:7:5
|
LL | bar: Bar,
| ^^^^^^^^
|
note: `std::mem::ManuallyDrop` can be used to wrap the type
--> $DIR/union-custom-drop.rs:7:5
|
LL | bar: Bar,
| ^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0740`.

View File

@ -1,5 +1,7 @@
#![feature(untagged_unions)]
use std::mem::ManuallyDrop;
#[derive(Clone)] //~ ERROR the trait bound `U1: std::marker::Copy` is not satisfied
union U1 {
a: u8,
@ -18,14 +20,19 @@ union U3 {
}
#[derive(Clone, Copy)]
union U4<T> {
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 = U4 { a: CloneNoCopy };
let w = u.clone(); //~ ERROR no method named `clone` found for type `U4<CloneNoCopy>`
let u = U5 { a: ManuallyDrop::new(CloneNoCopy) };
let w = u.clone(); //~ ERROR no method named `clone` found for type `U5<CloneNoCopy>`
}

View File

@ -1,22 +1,22 @@
error[E0277]: the trait bound `U1: std::marker::Copy` is not satisfied
--> $DIR/union-derive-clone.rs:3:10
--> $DIR/union-derive-clone.rs:5:10
|
LL | #[derive(Clone)]
| ^^^^^ the trait `std::marker::Copy` is not implemented for `U1`
|
= note: required by `std::clone::AssertParamIsCopy`
error[E0599]: no method named `clone` found for type `U4<CloneNoCopy>` in the current scope
--> $DIR/union-derive-clone.rs:30:15
error[E0599]: no method named `clone` found for type `U5<CloneNoCopy>` in the current scope
--> $DIR/union-derive-clone.rs:37:15
|
LL | union U4<T> {
LL | union U5<T> {
| ----------- method `clone` not found for this
...
LL | let w = u.clone();
| ^^^^^ method not found in `U4<CloneNoCopy>`
| ^^^^^ method not found in `U5<CloneNoCopy>`
|
= note: the method `clone` exists but the following trait bounds were not satisfied:
`U4<CloneNoCopy> : std::clone::Clone`
`U5<CloneNoCopy> : std::clone::Clone`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `clone`, perhaps you need to implement it:
candidate #1: `std::clone::Clone`

View File

@ -1,7 +1,6 @@
// run-pass
#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unions_with_drop_fields)]
// Some traits can be derived for unions.
@ -24,11 +23,11 @@ impl PartialEq for U { fn eq(&self, rhs: &Self) -> bool { true } }
Copy,
Eq
)]
union W<T> {
union W<T: Copy> {
a: T,
}
impl<T> PartialEq for W<T> { fn eq(&self, rhs: &Self) -> bool { true } }
impl<T: Copy> PartialEq for W<T> { fn eq(&self, rhs: &Self) -> bool { true } }
fn main() {
let u = U { b: 0 };

View File

@ -1,15 +1,16 @@
// run-pass
#![allow(unused_assignments)]
#![allow(unions_with_drop_fields)]
// Drop works for union itself.
#![feature(untagged_unions)]
use std::mem::ManuallyDrop;
struct S;
union U {
a: S
a: ManuallyDrop<S>
}
impl Drop for S {
@ -28,11 +29,11 @@ static mut CHECK: u8 = 0;
fn main() {
unsafe {
let mut u = U { a: S };
let mut u = U { a: ManuallyDrop::new(S) };
assert_eq!(CHECK, 0);
u = U { a: S };
u = U { a: ManuallyDrop::new(S) };
assert_eq!(CHECK, 1); // union itself is assigned, union is dropped, field is not dropped
u.a = S;
*u.a = S;
assert_eq!(CHECK, 11); // union field is assigned, field is dropped
}
}

View File

@ -1,7 +1,6 @@
// run-pass
#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unions_with_drop_fields)]
// Drop works for union itself.
@ -21,12 +20,6 @@ union Y {
a: S,
}
impl Drop for S {
fn drop(&mut self) {
unsafe { CHECK += 10; }
}
}
impl Drop for U {
fn drop(&mut self) {
unsafe { CHECK += 1; }
@ -51,10 +44,10 @@ fn main() {
{
let w = W { a: S };
}
assert_eq!(CHECK, 2); // 2, not 11, dtor of S is not called
assert_eq!(CHECK, 2); // 2, dtor of W is called
{
let y = Y { a: S };
}
assert_eq!(CHECK, 2); // 2, not 12, dtor of S is not called
assert_eq!(CHECK, 2); // 2, dtor of Y is called
}
}

View File

@ -1,37 +1,33 @@
// run-pass
#![allow(dead_code)]
#![allow(unions_with_drop_fields)]
#![feature(untagged_unions)]
use std::mem::ManuallyDrop;
union MaybeItem<T: Iterator> {
elem: T::Item,
elem: ManuallyDrop<T::Item>,
none: (),
}
union U<A, B> {
union U<A, B> where A: Copy, B: Copy {
a: A,
b: B,
}
unsafe fn union_transmute<A, B>(a: A) -> B {
unsafe fn union_transmute<A, B>(a: A) -> B where A: Copy, B: Copy {
U { a: a }.b
}
fn main() {
unsafe {
let u = U::<String, Vec<u8>> { a: String::from("abcd") };
assert_eq!(u.b.len(), 4);
assert_eq!(u.b[0], b'a');
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: i.next().unwrap() };
assert_eq!(*mi.elem, 2);
let mi = MaybeItem::<std::slice::Iter<_>> { elem: ManuallyDrop::new(i.next().unwrap()) };
assert_eq!(**mi.elem, 2);
}
}

View File

@ -0,0 +1,42 @@
#![feature(untagged_unions)]
#![allow(dead_code)]
// run-pass
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>>());
}

View File

@ -1,12 +1,11 @@
// run-pass
#![feature(core_intrinsics)]
#![feature(untagged_unions)]
#![allow(unions_with_drop_fields)]
#![allow(dead_code)]
use std::intrinsics::needs_drop;
use std::mem::needs_drop;
use std::mem::ManuallyDrop;
struct NeedDrop;
@ -16,10 +15,14 @@ impl Drop for NeedDrop {
// Constant expressios allow `NoDrop` to go out of scope,
// unlike a value of the interior type implementing `Drop`.
static X: () = (NoDrop { inner: NeedDrop }, ()).1;
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: T}
union NoDrop<T> { inner: ManuallyDrop<T> }
// Copy currently can't be implemented on drop-containing unions,
// this may change later
@ -40,7 +43,7 @@ struct Baz {
y: Box<u8>,
}
union ActuallyDrop<T> {inner: T}
union ActuallyDrop<T> { inner: ManuallyDrop<T> }
impl<T> Drop for ActuallyDrop<T> {
fn drop(&mut self) {}

View File

@ -1,21 +1,27 @@
// run-pass
#![allow(unions_with_drop_fields)]
#![feature(untagged_unions)]
#[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> {
union U<A, B>
where
A: Copy, B: Copy
{
a: Pair<A, A>,
b: B,
}
#[repr(C)]
union W<A, B> {
union W<A, B>
where
A: Copy, B: Copy
{
a: A,
b: B,
}

View File

@ -1,15 +1,16 @@
#![feature(untagged_unions)]
use std::mem::ManuallyDrop;
union U1 {
a: u8
}
union U2 {
a: String
a: ManuallyDrop<String>
}
union U3<T> {
a: T
a: ManuallyDrop<T>
}
union U4<T: Copy> {
@ -17,13 +18,16 @@ union U4<T: Copy> {
}
fn generic_noncopy<T: Default>() {
let mut u3 = U3 { a: T::default() };
u3.a = T::default(); //~ ERROR assignment to non-`Copy` union field is unsafe
let mut u3 = U3 { a: ManuallyDrop::new(T::default()) };
u3.a = ManuallyDrop::new(T::default()); //~ ERROR assignment to non-`Copy` union field is unsafe
*u3.a = T::default(); //~ ERROR access to union field is unsafe
}
fn generic_copy<T: Copy + Default>() {
let mut u3 = U3 { a: T::default() };
u3.a = T::default(); // OK
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
}
@ -32,14 +36,20 @@ 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: String::from("old") }; // OK
u2.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field is unsafe
let mut u3 = U3 { a: 0 }; // OK
u3.a = 1; // OK
let mut u3 = U3 { a: String::from("old") }; // OK
u3.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field is unsafe
let mut u2 = U2 { a: ManuallyDrop::new(String::from("old")) }; // OK
u2.a = ManuallyDrop::new(String::from("new")); //~ ERROR assignment to non-`Copy` union
*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")); //~ ERROR assignment to non-`Copy` union
*u3.a = String::from("new"); //~ ERROR access to union field is unsafe
}

View File

@ -1,13 +1,29 @@
error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:21:5
--> $DIR/union-unsafe.rs:22:5
|
LL | u3.a = T::default();
| ^^^^ assignment to non-`Copy` union field
LL | u3.a = ManuallyDrop::new(T::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
|
= note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
error[E0133]: access to union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:33:13
--> $DIR/union-unsafe.rs:23: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:29: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:37:13
|
LL | let a = u1.a;
| ^^^^ access to union field
@ -15,7 +31,7 @@ LL | let a = u1.a;
= 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:35:14
--> $DIR/union-unsafe.rs:40:14
|
LL | let U1 { a } = u1;
| ^ access to union field
@ -23,7 +39,7 @@ LL | let U1 { a } = u1;
= 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:36:20
--> $DIR/union-unsafe.rs:41:20
|
LL | if let U1 { a: 12 } = u1 {}
| ^^ access to union field
@ -31,21 +47,45 @@ LL | if let U1 { a: 12 } = u1 {}
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:40:5
--> $DIR/union-unsafe.rs:45:5
|
LL | u2.a = String::from("new");
| ^^^^ assignment to non-`Copy` union field
LL | u2.a = ManuallyDrop::new(String::from("new"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
|
= note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
error[E0133]: access to union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:46: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:50: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]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:44:5
--> $DIR/union-unsafe.rs:53:5
|
LL | u3.a = String::from("new");
| ^^^^ assignment to non-`Copy` union field
LL | u3.a = ManuallyDrop::new(String::from("new"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
|
= note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
error: aborting due to 6 previous errors
error[E0133]: access to union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:54: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 11 previous errors
For more information about this error, try `rustc --explain E0133`.

View File

@ -1,32 +0,0 @@
// run-pass
#![feature(untagged_unions)]
#![allow(dead_code)]
#![allow(unions_with_drop_fields)]
union U {
a: u8, // OK
}
union W {
a: String, // OK
b: String, // OK
}
struct S(String);
// `S` doesn't implement `Drop` trait, but still has non-trivial destructor
union Y {
a: S, // OK
}
// We don't know if `T` is trivially-destructable or not until trans
union J<T> {
a: T, // OK
}
union H<T: Copy> {
a: T, // OK
}
fn main() {}

View File

@ -1,26 +0,0 @@
error: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union
--> $DIR/union-with-drop-fields-lint.rs:10:5
|
LL | a: String,
| ^^^^^^^^^
|
note: lint level defined here
--> $DIR/union-with-drop-fields-lint.rs:3:9
|
LL | #![deny(unions_with_drop_fields)]
| ^^^^^^^^^^^^^^^^^^^^^^^
error: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union
--> $DIR/union-with-drop-fields-lint.rs:18:5
|
LL | a: S,
| ^^^^
error: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union
--> $DIR/union-with-drop-fields-lint.rs:23:5
|
LL | a: T,
| ^^^^
error: aborting due to 3 previous errors

View File

@ -1,13 +1,12 @@
#![feature(untagged_unions)]
#![allow(dead_code)]
#![deny(unions_with_drop_fields)]
union U {
a: u8, // OK
}
union W {
a: String, //~ ERROR union contains a field with possibly non-trivial drop code
a: String, //~ ERROR unions may not contain fields that need dropping
b: String, // OK, only one field is reported
}
@ -15,12 +14,12 @@ struct S(String);
// `S` doesn't implement `Drop` trait, but still has non-trivial destructor
union Y {
a: S, //~ ERROR union contains a field with possibly non-trivial drop code
a: S, //~ ERROR unions may not contain fields that need dropping
}
// We don't know if `T` is trivially-destructable or not until trans
union J<T> {
a: T, //~ ERROR union contains a field with possibly non-trivial drop code
a: T, //~ ERROR unions may not contain fields that need dropping
}
union H<T: Copy> {

View File

@ -0,0 +1,39 @@
error[E0740]: unions may not contain fields that need dropping
--> $DIR/union-with-drop-fields.rs:9:5
|
LL | a: String,
| ^^^^^^^^^
|
note: `std::mem::ManuallyDrop` can be used to wrap the type
--> $DIR/union-with-drop-fields.rs:9:5
|
LL | a: String,
| ^^^^^^^^^
error[E0740]: unions may not contain fields that need dropping
--> $DIR/union-with-drop-fields.rs:17:5
|
LL | a: S,
| ^^^^
|
note: `std::mem::ManuallyDrop` can be used to wrap the type
--> $DIR/union-with-drop-fields.rs:17:5
|
LL | a: S,
| ^^^^
error[E0740]: unions may not contain fields that need dropping
--> $DIR/union-with-drop-fields.rs:22:5
|
LL | a: T,
| ^^^^
|
note: `std::mem::ManuallyDrop` can be used to wrap the type
--> $DIR/union-with-drop-fields.rs:22:5
|
LL | a: T,
| ^^^^
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0740`.