[OPENMP] Parsing and sema analysis for 'omp task' directive.

llvm-svn: 212804
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index a7ad809..f065014 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -139,21 +139,22 @@
 
   /// \brief Returns data sharing attributes from top of the stack for the
   /// specified declaration.
-  DSAVarData getTopDSA(VarDecl *D);
+  DSAVarData getTopDSA(VarDecl *D, bool FromParent);
   /// \brief Returns data-sharing attributes for the specified declaration.
-  DSAVarData getImplicitDSA(VarDecl *D);
+  DSAVarData getImplicitDSA(VarDecl *D, bool FromParent);
   /// \brief Checks if the specified variables has data-sharing attributes which
   /// match specified \a CPred predicate in any directive which matches \a DPred
   /// predicate.
   template <class ClausesPredicate, class DirectivesPredicate>
   DSAVarData hasDSA(VarDecl *D, ClausesPredicate CPred,
-                    DirectivesPredicate DPred);
+                    DirectivesPredicate DPred, bool FromParent);
   /// \brief Checks if the specified variables has data-sharing attributes which
   /// match specified \a CPred predicate in any innermost directive which
   /// matches \a DPred predicate.
   template <class ClausesPredicate, class DirectivesPredicate>
   DSAVarData hasInnermostDSA(VarDecl *D, ClausesPredicate CPred,
-                             DirectivesPredicate DPred);
+                             DirectivesPredicate DPred,
+                             bool FromParent);
 
   /// \brief Returns currently analyzed directive.
   OpenMPDirectiveKind getCurrentDirective() const {
@@ -186,7 +187,7 @@
 
   /// \brief Checks if the specified variable is a threadprivate.
   bool isThreadPrivate(VarDecl *D) {
-    DSAVarData DVar = getTopDSA(D);
+    DSAVarData DVar = getTopDSA(D, false);
     return isOpenMPThreadPrivate(DVar.CKind);
   }
 
@@ -194,6 +195,10 @@
   Scope *getCurScope() { return Stack.back().CurScope; }
   SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; }
 };
+bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) {
+  return isOpenMPParallelDirective(DKind) || DKind == OMPD_task ||
+         DKind == OMPD_unknown;
+}
 } // namespace
 
 DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
@@ -234,6 +239,7 @@
   if (Iter->SharingMap.count(D)) {
     DVar.RefExpr = Iter->SharingMap[D].RefExpr;
     DVar.CKind = Iter->SharingMap[D].Attributes;
+    DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
     return DVar;
   }
 
@@ -282,7 +288,7 @@
           DVar.CKind = OMPC_firstprivate;
           return DVar;
         }
-        if (isOpenMPParallelDirective(I->Directive))
+        if (isParallelOrTaskRegion(I->Directive))
           break;
       }
       DVar.DKind = OMPD_task;
