Skip to content

Commit 3356ad7

Browse files
authored
Rollup merge of #77547 - RalfJung:stable-union-drop, r=matthewjasper
stabilize union with 'ManuallyDrop' fields and 'impl Drop for Union' As [discussed by @SimonSapin and @withoutboats](#55149 (comment)), this PR proposes to stabilize parts of the `untagged_union` feature gate: * It will be possible to have a union with field type `ManuallyDrop<T>` for any `T`. * While at it I propose we also stabilize `impl Drop for Union`; to my knowledge, there are no open concerns around this feature. In the RFC discussion, we also talked about allowing `&mut T` as another non-`Copy` non-dropping type, but that felt to me like an overly specific exception so I figured we'd wait if there is actually any use for such a special case. Some things remain unstable and still require the `untagged_union` feature gate: * Union with fields that do not drop, are not `Copy`, and are not `ManuallyDrop<_>`. The reason to not stabilize this is to avoid semver concerns around libraries adding `Drop` implementations later. (This is already not fully semver compatible as, to my knowledge, the borrow checker will exploit the non-dropping nature of any type, but it seems prudent to avoid further increasing the amount of trouble adding an `impl Drop` can cause.) Due to this, quite a few tests still need the `untagged_union` feature, but I think the ones where I could remove the feature flag provide good test coverage for the stable part. Cc @rust-lang/lang
2 parents 7581bb7 + defcd7f commit 3356ad7

33 files changed

+109
-150
lines changed

compiler/rustc_passes/src/stability.rs

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,13 @@ use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Varian
1313
use rustc_middle::hir::map::Map;
1414
use rustc_middle::middle::privacy::AccessLevels;
1515
use rustc_middle::middle::stability::{DeprecationEntry, Index};
16-
use rustc_middle::ty::query::Providers;
17-
use rustc_middle::ty::TyCtxt;
16+
use rustc_middle::ty::{self, query::Providers, TyCtxt};
1817
use rustc_session::lint;
1918
use rustc_session::lint::builtin::INEFFECTIVE_UNSTABLE_TRAIT_IMPL;
2019
use rustc_session::parse::feature_err;
2120
use rustc_session::Session;
2221
use rustc_span::symbol::{sym, Symbol};
23-
use rustc_span::Span;
24-
use rustc_trait_selection::traits::misc::can_type_implement_copy;
22+
use rustc_span::{Span, DUMMY_SP};
2523

2624
use std::cmp::Ordering;
2725
use std::mem::replace;
@@ -711,27 +709,35 @@ impl Visitor<'tcx> for Checker<'tcx> {
711709
// so semi-randomly perform it here in stability.rs
712710
hir::ItemKind::Union(..) if !self.tcx.features().untagged_unions => {
713711
let def_id = self.tcx.hir().local_def_id(item.hir_id);
714-
let adt_def = self.tcx.adt_def(def_id);
715712
let ty = self.tcx.type_of(def_id);
713+
let (adt_def, substs) = match ty.kind() {
714+
ty::Adt(adt_def, substs) => (adt_def, substs),
715+
_ => bug!(),
716+
};
716717

717-
if adt_def.has_dtor(self.tcx) {
718-
feature_err(
719-
&self.tcx.sess.parse_sess,
720-
sym::untagged_unions,
721-
item.span,
722-
"unions with `Drop` implementations are unstable",
723-
)
724-
.emit();
725-
} else {
726-
let param_env = self.tcx.param_env(def_id);
727-
if can_type_implement_copy(self.tcx, param_env, ty).is_err() {
728-
feature_err(
729-
&self.tcx.sess.parse_sess,
730-
sym::untagged_unions,
731-
item.span,
732-
"unions with non-`Copy` fields are unstable",
733-
)
734-
.emit();
718+
// Non-`Copy` fields are unstable, except for `ManuallyDrop`.
719+
let param_env = self.tcx.param_env(def_id);
720+
for field in &adt_def.non_enum_variant().fields {
721+
let field_ty = field.ty(self.tcx, substs);
722+
if !field_ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop())
723+
&& !field_ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), param_env)
724+
{
725+
if field_ty.needs_drop(self.tcx, param_env) {
726+
// Avoid duplicate error: This will error later anyway because fields
727+
// that need drop are not allowed.
728+
self.tcx.sess.delay_span_bug(
729+
item.span,
730+
"union should have been rejected due to potentially dropping field",
731+
);
732+
} else {
733+
feature_err(
734+
&self.tcx.sess.parse_sess,
735+
sym::untagged_unions,
736+
self.tcx.def_span(field.did),
737+
"unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable",
738+
)
739+
.emit();
740+
}
735741
}
736742
}
737743
}

compiler/rustc_typeck/src/check/check.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,7 @@ pub(super) fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
348348
check_packed(tcx, span, def);
349349
}
350350

