You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Another reproduction case, closer to what we hit in the kernel, was in a return type:
enumEf(void);
enumE { A };
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 #includes to the top of our bindgen 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, like E_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:
warning: ISO C forbids forward references to 'enum' types [-Wpedantic]
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 picks unsigned int), which contradicts bindgen's output:
`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/87tt7md1s6.fsf@kernel.org/ [2]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
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: