about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-08-09 01:18:47 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-09-03 13:39:33 +0300
commita014323e456c00f93134d03b4af95844b2ed4b95 (patch)
tree8d7c47cd7c965a03d8daf195d6a7f1d29a22fdf2
parentcbd912babab4b8cebe9e90a632117913ca192743 (diff)
downloadrust-a014323e456c00f93134d03b4af95844b2ed4b95.tar.gz
rust-a014323e456c00f93134d03b4af95844b2ed4b95.zip
Lower unions from AST to HIR and from HIR to types
Parse union items and add a feature for them
-rw-r--r--src/librustc/hir/lowering.rs5
-rw-r--r--src/librustc/ty/context.rs5
-rw-r--r--src/librustc/ty/mod.rs10
-rw-r--r--src/librustc_privacy/lib.rs2
-rw-r--r--src/librustc_typeck/check/dropck.rs3
-rw-r--r--src/librustc_typeck/collect.rs10
-rw-r--r--src/libsyntax/feature_gate.rs9
-rw-r--r--src/libsyntax/parse/parser.rs31
8 files changed, 69 insertions, 6 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 6739d3f662a..80e034721d6 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -638,7 +638,10 @@ impl<'a> LoweringContext<'a> {
                 let struct_def = self.lower_variant_data(struct_def);
                 hir::ItemStruct(struct_def, self.lower_generics(generics))
             }
-            ItemKind::Union(..) => panic!("`union` is not yet implemented"),
+            ItemKind::Union(ref vdata, ref generics) => {
+                let vdata = self.lower_variant_data(vdata);
+                hir::ItemUnion(vdata, self.lower_generics(generics))
+            }
             ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
                 hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
                                      self.lower_trait_ref(trait_ref))
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 8dd7bc562d7..0fc1641d31f 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1321,6 +1321,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.mk_ty(TyStruct(def, substs))
     }
 
+    pub fn mk_union(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
+        // take a copy of substs so that we own the vectors inside
+        self.mk_ty(TyUnion(def, substs))
+    }
+
     pub fn mk_closure(self,
                       closure_id: DefId,
                       substs: &'tcx Substs<'tcx>,
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index ddf25538ee4..4cda7491113 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1514,7 +1514,7 @@ impl<'tcx> Decodable for AdtDef<'tcx> {
 
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub enum AdtKind { Struct, Enum }
+pub enum AdtKind { Struct, Union, Enum }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub enum VariantKind { Struct, Tuple, Unit }
@@ -1545,8 +1545,10 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
         if Some(did) == tcx.lang_items.phantom_data() {
             flags = flags | AdtFlags::IS_PHANTOM_DATA;
         }
-        if let AdtKind::Enum = kind {
-            flags = flags | AdtFlags::IS_ENUM;
+        match kind {
+            AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM,
+            AdtKind::Union => flags = flags | AdtFlags::IS_UNION,
+            AdtKind::Struct => {}
         }
         AdtDefData {
             did: did,
@@ -1569,6 +1571,8 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
     pub fn adt_kind(&self) -> AdtKind {
         if self.flags.get().intersects(AdtFlags::IS_ENUM) {
             AdtKind::Enum
+        } else if self.flags.get().intersects(AdtFlags::IS_UNION) {
+            AdtKind::Union
         } else {
             AdtKind::Struct
         }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 4b13d13fb70..cd2eb4d2b58 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -383,7 +383,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
 
     // Checks that a field is in scope.
     fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) {
-        if def.adt_kind() == ty::AdtKind::Struct &&
+        if def.adt_kind() != ty::AdtKind::Enum &&
            !field.vis.is_accessible_from(self.curitem, &self.tcx.map) {
             struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of struct `{}` is private",
                       field.name, self.tcx.item_path_str(def.did))
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index b73b8b99887..bd47ff0b00b 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -304,7 +304,8 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
                                                      tcx.item_path_str(def_id),
                                                      variant),
                         ty::AdtKind::Struct => format!("struct {}",
-                                                       tcx.item_path_str(def_id))
+                                                       tcx.item_path_str(def_id)),
+                        ty::AdtKind::Union => unimplemented_unions!(),
                     };
                     span_note!(
                         &mut err,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index f2f3163dde7..7f9de2becee 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1069,6 +1069,16 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     adt
 }
 
+fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                it: &hir::Item,
+                                def: &hir::VariantData)
+                                -> ty::AdtDefMaster<'tcx>
+{
+    let did = ccx.tcx.map.local_def_id(it.id);
+    let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)];
+    ccx.tcx.intern_adt_def(did, ty::AdtKind::Union, variants)
+}
+
     fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr)
                           -> Option<ty::Disr> {
         debug!("disr expr, checking {}", pprust::expr_to_string(e));
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 683d5277359..b40124bd774 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 not fully implemented");
+            }
+
             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..290a59cf1e5 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,18 @@ impl<'a> Parser<'a> {
                                     maybe_append(attrs, extra_attrs));
             return Ok(Some(item));
         }
+        if self.eat_keyword(keywords::Union) {
+            // UNION ITEM
+            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)
     }