Unable to bypass gcc's -Wconversion

I just discovered that in the GCC's bug tracker there are several bugs related with -Wconversion. In particular: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39170

Specifically, comment #18 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39170#c18) reports an example almost identical to mine:

#include <stdint.h>

struct foo
{
   unsigned bar: 30;
   unsigned fill: 2;
};

struct foo test(uint32_t value)
{
   struct foo foo;

   foo.bar = (value >> 2) & 0x3fffffffU;

   return foo;
}

Therefore, I believe that this issue is definitively a gcc bug.

Personal workaround

Given the compiler's bug, my personal workaround was to just wrap the right shift operation in a static always_inline function, even if I'm not particularly happy by this hack.

#include <stdint.h>

static __attribute__((always_inline)) inline uintptr_t
rshift(uintptr_t val, uintptr_t bits)
{
   return val >> bits;
}

int main() {

    struct { unsigned int a:20; } s;
    unsigned int val = 0xaabbc000;

    s.a = val & 0xfffff;                // 1) works
    s.a = (rshift(val, 12)) & 0xfffff;  // 2) works
}

Workaround suggested by PSkocik

   s.a = (unsigned){(val >> 12)} & 0xfffff; // works

Which is my favorite by now.


A ... workaround: use a temp variable. Not ideal, but it gets rid of the warning

const unsigned t = val >> 12u;
s.a = t & 0xfffffu;

Other than that you could explicitly turn of the warning for the line:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
    s.a = (val  >> 12u) & 0xfffffu;
#pragma GCC diagnostic pop

Tags:

C

Gcc