[OPENMP] Fix handling of OpenMP code during template instantiation.
authorAlexey Bataev <a.bataev@hotmail.com>
Wed, 26 Apr 2017 15:06:24 +0000 (15:06 +0000)
committerAlexey Bataev <a.bataev@hotmail.com>
Wed, 26 Apr 2017 15:06:24 +0000 (15:06 +0000)
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.

llvm-svn: 301416

clang/include/clang/Sema/Sema.h
clang/lib/Sema/Sema.cpp
clang/lib/Sema/SemaOpenMP.cpp
clang/test/OpenMP/capturing_in_templates.cpp [new file with mode: 0644]

index d72193e..0f16cb9 100644 (file)
@@ -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.
index 950f040..94e792c 100644 (file)
@@ -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 AnalysisBasedWarnings::Policy *WP,
   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);
index c384d5f..fb13669 100644 (file)
@@ -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::getDSA(StackTy::reverse_iterator &Iter,
   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::getDSA(StackTy::reverse_iterator &Iter,
     //  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::getDSA(StackTy::reverse_iterator &Iter,
 }
 
 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(ValueDecl *D, Expr *NewDE) {
 }
 
 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, Expr *E, OpenMPClauseKind A,
     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, Expr *E, OpenMPClauseKind A,
     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, Expr *E, OpenMPClauseKind A,
 
 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::getTopDSA(ValueDecl *D, bool FromParent) {
     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::getTopDSA(ValueDecl *D, bool FromParent) {
 
   // 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::getTopDSA(ValueDecl *D, bool FromParent) {
 
 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::hasInnermostDSA(
     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::InitDataSharingAttributesStack() {
 
 #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");
 
diff --git a/clang/test/OpenMP/capturing_in_templates.cpp b/clang/test/OpenMP/capturing_in_templates.cpp
new file mode 100644 (file)
index 0000000..526361b
--- /dev/null
@@ -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