Bug 39170 - provide an option to silence -Wconversion warnings for bit-fields
Summary: provide an option to silence -Wconversion warnings for bit-fields
Status: ASSIGNED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.3.3
: P3 enhancement
Target Milestone: ---
Assignee: David Malcolm
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2009-02-12 17:34 UTC by Tom Geocaris
Modified: 2022-07-23 10:30 UTC (History)
12 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2010-03-06 12:18:44


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tom Geocaris 2009-02-12 17:34:14 UTC
I'm sure this has been reported.

General narrowing of a value (i,e double to int) needs to be reported, but bit-fields narrowing should not be reported unless asked for. There is nothing in "C" or "C++" to cast a bit-field, which in theory, would remove the warning. This is a serious problem and it makes gcc 4.3 not usable!

Test case:

Compile "gcc" with -Wconversion.

Bit-field warnings need to be disabled We need a 4.3.3 patch otherwise we punt on 4.3 release.
Comment 1 Andrew Pinski 2009-02-12 17:39:14 UTC
Really -Wconversion is correct to warn about bit-fields because the conversion will lose bits.
Comment 2 Tom Geocaris 2009-02-12 18:10:40 UTC
Subject: Re:  -Wconversion useless

You miss the point. The only way to assign a non-constant value to a bit
field outside of a struct is using an integral variable i.e.,

struct foo
{
    int a : 2;
};

void assign( struct foo v, int x )
{
    v.a = x;
}

This results automatically in a warning. How do code this assignment
type-safe? There is no (bit-field) cast operator in the C or C++.

Like the "gcc" code base, our code does a lot bit-field assignments. We
no get thousands of warning using -Wconversion, this behavior makes the
option useless.

Again, compile the "gcc" code-base with "-Wconversion" and then you will
understand the problem.

Expect for bit-fields which are problematic to do potential bit-loss
(you must use with caution), you want warnings for implicit narrowing if
values, e.g., (double -> int)

void foo( int x );

...

double n;
foo(n)

The old behavior was just fine!

I'm sure many people do not even realize they are NOT getting implicit
conversions warnings anymore because they are not caught by "-Wall"
anymore. We only discovered this be tracing a bug in our code! We then
turned on "-Wconversion" only to discover thousands of warnings with no
way practical way to fix them. 

Regards,

Tom Geocaris

On Thu, 2009-02-12 at 17:39 +0000, pinskia at gcc dot gnu dot org wrote:
> 
> ------- Comment #1 from pinskia at gcc dot gnu dot org  2009-02-12 17:39 -------
> Really -Wconversion is correct to warn about bit-fields because the conversion
> will lose bits.
> 
> 

Comment 3 Manuel López-Ibáñez 2009-03-08 03:30:20 UTC
> The old behavior was just fine!

You absolutely did not understand what the old -Wconversion did. 

http://gcc.gnu.org/wiki/NewWconversion

But if you still want the old behaviour, just use -Wtraditional-conversion.

> I'm sure many people do not even realize they are NOT getting implicit
> conversions warnings anymore because they are not caught by "-Wall"

See the FAQ in the link above.

> anymore. We only discovered this be tracing a bug in our code! We then

The new Wconversion is mentioned in the changes of GCC 4.3.

> turned on "-Wconversion" only to discover thousands of warnings with no
> way practical way to fix them. 

I admit it is unfortunate that there is no way to specify casts to bit-fields. But that is hardly the fault of Wconversion. Nonetheless, it could be possible to use bitwise-and to tell Wconversion that some conversion is really desired. Example:

struct foo
{
    int a : 2;
};

void assign( struct foo v, int x )
{
    v.a = x & 0x3;
}

