[cfe-dev] A disappearing CXXBindTemporaryExpr.

Artem Dergachev via cfe-dev cfe-dev at lists.llvm.org
Tue Mar 27 13:43:00 PDT 2018


Hmm, i understand why field 'a' being public is relevant. That's because 
it turns B into an aggregate.

But i still don't understand why templating/un-templating foo() makes a 
difference.

On 3/26/18 8:01 PM, Artem Dergachev wrote:
> Sorry, accidentally sent two concatenated emails. The corrected email 
> should be:
>
> On 3/26/18 7:58 PM, Artem Dergachev wrote:
>> I've a C++ AST question.
>>
>> I've got a piece of code that doesn't contain CXXBindTemporaryExpr in 
>> its AST, but would have contained it if only i explicitly unwrapped a 
>> template that contains it *or* changed a field visibility in a 
>> certain class from private to public. I want to understand if it's 
>> intentional and if so what's the language feature that provides such 
>> behavior. A few hours of debugging Sema didn't quite help me (but i'm 
>> not super good with it).
>>
>> The code looks like this and compiles under -std=c++14:
>>
>> ```
>> class A {
>> public:
>>   ~A();
>> };
>>
>> class B {
>>   A a;
>> };
>>
>> template <typename T> void foo(T) {
>>   B i;
>>   i = {};
>> }
>>
>> int main() {
>>   foo(1);
>>   return 0;
>> }
>> ```
>>
>> AST for foo():
>>
>>
>> ```
>> |-FunctionTemplateDecl 0x7fd5a8800f50 <line:10:1, line:13:1> 
>> line:10:28 foo
>> | |-TemplateTypeParmDecl 0x7fd5a8800ce8 <col:11, col:20> col:20 
>> referenced typename depth 0 index 0 T
>> | |-FunctionDecl 0x7fd5a8800eb0 <col:23, line:13:1> line:10:28 foo 
>> 'void (T)'
>> | | |-ParmVarDecl 0x7fd5a8800db0 <col:32> col:33 'T'
>> | | `-CompoundStmt 0x7fd5a8801740 <col:35, line:13:1>
>> | |   |-DeclStmt 0x7fd5a8801320 <line:11:3, col:6>
>> | |   | `-VarDecl 0x7fd5a8800ff8 <col:3, col:5> col:5 referenced i 
>> 'B' callinit
>> | |   |   `-CXXConstructExpr 0x7fd5a88012f0 <col:5> 'B' 'void () 
>> noexcept'
>> | |   `-ExprWithCleanups 0x7fd5a8801728 <line:12:3, col:8> 'B' lvalue
>> | |     `-CXXOperatorCallExpr 0x7fd5a88016e0 <col:3, col:8> 'B' lvalue
>> | |       |-ImplicitCastExpr 0x7fd5a88016c8 <col:5> 'B &(*)(B &&) 
>> noexcept' <FunctionToPointerDecay>
>> | |       | `-DeclRefExpr 0x7fd5a8801648 <col:5> 'B &(B &&) noexcept' 
>> lvalue CXXMethod 0x7fd5a785de28 'operator=' 'B &(B &&) noexcept'
>> | |       |-DeclRefExpr 0x7fd5a8801338 <col:3> 'B' lvalue Var 
>> 0x7fd5a8800ff8 'i' 'B'
>> | |       `-MaterializeTemporaryExpr 0x7fd5a88015b0 <col:7, col:8> 
>> 'B' xvalue
>> | |         `-CXXBindTemporaryExpr 0x7fd5a8801590 <col:7, col:8> 'B' 
>> (CXXTemporary 0x7fd5a8801588)
>> | |           `-CXXConstructExpr 0x7fd5a8801558 <col:7, col:8> 'B' 
>> 'void () noexcept' list zeroing
>> | `-FunctionDecl 0x7fd5a8801b10 <line:10:23, line:13:1> line:10:28 
>> used foo 'void (int)'
>> |   |-TemplateArgument type 'int'
>> |   |-ParmVarDecl 0x7fd5a8801a08 <col:32> col:33 'int':'int'
>> |   `-CompoundStmt 0x7fd5a8802e28 <col:35, line:13:1>
>> |     |-DeclStmt 0x7fd5a88029f8 <line:11:3, col:6>
>> |     | `-VarDecl 0x7fd5a8802958 <col:3, col:5> col:5 used i 'B' 
>> callinit
>> |     |   `-CXXConstructExpr 0x7fd5a88029b8 <col:5> 'B' 'void () 
>> noexcept'
>> |     `-ExprWithCleanups 0x7fd5a8802e10 <line:12:3, col:8> 'B' lvalue
>> |       `-CXXOperatorCallExpr 0x7fd5a8802dc8 <col:3, col:8> 'B' lvalue
>> |         |-ImplicitCastExpr 0x7fd5a8802db0 <col:5> 'B &(*)(B &&) 
>> noexcept' <FunctionToPointerDecay>
>> |         | `-DeclRefExpr 0x7fd5a8802d88 <col:5> 'B &(B &&) noexcept' 
>> lvalue CXXMethod 0x7fd5a785de28 'operator=' 'B &(B &&) noexcept'
>> |         |-DeclRefExpr 0x7fd5a8802d48 <col:3> 'B' lvalue Var 
>> 0x7fd5a8802958 'i' 'B'
>> |         `-MaterializeTemporaryExpr 0x7fd5a8802d70 <col:7, col:8> 
>> 'B' xvalue
>> |           `-CXXConstructExpr 0x7fd5a8801558 <col:7, col:8> 'B' 
>> 'void () noexcept' list zeroing
>> ```
>>
>> As you see, there's a CXXBindTemporaryExpr in the template, but it's 
>> not there in the instantiation. I expected the CXXBindTemporaryExpr 
>> to be there whenever the object has a non-trivial destructor, but in 
>> this case it's suddenly missing.
>>
>> However, if i replace "template <typename T> void foo(T)" with "void 
>> foo(int)" (to which it should resolve anyway), CXXBindTemporaryExpr 
>> would be present.
>>
>> Moreover, if instead of unrolling the template i simply add "public:" 
>> before "A a;", the mysterious CXXBindTemporaryExpr would also be 
>> present.
>>
>> WHY :)
>




More information about the cfe-dev mailing list