AST for C++11 brace initialization includes CompoundLiteralExpr?

Hi, Richard, Doug, et al. Somebody internally came up with a C++11 example that generates a strange AST:

struct Point {
Point(int x, int y);
};

void use(Point);

void test() {
use((Point){1, 2});
}

-FunctionDecl 0x7fa6410604b0 <line:7:1, line:9:1> test 'void (void)' -CompoundStmt 0x7fa641060d00 <line:7:13, line:9:1>
`-CallExpr 0x7fa641060c30 <line:8:2, col:19> ‘void’

-ImplicitCastExpr 0x7fa641060c18 col:2 ‘void (*)(struct Point)’
-DeclRefExpr 0x7fa641060bc8 <col:2> 'void (struct Point)' lvalue Function 0x7fa6410603b0 'use' 'void (struct Point)' -CXXConstructExpr 0x7fa641060cc8 col:6 ‘struct Point’ ‘void (struct Point &&) noexcept’ elidable
-MaterializeTemporaryExpr 0x7fa641060c60 <col:6, <invalid sloc>> 'struct Point' xvalue **-CompoundLiteralExpr 0x7fa641060ba0 <col:6, > ‘struct Point’**
**-CXXTemporaryObjectExpr 0x7fa641060a00 <col:6, <invalid sloc>> 'struct Point' 'void (int, int)'** -IntegerLiteral 0x7fa6410605b8 <col:14> 'int' 1 -IntegerLiteral 0x7fa6410605d8 col:17 ‘int’ 2

Notice the CXXTemporaryObjectExpr inside the CompoundLiteralExpr. Normally a CompoundLiteralExpr is used to initialize aggregates, and so its child is an InitListExpr. Here, though, the object is being initialized via a constructor, and so it’s not really a compound literal at all, even though it looks like one. I can hack around this in the analyzer, but honestly I don’t think we be forming a CompoundLiteralExpr at all. What do you think?

Jordan

It actually is a compound literal, because this isn’t syntax that would be accepted by pure C++11. So, it should be described as a CompoundLiteralExpr in the AST. We could clean up the AST for CompoundLiteralExpr to directly describe constructor calls, but this representation doesn’t seem wrong per se.

  • Doug

Well, that’s weird. Okay, thanks for the explanation.
Jordan

How about this one? Is the inner init list really creating a Point which is then copied by the CompoundLiteralExpr?

struct Point {
int x, y;
~Point();
};

void test() {
((Point){1,2});
}

-FunctionDecl 0x7f9558860720 <line:6:1, line:8:1> test 'void (void)' -CompoundStmt 0x7f9558860990 <line:6:13, line:8:1>
-ExprWithCleanups 0x7f9558860978 <line:7:2, col:15> 'struct Point' -ParenExpr 0x7f9558860958 <col:2, col:15> ‘struct Point’
**-CXXBindTemporaryExpr 0x7f9558860938 <col:3, col:14> 'struct Point' (CXXTemporary 0x7f9558860930)** -CompoundLiteralExpr 0x7f9558860908 <col:3, col:14> ‘struct Point’
**-CXXBindTemporaryExpr 0x7f95588608e8 <col:10, col:14> 'struct Point' (CXXTemporary 0x7f95588608e0)** -InitListExpr 0x7f9558860860 <col:10, col:14> ‘struct Point’

-IntegerLiteral 0x7f95588607d0 col:11 ‘int’ 1
`-IntegerLiteral 0x7f95588607f0 col:13 ‘int’ 2

(This is the same AST whether in C++03 or C++11.)

For comparison:

struct Point {
Point(int x, int y);
~Point();
};

void test() {
((Point){1,2});
}

-FunctionDecl 0x7ffb3c060460 <line:6:1, line:8:1> test 'void (void)' -CompoundStmt 0x7ffb3c0608b0 <line:6:13, line:8:1>
-ExprWithCleanups 0x7ffb3c060898 <line:7:2, col:15> 'struct Point' -ParenExpr 0x7ffb3c060878 <col:2, col:15> ‘struct Point’
**-CXXBindTemporaryExpr 0x7ffb3c060858 <col:3, <invalid sloc>> 'struct Point' (CXXTemporary 0x7ffb3c060850)** -CompoundLiteralExpr 0x7ffb3c060828 <col:3, > ‘struct Point’
**-CXXBindTemporaryExpr 0x7ffb3c060808 <col:3, <invalid sloc>> 'struct Point' (CXXTemporary 0x7ffb3c060800)** -CXXTemporaryObjectExpr 0x7ffb3c060780 <col:3, > ‘struct Point’ ‘void (int, int)’

-IntegerLiteral 0x7ffb3c060510 col:11 ‘int’ 1
`-IntegerLiteral 0x7ffb3c060530 col:13 ‘int’ 2

Jordan

Okay, that’s weird. There should just be one temporary there.

  • Doug