Bug 35852 - -Wconversion rejects bitwise negation and assignment, cannot cast around
Summary: -Wconversion rejects bitwise negation and assignment, cannot cast around
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.3.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-04-06 22:54 UTC by David Fang
Modified: 2008-10-23 01:48 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2008-04-18 15:08:04


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description David Fang 2008-04-06 22:54:31 UTC
g++-4.3.0 -ansi -pedantic-errors -std=c++0x -Wall -Wconversion
issues the following diagnostic on the following code:

// test case:
typedef unsigned short  ushort;

enum {
        FOO = 0x13
};

template <typename T>
inline
void
andnot(T& lv, T&& rv) {
        lv &= ~rv;
}

template <typename T>
inline
void
andnot(T& lv, const T& rv) {
        lv &= ~rv;
}

int
main(int, char*[]) {
        ushort x = 99;
        x = ~FOO;
        x &= ~FOO;              // -Wconversion
        x = x & ~FOO;           // -Wconversion
        x = x & ushort(~FOO);   // -Wconversion
        x = x & ushort(~ushort(FOO));   // -Wconversion
        x &= static_cast<ushort>(~FOO);         // -Wconversion
        x &= ~x;
        // andnot(x, FOO);              // no match
        andnot(x, ushort(FOO)); // -Wconversion
        return x;
}
// end test case.

../../../src/conv.cc: In function 'int main(int, char**)':
../../../src/conv.cc:25: warning: conversion to 'ushort' from 'int' may alter its value
../../../src/conv.cc:26: warning: conversion to 'ushort' from 'int' may alter its value
../../../src/conv.cc:27: warning: conversion to 'ushort' from 'int' may alter its value
../../../src/conv.cc:28: warning: conversion to 'ushort' from 'int' may alter its value
../../../src/conv.cc:29: warning: conversion to 'ushort' from 'int' may alter its value
../../../src/conv.cc: In function 'void andnot(T&, T&&) [with T = ushort]':
../../../src/conv.cc:32:   instantiated from here
../../../src/conv.cc:11: warning: conversion to 'short unsigned int' from 'int' may alter its value

All warnings disappear if -Wconversion is omitted.  
I don't understand the rationale why some of the above lines are diagnostic free (assignments), and others trigger the diagnostic, so I cannot claim which are valid w.r.t. -Wconversion.  I did however expect a function-style (ctor-style) cast or static_cast to suppress the diagnostic.  
Is there a bug, or proper "workaround" to locally suppress the diagnostic?

keywords: diagnostic
Comment 1 Manuel López-Ibáñez 2008-04-18 15:08:04 UTC
The C/C++ front-end plays games for bitwise operators, so it may drop the casts but then use the original type or surround the whole operation by a conversion to int. Part of the problem is fixed in mainline. However, other parts remain (PR35701 and PR34389). I don't have time to work on this at the moment but there was an initial attempt was in the thread originated here:

http://gcc.gnu.org/ml/gcc-patches/2008-02/msg00611.html
Comment 2 Manuel López-Ibáñez 2008-08-01 10:08:10 UTC
Could you provide a testcase that does not need -std=c++0x ?

Comment 3 Paolo Carlini 2008-08-01 10:22:21 UTC
If you just comment out the andnot(T&, T&&) overload, and compile without -std=c++0x, I think the warnings at issue are all still there.
Comment 4 Manuel López-Ibáñez 2008-08-01 17:54:09 UTC
To be honest, I am not sure what deserves a warning and what not in this testcase.

FOO is 19, ~FOO is -20. Therefore 
ushort x = ~FOO seems to deserve a warning (with -Wsing-conversion at least).

x = x & -20 is handled as x = (int)x & -20. If x == 0xFFFF, this seems like the case above and probably deserves a warning.

lv = lv & ~rv is seen as:

 <bit_and_expr 
    type <integer_type int public SI
        size <integer_cst constant 32>
        unit size <integer_cst  constant 4>
    arg 0 <nop_expr 0x2aaaab238940 type <integer_type  int>

        arg 0 <indirect_ref  type <integer_type  short unsigned int>
            arg 0 <parm_decl  lv>>>
    arg 1 <bit_not_expr  type <integer_type  int>
        arg 0 <nop_expr  type <integer_type  int>
            arg 0 <indirect_ref  type <integer_type  short unsigned int>
                tree_0 arg 0 <parm_decl  rv>>>>>

That is, we would need to peek inside each operand and recursively check whether the expressions/conversions are safe. I don't know if this is feasible at all and I personally don't know at this moment how to implement it properly.

On the other hand, in mainline, I don't get any warnings for:

        x = x & ushort(~FOO);   // -Wconversion
        x = x & ushort(~ushort(FOO));   // -Wconversion
        x &= static_cast<ushort>(~FOO);         // -Wconversion

So that seems fixed.


Comment 5 Manuel López-Ibáñez 2008-08-22 13:53:33 UTC
This is the current situation as of revision 139373.

typedef unsigned short  ushort;

enum {
        FOO = 0x13
};

template <typename T>
inline
void
andnot(T& lv, const T& rv) {
  lv &= ~rv; // -Wconversion  int(lv) & ~(int(rv))
}

int
main(int, char*[]) {
  ushort x = 99;
  x = ~FOO;               // -Wsign-conversion -20 -> unsigned short
  x &= ~FOO;              // -Wconversion int(x) & ~(int(19)) -> unsigned short
  x = x & ~FOO;           // -Wconversion int(x) & ~(int(19)) -> unsigned short
  x = x & ushort(~FOO);   // no warning
  x = x & ushort(~ushort(FOO));   // no warning
  x &= static_cast<ushort>(~FOO); // no warning
  x &= ~x;                        // no warning
  andnot(x, ushort(FOO)); // instantiated from here
  return x;
}

I don't see what is wrong with the warnings. Would you mind elaborating?
Comment 6 Manuel López-Ibáñez 2008-08-29 03:38:21 UTC
This is waiting for feedback.
Comment 7 David Fang 2008-08-29 04:54:52 UTC
(In reply to comment #5)
> This is the current situation as of revision 139373.
> 
> typedef unsigned short  ushort;
> 
> enum {
>         FOO = 0x13
> };
> 
> template <typename T>
> inline
> void
> andnot(T& lv, const T& rv) {
>   lv &= ~rv; // -Wconversion  int(lv) & ~(int(rv))
> }
> 
> int
> main(int, char*[]) {
>   ushort x = 99;
>   x = ~FOO;               // -Wsign-conversion -20 -> unsigned short
>   x &= ~FOO;              // -Wconversion int(x) & ~(int(19)) -> unsigned short
>   x = x & ~FOO;           // -Wconversion int(x) & ~(int(19)) -> unsigned short
>   x = x & ushort(~FOO);   // no warning
>   x = x & ushort(~ushort(FOO));   // no warning
>   x &= static_cast<ushort>(~FOO); // no warning
>   x &= ~x;                        // no warning
>   andnot(x, ushort(FOO)); // instantiated from here
>   return x;
> }
> 
> I don't see what is wrong with the warnings. Would you mind elaborating?

The situation then seems to have improved since I first reported it.  Originally, none of the cases with explicit casts would pass, but comment #4 suggests that those have been fixed.  I expect the cast-less cases to have warnings.  (I would consider this fixed.)

Comment 8 Manuel López-Ibáñez 2008-10-23 01:48:46 UTC
Marked as FIXED then. Thanks for the report.