Skip to content

Commit d748fa6

Browse files
authored
Auto merge of #36016 - petrochenkov:union, r=nikomatsakis
Implement untagged unions (RFC 1444) cc #32836 Notes: - The RFC doesn't talk about `#[packed]` unions, this implementation supports them, packing changes union's alignment to 1 and removes trailing padding. - The RFC doesn't talk about dynamically sized unions, this implementation doesn't support them and rejects them during wf-checking (similarly, dynamically sized enums are not supported as well). - The lint for drop fields in unions can't work precisely before monomorphization, so it works pessimistically - non-`Copy` generic fields are reported, types not implementing `Drop` directly, but having non-trivial drop code are reported. ``` struct S(String); // Doesn't implement `Drop` union U<T> { a: S, // Reported b: T, // Reported } ``` - #35764 was indeed helpful and landed timely, I didn't have to implement internal drop flags for unions. - Unions are not permitted in constant patterns, because matching on union fields is unsafe, I didn't want unsafety checker to dig into all constants to uncover this possible unsafety. - The RFC doesn't talk about `#[derive]`, generally trait impls cannot be derived for unions, but some of them can. I implemented only `#[derive(Copy)]` so far. In theory shallow `#[derive(Clone)]` can be derived as well if all union fields are `Copy`, I left it for later though, it requires changing how `Clone` impls are generated. - Moving union fields is implemented as per #32836 (comment). - Testing strategy: union specific behavior is tested, sometimes very basically (e.g. debuginfo), behavior common for all ADTs (e.g. something like coherence checks) is not generally tested. r? @eddyb
2 parents 01b35d8 + 436cfe5 commit d748fa6

File tree

167 files changed

+2899
-362
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

167 files changed

+2899
-362
lines changed

