stabilize union with 'ManuallyDrop' fields and 'impl Drop for Union'

This commit is contained in:
Ralf Jung 2020-10-04 22:24:14 +02:00
parent 8e6f69afc9
commit 6a32e794c2
30 changed files with 97 additions and 148 deletions

View File

@ -13,15 +13,13 @@ use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Varian
use rustc_middle::hir::map::Map;
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::middle::stability::{DeprecationEntry, Index};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{self, query::Providers, TyCtxt};
use rustc_session::lint;
use rustc_session::lint::builtin::INEFFECTIVE_UNSTABLE_TRAIT_IMPL;
use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use rustc_trait_selection::traits::misc::can_type_implement_copy;
use rustc_span::{Span, DUMMY_SP};
use std::cmp::Ordering;
use std::mem::replace;
@ -711,27 +709,35 @@ impl Visitor<'tcx> for Checker<'tcx> {
// so semi-randomly perform it here in stability.rs
hir::ItemKind::Union(..) if !self.tcx.features().untagged_unions => {
let def_id = self.tcx.hir().local_def_id(item.hir_id);
let adt_def = self.tcx.adt_def(def_id);
let ty = self.tcx.type_of(def_id);
let (adt_def, substs) = match ty.kind() {
ty::Adt(adt_def, substs) => (adt_def, substs),
_ => bug!(),
};
if adt_def.has_dtor(self.tcx) {
feature_err(
&self.tcx.sess.parse_sess,
sym::untagged_unions,
item.span,
"unions with `Drop` implementations are unstable",
)
.emit();
} else {
let param_env = self.tcx.param_env(def_id);
if can_type_implement_copy(self.tcx, param_env, ty).is_err() {
feature_err(
&self.tcx.sess.parse_sess,
sym::untagged_unions,
item.span,
"unions with non-`Copy` fields are unstable",
)
.emit();
// Non-`Copy` fields are unstable, except for `ManuallyDrop`.
let param_env = self.tcx.param_env(def_id);
for field in &adt_def.non_enum_variant().fields {
let field_ty = field.ty(self.tcx, substs);
if !field_ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop())
&& !field_ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), param_env)
{
if field_ty.needs_drop(self.tcx, param_env) {
// Avoid duplicate error: This will error later anyway because fields
// that need drop are not allowed.
self.tcx.sess.delay_span_bug(
item.span,
"union should have been rejected due to potentially dropping field",
);
} else {
feature_err(
&self.tcx.sess.parse_sess,
sym::untagged_unions,
self.tcx.def_span(field.did),
"unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable",
)
.emit();
}
}
}
}

View File

