r286584 - Fix for PR28523: unexpected compilation error.

Alexey Bataev via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 11 04:36:21 PST 2016


Author: abataev
Date: Fri Nov 11 06:36:20 2016
New Revision: 286584

URL: http://llvm.org/viewvc/llvm-project?rev=286584&view=rev
Log:
Fix for PR28523: unexpected compilation error.

Clang emits error message for the following code:
```
template <class F> void parallel_loop(F &&f) { f(0); }

int main() {
  int x;
  parallel_loop([&](auto y) {
    {
      x = y;
    };
  });
}
```

$ clang++ --std=gnu++14 clang_test.cc -o clang_test
clang_test.cc:9:7: error: reference to local variable 'x' declared in enclosing function 'main'
      x = y;
            ^
clang_test.cc:2:48: note: in instantiation of function template specialization 'main()::(anonymous class)::operator()<int>' requested here
            template <class F> void parallel_loop(F &&f) { f(0); }
                                                           ^
clang_test.cc:6:3: note: in instantiation of function template specialization 'parallel_loop<(lambda at clang_test.cc:6:17)>' requested here parallel_loop([&](auto y) {
           ^
clang_test.cc:5:7: note: 'x' declared here
      int x;
          ^
1 error generated.

Patch fixes this issue.

Added:
    cfe/trunk/test/CodeGenCXX/PR28523.cpp
Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaLambda.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=286584&r1=286583&r2=286584&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Nov 11 06:36:20 2016
@@ -1228,8 +1228,10 @@ public:
   /// \brief Retrieve the current block, if any.
   sema::BlockScopeInfo *getCurBlock();
 
-  /// \brief Retrieve the current lambda scope info, if any.
-  sema::LambdaScopeInfo *getCurLambda();
+  /// Retrieve the current lambda scope info, if any.
+  /// \param IgnoreCapturedRegions true if should find the top-most lambda scope
+  /// info ignoring all inner captured regions scope infos.
+  sema::LambdaScopeInfo *getCurLambda(bool IgnoreCapturedRegions = false);
 
   /// \brief Retrieve the current generic lambda info, if any.
   sema::LambdaScopeInfo *getCurGenericLambda();

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=286584&r1=286583&r2=286584&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Fri Nov 11 06:36:20 2016
@@ -1201,11 +1201,19 @@ BlockScopeInfo *Sema::getCurBlock() {
   return CurBSI;
 }
 
-LambdaScopeInfo *Sema::getCurLambda() {
+LambdaScopeInfo *Sema::getCurLambda(bool IgnoreCapturedRegions) {
   if (FunctionScopes.empty())
     return nullptr;
 
-  auto CurLSI = dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
+  auto I = FunctionScopes.rbegin();
+  if (IgnoreCapturedRegions) {
+    auto E = FunctionScopes.rend();
+    while (I != E && isa<CapturedRegionScopeInfo>(*I))
+      ++I;
+    if (I == E)
+      return nullptr;
+  }
+  auto *CurLSI = dyn_cast<LambdaScopeInfo>(*I);
   if (CurLSI && CurLSI->Lambda &&
       !CurLSI->Lambda->Encloses(CurContext)) {
     // We have switched contexts due to template instantiation.

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=286584&r1=286583&r2=286584&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Nov 11 06:36:20 2016
@@ -14079,7 +14079,8 @@ static void DoMarkVarDeclReferenced(Sema
         (SemaRef.CurContext != Var->getDeclContext() &&
          Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage());
     if (RefersToEnclosingScope) {
-      if (LambdaScopeInfo *const LSI = SemaRef.getCurLambda()) {
+      if (LambdaScopeInfo *const LSI =
+              SemaRef.getCurLambda(/*IgnoreCapturedRegions=*/true)) {
         // If a variable could potentially be odr-used, defer marking it so
         // until we finish analyzing the full expression for any
         // lvalue-to-rvalue

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=286584&r1=286583&r2=286584&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Nov 11 06:36:20 2016
@@ -6879,8 +6879,14 @@ static void CheckIfAnyEnclosingLambdasMu
 
   assert(!S.isUnevaluatedContext());
   assert(S.CurContext->isDependentContext());
-  assert(CurrentLSI->CallOperator == S.CurContext &&
+#ifndef NDEBUG
+  DeclContext *DC = S.CurContext;
+  while (DC && isa<CapturedDecl>(DC))
+    DC = DC->getParent();
+  assert(
+      CurrentLSI->CallOperator == DC &&
       "The current call operator must be synchronized with Sema's CurContext");
+#endif // NDEBUG
 
   const bool IsFullExprInstantiationDependent = FE->isInstantiationDependent();
 
@@ -7346,7 +7352,8 @@ ExprResult Sema::ActOnFinishFullExpr(Exp
   // and then the full-expression +n + ({ 0; }); ends, but it's too late
   // for us to see that we need to capture n after all.
 
-  LambdaScopeInfo *const CurrentLSI = getCurLambda();
+  LambdaScopeInfo *const CurrentLSI =
+      getCurLambda(/*IgnoreCapturedRegions=*/true);
   // FIXME: PR 17877 showed that getCurLambda() can return a valid pointer
   // even if CurContext is not a lambda call operator. Refer to that Bug Report
   // for an example of the code that might cause this asynchrony.
@@ -7361,7 +7368,10 @@ ExprResult Sema::ActOnFinishFullExpr(Exp
   //     constructor/destructor.
   //  - Teach the handful of places that iterate over FunctionScopes to
   //    stop at the outermost enclosing lexical scope."
-  const bool IsInLambdaDeclContext = isLambdaCallOperator(CurContext);
+  DeclContext *DC = CurContext;
+  while (DC && isa<CapturedDecl>(DC))
+    DC = DC->getParent();
+  const bool IsInLambdaDeclContext = isLambdaCallOperator(DC);
   if (IsInLambdaDeclContext && CurrentLSI &&
       CurrentLSI->hasPotentialCaptures() && !FullExpr.isInvalid())
     CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(FE, CurrentLSI,

Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=286584&r1=286583&r2=286584&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Fri Nov 11 06:36:20 2016
@@ -66,17 +66,20 @@ getStackIndexOfNearestEnclosingCaptureRe
   // Label failure to capture.
   const Optional<unsigned> NoLambdaIsCaptureReady;
 
+  // Ignore all inner captured regions.
+  unsigned CurScopeIndex = FunctionScopes.size() - 1;
+  while (CurScopeIndex > 0 && isa<clang::sema::CapturedRegionScopeInfo>(
+                                  FunctionScopes[CurScopeIndex]))
+    --CurScopeIndex;
   assert(
-      isa<clang::sema::LambdaScopeInfo>(
-          FunctionScopes[FunctionScopes.size() - 1]) &&
+      isa<clang::sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex]) &&
       "The function on the top of sema's function-info stack must be a lambda");
-  
+
   // If VarToCapture is null, we are attempting to capture 'this'.
   const bool IsCapturingThis = !VarToCapture;
   const bool IsCapturingVariable = !IsCapturingThis;
 
   // Start with the current lambda at the top of the stack (highest index).
-  unsigned CurScopeIndex = FunctionScopes.size() - 1;
   DeclContext *EnclosingDC =
       cast<sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex])->CallOperator;
 

Added: cfe/trunk/test/CodeGenCXX/PR28523.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/PR28523.cpp?rev=286584&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/PR28523.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/PR28523.cpp Fri Nov 11 06:36:20 2016
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++14 -verify -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+template <class F> void parallel_loop(F &&f) { f(0); }
+
+//CHECK-LABEL: @main
+int main() {
+// CHECK: [[X_ADDR:%.+]] = alloca i32,
+  int x;
+// CHECK: getelementptr inbounds
+// CHECK: store i32* [[X_ADDR]], i32** %
+// CHECK: call
+  parallel_loop([&](auto y) {
+#pragma clang __debug captured
+    {
+      x = y;
+    };
+  });
+}




More information about the cfe-commits mailing list