Skip to content

Commit acf82c7

Browse files
committed
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. The stable rule remains, that union fields must be Copy. We use the new rule for the `untagged_union` feature. See RFC 2514.
1 parent d6525ef commit acf82c7

File tree

2 files changed

+33
-0
lines changed

2 files changed

+33
-0
lines changed

src/librustc_typeck/check/mod.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,9 +1302,38 @@ fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
13021302
def.destructor(tcx); // force the destructor to be evaluated
13031303
check_representable(tcx, span, def_id);
13041304

1305+
check_dropless(tcx, span, def_id);
13051306
check_packed(tcx, span, def_id);
13061307
}
13071308

1309+
fn check_dropless<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1310+
sp: Span,
1311+
item_def_id: DefId)
1312+
-> bool {
1313+
// Without the feature we check Copy types only later
1314+
if !tcx.features().untagged_unions {
1315+
return true;
1316+
}
1317+
let t = tcx.type_of(item_def_id);
1318+
if let ty::Adt(def, substs) = t.sty {
1319+
if def.is_union() {
1320+
let fields = &def.non_enum_variant().fields;
1321+
for field in fields {
1322+
let field_ty = field.ty(tcx, substs);
1323+
let param_env = tcx.param_env(field.did);
1324+
if field_ty.needs_drop(tcx, param_env) {
1325+
struct_span_err!(tcx.sess, sp, E0730,
1326+
"unions may not contain fields that need dropping")
1327+
.span_label(sp, "ManuallyDrop can be used to wrap such fields")
1328+
.emit();
1329+
return false;
1330+
}
1331+
}
1332+
}
1333+
}
1334+
return true;
1335+
}
1336+
13081337
fn check_opaque<'a, 'tcx>(
13091338
tcx: TyCtxt<'a, 'tcx, 'tcx>,
13101339
def_id: DefId,

src/librustc_typeck/diagnostics.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4831,6 +4831,10 @@ fn make_recursive_type() -> impl Sized {
48314831
```
48324832
"##,
48334833

4834+
E0730: r##"
4835+
A `union` can not have fields with destructors.
4836+
"##,
4837+
48344838
}
48354839

48364840
register_diagnostics! {

0 commit comments

Comments
 (0)