@@ -328,7 +334,7 @@
   if (Stack.size() > 2) {
     reverse_iterator I = Iter, E = std::prev(Stack.rend());
     Scope *TopScope = nullptr;
-    while (I != E && !isOpenMPParallelDirective(I->Directive)) {
+    while (I != E && !isParallelOrTaskRegion(I->Directive)) {
       ++I;
     }
     if (I == E)
@@ -343,7 +349,7 @@
   return false;
 }
 
-DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {
+DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) {
   DSAVarData DVar;
 
   // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
@@ -363,9 +369,15 @@
   // in a Construct, C/C++, predetermined, p.1]
   // Variables with automatic storage duration that are declared in a scope
   // inside the construct are private.
-  OpenMPDirectiveKind Kind = getCurrentDirective();
-  if (!isOpenMPParallelDirective(Kind)) {
-    if (isOpenMPLocal(D, std::next(Stack.rbegin())) && D->isLocalVarDecl() &&
+  OpenMPDirectiveKind Kind =
+      FromParent ? getParentDirective() : getCurrentDirective();
+  auto StartI = std::next(Stack.rbegin());
+  auto EndI = std::prev(Stack.rend());
+  if (FromParent && StartI != EndI) {
+    StartI = std::next(StartI);
+  }
+  if (!isParallelOrTaskRegion(Kind)) {
+    if (isOpenMPLocal(D, StartI) && D->isLocalVarDecl() &&
         (D->getStorageClass() == SC_Auto || D->getStorageClass() == SC_None)) {
       DVar.CKind = OMPC_private;
       return DVar;
@@ -378,8 +390,8 @@
   if (D->isStaticDataMember()) {
     // Variables with const-qualified type having no mutable member may be
     // listed in a firstprivate clause, even if they are static data members.
-    DSAVarData DVarTemp =
-        hasDSA(D, MatchesAnyClause(OMPC_firstprivate), MatchesAlways());
+    DSAVarData DVarTemp = hasDSA(D, MatchesAnyClause(OMPC_firstprivate),
+                                 MatchesAlways(), FromParent);
     if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr)
       return DVar;
 
@@ -403,8 +415,8 @@
       !(SemaRef.getLangOpts().CPlusPlus && RD && RD->hasMutableFields())) {
     // Variables with const-qualified type having no mutable member may be
     // listed in a firstprivate clause, even if they are static data members.
-    DSAVarData DVarTemp =
-        hasDSA(D, MatchesAnyClause(OMPC_firstprivate), MatchesAlways());
+    DSAVarData DVarTemp = hasDSA(D, MatchesAnyClause(OMPC_firstprivate),
+                                 MatchesAlways(), FromParent);
     if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr)
       return DVar;
 
@@ -423,25 +435,36 @@
 
   // Explicitly specified attributes and local variables with predetermined
   // attributes.
-  if (Stack.back().SharingMap.count(D)) {
-    DVar.RefExpr = Stack.back().SharingMap[D].RefExpr;
-    DVar.CKind = Stack.back().SharingMap[D].Attributes;
+  auto I = std::prev(StartI);
+  if (I->SharingMap.count(D)) {
+    DVar.RefExpr = I->SharingMap[D].RefExpr;
+    DVar.CKind = I->SharingMap[D].Attributes;
+    DVar.ImplicitDSALoc = I->DefaultAttrLoc;
   }
 
   return DVar;
 }
 
-DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D) {
-  return getDSA(std::next(Stack.rbegin()), D);
+DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D, bool FromParent) {
+  auto StartI = Stack.rbegin();
+  auto EndI = std::prev(Stack.rend());
+  if (FromParent && StartI != EndI) {
+    StartI = std::next(StartI);
+  }
+  return getDSA(StartI, D);
 }
 
 template <class ClausesPredicate, class DirectivesPredicate>
 DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, ClausesPredicate CPred,
-                                          DirectivesPredicate DPred) {
-  for (StackTy::reverse_iterator I = std::next(Stack.rbegin()),
-                                 E = std::prev(Stack.rend());
-       I != E; ++I) {
-    if (!DPred(I->Directive))
+                                          DirectivesPredicate DPred,
+                                          bool FromParent) {
+  auto StartI = std::next(Stack.rbegin());
+  auto EndI = std::prev(Stack.rend());
+  if (FromParent && StartI != EndI) {
+    StartI = std::next(StartI);
+  }
+  for (auto I = StartI, EE = EndI; I != EE; ++I) {
+    if (!DPred(I->Directive) && !isParallelOrTaskRegion(I->Directive))
       continue;
     DSAVarData DVar = getDSA(I, D);
     if (CPred(DVar.CKind))
@@ -451,12 +474,17 @@
 }
 
 template <class ClausesPredicate, class DirectivesPredicate>
-DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(VarDecl *D,
-                                                   ClausesPredicate CPred,
-                                                   DirectivesPredicate DPred) {
-  for (auto I = Stack.rbegin(), EE = std::prev(Stack.rend()); I != EE; ++I) {
+DSAStackTy::DSAVarData
+DSAStackTy::hasInnermostDSA(VarDecl *D, ClausesPredicate CPred,
+                            DirectivesPredicate DPred, bool FromParent) {
+  auto StartI = std::next(Stack.rbegin());
+  auto EndI = std::prev(Stack.rend());
+  if (FromParent && StartI != EndI) {
+    StartI = std::next(StartI);
+  }
+  for (auto I = StartI, EE = EndI; I != EE; ++I) {
     if (!DPred(I->Directive))
-      continue;
+      break;
     DSAVarData DVar = getDSA(I, D);
     if (CPred(DVar.CKind))
       return DVar;
@@ -493,7 +521,7 @@
           if (VarRef->isValueDependent() || VarRef->isTypeDependent())
             continue;
           auto VD = cast<VarDecl>(cast<DeclRefExpr>(VarRef)->getDecl());
-          auto DVar = DSAStack->getTopDSA(VD);
+          auto DVar = DSAStack->getTopDSA(VD, false);
           if (DVar.CKind == OMPC_lastprivate) {
             SourceLocation ELoc = VarRef->getExprLoc();
             auto Type = VarRef->getType();
@@ -795,10 +823,12 @@
     PDSA_LoopIterVarLastprivate,
     PDSA_ConstVarShared,
     PDSA_GlobalVarShared,
+    PDSA_TaskVarFirstprivate,
     PDSA_LocalVarPrivate,
     PDSA_Implicit
   } Reason = PDSA_Implicit;
   bool ReportHint = false;
+  auto ReportLoc = VD->getLocation();
   if (IsLoopIterVar) {
     if (DVar.CKind == OMPC_private)
       Reason = PDSA_LoopIterVarPrivate;
@@ -806,6 +836,9 @@
       Reason = PDSA_LoopIterVarLastprivate;
     else
       Reason = PDSA_LoopIterVarLinear;
+  } else if (DVar.DKind == OMPD_task && DVar.CKind == OMPC_firstprivate) {
+    Reason = PDSA_TaskVarFirstprivate;
+    ReportLoc = DVar.ImplicitDSALoc;
   } else if (VD->isStaticLocal())
     Reason = PDSA_StaticLocalVarShared;
   else if (VD->isStaticDataMember())
@@ -819,7 +852,7 @@
     Reason = PDSA_LocalVarPrivate;
   }
   if (Reason != PDSA_Implicit) {
-    SemaRef.Diag(VD->getLocation(), diag::note_omp_predetermined_dsa)
+    SemaRef.Diag(ReportLoc, diag::note_omp_predetermined_dsa)
         << Reason << ReportHint
         << getOpenMPDirectiveName(Stack->getCurrentDirective());
   } else if (DVar.ImplicitDSALoc.isValid()) {
@@ -839,27 +872,23 @@
 
 public:
   void VisitDeclRefExpr(DeclRefExpr *E) {
-    if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) {
+    if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
       // Skip internally declared variables.
       if (VD->isLocalVarDecl() && !CS->capturesVariable(VD))
         return;
 
-      SourceLocation ELoc = E->getExprLoc();
+      auto DVar = Stack->getTopDSA(VD, false);
+      // Check if the variable has explicit DSA set and stop analysis if it so.
+      if (DVar.RefExpr) return;
 
-      OpenMPDirectiveKind DKind = Stack->getCurrentDirective();
-      DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD);
-      if (DVar.CKind != OMPC_unknown) {
-        if (DKind == OMPD_task && DVar.CKind != OMPC_shared &&
-            !Stack->isThreadPrivate(VD) && !DVar.RefExpr)
-          ImplicitFirstprivate.push_back(DVar.RefExpr);
-        return;
-      }
+      auto ELoc = E->getExprLoc();
+      auto DKind = Stack->getCurrentDirective();
       // The default(none) clause requires that each variable that is referenced
       // in the construct, and does not have a predetermined data-sharing
       // attribute, must have its data-sharing attribute explicitly determined
       // by being listed in a data-sharing attribute clause.
       if (DVar.CKind == OMPC_unknown && Stack->getDefaultDSA() == DSA_none &&
-          (isOpenMPParallelDirective(DKind) || DKind == OMPD_task) &&
+          isParallelOrTaskRegion(DKind) &&
           VarsWithInheritedDSA.count(VD) == 0) {
         VarsWithInheritedDSA[VD] = E;
         return;
@@ -870,7 +899,11 @@
       //  enclosing worksharing or parallel construct may not be accessed in an
       //  explicit task.
       DVar = Stack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction),
-                                    MatchesAlways());
+                                    [](OpenMPDirectiveKind K) -> bool {
+                                      return isOpenMPParallelDirective(K) ||
+                                             isOpenMPWorksharingDirective(K);
+                                    },
+                                    false);
       if (DKind == OMPD_task && DVar.CKind == OMPC_reduction) {
         ErrorFound = true;
         SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task);
@@ -879,24 +912,27 @@
       }
 
       // Define implicit data-sharing attributes for task.
-      DVar = Stack->getImplicitDSA(VD);
+      DVar = Stack->getImplicitDSA(VD, false);
       if (DKind == OMPD_task && DVar.CKind != OMPC_shared)
-        ImplicitFirstprivate.push_back(DVar.RefExpr);
+        ImplicitFirstprivate.push_back(E);
     }
   }
   void VisitOMPExecutableDirective(OMPExecutableDirective *S) {
-    for (auto C : S->clauses())
-      if (C)
-        for (StmtRange R = C->children(); R; ++R)
-          if (Stmt *Child = *R)
-            Visit(Child);
+    for (auto *C : S->clauses()) {
+      // Skip analysis of arguments of implicitly defined firstprivate clause
+      // for task directives.
+      if (C && (!isa<OMPFirstprivateClause>(C) || C->getLocStart().isValid()))
+        for (auto *CC : C->children()) {
+          if (CC)
+            Visit(CC);
+        }
+    }
   }
   void VisitStmt(Stmt *S) {
-    for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I != E;
-         ++I)
-      if (Stmt *Child = *I)
-        if (!isa<OMPExecutableDirective>(Child))
-          Visit(Child);
+    for (auto *C : S->children()) {
+      if (C && !isa<OMPExecutableDirective>(C))
+        Visit(C);
+    }
   }
 
   bool isErrorFound() { return ErrorFound; }
@@ -984,8 +1020,15 @@
                              Params);
     break;
   }
+  case OMPD_task: {
+    Sema::CapturedParamNameType Params[] = {
+        std::make_pair(StringRef(), QualType()) // __context with shared vars
+    };
+    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+                             Params);
+    break;
+  }
   case OMPD_threadprivate:
