Skip to content

Commit 504328a

Browse files
committed
Auto merge of #43274 - bitshifter:union-align, r=petrochenkov
Support repr alignment on unions. Requested as part of RFC 1358 #33626 (comment).
2 parents 15aa15b + ebc2f7d commit 504328a

File tree

4 files changed

+116
-8
lines changed

4 files changed

+116
-8
lines changed

src/librustc/hir/check_attr.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,10 @@ impl<'a> CheckAttrVisitor<'a> {
121121
}
122122
"align" => {
123123
found_align = true;
124-
if target != Target::Struct {
125-
("attribute should be applied to struct",
126-
"a struct")
124+
if target != Target::Struct &&
125+
target != Target::Union {
126+
("attribute should be applied to struct or union",
127+
"a struct or union")
127128
} else {
128129
continue
129130
}

src/librustc/ty/layout.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -908,13 +908,30 @@ pub struct Union {
908908
}
909909

910910
impl<'a, 'tcx> Union {
911-
fn new(dl: &TargetDataLayout, packed: bool) -> Union {
912-
let align = if packed { dl.i8_align } else { dl.aggregate_align };
911+
fn new(dl: &TargetDataLayout, repr: &ReprOptions) -> Union {
912+
if repr.packed() && repr.align > 0 {
913+
bug!("Union cannot be packed and aligned");
914+
}
915+
916+
let primitive_align = if repr.packed() {
917+
dl.i8_align
918+
} else {
919+
dl.aggregate_align
920+
};
921+
922+
let align = if repr.align > 0 {
923+
let repr_align = repr.align as u64;
924+
debug!("Union::new repr_align: {:?}", repr_align);
925+
primitive_align.max(Align::from_bytes(repr_align, repr_align).unwrap())
926+
} else {
927+
primitive_align
928+
};
929+
913930
Union {
914931
align,
915-
primitive_align: align,
932+
primitive_align,
916933
min_size: Size::from_bytes(0),
917-
packed,
934+
packed: repr.packed(),
918935
}
919936
}
920937

@@ -1311,7 +1328,7 @@ impl<'a, 'tcx> Layout {
13111328
field.ty(tcx, substs).layout(tcx, param_env)
13121329
}).collect::<Result<Vec<_>, _>>()?;
13131330
let layout = if def.is_union() {
1314-
let mut un = Union::new(dl, def.repr.packed());
1331+
let mut un = Union::new(dl, &def.repr);
13151332
un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?;
13161333
UntaggedUnion { variants: un }
13171334
} else {

src/test/run-pass/align-struct.rs

+18
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use std::mem;
1515

1616
// Raising alignment
1717
#[repr(align(16))]
18+
#[derive(Clone, Copy, Debug)]
1819
struct Align16(i32);
1920

2021
// Lowering has no effect
@@ -68,6 +69,11 @@ struct AlignLarge {
6869
stuff: [u8; 0x10000],
6970
}
7071

72+
union UnionContainsAlign {
73+
a: Align16,
74+
b: f32
75+
}
76+
7177
impl Align16 {
7278
// return aligned type
7379
pub fn new(i: i32) -> Align16 {
@@ -176,6 +182,18 @@ pub fn main() {
176182
}
177183
assert!(is_aligned_to(&e, 16));
178184

185+
// check union alignment
186+
assert_eq!(mem::align_of::<UnionContainsAlign>(), 16);
187+
assert_eq!(mem::size_of::<UnionContainsAlign>(), 16);
188+
let u = UnionContainsAlign { a: Align16(10) };
189+
unsafe {
190+
assert_eq!(mem::align_of_val(&u.a), 16);
191+
assert_eq!(mem::size_of_val(&u.a), 16);
192+
assert_eq!(u.a.0, 10);
193+
let UnionContainsAlign { a } = u;
194+
assert_eq!(a.0, 10);
195+
}
196+
179197
// arrays of aligned elements should also be aligned
180198
assert_eq!(mem::align_of::<[Align16;2]>(), 16);
181199
assert_eq!(mem::size_of::<[Align16;2]>(), 32);
+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(attr_literals)]
12+
#![feature(repr_align)]
13+
#![feature(untagged_unions)]
14+
15+
use std::mem::{size_of, size_of_val, align_of, align_of_val};
16+
17+
#[repr(align(16))]
18+
pub union U16 {
19+
a: u8,
20+
b: u32
21+
}
22+
23+
fn main() {
24+
assert_eq!(align_of::<U16>(), 16);
25+
assert_eq!(size_of::<U16>(), 16);
26+
let u = U16 { a: 10 };
27+
unsafe {
28+
assert_eq!(align_of_val(&u.a), 1);
29+
assert_eq!(size_of_val(&u.a), 1);
30+
assert_eq!(u.a, 10);
31+
}
32+
33+
let u = U16 { b: 11 };
34+
unsafe {
35+
assert_eq!(align_of_val(&u.b), 4);
36+
assert_eq!(size_of_val(&u.b), 4);
37+
assert_eq!(u.b, 11);
38+
}
39+
40+
hybrid::check_hybrid();
41+
}
42+
43+
mod hybrid {
44+
use std::mem::{size_of, align_of};
45+
46+
#[repr(align(16))]
47+
struct S1 {
48+
a: u16,
49+
b: u8,
50+
}
51+
52+
#[repr(align(32))]
53+
union U {
54+
s: S1,
55+
c: u16,
56+
}
57+
58+
#[repr(align(64))]
59+
struct S2 {
60+
d: u8,
61+
u: U,
62+
}
63+
64+
pub fn check_hybrid() {
65+
assert_eq!(align_of::<S1>(), 16);
66+
assert_eq!(size_of::<S1>(), 16);
67+
assert_eq!(align_of::<U>(), 32);
68+
assert_eq!(size_of::<U>(), 32);
69+
assert_eq!(align_of::<S2>(), 64);
70+
assert_eq!(size_of::<S2>(), 64);
71+
}
72+
}

0 commit comments

Comments
 (0)