rust-bindgen icon indicating copy to clipboard operation
rust-bindgen copied to clipboard

packed type cannot transitively contain a `#[repr(align)]` type

Open ic3man5 opened this issue 2 years ago • 8 comments

Input C/C++ Header

#include <stdint.h>

#pragma pack(push, 2)

typedef struct _UART_SETTINGS
{
	uint16_t Baudrate;
	uint16_t spbrg;
	uint16_t brgh;
	uint16_t parity;
	uint16_t stop_bits;
	uint8_t flow_control; /* 0- off, 1 - Simple CTS RTS */
	uint8_t reserved_1;
	union {
		uint32_t bOptions;
		struct
		{
			unsigned invert_tx : 1;
			unsigned invert_rx : 1;
			unsigned half_duplex : 1;
			unsigned reserved_bits : 13;
			unsigned reserved_bits2 : 16;
		} opts;
	} options;
} UART_SETTINGS;

#pragma pack(pop)

Bindgen Invocation

$ bindgen test.h >> test.rs

Actual Results

error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
   --> src\main.rs:149:1
    |
149 | / pub union _UART_SETTINGS__bindgen_ty_1 {
150 | |     pub bOptions: u32,
151 | |     pub opts: _UART_SETTINGS__bindgen_ty_1__bindgen_ty_1,
152 | | }
    | |_^
    |
note: `_UART_SETTINGS__bindgen_ty_1__bindgen_ty_1` has a `#[repr(align)]` attribute
   --> src\main.rs:156:1
    |
156 | / pub struct _UART_SETTINGS__bindgen_ty_1__bindgen_ty_1 {
157 | |     pub _bitfield_align_1: [u8; 0],
158 | |     pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>,
159 | | }
    | |_^

Expected Results

compile successfully. If bitfields are removed and or packed is removed this work.

ic3man5 avatar Mar 21 '22 02:03 ic3man5

I'm getting a similar error when trying to build https://github.com/nviennot/tinyusb-sys-rs.git

I'm building with: cargo build --verbose --features device,cdc,rp2040 --target thumbv6m-none-eabi

I get these errors

Running `rustc --crate-name tinyusb_sys --edition=2021 src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 --cfg 'feature="cdc"' --cfg 'feature="device"' --cfg 'feature="rp2040"' -C metadata=222396e23cc7c407 -C extra-filename=-222396e23cc7c407 --out-dir /Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/thumbv6m-none-eabi/debug/deps --target thumbv6m-none-eabi -C incremental=/Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/thumbv6m-none-eabi/debug/incremental -L dependency=/Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/thumbv6m-none-eabi/debug/deps -L dependency=/Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/debug/deps --extern cty=/Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/thumbv6m-none-eabi/debug/deps/libcty-539500295d24c90b.rmeta -L native=/Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/thumbv6m-none-eabi/debug/build/tinyusb-sys-d484e22ceeda2732/out -l static=tinyusb`
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
    --> /Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/thumbv6m-none-eabi/debug/build/tinyusb-sys-d484e22ceeda2732/out/bindings.rs:3910:1
     |
3910 | / pub struct cdc_desc_func_telephone_call_state_reporting_capabilities_t {
3911 | |     #[doc = "< Size of this descriptor in bytes."]
3912 | |     pub bLength: u8,
3913 | |     #[doc = "< Descriptor Type, must be Class-Specific"]
...    |
3917 | |     pub bmCapabilities: cdc_desc_func_telephone_call_state_reporting_capabilities_t__bindgen_ty_1,
3918 | | }
     | |_^
     |
note: `cdc_desc_func_telephone_call_state_reporting_capabilities_t__bindgen_ty_1` has a `#[repr(align)]` attribute
    --> /Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/thumbv6m-none-eabi/debug/build/tinyusb-sys-d484e22ceeda2732/out/bindings.rs:3922:1
     |
3922 | / pub struct cdc_desc_func_telephone_call_state_reporting_capabilities_t__bindgen_ty_1 {
3923 | |     pub _bitfield_align_1: [u32; 0],
3924 | |     pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>,
3925 | | }
     | |_^

For more information about this error, try `rustc --explain E0588`.
error: could not compile `tinyusb-sys` due to previous error

Caused by:
  process didn't exit successfully: `rustc --crate-name tinyusb_sys --edition=2021 src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 --cfg 'feature="cdc"' --cfg 'feature="device"' --cfg 'feature="rp2040"' -C metadata=222396e23cc7c407 -C extra-filename=-222396e23cc7c407 --out-dir /Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/thumbv6m-none-eabi/debug/deps --target thumbv6m-none-eabi -C incremental=/Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/thumbv6m-none-eabi/debug/incremental -L dependency=/Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/thumbv6m-none-eabi/debug/deps -L dependency=/Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/debug/deps --extern cty=/Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/thumbv6m-none-eabi/debug/deps/libcty-539500295d24c90b.rmeta -L native=/Users/kevinpeck/Desktop/RepRap-RatRigVCore3/tinyusb-sys-rs/target/thumbv6m-none-eabi/debug/build/tinyusb-sys-d484e22ceeda2732/out -l static=tinyusb` (exit status: 1)

