This is an archive of the discontinued LLVM Phabricator instance.

Fix PR20619 - failure to define implicit copy ctor of a by val capture in a generic lambda
AbandonedPublic

Authored by rsmith on Nov 7 2014, 9:53 AM.

Details

Reviewers
faisalv
Summary

http://llvm.org/bugs/show_bug.cgi?id=20619

Please see the above bug for details, but briefly:
Since a generic lambda's call operator is a dependent context, and since we have to process implicit captures once a generic lambda's call operator's DeclContext has been pushed (and currently process explicit by value captures that way too - (unlike init-captures whose initialization actually occurs prior to the call operator being pushed on)) - we need to indicate when deciding whether implicit special member functions should be generated, that we are initializing captures of generic lambdas and even though the current context is dependent, since the enclosing one is not, generate these implicit functions and mark them used.

For e.g.:
struct A { };
struct B : virtual A { };
int main() {

B x;
[=](auto a) { x; }; // Sans patch, this will crash since the copy ctor of B will not get defined.

}

As discussed within the Bug Report, explicit captures by val could be fixed by moving their initialization to prior to the call operator's decl context being pushed on - but this would not address implicit by val captures - hence we now do the initialization analysis after the call-operator's context has been popped off (per Richard's suggestion!)

Thank you!

Diff Detail

Event Timeline

faisalv updated this revision to Diff 15931.Nov 7 2014, 9:53 AM
faisalv retitled this revision from to Fix PR20619 - failure to define implicit copy ctor of a by val capture in a generic lambda.
faisalv updated this object.
faisalv edited the test plan for this revision. (Show Details)
faisalv added a reviewer: rsmith.
faisalv added a subscriber: Unknown Object (MLST).
rsmith edited edge metadata.Nov 7 2014, 11:46 AM

We shouldn't mark the operation as used if the generic lambda itself appears in a dependent context. I would strongly prefer that we set the CurContext to the context surrounding the generic lambda before processing an implicit capture to handle that case.

We shouldn't mark the operation as used if the generic lambda itself appears in a dependent context. I would strongly prefer that we set the CurContext to the context surrounding the generic lambda before processing an implicit capture to handle that case.

But I thought this patch won't mark it as used if the enclosing context is dependent - since I explicitly check for that - what am I missing?

rsmith added a comment.Dec 3 2014, 1:02 PM
In D6171#5, @faisalv wrote:

We shouldn't mark the operation as used if the generic lambda itself appears in a dependent context. I would strongly prefer that we set the CurContext to the context surrounding the generic lambda before processing an implicit capture to handle that case.

But I thought this patch won't mark it as used if the enclosing context is dependent - since I explicitly check for that - what am I missing?

It's still the wrong way to do this. Rather than working around the context being wrong, you should switch to the right context before building the copy.

faisalv updated this revision to Diff 17021.Dec 6 2014, 8:46 AM
faisalv edited edge metadata.

Modified the approach so that now we jump out to the right context temporarily while performing the initialization of the captures.

I'm not sure if I need to sync up the CurScope pointer here?

Thanks!

On reflection, can we delay building the initialization expressions for captures until we get to the end of the lambda expression? There seems to be no need to build them early, and delaying would solve the wrong-context problem implicitly.

lib/Sema/SemaExpr.cpp
12118–12136

This is:

ContextRAII SwitchToLambdaContext(S, LSI->Lambda->getDeclContext());
12125–12128

You shouldn't need this; CurScope should only be used while parsing (and ideally shouldn't be used in Sema for C++ at all); if we use CurScope in here, we will do the wrong thing during template instantiation, where CurScope is not set.

On reflection, can we delay building the initialization expressions for captures until we get to the end of the lambda expression? There seems to be no need to build them early, and delaying would solve the wrong-context problem implicitly.

very nice - I think this might be the cleanest solution if it works - will explore this avenue soon ...
Thanks!

faisalv updated this revision to Diff 20962.Mar 1 2015, 11:15 AM
faisalv updated this object.

Per Richard's suggestion, I moved the creation of the initializer expression (including analysis of conversion and generation of implicit functions) following the popping off of the lambda's call operator. This solution seems to work well.

In passing the following bug regarding VLA's was also fixed:

void foo(int I) {

int v[I];
int x[10];
auto L = [=, &v] (int n) { return v[n] + x[n]; } // Now works

}

Thanks!
}

As a motivation: if we get through this review and we ever meet at a conference, I'm buying both of you guys a beer. Let's finish this!

My friend, it is you who deserves a beer for your patience =)

Faisal Vali

emaste added a subscriber: emaste.Jun 16 2015, 12:49 PM

I encountered the assertion failure when compiling https://bitbucket.org/krojew/evernus on FreeBSD with clang 3.6.1.

The patch here solved the problem.

The underlying bug here was fixed in r235921.

rsmith commandeered this revision.Jun 16 2015, 6:49 PM
rsmith abandoned this revision.
rsmith edited reviewers, added: faisalv; removed: rsmith.