The code: #include <cstddef> static const char lwb = 0x80; static const char upb = 0x7f; static const size_t cnt = upb - lwb + 1; static const char lwba = 0x80; static const char upba = 0x01; static const size_t cnta = upba - lwba + 1; static const char lwbb = 0xff; static const char upbb = 0x7f; static const size_t cntb = upbb - lwbb + 1; static const char lwbc = 0x00; static const char upbc = 0x7f; static const size_t cntc = upbc - lwbc + 1; int main() { return 0; } gets you: ~/ootbc/common/src$ c++ foo.cc foo.cc:5: warning: integer overflow in expression foo.cc:9: warning: integer overflow in expression foo.cc:13: warning: integer overflow in expression which (as I read the promotion rules) is incorrect. First lwb and upb should be promoted to int, then subtraction is done, and then the addition. This gives no overflow. However, it appears that the subtraction is actually being done in char, not int, because the results actually do overflow 127 on all but the last case. Have the promotion rules changed? Ivan
Turns out that the promotion rules aren't the problem, because you still get the same message even with *explicit* promotion - the code: #include <cstddef> static const char lwb = 0x80; static const char upb = 0x7f; static const size_t cnt = int(upb) - int(lwb) + 1; int main() { return 0; } gets you: ~/ootbc/common/src$ c++ foo.cc foo.cc:5: warning: integer overflow in expression which *has* to be wrong regardless of the promotion rules. Ivan
No the warning is correct as char on a lot of targets is signed by default so promoting (char)0x80 to int will give 0xFFFFFF80.
WADR, but "char" on my (x86 Linux) machine in fact signed. So I tried: #include <cstddef> static const char lwb = 0x80; static const char upb = 0x7f; static const int lwbi = lwb; static const int upbi = upb; static const size_t cnt = upb - lwb; static const size_t cnti = upbi - lwbi; int main() { return 0; } Now I get: ~/ootbc/common/src$ c++ foo.cc foo.cc:7: warning: integer overflow in expression foo.cc:8: warning: integer overflow in expression Surely after I have assigned the chars to ints and done the arithmetic in int there cannot be an overflow, but I'm still getting a warning. And the result of the subtraction is positive on a machine with signed chars, so it can't be the assignment to the size_t. Reopened - please look again. Ivan
static const int lwbi = lwb; lwb = 0x80 lwbi is the signed extended version of lwb to the size of int so you will still get 0xFFFFFF80. So this is still not a bug.
Please: yes, the int value lwbi arising from the conversion of char(0x80) is the int value 0xffffff80, i.e. int(-128); you are quite right about that. That value is being *subtracted* from the int value upbi arising from the conversion of char(0x7f) which is the value 0x0000007f, i.e. 127. If you subtract -128 from 127, i.e (127 - (-128)), the result is 255, a positive number and there is NO overflow. This is signed subtract and it is permitted to subtract a negative from a positive. The result is exact. The result of the subtract is the positive number int(255). That can be converted to size_t (which is unsigned in in this case) also without overflow. Yet there is still a warning message. If the problem here is not clear, please pass this report on to your other colleagues for a second opinion. Thank you. Ivan
Subject: Re: incorrect overflow warning pinskia at gcc dot gnu dot org wrote:- > > ------- Additional Comments From pinskia at gcc dot gnu dot org 2005-02-17 03:14 ------- > No the warning is correct as char on a lot of targets is signed by default so promoting (char)0x80 to int > will give 0xFFFFFF80. This explanation just doesn't make sense. What should get a warning is the assignment of 0x80 to a char. Neil.
(In reply to comment #6) > What should get a warning is the assignment of 0x80 to a char. Not that either, as although the two differ in sign, the value does not exceed the type's precision.
Subject: Re: incorrect overflow warning schlie at comcast dot net wrote:- > > ------- Additional Comments From schlie at comcast dot net 2005-02-17 13:20 ------- > (In reply to comment #6) > > What should get a warning is the assignment of 0x80 to a char. > > Not that either, as although the two differ in sign, the value does not exceed the type's precision. I disagree. Like so: "/tmp/foo.c", line 1: warning: value changes sign during integer type conversion char x = 0x80; ^
(In reply to comment #8) > char x = 0x80; warning: value changes sign during integer type conversion Implying an analogous warning for all assignments between dissimilarly signed variables (i.e. signed x; unsigned y; x = y;) which I believe are considered "compatible"; and half of all unsigned hex constants being assigned to signed types even if cast, as it's arguably the cast which produces the virtual numerical over/underflow. (where although you're numerically correct, seems like a lot of noise?)
Subject: Re: incorrect overflow warning schlie at comcast dot net wrote:- > > ------- Additional Comments From schlie at comcast dot net 2005-02-17 14:33 ------- > (In reply to comment #8) > > char x = 0x80; warning: value changes sign during integer type conversion > > Implying an analogous warning for all assignments between dissimilarly > signed variables (i.e. signed x; unsigned y; x = y;) which I believe are > considered "compatible"; and half of all unsigned hex constants being > assigned to signed types even if cast, as it's arguably the cast which > produces the virtual numerical over/underflow. > > (where although you're numerically correct, seems like a lot of noise?) Well it's certainly a matter of taste. char is arguably a special case as you cannot assign a value with the high bit set without creating the warning on some targets. But if you are assigning values with the high bit set then arguably you have in mind whether you are dealing with signed or unsigned values and should be explicit about signedness. As such like any warning it tends to expose sloppy thinking. Your x=y example is of course not the same; whether a value is changing sign or not is not knowable at compile time and probably rarely the case, so I agree complaining about that would be annoying. Some people have in the past requested command-line switches to generate warnings for any implicit integer conversion. I agree a singed <-> unsigned should not be on by default, though potentially narrowing conversions are debatably more appropriate to have on by default. Neil.
I don't get the warning with current mainline (revision 119143). Still, I would like to keep this bug around since it may be interesting that Wconversion emits a warning for the int->char conversion. I would like to hear some opinions about this. My current patch does the following: manuel@gcc05:~$ local/bin/g++ -fsigned-char pr20019.cpp manuel@gcc05:~$ local/bin/g++ -fno-signed-char pr20019.cpp manuel@gcc05:~$ local/bin/g++ -fno-signed-char -Wconversion pr20019.cpp pr20019.cpp:9: warning: negative integer implicitly converted to unsigned type pr20019.cpp:13: warning: negative integer implicitly converted to unsigned type manuel@gcc05:~$ local/bin/g++ -fsigned-char -Wconversion pr20019.cpp pr20019.cpp:3: warning: conversion to ‘char’ alters ‘int’ constant value pr20019.cpp:7: warning: conversion to ‘char’ alters ‘int’ constant value pr20019.cpp:11: warning: conversion to ‘char’ alters ‘int’ constant value Does this seem correct to all of you?
There is no warning with GCC 4.3 and you can get a warning for the int->char conversion by using -Wconversion. So I am going to close this. Please, feel free to reopen if you think there is some unresolved issue.