diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2016-08-09 01:18:47 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2016-09-03 13:39:33 +0300 |
| commit | a014323e456c00f93134d03b4af95844b2ed4b95 (patch) | |
| tree | 8d7c47cd7c965a03d8daf195d6a7f1d29a22fdf2 | |
| parent | cbd912babab4b8cebe9e90a632117913ca192743 (diff) | |
| download | rust-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.rs | 5 | ||||
| -rw-r--r-- | src/librustc/ty/context.rs | 5 | ||||
| -rw-r--r-- | src/librustc/ty/mod.rs | 10 | ||||
| -rw-r--r-- | src/librustc_privacy/lib.rs | 2 | ||||
| -rw-r--r-- | src/librustc_typeck/check/dropck.rs | 3 | ||||
| -rw-r--r-- | src/librustc_typeck/collect.rs | 10 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 9 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 31 |
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) } |
