ISO/ IEC JTC1/SC22/WG14 N759


Minor issue with Compound Literals
Clive Feather


There is an ambiguity in the wording of Compound Literals. This paper
explains the issue and proposes new wording to clean it up.


N716 (Compound Literals) states, under Semantics:

| The value of the compound literal is that of an unnamed object
| initialized by the initializer list [...] otherwise, it has automatic
| storage duration associated with the enclosing block.

Consider the situation where a compound literal is evaluated more than once
during the lifetime of its block, such as the second compound literal in
example 8. The wording is unclear whether a new object is created each time
the compound literal is evaluated, or whether a single object is simply
reinitialized. If the former is the case, a burden will be placed on
implementations, which will now have to handle dynamic allocation with
block-related lifetime.

If the address of the object is not taken, there is no way to distinguish
between these two cases, and the as-if rule can be used. However, if the
address is taken, there is a problem.

For example, consider the following:

    struct foo { struct foo *next; int i };

    int f (void)
        int j;
        struct foo *p = NULL, *q;

        for (j = 0; j < 10; j++)
            q = &((struct foo) { .next = p, .i = j }), p = q;

If the first interpretation is taken, it builds up a linked list of
objects. If the second is taken, it is equivalent to:

    struct foo { struct foo *next; int i };

    int f (void)
        int j;
        struct foo *p = NULL, *q;
        struct foo __compound_literal;

        for (j = 0; j < 10; j++)
   = p,   // The order of these
            __compound_literal.i = j,      // two is unspecified
            q = &__compound_literal,
            p = q;

I believe that it is the second interpretation that was intended, but that
the wording should be altered to clarify it.


Add to the semantics (currently after the paragraph beginning
"The value of the compound literal" (currently paragraph 6):

    If a compound literal is re-evaluated while storage for the unnamed
    object created by that literal is still guaranteed to exist, the
    effect is to change the value of the existing object, not to create
    a second unnamed object.

Add a new example:


    Each compound literal creates only a single object in a given scope:

        struct foo { int i; };

        int f (void)
            struct foo *p = 0, *q;
            int j;

            for (j = 0; j < 2; j++)
                q = p, p = &((struct foo){ j });
            return p == q && q.i == 1;

    The function f() always returns the value 1.

    Note that if the body of the for loop were enclosed in braces, the
    lifetime of the unnamed object would be the body of the loop only, and
    on entry next time round p would be pointing to an object which is no
    longer guaranteed to exist, which is undefined behaviour.

==== END ====