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:
commit
aba84894d1
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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 | | }
|
||||
| |_^
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 | | }
|
||||
| |_^
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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); }
|
||||
}
|
|
@ -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`.
|
|
@ -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`
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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() {}
|
|
@ -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`.
|
|
@ -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>`
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>>());
|
||||
}
|
|
@ -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) {}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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() {}
|
|
@ -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
|
||||
|
|
@ -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> {
|
|
@ -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`.
|
Loading…
Reference in New Issue