Support repr alignment on unions.
This commit is contained in:
parent
8f1339af2e
commit
ebc2f7d6ed
4 changed files with 116 additions and 8 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
72
src/test/run-pass/union/union-align.rs
Normal file
72
src/test/run-pass/union/union-align.rs
Normal 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);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue