4cb762ec8f
This affected cases where the style was set to `Stle::Tag`.
In enumerations, do not emut the tag type name with an `enum`
prefix. C treats the `enum` type as an `int` even if the
representation should be something else.
Here's an example non-C-like-enumeration:
#[repr(C, u8)]
enum P {
P1(u8),
P2(u8, u8),
P3(u8, u8, u8),
}
Without this patch, this is what's generated:
enum P_Tag {
P1,
P2,
P3,
};
typedef uint8_t P_Tag;
typedef struct {
uint8_t _0;
} P1_Body;
typedef struct {
uint8_t _0;
uint8_t _1;
} P2_Body;
typedef struct {
uint8_t _0;
uint8_t _1;
uint8_t _2;
} P3_Body;
typedef struct {
enum P_Tag tag;
union {
P1_Body p1;
P2_Body p2;
P3_Body p3;
};
} P;
Rust expects the size of the type to be 4 (one for the discriminant,
and 3 for the widest alternative. C, however, treats the `enum P_Tag
tag` field as an `int` rather than a `uint8_t`. This puts the size
(with padding) of of `P` to 8 bytes instead of 4. When passing this
type between Rust and C, they will disagree on the size.
After the patch is applied, the `P` struct is properly defined:
typedef struct {
P_Tag tag;
union {
P1_Body p1;
P2_Body p2;
P3_Body p3;
};
} P;
203 lines
2.3 KiB
C++
203 lines
2.3 KiB
C++
#include <cstdarg>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <new>
|
|
|
|
enum class A : uint64_t {
|
|
a1 = 0,
|
|
a2 = 2,
|
|
a3,
|
|
a4 = 5,
|
|
};
|
|
|
|
enum class B : uint32_t {
|
|
b1 = 0,
|
|
b2 = 2,
|
|
b3,
|
|
b4 = 5,
|
|
};
|
|
|
|
enum class C : uint16_t {
|
|
c1 = 0,
|
|
c2 = 2,
|
|
c3,
|
|
c4 = 5,
|
|
};
|
|
|
|
enum class D : uint8_t {
|
|
d1 = 0,
|
|
d2 = 2,
|
|
d3,
|
|
d4 = 5,
|
|
};
|
|
|
|
enum class E : uintptr_t {
|
|
e1 = 0,
|
|
e2 = 2,
|
|
e3,
|
|
e4 = 5,
|
|
};
|
|
|
|
enum class F : intptr_t {
|
|
f1 = 0,
|
|
f2 = 2,
|
|
f3,
|
|
f4 = 5,
|
|
};
|
|
|
|
enum class L {
|
|
l1,
|
|
l2,
|
|
l3,
|
|
l4,
|
|
};
|
|
|
|
enum class M : int8_t {
|
|
m1 = -1,
|
|
m2 = 0,
|
|
m3 = 1,
|
|
};
|
|
|
|
enum N {
|
|
n1,
|
|
n2,
|
|
n3,
|
|
n4,
|
|
};
|
|
|
|
enum O : int8_t {
|
|
o1,
|
|
o2,
|
|
o3,
|
|
o4,
|
|
};
|
|
|
|
struct J;
|
|
|
|
struct K;
|
|
|
|
struct Opaque;
|
|
|
|
union G {
|
|
enum class Tag : uint8_t {
|
|
Foo,
|
|
Bar,
|
|
Baz,
|
|
};
|
|
|
|
struct Foo_Body {
|
|
Tag tag;
|
|
int16_t _0;
|
|
};
|
|
|
|
struct Bar_Body {
|
|
Tag tag;
|
|
uint8_t x;
|
|
int16_t y;
|
|
};
|
|
|
|
struct {
|
|
Tag tag;
|
|
};
|
|
Foo_Body foo;
|
|
Bar_Body bar;
|
|
};
|
|
|
|
struct H {
|
|
enum class Tag {
|
|
H_Foo,
|
|
H_Bar,
|
|
H_Baz,
|
|
};
|
|
|
|
struct H_Foo_Body {
|
|
int16_t _0;
|
|
};
|
|
|
|
struct H_Bar_Body {
|
|
uint8_t x;
|
|
int16_t y;
|
|
};
|
|
|
|
Tag tag;
|
|
union {
|
|
H_Foo_Body foo;
|
|
H_Bar_Body bar;
|
|
};
|
|
};
|
|
|
|
struct I {
|
|
enum class Tag : uint8_t {
|
|
I_Foo,
|
|
I_Bar,
|
|
I_Baz,
|
|
};
|
|
|
|
struct I_Foo_Body {
|
|
int16_t _0;
|
|
};
|
|
|
|
struct I_Bar_Body {
|
|
uint8_t x;
|
|
int16_t y;
|
|
};
|
|
|
|
Tag tag;
|
|
union {
|
|
I_Foo_Body foo;
|
|
I_Bar_Body bar;
|
|
};
|
|
};
|
|
|
|
struct P {
|
|
enum class Tag : uint8_t {
|
|
P0,
|
|
P1,
|
|
};
|
|
|
|
struct P0_Body {
|
|
uint8_t _0;
|
|
};
|
|
|
|
struct P1_Body {
|
|
uint8_t _0;
|
|
uint8_t _1;
|
|
uint8_t _2;
|
|
};
|
|
|
|
Tag tag;
|
|
union {
|
|
P0_Body p0;
|
|
P1_Body p1;
|
|
};
|
|
};
|
|
|
|
extern "C" {
|
|
|
|
void root(Opaque *opaque,
|
|
A a,
|
|
B b,
|
|
C c,
|
|
D d,
|
|
E e,
|
|
F f,
|
|
G g,
|
|
H h,
|
|
I i,
|
|
J j,
|
|
K k,
|
|
L l,
|
|
M m,
|
|
N n,
|
|
O o,
|
|
P p);
|
|
|
|
} // extern "C"
|
|
|
|
#include <stddef.h>
|
|
#include "testing-helpers.h"
|
|
static_assert(offsetof(CBINDGEN_STRUCT(P), tag) == 0, "unexpected offset for tag");
|
|
static_assert(offsetof(CBINDGEN_STRUCT(P), p0) == 1, "unexpected offset for p0");
|
|
static_assert(offsetof(CBINDGEN_STRUCT(P), p0) == 1, "unexpected offset for p1");
|
|
static_assert(sizeof(CBINDGEN_STRUCT(P)) == 4, "unexpected size for P");
|