[cfe-dev] Integer promotions in C-style cast expressions?

Enea Zaffanella zaffanella at cs.unipr.it
Wed Aug 12 23:38:35 PDT 2009


Hello.

We have a question related to ImplicitCastExpr nodes.
Consider the following program:

void* foo(char c) {
   return (void*) c;
}

When fed to clang, we obtain the following AST:

void *foo(char c) (CompoundStmt 0x2a0bb90 <bug.c:1:19, line:3:1>
   (ReturnStmt 0x2a0de10 <line:2:3, col:18>
     (CStyleCastExpr 0x2a0c8c0 <col:10, col:18> 'void *'
       (ImplicitCastExpr 0x2a094b0 <col:18> 'int'
         (DeclRefExpr 0x2a09470 <col:18> 'char' ParmVar='c' 0x2a0dd70)))))

Namely, the use of the char 'c' is first implicitly converted to 'int' 
and then immediately cast to 'void*'. We guess that the ImplicitCastExpr 
node was added to model the integer promotion of the c-style cast operator.

However, according to our understanding of the C99 standard, the 
operator of a C-style cast expression is not subject to promotions.

Footnote 48 to C99 6.3.1.1p2 (page 43) says:
===
The integer promotions are applied only: as part of the usual arithmetic 
conversions, to certain argument expressions, to the operands of the 
unary +, -, and ~ operators, and to both operands of the shift 
operators, as specified by their respective subclauses.
===

Note the word "only".
It is clear that the use above does not occur in a (function call) 
argument expression. Moreover, it is not an usual arithmetic conversion, 
because for these it is said (see C99 6.3.1.8):
===
The purpose is to determine a common real type for the operands and result.
===
which clearly does not fit the case of a cast expression. (Also, in the 
example at hand one may argue that casting to a pointer type is not an 
arithmetic operation at all).

Also note that the standard never mentions promotions or the usual 
arithmetic conversions when discussing casts (see C99 6.5.4), whereas 
they are explicitly mentioned when discussing other operators (e.g., the 
additive, multiplicative, relational operators or the unary arithmetic 
operators). In particular, promotions are not mentioned for and should 
not occur on the operator of sizeof (this is unrelated to C99 6.3.2.1, 
which only deals with array/function type decays).


Besides being "forbidden" by the C99 standard as argued above, these 
implicit casts may complicate semantic analysis.

For instance, when fed to gcc on an architecture where 'void*' and 'int' 
have the same size, the program above produces the following (useful and 
hence appreciated) diagnostic:

[zaffanella at charlie eclair]$ gcc -c bug.c
bug.c: In function ‘foo’:
bug.c:2: warning: cast to pointer from integer of different size

A similar diagnostic would be more difficult to obtain using clang, 
since one should first check if the ImplicitCastExpr node was unneeded 
and then skip it.


The following example shows that promotions inside c-style casts can 
also make the AST uselessly involved:

unsigned long p(signed char a, unsigned char b) {
   return a + (unsigned char) b;
}

This is parser by clang as follows:

unsigned long p(signed char a, unsigned char b) (CompoundStmt 0x3342b90 
<bug.c:5:49, line:7:1>
   (ReturnStmt 0x3343bc0 <line:6:3, col:30>
     (ImplicitCastExpr 0x3343b80 <col:10, col:30> 'unsigned long'
       (BinaryOperator 0x3343b40 <col:10, col:30> 'int' '+'
         (ImplicitCastExpr 0x3343ac0 <col:10> 'int'
           (DeclRefExpr 0x33439c0 <col:10> 'signed char' ParmVar='a' 
0x3343ec0))
         (ImplicitCastExpr 0x3343b00 <col:14, col:30> 'int'
           (CStyleCastExpr 0x3343a80 <col:14, col:30> 'unsigned char'
             (ImplicitCastExpr 0x3343a40 <col:30> 'int'
               (DeclRefExpr 0x3343a00 <col:30> 'unsigned char' 
ParmVar='b' 0x33438d0))))))))


We had a look to the clang sources and we identified the point (in 
lib/Sema/SemaExpr.cpp) where these unwanted promotions are generated:

/// CheckCastTypes - Check type constraints for casting between types.
bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr 
*&castExpr,
                           bool FunctionalStyle) {
   if (getLangOptions().CPlusPlus)
     return CXXCheckCStyleCast(TyR, castType, castExpr, FunctionalStyle);

   UsualUnaryConversions(castExpr);  <========== HERE.


Function UsualUnaryConversions mixes array/function decays and integral 
promotions. In our opinion, operands of explicit casts should be subject 
to type decay, but not to promotions.

Cheers,
Enea Zaffanella.



More information about the cfe-dev mailing list