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