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

`