src/librustc/hir/check_attr.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use syntax::visit::Visitor;
1818
enum Target {
1919
Fn,
2020
Struct,
21+
Union,
2122
Enum,
2223
Other,
2324
}
@@ -27,6 +28,7 @@ impl Target {
2728
match item.node {
2829
ast::ItemKind::Fn(..) => Target::Fn,
2930
ast::ItemKind::Struct(..) => Target::Struct,
31+
ast::ItemKind::Union(..) => Target::Union,
3032
ast::ItemKind::Enum(..) => Target::Enum,
3133
_ => Target::Other,
3234
}
@@ -62,17 +64,20 @@ impl<'a> CheckAttrVisitor<'a> {
6264
let message = match &*name {
6365
"C" => {
6466
conflicting_reprs += 1;
65-
if target != Target::Struct && target != Target::Enum {
66-
"attribute should be applied to struct or enum"
67+
if target != Target::Struct &&
68+
target != Target::Union &&
69+
target != Target::Enum {
70+
"attribute should be applied to struct, enum or union"
6771
} else {
6872
continue
6973
}
7074
}
7175
"packed" => {
7276
// Do not increment conflicting_reprs here, because "packed"
7377
// can be used to modify another repr hint
74-
if target != Target::Struct {
75-
"attribute should be applied to struct"
78+
if target != Target::Struct &&
79+
target != Target::Union {
80+
"attribute should be applied to struct or union"
7681
} else {
7782
continue
7883
}

src/librustc/hir/def.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub enum Def {
4141
// If Def::Struct lives in value namespace (e.g. tuple struct, unit struct expressions)
4242
// it denotes a constructor and its DefId refers to NodeId of the struct's constructor.
4343
Struct(DefId),
44+
Union(DefId),
4445
Label(ast::NodeId),
4546
Method(DefId),
4647
Err,
@@ -109,7 +110,7 @@ impl Def {
109110

110111
Def::Fn(..) | Def::Mod(..) | Def::ForeignMod(..) | Def::Static(..) |
111112
Def::Variant(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
112-
Def::TyParam(..) | Def::Struct(..) | Def::Trait(..) |
113+
Def::TyParam(..) | Def::Struct(..) | Def::Union(..) | Def::Trait(..) |
113114
Def::Method(..) | Def::Const(..) | Def::AssociatedConst(..) |
114115
Def::PrimTy(..) | Def::Label(..) | Def::SelfTy(..) | Def::Err => {
115116
bug!("attempted .var_id() on invalid {:?}", self)
@@ -121,7 +122,7 @@ impl Def {
121122
match *self {
122123
Def::Fn(id) | Def::Mod(id) | Def::ForeignMod(id) | Def::Static(id, _) |
123124
Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) |
124-
Def::TyParam(id) | Def::Struct(id) | Def::Trait(id) |
125+
Def::TyParam(id) | Def::Struct(id) | Def::Union(id) | Def::Trait(id) |
125126
Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) |
126127
Def::Local(id, _) | Def::Upvar(id, _, _, _) => {
127128
id
@@ -147,6 +148,7 @@ impl Def {
147148
Def::TyAlias(..) => "type",
148149
Def::AssociatedTy(..) => "associated type",
149150
Def::Struct(..) => "struct",
151+
Def::Union(..) => "union",
150152
Def::Trait(..) => "trait",
151153
Def::Method(..) => "method",
152154
Def::Const(..) => "constant",

src/librustc/hir/fold.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,10 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
761761
let struct_def = folder.fold_variant_data(struct_def);
762762
ItemStruct(struct_def, folder.fold_generics(generics))
763763
}
764+
ItemUnion(struct_def, generics) => {
765+
let struct_def = folder.fold_variant_data(struct_def);
766+
ItemUnion(struct_def, folder.fold_generics(generics))
767+
}
764768
ItemDefaultImpl(unsafety, ref trait_ref) => {
765769
ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
766770
}

src/librustc/hir/intravisit.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,8 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
348348
visitor.visit_ty(typ);
349349
walk_list!(visitor, visit_impl_item, impl_items);
350350
}
351-
ItemStruct(ref struct_definition, ref generics) => {
351+
ItemStruct(ref struct_definition, ref generics) |
352+
ItemUnion(ref struct_definition, ref generics) => {
352353
visitor.visit_generics(generics);
353354
visitor.visit_id(item.id);
354355
visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span);

src/librustc/hir/lowering.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,10 @@ impl<'a> LoweringContext<'a> {
638638
let struct_def = self.lower_variant_data(struct_def);
639639
hir::ItemStruct(struct_def, self.lower_generics(generics))
640640
}
641-
ItemKind::Union(..) => panic!("`union` is not yet implemented"),
641+
ItemKind::Union(ref vdata, ref generics) => {
642+
let vdata = self.lower_variant_data(vdata);
643+
hir::ItemUnion(vdata, self.lower_generics(generics))
644+
}
642645
ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
643646
hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
644647
self.lower_trait_ref(trait_ref))

src/librustc/hir/map/def_collector.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,9 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
302302
let def_data = match i.node {
303303
hir::ItemDefaultImpl(..) | hir::ItemImpl(..) =>
304304
DefPathData::Impl,
305-
hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemTrait(..) |
306-
hir::ItemExternCrate(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) |
307-
hir::ItemTy(..) =>
305+
hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) |
306+
hir::ItemTrait(..) | hir::ItemExternCrate(..) | hir::ItemMod(..) |
307+
hir::ItemForeignMod(..) | hir::ItemTy(..) =>
308308
DefPathData::TypeNs(i.name.as_str()),
309309
hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) =>
310310
DefPathData::ValueNs(i.name.as_str()),
@@ -331,7 +331,8 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
331331
});
332332
}
333333
}
334-
hir::ItemStruct(ref struct_def, _) => {
334+
hir::ItemStruct(ref struct_def, _) |
335+
hir::ItemUnion(ref struct_def, _) => {
335336
// If this is a tuple-like struct, register the constructor.
336337
if !struct_def.is_struct() {
337338
this.create_def(struct_def.id(),

src/librustc/hir/map/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
10301030
ItemTy(..) => "ty",
10311031
ItemEnum(..) => "enum",
10321032
ItemStruct(..) => "struct",
1033+
ItemUnion(..) => "union",
10331034
ItemTrait(..) => "trait",
10341035
ItemImpl(..) => "impl",
10351036
ItemDefaultImpl(..) => "default impl",

src/librustc/hir/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,8 @@ pub enum Item_ {
14831483
ItemEnum(EnumDef, Generics),
14841484
/// A struct definition, e.g. `struct Foo<A> {x: A}`
14851485
ItemStruct(VariantData, Generics),
1486+
/// A union definition, e.g. `union Foo<A, B> {x: A, y: B}`
1487+
ItemUnion(VariantData, Generics),
14861488
/// Represents a Trait Declaration
14871489
ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItem>),
14881490

@@ -1512,6 +1514,7 @@ impl Item_ {
15121514
ItemTy(..) => "type alias",
15131515
ItemEnum(..) => "enum",
15141516
ItemStruct(..) => "struct",
1517+
ItemUnion(..) => "union",
15151518
ItemTrait(..) => "trait",
15161519
ItemImpl(..) |
15171520
ItemDefaultImpl(..) => "item",

src/librustc/hir/print.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,10 @@ impl<'a> State<'a> {
752752
self.head(&visibility_qualified(&item.vis, "struct"))?;
753753
self.print_struct(struct_def, generics, item.name, item.span, true)?;
754754
}
755-
755+
hir::ItemUnion(ref struct_def, ref generics) => {
756+
self.head(&visibility_qualified(&item.vis, "union"))?;
757+
self.print_struct(struct_def, generics, item.name, item.span, true)?;
758+
}
756759
hir::ItemDefaultImpl(unsafety, ref trait_ref) => {
757760
self.head("")?;
758761
self.print_visibility(&item.vis)?;

src/librustc/infer/error_reporting.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
105105
match item.node {
106106
hir::ItemImpl(..) => "impl",
107107
hir::ItemStruct(..) => "struct",
108+
hir::ItemUnion(..) => "union",
108109
hir::ItemEnum(..) => "enum",
109110
hir::ItemTrait(..) => "trait",
110111
hir::ItemFn(..) => "function body",
@@ -1370,7 +1371,8 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
13701371
}
13711372
hir::TyPath(ref maybe_qself, ref path) => {
13721373
match self.tcx.expect_def(cur_ty.id) {
1373-
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
1374+
Def::Enum(did) | Def::TyAlias(did) |
1375+
Def::Struct(did) | Def::Union(did) => {
13741376
let generics = self.tcx.lookup_generics(did);
13751377

13761378
let expected =

0 commit comments

Comments
 (0)