}
"align" => {
found_align = true;
- if target != Target::Struct {
- ("attribute should be applied to struct",
- "a struct")
+ if target != Target::Struct &&
+ target != Target::Union {
+ ("attribute should be applied to struct or union",
+ "a struct or union")
} else {
continue
}
}
impl<'a, 'tcx> Union {
- fn new(dl: &TargetDataLayout, packed: bool) -> Union {
- let align = if packed { dl.i8_align } else { dl.aggregate_align };
+ fn new(dl: &TargetDataLayout, repr: &ReprOptions) -> Union {
+ if repr.packed() && repr.align > 0 {
+ bug!("Union cannot be packed and aligned");
+ }
+
+ let primitive_align = if repr.packed() {
+ dl.i8_align
+ } else {
+ dl.aggregate_align
+ };
+
+ let align = if repr.align > 0 {
+ let repr_align = repr.align as u64;
+ debug!("Union::new repr_align: {:?}", repr_align);
+ primitive_align.max(Align::from_bytes(repr_align, repr_align).unwrap())
+ } else {
+ primitive_align
+ };
+
Union {
align,
- primitive_align: align,
+ primitive_align,
min_size: Size::from_bytes(0),
- packed,
+ packed: repr.packed(),
}
}
field.ty(tcx, substs).layout(tcx, param_env)
}).collect::<Result<Vec<_>, _>>()?;
let layout = if def.is_union() {
- let mut un = Union::new(dl, def.repr.packed());
+ let mut un = Union::new(dl, &def.repr);
un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?;
UntaggedUnion { variants: un }
} else {
// Raising alignment
#[repr(align(16))]
+#[derive(Clone, Copy, Debug)]
struct Align16(i32);
// Lowering has no effect
stuff: [u8; 0x10000],
}
+union UnionContainsAlign {
+ a: Align16,
+ b: f32
+}
+
impl Align16 {
// return aligned type
pub fn new(i: i32) -> Align16 {
}
assert!(is_aligned_to(&e, 16));
+ // check union alignment
+ assert_eq!(mem::align_of::<UnionContainsAlign>(), 16);
+ assert_eq!(mem::size_of::<UnionContainsAlign>(), 16);
+ let u = UnionContainsAlign { a: Align16(10) };
+ unsafe {
+ assert_eq!(mem::align_of_val(&u.a), 16);
+ assert_eq!(mem::size_of_val(&u.a), 16);
+ assert_eq!(u.a.0, 10);
+ let UnionContainsAlign { a } = u;
+ assert_eq!(a.0, 10);
+ }
+
// arrays of aligned elements should also be aligned
assert_eq!(mem::align_of::<[Align16;2]>(), 16);
assert_eq!(mem::size_of::<[Align16;2]>(), 32);
--- /dev/null
+// Copyright 2017 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(attr_literals)]
+#![feature(repr_align)]
+#![feature(untagged_unions)]
+
+use std::mem::{size_of, size_of_val, align_of, align_of_val};
+
+#[repr(align(16))]
+pub union U16 {
+ a: u8,
+ b: u32
+}
+
+fn main() {
+ assert_eq!(align_of::<U16>(), 16);
+ assert_eq!(size_of::<U16>(), 16);
+ let u = U16 { a: 10 };
+ unsafe {
+ assert_eq!(align_of_val(&u.a), 1);
+ assert_eq!(size_of_val(&u.a), 1);
+ assert_eq!(u.a, 10);
+ }
+
+ let u = U16 { b: 11 };
+ unsafe {
+ assert_eq!(align_of_val(&u.b), 4);
+ assert_eq!(size_of_val(&u.b), 4);
+ assert_eq!(u.b, 11);
+ }
+
+ hybrid::check_hybrid();
+}
+
+mod hybrid {
+ use std::mem::{size_of, align_of};
+
+ #[repr(align(16))]
+ struct S1 {
+ a: u16,
+ b: u8,
+ }
+
+ #[repr(align(32))]
+ union U {
+ s: S1,
+ c: u16,
+ }
+
+ #[repr(align(64))]
+ struct S2 {
+ d: u8,
+ u: U,
+ }
+
+ pub fn check_hybrid() {
+ assert_eq!(align_of::<S1>(), 16);
+ assert_eq!(size_of::<S1>(), 16);
+ assert_eq!(align_of::<U>(), 32);
+ assert_eq!(size_of::<U>(), 32);
+ assert_eq!(align_of::<S2>(), 64);
+ assert_eq!(size_of::<S2>(), 64);
+ }
+}