Do you think this would be an acceptable solution? (I don't know if this works now in GCC 4.4)

Comment 4 Tom Geocaris 2009-03-10 17:40:11 UTC
Manuel,

You miss understood what I meant by "old behavior was just fine". I was saying that the previous behavior of "gcc" worked fine and I was NOT referring specifically to the "-Wconversion" option. 

The previous version of "gcc" warned when implicit narrowing of doubles to integral values, such as

    double n = 0.0000000005;
    int d = n;

when using the "-Wall" option. 

The behavior of "gcc" has changed. Moving all the conversion warnings to fall under "-Wconversion" may make semantic sense, but it alters the behavior of "gcc". 

We can fault ourselves for missing this change in the documentation, but there a level of expectation that the fundamental behavior of the compiler is consistent from release-to-release. And when fundamental behavior of "gcc" changes, ample notice should be given. People need to change Makefiles, alter code (if possible), etc... 

With regard to "-Wtraditional-conversion", it does not work when compiling "C++" code.

> Do you think this would be an acceptable solution? (I don't know if this works
> now in GCC 4.4)

Absolutely not. It's not a portable solution. There is nothing in the "C++" standard (that I'm aware of) that suggests that "anding" an integral value with a "constant" value results in a truncated integral value. It's a bad hack.

As you say, its is unfortunate that "C" and "C++" do not have a bit-field "cast-operators". But that is the reality. 

There is a lot of code written using "bit-fields". Look at "gcc" itself. Until the "C" or "C++" language contains a "type-safe" construct, such as a cast-operator, "gcc" should not issue a warning by default.

If you have ideas on how to solve this, please submit them to the "C" or "C++" standards group.

The "gcc" 4.3 stream is not safe (for us) to use as is. We need the compiler to issue warnings when implicit narrowing occurs (expect in the case of a bit-field). As is, we get thousands of warnings from our code when using "-Wconversion". Consequently, we are forced disable "-Wconversion" to suppress the bit-field warnings at the risk of missing other narrowing warnings. And this is not acceptable to us.

We've already moved back to the 4.2 "gcc".

Best Regards,

