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

Reply via email to