-  case OMPD_task:
     llvm_unreachable("OpenMP Directive is not allowed");
   case OMPD_unknown:
     llvm_unreachable("Unknown OpenMP directive");
@@ -1007,6 +1050,7 @@
   // | parallel         | single          | *                                  |
   // | parallel         | parallel for    | *                                  |
   // | parallel         |parallel sections| *                                  |
+  // | parallel         | task            | *                                  |
   // +------------------+-----------------+------------------------------------+
   // | for              | parallel        | *                                  |
   // | for              | for             | +                                  |
@@ -1016,6 +1060,7 @@
   // | for              | single          | +                                  |
   // | for              | parallel for    | *                                  |
   // | for              |parallel sections| *                                  |
+  // | for              | task            | *                                  |
   // +------------------+-----------------+------------------------------------+
   // | simd             | parallel        |                                    |
   // | simd             | for             |                                    |
@@ -1025,6 +1070,7 @@
   // | simd             | single          |                                    |
   // | simd             | parallel for    |                                    |
   // | simd             |parallel sections|                                    |
+  // | simd             | task            |                                    |
   // +------------------+-----------------+------------------------------------+
   // | sections         | parallel        | *                                  |
   // | sections         | for             | +                                  |
@@ -1034,6 +1080,7 @@
   // | sections         | single          | +                                  |
   // | sections         | parallel for    | *                                  |
   // | sections         |parallel sections| *                                  |
