Skip to content

Bitfield setter for enum-typed field emits invalid as cast (E0605), regression since 0.73.0 #3454

Description

@raiko86

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).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions