[cfe-dev] A disappearing CXXBindTemporaryExpr.

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Thu Mar 29 16:31:55 PDT 2018


On 29 March 2018 at 14:42, John McCall via cfe-dev <cfe-dev at lists.llvm.org>
wrote:

> On Mar 29, 2018, at 5:32 PM, Richard Smith <richard at metafoo.co.uk> wrote:
>
> On 29 March 2018 at 14:19, John McCall via cfe-dev <cfe-dev at lists.llvm.org
> > wrote:
>
>> On Mar 29, 2018, at 5:10 PM, Richard Smith via cfe-dev <
>> cfe-dev at lists.llvm.org> wrote:
>>
>> Looks like a bug to me, probably template instantiation for the
>> initializer is stripping this node out and we're failing to recreate it
>> when redoing the initialization in the instantiation.
>>
>> But I wonder whether we should just ditch the CXXBindTemporaryExpr node
>> entirely. The purpose of marking where a temporary is created that needs a
>> cleanup is handled much better by looking for CXXMaterializeTemporaryExprs
>> (since they also track whether the temporary was lifetime-extended), and it
>> doesn't seem like an imposition to ask clients to work out for themselves
>> whether the type of the temporary needs destruction.
>>
>> This would require us to start creating CXXMaterializeTemporaryExprs in
>> C++98 for cases like "A().n", where we currently avoid doing so because the
>> language rules say that expression is an rvalue, which in turn means
>> (carefully) extending the C++11 xvalue rules to C++98 mode. But that seems
>> feasible -- the hardest part is likely going to be avoiding using the term
>> "xvalue" in C++98 diagnostics :)
>>
>>
>> If we're going to do this, I think it would make sense to just store a
>> "semantic value kind" that papers over as many of these language
>> differences as possible, with the understanding that queries about the
>> formal value kind have to be parameterized by LangOpts.  So it would have
>> options like:
>>   - complete pr-value
>>   - pr-value subobject
>>   - l-value
>>   - x-value
>>   - function reference (because C considers these r-values)
>>
>> Obviously, some differences (like compound literals) are real semantic
>> differences between languages, but most of the rest of these are extremely
>> artificial and clients ought  to be able to ignore them.
>>
>
> Oh great, now we have a "naming things" problem too ;-)
>
>
> Heh, yeah, I was writing that and questioning everything I put down. :)
>
> Yes, I agree, that makes a lot of sense.
>
> If we're going to take on this work, I think we should also consider what
> should become of ExprClassification.cpp versus the value kind + object kind
> bits on Expr. It doesn't make much sense to have two independent mechanisms
> computing largely the same information.
>
>
> I agree that we might be able to get rid of ExprClassification.
>
> Also, do we need the ObjC parameter / subscript ObjectKind given that we
> have PseudoObject placeholder types to identify the relevant expressions?
>
>
> Yes, that's true, I think we no longer need a special object kind for
> these.
>
> (Conversely, compatibility with modern GCC suggests we should have an
> "underaligned field" object kind, reference bindings to which implicitly
> create temporaries just like for bit-fields.)
>
>
> Hmm, I feel like this might be more a special-case semantic rule for
> reference-binding than an actual difference in the expression.
>

As far as I can tell, it propagates through expressions exactly like
bit-field-ness, and generally acts like the expression is half-way to being
a bit-field (https://godbolt.org/g/teWxN7), affecting reference binding but
not preventing taking the address.

John.
>
>
> John.
>>
>>
>> On 27 March 2018 at 13:43, Artem Dergachev via cfe-dev <
>> cfe-dev at lists.llvm.org> wrote:
>>
>>> 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 :)
>>>>>
>>>>
>>>>
>>> _______________________________________________
>>> cfe-dev mailing list
>>> cfe-dev at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>>
>>
>> _______________________________________________
>> cfe-dev mailing list
>> cfe-dev at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>
>>
>>
>> _______________________________________________
>> cfe-dev mailing list
>> cfe-dev at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>
>>
>
>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20180329/bd107316/attachment.html>


More information about the cfe-dev mailing list