Where the source looks like


/// \brief Telephone Call and Line State Reporting Capabilities Descriptor
/// \details The Telephone Call and Line State Reporting Capabilities functional descriptor describes the abilities of a
/// telephone device to report optional call and line states.
typedef struct TU_ATTR_PACKED
{
  uint8_t bLength            ; ///< Size of this descriptor in bytes.
  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
  uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
  struct {
    uint32_t interrupted_dialtone   : 1; ///< 0 : Reports only dialtone (does not differentiate between normal and interrupted dialtone). 1 : R
eports interrupted dialtone in addition to normal dialtone
    uint32_t ringback_busy_fastbusy : 1; ///< 0 : Reports only dialing state. 1 : Reports ringback, busy, and fast busy states.
    uint32_t caller_id              : 1; ///< 0 : Does not report caller ID. 1 : Reports caller ID information.
    uint32_t incoming_distinctive   : 1; ///< 0 : Reports only incoming ringing. 1 : Reports incoming distinctive ringing patterns.
    uint32_t dual_tone_multi_freq   : 1; ///< 0 : Cannot report dual tone multi-frequency (DTMF) digits input remotely over the telephone line.
 1 : Can report DTMF digits input remotely over the telephone line.
    uint32_t line_state_change      : 1; ///< 0 : Does not support line state change notification. 1 : Does support line state change notificat
ion
    uint32_t TU_RESERVED            : 26;
  } bmCapabilities;
}cdc_desc_func_telephone_call_state_reporting_capabilities_t;

kpishere avatar Aug 12 '22 01:08 kpishere

Seen by the kernel as well at: https://lore.kernel.org/all/[email protected]/

struct alt_instr {
	s32 instr_offset;	/* original instruction */
	s32 repl_offset;	/* offset to replacement instruction */

	union {
		struct {
			u32 cpuid: 16;	/* CPUID bit set for replacement */
			u32 flags: 16;	/* patching control flags */
		};
		u32 ft_flgs;
	};

	u8  instrlen;		/* length of original instruction */
	u8  replacementlen;	/* length of new instruction */
} __packed;

ojeda avatar Jan 06 '23 23:01 ojeda

Encountered the same problem when binding spdk.

#include <stdint.h>

struct __attribute__((packed)) spdk_nvme_sgl_descriptor {
	uint64_t address;
	union {
		struct {
			uint8_t reserved[7];
			uint8_t subtype	: 4;
			uint8_t type	: 4;
		} generic;

		struct {
			uint32_t length;
			uint8_t reserved[3];
			uint8_t subtype	: 4;
			uint8_t type	: 4;
		} unkeyed;

		struct {
			uint64_t length		: 24;
			uint64_t key		: 32;
			uint64_t subtype	: 4;
			uint64_t type		: 4;
		} keyed;
	};
};

0x5459 avatar Apr 26 '23 08:04 0x5459

Any solution?

tomDev5 avatar Oct 28 '23 11:10 tomDev5

Here is a simple breakdown of the actual issue at hand. It looks the rust compiler can't align and pack at the same time which is causing the issue.



#[derive(Debug, Clone, Copy)]
#[repr(C, packed(2))]
struct PackedAlignedTest {
    a: u32,
    b: u16,
    inner: PackedAlignedInnerTest,
}

#[derive(Debug, Clone, Copy)]
#[repr(C, align(2))]
struct PackedAlignedInnerTest {
    c: u32,
    d: u16,
}

fn main() {
    let packed_aligned_test = PackedAlignedTest { 
        a: 0, 
        b: 1, 
        inner: PackedAlignedInnerTest { 
            c: 2, 
            d: 3 
        }
    };
    println!("{packed_aligned_test:#?}");
}
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
  --> src/main.rs:3:1
   |
3  | struct PackedAlignedTest {
   | ^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: `PackedAlignedInnerTest` has a `#[repr(align)]` attribute
  --> src/main.rs:11:1
   |
11 | struct PackedAlignedInnerTest {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0588`.
error: could not compile `playground` (bin "playground") due to previous error

From what I can tell there was an oversight in this issue: https://github.com/rust-lang/rust/issues/33158

Currently #[repr(packed())] structs cannot transitively contain #[repr(align())] structs due to differing behavior between msvc and gcc. Do we want to keep this a hard error, pick one behavior over the other, or provide some way to choose which behavior is desired?

This was never resolved and missed in review.

ic3man5 avatar Dec 12 '23 20:12 ic3man5