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
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
Could you provide a testcase that does not need -std=c++0x ?
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.
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.
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?
This is waiting for feedback.
(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.)
Marked as FIXED then. Thanks for the report.