Model of constant expressions in GNU C ====================================== This model derives from the models of constant expressions in C90 and C99 to describe how to determine whether an expression in GNU C is a constant expression, and what types of constant expression it is. It uses the notation from those models. Nothing in this model depends on the settings of pedantic or flag_iso. The extensions either involve other GNU extensions to C, or, where only standard syntax is involved, only extend constant expressions in initializers, where it is unambiguous that such extensions are permitted by the ISO standards. Except as stated here, the attributes are set as detailed in the underlying C90 or C99 model, depending on the standard version selected. The use of C99 features as an extension in C90 modes is handled thus. arith_bad_cast and arith_const_ok are always set as described for C99; this has no effect on programs without VLAs. VLAs (in sizeof, casts and pointer addition) are handled as described for C99. Compound literals are handled as described for C99. GNU C also permits VLAs in structures. This extension may be deprecated. Such structures are generally treated as VLAs. The results of offsetof applied to such structures are unspecified. The following in general terms are the GNU extensions to constant expressions; a formal model follows. (a) Integer constant expressions cast to pointer types are accepted as address constants regardless of the standard version selected. (b) Addresses of functions plus or minus constants are accepted as address constants. (c) Addresses of labels, and such addresses plus or minus constants, are accepted as address constants. (d) Address constants may be cast to and from integer types of the same width as pointers, the resulting integers also counting as address constants. (e) The difference between two address constants based on the same object or function address, and any expression made of such values and integer constant expressions, is a symbolic difference constant expression, which can be used in initializers, and in address constants where they permit integer constant expressions to be used. offsetof expressions containing integer constant expressions only as array indices count as integer constant expressions; if they also contain symbolic difference constant expressions, the offsetof expression counts as such an expression; if they contain any other form of expression, they do not count as constant. (f) The difference between two address constants each of which evaluates to the address of a label is a label difference constant expression; these are valid as initializers but variants such as label differences plus integer constant expressions are not. (g) Built-in functions starting __builtin_ may be used in certain circumstances in constant expressions: if the compiler can fold them to an integer constant, floating constant or address constant then they are treated as an integer constant expression, arithmetic constant expression or address constant, respectively. The exact circumstances in which they are folded are unspecified, may depend on optimisation levels and are subject to change. However, certain specific cases are defined: __builtin_types_compatible_p is considered an integer constant; __builtin_choose_expr's value is always considered exactly like the chosen alternative; the __builtin_huge_val* and __builtin_inf* functions are considered to return arithmetic constant expressions, as are the __builtin_nan* functions if passed a string constant argument (possibly with extra parentheses). (h) If __builtin_constant_p is evaluated at parse time, which it always will be in static initializers but may not be otherwise, and it is the controlling expression of a conditional expression, then that expression is treated exactly like the chosen alternative. The following boolean attributes are used to model these extensions. sym_diff_operands All operands are those permitted for integer constant expressions or symbolic differences. sym_diff_const_expr The expression is a symbolic difference constant expression. lab_diff_const_expr The expression is a label difference constant expression. bcp_call The expression is a call to __builtin_constant_p. These are merged thus: E.sym_diff_operands := A.sym_diff_operands && B.sym_diff_operands E.lab_diff_const_expr := false E.bcp_call := false sym_diff_const_expr is always computed thus: sym_diff_const_expr := (of integer type) && sym_diff_operands && !bad_operator && !overflow The model - standard syntax =========================== The following are applied in addition to the rules listed in the models for C90 and C99, as applicable. Implicit conversions of operands to a common type, in initialization, and otherwise, are treated as if they were explicit casts. (This is irrelevant to the standard models, but avoids problems here with implicit conversions of integer address constants to wider types.) Whenever int_operands is explicitly set by the standard model, sym_diff_operands is set to the same value unless explicitly stated otherwise below. lab_diff_const_expr is set to false unless explicitly stated below. bcp_call is set to false unless explicitly stated below. Where in the standard models overflow is set conditional on arith_const_expr flags, either arith_const_expr or sym_diff_const_expr suffices to set overflow in this model. (Other tests of arith_const_expr remain as in the standard models.) Operations on complex integers overflow if the calculation using the usual formulas overflows, including intermediate computations. That is, (a+ib)*(c+id) overflows if any of (a*c) or (b*d) or (a*c-b*d) or (a*d) or (b*c) or (a*d+b*c) overflow, and (a+ib)/(c+id) overflows if any of (a*c) or (b*d) or (a*c+b*d) or (b*c) or (a*d) or (b*c-a*d) or (c*c) or (d*d) or (c*c+d*d) overflow, or the denominator is zero. At present this also applies to complex floating point numbers; GCC wrongly always acts as if the CX_LIMITED_RANGE pragma is in effect. Complex integer and floating point constants are treated the same as real constants. E : offsetof(T, M) E.int_operands := M.int_operands E.sym_diff_operands := M.sym_diff_operands If T is a structure containing a VLA (or, recursively, containing such a structure), the attributes are unspecified. E : ( E1 ) All attributes including the new ones are copied from E1. E : + E1 E.addr_const_expr := E1.addr_const_expr (I.e., unary + may be applied to address constant expressions of integer type.) E : E1 [ E2 ] E.has_const_addr := E1.addr_const_expr && E2.sym_diff_const_expr E : __builtin_something (optional list E2, E3, ...) If this is not folded to a constant, as in standard models. If this is folded to an integer constant (__builtin_types_compatible_p always is), floating constant or address constant, as for integer constants, floating constants and identifiers for objects of static storage duration respectively, except E.float_constant := false E : __builtin_choose_expr (E1, E2, E3) E.attrs := (E2 or E3, as applicable).attrs (all attributes copied). E : __builtin_constant_p ( E1 ) If not folded at parse time, as for ordinary function calls. If folded at parse time, as for integer constants except E.bcp_call := true E : ( T ) E1 E.addr_const_expr := (E1.sym_diff_const_expr || E1.addr_const_expr) && (type is a pointer type || type is a real integer type of same width as pointers) E : E1 + E2 E : E1 - E2 E.addr_const_expr := (E1.addr_const_expr && (E1 does not point to a variable-length type) && E2.sym_diff_const_expr && (E2 has real integer type)) || (E2.addr_const_expr && (E2 does not point to a variable-length type) && E1.sym_diff_const_expr && (operation is addition) && (E1 has real integer type)) In the case of E1 - E2, if E1.addr_const_expr and E2.addr_const_expr and both E1 and E2 evaluate to addresses of labels, then: E.lab_diff_const_expr := true In the case of E1 - E2, if E1.addr_const_expr and E2.addr_const_expr and both E1 and E2 evaluate to addresses based on the address of the same object, function or label, then: E.sym_diff_operands := true E : E1 ? E2 : E3 Unless E1.bcp_call, as in standard models. If E1.bcp_call, then E.attrs := (E2 or E3, as applicable).attrs (copying all attributes) The model - new syntax ====================== The following are applied to new syntax of GNU C. The attributes of type names are derived from expressions appearing in typeof expressions as well as those appearing as array dimensions in declarators. The operand of a typeof expression is evaluated if and only if it is of or names a variably modified type. If the operand is not evaluated, expressions in the operand are not included in the merge of attributes. If it is evaluated, the operand (if an expression) or expressions within it (recursively) (if it is a type) are included in the expressions of which attributes are merged. Statement expressions: E : (compound-statement) E.bad_operator := true E.overflow := false E.int_operands := false E.sym_diff_operands := false E.arith_operands := false E.float_constant := false E.arith_bad_cast := false E.arith_const_ok := false E.has_const_addr := false E.addr_const_expr := false E.lab_diff_const_expr := false E.bcp_call := false Addresses of labels: E : &&label E.bad_operator := false E.overflow := false E.int_operands := false E.sym_diff_operands := false E.arith_operands := false E.float_constant := false E.arith_bad_cast := false E.arith_const_ok := false E.has_const_addr := false E.addr_const_expr := true E.lab_diff_const_expr := false E.bcp_call := false Conditionals with omitted operands: E : E1 ? : E2 Treated exactly as E1 ? E1 : E2. __extension__: E : __extension__ E1 Treated exactly as E1. Alignment: E : __alignof__ E1 E : __alignof__ ( T ) Treated exactly as integer constants (even for VLA types). Real and imaginary parts: E : __real__ E1 E : __imag__ E1 E.attrs := E1.attrs E.float_constant := false E.has_const_addr := false E.addr_const_expr := false E.lab_diff_const_expr := false E.bcp_call := false