vvaltchev
vvaltchev

Reputation: 628

Unable to bypass gcc's -Wconversion

int main() {

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

    s.a = val & 0xfffff;         // 1) works
    s.a = (val >> 12) & 0xfffff; // 2) generates -Wconversion warning
}

I'm compiling a project with -Wconversion and I hit a case where I'm unable to convince the compiler that I'm fine with the conversion.

Questions:

Note[1]: this question is not a duplicate of: c++ bit fields and -Wconversion because the solutions proposed there simply do not work in my case.

Note[2]: this question is not a duplicate of: Why >>24 causes -Wconversion but >>23 doesn't? because refers to a different bug (or different manifestation of the same core-bug) and has a simple workaround using a cast, like proposed in c++ bit fields and -Wconversion, at least with GCC 7.3.

Upvotes: 10

Views: 849

Answers (2)

vvaltchev
vvaltchev

Reputation: 628

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.

Upvotes: 4

bolov
bolov

Reputation: 75795

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

Upvotes: 3

Related Questions