Tom Geocaris
Comment 5 Manuel López-Ibáñez 2009-03-10 19:15:49 UTC
(In reply to comment #4)
> 
> The previous version of "gcc" warned when implicit narrowing of doubles to
> integral values, such as
> 
>     double n = 0.0000000005;
>     int d = n;
> 
> when using the "-Wall" option.

AFAIK, that is not true. I just tried your very example with gcc 4.2.4 and it doesn't warn with -Wall -Wextra -Wconversion. g++ did warn but not with -Wall, you still needed to specify -Wconversion, and it did not warn in many cases. So please, check your facts.

> The behavior of "gcc" has changed. Moving all the conversion warnings to fall
> under "-Wconversion" may make semantic sense, but it alters the behavior of
> "gcc". 

Fixing bugs alters behaviour. The change of behaviour was documented beyond what is normally expected.

> We can fault ourselves for missing this change in the documentation, but there
> a level of expectation that the fundamental behavior of the compiler is
> consistent from release-to-release. And when fundamental behavior of "gcc"
> changes, ample notice should be given. People need to change Makefiles, alter
> code (if possible), etc... 

The behaviour of the compiler changes *every* release in many aspects. That is exactly what http://gcc.gnu.org/gcc-X.X/changes.html is for.

> With regard to "-Wtraditional-conversion", it does not work when compiling
> "C++" code.

Of course it doesn't. Have you understood what -Wtraditional-converion (and the old -Wconversion) actually warned for?

> Absolutely not. It's not a portable solution. There is nothing in the "C++"
> standard (that I'm aware of) that suggests that "anding" an integral value with
> a "constant" value results in a truncated integral value. It's a bad hack.
> 

Really? Then I have no ideas. In any case, someone else would need to take care of this because I do not have time. http://gcc.gnu.org/faq.html#support

> If you have ideas on how to solve this, please submit them to the "C" or "C++"
> standards group.

bit-field cast operators?

> We've already moved back to the 4.2 "gcc".

Good that you found a solution. I will leave this open in case someone finds a better solution and decides to submit a patch.
Comment 6 Tom Geocaris 2009-03-10 20:34:22 UTC
Subject: Re:  cannot silence -Wconversion warnings for
	bit-fields


> AFAIK, that is not true. I just tried your very example with gcc 4.2.4 and it
> doesn't warn with -Wall -Wextra -Wconversion. g++ did warn but not with -Wall,
> you still needed to specify -Wconversion, and it did not warn in many cases. So
> please, check your facts.

You are correct in 4.2 you still need the -Wconversion option. We
upgraded from 3.4.6 to 4.2/4.3. In 3.4.6, gcc warned of this error
without any additional options.

> Fixing bugs alters behaviour. The change of behaviour was documented 
> beyond what is normally expected.

You are splitting hairs. I don't see this change as a bug-fix. It's
along the lines to reinterpreting the "C" or "C++" language with regard
to bit-field assignments. The only way "C" or "C++" to assign a integral
variable a bit field is an assignment:

   struct A
   {
      unsigned int v : 2;
   }

   void foo( A * a, int v ) { a->v = v; }

For which "gcc" now issues an warning for, always! And there is no
"language" defined way to eliminate this warning. Outside of writing
something ugly like:

 struct A
 {
    union {
       unsigned int v : 2;
       unsigned int fill;
    };
  };

  void foo( A * a, int v )
  {
    a->fill |= v & 0x3;
  }

And if I have to write this, I might as well not use a bit-field!

Again, gcc 4.3.x now issues thousands of warnings (in our code) for
which we have NO reasonable and portable way to clean the code and NO
way to suppress the warning.

It makes the compiler (for us) not usable.

> Of course it doesn't. Have you understood what -Wtraditional-converion (and the
> old -Wconversion) actually warned for?

I don't care what "-Wconversion" previously did. We never used it, we
did not need to! In 3.4.6 the compiler issued the implicit conversion
warnings without additional options. In 4.2/4.3 you need -Wconversion to
get these warnings. In 4.2.4, "gcc" doesn't warn about bit-fields, but
in 4.3.x it does.

> Really? Then I have no ideas. In any case, someone else would need to 
> take care of this because I do not have time. >
> http://gcc.gnu.org/faq.html#support

I don't understand why this change was made when "C" and the "C++"
language has no support for it... 

Given this has not been been an issue with "C" for over 30 years, there
is probably a reason it is not in the language.


Comment 7 David Faure 2010-01-13 13:40:06 UTC
I agree with Tom, the new behavior of -Wconversion is useless with bitfields, this should be fixed so that we can use -Wconversion again.
Why is this bug on "WAITING"?
Comment 8 Zachary Deretsky 2010-02-18 20:50:00 UTC
With -Wconversion for the assignment to bitfields gcc 4.4.2 gives a
warning, which is impossible to fix.

This BUG (I hope everybody agrees it is a BUG) gives us a lot of
trouble while porting our code (45 developers, 7 year history) from
4.2.4 to 4.4.2

We spent a lot of effort to make our code clean with 
-Wshadow -Wconversion -Wall -Werror flags and now our only choice is
to remove -Wconversion.

Please assign and fix this ASAP.

Thank you, Zach.

Comment 9 Zachary Deretsky 2010-03-06 00:20:08 UTC
I was wrong, the warning is correct and there is a way to fix it.

***1. The easy recipe: For the assignment to bit-fileds use unsigned int bit-field on the left and mask the right side with the appropriate mask.

***2. Explanation given by Alexander Smundak from Cisco:
Actually, the compiler is doing the right thing. Let's simplify it:
--------------
struct data_t {
        int bit:1;
} data;

void foo() {
        data.bit = 1;
}
-----------------
$ gcc.c4.4.0-p0 -fsyntax-only -Wall -Wconversion wbit.cpp
wbit.cpp: In function ‘void foo()’:
wbit.cpp:6: warning: conversion to ‘signed char:1’ alters ‘int’ constant value

`int' is signed, meaning that the highest bit of data.bit is to be extended when moved to a longer integer. Which means that the values for the 1-bit sized integer are 0 and -1. Indeed, if I change the assignment above to 
        data.bit = -1;
the code will compile without warnings. And indeed that's what happens.
Likewise, for the 2-bit bit fields the possible values are
0,1,-1 and -2. Etc.

***3. Here is a little code example to try with g++ -Wconversion b.cpp

-----------------------------------------------------------------
// b.cpp
#define M23 ((1 << 23) - 1)
#define M24 ((1 << 24) - 1)


class xxx {
public:
  xxx():u_24(0), i_24(0) {}
  unsigned int u_24:24;
  int i_24:24;
};

int main(int argc, char** argv) {
  xxx x;
  unsigned int y = 0xffff;
  x.u_24 = M24 & y;
  x.i_24 = M23 & y;
  x.i_24 = M24 & y; // warning: conversion to  int:24  from  int  may alter its value
}
---------------------------------------------------------

Thanks, Zach.
Comment 10 Jeng-Liang Tsai 2010-03-06 01:37:29 UTC
Hi Manuel,

I think it is a good idea to warn about narrowing both from a type to another type, and from a type to a bit-field.  For new codes, one should use the bit-masking technique for bit-field narrowing just as one should use type-casting for general narrowing.

However, with so many lines of legacy code out there using bit-filed that have been proven to work, it doesn't make sense to revisit/modify them.  Would it be possible for gcc to provide a -Wbitfield-conversion flag in new releases and make 39170 an enhancement (preferably high priority)?
Comment 11 Manuel López-Ibáñez 2010-03-06 12:18:43 UTC
(In reply to comment #10)
> However, with so many lines of legacy code out there using bit-filed that have
> been proven to work, it doesn't make sense to revisit/modify them.  Would it be
> possible for gcc to provide a -Wbitfield-conversion flag in new releases and
> make 39170 an enhancement (preferably high priority)?

Seriously, I am not the "maintainer" of GCC diagnostics or even Wconversion. Anyone can contribute!

Yes, it may be possible to provide such an option. I am not against such an option and even if I were I cannot stop you from implementing it and getting it approved by GCC maintainers. I don't know how much work it would be to implement it, and out of kindness I might invest some of my free time to try to do it for GCC 4.6. But even if I might try, that won't happen before summer almost for sure, and then GCC 4.6 won't be available before late next year.
Comment 12 Tom Geocaris 2013-01-04 17:32:22 UTC
Is there any resolution to this issue? We need to move to a more recent version of gcc, but are still stuck at gcc 4.2.4. 

I looked at gcc 4.7.2 but behavior is the same and I don't see an option to suppress these warnings.
Comment 13 Manuel López-Ibáñez 2013-01-04 17:53:00 UTC
(In reply to comment #12)
> Is there any resolution to this issue? We need to move to a more recent version
> of gcc, but are still stuck at gcc 4.2.4. 

I think the best option would be to have a GCC extension for casting bit-field types (int:2) so they can be used to silence false positives. But this may be rejected by the C/C++ FE maintainers, so unless you get their approval, I wouldn't try to pursue it.

The second best option, and probably easier to implement, is to have a new option -Wconversion-bitfields that gives the Wconversion warning for bitfields and use that to control the warning code like:

      if (unsafe_conversion_p (type, expr, true))
	warning_at (loc, TYPE_IS_BITFIELD(type) ? OPT_Wconversion_bitfield : OPT_Wconversion,
		    "conversion to %qT alters %qT constant value",
		    type, expr_type);
      return;

I don't even know if TYPE_IS_BITFIELD exists or there is an equivalent API.

Personally, I have no free time to work on this, so someone else will have to do it. I can give some hints on what you would need to do to implement it if someone is interested and needs guidance.
Comment 14 Eric Gallager 2015-03-06 18:53:18 UTC
(In reply to Jeng-Liang Tsai from comment #10)
> Would it be possible for gcc to provide a -Wbitfield-conversion flag in new
> releases and make 39170 an enhancement (preferably high priority)?

Just an FYI, there's a proposal to add a -Wbitfield-conversion flag that does something slightly different than the behavior described in this issue; for reference, see: https://gcc.gnu.org/ml/gcc-patches/2014-11/msg00723.html
I'd be fine with it doing either the behavior in that patch, or the behavior from this issue...
Comment 15 Manuel López-Ibáñez 2015-03-06 20:10:40 UTC
(In reply to Eric Gallager from comment #14)
> Just an FYI, there's a proposal to add a -Wbitfield-conversion flag that
> does something slightly different than the behavior described in this issue;
> for reference, see: https://gcc.gnu.org/ml/gcc-patches/2014-11/msg00723.html
> I'd be fine with it doing either the behavior in that patch, or the behavior
> from this issue...

I think the two behaviors are orthogonal. People still need an option that refines -Wconversion and allows silencing it for bit-fields. I will prefer if this option is called -Wbitfield-conversion and the other proposal is called something else (-Wbitfield-promotion ? -Wbitfield-shift ?).

But whoever does the implementation work, will decide the name.
Comment 16 Albi 2016-09-15 13:46:34 UTC
Here is a type safe C++ solution:

template<unsigned int N, typename T> union NBitValueUnion
{
        static_assert((sizeof(T)*8) > N, "Strange Bitfield Width");
private:
        const T Data;
public:
        struct
        {
                const T Value : N;
                const T : (sizeof(T)*8-N);
        };
        NBitValueUnion(const T& _Data): Data(_Data) {}
};
template<unsigned int N, typename T> const NBitValueUnion<N, T> NBitValue(const T& _Data)
{ return NBitValueUnion<N, T>(_Data); }
 

Usage:
Bitfield.Member = VariableName; //Triggers -Wconversion
Bitfield.Member = NBitValue<FieldWidth>(VariableName).Value; //Silent.

Unfortnunately it triggers -Waggregate-return (which is a topic for it self since its a type thats fits in a register, so its an aggregate.. but not in hardware.)

Any improvements are welcome.
Comment 17 Florin Iucha 2017-12-21 16:03:53 UTC
Warning if the code 'may alter its value' is one thing.

Can we have GCC at least not warn if it knows it will not alter the value?

For example, compiling

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

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

   foo.bar = value >> 2;

   return foo;
}

This yields:

test.c: In function ‘test’:
test.c:11:14: warning: conversion to ‘unsigned int:30’ from ‘unsigned int’ may alter its value [-Wconversion]
    foo.bar = value >> 2;
              ^

Tested with GCC 5.4.0 and 7.2.
Comment 18 Florin Iucha 2018-01-03 14:46:59 UTC
Even this version creates a warning:

#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;
}
Comment 19 Eric Gallager 2018-04-03 15:01:32 UTC
(In reply to Manuel López-Ibáñez from comment #11)
> (In reply to comment #10)
> > However, with so many lines of legacy code out there using bit-filed that have
> > been proven to work, it doesn't make sense to revisit/modify them.  Would it
> > be possible for gcc to provide a -Wbitfield-conversion flag in new releases
> > and make 39170 an enhancement (preferably high priority)?
> 
> Seriously, I am not the "maintainer" of GCC diagnostics

That's David Malcolm; adding him on cc
Comment 20 Eric Gallager 2018-07-03 01:48:30 UTC
(In reply to Eric Gallager from comment #19)
> (In reply to Manuel López-Ibáñez from comment #11)
> > (In reply to comment #10)
> > > However, with so many lines of legacy code out there using bit-filed that have
> > > been proven to work, it doesn't make sense to revisit/modify them.  Would it
> > > be possible for gcc to provide a -Wbitfield-conversion flag in new releases
> > > and make 39170 an enhancement (preferably high priority)?
> > 
> > Seriously, I am not the "maintainer" of GCC diagnostics
> 
> That's David Malcolm; adding him on cc

...and since he's now made himself the assignee, changing status to ASSIGNED
Comment 21 Eric Gallager 2018-10-03 02:28:42 UTC
Possibly related to bug 87406 which requests adding clang's -Wbitfield-constant-conversion
Comment 22 Eric Gallager 2020-05-20 21:56:30 UTC
*** Bug 95213 has been marked as a duplicate of this bug. ***