diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2016-08-22 19:56:14 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2016-09-03 13:39:35 +0300 |
| commit | d9b332bd69770cb716233b6998b11d345f6f184b (patch) | |
| tree | c83cf2e180339726ea9a9dee387e253d807cd12a | |
| parent | 2dc2fc5fc528aab7ba138f1a351df6f846dfec1d (diff) | |
| download | rust-d9b332bd69770cb716233b6998b11d345f6f184b.tar.gz rust-d9b332bd69770cb716233b6998b11d345f6f184b.zip | |
Translate union constants
Fix alignment for packed unions Add some missing privacy test Get rid of `unimplemented_unions` macro
| -rw-r--r-- | src/librustc_const_eval/eval.rs | 7 | ||||
| -rw-r--r-- | src/librustc_privacy/lib.rs | 5 | ||||
| -rw-r--r-- | src/librustc_trans/adt.rs | 23 | ||||
| -rw-r--r-- | src/librustc_trans/debuginfo/metadata.rs | 9 | ||||
| -rw-r--r-- | src/libsyntax/diagnostics/macros.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/union-const-eval.rs | 26 | ||||
| -rw-r--r-- | src/test/compile-fail/union-const-pat.rs | 25 | ||||
| -rw-r--r-- | src/test/compile-fail/union-field-privacy.rs | 21 | ||||
| -rw-r--r-- | src/test/run-pass/union-const-trans.rs | 27 | ||||
| -rw-r--r-- | src/test/run-pass/union-packed.rs | 74 |
11 files changed, 206 insertions, 20 deletions
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 81fe19812ca..114b5e1331d 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -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, @@ -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 { diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 25601b6bfec..6b291c69307 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -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(); } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index abbb9a5d4db..7fd02ab82a3 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -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(), } @@ -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)); @@ -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)) } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index bd67a215d65..00493b018c1 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -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, @@ -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 @@ -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.") + } } } } diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index e2a7ec0a33d..25e0428248d 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -108,13 +108,6 @@ macro_rules! help { } #[macro_export] -macro_rules! unimplemented_unions { - () => ({ - panic!("unions are not fully implemented"); - }) -} - -#[macro_export] macro_rules! register_diagnostics { ($($code:tt),*) => ( $(register_diagnostic! { $code })* diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index b40124bd774..287d33cc3e5 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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(..) => { diff --git a/src/test/compile-fail/union-const-eval.rs b/src/test/compile-fail/union-const-eval.rs new file mode 100644 index 00000000000..b2bf173c59c --- /dev/null +++ b/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 + } +} diff --git a/src/test/compile-fail/union-const-pat.rs b/src/test/compile-fail/union-const-pat.rs new file mode 100644 index 00000000000..3d168980ed2 --- /dev/null +++ b/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 + _ => {} + } +} diff --git a/src/test/compile-fail/union-field-privacy.rs b/src/test/compile-fail/union-field-privacy.rs new file mode 100644 index 00000000000..d1f2bbbc3d0 --- /dev/null +++ b/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 +} diff --git a/src/test/run-pass/union-const-trans.rs b/src/test/run-pass/union-const-trans.rs new file mode 100644 index 00000000000..bdae1a0eaf8 --- /dev/null +++ b/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); + } +} diff --git a/src/test/run-pass/union-packed.rs b/src/test/run-pass/union-packed.rs new file mode 100644 index 00000000000..b1650ae3a7c --- /dev/null +++ b/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); +} |
