-
Notifications
You must be signed in to change notification settings - Fork 747
Forward references to enum
types end up generating the wrong type
#3179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Labels
Comments
33 tasks
ojeda
added a commit
to ojeda/linux
that referenced
this issue
Mar 25, 2025
`bindgen` currently generates the wrong type for an `enum` when there is a forward reference to it. For instance: enum E; enum E { A }; generates: pub const E_A: E = 0; pub type E = i32; instead of the expected: pub const E_A: E = 0; pub type E = ffi::c_uint; The issue was reported to upstream `bindgen` [1]. Now, both GCC and Clang support silently these forward references to `enum` types, unless `-Wpedantic` is passed, and it turns out that some headers in the kernel depend on them. Thus, depending on how the headers are included, which in turn may depend on the kernel configuration or the architecture, we may get a different type on the Rust side for a given C `enum`. That can be quite confusing, to say the least, especially since developers may only notice issues when building for other architectures like in [2]. In particular, they may end up forcing a cast and adding an `#[allow(clippy::unnecessary_cast)]` like it was done in commit 94e05a6 ("rust: hrtimer: allow timer restart from timer handler"), which isn't great. Instead, let's have a section at the top of our `bindings_helper.h` that `#include`s the headers with the affected types -- hopefully there are not many cases and there is a single ordering that covers all cases. This allows us to remove the cast and the `#[allow]`, thus keeping the correct code in the source files. When the issue gets resolved in upstream `bindgen` (and we update our minimum `bindgen` version), we can easily remove this section at the top. Link: rust-lang/rust-bindgen#3179 [1] Link: https://lore.kernel.org/rust-for-linux/[email protected]/ [2] Signed-off-by: Miguel Ojeda <[email protected]>
Responsible code is here: rust-bindgen/bindgen/codegen/mod.rs Lines 3679 to 3683 in 97ab915
Perhaps we could just skip forward declarations of enums, and assume that the real definition will come later in the code? |
ojeda
added a commit
to ojeda/linux
that referenced
this issue
May 22, 2025
`bindgen` currently generates the wrong type for an `enum` when there is a forward reference to it. For instance: enum E; enum E { A }; generates: pub const E_A: E = 0; pub type E = i32; instead of the expected: pub const E_A: E = 0; pub type E = ffi::c_uint; The issue was reported to upstream `bindgen` [1]. Now, both GCC and Clang support silently these forward references to `enum` types, unless `-Wpedantic` is passed, and it turns out that some headers in the kernel depend on them. Thus, depending on how the headers are included, which in turn may depend on the kernel configuration or the architecture, we may get a different type on the Rust side for a given C `enum`. That can be quite confusing, to say the least, especially since developers may only notice issues when building for other architectures like in [2]. In particular, they may end up forcing a cast and adding an `#[allow(clippy::unnecessary_cast)]` like it was done in commit 94e05a6 ("rust: hrtimer: allow timer restart from timer handler"), which isn't great. Instead, let's have a section at the top of our `bindings_helper.h` that `#include`s the headers with the affected types -- hopefully there are not many cases and there is a single ordering that covers all cases. This allows us to remove the cast and the `#[allow]`, thus keeping the correct code in the source files. When the issue gets resolved in upstream `bindgen` (and we update our minimum `bindgen` version), we can easily remove this section at the top. Link: rust-lang/rust-bindgen#3179 [1] Link: https://lore.kernel.org/rust-for-linux/[email protected]/ [2] Acked-by: Andreas Hindborg <[email protected]> Link: https://lore.kernel.org/r/[email protected] [ Added extra paragraph on the comment to clarify that the workaround may not be possible in some cases. - Miguel ] Signed-off-by: Miguel Ojeda <[email protected]>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
Uh oh!
There was an error while loading. Please reload this page.
Forward references to
enum
types end up generating the wrong type for theenum
. For instance:generates:
instead of the expected:
If we move it below:
or if we remove it:
then the generated type is the expected one.
Another reproduction case, closer to what we hit in the kernel, was in a return type:
In turn, this can mean that big codebases that
#include
headers from other headers end up in situations that are quite confusing.For instance, in the Linux kernel, one may end up with a forward reference or not, depending on how the headers are included, which in turn may depend on the kernel configuration or the architecture. In turn, that means that we need to either be careful to avoid those (e.g. adding extra
#include
s to the top of ourbindgen
input to bring the actual definitions first), or developers may end up forcing casts and adding#[allow(clippy::unnecessary_cast)]
(since the type of the generated constants, likeE_A
above, depends on the particular configuration):It is worth noting that GCC and Clang both allow these forward references to
enum
types and do not complain unless-Wpedantic
is used:Other compilers such as MSVC and TCC allow them, too.
Moreover, to double-check that the type of the actual
enum
in GCC and Clang is not changing on their side whether there is a forward reference or not, I added the following to the C examples above and it always passes (assuming the compiler picksunsigned int
), which contradictsbindgen
's output:Finally, I could reproduce the issue with
bindgen
0.71.1 andlibclang
20.1.1, i.e. latest releases, among others.The text was updated successfully, but these errors were encountered: