From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18254 invoked by alias); 28 Mar 2012 19:32:18 -0000 Received: (qmail 18245 invoked by uid 22791); 28 Mar 2012 19:32:16 -0000 X-SWARE-Spam-Status: No, hits=-2.7 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW X-Spam-Check-By: sourceware.org Received: from mail-pb0-f47.google.com (HELO mail-pb0-f47.google.com) (209.85.160.47) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 28 Mar 2012 19:32:02 +0000 Received: by pbcum15 with SMTP id um15so2207528pbc.20 for ; Wed, 28 Mar 2012 12:32:02 -0700 (PDT) Received: by 10.68.201.98 with SMTP id jz2mr74040536pbc.97.1332963122075; Wed, 28 Mar 2012 12:32:02 -0700 (PDT) Received: from gmail.com ([79.172.193.89]) by mx.google.com with ESMTPS id f10sm3258929pbt.75.2012.03.28.12.31.58 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 28 Mar 2012 12:32:00 -0700 (PDT) Subject: Re: [bool wrapping] Request for warnings on implicit bool to int conversions Date: Wed, 28 Mar 2012 19:32:00 -0000 From: Michael Witten To: Russ Allbery Cc: Gabriel Dos Reis , Paolo Carlini , David Mathog , gcc@gcc.gnu.org Message-ID: In-Reply-To: <87398tea9n.fsf@windlord.stanford.edu> References: <97d1c137f40ae4bd6c6f89bfdbdd02ce@saf.bio.caltech.edu> <4F7261EE.4060409@oracle.com> <87398tea9n.fsf@windlord.stanford.edu> X-IsSubscribed: yes Mailing-List: contact gcc-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-owner@gcc.gnu.org X-SW-Source: 2012-03/txt/msg00443.txt.bz2 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 ": 1 The header 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 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; : b = 1; goto ; } D.1090 = 0; return D.1090; } As you can see, the loop simply keeps assigning to `b' the value `1': : b = 1; goto ; 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 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 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; : b = !b; goto ; } D.1090 = 0; return D.1090; } As you can see, the loop simply keeps assigning to `b' the logical negation of `b': : b = !b; goto ; 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.1090 = (int) b; D.1091 = D.1090 + 1; b = D.1091 != 0; goto ; 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.984 = (int) b; b = D.984 != -1; goto ; Maybe there's room for a patch? Anyway, I'm done with my mental pleasuring for the day. Ta ta! Michael Witten