r301416 - [OPENMP] Fix handling of OpenMP code during template instantiation.

Alexey Bataev via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 26 08:06:25 PDT 2017


Author: abataev
Date: Wed Apr 26 10:06:24 2017
New Revision: 301416

URL: http://llvm.org/viewvc/llvm-project?rev=301416&view=rev
Log:
[OPENMP] Fix handling of OpenMP code during template instantiation.

If some function template is instantiated during handling of OpenMP
code, currently it may cause crash of compiler because of trying of
capturing variables in non-capturing function scopes. Patch fixes this
bug.

Added:
    cfe/trunk/test/OpenMP/capturing_in_templates.cpp
Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/SemaOpenMP.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=301416&r1=301415&r2=301416&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Apr 26 10:06:24 2017
@@ -8327,6 +8327,12 @@ private:
   /// Returns OpenMP nesting level for current directive.
   unsigned getOpenMPNestingLevel() const;
 
+  /// Push new OpenMP function region for non-capturing function.
+  void pushOpenMPFunctionRegion();
+
+  /// Pop OpenMP function region for non-capturing function.
+  void popOpenMPFunctionRegion(const sema::FunctionScopeInfo *OldFSI);
+
   /// Checks if a type or a declaration is disabled due to the owning extension
   /// being disabled, and emits diagnostic messages if it is disabled.
   /// \param D type or declaration to be checked.

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=301416&r1=301415&r2=301416&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Wed Apr 26 10:06:24 2017
@@ -1161,10 +1161,14 @@ void Sema::PushFunctionScope() {
     // memory for a new scope.
     FunctionScopes.back()->Clear();
     FunctionScopes.push_back(FunctionScopes.back());
+    if (LangOpts.OpenMP)
+      pushOpenMPFunctionRegion();
     return;
   }
 
   FunctionScopes.push_back(new FunctionScopeInfo(getDiagnostics()));
+  if (LangOpts.OpenMP)
+    pushOpenMPFunctionRegion();
 }
 
 void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
@@ -1192,6 +1196,9 @@ void Sema::PopFunctionScopeInfo(const An
   FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
   assert(!FunctionScopes.empty() && "mismatched push/pop!");
 
+  if (LangOpts.OpenMP)
+    popOpenMPFunctionRegion(Scope);
+
   // Issue any analysis-based warnings.
   if (WP && D)
     AnalysisWarnings.IssueWarnings(*WP, Scope, D, blkExpr);

Modified: cfe/trunk/lib/Sema/SemaOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOpenMP.cpp?rev=301416&r1=301415&r2=301416&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOpenMP.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOpenMP.cpp Wed Apr 26 10:06:24 2017
@@ -119,7 +119,8 @@ private:
 
   /// \brief Stack of used declaration and their data-sharing attributes.
   DeclSAMapTy Threadprivates;
-  StackTy Stack;
+  const FunctionScopeInfo *CurrentNonCapturingFunctionScope = nullptr;
+  SmallVector<std::pair<StackTy, const FunctionScopeInfo *>, 4> Stack;
   /// \brief true, if check for DSA must be from parent directive, false, if
   /// from current directive.
   OpenMPClauseKind ClauseKindMode = OMPC_unknown;
@@ -134,6 +135,12 @@ private:
   /// \brief Checks if the variable is a local for OpenMP region.
   bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter);
 
+  bool isStackEmpty() const {
+    return Stack.empty() ||
+           Stack.back().second != CurrentNonCapturingFunctionScope ||
+           Stack.back().first.empty();
+  }
+
 public:
   explicit DSAStackTy(Sema &S) : SemaRef(S) {}
 
