]> git.lizzy.rs Git - rust.git/commitdiff
Translate union constants
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Mon, 22 Aug 2016 16:56:14 +0000 (19:56 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Sat, 3 Sep 2016 10:39:35 +0000 (13:39 +0300)
Fix alignment for packed unions
Add some missing privacy test
Get rid of `unimplemented_unions` macro

src/librustc_const_eval/eval.rs
src/librustc_privacy/lib.rs
src/librustc_trans/adt.rs
src/librustc_trans/debuginfo/metadata.rs
src/libsyntax/diagnostics/macros.rs
src/libsyntax/feature_gate.rs
src/test/compile-fail/union-const-eval.rs [new file with mode: 0644]
src/test/compile-fail/union-const-pat.rs [new file with mode: 0644]
src/test/compile-fail/union-field-privacy.rs [new file with mode: 0644]
src/test/run-pass/union-const-trans.rs [new file with mode: 0644]
src/test/run-pass/union-packed.rs [new file with mode: 0644]

index 81fe19812ca47765182457ee58f54f253150b4e6..114b5e1331de2392ab25fc5e592f527862af54aa 100644 (file)
@@ -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 {
index 25601b6bfec7fe764456bf057609ae762cd52e4e..6b291c69307227e90acd9f82c1dc88ff9ef86b3f 100644 (file)
@@ -385,8 +385,9 @@ fn item_is_accessible(&self, did: DefId) -> bool {
     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();
         }
index abbb9a5d4dbe592ca2cdb0b67ff613dd72ce2451..7fd02ab82a3f8698283310e7c34d72f40c11ea05 100644 (file)
@@ -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))
 }
index bd67a215d65eb02163f31ca81dcb0c9827128171..00493b018c10e218948b49aff3752c164e49eb7c 100644 (file)
@@ -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 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, '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 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
                     }
                 ]
             },
-            adt::CEnum(..) => span_bug!(self.span, "This should be unreachable.")
+            adt::CEnum(..) | adt::UntaggedUnion(..) => {
+                span_bug!(self.span, "This should be unreachable.")
+            }
         }
     }
 }
index e2a7ec0a33de1be6ce5a6f97e04d6b9098e86dab..25e0428248df4f7a9a6d03ad9ff75babb52582f5 100644 (file)
@@ -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),*) => (
index b40124bd7741a8da040e2bdbe60ad7d9a2b27af7..287d33cc3e5b23b56a7f23b7b9656206ed162551 100644 (file)
@@ -959,7 +959,7 @@ fn visit_item(&mut self, i: &ast::Item) {
             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 (file)
index 0000000..b2bf173
--- /dev/null
@@ -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 (file)
index 0000000..3d16898
--- /dev/null
@@ -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 (file)
index 0000000..d1f2bbb
--- /dev/null
@@ -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 (file)
index 0000000..bdae1a0
--- /dev/null
@@ -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 (file)
index 0000000..b1650ae
--- /dev/null
@@ -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);
+}