about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-09-03 07:48:06 -0700
committerGitHub <noreply@github.com>2016-09-03 07:48:06 -0700
commitd748fa6ecccf6f5b4c7ae4abee0a2d206b165de2 (patch)
tree5ada2c11762533ba6c6f21a7593b015cb1a89912 /src/libsyntax
parent01b35d82e51458870f61cf850b73479f253fcb54 (diff)
parent436cfe56534b405786816d4bbcccd11ed7571981 (diff)
downloadrust-d748fa6ecccf6f5b4c7ae4abee0a2d206b165de2.tar.gz
rust-d748fa6ecccf6f5b4c7ae4abee0a2d206b165de2.zip
Auto merge of #36016 - petrochenkov:union, r=nikomatsakis
Implement untagged unions (RFC 1444)

cc https://github.com/rust-lang/rust/issues/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
    }
    ```

- https://github.com/rust-lang/rust/pull/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 https://github.com/rust-lang/rust/issues/32836#issuecomment-242511491.
- 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
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/feature_gate.rs9
-rw-r--r--src/libsyntax/parse/parser.rs33
3 files changed, 43 insertions, 1 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index fcb99444957..4394fb0e143 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1886,7 +1886,7 @@ pub enum ItemKind {
     /// A union definition (`union` or `pub union`).
     ///
     /// E.g. `union Foo<A, B> { x: A, y: B }`
-    Union(VariantData, Generics), // FIXME: not yet implemented
+    Union(VariantData, Generics),
     /// A Trait declaration (`trait` or `pub trait`).
     ///
     /// E.g. `trait Foo { .. }` or `trait Foo<T> { .. }`
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 683d5277359..287d33cc3e5 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -292,6 +292,9 @@ declare_features! (
 
     // Macros 1.1
     (active, rustc_macro, "1.13.0", Some(35900)),
+
+    // Allows untagged unions `union U { ... }`
+    (active, untagged_unions, "1.13.0", Some(32836)),
 );
 
 declare_features! (
@@ -953,6 +956,12 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
                 }
             }
 
+            ast::ItemKind::Union(..) => {
+                gate_feature_post!(&self, untagged_unions,
+                                   i.span,
+                                   "unions are unstable and possibly buggy");
+            }
+
             ast::ItemKind::DefaultImpl(..) => {
                 gate_feature_post!(&self, optin_builtin_traits,
                                    i.span,
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 92ec0fdb3de..ec9dc1bae5a 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -5102,6 +5102,25 @@ impl<'a> Parser<'a> {
         Ok((class_name, ItemKind::Struct(vdata, generics), None))
     }
 
+    /// Parse union Foo { ... }
+    fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> {
+        let class_name = self.parse_ident()?;
+        let mut generics = self.parse_generics()?;
+
+        let vdata = if self.token.is_keyword(keywords::Where) {
+            generics.where_clause = self.parse_where_clause()?;
+            VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
+        } else if self.token == token::OpenDelim(token::Brace) {
+            VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
+        } else {
+            let token_str = self.this_token_to_string();
+            return Err(self.fatal(&format!("expected `where` or `{{` after union \
+                                            name, found `{}`", token_str)))
+        };
+
+        Ok((class_name, ItemKind::Union(vdata, generics), None))
+    }
+
     pub fn parse_record_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
         let mut fields = Vec::new();
         if self.eat(&token::OpenDelim(token::Brace)) {
@@ -5938,6 +5957,20 @@ impl<'a> Parser<'a> {
                                     maybe_append(attrs, extra_attrs));
             return Ok(Some(item));
         }
+        if self.check_keyword(keywords::Union) &&
+                self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) {
+            // UNION ITEM
+            self.bump();
+            let (ident, item_, extra_attrs) = self.parse_item_union()?;
+            let last_span = self.last_span;
+            let item = self.mk_item(lo,
+                                    last_span.hi,
+                                    ident,
+                                    item_,
+                                    visibility,
+                                    maybe_append(attrs, extra_attrs));
+            return Ok(Some(item));
+        }
         self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility)
     }