This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: [bool wrapping] Request for warnings on implicit bool to int conversions
On Tue, 27 Mar 2012 19:20:52 -0700, Russ Allbery wrote:
> (For example, b++ could easily wrap, and unexpectedly fast
> depending on the size of bool on a platform.)
Actually, it would appear that a bool (or a _Bool) can't wrap
on increment, but it CAN wrap on decrement (and strangely,
when the operand is a bool, C++ not only deprecates the prefix
and postfix `++' operators, but also forbids the prefix and
postfix `--' operators; this is particularly strange given
that similar semantics are still to be had with the `+='
and `-=' compound assignments).
I'm going to deal with the prefix operators rather than the
postfix operators, in order to concentrate on the value that
is newly assigned to the variable in question.
Firstly, the C++ standard is very explicit and concise.
According to C++11.5.3.2 "Increment and decrement":
1 The operand of prefix ++ is modified by adding 1, or set to
true if it is bool (this use is deprecated). The operand
shall be a modifiable lvalue. The type of the operand shall
be an arithmetic type or a pointer to a completely-defined
object type. The result is the updated operand; it is an
lvalue, and it is a bit-field if the operand is a bit-field.
If x is not of type bool, the expression ++x is equivalent
to x+=1...
2 The operand of prefix -- is modified by subtracting 1. The
operand shall not be of type bool. The requirements on the
operand of prefix -- and the properties of its result are
otherwise the same as those of prefix ++...
As for C99, indulge me for a moment.
According to C99.6.5.3.1 "Prefix increment and decrement operators":
...
2 The value of the operand of the prefix ++ operator is
incremented. The result is the new value of the operand after
incrementation. The expression ++E is equivalent to (E+=1).
See the discussions of additive operators and compound
assignment for information on constraints, types, side
effects, and conversions and the effects of operations on
pointers.
...
and according to C99.6.5.16.2 "Compound Assignment":
...
3 A compound assignment of the form E1 op= E2 differs from the
simple assignment expression E1 = E1 op (E2) only in that the
lvalue E1 is evaluated only once.
and according to C99.6.5.6 "Additive operators":
...
2 For addition, either both operands shall have arithmetic
type, or one operand shall be a pointer to an object type
and the other shall have integer type. (Incrementing is
equivalent to adding 1.)
...
4 If both operands have arithmetic type, the usual arithmetic
conversions are performed on them.
5 The result of the binary + operator is the sum of the
operands.
...
and according to C99.6.2.5 "Types":
...
6 ... The type _Bool and the unsigned integer types that correspond
to the standard signed integer types are the standard unsigned
integer types... The standard and extended unsigned integer types
are collectively called unsigned integer types.
...
17 The type char, the signed and unsigned integer types, and the
enumerated types are collectively called integer types...
18 Integer and floating types are collectively called arithmetic
types.
...
and according to C99.6.3.1.8 "Usual arithmetic conversions":
1 ...
Otherwise, the integer promotions are performed on both
operands. Then the following rules are applied to the
promoted operands:
If both operands have the same type, then no further
conversion is needed.
...
...
...
and according to C99.6.3.1.1 "Boolean, characters, and integers"
2 ... If an int can represent all values of the original
type, the value is converted to an int; otherwise, it is
converted to an unsigned int. These are called the integer
promotions...
and according to C99.6.3.1.2 "Boolean type":
1 When any scalar value is converted to _Bool,
the result is 0 if the value compares equal
to 0; otherwise, the result is 1.
and according to C99.7.16 "Boolean type and values <stdbool.h>":
1 The header <stdbool.h> defines four macros.
2 The macro
bool
expands to _Bool.
...
So, the prefix `++' operator expression in the following:
bool b = 1;
++b;
should assign to `b' the value of the following expression:
(bool)((int)b + (int)1)
(bool)((int)1 + (int)1)
(bool)2
1
That is, the value of `b' should remain `1', which is corroborated
when the following program:
#include <stdbool.h>
int main(void)
{
bool b = 1;
for (;;) ++b;
}
is compiled with:
gcc -std=c99 -pedantic -Wall -O0 -fdump-tree-gimple d.c
thereby yield the following GIMPLE representation:
main ()
{
int D.1090;
{
_Bool b;
b = 1;
<D.1088>:
b = 1;
goto <D.1088>;
}
D.1090 = 0;
return D.1090;
}
As you can see, the loop simply keeps assigning to `b' the value `1':
<D.1088>:
b = 1;
goto <D.1088>;
As for decrementing a _Bool, according to C99.6.5.3.1
"Prefix increment and decrement operators":
The prefix -- operator is analogous to the prefix ++
operator, except that the value of the operand is
decremented.
So, the prefix `--' operator expression in the following:
#include <stdbool.h>
bool b = 0;
--b;
should assign to `b' the value of the following expression:
(bool)((int)b - (int)1)
(bool)((int)0 - (int)1)
(bool)-1
1
That is, the value of `b' can wrap on decrement, which is
corroborated when the following program:
#include <stdbool.h>
int main(void)
{
bool b = 0;
for (;;) --b;
}
is compiled with:
gcc -std=c99 -pedantic -Wall -O0 -fdump-tree-gimple d.c
thereby yield the following GIMPLE representation:
main ()
{
int D.1090;
{
_Bool b;
b = 0;
<D.1088>:
b = !b;
goto <D.1088>;
}
D.1090 = 0;
return D.1090;
}
As you can see, the loop simply keeps assigning to `b' the logical
negation of `b':
<D.1088>:
b = !b;
goto <D.1088>;
Similar arguments can be made for `b+=1' and `b-=1' (even for C++);
however, the GIMPLE representation is sometimes not as optimized:
For `b+=1' (and similarly for `b-=1'), gcc produces the following
more general computation:
<D.1088>:
D.1090 = (int) b;
D.1091 = D.1090 + 1;
b = D.1091 != 0;
goto <D.1088>;
Also, while g++ does the simple logical negation for `b-=1', it
instead forgos a simple assignment of `1' in favor of the following
bizarre gymnastics for `b+=1':
<D.983>:
D.984 = (int) b;
b = D.984 != -1;
goto <D.983>;
Maybe there's room for a patch?
Anyway, I'm done with my mental pleasuring for the day.
Ta ta!
Michael Witten