Skip to content

Commit

Permalink
Translate union constants
Browse files Browse the repository at this point in the history
Fix alignment for packed unions
Add some missing privacy test
Get rid of `unimplemented_unions` macro
  • Loading branch information
petrochenkov committed Sep 3, 2016
1 parent 2dc2fc5 commit d9b332b
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 20 deletions.
7 changes: 5 additions & 2 deletions src/librustc_const_eval/eval.rs
Expand Up @@ -258,8 +258,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
format!("floating point constants cannot be used in patterns"));
}
ty::TyEnum(adt_def, _) |
ty::TyStruct(adt_def, _) |
ty::TyUnion(adt_def, _) => {
ty::TyStruct(adt_def, _) => {
if !tcx.has_attr(adt_def.did, "structural_match") {
tcx.sess.add_lint(
lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
Expand All @@ -272,6 +271,10 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tcx.item_path_str(adt_def.did)));
}
}
ty::TyUnion(..) => {
// Matching on union fields is unsafe, we can't hide it in constants
tcx.sess.span_err(span, "cannot use unions in constant patterns");
}
_ => { }
}
let pat = match expr.node {
Expand Down
5 changes: 3 additions & 2 deletions src/librustc_privacy/lib.rs
Expand Up @@ -385,8 +385,9 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) {
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))
let kind_descr = if def.adt_kind() == ty::AdtKind::Union { "union" } else { "struct" };
struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private",
field.name, kind_descr, self.tcx.item_path_str(def.did))
.span_label(span, &format!("field `{}` is private", field.name))
.emit();
}
Expand Down
23 changes: 20 additions & 3 deletions src/librustc_trans/adt.rs
Expand Up @@ -516,7 +516,7 @@ fn mk_union<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,

Union {
min_size: min_size,
align: align,
align: if packed { 1 } else { align },
packed: packed,
fields: tys.to_vec(),
}
Expand Down Expand Up @@ -1176,8 +1176,10 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
contents.extend_from_slice(&[padding(ccx, max_sz - case.size)]);
C_struct(ccx, &contents[..], false)
}
UntaggedUnion(..) => {
unimplemented_unions!();
UntaggedUnion(ref un) => {
assert_eq!(discr, Disr(0));
let contents = build_const_union(ccx, un, vals[0]);
C_struct(ccx, &contents, un.packed)
}
Univariant(ref st) => {
assert_eq!(discr, Disr(0));
Expand Down Expand Up @@ -1272,6 +1274,21 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
cfields
}

fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
un: &Union<'tcx>,
field_val: ValueRef)
-> Vec<ValueRef> {
let mut cfields = vec![field_val];

let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
let size = roundup(un.min_size, un.align);
if offset != size {
cfields.push(padding(ccx, size - offset));
}

cfields
}

fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
C_undef(Type::array(&Type::i8(ccx), size))
}
Expand Down
9 changes: 4 additions & 5 deletions src/librustc_trans/debuginfo/metadata.rs
Expand Up @@ -786,7 +786,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
usage_site_span).finalize(cx)
}
ty::TyUnion(..) => {
unimplemented_unions!();
unimplemented!();
}
ty::TyTuple(ref elements) => {
prepare_tuple_metadata(cx,
Expand Down Expand Up @@ -1302,9 +1302,6 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
]
}
}
adt::UntaggedUnion(..) => {
unimplemented_unions!();
}
adt::RawNullablePointer { nndiscr: non_null_variant_index, nnty, .. } => {
// As far as debuginfo is concerned, the pointer this enum
// represents is still wrapped in a struct. This is to make the
Expand Down Expand Up @@ -1421,7 +1418,9 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
}
]
},
adt::CEnum(..) => span_bug!(self.span, "This should be unreachable.")
adt::CEnum(..) | adt::UntaggedUnion(..) => {
span_bug!(self.span, "This should be unreachable.")
}
}
}
}
Expand Down
7 changes: 0 additions & 7 deletions src/libsyntax/diagnostics/macros.rs
Expand Up @@ -107,13 +107,6 @@ macro_rules! help {
})
}

#[macro_export]
macro_rules! unimplemented_unions {
() => ({
panic!("unions are not fully implemented");
})
}

