cbindgen icon indicating copy to clipboard operation
cbindgen copied to clipboard

Generating enum classes doesn't annotate the C-equivalent tag type

Open vadixidav opened this issue 3 years ago • 5 comments

This issue happened on gcc-arm-none-eabi-10.3-2021.10.

When you annotate a Rust type like:

#[repr(C)]
pub enum Error {
    A,
    B
}

cbindgen generates the following for C++:

enum class Error {
  A,
  B,
};

However, this is not necessarily correct. cbindgen needs to specify the type of the enum class using the same method that C does. cbindgen must be aware of how to generate the appropriate C representation, so it just needs to ensure that the enum class has the same layout. On the platform I am building for, this is apparently different between the enum class and C style enums.

What it should look like:

enum class Error: <c enum type here> {
  A,
  B,
};

As a workaround, I use #[repr(usize)] and #[repr(C, usize)]. cbindgen automatically annotates the correct type for the enum classes in this case.

Let me know if any more info is required.

vadixidav avatar Aug 03 '22 17:08 vadixidav

However, this is not necessarily correct. cbindgen needs to specify the type of the enum class using the same method that C does.

Can you elaborate? C uses int representation by default, IIRC, what do you do to make that layout not match?

emilio avatar Aug 03 '22 18:08 emilio

However, this is not necessarily correct. cbindgen needs to specify the type of the enum class using the same method that C does.

Can you elaborate? C uses int representation by default, IIRC, what do you do to make that layout not match?

For some reason, with the example above, it doesn't match the ABI unless I add , usize after C. I am doing nothing other than linking it in via staticlib. If you would like, I can get the exact size of the field with and without that annotation in Rust on the C++ side. It is possible that the compiler I am using has been modified. It is part of the Renesas FSP.

vadixidav avatar Aug 03 '22 19:08 vadixidav

Can you printf("size: %zu\n", sizeof(Error)); on your target? Are you compiling with flags that shrink the enum or something? I've remember seeing such flags at some point

emilio avatar Aug 03 '22 19:08 emilio

I am on an embedded platform, so I can't currently printf easily, but I will send the data over a serial port.

I got a sizeof(Error) of 4 with #[repr(usize)]. I got a sizeof(Error) of 4 with #[repr(C)] as well.

My C flags: -D_RA_CORE=CM23 -D_RENESAS_RA_ <include dirs> -std=c99

My C++ flags: -D_RA_CORE=CM23 -D_RENESAS_RA_ <include dirs> -std=c++11 -fabi-version=0

My linker flags: -T "fsp.ld" -Xlinker --gc-sections <library dirs> -Wl,-Map,"digitizer.map" --specs=nano.specs --specs=rdimon.specs

So apparently the issue isn't that the size is wrong. Notably, I have this section in my header generated by cbindgen:

extern "C" {
CResult<uintptr_t, Error> serialize(const Message *self, CSliceMut<uint8_t> dest);
} // extern "C"

When I run the code, it creates a hard fault. I debugged it to investigate the issue, and the returned CResult<uintptr_t, Error> has an incorrect tag. The tag is clearly garbage data, but it should be 0 or 1.

I think I can help you best if I just show you exactly what is happening with some screenshots.

Here is what happens when I return this tagged enum using #[repr(C)]:

image image image

Here is what happens when I return this tagged enum using #[repr(C, usize)]:

image image image

The only change that I make is just that I change cbindgen from #[repr(C)] to #[repr(C, usize)]. There is no change to any other lines of code aside from the type specifier on this enum and on the Rust side. With #[repr(C)], the code has undefined behavior. With #[repr(C, usize)], the code works fine. I am not sure exactly why that is at this point.

Let me know if there is anything else I can do to help. Perhaps this ticket needs to be renamed based on the issue here.

vadixidav avatar Aug 03 '22 21:08 vadixidav

If #[repr(C)] in rust disagrees with enum Foo in some platforms, that seems like a rustc bug rather than a cbindgen bug, IMO.

emilio avatar Aug 16 '22 07:08 emilio