codegen: Track union layout more accurately. · rust-lang/rust-bindgen@8ac787a (original) (raw)
`@@ -1219,7 +1219,7 @@ impl<'a> FieldCodegen<'a> for FieldData {
`
1219
1219
` ty.append_implicit_template_params(ctx, field_item);
`
1220
1220
``
1221
1221
`` // NB: If supported, we use proper union
types.
``
1222
``
`-
let ty = if parent.is_union() && !parent.can_be_rust_union(ctx) {
`
``
1222
`+
let ty = if parent.is_union() && !struct_layout.is_rust_union() {
`
1223
1223
` result.saw_bindgen_union();
`
1224
1224
`if ctx.options().enable_cxx_namespaces {
`
1225
1225
`quote! {
`
`@@ -1263,12 +1263,10 @@ impl<'a> FieldCodegen<'a> for FieldData {
`
1263
1263
`.expect("Each field should have a name in codegen!");
`
1264
1264
`let field_ident = ctx.rust_ident_raw(field_name.as_str());
`
1265
1265
``
1266
``
`-
if !parent.is_union() {
`
1267
``
`-
if let Some(padding_field) =
`
1268
``
`-
struct_layout.pad_field(&field_name, field_ty, self.offset())
`
1269
``
`-
{
`
1270
``
`-
fields.extend(Some(padding_field));
`
1271
``
`-
}
`
``
1266
`+
if let Some(padding_field) =
`
``
1267
`+
struct_layout.saw_field(&field_name, field_ty, self.offset())
`
``
1268
`+
{
`
``
1269
`+
fields.extend(Some(padding_field));
`
1272
1270
`}
`
1273
1271
``
1274
1272
`let is_private = (!self.is_public() &&
`
`@@ -1433,7 +1431,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
`
1433
1431
`let layout = self.layout();
`
1434
1432
`let unit_field_ty = helpers::bitfield_unit(ctx, layout);
`
1435
1433
`let field_ty = {
`
1436
``
`-
if parent.is_union() && !parent.can_be_rust_union(ctx) {
`
``
1434
`+
if parent.is_union() && !struct_layout.is_rust_union() {
`
1437
1435
` result.saw_bindgen_union();
`
1438
1436
`if ctx.options().enable_cxx_namespaces {
`
1439
1437
`quote! {
`
`@@ -1571,7 +1569,7 @@ impl<'a> FieldCodegen<'a> for Bitfield {
`
1571
1569
`_accessor_kind: FieldAccessorKind,
`
1572
1570
`parent: &CompInfo,
`
1573
1571
`_result: &mut CodegenResult,
`
1574
``
`-
_struct_layout: &mut StructLayoutTracker,
`
``
1572
`+
struct_layout: &mut StructLayoutTracker,
`
1575
1573
`_fields: &mut F,
`
1576
1574
`methods: &mut M,
`
1577
1575
`(unit_field_name, bitfield_representable_as_int): (&'a str, &mut bool),
`
`@@ -1612,7 +1610,7 @@ impl<'a> FieldCodegen<'a> for Bitfield {
`
1612
1610
`self.is_public() && !fields_should_be_private,
`
1613
1611
`);
`
1614
1612
``
1615
``
`-
if parent.is_union() && !parent.can_be_rust_union(ctx) {
`
``
1613
`+
if parent.is_union() && !struct_layout.is_rust_union() {
`
1616
1614
` methods.extend(Some(quote! {
`
1617
1615
` #[inline]
`
1618
1616
` #access_spec fn #getter_name(&self) -> #bitfield_ty {
`
`@@ -1768,15 +1766,53 @@ impl CodeGenerator for CompInfo {
`
1768
1766
`}
`
1769
1767
`}
`
1770
1768
``
1771
``
`-
let is_union = self.kind() == CompKind::Union;
`
1772
``
`-
let layout = item.kind().expect_type().layout(ctx);
`
1773
``
-
1774
``
`-
let mut explicit_align = None;
`
1775
1769
`if is_opaque {
`
1776
1770
`// Opaque item should not have generated methods, fields.
`
1777
1771
`debug_assert!(fields.is_empty());
`
1778
1772
`debug_assert!(methods.is_empty());
`
``
1773
`+
}
`
1779
1774
``
``
1775
`+
let is_union = self.kind() == CompKind::Union;
`
``
1776
`+
let layout = item.kind().expect_type().layout(ctx);
`
``
1777
`+
let zero_sized = item.is_zero_sized(ctx);
`
``
1778
`+
let forward_decl = self.is_forward_declaration();
`
``
1779
+
``
1780
`+
let mut explicit_align = None;
`
``
1781
+
``
1782
`+
// C++ requires every struct to be addressable, so what C++ compilers do
`
``
1783
`+
// is making the struct 1-byte sized.
`
``
1784
`+
//
`
``
1785
`+
// This is apparently not the case for C, see:
`
``
1786
`+
// https://github.com/rust-lang/rust-bindgen/issues/551
`
``
1787
`+
//
`
``
1788
`+
// Just get the layout, and assume C++ if not.
`
``
1789
`+
//
`
``
1790
`+
// NOTE: This check is conveniently here to avoid the dummy fields we
`
``
1791
`+
// may add for unused template parameters.
`
``
1792
`+
if !forward_decl && zero_sized {
`
``
1793
`+
let has_address = if is_opaque {
`
``
1794
`+
// Generate the address field if it's an opaque type and
`
``
1795
`+
// couldn't determine the layout of the blob.
`
``
1796
`+
layout.is_none()
`
``
1797
`+
} else {
`
``
1798
`+
layout.map_or(true, |l| l.size != 0)
`
``
1799
`+
};
`
``
1800
+
``
1801
`+
if has_address {
`
``
1802
`+
let layout = Layout::new(1, 1);
`
``
1803
`+
let ty = helpers::blob(ctx, Layout::new(1, 1));
`
``
1804
`+
struct_layout.saw_field_with_layout(
`
``
1805
`+
"_address",
`
``
1806
`+
layout,
`
``
1807
`+
/* offset = */ Some(0),
`
``
1808
`+
);
`
``
1809
`+
fields.push(quote! {
`
``
1810
`+
pub _address: #ty,
`
``
1811
`+
});
`
``
1812
`+
}
`
``
1813
`+
}
`
``
1814
+
``
1815
`+
if is_opaque {
`
1780
1816
`match layout {
`
1781
1817
`Some(l) => {
`
1782
1818
` explicit_align = Some(l.align);
`
`@@ -1790,7 +1826,7 @@ impl CodeGenerator for CompInfo {
`
1790
1826
`warn!("Opaque type without layout! Expect dragons!");
`
1791
1827
`}
`
1792
1828
`}
`
1793
``
`-
} else if !is_union && !item.is_zero_sized(ctx) {
`
``
1829
`+
} else if !is_union && !zero_sized {
`
1794
1830
`if let Some(padding_field) =
`
1795
1831
` layout.and_then(|layout| struct_layout.pad_struct(layout))
`
1796
1832
`{
`
`@@ -1815,57 +1851,26 @@ impl CodeGenerator for CompInfo {
`
1815
1851
`}
`
1816
1852
`}
`
1817
1853
`}
`
1818
``
`-
} else if is_union && !self.is_forward_declaration() {
`
``
1854
`+
} else if is_union && !forward_decl {
`
1819
1855
`// TODO(emilio): It'd be nice to unify this with the struct path
`
1820
1856
`// above somehow.
`
1821
1857
`let layout = layout.expect("Unable to get layout information?");
`
1822
``
`-
struct_layout.saw_union(layout);
`
1823
``
-
1824
1858
`if struct_layout.requires_explicit_align(layout) {
`
1825
1859
` explicit_align = Some(layout.align);
`
1826
1860
`}
`
1827
1861
``
1828
``
`-
let ty = helpers::blob(ctx, layout);
`
1829
``
`-
fields.push(if self.can_be_rust_union(ctx) {
`
1830
``
`-
quote! {
`
1831
``
`-
_bindgen_union_align: #ty ,
`
1832
``
`-
}
`
1833
``
`-
} else {
`
1834
``
`-
quote! {
`
``
1862
`+
if !struct_layout.is_rust_union() {
`
``
1863
`+
let ty = helpers::blob(ctx, layout);
`
``
1864
`+
fields.push(quote! {
`
1835
1865
`pub bindgen_union_field: #ty ,
`
1836
``
`-
}
`
1837
``
`-
});
`
``
1866
`+
})
`
``
1867
`+
}
`
1838
1868
`}
`
1839
1869
``
1840
``
`-
// C++ requires every struct to be addressable, so what C++ compilers do
`
1841
``
`-
// is making the struct 1-byte sized.
`
1842
``
`-
//
`
1843
``
`-
// This is apparently not the case for C, see:
`
1844
``
`-
// https://github.com/rust-lang/rust-bindgen/issues/551
`
1845
``
`-
//
`
1846
``
`-
// Just get the layout, and assume C++ if not.
`
1847
``
`-
//
`
1848
``
`-
// NOTE: This check is conveniently here to avoid the dummy fields we
`
1849
``
`-
// may add for unused template parameters.
`
1850
``
`-
if self.is_forward_declaration() {
`
``
1870
`+
if forward_decl {
`
1851
1871
` fields.push(quote! {
`
1852
1872
` _unused: [u8; 0],
`
1853
1873
`});
`
1854
``
`-
} else if item.is_zero_sized(ctx) {
`
1855
``
`-
let has_address = if is_opaque {
`
1856
``
`-
// Generate the address field if it's an opaque type and
`
1857
``
`-
// couldn't determine the layout of the blob.
`
1858
``
`-
layout.is_none()
`
1859
``
`-
} else {
`
1860
``
`-
layout.map_or(true, |l| l.size != 0)
`
1861
``
`-
};
`
1862
``
-
1863
``
`-
if has_address {
`
1864
``
`-
let ty = helpers::blob(ctx, Layout::new(1, 1));
`
1865
``
`-
fields.push(quote! {
`
1866
``
`-
pub _address: #ty,
`
1867
``
`-
});
`
1868
``
`-
}
`
1869
1874
`}
`
1870
1875
``
1871
1876
`let mut generic_param_names = vec![];
`
`@@ -1963,7 +1968,7 @@ impl CodeGenerator for CompInfo {
`
1963
1968
` attributes.push(attributes::derives(&derives))
`
1964
1969
`}
`
1965
1970
``
1966
``
`-
let mut tokens = if is_union && self.can_be_rust_union(ctx) {
`
``
1971
`+
let mut tokens = if is_union && struct_layout.is_rust_union() {
`
1967
1972
`quote! {
`
1968
1973
` #( #attributes )*
`
1969
1974
`pub union #canonical_ident
`