bindgen 0.73.0/0.73.1 generates a bitfield setter that tries to as-cast an
enum-typed value to u32, which fails to compile with E0605: non-primitive cast. The corresponding getter for the same field correctly uses
mem::transmute instead of as, so the getter/setter pair is inconsistent.
This regressed between 0.72.1 (works) and 0.73.0 (broken). It breaks the Mesa
mesa-git build (rusticl / OpenCL frontend), which uses a C bitfield of enum
type:
enum pipe_resource_usage { PIPE_USAGE_DEFAULT, PIPE_USAGE_IMMUTABLE,
PIPE_USAGE_DYNAMIC, PIPE_USAGE_STREAM,
PIPE_USAGE_STAGING };
struct pipe_resource {
...
unsigned compression_rate:4;
enum pipe_resource_usage usage:4;
...
};
Environment
bindgen / bindgen-cli: 0.73.1 (also reproduces on 0.73.0)
- Last known-good version: 0.72.1
- rustc: 1.98.1
- OS: Arch Linux x86_64
- libclang: system clang (Arch
extra package)
Actual generated code (from Mesa, verified against bindgen 0.73.1)
#[inline]
pub fn usage(&self) -> pipe_resource_usage {
unsafe { ::std::mem::transmute(self._bitfield_2.get_const::<4usize, 4u8>() as u32) }
}
#[inline]
pub fn set_usage(&mut self, val: pipe_resource_usage) {
let val: u32 = val as _; // <-- E0605 here
self._bitfield_2.set_const::<4usize, 4u8>(val as u64)
}
Compiler error:
error[E0605]: non-primitive cast: `pipe_resource_usage` as `u32`
--> rusticl_mesa_bindings.rs:41575:24
|
41575 | let val: u32 = val as _;
| ^^^^^^^^ an `as` expression can only be used to
| convert between primitive types or to
| coerce to a specific trait object
The getter uses transmute (which is correct for a fieldless C-like enum),
but the setter and the _raw/new_bitfield_* constructor helpers use as _,
which does not work for enum types — only for values already known to be
primitive.
How to reproduce with the real project
git clone https://gitlab.freedesktop.org/mesa/mesa.git
cd mesa
git checkout c3b008c1ba01d455351b762253ef44c3ca19653f # commit used when this was found
meson setup build -Dgallium-drivers=radeonsi -Dgallium-rusticl=true -Dllvm=enabled
ninja -C build src/gallium/frontends/rusticl/rusticl_mesa_bindings.rs
ninja -C build src/gallium/frontends/rusticl/libmesa_rust_gen.rlib
The rust.bindgen() invocation for this target
(src/gallium/frontends/rusticl/meson.build) uses:
--no-convert-floats
--default-enum-style rust
--with-derive-partialeq --with-derive-eq
--with-derive-partialord --with-derive-ord
--with-derive-hash --with-derive-default
--anon-fields-prefix anon_
What I tried (did NOT reproduce in isolation)
I tried to shrink this to a minimal standalone header:
enum Color { RED = 0, GREEN = 1, BLUE = 2 };
struct Foo {
unsigned other : 4;
enum Color color : 4;
};
Run with bindgen repro.h --default-enum-style rust (with and without all the
mesa --with-derive-* flags): this generates the same-looking
let val: u32 = val as _; setter code, but in this minimal case
Color is a plain fieldless enum and the as cast does compile
successfully — no error. So the bug seems to depend on something about the
larger translation unit / real header graph (Mesa's rusticl_mesa_bindings.h
pulls in many headers where pipe_resource_usage and pipe_map_flags are
also used as ordinary (non-bitfield) types in dozens of function signatures
across other headers, and are forward/re-referenced in several places). I did
not have time to narrow down the exact trigger further — possibly related to
enum type canonicalization changes in #3346 ("Do not use the canonical
declaration for enum type building"), but I can't confirm that without more
digging. Flagging this here so maintainers with more context on that change
can take a look.
Expected behavior
The setter (and _raw/new_bitfield_* helpers) for an enum-typed bitfield
should use the same conversion mechanism as the getter (e.g. a cast through
the underlying representation via transmute, or requiring the enum to
implement Into<u32>), not a bare as _ cast.
Impact
This currently breaks compilation of Mesa's rusticl (OpenCL) frontend
whenever it's built against bindgen >= 0.73.0, for anyone building
mesa-git-style packages (e.g. Arch Linux AUR mesa-amdonly-gaming-git,
and presumably any other rusticl build using a newer bindgen).
bindgen0.73.0/0.73.1 generates a bitfield setter that tries toas-cast anenum-typed value to
u32, which fails to compile withE0605: non-primitive cast. The corresponding getter for the same field correctly usesmem::transmuteinstead ofas, so the getter/setter pair is inconsistent.This regressed between 0.72.1 (works) and 0.73.0 (broken). It breaks the Mesa
mesa-gitbuild (rusticl / OpenCL frontend), which uses a C bitfield of enumtype:
Environment
bindgen/bindgen-cli: 0.73.1 (also reproduces on 0.73.0)extrapackage)Actual generated code (from Mesa, verified against bindgen 0.73.1)
Compiler error:
The getter uses
transmute(which is correct for a fieldless C-like enum),but the setter and the
_raw/new_bitfield_*constructor helpers useas _,which does not work for enum types — only for values already known to be
primitive.
How to reproduce with the real project
The
rust.bindgen()invocation for this target(
src/gallium/frontends/rusticl/meson.build) uses:What I tried (did NOT reproduce in isolation)
I tried to shrink this to a minimal standalone header:
Run with
bindgen repro.h --default-enum-style rust(with and without all themesa
--with-derive-*flags): this generates the same-lookinglet val: u32 = val as _;setter code, but in this minimal caseColoris a plain fieldless enum and theascast does compilesuccessfully — no error. So the bug seems to depend on something about the
larger translation unit / real header graph (Mesa's
rusticl_mesa_bindings.hpulls in many headers where
pipe_resource_usageandpipe_map_flagsarealso used as ordinary (non-bitfield) types in dozens of function signatures
across other headers, and are forward/re-referenced in several places). I did
not have time to narrow down the exact trigger further — possibly related to
enum type canonicalization changes in #3346 ("Do not use the canonical
declaration for enum type building"), but I can't confirm that without more
digging. Flagging this here so maintainers with more context on that change
can take a look.
Expected behavior
The setter (and
_raw/new_bitfield_*helpers) for an enum-typed bitfieldshould use the same conversion mechanism as the getter (e.g. a cast through
the underlying representation via
transmute, or requiring the enum toimplement
Into<u32>), not a bareas _cast.Impact
This currently breaks compilation of Mesa's rusticl (OpenCL) frontend
whenever it's built against bindgen >= 0.73.0, for anyone building
mesa-git-style packages (e.g. Arch Linux AURmesa-amdonly-gaming-git,and presumably any other rusticl build using a newer bindgen).