@@ -145,13 +152,38 @@ public:
 
   void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName,
             Scope *CurScope, SourceLocation Loc) {
-    Stack.push_back(SharingMapTy(DKind, DirName, CurScope, Loc));
-    Stack.back().DefaultAttrLoc = Loc;
+    if (Stack.empty() ||
+        Stack.back().second != CurrentNonCapturingFunctionScope)
+      Stack.emplace_back(StackTy(), CurrentNonCapturingFunctionScope);
+    Stack.back().first.emplace_back(DKind, DirName, CurScope, Loc);
+    Stack.back().first.back().DefaultAttrLoc = Loc;
   }
 
   void pop() {
-    assert(!Stack.empty() && "Data-sharing attributes stack is empty!");
-    Stack.pop_back();
+    assert(!Stack.back().first.empty() &&
+           "Data-sharing attributes stack is empty!");
+    Stack.back().first.pop_back();
+  }
+
+  /// Start new OpenMP region stack in new non-capturing function.
+  void pushFunction() {
+    const FunctionScopeInfo *CurFnScope = SemaRef.getCurFunction();
+    assert(!isa<CapturingScopeInfo>(CurFnScope));
+    CurrentNonCapturingFunctionScope = CurFnScope;
+  }
+  /// Pop region stack for non-capturing function.
+  void popFunction(const FunctionScopeInfo *OldFSI) {
+    if (!Stack.empty() && Stack.back().second == OldFSI) {
+      assert(Stack.back().first.empty());
+      Stack.pop_back();
+    }
+    CurrentNonCapturingFunctionScope = nullptr;
+    for (const FunctionScopeInfo *FSI : llvm::reverse(SemaRef.FunctionScopes)) {
+      if (!isa<CapturingScopeInfo>(FSI)) {
+        CurrentNonCapturingFunctionScope = FSI;
+        break;
+      }
+    }
   }
 
   void addCriticalWithHint(OMPCriticalDirective *D, llvm::APSInt Hint) {
@@ -230,31 +262,35 @@ public:
 
   /// \brief Returns currently analyzed directive.
   OpenMPDirectiveKind getCurrentDirective() const {
-    return Stack.empty() ? OMPD_unknown : Stack.back().Directive;
+    return isStackEmpty() ? OMPD_unknown : Stack.back().first.back().Directive;
   }
   /// \brief Returns parent directive.
   OpenMPDirectiveKind getParentDirective() const {
-    if (Stack.size() > 1)
-      return Stack[Stack.size() - 2].Directive;
-    return OMPD_unknown;
+    if (isStackEmpty() || Stack.back().first.size() == 1)
+      return OMPD_unknown;
+    return std::next(Stack.back().first.rbegin())->Directive;
   }
 
   /// \brief Set default data sharing attribute to none.
   void setDefaultDSANone(SourceLocation Loc) {
-    Stack.back().DefaultAttr = DSA_none;
-    Stack.back().DefaultAttrLoc = Loc;
+    assert(!isStackEmpty());
+    Stack.back().first.back().DefaultAttr = DSA_none;
+    Stack.back().first.back().DefaultAttrLoc = Loc;
   }
   /// \brief Set default data sharing attribute to shared.
   void setDefaultDSAShared(SourceLocation Loc) {
-    Stack.back().DefaultAttr = DSA_shared;
-    Stack.back().DefaultAttrLoc = Loc;
+    assert(!isStackEmpty());
+    Stack.back().first.back().DefaultAttr = DSA_shared;
+    Stack.back().first.back().DefaultAttrLoc = Loc;
   }
 
   DefaultDataSharingAttributes getDefaultDSA() const {
-    return Stack.empty() ? DSA_unspecified : Stack.back().DefaultAttr;
+    return isStackEmpty() ? DSA_unspecified
+                          : Stack.back().first.back().DefaultAttr;
   }
   SourceLocation getDefaultDSALocation() const {
-    return Stack.empty() ? SourceLocation() : Stack.back().DefaultAttrLoc;
+    return isStackEmpty() ? SourceLocation()
+                          : Stack.back().first.back().DefaultAttrLoc;
   }
 
   /// \brief Checks if the specified variable is a threadprivate.
@@ -265,56 +301,64 @@ public:
 
   /// \brief Marks current region as ordered (it has an 'ordered' clause).
   void setOrderedRegion(bool IsOrdered, Expr *Param) {
-    Stack.back().OrderedRegion.setInt(IsOrdered);
-    Stack.back().OrderedRegion.setPointer(Param);
+    assert(!isStackEmpty());
+    Stack.back().first.back().OrderedRegion.setInt(IsOrdered);
+    Stack.back().first.back().OrderedRegion.setPointer(Param);
   }
   /// \brief Returns true, if parent region is ordered (has associated
   /// 'ordered' clause), false - otherwise.
   bool isParentOrderedRegion() const {
-    if (Stack.size() > 1)
-      return Stack[Stack.size() - 2].OrderedRegion.getInt();
-    return false;
+    if (isStackEmpty() || Stack.back().first.size() == 1)
+      return false;
+    return std::next(Stack.back().first.rbegin())->OrderedRegion.getInt();
   }
   /// \brief Returns optional parameter for the ordered region.
   Expr *getParentOrderedRegionParam() const {
-    if (Stack.size() > 1)
-      return Stack[Stack.size() - 2].OrderedRegion.getPointer();
-    return nullptr;
+    if (isStackEmpty() || Stack.back().first.size() == 1)
+      return nullptr;
+    return std::next(Stack.back().first.rbegin())->OrderedRegion.getPointer();
   }
   /// \brief Marks current region as nowait (it has a 'nowait' clause).
   void setNowaitRegion(bool IsNowait = true) {
-    Stack.back().NowaitRegion = IsNowait;
+    assert(!isStackEmpty());
+    Stack.back().first.back().NowaitRegion = IsNowait;
   }
   /// \brief Returns true, if parent region is nowait (has associated
   /// 'nowait' clause), false - otherwise.
   bool isParentNowaitRegion() const {
-    if (Stack.size() > 1)
-      return Stack[Stack.size() - 2].NowaitRegion;
-    return false;
+    if (isStackEmpty() || Stack.back().first.size() == 1)
+      return false;
+    return std::next(Stack.back().first.rbegin())->NowaitRegion;
   }
   /// \brief Marks parent region as cancel region.
   void setParentCancelRegion(bool Cancel = true) {
-    if (Stack.size() > 1)
-      Stack[Stack.size() - 2].CancelRegion =
-          Stack[Stack.size() - 2].CancelRegion || Cancel;
+    if (!isStackEmpty() && Stack.back().first.size() > 1) {
+      auto &StackElemRef = *std::next(Stack.back().first.rbegin());
+      StackElemRef.CancelRegion |= StackElemRef.CancelRegion || Cancel;
+    }
   }
   /// \brief Return true if current region has inner cancel construct.
   bool isCancelRegion() const {
-    return Stack.empty() ? false : Stack.back().CancelRegion;
+    return isStackEmpty() ? false : Stack.back().first.back().CancelRegion;
   }
 
   /// \brief Set collapse value for the region.
-  void setAssociatedLoops(unsigned Val) { Stack.back().AssociatedLoops = Val; }
+  void setAssociatedLoops(unsigned Val) {
+    assert(!isStackEmpty());
+    Stack.back().first.back().AssociatedLoops = Val;
+  }
   /// \brief Return collapse value for region.
   unsigned getAssociatedLoops() const {
-    return Stack.empty() ? 0 : Stack.back().AssociatedLoops;
+    return isStackEmpty() ? 0 : Stack.back().first.back().AssociatedLoops;
   }
 
   /// \brief Marks current target region as one with closely nested teams
   /// region.
   void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) {
-    if (Stack.size() > 1)
-      Stack[Stack.size() - 2].InnerTeamsRegionLoc = TeamsRegionLoc;
+    if (!isStackEmpty() && Stack.back().first.size() > 1) {
+      std::next(Stack.back().first.rbegin())->InnerTeamsRegionLoc =
+          TeamsRegionLoc;
+    }
   }
   /// \brief Returns true, if current region has closely nested teams region.
   bool hasInnerTeamsRegion() const {
@@ -322,17 +366,19 @@ public:
   }
   /// \brief Returns location of the nested teams region (if any).
   SourceLocation getInnerTeamsRegionLoc() const {
-    return Stack.empty() ? SourceLocation() : Stack.back().InnerTeamsRegionLoc;
+    return isStackEmpty() ? SourceLocation()
+                          : Stack.back().first.back().InnerTeamsRegionLoc;
   }
 
   Scope *getCurScope() const {
-    return Stack.empty() ? nullptr : Stack.back().CurScope;
+    return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope;
   }
   Scope *getCurScope() {
-    return Stack.empty() ? nullptr : Stack.back().CurScope;
+    return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope;
   }
   SourceLocation getConstructLoc() {
-    return Stack.empty() ? SourceLocation() : Stack.back().ConstructLoc;
+    return isStackEmpty() ? SourceLocation()
+                          : Stack.back().first.back().ConstructLoc;
   }
 
   /// Do the check specified in \a Check to all component lists and return true
