Skip to content

Commit e17bd8d

Browse files
committed
Unnamed bit-fields should not affect alignment
According to the x86[-64] ABI spec: "Unnamed bit-fields’ types do not affect the alignment of a structure or union". This makes sense: such bit-fields are only used for padding, and we can't perform an un-aligned read of something we can't read because we can't even name it. Fixes rust-lang#1076
1 parent 7bc4f34 commit e17bd8d

File tree

4 files changed

+54
-10
lines changed

4 files changed

+54
-10
lines changed

src/ir/comp.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -608,20 +608,28 @@ fn bitfields_to_allocation_units<E, I>(
608608
}
609609
}
610610

611+
// According to the x86[-64] ABI spec: "Unnamed bit-fields’ types do not
612+
// affect the alignment of a structure or union". This makes sense: such
613+
// bit-fields are only used for padding, and we can't perform an
614+
// un-aligned read of something we can't read because we can't even name
615+
// it.
616+
if bitfield.name().is_some() {
617+
max_align = cmp::max(max_align, bitfield_align);
618+
619+
// NB: The `bitfield_width` here is completely, absolutely
620+
// intentional. Alignment of the allocation unit is based on the
621+
// maximum bitfield width, not (directly) on the bitfields' types'
622+
// alignment.
623+
unit_align = cmp::max(unit_align, bitfield_width);
624+
}
625+
611626
// Always keep all bitfields around. While unnamed bitifields are used
612627
// for padding (and usually not needed hereafter), large unnamed
613628
// bitfields over their types size cause weird allocation size behavior from clang.
614629
// Therefore, all bitfields needed to be kept around in order to check for this
615630
// and make the struct opaque in this case
616631
bitfields_in_unit.push(Bitfield::new(offset, bitfield));
617632

618-
max_align = cmp::max(max_align, bitfield_align);
619-
620-
// NB: The `bitfield_width` here is completely, absolutely intentional.
621-
// Alignment of the allocation unit is based on the maximum bitfield
622-
// width, not (directly) on the bitfields' types' alignment.
623-
unit_align = cmp::max(unit_align, bitfield_width);
624-
625633
unit_size_in_bits = offset + bitfield_width;
626634

627635
// Compute what the physical unit's final size would be given what we

tests/expectations/tests/issue-1034.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
55

66

7-
#[repr(C, packed)]
7+
#[repr(C)]
88
#[derive(Debug, Default, Copy, Clone)]
99
pub struct S2 {
10-
pub _bitfield_1: u16,
10+
pub _bitfield_1: u8,
11+
pub __bindgen_padding_0: u8,
1112
}
1213
#[test]
1314
fn bindgen_test_layout_S2() {
@@ -24,7 +25,7 @@ fn bindgen_test_layout_S2() {
2425
}
2526
impl S2 {
2627
#[inline]
27-
pub fn new_bitfield_1() -> u16 {
28+
pub fn new_bitfield_1() -> u8 {
2829
0
2930
}
3031
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Default, Copy, Clone)]
9+
pub struct S1 {
10+
pub _bitfield_1: [u8; 2usize],
11+
pub __bindgen_padding_0: u8,
12+
}
13+
#[test]
14+
fn bindgen_test_layout_S1() {
15+
assert_eq!(
16+
::std::mem::size_of::<S1>(),
17+
3usize,
18+
concat!("Size of: ", stringify!(S1))
19+
);
20+
assert_eq!(
21+
::std::mem::align_of::<S1>(),
22+
1usize,
23+
concat!("Alignment of ", stringify!(S1))
24+
);
25+
}
26+
impl S1 {
27+
#[inline]
28+
pub fn new_bitfield_1() -> u16 {
29+
0
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
struct S1 {
2+
signed : 15;
3+
unsigned : 6
4+
};

0 commit comments

Comments
 (0)