Hi rsmith,
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 this
less elegant solution seemed necessary.
Thoughts?
Thank you!
http://reviews.llvm.org/D6171
Files:
include/clang/Sema/ScopeInfo.h
lib/Sema/SemaExpr.cpp
test/SemaCXX/cxx1y-generic-lambdas-pr20619.cpp
Index: include/clang/Sema/ScopeInfo.h
===================================================================
--- include/clang/Sema/ScopeInfo.h
+++ include/clang/Sema/ScopeInfo.h
@@ -675,11 +675,14 @@
SourceLocation PotentialThisCaptureLocation;
+ bool IsInitializingExplicitOrImplicitCapture;
+
LambdaScopeInfo(DiagnosticsEngine &Diag)
: CapturingScopeInfo(Diag, ImpCap_None), Lambda(nullptr),
CallOperator(nullptr), NumExplicitCaptures(0), Mutable(false),
ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false),
- AutoTemplateParameterDepth(0), GLTemplateParameterList(nullptr)
+ AutoTemplateParameterDepth(0), GLTemplateParameterList(nullptr),
+ IsInitializingExplicitOrImplicitCapture(false)
{
Kind = SK_Lambda;
}
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -11394,20 +11394,42 @@
Func->setReferenced();
- // C++11 [basic.def.odr]p3:
- // A function whose name appears as a potentially-evaluated expression is
- // odr-used if it is the unique lookup result or the selected member of a
- // set of overloaded functions [...].
+ // We need to identify copy initializations of explicit or implicit captures
+ // of generic lambdas since even if the current context is dependent (i.e. the
+ // generic lambda's member function template call operator has been pushed on
+ // the declcontext stack) we still need to mark these copy constructors
+ // as used if the context surrounding the generic lambda is non-dependent
+ // since the initialization of the data members of the closure type (which is
+ // a non-dependent context, if the surrounding context is non-dependent) must
+ // occur.
+ const bool IsInitializingExplicitOrImplicitByValCaptureOfGenericLambda =
+ ([](FunctionDecl *Func, Sema &S) {
+ if (auto *GenericLSI = S.getCurGenericLambda()) {
+ auto *GenericCallOp = GenericLSI->CallOperator;
+ return GenericLSI->IsInitializingExplicitOrImplicitCapture &&
+ !getLambdaAwareParentOfDeclContext(GenericCallOp)
+ ->isDependentContext() &&
+ isa<CXXConstructorDecl>(Func) &&
+ cast<CXXConstructorDecl>(Func)->isCopyConstructor();
+ }
+ return false;
+ }(Func, *this));
+
+ // C++11 [basic.def.odr]p3: A function whose name appears as a
+ // potentially-evaluated expression is odr-used if it is the unique lookup
+ // result or the selected member of a set of overloaded functions [...].
//
// We (incorrectly) mark overload resolution as an unevaluated context, so we
// can just check that here. Skip the rest of this function if we've already
// marked the function as used.
- if (Func->isUsed(false) || !IsPotentiallyEvaluatedContext(*this)) {
- // C++11 [temp.inst]p3:
- // Unless a function template specialization has been explicitly
- // instantiated or explicitly specialized, the function template
- // specialization is implicitly instantiated when the specialization is
- // referenced in a context that requires a function definition to exist.
+ if (Func->isUsed(false) ||
+ (!IsPotentiallyEvaluatedContext(*this) &&
+ !IsInitializingExplicitOrImplicitByValCaptureOfGenericLambda)) {
+ // C++11 [temp.inst]p3: Unless a function template specialization has been
+ // explicitly instantiated or explicitly specialized, the function
+ // template specialization is implicitly instantiated when the
+ // specialization is referenced in a context that requires a function
+ // definition to exist.
//
// We consider constexpr function templates to be referenced in a context
// that requires a definition to exist whenever they are referenced.
@@ -11922,7 +11944,13 @@
IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get());
assert(!IterationVarRef.isInvalid() &&
"Conversion of invented variable cannot fail!");
-
+
+ // If we are capturing within a generic lambda and the enclosing context is
+ // not dependent, mark the iteration-var as used.
+ if (!IterationVar->isUsed(false) && S.getCurGenericLambda() &&
+ !Lambda->getDeclContext()->isDependentContext())
+ IterationVar->markUsed(S.Context);
+
// Subscript the array with this iteration variable.
ExprResult Subscript = S.CreateBuiltinArraySubscriptExpr(
Ref, Loc, IterationVarRef.get(), Loc);
@@ -11935,7 +11963,27 @@
Ref = Subscript.get();
BaseType = Array->getElementType();
}
+ // We need to mark within the current lambda scope info that we will be
+ // copy-initializing a byvalue capture. This is necessary because for generic
+ // lambdas even though the current DeclContext (the generic lambda's call
+ // operator template) is dependent, any constructors that are referenced need
+ // to be marked as used since the initialization occurs within the enclosing
+ // closure object which is non-dependent if the enclosing ctx is.
+ // We can not move the initialization prior to the pushing of the generic
+ // lambda's call operator since we don't know which implicit captures to make
+ // unless we are processing the call operator's body.
+ struct ScopeGuardForMarkingByValCaptureInitialization {
+ LambdaScopeInfo *const CurLSI;
+ ScopeGuardForMarkingByValCaptureInitialization(LambdaScopeInfo *LSI)
+ : CurLSI(LSI) {
+ CurLSI->IsInitializingExplicitOrImplicitCapture = true;
+ }
+ ~ScopeGuardForMarkingByValCaptureInitialization() {
+ CurLSI->IsInitializingExplicitOrImplicitCapture = false;
+ }
+ } RAIIMarkByValCaptureInitializationInLambdaScopeInfo(LSI);
+
// Construct the entity that we will be initializing. For an array, this
// will be first element in the array, which may require several levels
// of array-subscript entities.
Index: test/SemaCXX/cxx1y-generic-lambdas-pr20619.cpp
===================================================================
--- test/SemaCXX/cxx1y-generic-lambdas-pr20619.cpp
+++ test/SemaCXX/cxx1y-generic-lambdas-pr20619.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks -emit-llvm-only %s
+// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
+// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
+// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
+
+//expected-no-diagnostics
+
+namespace PR20619_capturing_class_variables_within_generic_lambdas {
+// http://llvm.org/bugs/show_bug.cgi?id=20619
+namespace ns1 {
+int g;
+struct A { };
+struct B : virtual A { int get() const { return g; } };
+
+void foo() {
+ B x;
+ B arrX[100];
+ auto L = [x, arrX](auto) { };
+ (void) [=](auto) { return arrX[0].get() + x.get(); };
+}
+} // end ns1
+
+namespace ns2 {
+
+struct A { A(A &); };
+struct B : A { B(int); };
+
+void foo2() {
+ B x{0};
+ (void)[x](auto) { };
+}
+} //end ns2
+
+
+} // end PR20619_capturing_class_variables_within_generic_lambdas
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits