Skip to content

fix(macros): reject #[repr(C)] on enums in derive(Type) - #4508

Open
thelastbackspace wants to merge 2 commits into
transact-rs:mainfrom
thelastbackspace:fix/4366-repr-c-enum
Open

thelastbackspace wants to merge 2 commits into
transact-rs:mainfrom
thelastbackspace:fix/4366-repr-c-enum

Conversation

@thelastbackspace

@thelastbackspace thelastbackspace commented Nov 5, 2026 •

Copy link
Copy Markdown

Does your PR solve an issue?

fixes #4366

The enum derive picked the first path-only item in #[repr(..)] as the integer type to encode through. With #[repr(C)] that ended up as C, so the expansion had MyEnum::A as C and failed with confusing errors.

Following the review on #4403, #[repr(C)] on an enum is now rejected with a clear error instead of guessing what it should map to:

error: #[repr(C)] is ambiguous for #[derive(sqlx::Type)]: use an explicit integer repr like #[repr(i32)] to encode as an integer, or remove #[repr(C)] to encode as a string

Other details:

  • Only integer reprs (u8..u128, i8..i128, usize, isize) are used as the encoded type. #[repr(C, u8)] is allowed since the integer type is explicit there.
  • align(..), packed, transparent and Rust are still ignored. They only affect layout and don't say anything about the encoding, so I didn't want to error on them.

I added unit tests in sqlx-macros-core/src/derives/attributes.rs (enum_repr_c_is_rejected, enum_repr_c_with_integer_is_accepted, enum_layout_only_reprs_are_ignored). The first two fail without the change. I also checked the error end to end on a sqlite derive.

Is this a breaking change?

No. Enums with only #[repr(C)] didn't compile before either, now they just get a better error.

… for enums

The derive took the first path-only item of #[repr(..)] as the integer type, so #[repr(C)] produced `as C` casts that don't compile. Only use integer reprs; anything else is treated like an enum without a repr.
@abonander

Copy link
Copy Markdown
Collaborator

Did you see this comment on a prior PR I reviewed: #4403 (comment)

repr(C) doesn't say whether the enum should be encoded as a string or as a
C-like integer, and the C integer type differs per target. Instead of guessing,
emit a compile error that points at #[repr(i32)] or removing the repr.

Integer reprs work as before (also combined with C, e.g. #[repr(C, u8)]).
Layout-only reprs like align(..), packed, transparent and Rust are still
ignored since they don't affect the encoding.
@thelastbackspace thelastbackspace changed the title fix(macros): ignore #[repr(C)] and other non-integer reprs in derive(Type) for enums fix(macros): reject #[repr(C)] on enums in derive(Type) Nov 9, 2026
@thelastbackspace

Copy link
Copy Markdown
Author

Yes, I saw it, thanks for the pointer. I changed this PR to reject #[repr(C)] on enums with a compile error that suggests #[repr(i32)] or dropping the repr. #[repr(C, u8)] still works since the integer is explicit. align, packed, transparent and Rust are still ignored because they only affect layout, not the encoding. The test is enum_repr_c_is_rejected in sqlx-macros-core/src/derives/attributes.rs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

repr(C) breaks sqlx::Type on enums

2 participants