+  // | sections         | task            | *                                  |
   // +------------------+-----------------+------------------------------------+
   // | section          | parallel        | *                                  |
   // | section          | for             | +                                  |
@@ -1043,6 +1090,7 @@
   // | section          | single          | +                                  |
   // | section          | parallel for    | *                                  |
   // | section          |parallel sections| *                                  |
+  // | section          | task            | *                                  |
   // +------------------+-----------------+------------------------------------+
   // | single           | parallel        | *                                  |
   // | single           | for             | +                                  |
@@ -1052,6 +1100,7 @@
   // | single           | single          | +                                  |
   // | single           | parallel for    | *                                  |
   // | single           |parallel sections| *                                  |
+  // | single           | task            | *                                  |
   // +------------------+-----------------+------------------------------------+
   // | parallel for     | parallel        | *                                  |
   // | parallel for     | for             | +                                  |
@@ -1061,6 +1110,7 @@
   // | parallel for     | single          | +                                  |
   // | parallel for     | parallel for    | *                                  |
   // | parallel for     |parallel sections| *                                  |
+  // | parallel for     | task            | *                                  |
   // +------------------+-----------------+------------------------------------+
   // | parallel sections| parallel        | *                                  |
   // | parallel sections| for             | +                                  |
@@ -1070,6 +1120,17 @@
   // | parallel sections| single          | +                                  |
   // | parallel sections| parallel for    | *                                  |
   // | parallel sections|parallel sections| *                                  |
