Support repr alignment on unions.

This commit is contained in:
Cameron Hart 2017-07-17 00:44:13 +10:00
parent 8f1339af2e
commit ebc2f7d6ed
4 changed files with 116 additions and 8 deletions

View file

@ -121,9 +121,10 @@ impl<'a> CheckAttrVisitor<'a> {
}
"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
}

View file

@ -908,13 +908,30 @@ pub struct Union {
}
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(),
}
}
@ -1311,7 +1328,7 @@ impl<'a, 'tcx> Layout {
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 {

View file

@ -15,6 +15,7 @@ use std::mem;
// Raising alignment
#[repr(align(16))]
#[derive(Clone, Copy, Debug)]
struct Align16(i32);
// Lowering has no effect
@ -68,6 +69,11 @@ struct AlignLarge {
stuff: [u8; 0x10000],
}
union UnionContainsAlign {
a: Align16,
b: f32
}
impl Align16 {
// return aligned type
pub fn new(i: i32) -> Align16 {
@ -176,6 +182,18 @@ pub fn main() {
}
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);

View file

@ -0,0 +1,72 @@
// 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);
}
}