Given, 1 volatile int jv; 2 3 int main () 4 { 5 ++jv; 6 }
GCC (development branch, 4.0 and up) creates a tree node for the expression ++jv that has 'volatile' asserted in the type associated with the expression: <preincrement_expr 0x4026a144 type <integer_type 0x402f2e04 int volatile public SI size <integer_cst 0x402633f0 constant invariant 32> unit size <integer_cst 0x40263180 constant invariant 4> align 32 symtab 0 alias set -1 precision 32 min <integer_cst 0x402633a8 -2147483648> max <integer_cst 0x402633c0 2147483647>> side-effects arg 0 <var_decl 0x4026f0b0 jv type <integer_type 0x402f2e04 int> side-effects volatile used public static common SI defer-output file a.c line 1 size <integer_cst 0x402633f0 32> unit size <integer_cst 0x40263180 4> align 32> arg 1 <integer_cst 0x402fbee8 type <integer_type 0x402f2e04 int> constant invariant 1>> Further, 'volatile' is asserted in the type associated with the integral constant 1, above: (gdb) pt <integer_cst 0x402fbee8 type <integer_type 0x402f2e04 int> constant invariant 1> (gdb) p 0x402f2e04 $19 = 1076833796 (gdb) pt <integer_type 0x402f2e04 int volatile public SI size <integer_cst 0x402633f0 type <integer_type 0x4027205c bit_size_type> constant invariant 32> unit size <integer_cst 0x40263180 type <integer_type 0x40272000 unsigned int> constant invariant 4> align 32 symtab 0 alias set -1 precision 32 min <integer_cst 0x402633a8 -2147483648> max <integer_cst 0x402633c0 2147483647>> We could argue whether this causes any real harm, because the ISO C spec. says the following: === 6.7.3: The properties associated with qualified types are meaningful only for expressions that are lvalues. 6.5.16: The type of an assignment expression is the type of the left operand unless the left operand has qualified type, in which case it is the unqualified version of the type of the left operand. ==== And hopefully subsequent passes in the compiler won't be confused by seeing qualifiers asserted in expression nodes and in constants. IMO it would be better if the original tree constructed from the parsed program more closely followed the original source code, and where possible, removed extraneous qualifiers, unless they absolutely needed to convey correct semantics. Above, the qualifiers on expression nodes and constants seem to come about by a call to convert() from build_unary_op()which works its way through to this statement in fold_convert(): if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig) || lang_hooks.types_compatible_p (TYPE_MAIN_VARIANT (type), TYPE_MAIN_VARIANT (orig))) return fold_build1 (NOP_EXPR, type, arg); because the main variant types of the qualified "volatile int" and unqualified "int" are the same, convert() ends up recasting 'arg' into a qualified (volatile int) type. I don't know if there are other cases besides pre-/post- increment that have this problem. I think it is also possible that the code in the development head branch does a better job of generating expression nodes that have their qualifiers stripped than 4.0 did for example. Perhaps one way to gain some confidence that all possibilities have been covered is to add assertions in build_binary_op and build_unary_op (or build1 and build2 for that matter, for expression class nodes) that checks that TYPE_QUALS(t) == TYPE_UNQUALIFIED on expression nodes and constant nodes (though perhaps TYPE_CONST is meaninful for certain named constants?).