summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Fitzgerald <fitzgen@gmail.com>2017-10-31 15:34:56 -0700
committerNick Fitzgerald <fitzgen@gmail.com>2017-10-31 15:34:56 -0700
commite17bd8df3fbd686fa0857b2e09d6e38c9fb6262c (patch)
treee5c385a8060cddda62009b9d4f979757c93bf1fb
parent7bc4f34ab6a1361ac7232a99da794873a3feaffc (diff)
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 #1076
-rw-r--r--src/ir/comp.rs22
-rw-r--r--tests/expectations/tests/issue-1034.rs7
-rw-r--r--tests/expectations/tests/issue-1076-unnamed-bitfield-alignment.rs31
-rw-r--r--tests/headers/issue-1076-unnamed-bitfield-alignment.h4
4 files changed, 54 insertions, 10 deletions
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index f3c986e7..7265660c 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -608,6 +608,21 @@ fn bitfields_to_allocation_units<E, I>(
}
}
+ // 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.
+ if bitfield.name().is_some() {
+ max_align = cmp::max(max_align, bitfield_align);
+
+ // NB: The `bitfield_width` here is completely, absolutely
+ // intentional. Alignment of the allocation unit is based on the
+ // maximum bitfield width, not (directly) on the bitfields' types'
+ // alignment.
+ unit_align = cmp::max(unit_align, bitfield_width);
+ }
+
// Always keep all bitfields around. While unnamed bitifields are used
// for padding (and usually not needed hereafter), large unnamed
// bitfields over their types size cause weird allocation size behavior from clang.
@@ -615,13 +630,6 @@ fn bitfields_to_allocation_units<E, I>(
// and make the struct opaque in this case
bitfields_in_unit.push(Bitfield::new(offset, bitfield));
- max_align = cmp::max(max_align, bitfield_align);
-
- // NB: The `bitfield_width` here is completely, absolutely intentional.
- // Alignment of the allocation unit is based on the maximum bitfield
- // width, not (directly) on the bitfields' types' alignment.
- unit_align = cmp::max(unit_align, bitfield_width);
-
unit_size_in_bits = offset + bitfield_width;
// Compute what the physical unit's final size would be given what we
diff --git a/tests/expectations/tests/issue-1034.rs b/tests/expectations/tests/issue-1034.rs
index b0c4b529..b5c7d6bb 100644
--- a/tests/expectations/tests/issue-1034.rs
+++ b/tests/expectations/tests/issue-1034.rs
@@ -4,10 +4,11 @@
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
-#[repr(C, packed)]
+#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct S2 {
- pub _bitfield_1: u16,
+ pub _bitfield_1: u8,
+ pub __bindgen_padding_0: u8,
}
#[test]
fn bindgen_test_layout_S2() {
@@ -24,7 +25,7 @@ fn bindgen_test_layout_S2() {
}
impl S2 {
#[inline]
- pub fn new_bitfield_1() -> u16 {
+ pub fn new_bitfield_1() -> u8 {
0
}
}
diff --git a/tests/expectations/tests/issue-1076-unnamed-bitfield-alignment.rs b/tests/expectations/tests/issue-1076-unnamed-bitfield-alignment.rs
new file mode 100644
index 00000000..00b3f11b
--- /dev/null
+++ b/tests/expectations/tests/issue-1076-unnamed-bitfield-alignment.rs
@@ -0,0 +1,31 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct S1 {
+ pub _bitfield_1: [u8; 2usize],
+ pub __bindgen_padding_0: u8,
+}
+#[test]
+fn bindgen_test_layout_S1() {
+ assert_eq!(
+ ::std::mem::size_of::<S1>(),
+ 3usize,
+ concat!("Size of: ", stringify!(S1))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<S1>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(S1))
+ );
+}
+impl S1 {
+ #[inline]
+ pub fn new_bitfield_1() -> u16 {
+ 0
+ }
+}
diff --git a/tests/headers/issue-1076-unnamed-bitfield-alignment.h b/tests/headers/issue-1076-unnamed-bitfield-alignment.h
new file mode 100644
index 00000000..876ec174
--- /dev/null
+++ b/tests/headers/issue-1076-unnamed-bitfield-alignment.h
@@ -0,0 +1,4 @@
+struct S1 {
+ signed : 15;
+ unsigned : 6
+};