SC22/WG14 N782 Cleanup of aggregate initialization Clive D.W. Feather clive@demon.net 1997-10-20 Abstract ======== The compound literals proposal - N716 - innocently introduces an inconsistency in aggregate initialization. No-one has given a rationale for it, and this paper proposes that it be removed. Following discussion at Menlo Park, other areas needing change to bring them into line have been noted. These are the compound literals section itself and the IEC 559 floating-point arithmetic annex. Discussion ========== Consider the following code: struct s { int a; int b; }; int x = 1, y = 2; struct s sx; int main (void) { sx.a = 3; sx.b = 4; { int z = x; // Valid struct s s1 = sx; // Valid struct s s2 = (struct s) { x, y }; // Valid struct s s3 = { x, y }; // Forbidden /* ... */ } } There is no semantic difference between the declarations of s2 and s3, yet the latter is forbidden by 6.5.7 paragraph 4: All the expressions in an initializer for an object that has static storage duration or in an initializer list for an object that has aggregate or union type shall be constant expressions. It has been suggested that the original constraint was to allow for implementations where the dynamic initializer would have been a burden. Since such implementations now have to cope with compound literals and the declaration of s2, the restriction has outlived its usefulness. Proposal ======== [References are to draft 11 pre 3.] Change 6.3.2.6 paragraph 7 from: Except that the initializers need not be constant expressions (when the unnamed object has automatic storage duration), all the semantic rules and constraints for initializer lists in 6.5.7 are applicable to compound literals.[71] The order in which any side effects occur among the initialization list expressions is unspecified.[72] to: | All the semantic rules and constraints for initializer lists in 6.5.8 | are applicable to compound literals.[71] Delete footnote 72. Change 6.5.8 paragraph 4 from: All the expressions in an initializer for an object that has static storage duration or in an initializer list for an object that has aggregate or union type shall be constant expressions. to: All the expressions in an initializer for an object that has | static storage duration shall be constant expressions. Add a new paragraph to the end of subclause 6.5.8: | The order in which any side effects occur among the initialization | list expressions is unspecified.[*] | [*] In particular, the evaluation order need not be the same as the | order of subobject initialization. Change F.7.4 paragraph 1 from: An arithmetic constant expression of floating type, other than one in an initializer for an object that has static storage duration or in an initializer list for an object that has aggregate or union type, is evaluated (as if) during execution. As execution-time evaluation, it is affected by any operative modes and raises exceptions as required by IEC 559 (provided the state for the FENV_ACCESS pragma is on).[283] to: An arithmetic constant expression of floating type, other than one in | an initializer for an object that has static storage duration, is evaluated (as if) during execution. As execution-time evaluation, it is affected by any operative modes and raises exceptions as required by IEC 559 (provided the state for the FENV_ACCESS pragma is on).[283] In the example, change: float w[] = { 0.0/0.0 }; /* does not raise an exception */ to: float w[] = { 0.0/0.0 }; /* raises an exception */ and change the text paragraph from: For the aggregate and static initializations, the division is done at translation time, raising no (execution-time) exceptions. On the other hand, for the two automatic scalar initializations the invalid division occurs at execution time. to: | For the static initialization, the division is done at translation time, raising no (execution-time) exceptions. On the | other hand, for the three automatic initializations the invalid division occurs at execution time. Change F.7.5 paragraph 1 from: All computation for automatic scalar initialization is done (as if) at execution time. As execution-time evaluation, it is affected by any operative modes and raises exceptions as required by IEC 559 (provided the state for the FENV_ACCESS pragma is on). All computation for initialization of objects that have static storage duration or that have aggregate or union type is done (as if) at translation time. to: | All computation for automatic initialization is done (as if) at execution time. As execution-time evaluation, it is affected by any operative modes and raises exceptions as required by IEC 559 (provided the state for the FENV_ACCESS pragma is on). All computation for initialization of objects that have static storage | duration is done (as if) at translation time. In the example, change: float u[] = { 1.1e75 }; /* does not raise exceptions */ to: float u[] = { 1.1e75 }; /* raises exceptions */ and change the text paragraph from: The aggregate and static initializations of u and v raise no (execution-time) exceptions because their computation is done at translation time. The automatic initialization of w requires an execution-time conversion to float of the wider value 1.1e75, which raises exceptions. The automatic initializations of x and y entail execution-time conversion; however, in some expression evaluation methods, the conversions is not to a narrower format, in which case no exception is raised.[284] The automatic initialization of z entails execution-time conversion, but not to a narrower format, so no exception is raised. Note that the conversions of the floating constants 1.1e75 and 1.1e75f to their internal representations occur at translation time in all cases. to: | The static initialization of v raises no | (execution-time) exception because its computation is done at | translation time. The automatic initializations of u and w require an execution-time conversion to float of the wider value 1.1e75, which raises exceptions. The automatic initializations of x and y entail execution-time conversion; however, in some expression evaluation methods, the conversions is not to a narrower format, in which case no exception is raised.[284] The automatic initialization of z entails execution-time conversion, but not to a narrower format, so no exception is raised. Note that the conversions of the floating constants 1.1e75 and 1.1e75f to their internal representations occur at translation time in all cases.