+  // | parallel sections| task            | *                                  |
+  // +------------------+-----------------+------------------------------------+
+  // | task             | parallel        | *                                  |
+  // | task             | for             | +                                  |
+  // | task             | simd            | *                                  |
+  // | task             | sections        | +                                  |
+  // | task             | section         | +                                  | 
+  // | task             | single          | +                                  |
+  // | task             | parallel for    | *                                  |
+  // | task             |parallel sections| *                                  |
+  // | task             | task            | *                                  |
   // +------------------+-----------------+------------------------------------+
   if (Stack->getCurScope()) {
     auto ParentRegion = Stack->getParentDirective();
@@ -1103,8 +1164,9 @@
       // A worksharing region may not be closely nested inside a worksharing,
       // explicit task, critical, ordered, atomic, or master region.
       // TODO
-      NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) &&
-                          !isOpenMPSimdDirective(ParentRegion);
+      NestingProhibited = (isOpenMPWorksharingDirective(ParentRegion) &&
+                           !isOpenMPSimdDirective(ParentRegion)) ||
+                          ParentRegion == OMPD_task;
       ShouldBeInParallelRegion = true;
     }
     if (NestingProhibited) {
@@ -1184,8 +1246,11 @@
     Res = ActOnOpenMPParallelSectionsDirective(ClausesWithImplicit, AStmt,
                                                StartLoc, EndLoc);
     break;
-  case OMPD_threadprivate:
   case OMPD_task:
+    Res =
+        ActOnOpenMPTaskDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc);
+    break;
+  case OMPD_threadprivate:
     llvm_unreachable("OpenMP Directive is not allowed");
   case OMPD_unknown:
     llvm_unreachable("Unknown OpenMP directive");
@@ -1651,7 +1716,7 @@
   // constant-linear-step that is the increment of the associated for-loop.
   // The loop iteration variable(s) in the associated for-loop(s) of a for or
   // parallel for construct may be listed in a private or lastprivate clause.
-  DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var);
+  DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var, false);
   auto PredeterminedCKind =
       isOpenMPSimdDirective(DKind)
           ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate)
@@ -1898,6 +1963,23 @@
                                               Clauses, AStmt);
 }
 
+StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses,
+                                          Stmt *AStmt, SourceLocation StartLoc,
+                                          SourceLocation EndLoc) {
+  assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+  CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+  // 1.2.2 OpenMP Language Terminology
+  // Structured block - An executable statement with a single entry at the
+  // top and a single exit at the bottom.
+  // The point of exit cannot be a branch out of the structured block.
+  // longjmp() and throw() must not violate the entry/exit criteria.
+  CS->getCapturedDecl()->setNothrow();
+
+  getCurFunction()->setHasBranchProtectedScope();
+
+  return OMPTaskDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
+}
+
 OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
                                              SourceLocation StartLoc,
                                              SourceLocation LParenLoc,
@@ -2494,7 +2576,7 @@
     //  listed below. For these exceptions only, listing a predetermined
     //  variable in a data-sharing attribute clause is allowed and overrides
     //  the variable's predetermined data-sharing attributes.