@@ -342,8 +388,10 @@ public:
       const llvm::function_ref<
           bool(OMPClauseMappableExprCommon::MappableExprComponentListRef,
                OpenMPClauseKind)> &Check) {
-    auto SI = Stack.rbegin();
-    auto SE = Stack.rend();
+    if (isStackEmpty())
+      return false;
+    auto SI = Stack.back().first.rbegin();
+    auto SE = Stack.back().first.rend();
 
     if (SI == SE)
       return false;
@@ -370,9 +418,9 @@ public:
       ValueDecl *VD,
       OMPClauseMappableExprCommon::MappableExprComponentListRef Components,
       OpenMPClauseKind WhereFoundClauseKind) {
-    assert(!Stack.empty() &&
+    assert(!isStackEmpty() &&
            "Not expecting to retrieve components from a empty stack!");
-    auto &MEC = Stack.back().MappedExprComponents[VD];
+    auto &MEC = Stack.back().first.back().MappedExprComponents[VD];
     // Create new entry and append the new components there.
     MEC.Components.resize(MEC.Components.size() + 1);
     MEC.Components.back().append(Components.begin(), Components.end());
@@ -380,23 +428,25 @@ public:
   }
 
   unsigned getNestingLevel() const {
-    assert(!Stack.empty());
-    return Stack.size() - 1;
+    assert(!isStackEmpty());
+    return Stack.back().first.size() - 1;
   }
   void addDoacrossDependClause(OMPDependClause *C, OperatorOffsetTy &OpsOffs) {
-    assert(Stack.size() > 1);
-    assert(isOpenMPWorksharingDirective(Stack[Stack.size() - 2].Directive));
-    Stack[Stack.size() - 2].DoacrossDepends.insert({C, OpsOffs});
+    assert(!isStackEmpty() && Stack.back().first.size() > 1);
+    auto &StackElem = *std::next(Stack.back().first.rbegin());
+    assert(isOpenMPWorksharingDirective(StackElem.Directive));
+    StackElem.DoacrossDepends.insert({C, OpsOffs});
   }
   llvm::iterator_range<DoacrossDependMapTy::const_iterator>
   getDoacrossDependClauses() const {
-    assert(!Stack.empty());
-    if (isOpenMPWorksharingDirective(Stack.back().Directive)) {
-      auto &Ref = Stack.back().DoacrossDepends;
+    assert(!isStackEmpty());
+    auto &StackElem = Stack.back().first.back();
+    if (isOpenMPWorksharingDirective(StackElem.Directive)) {
+      auto &Ref = StackElem.DoacrossDepends;
       return llvm::make_range(Ref.begin(), Ref.end());
     }
-    return llvm::make_range(Stack.back().DoacrossDepends.end(),
-                            Stack.back().DoacrossDepends.end());
+    return llvm::make_range(StackElem.DoacrossDepends.end(),
+                            StackElem.DoacrossDepends.end());
   }
 };
 bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) {
@@ -425,7 +475,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDS
   auto *VD = dyn_cast<VarDecl>(D);
   auto *FD = dyn_cast<FieldDecl>(D);
   DSAVarData DVar;
-  if (Iter == Stack.rend()) {
+  if (isStackEmpty() || Iter == Stack.back().first.rend()) {
     // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
     // in a region but not in construct]
     //  File-scope or namespace-scope variables referenced in called routines
@@ -499,7 +549,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDS
     //  bound to the current team is shared.
     if (isOpenMPTaskingDirective(DVar.DKind)) {
       DSAVarData DVarTemp;
-      auto I = Iter, E = Stack.rend();
+      auto I = Iter, E = Stack.back().first.rend();
       do {
         ++I;
         // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables
@@ -528,12 +578,13 @@ DSAStackTy::DSAVarData DSAStackTy::getDS
 }
 
 Expr *DSAStackTy::addUniqueAligned(ValueDecl *D, Expr *NewDE) {
-  assert(!Stack.empty() && "Data sharing attributes stack is empty");
+  assert(!isStackEmpty() && "Data sharing attributes stack is empty");
   D = getCanonicalDecl(D);
-  auto It = Stack.back().AlignedMap.find(D);
-  if (It == Stack.back().AlignedMap.end()) {
+  auto &StackElem = Stack.back().first.back();
+  auto It = StackElem.AlignedMap.find(D);
+  if (It == StackElem.AlignedMap.end()) {
     assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
-    Stack.back().AlignedMap[D] = NewDE;
+    StackElem.AlignedMap[D] = NewDE;
     return nullptr;
   } else {
     assert(It->second && "Unexpected nullptr expr in the aligned map");
@@ -543,35 +594,43 @@ Expr *DSAStackTy::addUniqueAligned(Value
 }
 
 void DSAStackTy::addLoopControlVariable(ValueDecl *D, VarDecl *Capture) {
-  assert(!Stack.empty() && "Data-sharing attributes stack is empty");
+  assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
   D = getCanonicalDecl(D);
-  Stack.back().LCVMap.insert(
-      {D, LCDeclInfo(Stack.back().LCVMap.size() + 1, Capture)});
+  auto &StackElem = Stack.back().first.back();
+  StackElem.LCVMap.insert(
+      {D, LCDeclInfo(StackElem.LCVMap.size() + 1, Capture)});
 }
 
 DSAStackTy::LCDeclInfo DSAStackTy::isLoopControlVariable(ValueDecl *D) {
-  assert(!Stack.empty() && "Data-sharing attributes stack is empty");
+  assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
   D = getCanonicalDecl(D);
-  return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D]
-                                          : LCDeclInfo(0, nullptr);
+  auto &StackElem = Stack.back().first.back();
+  auto It = StackElem.LCVMap.find(D);
+  if (It != StackElem.LCVMap.end())
+    return It->second;
+  return {0, nullptr};
 }
 
 DSAStackTy::LCDeclInfo DSAStackTy::isParentLoopControlVariable(ValueDecl *D) {
-  assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
+  assert(!isStackEmpty() && Stack.back().first.size() > 1 &&
+         "Data-sharing attributes stack is empty");
   D = getCanonicalDecl(D);
-  return Stack[Stack.size() - 2].LCVMap.count(D) > 0
-             ? Stack[Stack.size() - 2].LCVMap[D]
-             : LCDeclInfo(0, nullptr);
+  auto &StackElem = *std::next(Stack.back().first.rbegin());
+  auto It = StackElem.LCVMap.find(D);
+  if (It != StackElem.LCVMap.end())
+    return It->second;
+  return {0, nullptr};
 }
 
 ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) {
-  assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
-  if (Stack[Stack.size() - 2].LCVMap.size() < I)
+  assert(!isStackEmpty() && Stack.back().first.size() > 1 &&
+         "Data-sharing attributes stack is empty");
+  auto &StackElem = *std::next(Stack.back().first.rbegin());
+  if (StackElem.LCVMap.size() < I)
     return nullptr;
-  for (auto &Pair : Stack[Stack.size() - 2].LCVMap) {
+  for (auto &Pair : StackElem.LCVMap)
     if (Pair.second.first == I)
       return Pair.first;
-  }
   return nullptr;
 }
 
@@ -584,8 +643,8 @@ void DSAStackTy::addDSA(ValueDecl *D, Ex
     Data.RefExpr.setPointer(E);
     Data.PrivateCopy = nullptr;
   } else {
-    assert(!Stack.empty() && "Data-sharing attributes stack is empty");
-    auto &Data = Stack.back().SharingMap[D];
+    assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
+    auto &Data = Stack.back().first.back().SharingMap[D];
     assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) ||
            (A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) ||
            (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) ||
@@ -600,7 +659,7 @@ void DSAStackTy::addDSA(ValueDecl *D, Ex
     Data.RefExpr.setPointerAndInt(E, IsLastprivate);
     Data.PrivateCopy = PrivateCopy;
     if (PrivateCopy) {
-      auto &Data = Stack.back().SharingMap[PrivateCopy->getDecl()];
+      auto &Data = Stack.back().first.back().SharingMap[PrivateCopy->getDecl()];
       Data.Attributes = A;
       Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate);
       Data.PrivateCopy = nullptr;
@@ -610,8 +669,8 @@ void DSAStackTy::addDSA(ValueDecl *D, Ex
 
 bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) {
   D = D->getCanonicalDecl();
-  if (Stack.size() > 1) {
-    reverse_iterator I = Iter, E = Stack.rend();
+  if (!isStackEmpty() && Stack.back().first.size() > 1) {
+    reverse_iterator I = Iter, E = Stack.back().first.rend();
     Scope *TopScope = nullptr;
     while (I != E && !isParallelOrTaskRegion(I->Directive))
       ++I;
@@ -678,7 +737,7 @@ DSAStackTy::DSAVarData DSAStackTy::getTo
     return DVar;
   }
 
-  if (Stack.empty())
+  if (isStackEmpty())
     // Not in OpenMP execution region and top scope was already checked.
     return DVar;
 
@@ -728,8 +787,8 @@ DSAStackTy::DSAVarData DSAStackTy::getTo
 
   // Explicitly specified attributes and local variables with predetermined
   // attributes.
-  auto StartI = std::next(Stack.rbegin());
-  auto EndI = Stack.rend();
+  auto StartI = std::next(Stack.back().first.rbegin());
+  auto EndI = Stack.back().first.rend();
   if (FromParent && StartI != EndI)
     StartI = std::next(StartI);
   auto I = std::prev(StartI);
@@ -745,9 +804,13 @@ DSAStackTy::DSAVarData DSAStackTy::getTo
 
 DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
                                                   bool FromParent) {
+  if (isStackEmpty()) {
+    StackTy::reverse_iterator I;
+    return getDSA(I, D);
+  }
   D = getCanonicalDecl(D);
-  auto StartI = Stack.rbegin();
-  auto EndI = Stack.rend();
+  auto StartI = Stack.back().first.rbegin();
+  auto EndI = Stack.back().first.rend();
   if (FromParent && StartI != EndI)
     StartI = std::next(StartI);
   return getDSA(StartI, D);
@@ -758,9 +821,11 @@ DSAStackTy::hasDSA(ValueDecl *D,
                    const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
                    const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
                    bool FromParent) {
+  if (isStackEmpty())
+    return {};
   D = getCanonicalDecl(D);
-  auto StartI = std::next(Stack.rbegin());
-  auto EndI = Stack.rend();
+  auto StartI = std::next(Stack.back().first.rbegin());
+  auto EndI = Stack.back().first.rend();
   if (FromParent && StartI != EndI)
     StartI = std::next(StartI);
   if (StartI == EndI)
@@ -781,13 +846,15 @@ DSAStackTy::DSAVarData DSAStackTy::hasIn
     ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
     const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
     bool FromParent) {
+  if (isStackEmpty())
+    return {};
   D = getCanonicalDecl(D);
-  auto StartI = std::next(Stack.rbegin());
-  auto EndI = Stack.rend();
+  auto StartI = std::next(Stack.back().first.rbegin());
+  auto EndI = Stack.back().first.rend();
   if (FromParent && StartI != EndI)
     StartI = std::next(StartI);
   if (StartI == EndI || !DPred(StartI->Directive))
-    return DSAVarData();
+    return {};
   DSAVarData DVar = getDSA(StartI, D);
   return CPred(DVar.CKind) ? DVar : DSAVarData();
 }
@@ -797,9 +864,11 @@ bool DSAStackTy::hasExplicitDSA(
     unsigned Level, bool NotLastprivate) {
   if (CPred(ClauseKindMode))
     return true;
+  if (isStackEmpty())
+    return false;
   D = getCanonicalDecl(D);
-  auto StartI = Stack.begin();
-  auto EndI = Stack.end();
+  auto StartI = Stack.back().first.begin();
+  auto EndI = Stack.back().first.end();
   if (std::distance(StartI, EndI) <= (int)Level)
     return false;
   std::advance(StartI, Level);
@@ -812,8 +881,10 @@ bool DSAStackTy::hasExplicitDSA(
 bool DSAStackTy::hasExplicitDirective(
     const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
     unsigned Level) {
-  auto StartI = Stack.begin();
-  auto EndI = Stack.end();
+  if (isStackEmpty())
+    return false;
+  auto StartI = Stack.back().first.begin();
+  auto EndI = Stack.back().first.end();
   if (std::distance(StartI, EndI) <= (int)Level)
     return false;
   std::advance(StartI, Level);
@@ -826,10 +897,10 @@ bool DSAStackTy::hasDirective(
         &DPred,
     bool FromParent) {
   // We look only in the enclosing region.
-  if (Stack.size() < 1)
+  if (isStackEmpty())
     return false;
-  auto StartI = std::next(Stack.rbegin());
-  auto EndI = Stack.rend();
+  auto StartI = std::next(Stack.back().first.rbegin());
+  auto EndI = Stack.back().first.rend();
   if (FromParent && StartI != EndI)
     StartI = std::next(StartI);
   for (auto I = StartI, EE = EndI; I != EE; ++I) {
@@ -845,6 +916,14 @@ void Sema::InitDataSharingAttributesStac
 
 #define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack)
 
+void Sema::pushOpenMPFunctionRegion() {
+  DSAStack->pushFunction();
+}
+
+void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) {
+  DSAStack->popFunction(OldFSI);
+}
+
 bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) {
   assert(LangOpts.OpenMP && "OpenMP is not allowed");
 

Added: cfe/trunk/test/OpenMP/capturing_in_templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/capturing_in_templates.cpp?rev=301416&view=auto
==============================================================================
--- cfe/trunk/test/OpenMP/capturing_in_templates.cpp (added)
+++ cfe/trunk/test/OpenMP/capturing_in_templates.cpp Wed Apr 26 10:06:24 2017
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-ibm-linux-gnu -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+template <typename T1, typename T2>
+struct pair {
+  T1 t1;
+  T2 t2;
+  pair(T1 t1, T2 t2) : t1(t1), t2(t2) {}
+};
+
+template <typename T1, typename T2>
+pair<T1, T2> make_pair(T1 &&t1, T2 &&t2) {
+  return {t1, t2};
+}
+
+// CHECK-LABEL: @main
+int main(int argc, char **argv) {
+// CHECK: call i32 @__tgt_target(i32 -1, i8* [[OFFLOAD:@[^.]+]].region_id, i32 0, i8** null, i8** null, i64* null, i32* null)
+#pragma omp target
+ {
+    for (int i = 0; i < 64; ++i) {
+      for (int j = 0; j < 64; ++j) {
+        auto foo = make_pair(i * i, j * j);
+      }
+    }
+  }
+  return 0;
+}
+
+// CHECK: define internal void [[OFFLOAD]](
+// CHECK: call {{.+}} @{{.*}}make_pair




More information about the cfe-commits mailing list