#[macro_export]
macro_rules! register_diagnostics {
($($code:tt),*) => (
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/feature_gate.rs
Expand Up @@ -959,7 +959,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
ast::ItemKind::Union(..) => {
gate_feature_post!(&self, untagged_unions,
i.span,
"unions are unstable and not fully implemented");
"unions are unstable and possibly buggy");
}

ast::ItemKind::DefaultImpl(..) => {
Expand Down
26 changes: 26 additions & 0 deletions src/test/compile-fail/union-const-eval.rs
@@ -0,0 +1,26 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(untagged_unions)]

union U {
a: usize,
b: usize,
}

const C: U = U { a: 10 };

fn main() {
unsafe {
let a: [u8; C.a]; // OK
let b: [u8; C.b]; //~ ERROR constant evaluation error
//~^ NOTE nonexistent struct field
}
}
25 changes: 25 additions & 0 deletions src/test/compile-fail/union-const-pat.rs
@@ -0,0 +1,25 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(untagged_unions)]

union U {
a: usize,
b: usize,
}

const C: U = U { a: 10 };

fn main() {
match C {
C => {} //~ ERROR cannot use unions in constant patterns
_ => {}
}
}
21 changes: 21 additions & 0 deletions src/test/compile-fail/union-field-privacy.rs
@@ -0,0 +1,21 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(untagged_unions)]

mod m {
pub union U {
a: u8
}
}

fn main() {
let u = m::U { a: 0 }; //~ ERROR field `a` of union `m::U` is private
}
27 changes: 27 additions & 0 deletions src/test/run-pass/union-const-trans.rs
@@ -0,0 +1,27 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(untagged_unions)]

union U {
a: u64,
b: u64,
}

const C: U = U { b: 10 };

fn main() {
unsafe {
let a = C.a;
let b = C.b;
assert_eq!(a, 10);
assert_eq!(b, 10);
}
}
74 changes: 74 additions & 0 deletions src/test/run-pass/union-packed.rs
@@ -0,0 +1,74 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(untagged_unions)]

use std::mem::{size_of, size_of_val, align_of, align_of_val};

struct S {
a: u16,
b: [u8; 3],
}

#[repr(packed)]
struct Sp {
a: u16,
b: [u8; 3],
}

union U {
a: u16,
b: [u8; 3],
}

#[repr(packed)]
union Up {
a: u16,
b: [u8; 3],
}

const CS: S = S { a: 0, b: [0, 0, 0] };
const CSP: Sp = Sp { a: 0, b: [0, 0, 0] };
const CU: U = U { b: [0, 0, 0] };
const CUP: Up = Up { b: [0, 0, 0] };

fn main() {
let s = S { a: 0, b: [0, 0, 0] };
assert_eq!(size_of::<S>(), 6);
assert_eq!(size_of_val(&s), 6);
assert_eq!(size_of_val(&CS), 6);
assert_eq!(align_of::<S>(), 2);
assert_eq!(align_of_val(&s), 2);
assert_eq!(align_of_val(&CS), 2);

let sp = Sp { a: 0, b: [0, 0, 0] };
assert_eq!(size_of::<Sp>(), 5);
assert_eq!(size_of_val(&sp), 5);
assert_eq!(size_of_val(&CSP), 5);
assert_eq!(align_of::<Sp>(), 1);
assert_eq!(align_of_val(&sp), 1);
assert_eq!(align_of_val(&CSP), 1);

let u = U { b: [0, 0, 0] };
assert_eq!(size_of::<U>(), 4);
assert_eq!(size_of_val(&u), 4);
assert_eq!(size_of_val(&CU), 4);
assert_eq!(align_of::<U>(), 2);
assert_eq!(align_of_val(&u), 2);
assert_eq!(align_of_val(&CU), 2);

let up = Up { b: [0, 0, 0] };
assert_eq!(size_of::<Up>(), 3);
assert_eq!(size_of_val(&up), 3);
assert_eq!(size_of_val(&CUP), 3);
assert_eq!(align_of::<Up>(), 1);
assert_eq!(align_of_val(&up), 1);
assert_eq!(align_of_val(&CUP), 1);
}

0 comments on commit d9b332b

Please sign in to comment.