-    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
     if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private) {
       Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
                                           << getOpenMPClauseName(OMPC_private);
@@ -2517,6 +2599,10 @@
                                                SourceLocation LParenLoc,
                                                SourceLocation EndLoc) {
   SmallVector<Expr *, 8> Vars;
+  bool IsImplicitClause =
+      StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid();
+  auto ImplicitClauseLoc = DSAStack->getConstructLoc();
+
   for (auto &RefExpr : VarList) {
     assert(RefExpr && "NULL expr in OpenMP firstprivate clause.");
     if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
@@ -2525,7 +2611,8 @@
       continue;
     }
 
-    SourceLocation ELoc = RefExpr->getExprLoc();
+    SourceLocation ELoc = IsImplicitClause ? ImplicitClauseLoc
+                                           : RefExpr->getExprLoc();
     // OpenMP [2.1, C/C++]
     //  A list item is a variable name.
     // OpenMP  [2.9.3.3, Restrictions, p.1]
@@ -2554,8 +2641,15 @@
       continue;
     }
     if (Type->isReferenceType()) {
-      Diag(ELoc, diag::err_omp_clause_ref_type_arg)
-          << getOpenMPClauseName(OMPC_firstprivate) << Type;
+      if (IsImplicitClause) {
+        Diag(ImplicitClauseLoc,
+             diag::err_omp_task_predetermined_firstprivate_ref_type_arg)
+            << Type;
+        Diag(RefExpr->getExprLoc(), diag::note_used_here);
+      } else {
+        Diag(ELoc, diag::err_omp_clause_ref_type_arg)
+            << getOpenMPClauseName(OMPC_firstprivate) << Type;
+      }
       bool IsDecl =
           VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
       Diag(VD->getLocation(),
@@ -2583,8 +2677,15 @@
                                  InitializedEntity::InitializeTemporary(Type),
                                  CD->getAccess(), PD) == AR_inaccessible ||
           CD->isDeleted()) {
-        Diag(ELoc, diag::err_omp_required_method)
-            << getOpenMPClauseName(OMPC_firstprivate) << 1;
+        if (IsImplicitClause) {
+          Diag(ImplicitClauseLoc,
+               diag::err_omp_task_predetermined_firstprivate_required_method)
+              << 0;
+          Diag(RefExpr->getExprLoc(), diag::note_used_here);
+        } else {
+          Diag(ELoc, diag::err_omp_required_method)
+              << getOpenMPClauseName(OMPC_firstprivate) << 1;
+        }
         bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
                       VarDecl::DeclarationOnly;
         Diag(VD->getLocation(),
@@ -2600,8 +2701,15 @@
       if (DD) {
         if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
             DD->isDeleted()) {
-          Diag(ELoc, diag::err_omp_required_method)
-              << getOpenMPClauseName(OMPC_firstprivate) << 4;
+          if (IsImplicitClause) {
+            Diag(ImplicitClauseLoc,
+                 diag::err_omp_task_predetermined_firstprivate_required_method)
+                << 1;
+            Diag(RefExpr->getExprLoc(), diag::note_used_here);
+          } else {
+            Diag(ELoc, diag::err_omp_required_method)
+                << getOpenMPClauseName(OMPC_firstprivate) << 4;
+          }
           bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
                         VarDecl::DeclarationOnly;
           Diag(VD->getLocation(),
@@ -2615,10 +2723,9 @@
       }
     }
 
-    // If StartLoc and EndLoc are invalid - this is an implicit firstprivate
-    // variable and it was checked already.
-    if (StartLoc.isValid() && EndLoc.isValid()) {
-      DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+    // If an implicit firstprivate variable found it was checked already.
+    if (!IsImplicitClause) {
+      DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
       Type = Type.getNonReferenceType().getCanonicalType();
       bool IsConstant = Type.isConstant(Context);
       Type = Context.getBaseElementType(Type);
@@ -2663,8 +2770,10 @@
       //  to any of the parallel regions arising from the parallel construct.
       if (isOpenMPWorksharingDirective(CurrDir) &&
           !isOpenMPParallelDirective(CurrDir)) {
-        DVar = DSAStack->getImplicitDSA(VD);
-        if (DVar.CKind != OMPC_shared) {
+        DVar = DSAStack->getImplicitDSA(VD, true);
+        if (DVar.CKind != OMPC_shared &&
+            (isOpenMPParallelDirective(DVar.DKind) ||
+             DVar.DKind == OMPD_unknown)) {
           Diag(ELoc, diag::err_omp_required_access)
               << getOpenMPClauseName(OMPC_firstprivate)
               << getOpenMPClauseName(OMPC_shared);
@@ -2678,13 +2787,28 @@
       //  construct if any of the worksharing or task regions arising from the
       //  worksharing or task construct ever bind to any of the parallel regions
       //  arising from the parallel construct.
-      // TODO
       // OpenMP [2.9.3.4, Restrictions, p.4]
       //  A list item that appears in a reduction clause in worksharing
       //  construct must not appear in a firstprivate clause in a task construct
       //  encountered during execution of any of the worksharing regions arising
       //  from the worksharing construct.
-      // TODO
+      if (CurrDir == OMPD_task) {
+        DVar =
+            DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction),
+                                      [](OpenMPDirectiveKind K) -> bool {
+                                        return isOpenMPParallelDirective(K) ||
+                                               isOpenMPWorksharingDirective(K);
+                                      },
+                                      false);
+        if (DVar.CKind == OMPC_reduction &&
+            (isOpenMPParallelDirective(DVar.DKind) ||
+             isOpenMPWorksharingDirective(DVar.DKind))) {
+          Diag(ELoc, diag::err_omp_parallel_reduction_in_task_firstprivate)
+              << getOpenMPDirectiveName(DVar.DKind);
+          ReportOriginalDSA(*this, DSAStack, VD, DVar);
+          continue;
+        }
+      }
     }
 
     DSAStack->addDSA(VD, DE, OMPC_firstprivate);
@@ -2755,7 +2879,7 @@
     //  Variables with the predetermined data-sharing attributes may not be
     //  listed in data-sharing attributes clauses, except for the cases
     //  listed below.
-    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
     if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate &&
         DVar.CKind != OMPC_firstprivate &&
         (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
@@ -2775,7 +2899,7 @@
     // regions.
     if (isOpenMPWorksharingDirective(CurrDir) &&
         !isOpenMPParallelDirective(CurrDir)) {
-      DVar = DSAStack->getImplicitDSA(VD);
+      DVar = DSAStack->getImplicitDSA(VD, true);
       if (DVar.CKind != OMPC_shared) {
         Diag(ELoc, diag::err_omp_required_access)
             << getOpenMPClauseName(OMPC_lastprivate)
@@ -2895,7 +3019,7 @@
     //  listed below. For these exceptions only, listing a predetermined
     //  variable in a data-sharing attribute clause is allowed and overrides
     //  the variable's predetermined data-sharing attributes.
-    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
     if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared &&
         DVar.RefExpr) {
       Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
@@ -2921,13 +3045,13 @@
 public:
   bool VisitDeclRefExpr(DeclRefExpr *E) {
     if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) {
-      DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD);
+      DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, false);
       if (DVar.CKind == OMPC_shared && !DVar.RefExpr)
         return false;
       if (DVar.CKind != OMPC_unknown)
         return true;
       DSAStackTy::DSAVarData DVarPrivate =
-          Stack->hasDSA(VD, isOpenMPPrivate, MatchesAlways());
+          Stack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), false);
       if (DVarPrivate.CKind != OMPC_unknown)
         return true;
       return false;
@@ -3145,7 +3269,7 @@
     //  Any number of reduction clauses can be specified on the directive,
     //  but a list item can appear only once in the reduction clauses for that
     //  directive.
-    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
     if (DVar.CKind == OMPC_reduction) {
       Diag(ELoc, diag::err_omp_once_referenced)
           << getOpenMPClauseName(OMPC_reduction);
@@ -3167,7 +3291,7 @@
     OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
     if (isOpenMPWorksharingDirective(CurrDir) &&
         !isOpenMPParallelDirective(CurrDir)) {
-      DVar = DSAStack->getImplicitDSA(VD);
+      DVar = DSAStack->getImplicitDSA(VD, true);
       if (DVar.CKind != OMPC_shared) {
         Diag(ELoc, diag::err_omp_required_access)
             << getOpenMPClauseName(OMPC_reduction)
@@ -3275,7 +3399,7 @@
     //  A list-item cannot appear in more than one linear clause.
     //  A list-item that appears in a linear clause cannot appear in any
     //  other data-sharing attribute clause.
-    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
     if (DVar.RefExpr) {
       Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
                                           << getOpenMPClauseName(OMPC_linear);
@@ -3558,7 +3682,7 @@
     //  A list item that appears in a copyprivate clause may not appear in a
     //  private or firstprivate clause on the single construct.
     if (!DSAStack->isThreadPrivate(VD)) {
-      auto DVar = DSAStack->getTopDSA(VD);
+      auto DVar = DSAStack->getTopDSA(VD, false);
       if (DVar.CKind != OMPC_copyprivate && DVar.CKind != OMPC_unknown &&
           !(DVar.CKind == OMPC_private && !DVar.RefExpr)) {
         Diag(ELoc, diag::err_omp_wrong_dsa)
@@ -3572,7 +3696,7 @@
       //  All list items that appear in a copyprivate clause must be either
       //  threadprivate or private in the enclosing context.
       if (DVar.CKind == OMPC_unknown) {
-        DVar = DSAStack->getImplicitDSA(VD);
+        DVar = DSAStack->getImplicitDSA(VD, false);
         if (DVar.CKind == OMPC_shared) {
           Diag(ELoc, diag::err_omp_required_access)
               << getOpenMPClauseName(OMPC_copyprivate)