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