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!
http://reviews.llvm.org/D6171
Files:
include/clang/Sema/Sema.h
lib/Sema/Sema.cpp
lib/Sema/SemaExpr.cpp
test/SemaCXX/cxx1y-generic-lambdas-pr20619.cpp
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -8684,6 +8684,8 @@
/// template substitution or instantiation.
Scope *getCurScope() const { return CurScope; }
+ void setCurScope(Scope *S) { CurScope = S; }
+
void incrementMSLocalManglingNumber() const {
return CurScope->incrementMSLocalManglingNumber();
}
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -15,6 +15,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
@@ -1169,10 +1170,22 @@
if (FunctionScopes.empty())
return nullptr;
- auto CurLSI = dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
- if (CurLSI && CurLSI->Lambda &&
- !CurLSI->Lambda->Encloses(CurContext)) {
- // We have switched contexts due to template instantiation.
+ auto *CurLSI = dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
+ if (CurLSI && CurLSI->Lambda && !CurLSI->Lambda->Encloses(CurContext)) {
+ // We might have temporarily jumped out to an enclosing lambda's context
+ // when initializing explicit or implicit captures of that lambda. Check if
+ // that enclosing context is a lambda, and if so return its corresponding
+ // LambdaScopeInfo.
+ if (CurContext->Encloses(CurLSI->Lambda)) {
+ if (!isLambdaCallOperator(CurContext))
+ return nullptr;
+ for (FunctionScopeInfo *FSI : FunctionScopes) {
+ if (auto *LSI = dyn_cast<LambdaScopeInfo>(FSI))
+ if (LSI->CallOperator == CurContext)
+ return LSI;
+ }
+ }
+ // ... Or we have switched contexts due to template instantiation
assert(!ActiveTemplateInstantiations.empty());
return nullptr;
}
@@ -1179,8 +1192,8 @@
return CurLSI;
}
-// We have a generic lambda if we parsed auto parameters, or we have
-// an associated template parameter list.
+// We have a generic lambda if we parsed auto parameters, or we have an
+// associated template parameter list.
LambdaScopeInfo *Sema::getCurGenericLambda() {
if (LambdaScopeInfo *LSI = getCurLambda()) {
return (LSI->AutoTemplateParams.size() ||
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -12079,7 +12079,17 @@
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) &&
+ LSI->CallOperator->isDependentContext() &&
+ !Lambda->getDeclContext()->isDependentContext()) {
+ assert(S.getCurGenericLambda() &&
+ "How can this occur if the lambda is not generic!");
+ IterationVar->markUsed(S.Context);
+ }
+
// Subscript the array with this iteration variable.
ExprResult Subscript = S.CreateBuiltinArraySubscriptExpr(
Ref, Loc, IterationVarRef.get(), Loc);
@@ -12093,9 +12103,40 @@
BaseType = Array->getElementType();
}
- // 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.
+ // Before performing the initialization of the capture, temporarily jump out
+ // to the capturing LambdaScopeInfo's enclosing context (this is not
+ // necessarily the CurContext's lambda's enclosing context, since when
+ // processing implicit captures, we might have to capture in enclosing
+ // lambdas, while processing inner lambdas) since the initialization of the
+ // capture has to occur within the enclosing context - this can have
+ // consequences on what gets marked odr-used depending on whether the
+ // enclosing context is dependent or not. 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 TemporarilyJumpOutToDeclContextScopeGuard {
+ Sema &S;
+ Scope *CurScope;
+ DeclContext *CurContext;
+ TemporarilyJumpOutToDeclContextScopeGuard(Sema &S, LambdaScopeInfo *LSI)
+ : S(S), CurScope(S.getCurScope()), CurContext(S.CurContext) {
+ S.CurContext = LSI->Lambda->getDeclContext();
+ // FVQUESTION: Do we really need to mess with the Scope - or can I just
+ // ignore it since, unless I am entirely mistake, its raison d'ĂȘtre seems
+ // to be to aid the Parser, which will not be invoked from the ensuing
+ // sequence?
+ S.setCurScope(S.getScopeForContext(S.CurContext));
+ }
+ ~TemporarilyJumpOutToDeclContextScopeGuard() {
+ S.CurContext = CurContext;
+ S.setCurScope(CurScope);
+ }
+ } DeclContextScopeGuard(S, 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.
SmallVector<InitializedEntity, 4> Entities;
Entities.reserve(1 + IndexVariables.size());
Entities.push_back(
@@ -12110,6 +12151,9 @@
= InitializationKind::CreateDirect(Loc, Loc, Loc);
InitializationSequence Init(S, Entities.back(), InitKind, Ref);
ExprResult Result(true);
+ // The Initialization should occur in the lambda's enclosing context - this
+ // ensures that variables get marked as used even if the current lambda's
+ // declaration context is dependent - but the enclosing context is not.
if (!Init.Diagnose(S, Entities.back(), InitKind, Ref))
Result = Init.Perform(S, Entities.back(), InitKind, Ref);
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