Skip to content

Commit 5f9ef3c

Browse files
committed
Implement encoding/decoding unions in metadata
Add well-formedness check Implement some more missing code
1 parent 6792bd9 commit 5f9ef3c

File tree

12 files changed

+119
-38
lines changed

12 files changed

+119
-38
lines changed

src/librustc/middle/expr_use_visitor.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
414414
}
415415

416416
hir::ExprStruct(_, ref fields, ref opt_with) => {
417-
self.walk_struct_expr(expr, fields, opt_with);
417+
self.walk_struct_expr(fields, opt_with);
418418
}
419419

420420
hir::ExprTup(ref exprs) => {
@@ -655,7 +655,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
655655
}
656656

657657
fn walk_struct_expr(&mut self,
658-
_expr: &hir::Expr,
659658
fields: &[hir::Field],
660659
opt_with: &Option<P<hir::Expr>>) {
661660
// Consume the expressions supplying values for each field.
@@ -687,9 +686,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
687686
}
688687
}
689688
}
690-
ty::TyUnion(..) => {
691-
unimplemented_unions!();
692-
}
693689
_ => {
694690
// the base expression should always evaluate to a
695691
// struct; however, when EUV is run during typeck, it

src/librustc/ty/fast_reject.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub enum SimplifiedType {
3030
TupleSimplifiedType(usize),
3131
TraitSimplifiedType(DefId),
3232
StructSimplifiedType(DefId),
33+
UnionSimplifiedType(DefId),
3334
ClosureSimplifiedType(DefId),
3435
AnonSimplifiedType(DefId),
3536
FunctionSimplifiedType(usize),
@@ -66,8 +67,8 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
6667
ty::TyStruct(def, _) => {
6768
Some(StructSimplifiedType(def.did))
6869
}
69-
ty::TyUnion(..) => {
70-
unimplemented_unions!();
70+
ty::TyUnion(def, _) => {
71+
Some(UnionSimplifiedType(def.did))
7172
}
7273
ty::TyRef(_, mt) => {
7374
// since we introduce auto-refs during method lookup, we

src/librustc_metadata/decoder.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ enum Family {
133133
DefaultImpl, // d
134134
Trait, // I
135135
Struct(VariantKind), // S, s, u
136+
Union, // U
136137
PublicField, // g
137138
InheritedField, // N
138139
Constant, // C
@@ -160,6 +161,7 @@ fn item_family(item: rbml::Doc) -> Family {
160161
'S' => Struct(VariantKind::Struct),
161162
's' => Struct(VariantKind::Tuple),
162163
'u' => Struct(VariantKind::Unit),
164+
'U' => Union,
163165
'g' => PublicField,
164166
'N' => InheritedField,
165167
c => bug!("unexpected family char: {}", c)
@@ -317,6 +319,7 @@ fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike {
317319
ImmStatic => DlDef(Def::Static(did, false)),
318320
MutStatic => DlDef(Def::Static(did, true)),
319321
Struct(..) => DlDef(Def::Struct(did)),
322+
Union => DlDef(Def::Union(did)),
320323
Fn => DlDef(Def::Fn(did)),
321324
Method | StaticMethod => {
322325
DlDef(Def::Method(did))
@@ -461,6 +464,10 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd,
461464
(ty::AdtKind::Struct,
462465
vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))])
463466
}
467+
Union => {
468+
(ty::AdtKind::Union,
469+
vec![get_struct_variant(cdata, doc, did)])
470+
}
464471
_ => bug!("get_adt_def called on a non-ADT {:?} - {:?}",
465472
item_family(doc), did)
466473
};

src/librustc_typeck/check/dropck.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,8 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
306306
variant),
307307
ty::AdtKind::Struct => format!("struct {}",
308308
tcx.item_path_str(def_id)),
309-
ty::AdtKind::Union => unimplemented_unions!(),
309+
ty::AdtKind::Union => format!("union {}",
310+
tcx.item_path_str(def_id)),
310311
};
311312
span_note!(
312313
&mut err,

src/librustc_typeck/check/mod.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -713,16 +713,18 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
713713
fcx
714714
}
715715

716-
pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
717-
let tcx = ccx.tcx;
718-
719-
check_representable(tcx, span, id, "struct");
716+
fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
717+
check_representable(ccx.tcx, span, id);
720718

721-
if tcx.lookup_simd(ccx.tcx.map.local_def_id(id)) {
722-
check_simd(tcx, span, id);
719+
if ccx.tcx.lookup_simd(ccx.tcx.map.local_def_id(id)) {
720+
check_simd(ccx.tcx, span, id);
723721
}
724722
}
725723

724+
fn check_union(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
725+
check_representable(ccx.tcx, span, id);
726+
}
727+
726728
pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
727729
debug!("check_item_type(it.id={}, it.name={})",
728730
it.id,
@@ -763,7 +765,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
763765
check_struct(ccx, it.id, it.span);
764766
}
765767
hir::ItemUnion(..) => {
766-
unimplemented_unions!();
768+
check_union(ccx, it.id, it.span);
767769
}
768770
hir::ItemTy(_, ref generics) => {
769771
let pty_ty = ccx.tcx.node_id_to_type(it.id);
@@ -1174,10 +1176,10 @@ fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
11741176
/// Checks whether a type can be represented in memory. In particular, it
11751177
/// identifies types that contain themselves without indirection through a
11761178
/// pointer, which would mean their size is unbounded.
1177-
pub fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1178-
sp: Span,
1179-
item_id: ast::NodeId,
1180-
_designation: &str) -> bool {
1179+
fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1180+
sp: Span,
1181+
item_id: ast::NodeId)
1182+
-> bool {
11811183
let rty = tcx.node_id_to_type(item_id);
11821184

11831185
// Check that it is possible to represent this type. This call identifies
@@ -1277,7 +1279,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
12771279
disr_vals.push(current_disr_val);
12781280
}
12791281

1280-
check_representable(ccx.tcx, sp, id, "enum");
1282+
check_representable(ccx.tcx, sp, id);
12811283
}
12821284