@ -348,8 +348,7 @@ pub(super) fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
check_packed(tcx, span, def);
}
/// When the `#![feature(untagged_unions)]` gate is active,
/// check that the fields of the `union` does not contain fields that need dropping.
/// Check that the fields of the `union` do not need dropping.
pub(super) fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
let item_type = tcx.type_of(item_def_id);
if let ty::Adt(def, substs) = item_type.kind() {

View File

@ -68,7 +68,6 @@ enum N<F> where F: Fn() -> _ {
union O<F> where F: Fn() -> _ {
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
//~| ERROR unions with non-`Copy` fields are unstable
foo: F,
}

View File

@ -57,19 +57,6 @@ LL | type J = ty!(u8);
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0658]: unions with non-`Copy` fields are unstable
--> $DIR/bad-assoc-ty.rs:69:1
|
LL | / union O<F> where F: Fn() -> _ {
LL | |
LL | |
LL | | foo: F,
LL | | }
| |_^
|
= note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information
= help: add `#![feature(untagged_unions)]` to the crate attributes to enable
error[E0223]: ambiguous associated type
--> $DIR/bad-assoc-ty.rs:1:10
|
@ -215,7 +202,7 @@ LL | union O<F, T> where F: Fn() -> T {
| ^^^ ^
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/bad-assoc-ty.rs:75:29
--> $DIR/bad-assoc-ty.rs:74:29
|
LL | trait P<F> where F: Fn() -> _ {
| ^ not allowed in type signatures
@ -226,7 +213,7 @@ LL | trait P<F, T> where F: Fn() -> T {
| ^^^ ^
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/bad-assoc-ty.rs:80:38
--> $DIR/bad-assoc-ty.rs:79:38
|
LL | fn foo<F>(_: F) where F: Fn() -> _ {}
| ^ not allowed in type signatures
@ -236,7 +223,7 @@ help: use type parameters instead
LL | fn foo<F, T>(_: F) where F: Fn() -> T {}
| ^^^ ^
error: aborting due to 29 previous errors
error: aborting due to 28 previous errors
Some errors have detailed explanations: E0121, E0223, E0658.
Some errors have detailed explanations: E0121, E0223.
For more information about an error, try `rustc --explain E0121`.

View File

@ -1,7 +1,7 @@
// run-pass
// ignore-wasm32-bare compiled with panic=abort by default
#![feature(generators, generator_trait, untagged_unions)]
#![feature(generators, generator_trait)]
#![feature(bindings_after_at)]
#![allow(unused_assignments)]

View File

@ -1,5 +1,3 @@
#![feature(untagged_unions)]
use std::cell::Cell;
use std::ops::Deref;
use std::mem::ManuallyDrop;

View File

@ -1,5 +1,5 @@
error[E0597]: `v` does not live long enough
--> $DIR/dropck-union.rs:39:18
--> $DIR/dropck-union.rs:37:18
|
LL | v.0.set(Some(&v));
| ^^ borrowed value does not live long enough

View File

@ -1,3 +1,5 @@
// ignore-tidy-linelength
union U1 { // OK
a: u8,
}
@ -6,15 +8,23 @@ union U2<T: Copy> { // OK
a: T,
}
union U3 { //~ ERROR unions with non-`Copy` fields are unstable
union U22<T> { // OK
a: std::mem::ManuallyDrop<T>,
}
union U3 {
a: String, //~ ERROR unions may not contain fields that need dropping
}
union U4<T> { //~ ERROR unions with non-`Copy` fields are unstable
union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test!
a: std::cell::RefCell<i32>, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable
}
union U4<T> {
a: T, //~ ERROR unions may not contain fields that need dropping
}
union U5 { //~ ERROR unions with `Drop` implementations are unstable
union U5 { // Having a drop impl is OK
a: u8,
}

View File

@ -1,61 +1,37 @@
error[E0658]: unions with non-`Copy` fields are unstable
--> $DIR/feature-gate-untagged_unions.rs:9:1
error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable
--> $DIR/feature-gate-untagged_unions.rs:20:5
|
LL | / union U3 {
LL | | a: String,
LL | | }
| |_^
|
= note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information
= help: add `#![feature(untagged_unions)]` to the crate attributes to enable
error[E0658]: unions with non-`Copy` fields are unstable
--> $DIR/feature-gate-untagged_unions.rs:13:1
|
LL | / union U4<T> {
LL | | a: T,
LL | | }
| |_^
|
= note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information
= help: add `#![feature(untagged_unions)]` to the crate attributes to enable
error[E0658]: unions with `Drop` implementations are unstable
--> $DIR/feature-gate-untagged_unions.rs:17:1
|
LL | / union U5 {
LL | | a: u8,
LL | | }
| |_^
LL | a: std::cell::RefCell<i32>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information
= help: add `#![feature(untagged_unions)]` to the crate attributes to enable
error[E0740]: unions may not contain fields that need dropping
--> $DIR/feature-gate-untagged_unions.rs:10:5
--> $DIR/feature-gate-untagged_unions.rs:16:5
|
LL | a: String,
| ^^^^^^^^^
|
note: `std::mem::ManuallyDrop` can be used to wrap the type
--> $DIR/feature-gate-untagged_unions.rs:10:5
--> $DIR/feature-gate-untagged_unions.rs:16:5
|
LL | a: String,
| ^^^^^^^^^
error[E0740]: unions may not contain fields that need dropping
--> $DIR/feature-gate-untagged_unions.rs:14:5
--> $DIR/feature-gate-untagged_unions.rs:24:5
|
LL | a: T,
| ^^^^
|
note: `std::mem::ManuallyDrop` can be used to wrap the type
--> $DIR/feature-gate-untagged_unions.rs:14:5
--> $DIR/feature-gate-untagged_unions.rs:24:5
|
LL | a: T,
| ^^^^
error: aborting due to 5 previous errors
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0658, E0740.
For more information about an error, try `rustc --explain E0658`.

View File

@ -1,15 +1,3 @@
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not
--> $DIR/reject-specialized-drops-8142.rs:67:21
|
LL | impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT
| ^^^^^
|
note: the implementor must specify the same requirement
--> $DIR/reject-specialized-drops-8142.rs:21:1
|
LL | union Union<T: Copy> { f: T }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not
--> $DIR/reject-specialized-drops-8142.rs:23:20
|
@ -145,6 +133,18 @@ note: the implementor must specify the same requirement
LL | struct TupleStruct<T>(T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not
--> $DIR/reject-specialized-drops-8142.rs:67:21
|
LL | impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT
| ^^^^^
|
note: the implementor must specify the same requirement
--> $DIR/reject-specialized-drops-8142.rs:21:1
|
LL | union Union<T: Copy> { f: T }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 11 previous errors
Some errors have detailed explanations: E0308, E0366, E0367, E0495.

View File

@ -1,7 +1,4 @@
// build-pass (FIXME(62277): could be check-pass?)
#![feature(untagged_unions)]
#![allow(dead_code)]
use std::mem::ManuallyDrop;

View File

@ -1,9 +1,6 @@
// normalize-stderr-32bit: "`&str` \(64 bits\)" -> "`&str` ($$STR bits)"
// normalize-stderr-64bit: "`&str` \(128 bits\)" -> "`&str` ($$STR bits)"
#![feature(untagged_unions)]
use std::mem::transmute;
pub trait TypeConstructor<'a> {

View File

@ -1,5 +1,5 @@
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/main.rs:16:5
--> $DIR/main.rs:13:5
|
LL | transmute(x)
| ^^^^^^^^^
@ -7,7 +7,7 @@ LL | transmute(x)
= note: `<C as TypeConstructor>::T` does not have a fixed size
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/main.rs:20:17
--> $DIR/main.rs:17:17
|
LL | let x: u8 = transmute(10u16);
| ^^^^^^^^^
@ -16,7 +16,7 @@ LL | let x: u8 = transmute(10u16);
= note: target type: `u8` (8 bits)
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/main.rs:24:17
--> $DIR/main.rs:21:17
|
LL | let x: u8 = transmute("test");
| ^^^^^^^^^
@ -25,7 +25,7 @@ LL | let x: u8 = transmute("test");
= note: target type: `u8` (8 bits)
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/main.rs:29:18
--> $DIR/main.rs:26:18
|
LL | let x: Foo = transmute(10);
| ^^^^^^^^^

View File

@ -1,8 +1,6 @@
// run-pass
#![allow(dead_code)]
#![feature(untagged_unions)]
use std::mem::{size_of, size_of_val, align_of, align_of_val};
#[repr(align(16))]
@ -35,6 +33,7 @@ mod hybrid {
use std::mem::{size_of, align_of};
#[repr(align(16))]
#[derive(Copy, Clone)]
struct S1 {
a: u16,
b: u8,

View File

@ -1,5 +1,3 @@
#![feature(untagged_unions)]
#[derive(Clone)]
union U {
a: u8
@ -7,7 +5,7 @@ union U {
#[derive(Clone)]
union W {
a: String
a: std::mem::ManuallyDrop<String>
}
impl Copy for U {} // OK

View File

@ -1,8 +1,8 @@
error[E0204]: the trait `Copy` may not be implemented for this type
--> $DIR/union-copy.rs:14:6
--> $DIR/union-copy.rs:12:6
|
LL | a: String
| --------- this field does not implement `Copy`
LL | a: std::mem::ManuallyDrop<String>
| --------------------------------- this field does not implement `Copy`
...
LL | impl Copy for W {}
| ^^^^

View File

@ -1,5 +1,3 @@
#![feature(untagged_unions)]
use std::mem::ManuallyDrop;
#[derive(Clone)] //~ ERROR the trait bound `U1: Copy` is not satisfied

View File

@ -1,5 +1,5 @@
error[E0277]: the trait bound `U1: Copy` is not satisfied
--> $DIR/union-derive-clone.rs:5:10
--> $DIR/union-derive-clone.rs:3:10
|
LL | #[derive(Clone)]
| ^^^^^ the trait `Copy` is not implemented for `U1`
@ -12,7 +12,7 @@ LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0599]: no method named `clone` found for union `U5<CloneNoCopy>` in the current scope
--> $DIR/union-derive-clone.rs:37:15
--> $DIR/union-derive-clone.rs:35:15
|
LL | union U5<T> {
| -----------

View File

@ -1,5 +1,3 @@
#![feature(untagged_unions)]
#[derive(Eq)] // OK
union U1 {
a: u8,
@ -7,7 +5,7 @@ union U1 {
impl PartialEq for U1 { fn eq(&self, rhs: &Self) -> bool { true } }
#[derive(PartialEq)]
#[derive(PartialEq, Copy, Clone)]
struct PartialEqNotEq;
#[derive(Eq)]

View File

@ -1,5 +1,5 @@
error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied
--> $DIR/union-derive-eq.rs:15:5
--> $DIR/union-derive-eq.rs:13:5
|
LL | a: PartialEqNotEq,
| ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`

View File

@ -4,8 +4,6 @@
// Some traits can be derived for unions.
#![feature(untagged_unions)]
#[derive(
Copy,
Clone,

View File

@ -3,8 +3,6 @@
// Drop works for union itself.
#![feature(untagged_unions)]
use std::mem::ManuallyDrop;
struct S;

View File

@ -4,8 +4,7 @@
// Drop works for union itself.
#![feature(untagged_unions)]
#[derive(Copy, Clone)]
struct S;
union U {

View File

@ -1,8 +1,6 @@
// run-pass
#![allow(dead_code)]
#![feature(untagged_unions)]
use std::mem::ManuallyDrop;
union MaybeItem<T: Iterator> {
@ -16,7 +14,7 @@ union U<A, B> where A: Copy, B: Copy {
}
unsafe fn union_transmute<A, B>(a: A) -> B where A: Copy, B: Copy {
U { a: a }.b
U { a }.b
}
fn main() {

View File

@ -1,4 +1,3 @@
#![feature(untagged_unions)]
#![allow(dead_code)]
// run-pass

View File

@ -1,7 +1,5 @@
// run-pass
#![feature(untagged_unions)]
#![allow(dead_code)]
use std::mem::needs_drop;

View File

@ -1,5 +1,4 @@
// run-pass
#![feature(untagged_unions)]
#[repr(C)]
#[derive(Copy, Clone)]

View File

@ -2,8 +2,6 @@
#![allow(dead_code)]
#![allow(non_snake_case)]
#![feature(untagged_unions)]
use std::mem::{size_of, size_of_val, align_of, align_of_val};
struct S {
@ -118,6 +116,7 @@ mod hybrid {
use std::mem::{size_of, align_of};
#[repr(packed)]
#[derive(Copy, Clone)]
struct S1 {
a: u16,
b: u8,

View File

@ -1,4 +1,3 @@
#![feature(untagged_unions)]
use std::mem::ManuallyDrop;
union U1 {

View File

@ -1,5 +1,5 @@
error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:22:5
--> $DIR/union-unsafe.rs:21:5
|
LL | u3.a = ManuallyDrop::new(T::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
@ -7,7 +7,7 @@ LL | u3.a = ManuallyDrop::new(T::default());
= 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:23:6
--> $DIR/union-unsafe.rs:22:6
|
LL | *u3.a = T::default();
| ^^^^ access to union field
@ -15,7 +15,7 @@ LL | *u3.a = T::default();
= 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
--> $DIR/union-unsafe.rs:28:6
|
LL | *u3.a = T::default();
| ^^^^ access to union field
@ -23,7 +23,7 @@ LL | *u3.a = T::default();
= 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
--> $DIR/union-unsafe.rs:36:13
|
LL | let a = u1.a;
| ^^^^ access to union field
@ -31,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:40:14
--> $DIR/union-unsafe.rs:39:14
|
LL | let U1 { a } = u1;
| ^ access to union field
@ -39,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:41:20
--> $DIR/union-unsafe.rs:40:20
|
LL | if let U1 { a: 12 } = u1 {}
| ^^ access to union field
@ -47,7 +47,7 @@ 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:45:5
--> $DIR/union-unsafe.rs:44:5
|
LL | u2.a = ManuallyDrop::new(String::from("new"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
@ -55,7 +55,7 @@ LL | u2.a = ManuallyDrop::new(String::from("new"));
= 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
--> $DIR/union-unsafe.rs:45:6
|
LL | *u2.a = String::from("new");
| ^^^^ access to union field
@ -63,7 +63,7 @@ LL | *u2.a = String::from("new");
= 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
--> $DIR/union-unsafe.rs:49:6
|
LL | *u3.a = 1;
| ^^^^ access to union field
@ -71,7 +71,7 @@ LL | *u3.a = 1;
= 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:53:5
--> $DIR/union-unsafe.rs:52:5
|
LL | u3.a = ManuallyDrop::new(String::from("new"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
@ -79,7 +79,7 @@ LL | u3.a = ManuallyDrop::new(String::from("new"));
= 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:54:6
--> $DIR/union-unsafe.rs:53:6
|
LL | *u3.a = String::from("new");
| ^^^^ access to union field