Skip to content

Commit a014323

Browse files
committed
Lower unions from AST to HIR and from HIR to types
Parse union items and add a feature for them
1 parent cbd912b commit a014323

File tree

8 files changed

+69
-6
lines changed

8 files changed

+69
-6
lines changed

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/ty/context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
13211321
self.mk_ty(TyStruct(def, substs))
13221322
}
13231323

1324+
pub fn mk_union(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
1325+
// take a copy of substs so that we own the vectors inside
1326+
self.mk_ty(TyUnion(def, substs))
1327+
}
1328+
13241329
pub fn mk_closure(self,
13251330
closure_id: DefId,
13261331
substs: &'tcx Substs<'tcx>,

src/librustc/ty/mod.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,7 +1514,7 @@ impl<'tcx> Decodable for AdtDef<'tcx> {
15141514

15151515

15161516
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1517-
pub enum AdtKind { Struct, Enum }
1517+
pub enum AdtKind { Struct, Union, Enum }
15181518

15191519
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
15201520
pub enum VariantKind { Struct, Tuple, Unit }
@@ -1545,8 +1545,10 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
15451545
if Some(did) == tcx.lang_items.phantom_data() {
15461546
flags = flags | AdtFlags::IS_PHANTOM_DATA;
15471547
}
1548-
if let AdtKind::Enum = kind {
1549-
flags = flags | AdtFlags::IS_ENUM;
1548+
match kind {
1549+
AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM,
1550+
AdtKind::Union => flags = flags | AdtFlags::IS_UNION,
1551+
AdtKind::Struct => {}
15501552
}
15511553
AdtDefData {
15521554
did: did,
@@ -1569,6 +1571,8 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
15691571
pub fn adt_kind(&self) -> AdtKind {
15701572
if self.flags.get().intersects(AdtFlags::IS_ENUM) {
15711573
AdtKind::Enum
1574+
} else if self.flags.get().intersects(AdtFlags::IS_UNION) {
1575+
AdtKind::Union
15721576
} else {
15731577
AdtKind::Struct
15741578
}

src/librustc_privacy/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
383383

384384
// Checks that a field is in scope.
385385
fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) {
386-
if def.adt_kind() == ty::AdtKind::Struct &&
386+
if def.adt_kind() != ty::AdtKind::Enum &&
387387
!field.vis.is_accessible_from(self.curitem, &self.tcx.map) {
388388
struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of struct `{}` is private",
389389
field.name, self.tcx.item_path_str(def.did))

src/librustc_typeck/check/dropck.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,8 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
304304
tcx.item_path_str(def_id),
305305
variant),
306306
ty::AdtKind::Struct => format!("struct {}",
307-
tcx.item_path_str(def_id))
307+
tcx.item_path_str(def_id)),
308+
ty::AdtKind::Union => unimplemented_unions!(),
308309
};
309310
span_note!(
310311
&mut err,

src/librustc_typeck/collect.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,16 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
10691069
adt
10701070
}
10711071

1072+
fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
1073+
it: &hir::Item,
1074+
def: &hir::VariantData)
1075+
-> ty::AdtDefMaster<'tcx>
1076+
{
1077+
let did = ccx.tcx.map.local_def_id(it.id);
1078+
let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)];
1079+
ccx.tcx.intern_adt_def(did, ty::AdtKind::Union, variants)
1080+
}
1081+
10721082
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr)
10731083
-> Option<ty::Disr> {
10741084
debug!("disr expr, checking {}", pprust::expr_to_string(e));

src/libsyntax/feature_gate.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,9 @@ declare_features! (
292292

293293
// Macros 1.1
294294
(active, rustc_macro, "1.13.0", Some(35900)),
295+
296+
// Allows untagged unions `union U { ... }`
297+
(active, untagged_unions, "1.13.0", Some(32836)),
295298
);
296299

297300
declare_features! (
@@ -953,6 +956,12 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
953956
}
954957
}
955958

959+
ast::ItemKind::Union(..) => {
960+
gate_feature_post!(&self, untagged_unions,
961+
i.span,
962+
"unions are unstable and not fully implemented");
963+
}
964+
956965
ast::ItemKind::DefaultImpl(..) => {
957966
gate_feature_post!(&self, optin_builtin_traits,
958967
i.span,

src/libsyntax/parse/parser.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5102,6 +5102,25 @@ impl<'a> Parser<'a> {
51025102
Ok((class_name, ItemKind::Struct(vdata, generics), None))
51035103
}
51045104

5105+
/// Parse union Foo { ... }
5106+
fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> {
5107+
let class_name = self.parse_ident()?;
5108+
let mut generics = self.parse_generics()?;
5109+
5110+
let vdata = if self.token.is_keyword(keywords::Where) {
5111+
generics.where_clause = self.parse_where_clause()?;
5112+
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
5113+
} else if self.token == token::OpenDelim(token::Brace) {
5114+
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
5115+
} else {
5116+
let token_str = self.this_token_to_string();
5117+
return Err(self.fatal(&format!("expected `where` or `{{` after union \
5118+
name, found `{}`", token_str)))
5119+
};
5120+
5121+
Ok((class_name, ItemKind::Union(vdata, generics), None))
5122+
}
5123+
51055124
pub fn parse_record_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
51065125
let mut fields = Vec::new();
51075126
if self.eat(&token::OpenDelim(token::Brace)) {
@@ -5938,6 +5957,18 @@ impl<'a> Parser<'a> {
59385957
maybe_append(attrs, extra_attrs));
59395958
return Ok(Some(item));
59405959
}
5960+
if self.eat_keyword(keywords::Union) {
5961+
// UNION ITEM
5962+
let (ident, item_, extra_attrs) = self.parse_item_union()?;
5963+
let last_span = self.last_span;
5964+
let item = self.mk_item(lo,
5965+
last_span.hi,
5966+
ident,
5967+
item_,
5968+
visibility,
5969+
maybe_append(attrs, extra_attrs));
5970+
return Ok(Some(item));
5971+
}
59415972
self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility)
59425973
}
59435974

0 commit comments

Comments
 (0)