12831285
impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {

src/librustc_typeck/check/wfcheck.rs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -136,17 +136,21 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
136136
self.check_item_type(item);
137137
}
138138
hir::ItemStruct(ref struct_def, ref ast_generics) => {
139-
self.check_type_defn(item, |fcx| {
139+
self.check_type_defn(item, false, |fcx| {
140140
vec![fcx.struct_variant(struct_def)]
141141
});
142142

143143
self.check_variances_for_type_defn(item, ast_generics);
144144
}
145-
hir::ItemUnion(..) => {
146-
unimplemented_unions!();
145+
hir::ItemUnion(ref struct_def, ref ast_generics) => {
146+
self.check_type_defn(item, true, |fcx| {
147+
vec![fcx.struct_variant(struct_def)]
148+
});
149+
150+
self.check_variances_for_type_defn(item, ast_generics);
147151
}
148152
hir::ItemEnum(ref enum_def, ref ast_generics) => {
149-
self.check_type_defn(item, |fcx| {
153+
self.check_type_defn(item, false, |fcx| {
150154
fcx.enum_variants(enum_def)
151155
});
152156

@@ -219,24 +223,22 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
219223
}
220224

221225
/// In a type definition, we check that to ensure that the types of the fields are well-formed.
222-
fn check_type_defn<F>(&mut self, item: &hir::Item, mut lookup_fields: F) where
223-
F: for<'fcx, 'tcx> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx>)
224-
-> Vec<AdtVariant<'tcx>>
226+
fn check_type_defn<F>(&mut self, item: &hir::Item, all_sized: bool, mut lookup_fields: F)
227+
where F: for<'fcx, 'tcx> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx>) -> Vec<AdtVariant<'tcx>>
225228
{
226229
self.for_item(item).with_fcx(|fcx, this| {
227230
let variants = lookup_fields(fcx);
228231

229232
for variant in &variants {
230233
// For DST, all intermediate types must be sized.
231-
if let Some((_, fields)) = variant.fields.split_last() {
232-
for field in fields {
233-
fcx.register_builtin_bound(
234-
field.ty,
235-
ty::BoundSized,
236-
traits::ObligationCause::new(field.span,
237-
fcx.body_id,
238-
traits::FieldSized));
239-
}
234+
let unsized_len = if all_sized || variant.fields.is_empty() { 0 } else { 1 };
235+
for field in &variant.fields[..variant.fields.len() - unsized_len] {
236+
fcx.register_builtin_bound(
237+
field.ty,
238+
ty::BoundSized,
239+
traits::ObligationCause::new(field.span,
240+
fcx.body_id,
241+
traits::FieldSized));
240242
}
241243

242244
// All field types must be well-formed.

src/test/compile-fail/attr-usage-repr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#![allow(dead_code)]
1212
#![feature(repr_simd)]
1313

14-
#[repr(C)] //~ ERROR: attribute should be applied to struct or enum
14+
#[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union
1515
fn f() {}
1616

1717
#[repr(C)]

src/test/compile-fail/issue-31769.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010

1111
fn main() {
1212
#[inline] struct Foo; //~ ERROR attribute should be applied to function
13-
#[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct or enum
13+
#[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum or union
1414
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(untagged_unions)]
12+
13+
union U { //~ ERROR recursive type `U` has infinite size
14+
a: u8,
15+
b: U,
16+
}
17+
18+
fn main() {}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(untagged_unions)]
12+
13+
union U {
14+
a: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
15+
}
16+
17+
fn main() {}

src/test/run-pass/auxiliary/union.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(untagged_unions)]
12+
13+
pub union U {
14+
pub a: u8,
15+
b: u16,
16+
}

src/test/run-pass/union-xcrate.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:union.rs
12+
13+
// #![feature(untagged_unions)]
14+
15+
extern crate union;
16+
17+
type A = union::U;
18+
19+
fn main() {
20+
assert_eq!(std::mem::size_of::<A>(), 8);
21+
}

0 commit comments

Comments
 (0)