Menu

#509 A compound literal in a declaration initializer is never allocated

None
closed-accepted
None
5
6 days ago
6 days ago
No

Against trunk [r16743]. One patch, independent of anything else I have open.

A compound literal is parsed into a temporary symbol marked iscomplit, and gatherImplicitVariables() adds that symbol to the declaration list of the enclosing block. It walks the function body, so it finds the literal in a statement:

struct s v;  v = (struct s) {1, 2, 3};      /* worked */

but not in the initializer of a declaration:

struct s v = (struct s) {1, 2, 3};          /* did not */

There the literal is still in sym->ival — an initializer list, not a tree — and gatherAutoInit() only turns it into a tree later, after gatherImplicitVariables() has run and after allocVariables() has assigned storage. The temporary is therefore never declared and never allocated, so it has no rname:

  • z80 emits the copy's source operand as ld hl, # with an empty symbol, which the assembler rejects — <q> missing or improper operators;
  • a target whose assembler accepts the empty operand assembles it and copies whatever that address holds, without a diagnostic.

&(struct s){...} and char *p = (char[]){...} in a declaration are affected the same way. Assignment-RHS and static locals are not, which is why support/regression/tests/compound-literal.c did not catch it — it covers only those two forms. The patch extends it.

The fix attaches and allocates the temporary in gatherAutoInit(), once the initializer has become a tree.

On where the literal's initializer is placed

It is prepended to the initializer that reads it, not hoisted to the top of the block. Hoisting would be wrong:

char x = 5;
struct s v = (struct s){x, 2, 3};   /* would read x before x = 5 */

gatherAutoInit() already walks declarations in order, so placing it per symbol preserves the ordering. The test covers two literals cross-referencing two earlier locals, and a literal in a nested block, with volatile seeds so constant folding cannot mask a mistake.

Limitations

  • A file-scope compound literal is still rejected with error 2. Unchanged by this patch. The existing test has that case commented out along with its assertion, which I have left as it is.
  • The patch covers compound literals in a declaration initializer. It does not revisit the assignment-RHS or static-local paths, which already worked.

Verification

  • Pre-fix, the extended compound-literal.c does not link on ucz80 and fails 17 of 26 cases on a target whose assembler accepts the empty operand. Post-fix, 0 of 26 on both.
  • Full suite, nine ports — ucz80, mcs51-small, mcs51-large, ds390, stm8, hc08, s08, f8, pdk14 — 287,635 test executions, 0 failures.
  • The test also runs directly under gcc, clang, and s390x gcc via qemu.
1 Attachments

Related

Bugs: #3886
Commit: [r16743]

Discussion

  • Benedikt Freisen

    Very nice. As the author of the compound literal functionality, I felt competent enough to review this one, quickly. (Never found the time to fix it myself, unfortunately)
    Your patch is now in [r16747] with one very minor change: I had to comment out a union-related line in the test case. It is quite possible that one of your patches in [patches:#508] would have taken care of the underlying problem.

     

    Related

    Commit: [r16747]
    Patches: #508

  • Benedikt Freisen

    • status: open --> closed-accepted
    • assigned_to: Benedikt Freisen
    • Group: -->
     

Log in to post a comment.