351-
/// When the `#![feature(untagged_unions)]` gate is active,
352-
/// check that the fields of the `union` does not contain fields that need dropping.
351+
/// Check that the fields of the `union` do not need dropping.
353352
pub(super) fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
354353
let item_type = tcx.type_of(item_def_id);
355354
if let ty::Adt(def, substs) = item_type.kind() {

library/core/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@
131131
#![feature(transparent_unions)]
132132
#![feature(unboxed_closures)]
133133
#![feature(unsized_locals)]
134-
#![feature(untagged_unions)]
134+
#![cfg_attr(bootstrap, feature(untagged_unions))]
135135
#![feature(unwind_attributes)]
136136
#![feature(variant_count)]
137137
#![feature(tbm_target_feature)]

library/core/src/ptr/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,16 @@ pub(crate) struct FatPtr<T> {
229229
pub(crate) len: usize,
230230
}
231231

232+
// Manual impl needed to avoid `T: Clone` bound.
233+
impl<T> Clone for FatPtr<T> {
234+
fn clone(&self) -> Self {
235+
*self
236+
}
237+
}
238+
239+
// Manual impl needed to avoid `T: Copy` bound.
240+
impl<T> Copy for FatPtr<T> {}
241+
232242
/// Forms a raw slice from a pointer and a length.
233243
///
234244
/// The `len` argument is the number of **elements**, not the number of bytes.

library/std/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@
319319
#![feature(unsafe_block_in_unsafe_fn)]
320320
#![feature(unsafe_cell_get_mut)]
321321
#![feature(unsafe_cell_raw_get)]
322-
#![feature(untagged_unions)]
322+
#![cfg_attr(bootstrap, feature(untagged_unions))]
323323
#![feature(unwind_attributes)]
324324
#![feature(vec_into_raw_parts)]
325325
#![feature(wake_trait)]

src/test/ui/did_you_mean/bad-assoc-ty.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ enum N<F> where F: Fn() -> _ {
6868

6969
union O<F> where F: Fn() -> _ {
7070
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
71-
//~| ERROR unions with non-`Copy` fields are unstable
7271
foo: F,
7372
}
7473

src/test/ui/did_you_mean/bad-assoc-ty.stderr

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,6 @@ LL | type J = ty!(u8);
5757
|
5858
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
5959

60-
error[E0658]: unions with non-`Copy` fields are unstable
61-
--> $DIR/bad-assoc-ty.rs:69:1
62-
|
63-
LL | / union O<F> where F: Fn() -> _ {
64-
LL | |
65-
LL | |
66-
LL | | foo: F,
67-
LL | | }
68-
| |_^
69-
|
70-
= note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information
71-
= help: add `#![feature(untagged_unions)]` to the crate attributes to enable
72-
7360
error[E0223]: ambiguous associated type
7461
--> $DIR/bad-assoc-ty.rs:1:10
7562
|
@@ -215,7 +202,7 @@ LL | union O<F, T> where F: Fn() -> T {
215202
| ^^^ ^
216203

217204
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
218-
--> $DIR/bad-assoc-ty.rs:75:29
205+
--> $DIR/bad-assoc-ty.rs:74:29
219206
|
220207
LL | trait P<F> where F: Fn() -> _ {
221208
| ^ not allowed in type signatures
@@ -226,7 +213,7 @@ LL | trait P<F, T> where F: Fn() -> T {
226213
| ^^^ ^
227214

228215
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
229-
--> $DIR/bad-assoc-ty.rs:80:38
216+
--> $DIR/bad-assoc-ty.rs:79:38
230217
|
231218
LL | fn foo<F>(_: F) where F: Fn() -> _ {}
232219
| ^ not allowed in type signatures
@@ -236,7 +223,7 @@ help: use type parameters instead
236223
LL | fn foo<F, T>(_: F) where F: Fn() -> T {}
237224
| ^^^ ^
238225

239-
error: aborting due to 29 previous errors
226+
error: aborting due to 28 previous errors
240227

241-
Some errors have detailed explanations: E0121, E0223, E0658.
228+
Some errors have detailed explanations: E0121, E0223.
242229
For more information about an error, try `rustc --explain E0121`.

src/test/ui/drop/dynamic-drop.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// run-pass
22
// ignore-wasm32-bare compiled with panic=abort by default
33

4-
#![feature(generators, generator_trait, untagged_unions)]
4+
#![feature(generators, generator_trait)]
55
#![feature(bindings_after_at)]
66

77
#![allow(unused_assignments)]

src/test/ui/dropck/dropck-union.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#![feature(untagged_unions)]
2-
31
use std::cell::Cell;
42
use std::ops::Deref;
53
use std::mem::ManuallyDrop;

src/test/ui/dropck/dropck-union.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0597]: `v` does not live long enough
2-
--> $DIR/dropck-union.rs:39:18
2+
--> $DIR/dropck-union.rs:37:18
33
|
44
LL | v.0.set(Some(&v));
55
| ^^ borrowed value does not live long enough

0 commit comments

Comments
 (0)