Skip to content

Commit ec7152c

Browse files
committed
allow unions with mutable references and tuples of allowed types
1 parent 848d23b commit ec7152c

File tree

3 files changed

+59
-12
lines changed

3 files changed

+59
-12
lines changed

compiler/rustc_passes/src/stability.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -772,17 +772,27 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
772772
let ty = self.tcx.type_of(item.def_id);
773773
let ty::Adt(adt_def, substs) = ty.kind() else { bug!() };
774774

775-
#[allow(rustc::usage_of_qualified_ty)] // `Ty` is the wrong type here, we really want `ty::Ty`.
775+
#[allow(rustc::usage_of_qualified_ty)] // `Ty` is `hir::Ty` here, we really want `ty::Ty`.
776776
fn allowed_union_field<'tcx>(
777777
tcx: TyCtxt<'tcx>,
778778
param_env: ty::ParamEnv<'tcx>,
779779
ty: ty::Ty<'tcx>,
780780
) -> bool {
781-
ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop())
782-
|| ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env)
781+
// We don't just accept all !needs_drop fields, due to semver concerns.
782+
match ty.kind() {
783+
ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check)
784+
ty::Tuple(tys) => {
785+
// allow tuples of allowed types
786+
tys.iter().all(|ty| allowed_union_field(tcx, param_env, ty))
787+
}
788+
_ => {
789+
ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop())
790+
|| ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env)
791+
}
792+
}
783793
}
784794

785-
// Non-`Copy` fields are unstable, except for `ManuallyDrop`.
795+
// `allowed_union_field` determines which fields are allowed on stable.
786796
let param_env = self.tcx.param_env(item.def_id);
787797
for field in &adt_def.non_enum_variant().fields {
788798
let field_ty = field.ty(self.tcx, substs);
@@ -799,10 +809,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
799809
&self.tcx.sess.parse_sess,
800810
sym::untagged_unions,
801811
self.tcx.def_span(field.did),
802-
"unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable",
812+
"unions with non-`Copy` fields other than `ManuallyDrop<T>`, \
813+
references, and tuples of such types are unstable",
803814
)
804815
.emit();
805816
}
817+
} else {
818+
// We allow this field. Make extra sure it does not drop.
819+
assert!(
820+
!field_ty.needs_drop(self.tcx, param_env),
821+
"we should accept no maybe-dropping union fields"
822+
);
806823
}
807824
}
808825
}

src/test/ui/feature-gates/feature-gate-untagged_unions.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// ignore-tidy-linelength
2+
use std::mem::ManuallyDrop;
23

34
union U1 { // OK
45
a: u8,
@@ -9,15 +10,19 @@ union U2<T: Copy> { // OK
910
}
1011

1112
union U22<T> { // OK
12-
a: std::mem::ManuallyDrop<T>,
13+
a: ManuallyDrop<T>,
14+
}
15+
16+
union U23<T> { // OK
17+
a: (ManuallyDrop<T>, i32),
1318
}
1419

1520
union U3 {
1621
a: String, //~ ERROR unions cannot contain fields that may need dropping
1722
}
1823

1924
union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test!
20-
a: std::cell::RefCell<i32>, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable
25+
a: std::cell::RefCell<i32>, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop<T>`, references, and tuples of such types are unstable
2126
}
2227

2328
union U4<T> {
@@ -32,4 +37,17 @@ impl Drop for U5 {
3237
fn drop(&mut self) {}
3338
}
3439

40+
union U5Nested { // a nested union that drops is NOT OK
41+
nest: U5, //~ ERROR unions cannot contain fields that may need dropping
42+
}
43+
44+
union U6 { // OK
45+
s: &'static i32,
46+
m: &'static mut i32,
47+
}
48+
49+
union U7<T> { // OK
50+
f: (&'static mut i32, ManuallyDrop<T>, i32),
51+
}
52+
3553
fn main() {}

src/test/ui/feature-gates/feature-gate-untagged_unions.stderr

+17-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable
2-
--> $DIR/feature-gate-untagged_unions.rs:20:5
1+
error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop<T>`, references, and tuples of such types are unstable
2+
--> $DIR/feature-gate-untagged_unions.rs:25:5
33
|
44
LL | a: std::cell::RefCell<i32>,
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | a: std::cell::RefCell<i32>,
88
= help: add `#![feature(untagged_unions)]` to the crate attributes to enable
99

1010
error[E0740]: unions cannot contain fields that may need dropping
11-
--> $DIR/feature-gate-untagged_unions.rs:16:5
11+
--> $DIR/feature-gate-untagged_unions.rs:21:5
1212
|
1313
LL | a: String,
1414
| ^^^^^^^^^
@@ -20,7 +20,7 @@ LL | a: std::mem::ManuallyDrop<String>,
2020
| +++++++++++++++++++++++ +
2121

2222
error[E0740]: unions cannot contain fields that may need dropping
23-
--> $DIR/feature-gate-untagged_unions.rs:24:5
23+
--> $DIR/feature-gate-untagged_unions.rs:29:5
2424
|
2525
LL | a: T,
2626
| ^^^^
@@ -31,7 +31,19 @@ help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>
3131
LL | a: std::mem::ManuallyDrop<T>,
3232
| +++++++++++++++++++++++ +
3333

34-
error: aborting due to 3 previous errors
34+
error[E0740]: unions cannot contain fields that may need dropping
35+
--> $DIR/feature-gate-untagged_unions.rs:41:5
36+
|
37+
LL | nest: U5,
38+
| ^^^^^^^^
39+
|
40+
= note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
41+
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
42+
|
43+
LL | nest: std::mem::ManuallyDrop<U5>,
44+
| +++++++++++++++++++++++ +
45+
46+
error: aborting due to 4 previous errors
3547

3648
Some errors have detailed explanations: E0658, E0740.
3749
For more information about an error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)