diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2014-11-24 18:11:16 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2014-11-24 18:11:16 +0000 | 
| commit | 59d1ed5b206db2a86b3b5bb851f393c43b568ce2 (patch) | |
| tree | d4426858455f04d0d8c25a2f9eb9ea5582ffe1b6 /contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp | |
| parent | 91bc56ed825ba56b3cc264aa5c95ab84f86832ab (diff) | |
| parent | 9f4dbff6669c8037f3b036bcf580d14f1a4f12a5 (diff) | |
Notes
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp')
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp | 3628 | 
1 files changed, 3284 insertions, 344 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp index c63caf46b9e0..7f2af68e55d5 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp @@ -1,4 +1,4 @@ -//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ----------===// +//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ---------===//  //  //                     The LLVM Compiler Infrastructure  // @@ -12,19 +12,20 @@  ///  //===----------------------------------------------------------------------===// -#include "clang/Basic/OpenMPKinds.h" +#include "clang/AST/ASTContext.h"  #include "clang/AST/Decl.h"  #include "clang/AST/DeclCXX.h"  #include "clang/AST/DeclOpenMP.h"  #include "clang/AST/StmtCXX.h"  #include "clang/AST/StmtOpenMP.h"  #include "clang/AST/StmtVisitor.h" +#include "clang/Basic/OpenMPKinds.h"  #include "clang/Lex/Preprocessor.h"  #include "clang/Sema/Initialization.h" -#include "clang/Sema/SemaInternal.h"  #include "clang/Sema/Lookup.h"  #include "clang/Sema/Scope.h"  #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h"  using namespace clang;  //===----------------------------------------------------------------------===// @@ -34,11 +35,31 @@ using namespace clang;  namespace {  /// \brief Default data sharing attributes, which can be applied to directive.  enum DefaultDataSharingAttributes { -  DSA_unspecified = 0,   /// \brief Data sharing attribute not specified. -  DSA_none = 1 << 0,     /// \brief Default data sharing attribute 'none'. -  DSA_shared = 1 << 1    /// \brief Default data sharing attribute 'shared'. +  DSA_unspecified = 0, /// \brief Data sharing attribute not specified. +  DSA_none = 1 << 0,   /// \brief Default data sharing attribute 'none'. +  DSA_shared = 1 << 1  /// \brief Default data sharing attribute 'shared'. +}; + +template <class T> struct MatchesAny { +  explicit MatchesAny(ArrayRef<T> Arr) : Arr(std::move(Arr)) {} +  bool operator()(T Kind) { +    for (auto KindEl : Arr) +      if (KindEl == Kind) +        return true; +    return false; +  } + +private: +  ArrayRef<T> Arr; +}; +struct MatchesAlways { +  MatchesAlways() {} +  template <class T> bool operator()(T) { return true; }  }; +typedef MatchesAny<OpenMPClauseKind> MatchesAnyClause; +typedef MatchesAny<OpenMPDirectiveKind> MatchesAnyDirective; +  /// \brief Stack for tracking declarations used in OpenMP directives and  /// clauses and their data-sharing attributes.  class DSAStackTy { @@ -47,47 +68,60 @@ public:      OpenMPDirectiveKind DKind;      OpenMPClauseKind CKind;      DeclRefExpr *RefExpr; -    DSAVarData() : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(0) { } +    SourceLocation ImplicitDSALoc; +    DSAVarData() +        : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(nullptr), +          ImplicitDSALoc() {}    }; +  private:    struct DSAInfo {      OpenMPClauseKind Attributes;      DeclRefExpr *RefExpr;    };    typedef llvm::SmallDenseMap<VarDecl *, DSAInfo, 64> DeclSAMapTy; +  typedef llvm::SmallDenseMap<VarDecl *, DeclRefExpr *, 64> AlignedMapTy;    struct SharingMapTy {      DeclSAMapTy SharingMap; +    AlignedMapTy AlignedMap;      DefaultDataSharingAttributes DefaultAttr; +    SourceLocation DefaultAttrLoc;      OpenMPDirectiveKind Directive;      DeclarationNameInfo DirectiveName;      Scope *CurScope; -    SharingMapTy(OpenMPDirectiveKind DKind, -                 const DeclarationNameInfo &Name, -                 Scope *CurScope) -      : SharingMap(), DefaultAttr(DSA_unspecified), Directive(DKind), -        DirectiveName(Name), CurScope(CurScope) { } +    SourceLocation ConstructLoc; +    SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, +                 Scope *CurScope, SourceLocation Loc) +        : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified), +          Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope), +          ConstructLoc(Loc) {}      SharingMapTy() -      : SharingMap(), DefaultAttr(DSA_unspecified), -        Directive(OMPD_unknown), DirectiveName(), -        CurScope(0) { } +        : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified), +          Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr), +          ConstructLoc() {}    };    typedef SmallVector<SharingMapTy, 64> StackTy;    /// \brief Stack of used declaration and their data-sharing attributes.    StackTy Stack; -  Sema &Actions; +  Sema &SemaRef;    typedef SmallVector<SharingMapTy, 8>::reverse_iterator reverse_iterator;    DSAVarData getDSA(StackTy::reverse_iterator Iter, VarDecl *D); + +  /// \brief Checks if the variable is a local for OpenMP region. +  bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter); +  public: -  explicit DSAStackTy(Sema &S) : Stack(1), Actions(S) { } +  explicit DSAStackTy(Sema &S) : Stack(1), SemaRef(S) {}    void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, -            Scope *CurScope) { -    Stack.push_back(SharingMapTy(DKind, DirName, CurScope)); +            Scope *CurScope, SourceLocation Loc) { +    Stack.push_back(SharingMapTy(DKind, DirName, CurScope, Loc)); +    Stack.back().DefaultAttrLoc = Loc;    }    void pop() { @@ -95,51 +129,90 @@ public:      Stack.pop_back();    } +  /// \brief If 'aligned' declaration for given variable \a D was not seen yet, +  /// add it and return NULL; otherwise return previous occurrence's expression +  /// for diagnostics. +  DeclRefExpr *addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE); +    /// \brief Adds explicit data sharing attribute to the specified declaration.    void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A); -  /// \brief Checks if the variable is a local for OpenMP region. -  bool isOpenMPLocal(VarDecl *D); -    /// \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); -  /// \brief Checks if the specified variables has \a CKind data-sharing -  /// attribute in \a DKind directive. -  DSAVarData hasDSA(VarDecl *D, OpenMPClauseKind CKind, -                    OpenMPDirectiveKind DKind = OMPD_unknown); - +  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, 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, +                             bool FromParent); +  /// \brief Finds a directive which matches specified \a DPred predicate. +  template <class NamedDirectivesPredicate> +  bool hasDirective(NamedDirectivesPredicate DPred, bool FromParent);    /// \brief Returns currently analyzed directive.    OpenMPDirectiveKind getCurrentDirective() const {      return Stack.back().Directive;    } +  /// \brief Returns parent directive. +  OpenMPDirectiveKind getParentDirective() const { +    if (Stack.size() > 2) +      return Stack[Stack.size() - 2].Directive; +    return OMPD_unknown; +  }    /// \brief Set default data sharing attribute to none. -  void setDefaultDSANone() { Stack.back().DefaultAttr = DSA_none; } +  void setDefaultDSANone(SourceLocation Loc) { +    Stack.back().DefaultAttr = DSA_none; +    Stack.back().DefaultAttrLoc = Loc; +  }    /// \brief Set default data sharing attribute to shared. -  void setDefaultDSAShared() { Stack.back().DefaultAttr = DSA_shared; } +  void setDefaultDSAShared(SourceLocation Loc) { +    Stack.back().DefaultAttr = DSA_shared; +    Stack.back().DefaultAttrLoc = Loc; +  }    DefaultDataSharingAttributes getDefaultDSA() const {      return Stack.back().DefaultAttr;    } +  SourceLocation getDefaultDSALocation() const { +    return Stack.back().DefaultAttrLoc; +  } +  /// \brief Checks if the specified variable is a threadprivate. +  bool isThreadPrivate(VarDecl *D) { +    DSAVarData DVar = getTopDSA(D, false); +    return isOpenMPThreadPrivate(DVar.CKind); +  } + +  Scope *getCurScope() const { return Stack.back().CurScope; }    Scope *getCurScope() { return Stack.back().CurScope; } +  SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; }  }; -} // end anonymous namespace. +bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) { +  return isOpenMPParallelDirective(DKind) || DKind == OMPD_task || +         DKind == OMPD_unknown; +} +} // namespace  DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,                                            VarDecl *D) {    DSAVarData DVar; -  if (Iter == Stack.rend() - 1) { +  if (Iter == std::prev(Stack.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      //  in the region are shared unless they appear in a threadprivate      //  directive. -    // TODO      if (!D->isFunctionOrMethodVarDecl())        DVar.CKind = OMPC_shared; @@ -152,12 +225,24 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,      return DVar;    } +    DVar.DKind = Iter->Directive; +  // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced +  // in a Construct, C/C++, predetermined, p.1] +  // Variables with automatic storage duration that are declared in a scope +  // inside the construct are private. +  if (isOpenMPLocal(D, Iter) && D->isLocalVarDecl() && +      (D->getStorageClass() == SC_Auto || D->getStorageClass() == SC_None)) { +    DVar.CKind = OMPC_private; +    return DVar; +  } +    // Explicitly specified attributes and local variables with predetermined    // attributes.    if (Iter->SharingMap.count(D)) {      DVar.RefExpr = Iter->SharingMap[D].RefExpr;      DVar.CKind = Iter->SharingMap[D].Attributes; +    DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;      return DVar;    } @@ -168,6 +253,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,    switch (Iter->DefaultAttr) {    case DSA_shared:      DVar.CKind = OMPC_shared; +    DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;      return DVar;    case DSA_none:      return DVar; @@ -176,7 +262,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,      // in a Construct, implicitly determined, p.2]      //  In a parallel construct, if no default clause is present, these      //  variables are shared. -    if (DVar.DKind == OMPD_parallel) { +    DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; +    if (isOpenMPParallelDirective(DVar.DKind)) {        DVar.CKind = OMPC_shared;        return DVar;      } @@ -186,29 +273,30 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,      //  In a task construct, if no default clause is present, a variable that in      //  the enclosing context is determined to be shared by all implicit tasks      //  bound to the current team is shared. -    // TODO      if (DVar.DKind == OMPD_task) {        DSAVarData DVarTemp; -      for (StackTy::reverse_iterator I = Iter + 1, -                                     EE = Stack.rend() - 1; +      for (StackTy::reverse_iterator I = std::next(Iter), +                                     EE = std::prev(Stack.rend());             I != EE; ++I) { -        // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced +        // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables +        // Referenced          // in a Construct, implicitly determined, p.6]          //  In a task construct, if no default clause is present, a variable          //  whose data-sharing attribute is not determined by the rules above is          //  firstprivate.          DVarTemp = getDSA(I, D);          if (DVarTemp.CKind != OMPC_shared) { -          DVar.RefExpr = 0; +          DVar.RefExpr = nullptr;            DVar.DKind = OMPD_task;            DVar.CKind = OMPC_firstprivate;            return DVar;          } -        if (I->Directive == OMPD_parallel) break; +        if (isParallelOrTaskRegion(I->Directive)) +          break;        }        DVar.DKind = OMPD_task;        DVar.CKind = -        (DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared; +          (DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared;        return DVar;      }    } @@ -217,7 +305,21 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,    //  For constructs other than task, if no default clause is present, these    //  variables inherit their data-sharing attributes from the enclosing    //  context. -  return getDSA(Iter + 1, D); +  return getDSA(std::next(Iter), D); +} + +DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) { +  assert(Stack.size() > 1 && "Data sharing attributes stack is empty"); +  auto It = Stack.back().AlignedMap.find(D); +  if (It == Stack.back().AlignedMap.end()) { +    assert(NewDE && "Unexpected nullptr expr to be added into aligned map"); +    Stack.back().AlignedMap[D] = NewDE; +    return nullptr; +  } else { +    assert(It->second && "Unexpected nullptr expr in the aligned map"); +    return It->second; +  } +  return nullptr;  }  void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) { @@ -231,26 +333,26 @@ void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) {    }  } -bool DSAStackTy::isOpenMPLocal(VarDecl *D) { -  Scope *CurScope = getCurScope(); -  while (CurScope && !CurScope->isDeclScope(D)) -    CurScope = CurScope->getParent(); -  while (CurScope && !CurScope->isOpenMPDirectiveScope()) -    CurScope = CurScope->getParent(); -  bool isOpenMPLocal = !!CurScope; -  if (!isOpenMPLocal) { -    CurScope = getCurScope(); -    while (CurScope && !CurScope->isOpenMPDirectiveScope()) +bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) { +  if (Stack.size() > 2) { +    reverse_iterator I = Iter, E = std::prev(Stack.rend()); +    Scope *TopScope = nullptr; +    while (I != E && !isParallelOrTaskRegion(I->Directive)) { +      ++I; +    } +    if (I == E) +      return false; +    TopScope = I->CurScope ? I->CurScope->getParent() : nullptr; +    Scope *CurScope = getCurScope(); +    while (CurScope != TopScope && !CurScope->isDeclScope(D)) {        CurScope = CurScope->getParent(); -    isOpenMPLocal = -      CurScope && -      isa<CapturedDecl>(D->getDeclContext()) && -      CurScope->getFnParent()->getEntity()->Encloses(D->getDeclContext()); +    } +    return CurScope != TopScope;    } -  return isOpenMPLocal; +  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 @@ -270,20 +372,29 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {    // in a Construct, C/C++, predetermined, p.1]    // Variables with automatic storage duration that are declared in a scope    // inside the construct are private. -  if (isOpenMPLocal(D) && D->isLocalVarDecl() && -      (D->getStorageClass() == SC_Auto || -       D->getStorageClass() == SC_None)) { -    DVar.CKind = OMPC_private; -    return DVar; +  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; +    }    }    // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced    // in a Construct, C/C++, predetermined, p.4] -  //  Static data memebers are shared. +  //  Static data members are shared.    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, OMPC_firstprivate); +    // 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(), FromParent);      if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr)        return DVar; @@ -292,7 +403,7 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {    }    QualType Type = D->getType().getNonReferenceType().getCanonicalType(); -  bool IsConstant = Type.isConstant(Actions.getASTContext()); +  bool IsConstant = Type.isConstant(SemaRef.getASTContext());    while (Type->isArrayType()) {      QualType ElemType = cast<ArrayType>(Type.getTypePtr())->getElementType();      Type = ElemType.getNonReferenceType().getCanonicalType(); @@ -301,13 +412,14 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {    // in a Construct, C/C++, predetermined, p.6]    //  Variables with const qualified type having no mutable member are    //  shared. -  CXXRecordDecl *RD = Actions.getLangOpts().CPlusPlus ? -                                Type->getAsCXXRecordDecl() : 0; +  CXXRecordDecl *RD = +      SemaRef.getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr;    if (IsConstant && -      !(Actions.getLangOpts().CPlusPlus && RD && RD->hasMutableFields())) { +      !(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, OMPC_firstprivate); +    DSAVarData DVarTemp = hasDSA(D, MatchesAnyClause(OMPC_firstprivate), +                                 MatchesAlways(), FromParent);      if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr)        return DVar; @@ -319,56 +431,151 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {    // in a Construct, C/C++, predetermined, p.7]    //  Variables with static storage duration that are declared in a scope    //  inside the construct are shared. -  if (isOpenMPLocal(D) && D->isStaticLocal()) { +  if (D->isStaticLocal()) {      DVar.CKind = OMPC_shared;      return DVar;    }    // 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(Stack.rbegin() + 1, 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, +                                          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)) +      return DVar; +  } +  return DSAVarData();  } -DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, OpenMPClauseKind CKind, -                                          OpenMPDirectiveKind DKind) { -  for (StackTy::reverse_iterator I = Stack.rbegin() + 1, -                                 E = Stack.rend() - 1; -       I != E; ++I) { -    if (DKind != OMPD_unknown && DKind != I->Directive) continue; +template <class ClausesPredicate, class DirectivesPredicate> +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)) +      break;      DSAVarData DVar = getDSA(I, D); -    if (DVar.CKind == CKind) +    if (CPred(DVar.CKind))        return DVar; +    return DSAVarData();    }    return DSAVarData();  } +template <class NamedDirectivesPredicate> +bool DSAStackTy::hasDirective(NamedDirectivesPredicate 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, I->DirectiveName, I->ConstructLoc)) +      return true; +  } +  return false; +} +  void Sema::InitDataSharingAttributesStack() {    VarDataSharingAttributesStack = new DSAStackTy(*this);  }  #define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack) -void Sema::DestroyDataSharingAttributesStack() { -  delete DSAStack; -} +void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; }  void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,                                 const DeclarationNameInfo &DirName, -                               Scope *CurScope) { -  DSAStack->push(DKind, DirName, CurScope); +                               Scope *CurScope, SourceLocation Loc) { +  DSAStack->push(DKind, DirName, CurScope, Loc);    PushExpressionEvaluationContext(PotentiallyEvaluated);  }  void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { +  // OpenMP [2.14.3.5, Restrictions, C/C++, p.1] +  //  A variable of class type (or array thereof) that appears in a lastprivate +  //  clause requires an accessible, unambiguous default constructor for the +  //  class type, unless the list item is also specified in a firstprivate +  //  clause. +  if (auto D = dyn_cast_or_null<OMPExecutableDirective>(CurDirective)) { +    for (auto C : D->clauses()) { +      if (auto Clause = dyn_cast<OMPLastprivateClause>(C)) { +        for (auto VarRef : Clause->varlists()) { +          if (VarRef->isValueDependent() || VarRef->isTypeDependent()) +            continue; +          auto VD = cast<VarDecl>(cast<DeclRefExpr>(VarRef)->getDecl()); +          auto DVar = DSAStack->getTopDSA(VD, false); +          if (DVar.CKind == OMPC_lastprivate) { +            SourceLocation ELoc = VarRef->getExprLoc(); +            auto Type = VarRef->getType(); +            if (Type->isArrayType()) +              Type = QualType(Type->getArrayElementTypeNoTypeQual(), 0); +            CXXRecordDecl *RD = +                getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr; +            // FIXME This code must be replaced by actual constructing of the +            // lastprivate variable. +            if (RD) { +              CXXConstructorDecl *CD = LookupDefaultConstructor(RD); +              PartialDiagnostic PD = +                  PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); +              if (!CD || +                  CheckConstructorAccess( +                      ELoc, CD, InitializedEntity::InitializeTemporary(Type), +                      CD->getAccess(), PD) == AR_inaccessible || +                  CD->isDeleted()) { +                Diag(ELoc, diag::err_omp_required_method) +                    << getOpenMPClauseName(OMPC_lastprivate) << 0; +                bool IsDecl = VD->isThisDeclarationADefinition(Context) == +                              VarDecl::DeclarationOnly; +                Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl +                                               : diag::note_defined_here) +                    << VD; +                Diag(RD->getLocation(), diag::note_previous_decl) << RD; +                continue; +              } +              MarkFunctionReferenced(ELoc, CD); +              DiagnoseUseOfDecl(CD, ELoc); +            } +          } +        } +      } +    } +  } +    DSAStack->pop();    DiscardCleanupsInEvaluationContext();    PopExpressionEvaluationContext(); @@ -378,20 +585,21 @@ namespace {  class VarDeclFilterCCC : public CorrectionCandidateCallback {  private: -  Sema &Actions; +  Sema &SemaRef; +  public: -  VarDeclFilterCCC(Sema &S) : Actions(S) { } -  virtual bool ValidateCandidate(const TypoCorrection &Candidate) { +  explicit VarDeclFilterCCC(Sema &S) : SemaRef(S) {} +  bool ValidateCandidate(const TypoCorrection &Candidate) override {      NamedDecl *ND = Candidate.getCorrectionDecl();      if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) {        return VD->hasGlobalStorage() && -             Actions.isDeclInScope(ND, Actions.getCurLexicalContext(), -                                   Actions.getCurScope()); +             SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(), +                                   SemaRef.getCurScope());      }      return false;    }  }; -} +} // namespace  ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,                                           CXXScopeSpec &ScopeSpec, @@ -405,12 +613,14 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,    VarDecl *VD;    if (!Lookup.isSingleResult()) {      VarDeclFilterCCC Validator(*this); -    if (TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope, -                                               0, Validator)) { +    if (TypoCorrection Corrected = +            CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, Validator, +                        CTK_ErrorRecovery)) {        diagnoseTypo(Corrected, -                   PDiag(Lookup.empty()? diag::err_undeclared_var_use_suggest -                                       : diag::err_omp_expected_var_arg_suggest) -                     << Id.getName()); +                   PDiag(Lookup.empty() +                             ? diag::err_undeclared_var_use_suggest +                             : diag::err_omp_expected_var_arg_suggest) +                       << Id.getName());        VD = Corrected.getCorrectionDeclAs<VarDecl>();      } else {        Diag(Id.getLoc(), Lookup.empty() ? diag::err_undeclared_var_use @@ -420,8 +630,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,      }    } else {      if (!(VD = Lookup.getAsSingle<VarDecl>())) { -      Diag(Id.getLoc(), diag::err_omp_expected_var_arg) -        << Id.getName(); +      Diag(Id.getLoc(), diag::err_omp_expected_var_arg) << Id.getName();        Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at);        return ExprError();      } @@ -432,12 +641,12 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,    //   Variables must be file-scope, namespace-scope, or static block-scope.    if (!VD->hasGlobalStorage()) {      Diag(Id.getLoc(), diag::err_omp_global_var_arg) -      << getOpenMPDirectiveName(OMPD_threadprivate) -      << !VD->isStaticLocal(); -    bool IsDecl = VD->isThisDeclarationADefinition(Context) == -                  VarDecl::DeclarationOnly; +        << getOpenMPDirectiveName(OMPD_threadprivate) << !VD->isStaticLocal(); +    bool IsDecl = +        VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;      Diag(VD->getLocation(), -         IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; +         IsDecl ? diag::note_previous_decl : diag::note_defined_here) +        << VD;      return ExprError();    } @@ -449,11 +658,12 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,    if (CanonicalVD->getDeclContext()->isTranslationUnit() &&        !getCurLexicalContext()->isTranslationUnit()) {      Diag(Id.getLoc(), diag::err_omp_var_scope) -      << getOpenMPDirectiveName(OMPD_threadprivate) << VD; -    bool IsDecl = VD->isThisDeclarationADefinition(Context) == -                  VarDecl::DeclarationOnly; -    Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : -                                     diag::note_defined_here) << VD; +        << getOpenMPDirectiveName(OMPD_threadprivate) << VD; +    bool IsDecl = +        VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +    Diag(VD->getLocation(), +         IsDecl ? diag::note_previous_decl : diag::note_defined_here) +        << VD;      return ExprError();    }    // OpenMP [2.9.2, Restrictions, C/C++, p.3] @@ -463,11 +673,12 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,    if (CanonicalVD->isStaticDataMember() &&        !CanonicalVD->getDeclContext()->Equals(getCurLexicalContext())) {      Diag(Id.getLoc(), diag::err_omp_var_scope) -      << getOpenMPDirectiveName(OMPD_threadprivate) << VD; -    bool IsDecl = VD->isThisDeclarationADefinition(Context) == -                  VarDecl::DeclarationOnly; -    Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : -                                     diag::note_defined_here) << VD; +        << getOpenMPDirectiveName(OMPD_threadprivate) << VD; +    bool IsDecl = +        VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +    Diag(VD->getLocation(), +         IsDecl ? diag::note_previous_decl : diag::note_defined_here) +        << VD;      return ExprError();    }    // OpenMP [2.9.2, Restrictions, C/C++, p.4] @@ -478,11 +689,12 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,        (!getCurLexicalContext()->isFileContext() ||         !getCurLexicalContext()->Encloses(CanonicalVD->getDeclContext()))) {      Diag(Id.getLoc(), diag::err_omp_var_scope) -      << getOpenMPDirectiveName(OMPD_threadprivate) << VD; -    bool IsDecl = VD->isThisDeclarationADefinition(Context) == -                  VarDecl::DeclarationOnly; -    Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : -                                     diag::note_defined_here) << VD; +        << getOpenMPDirectiveName(OMPD_threadprivate) << VD; +    bool IsDecl = +        VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +    Diag(VD->getLocation(), +         IsDecl ? diag::note_previous_decl : diag::note_defined_here) +        << VD;      return ExprError();    }    // OpenMP [2.9.2, Restrictions, C/C++, p.6] @@ -491,11 +703,12 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,    if (CanonicalVD->isStaticLocal() && CurScope &&        !isDeclInScope(ND, getCurLexicalContext(), CurScope)) {      Diag(Id.getLoc(), diag::err_omp_var_scope) -      << getOpenMPDirectiveName(OMPD_threadprivate) << VD; -    bool IsDecl = VD->isThisDeclarationADefinition(Context) == -                  VarDecl::DeclarationOnly; -    Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : -                                     diag::note_defined_here) << VD; +        << getOpenMPDirectiveName(OMPD_threadprivate) << VD; +    bool IsDecl = +        VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +    Diag(VD->getLocation(), +         IsDecl ? diag::note_previous_decl : diag::note_defined_here) +        << VD;      return ExprError();    } @@ -504,19 +717,18 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,    //   of the variables in its list.    if (VD->isUsed()) {      Diag(Id.getLoc(), diag::err_omp_var_used) -      << getOpenMPDirectiveName(OMPD_threadprivate) << VD; +        << getOpenMPDirectiveName(OMPD_threadprivate) << VD;      return ExprError();    }    QualType ExprType = VD->getType().getNonReferenceType(); -  ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_RValue, Id.getLoc()); -  DSAStack->addDSA(VD, cast<DeclRefExpr>(DE.get()), OMPC_threadprivate); +  ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_LValue, Id.getLoc());    return DE;  } -Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective( -                                SourceLocation Loc, -                                ArrayRef<Expr *> VarList) { +Sema::DeclGroupPtrTy +Sema::ActOnOpenMPThreadprivateDirective(SourceLocation Loc, +                                        ArrayRef<Expr *> VarList) {    if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) {      CurContext->addDecl(D);      return DeclGroupPtrTy::make(DeclGroupRef(D)); @@ -524,14 +736,40 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(    return DeclGroupPtrTy();  } -OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( -                                 SourceLocation Loc, -                                 ArrayRef<Expr *> VarList) { +namespace { +class LocalVarRefChecker : public ConstStmtVisitor<LocalVarRefChecker, bool> { +  Sema &SemaRef; + +public: +  bool VisitDeclRefExpr(const DeclRefExpr *E) { +    if (auto VD = dyn_cast<VarDecl>(E->getDecl())) { +      if (VD->hasLocalStorage()) { +        SemaRef.Diag(E->getLocStart(), +                     diag::err_omp_local_var_in_threadprivate_init) +            << E->getSourceRange(); +        SemaRef.Diag(VD->getLocation(), diag::note_defined_here) +            << VD << VD->getSourceRange(); +        return true; +      } +    } +    return false; +  } +  bool VisitStmt(const Stmt *S) { +    for (auto Child : S->children()) { +      if (Child && Visit(Child)) +        return true; +    } +    return false; +  } +  explicit LocalVarRefChecker(Sema &SemaRef) : SemaRef(SemaRef) {} +}; +} // namespace + +OMPThreadPrivateDecl * +Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) {    SmallVector<Expr *, 8> Vars; -  for (ArrayRef<Expr *>::iterator I = VarList.begin(), -                                         E = VarList.end(); -       I != E; ++I) { -    DeclRefExpr *DE = cast<DeclRefExpr>(*I); +  for (auto &RefExpr : VarList) { +    DeclRefExpr *DE = cast<DeclRefExpr>(RefExpr);      VarDecl *VD = cast<VarDecl>(DE->getDecl());      SourceLocation ILoc = DE->getExprLoc(); @@ -546,64 +784,130 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(      //   A threadprivate variable must not have a reference type.      if (VD->getType()->isReferenceType()) {        Diag(ILoc, diag::err_omp_ref_type_arg) -        << getOpenMPDirectiveName(OMPD_threadprivate) -        << VD->getType(); -      bool IsDecl = VD->isThisDeclarationADefinition(Context) == -                    VarDecl::DeclarationOnly; -      Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : -                                       diag::note_defined_here) << VD; +          << getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType(); +      bool IsDecl = +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +      Diag(VD->getLocation(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD;        continue;      }      // Check if this is a TLS variable.      if (VD->getTLSKind()) {        Diag(ILoc, diag::err_omp_var_thread_local) << VD; -      bool IsDecl = VD->isThisDeclarationADefinition(Context) == -                    VarDecl::DeclarationOnly; -      Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : -                                       diag::note_defined_here) << VD; +      bool IsDecl = +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +      Diag(VD->getLocation(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD;        continue;      } -    Vars.push_back(*I); +    // Check if initial value of threadprivate variable reference variable with +    // local storage (it is not supported by runtime). +    if (auto Init = VD->getAnyInitializer()) { +      LocalVarRefChecker Checker(*this); +      if (Checker.Visit(Init)) +        continue; +    } + +    Vars.push_back(RefExpr); +    DSAStack->addDSA(VD, DE, OMPC_threadprivate); +  } +  OMPThreadPrivateDecl *D = nullptr; +  if (!Vars.empty()) { +    D = OMPThreadPrivateDecl::Create(Context, getCurLexicalContext(), Loc, +                                     Vars); +    D->setAccess(AS_public); +  } +  return D; +} + +static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack, +                              const VarDecl *VD, DSAStackTy::DSAVarData DVar, +                              bool IsLoopIterVar = false) { +  if (DVar.RefExpr) { +    SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) +        << getOpenMPClauseName(DVar.CKind); +    return; +  } +  enum { +    PDSA_StaticMemberShared, +    PDSA_StaticLocalVarShared, +    PDSA_LoopIterVarPrivate, +    PDSA_LoopIterVarLinear, +    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; +    else if (DVar.CKind == OMPC_lastprivate) +      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()) +    Reason = PDSA_StaticMemberShared; +  else if (VD->isFileVarDecl()) +    Reason = PDSA_GlobalVarShared; +  else if (VD->getType().isConstant(SemaRef.getASTContext())) +    Reason = PDSA_ConstVarShared; +  else if (VD->isLocalVarDecl() && DVar.CKind == OMPC_private) { +    ReportHint = true; +    Reason = PDSA_LocalVarPrivate; +  } +  if (Reason != PDSA_Implicit) { +    SemaRef.Diag(ReportLoc, diag::note_omp_predetermined_dsa) +        << Reason << ReportHint +        << getOpenMPDirectiveName(Stack->getCurrentDirective()); +  } else if (DVar.ImplicitDSALoc.isValid()) { +    SemaRef.Diag(DVar.ImplicitDSALoc, diag::note_omp_implicit_dsa) +        << getOpenMPClauseName(DVar.CKind);    } -  return Vars.empty() ? -              0 : OMPThreadPrivateDecl::Create(Context, -                                               getCurLexicalContext(), -                                               Loc, Vars);  }  namespace {  class DSAAttrChecker : public StmtVisitor<DSAAttrChecker, void> {    DSAStackTy *Stack; -  Sema &Actions; +  Sema &SemaRef;    bool ErrorFound;    CapturedStmt *CS;    llvm::SmallVector<Expr *, 8> ImplicitFirstprivate; +  llvm::DenseMap<VarDecl *, Expr *> VarsWithInheritedDSA; +  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; +      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 && -            DVar.CKind != OMPC_threadprivate && !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 && -          (DKind == OMPD_parallel || DKind == OMPD_task)) { -        ErrorFound = true; -        Actions.Diag(ELoc, diag::err_omp_no_dsa_for_variable) << VD; +          isParallelOrTaskRegion(DKind) && +          VarsWithInheritedDSA.count(VD) == 0) { +        VarsWithInheritedDSA[VD] = E;          return;        } @@ -611,84 +915,593 @@ public:        //  A list item that appears in a reduction clause of the innermost        //  enclosing worksharing or parallel construct may not be accessed in an        //  explicit task. -      // TODO: +      DVar = Stack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction), +                                    [](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); +        ReportOriginalDSA(SemaRef, Stack, VD, DVar); +        return; +      }        // 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 (ArrayRef<OMPClause *>::iterator I = S->clauses().begin(), -                                         E = S->clauses().end(); -         I != E; ++I) -      if (OMPClause *C = *I) -        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; }    ArrayRef<Expr *> getImplicitFirstprivate() { return ImplicitFirstprivate; } +  llvm::DenseMap<VarDecl *, Expr *> &getVarsWithInheritedDSA() { +    return VarsWithInheritedDSA; +  } -  DSAAttrChecker(DSAStackTy *S, Sema &Actions, CapturedStmt *CS) -    : Stack(S), Actions(Actions), ErrorFound(false), CS(CS) { } +  DSAAttrChecker(DSAStackTy *S, Sema &SemaRef, CapturedStmt *CS) +      : Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) {}  }; +} // namespace + +void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { +  switch (DKind) { +  case OMPD_parallel: { +    QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); +    QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty); +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(".global_tid.", KmpInt32PtrTy), +        std::make_pair(".bound_tid.", KmpInt32PtrTy), +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             Params); +    break; +  } +  case OMPD_simd: { +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             Params); +    break; +  } +  case OMPD_for: { +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             Params); +    break; +  } +  case OMPD_sections: { +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             Params); +    break; +  } +  case OMPD_section: { +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             Params); +    break; +  } +  case OMPD_single: { +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             Params); +    break; +  } +  case OMPD_master: { +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             Params); +    break; +  } +  case OMPD_critical: { +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             Params); +    break; +  } +  case OMPD_parallel_for: { +    QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); +    QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty); +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(".global_tid.", KmpInt32PtrTy), +        std::make_pair(".bound_tid.", KmpInt32PtrTy), +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             Params); +    break; +  } +  case OMPD_parallel_sections: { +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             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_taskyield: { +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             Params); +    break; +  } +  case OMPD_barrier: { +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             Params); +    break; +  } +  case OMPD_taskwait: { +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             Params); +    break; +  } +  case OMPD_flush: { +    Sema::CapturedParamNameType Params[] = { +        std::make_pair(StringRef(), QualType()) // __context with shared vars +    }; +    ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, +                             Params); +    break; +  } +  case OMPD_threadprivate: +    llvm_unreachable("OpenMP Directive is not allowed"); +  case OMPD_unknown: +    llvm_unreachable("Unknown OpenMP directive"); +  } +} + +static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, +                                  OpenMPDirectiveKind CurrentRegion, +                                  const DeclarationNameInfo &CurrentName, +                                  SourceLocation StartLoc) { +  // Allowed nesting of constructs +  // +------------------+-----------------+------------------------------------+ +  // | Parent directive | Child directive | Closely (!), No-Closely(+), Both(*)| +  // +------------------+-----------------+------------------------------------+ +  // | parallel         | parallel        | *                                  | +  // | parallel         | for             | *                                  | +  // | parallel         | master          | *                                  | +  // | parallel         | critical        | *                                  | +  // | parallel         | simd            | *                                  | +  // | parallel         | sections        | *                                  | +  // | parallel         | section         | +                                  | +  // | parallel         | single          | *                                  | +  // | parallel         | parallel for    | *                                  | +  // | parallel         |parallel sections| *                                  | +  // | parallel         | task            | *                                  | +  // | parallel         | taskyield       | *                                  | +  // | parallel         | barrier         | *                                  | +  // | parallel         | taskwait        | *                                  | +  // | parallel         | flush           | *                                  | +  // +------------------+-----------------+------------------------------------+ +  // | for              | parallel        | *                                  | +  // | for              | for             | +                                  | +  // | for              | master          | +                                  | +  // | for              | critical        | *                                  | +  // | for              | simd            | *                                  | +  // | for              | sections        | +                                  | +  // | for              | section         | +                                  | +  // | for              | single          | +                                  | +  // | for              | parallel for    | *                                  | +  // | for              |parallel sections| *                                  | +  // | for              | task            | *                                  | +  // | for              | taskyield       | *                                  | +  // | for              | barrier         | +                                  | +  // | for              | taskwait        | *                                  | +  // | for              | flush           | *                                  | +  // +------------------+-----------------+------------------------------------+ +  // | master           | parallel        | *                                  | +  // | master           | for             | +                                  | +  // | master           | master          | *                                  | +  // | master           | critical        | *                                  | +  // | master           | simd            | *                                  | +  // | master           | sections        | +                                  | +  // | master           | section         | +                                  | +  // | master           | single          | +                                  | +  // | master           | parallel for    | *                                  | +  // | master           |parallel sections| *                                  | +  // | master           | task            | *                                  | +  // | master           | taskyield       | *                                  | +  // | master           | barrier         | +                                  | +  // | master           | taskwait        | *                                  | +  // | master           | flush           | *                                  | +  // +------------------+-----------------+------------------------------------+ +  // | critical         | parallel        | *                                  | +  // | critical         | for             | +                                  | +  // | critical         | master          | *                                  | +  // | critical         | critical        | * (should have dirrerent names)    | +  // | critical         | simd            | *                                  | +  // | critical         | sections        | +                                  | +  // | critical         | section         | +                                  | +  // | critical         | single          | +                                  | +  // | critical         | parallel for    | *                                  | +  // | critical         |parallel sections| *                                  | +  // | critical         | task            | *                                  | +  // | critical         | taskyield       | *                                  | +  // | critical         | barrier         | +                                  | +  // | critical         | taskwait        | *                                  | +  // +------------------+-----------------+------------------------------------+ +  // | simd             | parallel        |                                    | +  // | simd             | for             |                                    | +  // | simd             | master          |                                    | +  // | simd             | critical        |                                    | +  // | simd             | simd            |                                    | +  // | simd             | sections        |                                    | +  // | simd             | section         |                                    | +  // | simd             | single          |                                    | +  // | simd             | parallel for    |                                    | +  // | simd             |parallel sections|                                    | +  // | simd             | task            |                                    | +  // | simd             | taskyield       |                                    | +  // | simd             | barrier         |                                    | +  // | simd             | taskwait        |                                    | +  // | simd             | flush           |                                    | +  // +------------------+-----------------+------------------------------------+ +  // | sections         | parallel        | *                                  | +  // | sections         | for             | +                                  | +  // | sections         | master          | +                                  | +  // | sections         | critical        | *                                  | +  // | sections         | simd            | *                                  | +  // | sections         | sections        | +                                  | +  // | sections         | section         | *                                  | +  // | sections         | single          | +                                  | +  // | sections         | parallel for    | *                                  | +  // | sections         |parallel sections| *                                  | +  // | sections         | task            | *                                  | +  // | sections         | taskyield       | *                                  | +  // | sections         | barrier         | +                                  | +  // | sections         | taskwait        | *                                  | +  // | sections         | flush           | *                                  | +  // +------------------+-----------------+------------------------------------+ +  // | section          | parallel        | *                                  | +  // | section          | for             | +                                  | +  // | section          | master          | +                                  | +  // | section          | critical        | *                                  | +  // | section          | simd            | *                                  | +  // | section          | sections        | +                                  | +  // | section          | section         | +                                  | +  // | section          | single          | +                                  | +  // | section          | parallel for    | *                                  | +  // | section          |parallel sections| *                                  | +  // | section          | task            | *                                  | +  // | section          | taskyield       | *                                  | +  // | section          | barrier         | +                                  | +  // | section          | taskwait        | *                                  | +  // | section          | flush           | *                                  | +  // +------------------+-----------------+------------------------------------+ +  // | single           | parallel        | *                                  | +  // | single           | for             | +                                  | +  // | single           | master          | +                                  | +  // | single           | critical        | *                                  | +  // | single           | simd            | *                                  | +  // | single           | sections        | +                                  | +  // | single           | section         | +                                  | +  // | single           | single          | +                                  | +  // | single           | parallel for    | *                                  | +  // | single           |parallel sections| *                                  | +  // | single           | task            | *                                  | +  // | single           | taskyield       | *                                  | +  // | single           | barrier         | +                                  | +  // | single           | taskwait        | *                                  | +  // | single           | flush           | *                                  | +  // +------------------+-----------------+------------------------------------+ +  // | parallel for     | parallel        | *                                  | +  // | parallel for     | for             | +                                  | +  // | parallel for     | master          | +                                  | +  // | parallel for     | critical        | *                                  | +  // | parallel for     | simd            | *                                  | +  // | parallel for     | sections        | +                                  | +  // | parallel for     | section         | +                                  | +  // | parallel for     | single          | +                                  | +  // | parallel for     | parallel for    | *                                  | +  // | parallel for     |parallel sections| *                                  | +  // | parallel for     | task            | *                                  | +  // | parallel for     | taskyield       | *                                  | +  // | parallel for     | barrier         | +                                  | +  // | parallel for     | taskwait        | *                                  | +  // | parallel for     | flush           | *                                  | +  // +------------------+-----------------+------------------------------------+ +  // | parallel sections| parallel        | *                                  | +  // | parallel sections| for             | +                                  | +  // | parallel sections| master          | +                                  | +  // | parallel sections| critical        | +                                  | +  // | parallel sections| simd            | *                                  | +  // | parallel sections| sections        | +                                  | +  // | parallel sections| section         | *                                  | +  // | parallel sections| single          | +                                  | +  // | parallel sections| parallel for    | *                                  | +  // | parallel sections|parallel sections| *                                  | +  // | parallel sections| task            | *                                  | +  // | parallel sections| taskyield       | *                                  | +  // | parallel sections| barrier         | +                                  | +  // | parallel sections| taskwait        | *                                  | +  // | parallel sections| flush           | *                                  | +  // +------------------+-----------------+------------------------------------+ +  // | task             | parallel        | *                                  | +  // | task             | for             | +                                  | +  // | task             | master          | +                                  | +  // | task             | critical        | *                                  | +  // | task             | simd            | *                                  | +  // | task             | sections        | +                                  | +  // | task             | section         | +                                  | +  // | task             | single          | +                                  | +  // | task             | parallel for    | *                                  | +  // | task             |parallel sections| *                                  | +  // | task             | task            | *                                  | +  // | task             | taskyield       | *                                  | +  // | task             | barrier         | +                                  | +  // | task             | taskwait        | *                                  | +  // | task             | flush           | *                                  | +  // +------------------+-----------------+------------------------------------+ +  if (Stack->getCurScope()) { +    auto ParentRegion = Stack->getParentDirective(); +    bool NestingProhibited = false; +    bool CloseNesting = true; +    bool ShouldBeInParallelRegion = false; +    if (isOpenMPSimdDirective(ParentRegion)) { +      // OpenMP [2.16, Nesting of Regions] +      // OpenMP constructs may not be nested inside a simd region. +      SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_simd); +      return true; +    } +    if (CurrentRegion == OMPD_section) { +      // OpenMP [2.7.2, sections Construct, Restrictions] +      // Orphaned section directives are prohibited. That is, the section +      // directives must appear within the sections construct and must not be +      // encountered elsewhere in the sections region. +      if (ParentRegion != OMPD_sections && +          ParentRegion != OMPD_parallel_sections) { +        SemaRef.Diag(StartLoc, diag::err_omp_orphaned_section_directive) +            << (ParentRegion != OMPD_unknown) +            << getOpenMPDirectiveName(ParentRegion); +        return true; +      } +      return false; +    } +    if (CurrentRegion == OMPD_master) { +      // OpenMP [2.16, Nesting of Regions] +      // A master region may not be closely nested inside a worksharing, +      // atomic (TODO), or explicit task region. +      NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || +                          ParentRegion == OMPD_task; +    } else if (CurrentRegion == OMPD_critical && CurrentName.getName()) { +      // OpenMP [2.16, Nesting of Regions] +      // A critical region may not be nested (closely or otherwise) inside a +      // critical region with the same name. Note that this restriction is not +      // sufficient to prevent deadlock. +      SourceLocation PreviousCriticalLoc; +      bool DeadLock = +          Stack->hasDirective([CurrentName, &PreviousCriticalLoc]( +                                  OpenMPDirectiveKind K, +                                  const DeclarationNameInfo &DNI, +                                  SourceLocation Loc) +                                  ->bool { +                                if (K == OMPD_critical && +                                    DNI.getName() == CurrentName.getName()) { +                                  PreviousCriticalLoc = Loc; +                                  return true; +                                } else +                                  return false; +                              }, +                              false /* skip top directive */); +      if (DeadLock) { +        SemaRef.Diag(StartLoc, +                     diag::err_omp_prohibited_region_critical_same_name) +            << CurrentName.getName(); +        if (PreviousCriticalLoc.isValid()) +          SemaRef.Diag(PreviousCriticalLoc, +                       diag::note_omp_previous_critical_region); +        return true; +      } +    } else if (CurrentRegion == OMPD_barrier) { +      // OpenMP [2.16, Nesting of Regions] +      // A barrier region may not be closely nested inside a worksharing, +      // explicit task, critical, ordered(TODO), atomic(TODO), or master +      // region. +      NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || +                          ParentRegion == OMPD_task || +                          ParentRegion == OMPD_master || +                          ParentRegion == OMPD_critical; +    } else if (isOpenMPWorksharingDirective(CurrentRegion) && +               !isOpenMPParallelDirective(CurrentRegion) && +               !isOpenMPSimdDirective(CurrentRegion)) { +      // OpenMP [2.16, Nesting of Regions] +      // 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)) || +                          ParentRegion == OMPD_task || +                          ParentRegion == OMPD_master || +                          ParentRegion == OMPD_critical; +      ShouldBeInParallelRegion = true; +    } +    if (NestingProhibited) { +      SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region) +          << CloseNesting << getOpenMPDirectiveName(ParentRegion) +          << ShouldBeInParallelRegion << getOpenMPDirectiveName(CurrentRegion); +      return true; +    } +  } +  return false;  }  StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, +                                                const DeclarationNameInfo &DirName,                                                  ArrayRef<OMPClause *> Clauses,                                                  Stmt *AStmt,                                                  SourceLocation StartLoc,                                                  SourceLocation EndLoc) { -  assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); -    StmtResult Res = StmtError(); - -  // Check default data sharing attributes for referenced variables. -  DSAAttrChecker DSAChecker(DSAStack, *this, cast<CapturedStmt>(AStmt)); -  DSAChecker.Visit(cast<CapturedStmt>(AStmt)->getCapturedStmt()); -  if (DSAChecker.isErrorFound()) +  if (CheckNestingOfRegions(*this, DSAStack, Kind, DirName, StartLoc))      return StmtError(); -  // Generate list of implicitly defined firstprivate variables. +    llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit; +  llvm::DenseMap<VarDecl *, Expr *> VarsWithInheritedDSA; +  bool ErrorFound = false;    ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); +  if (AStmt) { +    assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); -  bool ErrorFound = false; -  if (!DSAChecker.getImplicitFirstprivate().empty()) { -    if (OMPClause *Implicit = -         ActOnOpenMPFirstprivateClause(DSAChecker.getImplicitFirstprivate(), -                                       SourceLocation(), SourceLocation(), -                                       SourceLocation())) { -      ClausesWithImplicit.push_back(Implicit); -      ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() != -                                    DSAChecker.getImplicitFirstprivate().size(); -    } else -      ErrorFound = true; +    // Check default data sharing attributes for referenced variables. +    DSAAttrChecker DSAChecker(DSAStack, *this, cast<CapturedStmt>(AStmt)); +    DSAChecker.Visit(cast<CapturedStmt>(AStmt)->getCapturedStmt()); +    if (DSAChecker.isErrorFound()) +      return StmtError(); +    // Generate list of implicitly defined firstprivate variables. +    VarsWithInheritedDSA = DSAChecker.getVarsWithInheritedDSA(); + +    if (!DSAChecker.getImplicitFirstprivate().empty()) { +      if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause( +              DSAChecker.getImplicitFirstprivate(), SourceLocation(), +              SourceLocation(), SourceLocation())) { +        ClausesWithImplicit.push_back(Implicit); +        ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() != +                     DSAChecker.getImplicitFirstprivate().size(); +      } else +        ErrorFound = true; +    }    }    switch (Kind) {    case OMPD_parallel: -    Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt, -                                       StartLoc, EndLoc); +    Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt, StartLoc, +                                       EndLoc); +    break; +  case OMPD_simd: +    Res = ActOnOpenMPSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, +                                   VarsWithInheritedDSA); +    break; +  case OMPD_for: +    Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, +                                  VarsWithInheritedDSA); +    break; +  case OMPD_sections: +    Res = ActOnOpenMPSectionsDirective(ClausesWithImplicit, AStmt, StartLoc, +                                       EndLoc); +    break; +  case OMPD_section: +    assert(ClausesWithImplicit.empty() && +           "No clauses are allowed for 'omp section' directive"); +    Res = ActOnOpenMPSectionDirective(AStmt, StartLoc, EndLoc); +    break; +  case OMPD_single: +    Res = ActOnOpenMPSingleDirective(ClausesWithImplicit, AStmt, StartLoc, +                                     EndLoc); +    break; +  case OMPD_master: +    assert(ClausesWithImplicit.empty() && +           "No clauses are allowed for 'omp master' directive"); +    Res = ActOnOpenMPMasterDirective(AStmt, StartLoc, EndLoc); +    break; +  case OMPD_critical: +    assert(ClausesWithImplicit.empty() && +           "No clauses are allowed for 'omp critical' directive"); +    Res = ActOnOpenMPCriticalDirective(DirName, AStmt, StartLoc, EndLoc); +    break; +  case OMPD_parallel_for: +    Res = ActOnOpenMPParallelForDirective(ClausesWithImplicit, AStmt, StartLoc, +                                          EndLoc, VarsWithInheritedDSA); +    break; +  case OMPD_parallel_sections: +    Res = ActOnOpenMPParallelSectionsDirective(ClausesWithImplicit, AStmt, +                                               StartLoc, EndLoc);      break; -  case OMPD_threadprivate:    case OMPD_task: +    Res = +        ActOnOpenMPTaskDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); +    break; +  case OMPD_taskyield: +    assert(ClausesWithImplicit.empty() && +           "No clauses are allowed for 'omp taskyield' directive"); +    assert(AStmt == nullptr && +           "No associated statement allowed for 'omp taskyield' directive"); +    Res = ActOnOpenMPTaskyieldDirective(StartLoc, EndLoc); +    break; +  case OMPD_barrier: +    assert(ClausesWithImplicit.empty() && +           "No clauses are allowed for 'omp barrier' directive"); +    assert(AStmt == nullptr && +           "No associated statement allowed for 'omp barrier' directive"); +    Res = ActOnOpenMPBarrierDirective(StartLoc, EndLoc); +    break; +  case OMPD_taskwait: +    assert(ClausesWithImplicit.empty() && +           "No clauses are allowed for 'omp taskwait' directive"); +    assert(AStmt == nullptr && +           "No associated statement allowed for 'omp taskwait' directive"); +    Res = ActOnOpenMPTaskwaitDirective(StartLoc, EndLoc); +    break; +  case OMPD_flush: +    assert(AStmt == nullptr && +           "No associated statement allowed for 'omp flush' directive"); +    Res = ActOnOpenMPFlushDirective(ClausesWithImplicit, StartLoc, EndLoc); +    break; +  case OMPD_threadprivate:      llvm_unreachable("OpenMP Directive is not allowed");    case OMPD_unknown: -  case NUM_OPENMP_DIRECTIVES:      llvm_unreachable("Unknown OpenMP directive");    } -  if (ErrorFound) return StmtError(); +  for (auto P : VarsWithInheritedDSA) { +    Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable) +        << P.first << P.second->getSourceRange(); +  } +  if (!VarsWithInheritedDSA.empty()) +    return StmtError(); + +  if (ErrorFound) +    return StmtError();    return Res;  } @@ -696,31 +1509,1004 @@ StmtResult Sema::ActOnOpenMPParallelDirective(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 Owned(OMPParallelDirective::Create(Context, StartLoc, EndLoc, -                                            Clauses, AStmt)); +  return OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, +                                      AStmt);  } -OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, -                                         unsigned Argument, -                                         SourceLocation ArgumentLoc, -                                         SourceLocation StartLoc, -                                         SourceLocation LParenLoc, -                                         SourceLocation EndLoc) { -  OMPClause *Res = 0; +namespace { +/// \brief Helper class for checking canonical form of the OpenMP loops and +/// extracting iteration space of each loop in the loop nest, that will be used +/// for IR generation. +class OpenMPIterationSpaceChecker { +  /// \brief Reference to Sema. +  Sema &SemaRef; +  /// \brief A location for diagnostics (when there is no some better location). +  SourceLocation DefaultLoc; +  /// \brief A location for diagnostics (when increment is not compatible). +  SourceLocation ConditionLoc; +  /// \brief A source location for referring to condition later. +  SourceRange ConditionSrcRange; +  /// \brief Loop variable. +  VarDecl *Var; +  /// \brief Lower bound (initializer for the var). +  Expr *LB; +  /// \brief Upper bound. +  Expr *UB; +  /// \brief Loop step (increment). +  Expr *Step; +  /// \brief This flag is true when condition is one of: +  ///   Var <  UB +  ///   Var <= UB +  ///   UB  >  Var +  ///   UB  >= Var +  bool TestIsLessOp; +  /// \brief This flag is true when condition is strict ( < or > ). +  bool TestIsStrictOp; +  /// \brief This flag is true when step is subtracted on each iteration. +  bool SubtractStep; + +public: +  OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc) +      : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc), +        ConditionSrcRange(SourceRange()), Var(nullptr), LB(nullptr), +        UB(nullptr), Step(nullptr), TestIsLessOp(false), TestIsStrictOp(false), +        SubtractStep(false) {} +  /// \brief Check init-expr for canonical loop form and save loop counter +  /// variable - #Var and its initialization value - #LB. +  bool CheckInit(Stmt *S); +  /// \brief Check test-expr for canonical form, save upper-bound (#UB), flags +  /// for less/greater and for strict/non-strict comparison. +  bool CheckCond(Expr *S); +  /// \brief Check incr-expr for canonical loop form and return true if it +  /// does not conform, otherwise save loop step (#Step). +  bool CheckInc(Expr *S); +  /// \brief Return the loop counter variable. +  VarDecl *GetLoopVar() const { return Var; } +  /// \brief Return true if any expression is dependent. +  bool Dependent() const; + +private: +  /// \brief Check the right-hand side of an assignment in the increment +  /// expression. +  bool CheckIncRHS(Expr *RHS); +  /// \brief Helper to set loop counter variable and its initializer. +  bool SetVarAndLB(VarDecl *NewVar, Expr *NewLB); +  /// \brief Helper to set upper bound. +  bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, const SourceRange &SR, +             const SourceLocation &SL); +  /// \brief Helper to set loop increment. +  bool SetStep(Expr *NewStep, bool Subtract); +}; + +bool OpenMPIterationSpaceChecker::Dependent() const { +  if (!Var) { +    assert(!LB && !UB && !Step); +    return false; +  } +  return Var->getType()->isDependentType() || (LB && LB->isValueDependent()) || +         (UB && UB->isValueDependent()) || (Step && Step->isValueDependent()); +} + +bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, Expr *NewLB) { +  // State consistency checking to ensure correct usage. +  assert(Var == nullptr && LB == nullptr && UB == nullptr && Step == nullptr && +         !TestIsLessOp && !TestIsStrictOp); +  if (!NewVar || !NewLB) +    return true; +  Var = NewVar; +  LB = NewLB; +  return false; +} + +bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp, +                                        const SourceRange &SR, +                                        const SourceLocation &SL) { +  // State consistency checking to ensure correct usage. +  assert(Var != nullptr && LB != nullptr && UB == nullptr && Step == nullptr && +         !TestIsLessOp && !TestIsStrictOp); +  if (!NewUB) +    return true; +  UB = NewUB; +  TestIsLessOp = LessOp; +  TestIsStrictOp = StrictOp; +  ConditionSrcRange = SR; +  ConditionLoc = SL; +  return false; +} + +bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { +  // State consistency checking to ensure correct usage. +  assert(Var != nullptr && LB != nullptr && Step == nullptr); +  if (!NewStep) +    return true; +  if (!NewStep->isValueDependent()) { +    // Check that the step is integer expression. +    SourceLocation StepLoc = NewStep->getLocStart(); +    ExprResult Val = +        SemaRef.PerformOpenMPImplicitIntegerConversion(StepLoc, NewStep); +    if (Val.isInvalid()) +      return true; +    NewStep = Val.get(); + +    // OpenMP [2.6, Canonical Loop Form, Restrictions] +    //  If test-expr is of form var relational-op b and relational-op is < or +    //  <= then incr-expr must cause var to increase on each iteration of the +    //  loop. If test-expr is of form var relational-op b and relational-op is +    //  > or >= then incr-expr must cause var to decrease on each iteration of +    //  the loop. +    //  If test-expr is of form b relational-op var and relational-op is < or +    //  <= then incr-expr must cause var to decrease on each iteration of the +    //  loop. If test-expr is of form b relational-op var and relational-op is +    //  > or >= then incr-expr must cause var to increase on each iteration of +    //  the loop. +    llvm::APSInt Result; +    bool IsConstant = NewStep->isIntegerConstantExpr(Result, SemaRef.Context); +    bool IsUnsigned = !NewStep->getType()->hasSignedIntegerRepresentation(); +    bool IsConstNeg = +        IsConstant && Result.isSigned() && (Subtract != Result.isNegative()); +    bool IsConstZero = IsConstant && !Result.getBoolValue(); +    if (UB && (IsConstZero || +               (TestIsLessOp ? (IsConstNeg || (IsUnsigned && Subtract)) +                             : (!IsConstNeg || (IsUnsigned && !Subtract))))) { +      SemaRef.Diag(NewStep->getExprLoc(), +                   diag::err_omp_loop_incr_not_compatible) +          << Var << TestIsLessOp << NewStep->getSourceRange(); +      SemaRef.Diag(ConditionLoc, +                   diag::note_omp_loop_cond_requres_compatible_incr) +          << TestIsLessOp << ConditionSrcRange; +      return true; +    } +  } + +  Step = NewStep; +  SubtractStep = Subtract; +  return false; +} + +bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) { +  // Check init-expr for canonical loop form and save loop counter +  // variable - #Var and its initialization value - #LB. +  // OpenMP [2.6] Canonical loop form. init-expr may be one of the following: +  //   var = lb +  //   integer-type var = lb +  //   random-access-iterator-type var = lb +  //   pointer-type var = lb +  // +  if (!S) { +    SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init); +    return true; +  } +  if (Expr *E = dyn_cast<Expr>(S)) +    S = E->IgnoreParens(); +  if (auto BO = dyn_cast<BinaryOperator>(S)) { +    if (BO->getOpcode() == BO_Assign) +      if (auto DRE = dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens())) +        return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), BO->getLHS()); +  } else if (auto DS = dyn_cast<DeclStmt>(S)) { +    if (DS->isSingleDecl()) { +      if (auto Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) { +        if (Var->hasInit()) { +          // Accept non-canonical init form here but emit ext. warning. +          if (Var->getInitStyle() != VarDecl::CInit) +            SemaRef.Diag(S->getLocStart(), +                         diag::ext_omp_loop_not_canonical_init) +                << S->getSourceRange(); +          return SetVarAndLB(Var, Var->getInit()); +        } +      } +    } +  } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) +    if (CE->getOperator() == OO_Equal) +      if (auto DRE = dyn_cast<DeclRefExpr>(CE->getArg(0))) +        return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), CE->getArg(1)); + +  SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init) +      << S->getSourceRange(); +  return true; +} + +/// \brief Ignore parenthesizes, implicit casts, copy constructor and return the +/// variable (which may be the loop variable) if possible. +static const VarDecl *GetInitVarDecl(const Expr *E) { +  if (!E) +    return nullptr; +  E = E->IgnoreParenImpCasts(); +  if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(E)) +    if (const CXXConstructorDecl *Ctor = CE->getConstructor()) +      if (Ctor->isCopyConstructor() && CE->getNumArgs() == 1 && +          CE->getArg(0) != nullptr) +        E = CE->getArg(0)->IgnoreParenImpCasts(); +  auto DRE = dyn_cast_or_null<DeclRefExpr>(E); +  if (!DRE) +    return nullptr; +  return dyn_cast<VarDecl>(DRE->getDecl()); +} + +bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { +  // Check test-expr for canonical form, save upper-bound UB, flags for +  // less/greater and for strict/non-strict comparison. +  // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following: +  //   var relational-op b +  //   b relational-op var +  // +  if (!S) { +    SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << Var; +    return true; +  } +  S = S->IgnoreParenImpCasts(); +  SourceLocation CondLoc = S->getLocStart(); +  if (auto BO = dyn_cast<BinaryOperator>(S)) { +    if (BO->isRelationalOp()) { +      if (GetInitVarDecl(BO->getLHS()) == Var) +        return SetUB(BO->getRHS(), +                     (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE), +                     (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), +                     BO->getSourceRange(), BO->getOperatorLoc()); +      if (GetInitVarDecl(BO->getRHS()) == Var) +        return SetUB(BO->getLHS(), +                     (BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE), +                     (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), +                     BO->getSourceRange(), BO->getOperatorLoc()); +    } +  } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) { +    if (CE->getNumArgs() == 2) { +      auto Op = CE->getOperator(); +      switch (Op) { +      case OO_Greater: +      case OO_GreaterEqual: +      case OO_Less: +      case OO_LessEqual: +        if (GetInitVarDecl(CE->getArg(0)) == Var) +          return SetUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual, +                       Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), +                       CE->getOperatorLoc()); +        if (GetInitVarDecl(CE->getArg(1)) == Var) +          return SetUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual, +                       Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), +                       CE->getOperatorLoc()); +        break; +      default: +        break; +      } +    } +  } +  SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond) +      << S->getSourceRange() << Var; +  return true; +} + +bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) { +  // RHS of canonical loop form increment can be: +  //   var + incr +  //   incr + var +  //   var - incr +  // +  RHS = RHS->IgnoreParenImpCasts(); +  if (auto BO = dyn_cast<BinaryOperator>(RHS)) { +    if (BO->isAdditiveOp()) { +      bool IsAdd = BO->getOpcode() == BO_Add; +      if (GetInitVarDecl(BO->getLHS()) == Var) +        return SetStep(BO->getRHS(), !IsAdd); +      if (IsAdd && GetInitVarDecl(BO->getRHS()) == Var) +        return SetStep(BO->getLHS(), false); +    } +  } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(RHS)) { +    bool IsAdd = CE->getOperator() == OO_Plus; +    if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) { +      if (GetInitVarDecl(CE->getArg(0)) == Var) +        return SetStep(CE->getArg(1), !IsAdd); +      if (IsAdd && GetInitVarDecl(CE->getArg(1)) == Var) +        return SetStep(CE->getArg(0), false); +    } +  } +  SemaRef.Diag(RHS->getLocStart(), diag::err_omp_loop_not_canonical_incr) +      << RHS->getSourceRange() << Var; +  return true; +} + +bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { +  // Check incr-expr for canonical loop form and return true if it +  // does not conform. +  // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following: +  //   ++var +  //   var++ +  //   --var +  //   var-- +  //   var += incr +  //   var -= incr +  //   var = var + incr +  //   var = incr + var +  //   var = var - incr +  // +  if (!S) { +    SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << Var; +    return true; +  } +  S = S->IgnoreParens(); +  if (auto UO = dyn_cast<UnaryOperator>(S)) { +    if (UO->isIncrementDecrementOp() && GetInitVarDecl(UO->getSubExpr()) == Var) +      return SetStep( +          SemaRef.ActOnIntegerConstant(UO->getLocStart(), +                                       (UO->isDecrementOp() ? -1 : 1)).get(), +          false); +  } else if (auto BO = dyn_cast<BinaryOperator>(S)) { +    switch (BO->getOpcode()) { +    case BO_AddAssign: +    case BO_SubAssign: +      if (GetInitVarDecl(BO->getLHS()) == Var) +        return SetStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign); +      break; +    case BO_Assign: +      if (GetInitVarDecl(BO->getLHS()) == Var) +        return CheckIncRHS(BO->getRHS()); +      break; +    default: +      break; +    } +  } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) { +    switch (CE->getOperator()) { +    case OO_PlusPlus: +    case OO_MinusMinus: +      if (GetInitVarDecl(CE->getArg(0)) == Var) +        return SetStep( +            SemaRef.ActOnIntegerConstant( +                        CE->getLocStart(), +                        ((CE->getOperator() == OO_MinusMinus) ? -1 : 1)).get(), +            false); +      break; +    case OO_PlusEqual: +    case OO_MinusEqual: +      if (GetInitVarDecl(CE->getArg(0)) == Var) +        return SetStep(CE->getArg(1), CE->getOperator() == OO_MinusEqual); +      break; +    case OO_Equal: +      if (GetInitVarDecl(CE->getArg(0)) == Var) +        return CheckIncRHS(CE->getArg(1)); +      break; +    default: +      break; +    } +  } +  SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_incr) +      << S->getSourceRange() << Var; +  return true; +} +} // namespace + +/// \brief Called on a for stmt to check and extract its iteration space +/// for further processing (such as collapsing). +static bool CheckOpenMPIterationSpace( +    OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA, +    unsigned CurrentNestedLoopCount, unsigned NestedLoopCount, +    Expr *NestedLoopCountExpr, +    llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { +  // OpenMP [2.6, Canonical Loop Form] +  //   for (init-expr; test-expr; incr-expr) structured-block +  auto For = dyn_cast_or_null<ForStmt>(S); +  if (!For) { +    SemaRef.Diag(S->getLocStart(), diag::err_omp_not_for) +        << (NestedLoopCountExpr != nullptr) << getOpenMPDirectiveName(DKind) +        << NestedLoopCount << (CurrentNestedLoopCount > 0) +        << CurrentNestedLoopCount; +    if (NestedLoopCount > 1) +      SemaRef.Diag(NestedLoopCountExpr->getExprLoc(), +                   diag::note_omp_collapse_expr) +          << NestedLoopCountExpr->getSourceRange(); +    return true; +  } +  assert(For->getBody()); + +  OpenMPIterationSpaceChecker ISC(SemaRef, For->getForLoc()); + +  // Check init. +  auto Init = For->getInit(); +  if (ISC.CheckInit(Init)) { +    return true; +  } + +  bool HasErrors = false; + +  // Check loop variable's type. +  auto Var = ISC.GetLoopVar(); + +  // OpenMP [2.6, Canonical Loop Form] +  // Var is one of the following: +  //   A variable of signed or unsigned integer type. +  //   For C++, a variable of a random access iterator type. +  //   For C, a variable of a pointer type. +  auto VarType = Var->getType(); +  if (!VarType->isDependentType() && !VarType->isIntegerType() && +      !VarType->isPointerType() && +      !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) { +    SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type) +        << SemaRef.getLangOpts().CPlusPlus; +    HasErrors = true; +  } + +  // OpenMP, 2.14.1.1 Data-sharing Attribute Rules for Variables Referenced in a +  // Construct +  // The loop iteration variable(s) in the associated for-loop(s) of a for or +  // parallel for construct is (are) private. +  // The loop iteration variable in the associated for-loop of a simd construct +  // with just one associated for-loop is linear with a constant-linear-step +  // that is the increment of the associated for-loop. +  // Exclude loop var from the list of variables with implicitly defined data +  // sharing attributes. +  while (VarsWithImplicitDSA.count(Var) > 0) +    VarsWithImplicitDSA.erase(Var); + +  // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced in +  // a Construct, C/C++]. +  // The loop iteration variable in the associated for-loop of a simd construct +  // with just one associated for-loop may be listed in a linear clause with a +  // 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, false); +  auto PredeterminedCKind = +      isOpenMPSimdDirective(DKind) +          ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) +          : OMPC_private; +  if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && +        DVar.CKind != PredeterminedCKind) || +       (isOpenMPWorksharingDirective(DKind) && DVar.CKind != OMPC_unknown && +        DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && +      (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { +    SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa) +        << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind) +        << getOpenMPClauseName(PredeterminedCKind); +    ReportOriginalDSA(SemaRef, &DSA, Var, DVar, true); +    HasErrors = true; +  } else { +    // Make the loop iteration variable private (for worksharing constructs), +    // linear (for simd directives with the only one associated loop) or +    // lastprivate (for simd directives with several collapsed loops). +    DSA.addDSA(Var, nullptr, PredeterminedCKind); +  } + +  assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); + +  // Check test-expr. +  HasErrors |= ISC.CheckCond(For->getCond()); + +  // Check incr-expr. +  HasErrors |= ISC.CheckInc(For->getInc()); + +  if (ISC.Dependent()) +    return HasErrors; + +  // FIXME: Build loop's iteration space representation. +  return HasErrors; +} + +/// \brief A helper routine to skip no-op (attributed, compound) stmts get the +/// next nested for loop. If \a IgnoreCaptured is true, it skips captured stmt +/// to get the first for loop. +static Stmt *IgnoreContainerStmts(Stmt *S, bool IgnoreCaptured) { +  if (IgnoreCaptured) +    if (auto CapS = dyn_cast_or_null<CapturedStmt>(S)) +      S = CapS->getCapturedStmt(); +  // OpenMP [2.8.1, simd construct, Restrictions] +  // All loops associated with the construct must be perfectly nested; that is, +  // there must be no intervening code nor any OpenMP directive between any two +  // loops. +  while (true) { +    if (auto AS = dyn_cast_or_null<AttributedStmt>(S)) +      S = AS->getSubStmt(); +    else if (auto CS = dyn_cast_or_null<CompoundStmt>(S)) { +      if (CS->size() != 1) +        break; +      S = CS->body_back(); +    } else +      break; +  } +  return S; +} + +/// \brief Called on a for stmt to check itself and nested loops (if any). +/// \return Returns 0 if one of the collapsed stmts is not canonical for loop, +/// number of collapsed loops otherwise. +static unsigned +CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, +                Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA, +                llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { +  unsigned NestedLoopCount = 1; +  if (NestedLoopCountExpr) { +    // Found 'collapse' clause - calculate collapse number. +    llvm::APSInt Result; +    if (NestedLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) +      NestedLoopCount = Result.getLimitedValue(); +  } +  // This is helper routine for loop directives (e.g., 'for', 'simd', +  // 'for simd', etc.). +  Stmt *CurStmt = IgnoreContainerStmts(AStmt, true); +  for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) { +    if (CheckOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt, +                                  NestedLoopCount, NestedLoopCountExpr, +                                  VarsWithImplicitDSA)) +      return 0; +    // Move on to the next nested for loop, or to the loop body. +    CurStmt = IgnoreContainerStmts(cast<ForStmt>(CurStmt)->getBody(), false); +  } + +  // FIXME: Build resulting iteration space for IR generation (collapsing +  // iteration spaces when loop count > 1 ('collapse' clause)). +  return NestedLoopCount; +} + +static Expr *GetCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) { +  auto CollapseFilter = [](const OMPClause *C) -> bool { +    return C->getClauseKind() == OMPC_collapse; +  }; +  OMPExecutableDirective::filtered_clause_iterator<decltype(CollapseFilter)> I( +      Clauses, CollapseFilter); +  if (I) +    return cast<OMPCollapseClause>(*I)->getNumForLoops(); +  return nullptr; +} + +StmtResult Sema::ActOnOpenMPSimdDirective( +    ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, +    SourceLocation EndLoc, +    llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { +  // In presence of clause 'collapse', it will define the nested loops number. +  unsigned NestedLoopCount = +      CheckOpenMPLoop(OMPD_simd, GetCollapseNumberExpr(Clauses), AStmt, *this, +                      *DSAStack, VarsWithImplicitDSA); +  if (NestedLoopCount == 0) +    return StmtError(); + +  getCurFunction()->setHasBranchProtectedScope(); +  return OMPSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, +                                  Clauses, AStmt); +} + +StmtResult Sema::ActOnOpenMPForDirective( +    ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, +    SourceLocation EndLoc, +    llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { +  // In presence of clause 'collapse', it will define the nested loops number. +  unsigned NestedLoopCount = +      CheckOpenMPLoop(OMPD_for, GetCollapseNumberExpr(Clauses), AStmt, *this, +                      *DSAStack, VarsWithImplicitDSA); +  if (NestedLoopCount == 0) +    return StmtError(); + +  getCurFunction()->setHasBranchProtectedScope(); +  return OMPForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, +                                 Clauses, AStmt); +} + +StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses, +                                              Stmt *AStmt, +                                              SourceLocation StartLoc, +                                              SourceLocation EndLoc) { +  assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); +  auto BaseStmt = AStmt; +  while (CapturedStmt *CS = dyn_cast_or_null<CapturedStmt>(BaseStmt)) +    BaseStmt = CS->getCapturedStmt(); +  if (auto C = dyn_cast_or_null<CompoundStmt>(BaseStmt)) { +    auto S = C->children(); +    if (!S) +      return StmtError(); +    // All associated statements must be '#pragma omp section' except for +    // the first one. +    for (++S; S; ++S) { +      auto SectionStmt = *S; +      if (!SectionStmt || !isa<OMPSectionDirective>(SectionStmt)) { +        if (SectionStmt) +          Diag(SectionStmt->getLocStart(), +               diag::err_omp_sections_substmt_not_section); +        return StmtError(); +      } +    } +  } else { +    Diag(AStmt->getLocStart(), diag::err_omp_sections_not_compound_stmt); +    return StmtError(); +  } + +  getCurFunction()->setHasBranchProtectedScope(); + +  return OMPSectionsDirective::Create(Context, StartLoc, EndLoc, Clauses, +                                      AStmt); +} + +StmtResult Sema::ActOnOpenMPSectionDirective(Stmt *AStmt, +                                             SourceLocation StartLoc, +                                             SourceLocation EndLoc) { +  assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + +  getCurFunction()->setHasBranchProtectedScope(); + +  return OMPSectionDirective::Create(Context, StartLoc, EndLoc, AStmt); +} + +StmtResult Sema::ActOnOpenMPSingleDirective(ArrayRef<OMPClause *> Clauses, +                                            Stmt *AStmt, +                                            SourceLocation StartLoc, +                                            SourceLocation EndLoc) { +  assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + +  getCurFunction()->setHasBranchProtectedScope(); + +  return OMPSingleDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); +} + +StmtResult Sema::ActOnOpenMPMasterDirective(Stmt *AStmt, +                                            SourceLocation StartLoc, +                                            SourceLocation EndLoc) { +  assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + +  getCurFunction()->setHasBranchProtectedScope(); + +  return OMPMasterDirective::Create(Context, StartLoc, EndLoc, AStmt); +} + +StmtResult +Sema::ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName, +                                   Stmt *AStmt, SourceLocation StartLoc, +                                   SourceLocation EndLoc) { +  assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + +  getCurFunction()->setHasBranchProtectedScope(); + +  return OMPCriticalDirective::Create(Context, DirName, StartLoc, EndLoc, +                                      AStmt); +} + +StmtResult Sema::ActOnOpenMPParallelForDirective( +    ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, +    SourceLocation EndLoc, +    llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { +  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(); + +  // In presence of clause 'collapse', it will define the nested loops number. +  unsigned NestedLoopCount = +      CheckOpenMPLoop(OMPD_parallel_for, GetCollapseNumberExpr(Clauses), AStmt, +                      *this, *DSAStack, VarsWithImplicitDSA); +  if (NestedLoopCount == 0) +    return StmtError(); + +  getCurFunction()->setHasBranchProtectedScope(); +  return OMPParallelForDirective::Create(Context, StartLoc, EndLoc, +                                         NestedLoopCount, Clauses, AStmt); +} + +StmtResult +Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses, +                                           Stmt *AStmt, SourceLocation StartLoc, +                                           SourceLocation EndLoc) { +  assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); +  auto BaseStmt = AStmt; +  while (CapturedStmt *CS = dyn_cast_or_null<CapturedStmt>(BaseStmt)) +    BaseStmt = CS->getCapturedStmt(); +  if (auto C = dyn_cast_or_null<CompoundStmt>(BaseStmt)) { +    auto S = C->children(); +    if (!S) +      return StmtError(); +    // All associated statements must be '#pragma omp section' except for +    // the first one. +    for (++S; S; ++S) { +      auto SectionStmt = *S; +      if (!SectionStmt || !isa<OMPSectionDirective>(SectionStmt)) { +        if (SectionStmt) +          Diag(SectionStmt->getLocStart(), +               diag::err_omp_parallel_sections_substmt_not_section); +        return StmtError(); +      } +    } +  } else { +    Diag(AStmt->getLocStart(), +         diag::err_omp_parallel_sections_not_compound_stmt); +    return StmtError(); +  } + +  getCurFunction()->setHasBranchProtectedScope(); + +  return OMPParallelSectionsDirective::Create(Context, StartLoc, EndLoc, +                                              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); +} + +StmtResult Sema::ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc, +                                               SourceLocation EndLoc) { +  return OMPTaskyieldDirective::Create(Context, StartLoc, EndLoc); +} + +StmtResult Sema::ActOnOpenMPBarrierDirective(SourceLocation StartLoc, +                                             SourceLocation EndLoc) { +  return OMPBarrierDirective::Create(Context, StartLoc, EndLoc); +} + +StmtResult Sema::ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, +                                              SourceLocation EndLoc) { +  return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc); +} + +StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses, +                                           SourceLocation StartLoc, +                                           SourceLocation EndLoc) { +  assert(Clauses.size() <= 1 && "Extra clauses in flush directive"); +  return OMPFlushDirective::Create(Context, StartLoc, EndLoc, Clauses); +} + +OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, +                                             SourceLocation StartLoc, +                                             SourceLocation LParenLoc, +                                             SourceLocation EndLoc) { +  OMPClause *Res = nullptr; +  switch (Kind) { +  case OMPC_if: +    Res = ActOnOpenMPIfClause(Expr, StartLoc, LParenLoc, EndLoc); +    break; +  case OMPC_final: +    Res = ActOnOpenMPFinalClause(Expr, StartLoc, LParenLoc, EndLoc); +    break; +  case OMPC_num_threads: +    Res = ActOnOpenMPNumThreadsClause(Expr, StartLoc, LParenLoc, EndLoc); +    break; +  case OMPC_safelen: +    Res = ActOnOpenMPSafelenClause(Expr, StartLoc, LParenLoc, EndLoc); +    break; +  case OMPC_collapse: +    Res = ActOnOpenMPCollapseClause(Expr, StartLoc, LParenLoc, EndLoc); +    break; +  case OMPC_default: +  case OMPC_proc_bind: +  case OMPC_schedule: +  case OMPC_private: +  case OMPC_firstprivate: +  case OMPC_lastprivate: +  case OMPC_shared: +  case OMPC_reduction: +  case OMPC_linear: +  case OMPC_aligned: +  case OMPC_copyin: +  case OMPC_copyprivate: +  case OMPC_ordered: +  case OMPC_nowait: +  case OMPC_untied: +  case OMPC_mergeable: +  case OMPC_threadprivate: +  case OMPC_flush: +  case OMPC_unknown: +    llvm_unreachable("Clause is not allowed."); +  } +  return Res; +} + +OMPClause *Sema::ActOnOpenMPIfClause(Expr *Condition, SourceLocation StartLoc, +                                     SourceLocation LParenLoc, +                                     SourceLocation EndLoc) { +  Expr *ValExpr = Condition; +  if (!Condition->isValueDependent() && !Condition->isTypeDependent() && +      !Condition->isInstantiationDependent() && +      !Condition->containsUnexpandedParameterPack()) { +    ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(), +                                           Condition->getExprLoc(), Condition); +    if (Val.isInvalid()) +      return nullptr; + +    ValExpr = Val.get(); +  } + +  return new (Context) OMPIfClause(ValExpr, StartLoc, LParenLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition, +                                        SourceLocation StartLoc, +                                        SourceLocation LParenLoc, +                                        SourceLocation EndLoc) { +  Expr *ValExpr = Condition; +  if (!Condition->isValueDependent() && !Condition->isTypeDependent() && +      !Condition->isInstantiationDependent() && +      !Condition->containsUnexpandedParameterPack()) { +    ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(), +                                           Condition->getExprLoc(), Condition); +    if (Val.isInvalid()) +      return nullptr; + +    ValExpr = Val.get(); +  } + +  return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc); +} + +ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc, +                                                        Expr *Op) { +  if (!Op) +    return ExprError(); + +  class IntConvertDiagnoser : public ICEConvertDiagnoser { +  public: +    IntConvertDiagnoser() +        : ICEConvertDiagnoser(/*AllowScopedEnumerations*/ false, false, true) {} +    SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, +                                         QualType T) override { +      return S.Diag(Loc, diag::err_omp_not_integral) << T; +    } +    SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, +                                             QualType T) override { +      return S.Diag(Loc, diag::err_omp_incomplete_type) << T; +    } +    SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc, +                                               QualType T, +                                               QualType ConvTy) override { +      return S.Diag(Loc, diag::err_omp_explicit_conversion) << T << ConvTy; +    } +    SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, +                                           QualType ConvTy) override { +      return S.Diag(Conv->getLocation(), diag::note_omp_conversion_here) +             << ConvTy->isEnumeralType() << ConvTy; +    } +    SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, +                                            QualType T) override { +      return S.Diag(Loc, diag::err_omp_ambiguous_conversion) << T; +    } +    SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, +                                        QualType ConvTy) override { +      return S.Diag(Conv->getLocation(), diag::note_omp_conversion_here) +             << ConvTy->isEnumeralType() << ConvTy; +    } +    SemaDiagnosticBuilder diagnoseConversion(Sema &, SourceLocation, QualType, +                                             QualType) override { +      llvm_unreachable("conversion functions are permitted"); +    } +  } ConvertDiagnoser; +  return PerformContextualImplicitConversion(Loc, Op, ConvertDiagnoser); +} + +OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads, +                                             SourceLocation StartLoc, +                                             SourceLocation LParenLoc, +                                             SourceLocation EndLoc) { +  Expr *ValExpr = NumThreads; +  if (!NumThreads->isValueDependent() && !NumThreads->isTypeDependent() && +      !NumThreads->isInstantiationDependent() && +      !NumThreads->containsUnexpandedParameterPack()) { +    SourceLocation NumThreadsLoc = NumThreads->getLocStart(); +    ExprResult Val = +        PerformOpenMPImplicitIntegerConversion(NumThreadsLoc, NumThreads); +    if (Val.isInvalid()) +      return nullptr; + +    ValExpr = Val.get(); + +    // OpenMP [2.5, Restrictions] +    //  The num_threads expression must evaluate to a positive integer value. +    llvm::APSInt Result; +    if (ValExpr->isIntegerConstantExpr(Result, Context) && Result.isSigned() && +        !Result.isStrictlyPositive()) { +      Diag(NumThreadsLoc, diag::err_omp_negative_expression_in_clause) +          << "num_threads" << NumThreads->getSourceRange(); +      return nullptr; +    } +  } + +  return new (Context) +      OMPNumThreadsClause(ValExpr, StartLoc, LParenLoc, EndLoc); +} + +ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E, +                                                       OpenMPClauseKind CKind) { +  if (!E) +    return ExprError(); +  if (E->isValueDependent() || E->isTypeDependent() || +      E->isInstantiationDependent() || E->containsUnexpandedParameterPack()) +    return E; +  llvm::APSInt Result; +  ExprResult ICE = VerifyIntegerConstantExpression(E, &Result); +  if (ICE.isInvalid()) +    return ExprError(); +  if (!Result.isStrictlyPositive()) { +    Diag(E->getExprLoc(), diag::err_omp_negative_expression_in_clause) +        << getOpenMPClauseName(CKind) << E->getSourceRange(); +    return ExprError(); +  } +  return ICE; +} + +OMPClause *Sema::ActOnOpenMPSafelenClause(Expr *Len, SourceLocation StartLoc, +                                          SourceLocation LParenLoc, +                                          SourceLocation EndLoc) { +  // OpenMP [2.8.1, simd construct, Description] +  // The parameter of the safelen clause must be a constant +  // positive integer expression. +  ExprResult Safelen = VerifyPositiveIntegerConstantInClause(Len, OMPC_safelen); +  if (Safelen.isInvalid()) +    return nullptr; +  return new (Context) +      OMPSafelenClause(Safelen.get(), StartLoc, LParenLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *NumForLoops, +                                           SourceLocation StartLoc, +                                           SourceLocation LParenLoc, +                                           SourceLocation EndLoc) { +  // OpenMP [2.7.1, loop construct, Description] +  // OpenMP [2.8.1, simd construct, Description] +  // OpenMP [2.9.6, distribute construct, Description] +  // The parameter of the collapse clause must be a constant +  // positive integer expression. +  ExprResult NumForLoopsResult = +      VerifyPositiveIntegerConstantInClause(NumForLoops, OMPC_collapse); +  if (NumForLoopsResult.isInvalid()) +    return nullptr; +  return new (Context) +      OMPCollapseClause(NumForLoopsResult.get(), StartLoc, LParenLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPSimpleClause( +    OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc, +    SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { +  OMPClause *Res = nullptr;    switch (Kind) {    case OMPC_default:      Res = -      ActOnOpenMPDefaultClause(static_cast<OpenMPDefaultClauseKind>(Argument), -                               ArgumentLoc, StartLoc, LParenLoc, EndLoc); +        ActOnOpenMPDefaultClause(static_cast<OpenMPDefaultClauseKind>(Argument), +                                 ArgumentLoc, StartLoc, LParenLoc, EndLoc);      break; +  case OMPC_proc_bind: +    Res = ActOnOpenMPProcBindClause( +        static_cast<OpenMPProcBindClauseKind>(Argument), ArgumentLoc, StartLoc, +        LParenLoc, EndLoc); +    break; +  case OMPC_if: +  case OMPC_final: +  case OMPC_num_threads: +  case OMPC_safelen: +  case OMPC_collapse: +  case OMPC_schedule:    case OMPC_private:    case OMPC_firstprivate: +  case OMPC_lastprivate:    case OMPC_shared: +  case OMPC_reduction: +  case OMPC_linear: +  case OMPC_aligned: +  case OMPC_copyin: +  case OMPC_copyprivate: +  case OMPC_ordered: +  case OMPC_nowait: +  case OMPC_untied: +  case OMPC_mergeable:    case OMPC_threadprivate: +  case OMPC_flush:    case OMPC_unknown: -  case NUM_OPENMP_CLAUSES:      llvm_unreachable("Clause is not allowed.");    }    return Res; @@ -733,17 +2519,18 @@ OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,                                            SourceLocation EndLoc) {    if (Kind == OMPC_DEFAULT_unknown) {      std::string Values; -    std::string Sep(NUM_OPENMP_DEFAULT_KINDS > 1 ? ", " : ""); -    for (unsigned i = OMPC_DEFAULT_unknown + 1; -         i < NUM_OPENMP_DEFAULT_KINDS; ++i) { +    static_assert(OMPC_DEFAULT_unknown > 0, +                  "OMPC_DEFAULT_unknown not greater than 0"); +    std::string Sep(", "); +    for (unsigned i = 0; i < OMPC_DEFAULT_unknown; ++i) {        Values += "'";        Values += getOpenMPSimpleClauseTypeName(OMPC_default, i);        Values += "'";        switch (i) { -      case NUM_OPENMP_DEFAULT_KINDS - 2: +      case OMPC_DEFAULT_unknown - 2:          Values += " or ";          break; -      case NUM_OPENMP_DEFAULT_KINDS - 1: +      case OMPC_DEFAULT_unknown - 1:          break;        default:          Values += Sep; @@ -751,29 +2538,219 @@ OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,        }      }      Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) -      << Values << getOpenMPClauseName(OMPC_default); -    return 0; +        << Values << getOpenMPClauseName(OMPC_default); +    return nullptr;    }    switch (Kind) {    case OMPC_DEFAULT_none: -    DSAStack->setDefaultDSANone(); +    DSAStack->setDefaultDSANone(KindKwLoc);      break;    case OMPC_DEFAULT_shared: -    DSAStack->setDefaultDSAShared(); +    DSAStack->setDefaultDSAShared(KindKwLoc);      break; -  default: +  case OMPC_DEFAULT_unknown: +    llvm_unreachable("Clause kind is not allowed.");      break;    } -  return new (Context) OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, -                                        EndLoc); +  return new (Context) +      OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);  } -OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, -                                          ArrayRef<Expr *> VarList, -                                          SourceLocation StartLoc, -                                          SourceLocation LParenLoc, +OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind, +                                           SourceLocation KindKwLoc, +                                           SourceLocation StartLoc, +                                           SourceLocation LParenLoc, +                                           SourceLocation EndLoc) { +  if (Kind == OMPC_PROC_BIND_unknown) { +    std::string Values; +    std::string Sep(", "); +    for (unsigned i = 0; i < OMPC_PROC_BIND_unknown; ++i) { +      Values += "'"; +      Values += getOpenMPSimpleClauseTypeName(OMPC_proc_bind, i); +      Values += "'"; +      switch (i) { +      case OMPC_PROC_BIND_unknown - 2: +        Values += " or "; +        break; +      case OMPC_PROC_BIND_unknown - 1: +        break; +      default: +        Values += Sep; +        break; +      } +    } +    Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) +        << Values << getOpenMPClauseName(OMPC_proc_bind); +    return nullptr; +  } +  return new (Context) +      OMPProcBindClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( +    OpenMPClauseKind Kind, unsigned Argument, Expr *Expr, +    SourceLocation StartLoc, SourceLocation LParenLoc, +    SourceLocation ArgumentLoc, SourceLocation CommaLoc, +    SourceLocation EndLoc) { +  OMPClause *Res = nullptr; +  switch (Kind) { +  case OMPC_schedule: +    Res = ActOnOpenMPScheduleClause( +        static_cast<OpenMPScheduleClauseKind>(Argument), Expr, StartLoc, +        LParenLoc, ArgumentLoc, CommaLoc, EndLoc); +    break; +  case OMPC_if: +  case OMPC_final: +  case OMPC_num_threads: +  case OMPC_safelen: +  case OMPC_collapse: +  case OMPC_default: +  case OMPC_proc_bind: +  case OMPC_private: +  case OMPC_firstprivate: +  case OMPC_lastprivate: +  case OMPC_shared: +  case OMPC_reduction: +  case OMPC_linear: +  case OMPC_aligned: +  case OMPC_copyin: +  case OMPC_copyprivate: +  case OMPC_ordered: +  case OMPC_nowait: +  case OMPC_untied: +  case OMPC_mergeable: +  case OMPC_threadprivate: +  case OMPC_flush: +  case OMPC_unknown: +    llvm_unreachable("Clause is not allowed."); +  } +  return Res; +} + +OMPClause *Sema::ActOnOpenMPScheduleClause( +    OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, +    SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, +    SourceLocation EndLoc) { +  if (Kind == OMPC_SCHEDULE_unknown) { +    std::string Values; +    std::string Sep(", "); +    for (unsigned i = 0; i < OMPC_SCHEDULE_unknown; ++i) { +      Values += "'"; +      Values += getOpenMPSimpleClauseTypeName(OMPC_schedule, i); +      Values += "'"; +      switch (i) { +      case OMPC_SCHEDULE_unknown - 2: +        Values += " or "; +        break; +      case OMPC_SCHEDULE_unknown - 1: +        break; +      default: +        Values += Sep; +        break; +      } +    } +    Diag(KindLoc, diag::err_omp_unexpected_clause_value) +        << Values << getOpenMPClauseName(OMPC_schedule); +    return nullptr; +  } +  Expr *ValExpr = ChunkSize; +  if (ChunkSize) { +    if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() && +        !ChunkSize->isInstantiationDependent() && +        !ChunkSize->containsUnexpandedParameterPack()) { +      SourceLocation ChunkSizeLoc = ChunkSize->getLocStart(); +      ExprResult Val = +          PerformOpenMPImplicitIntegerConversion(ChunkSizeLoc, ChunkSize); +      if (Val.isInvalid()) +        return nullptr; + +      ValExpr = Val.get(); + +      // OpenMP [2.7.1, Restrictions] +      //  chunk_size must be a loop invariant integer expression with a positive +      //  value. +      llvm::APSInt Result; +      if (ValExpr->isIntegerConstantExpr(Result, Context) && +          Result.isSigned() && !Result.isStrictlyPositive()) { +        Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause) +            << "schedule" << ChunkSize->getSourceRange(); +        return nullptr; +      } +    } +  } + +  return new (Context) OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, +                                         EndLoc, Kind, ValExpr); +} + +OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, +                                   SourceLocation StartLoc, +                                   SourceLocation EndLoc) { +  OMPClause *Res = nullptr; +  switch (Kind) { +  case OMPC_ordered: +    Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc); +    break; +  case OMPC_nowait: +    Res = ActOnOpenMPNowaitClause(StartLoc, EndLoc); +    break; +  case OMPC_untied: +    Res = ActOnOpenMPUntiedClause(StartLoc, EndLoc); +    break; +  case OMPC_mergeable: +    Res = ActOnOpenMPMergeableClause(StartLoc, EndLoc); +    break; +  case OMPC_if: +  case OMPC_final: +  case OMPC_num_threads: +  case OMPC_safelen: +  case OMPC_collapse: +  case OMPC_schedule: +  case OMPC_private: +  case OMPC_firstprivate: +  case OMPC_lastprivate: +  case OMPC_shared: +  case OMPC_reduction: +  case OMPC_linear: +  case OMPC_aligned: +  case OMPC_copyin: +  case OMPC_copyprivate: +  case OMPC_default: +  case OMPC_proc_bind: +  case OMPC_threadprivate: +  case OMPC_flush: +  case OMPC_unknown: +    llvm_unreachable("Clause is not allowed."); +  } +  return Res; +} + +OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc,                                            SourceLocation EndLoc) { -  OMPClause *Res = 0; +  return new (Context) OMPOrderedClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPNowaitClause(SourceLocation StartLoc, +                                         SourceLocation EndLoc) { +  return new (Context) OMPNowaitClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPUntiedClause(SourceLocation StartLoc, +                                         SourceLocation EndLoc) { +  return new (Context) OMPUntiedClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPMergeableClause(SourceLocation StartLoc, +                                            SourceLocation EndLoc) { +  return new (Context) OMPMergeableClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPVarListClause( +    OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr, +    SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, +    SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, +    const DeclarationNameInfo &ReductionId) { +  OMPClause *Res = nullptr;    switch (Kind) {    case OMPC_private:      Res = ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc); @@ -781,13 +2758,47 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,    case OMPC_firstprivate:      Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc);      break; +  case OMPC_lastprivate: +    Res = ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc, EndLoc); +    break;    case OMPC_shared:      Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);      break; +  case OMPC_reduction: +    Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, +                                     EndLoc, ReductionIdScopeSpec, ReductionId); +    break; +  case OMPC_linear: +    Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc, +                                  ColonLoc, EndLoc); +    break; +  case OMPC_aligned: +    Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc, +                                   ColonLoc, EndLoc); +    break; +  case OMPC_copyin: +    Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc); +    break; +  case OMPC_copyprivate: +    Res = ActOnOpenMPCopyprivateClause(VarList, StartLoc, LParenLoc, EndLoc); +    break; +  case OMPC_flush: +    Res = ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc, EndLoc); +    break; +  case OMPC_if: +  case OMPC_final: +  case OMPC_num_threads: +  case OMPC_safelen: +  case OMPC_collapse:    case OMPC_default: +  case OMPC_proc_bind: +  case OMPC_schedule: +  case OMPC_ordered: +  case OMPC_nowait: +  case OMPC_untied: +  case OMPC_mergeable:    case OMPC_threadprivate:    case OMPC_unknown: -  case NUM_OPENMP_CLAUSES:      llvm_unreachable("Clause is not allowed.");    }    return Res; @@ -798,25 +2809,23 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,                                            SourceLocation LParenLoc,                                            SourceLocation EndLoc) {    SmallVector<Expr *, 8> Vars; -  for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); -       I != E; ++I) { -    assert(*I && "NULL expr in OpenMP private clause."); -    if (isa<DependentScopeDeclRefExpr>(*I)) { +  for (auto &RefExpr : VarList) { +    assert(RefExpr && "NULL expr in OpenMP private clause."); +    if (isa<DependentScopeDeclRefExpr>(RefExpr)) {        // It will be analyzed later. -      Vars.push_back(*I); +      Vars.push_back(RefExpr);        continue;      } -    SourceLocation ELoc = (*I)->getExprLoc(); +    SourceLocation ELoc = RefExpr->getExprLoc();      // OpenMP [2.1, C/C++]      //  A list item is a variable name.      // OpenMP  [2.9.3.3, Restrictions, p.1]      //  A variable that is part of another variable (as an array or      //  structure element) cannot appear in a private clause. -    DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I); +    DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);      if (!DE || !isa<VarDecl>(DE->getDecl())) { -      Diag(ELoc, diag::err_omp_expected_var_name) -        << (*I)->getSourceRange(); +      Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();        continue;      }      Decl *D = DE->getDecl(); @@ -838,39 +2847,44 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,      }      if (Type->isReferenceType()) {        Diag(ELoc, diag::err_omp_clause_ref_type_arg) -        << getOpenMPClauseName(OMPC_private) << Type; -      bool IsDecl = VD->isThisDeclarationADefinition(Context) == -                    VarDecl::DeclarationOnly; -      Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : -                                       diag::note_defined_here) << VD; +          << getOpenMPClauseName(OMPC_private) << Type; +      bool IsDecl = +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +      Diag(VD->getLocation(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD;        continue;      }      // OpenMP [2.9.3.3, Restrictions, C/C++, p.1]      //  A variable of class type (or array thereof) that appears in a private -    //  clause requires an accesible, unambiguous default constructor for the +    //  clause requires an accessible, unambiguous default constructor for the      //  class type.      while (Type.getNonReferenceType()->isArrayType()) { -      Type = cast<ArrayType>( -                 Type.getNonReferenceType().getTypePtr())->getElementType(); +      Type = cast<ArrayType>(Type.getNonReferenceType().getTypePtr()) +                 ->getElementType();      } -    CXXRecordDecl *RD = getLangOpts().CPlusPlus ? -                          Type.getNonReferenceType()->getAsCXXRecordDecl() : 0; +    CXXRecordDecl *RD = getLangOpts().CPlusPlus +                            ? Type.getNonReferenceType()->getAsCXXRecordDecl() +                            : nullptr; +    // FIXME This code must be replaced by actual constructing/destructing of +    // the private variable.      if (RD) {        CXXConstructorDecl *CD = LookupDefaultConstructor(RD);        PartialDiagnostic PD = -        PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); +          PartialDiagnostic(PartialDiagnostic::NullDiagnostic());        if (!CD ||            CheckConstructorAccess(ELoc, CD,                                   InitializedEntity::InitializeTemporary(Type),                                   CD->getAccess(), PD) == AR_inaccessible ||            CD->isDeleted()) {          Diag(ELoc, diag::err_omp_required_method) -             << getOpenMPClauseName(OMPC_private) << 0; +            << getOpenMPClauseName(OMPC_private) << 0;          bool IsDecl = VD->isThisDeclarationADefinition(Context) ==                        VarDecl::DeclarationOnly; -        Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : -                                         diag::note_defined_here) << VD; +        Diag(VD->getLocation(), +             IsDecl ? diag::note_previous_decl : diag::note_defined_here) +            << VD;          Diag(RD->getLocation(), diag::note_previous_decl) << RD;          continue;        } @@ -882,11 +2896,12 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,          if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||              DD->isDeleted()) {            Diag(ELoc, diag::err_omp_required_method) -               << getOpenMPClauseName(OMPC_private) << 4; +              << getOpenMPClauseName(OMPC_private) << 4;            bool IsDecl = VD->isThisDeclarationADefinition(Context) ==                          VarDecl::DeclarationOnly; -          Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : -                                           diag::note_defined_here) << VD; +          Diag(VD->getLocation(), +               IsDecl ? diag::note_previous_decl : diag::note_defined_here) +              << VD;            Diag(RD->getLocation(), diag::note_previous_decl) << RD;            continue;          } @@ -902,18 +2917,11 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,      //  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); -      if (DVar.RefExpr) { -        Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) -             << getOpenMPClauseName(DVar.CKind); -      } else { -        Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) -             << getOpenMPClauseName(DVar.CKind); -      } +      Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) +                                          << getOpenMPClauseName(OMPC_private); +      ReportOriginalDSA(*this, DSAStack, VD, DVar);        continue;      } @@ -921,7 +2929,8 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,      Vars.push_back(DE);    } -  if (Vars.empty()) return 0; +  if (Vars.empty()) +    return nullptr;    return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);  } @@ -931,25 +2940,28 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,                                                 SourceLocation LParenLoc,                                                 SourceLocation EndLoc) {    SmallVector<Expr *, 8> Vars; -  for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); -       I != E; ++I) { -    assert(*I && "NULL expr in OpenMP firstprivate clause."); -    if (isa<DependentScopeDeclRefExpr>(*I)) { +  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)) {        // It will be analyzed later. -      Vars.push_back(*I); +      Vars.push_back(RefExpr);        continue;      } -    SourceLocation ELoc = (*I)->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]      //  A variable that is part of another variable (as an array or      //  structure element) cannot appear in a private clause. -    DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I); +    DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);      if (!DE || !isa<VarDecl>(DE->getDecl())) { -      Diag(ELoc, diag::err_omp_expected_var_name) -        << (*I)->getSourceRange(); +      Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();        continue;      }      Decl *D = DE->getDecl(); @@ -970,37 +2982,56 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,        continue;      }      if (Type->isReferenceType()) { -      Diag(ELoc, diag::err_omp_clause_ref_type_arg) -        << getOpenMPClauseName(OMPC_firstprivate) << Type; -      bool IsDecl = VD->isThisDeclarationADefinition(Context) == -                    VarDecl::DeclarationOnly; -      Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : -                                       diag::note_defined_here) << VD; +      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(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD;        continue;      }      // OpenMP [2.9.3.4, Restrictions, C/C++, p.1]      //  A variable of class type (or array thereof) that appears in a private -    //  clause requires an accesible, unambiguous copy constructor for the +    //  clause requires an accessible, unambiguous copy constructor for the      //  class type.      Type = Context.getBaseElementType(Type); -    CXXRecordDecl *RD = getLangOpts().CPlusPlus ? -                          Type.getNonReferenceType()->getAsCXXRecordDecl() : 0; +    CXXRecordDecl *RD = getLangOpts().CPlusPlus +                            ? Type.getNonReferenceType()->getAsCXXRecordDecl() +                            : nullptr; +    // FIXME This code must be replaced by actual constructing/destructing of +    // the firstprivate variable.      if (RD) {        CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0);        PartialDiagnostic PD = -        PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); +          PartialDiagnostic(PartialDiagnostic::NullDiagnostic());        if (!CD ||            CheckConstructorAccess(ELoc, CD,                                   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(), IsDecl ? diag::note_previous_decl : -                                         diag::note_defined_here) << VD; +        Diag(VD->getLocation(), +             IsDecl ? diag::note_previous_decl : diag::note_defined_here) +            << VD;          Diag(RD->getLocation(), diag::note_previous_decl) << RD;          continue;        } @@ -1011,12 +3042,20 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,        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(), IsDecl ? diag::note_previous_decl : -                                           diag::note_defined_here) << VD; +          Diag(VD->getLocation(), +               IsDecl ? diag::note_previous_decl : diag::note_defined_here) +              << VD;            Diag(RD->getLocation(), diag::note_previous_decl) << RD;            continue;          } @@ -1025,10 +3064,9 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,        }      } -    // 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); @@ -1036,14 +3074,12 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,        //  A list item that specifies a given variable may not appear in more        // than one clause on the same directive, except that a variable may be        //  specified in both firstprivate and lastprivate clauses. -      //  TODO: add processing for lastprivate.        if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate && -          DVar.RefExpr) { +          DVar.CKind != OMPC_lastprivate && DVar.RefExpr) {          Diag(ELoc, diag::err_omp_wrong_dsa) -           << getOpenMPClauseName(DVar.CKind) -           << getOpenMPClauseName(OMPC_firstprivate); -        Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) -           << getOpenMPClauseName(DVar.CKind); +            << getOpenMPClauseName(DVar.CKind) +            << getOpenMPClauseName(OMPC_firstprivate); +        ReportOriginalDSA(*this, DSAStack, VD, DVar);          continue;        } @@ -1061,18 +3097,31 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,        if (!(IsConstant || VD->isStaticDataMember()) && !DVar.RefExpr &&            DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) {          Diag(ELoc, diag::err_omp_wrong_dsa) -           << getOpenMPClauseName(DVar.CKind) -           << getOpenMPClauseName(OMPC_firstprivate); -        Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) -           << getOpenMPClauseName(DVar.CKind); +            << getOpenMPClauseName(DVar.CKind) +            << getOpenMPClauseName(OMPC_firstprivate); +        ReportOriginalDSA(*this, DSAStack, VD, DVar);          continue;        } +      OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();        // OpenMP [2.9.3.4, Restrictions, p.2]        //  A list item that is private within a parallel region must not appear        //  in a firstprivate clause on a worksharing construct if any of the        //  worksharing regions arising from the worksharing construct ever bind        //  to any of the parallel regions arising from the parallel construct. +      if (isOpenMPWorksharingDirective(CurrDir) && +          !isOpenMPParallelDirective(CurrDir)) { +        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); +          ReportOriginalDSA(*this, DSAStack, VD, DVar); +          continue; +        } +      }        // OpenMP [2.9.3.4, Restrictions, p.3]        //  A list item that appears in a reduction clause of a parallel construct        //  must not appear in a firstprivate clause on a worksharing or task @@ -1084,43 +3133,214 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,        //  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);      Vars.push_back(DE);    } -  if (Vars.empty()) return 0; +  if (Vars.empty()) +    return nullptr;    return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,                                         Vars);  } +OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, +                                              SourceLocation StartLoc, +                                              SourceLocation LParenLoc, +                                              SourceLocation EndLoc) { +  SmallVector<Expr *, 8> Vars; +  for (auto &RefExpr : VarList) { +    assert(RefExpr && "NULL expr in OpenMP lastprivate clause."); +    if (isa<DependentScopeDeclRefExpr>(RefExpr)) { +      // It will be analyzed later. +      Vars.push_back(RefExpr); +      continue; +    } + +    SourceLocation ELoc = RefExpr->getExprLoc(); +    // OpenMP [2.1, C/C++] +    //  A list item is a variable name. +    // OpenMP  [2.14.3.5, Restrictions, p.1] +    //  A variable that is part of another variable (as an array or structure +    //  element) cannot appear in a lastprivate clause. +    DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr); +    if (!DE || !isa<VarDecl>(DE->getDecl())) { +      Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); +      continue; +    } +    Decl *D = DE->getDecl(); +    VarDecl *VD = cast<VarDecl>(D); + +    QualType Type = VD->getType(); +    if (Type->isDependentType() || Type->isInstantiationDependentType()) { +      // It will be analyzed later. +      Vars.push_back(DE); +      continue; +    } + +    // OpenMP [2.14.3.5, Restrictions, C/C++, p.2] +    //  A variable that appears in a lastprivate clause must not have an +    //  incomplete type or a reference type. +    if (RequireCompleteType(ELoc, Type, +                            diag::err_omp_lastprivate_incomplete_type)) { +      continue; +    } +    if (Type->isReferenceType()) { +      Diag(ELoc, diag::err_omp_clause_ref_type_arg) +          << getOpenMPClauseName(OMPC_lastprivate) << Type; +      bool IsDecl = +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +      Diag(VD->getLocation(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD; +      continue; +    } + +    // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced +    // in a Construct] +    //  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, false); +    if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate && +        DVar.CKind != OMPC_firstprivate && +        (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { +      Diag(ELoc, diag::err_omp_wrong_dsa) +          << getOpenMPClauseName(DVar.CKind) +          << getOpenMPClauseName(OMPC_lastprivate); +      ReportOriginalDSA(*this, DSAStack, VD, DVar); +      continue; +    } + +    OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); +    // OpenMP [2.14.3.5, Restrictions, p.2] +    // A list item that is private within a parallel region, or that appears in +    // the reduction clause of a parallel construct, must not appear in a +    // lastprivate clause on a worksharing construct if any of the corresponding +    // worksharing regions ever binds to any of the corresponding parallel +    // regions. +    if (isOpenMPWorksharingDirective(CurrDir) && +        !isOpenMPParallelDirective(CurrDir)) { +      DVar = DSAStack->getImplicitDSA(VD, true); +      if (DVar.CKind != OMPC_shared) { +        Diag(ELoc, diag::err_omp_required_access) +            << getOpenMPClauseName(OMPC_lastprivate) +            << getOpenMPClauseName(OMPC_shared); +        ReportOriginalDSA(*this, DSAStack, VD, DVar); +        continue; +      } +    } +    // OpenMP [2.14.3.5, Restrictions, C++, p.1,2] +    //  A variable of class type (or array thereof) that appears in a +    //  lastprivate clause requires an accessible, unambiguous default +    //  constructor for the class type, unless the list item is also specified +    //  in a firstprivate clause. +    //  A variable of class type (or array thereof) that appears in a +    //  lastprivate clause requires an accessible, unambiguous copy assignment +    //  operator for the class type. +    while (Type.getNonReferenceType()->isArrayType()) +      Type = cast<ArrayType>(Type.getNonReferenceType().getTypePtr()) +                 ->getElementType(); +    CXXRecordDecl *RD = getLangOpts().CPlusPlus +                            ? Type.getNonReferenceType()->getAsCXXRecordDecl() +                            : nullptr; +    // FIXME This code must be replaced by actual copying and destructing of the +    // lastprivate variable. +    if (RD) { +      CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0); +      DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess()); +      if (MD) { +        if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible || +            MD->isDeleted()) { +          Diag(ELoc, diag::err_omp_required_method) +              << getOpenMPClauseName(OMPC_lastprivate) << 2; +          bool IsDecl = VD->isThisDeclarationADefinition(Context) == +                        VarDecl::DeclarationOnly; +          Diag(VD->getLocation(), +               IsDecl ? diag::note_previous_decl : diag::note_defined_here) +              << VD; +          Diag(RD->getLocation(), diag::note_previous_decl) << RD; +          continue; +        } +        MarkFunctionReferenced(ELoc, MD); +        DiagnoseUseOfDecl(MD, ELoc); +      } + +      CXXDestructorDecl *DD = RD->getDestructor(); +      if (DD) { +        PartialDiagnostic PD = +            PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); +        if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || +            DD->isDeleted()) { +          Diag(ELoc, diag::err_omp_required_method) +              << getOpenMPClauseName(OMPC_lastprivate) << 4; +          bool IsDecl = VD->isThisDeclarationADefinition(Context) == +                        VarDecl::DeclarationOnly; +          Diag(VD->getLocation(), +               IsDecl ? diag::note_previous_decl : diag::note_defined_here) +              << VD; +          Diag(RD->getLocation(), diag::note_previous_decl) << RD; +          continue; +        } +        MarkFunctionReferenced(ELoc, DD); +        DiagnoseUseOfDecl(DD, ELoc); +      } +    } + +    if (DVar.CKind != OMPC_firstprivate) +      DSAStack->addDSA(VD, DE, OMPC_lastprivate); +    Vars.push_back(DE); +  } + +  if (Vars.empty()) +    return nullptr; + +  return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, +                                      Vars); +} +  OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,                                           SourceLocation StartLoc,                                           SourceLocation LParenLoc,                                           SourceLocation EndLoc) {    SmallVector<Expr *, 8> Vars; -  for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); -       I != E; ++I) { -    assert(*I && "NULL expr in OpenMP shared clause."); -    if (isa<DependentScopeDeclRefExpr>(*I)) { +  for (auto &RefExpr : VarList) { +    assert(RefExpr && "NULL expr in OpenMP shared clause."); +    if (isa<DependentScopeDeclRefExpr>(RefExpr)) {        // It will be analyzed later. -      Vars.push_back(*I); +      Vars.push_back(RefExpr);        continue;      } -    SourceLocation ELoc = (*I)->getExprLoc(); +    SourceLocation ELoc = RefExpr->getExprLoc();      // OpenMP [2.1, C/C++]      //  A list item is a variable name. -    // OpenMP  [2.9.3.4, Restrictions, p.1] -    //  A variable that is part of another variable (as an array or -    //  structure element) cannot appear in a private clause. -    DeclRefExpr *DE = dyn_cast<DeclRefExpr>(*I); +    // OpenMP  [2.14.3.2, Restrictions, p.1] +    //  A variable that is part of another variable (as an array or structure +    //  element) cannot appear in a shared unless it is a static data member +    //  of a C++ class. +    DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);      if (!DE || !isa<VarDecl>(DE->getDecl())) { -      Diag(ELoc, diag::err_omp_expected_var_name) -        << (*I)->getSourceRange(); +      Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();        continue;      }      Decl *D = DE->getDecl(); @@ -1140,13 +3360,12 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,      //  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); -    if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared && DVar.RefExpr) { -      Diag(ELoc, diag::err_omp_wrong_dsa) -         << getOpenMPClauseName(DVar.CKind) -         << getOpenMPClauseName(OMPC_shared); -      Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) -           << getOpenMPClauseName(DVar.CKind); +    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) +                                          << getOpenMPClauseName(OMPC_shared); +      ReportOriginalDSA(*this, DSAStack, VD, DVar);        continue;      } @@ -1154,9 +3373,730 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,      Vars.push_back(DE);    } -  if (Vars.empty()) return 0; +  if (Vars.empty()) +    return nullptr;    return OMPSharedClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);  } +namespace { +class DSARefChecker : public StmtVisitor<DSARefChecker, bool> { +  DSAStackTy *Stack; + +public: +  bool VisitDeclRefExpr(DeclRefExpr *E) { +    if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) { +      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(), false); +      if (DVarPrivate.CKind != OMPC_unknown) +        return true; +      return false; +    } +    return false; +  } +  bool VisitStmt(Stmt *S) { +    for (auto Child : S->children()) { +      if (Child && Visit(Child)) +        return true; +    } +    return false; +  } +  explicit DSARefChecker(DSAStackTy *S) : Stack(S) {} +}; +} // namespace + +OMPClause *Sema::ActOnOpenMPReductionClause( +    ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, +    SourceLocation ColonLoc, SourceLocation EndLoc, +    CXXScopeSpec &ReductionIdScopeSpec, +    const DeclarationNameInfo &ReductionId) { +  // TODO: Allow scope specification search when 'declare reduction' is +  // supported. +  assert(ReductionIdScopeSpec.isEmpty() && +         "No support for scoped reduction identifiers yet."); + +  auto DN = ReductionId.getName(); +  auto OOK = DN.getCXXOverloadedOperator(); +  BinaryOperatorKind BOK = BO_Comma; + +  // OpenMP [2.14.3.6, reduction clause] +  // C +  // reduction-identifier is either an identifier or one of the following +  // operators: +, -, *,  &, |, ^, && and || +  // C++ +  // reduction-identifier is either an id-expression or one of the following +  // operators: +, -, *, &, |, ^, && and || +  // FIXME: Only 'min' and 'max' identifiers are supported for now. +  switch (OOK) { +  case OO_Plus: +  case OO_Minus: +    BOK = BO_AddAssign; +    break; +  case OO_Star: +    BOK = BO_MulAssign; +    break; +  case OO_Amp: +    BOK = BO_AndAssign; +    break; +  case OO_Pipe: +    BOK = BO_OrAssign; +    break; +  case OO_Caret: +    BOK = BO_XorAssign; +    break; +  case OO_AmpAmp: +    BOK = BO_LAnd; +    break; +  case OO_PipePipe: +    BOK = BO_LOr; +    break; +  default: +    if (auto II = DN.getAsIdentifierInfo()) { +      if (II->isStr("max")) +        BOK = BO_GT; +      else if (II->isStr("min")) +        BOK = BO_LT; +    } +    break; +  } +  SourceRange ReductionIdRange; +  if (ReductionIdScopeSpec.isValid()) { +    ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc()); +  } +  ReductionIdRange.setEnd(ReductionId.getEndLoc()); +  if (BOK == BO_Comma) { +    // Not allowed reduction identifier is found. +    Diag(ReductionId.getLocStart(), diag::err_omp_unknown_reduction_identifier) +        << ReductionIdRange; +    return nullptr; +  } + +  SmallVector<Expr *, 8> Vars; +  for (auto RefExpr : VarList) { +    assert(RefExpr && "nullptr expr in OpenMP reduction clause."); +    if (isa<DependentScopeDeclRefExpr>(RefExpr)) { +      // It will be analyzed later. +      Vars.push_back(RefExpr); +      continue; +    } + +    if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() || +        RefExpr->isInstantiationDependent() || +        RefExpr->containsUnexpandedParameterPack()) { +      // It will be analyzed later. +      Vars.push_back(RefExpr); +      continue; +    } + +    auto ELoc = RefExpr->getExprLoc(); +    auto ERange = RefExpr->getSourceRange(); +    // OpenMP [2.1, C/C++] +    //  A list item is a variable or array section, subject to the restrictions +    //  specified in Section 2.4 on page 42 and in each of the sections +    // describing clauses and directives for which a list appears. +    // OpenMP  [2.14.3.3, Restrictions, p.1] +    //  A variable that is part of another variable (as an array or +    //  structure element) cannot appear in a private clause. +    auto DE = dyn_cast<DeclRefExpr>(RefExpr); +    if (!DE || !isa<VarDecl>(DE->getDecl())) { +      Diag(ELoc, diag::err_omp_expected_var_name) << ERange; +      continue; +    } +    auto D = DE->getDecl(); +    auto VD = cast<VarDecl>(D); +    auto Type = VD->getType(); +    // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] +    //  A variable that appears in a private clause must not have an incomplete +    //  type or a reference type. +    if (RequireCompleteType(ELoc, Type, +                            diag::err_omp_reduction_incomplete_type)) +      continue; +    // OpenMP [2.14.3.6, reduction clause, Restrictions] +    // Arrays may not appear in a reduction clause. +    if (Type.getNonReferenceType()->isArrayType()) { +      Diag(ELoc, diag::err_omp_reduction_type_array) << Type << ERange; +      bool IsDecl = +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +      Diag(VD->getLocation(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD; +      continue; +    } +    // OpenMP [2.14.3.6, reduction clause, Restrictions] +    // A list item that appears in a reduction clause must not be +    // const-qualified. +    if (Type.getNonReferenceType().isConstant(Context)) { +      Diag(ELoc, diag::err_omp_const_variable) +          << getOpenMPClauseName(OMPC_reduction) << Type << ERange; +      bool IsDecl = +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +      Diag(VD->getLocation(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD; +      continue; +    } +    // OpenMP [2.9.3.6, Restrictions, C/C++, p.4] +    //  If a list-item is a reference type then it must bind to the same object +    //  for all threads of the team. +    VarDecl *VDDef = VD->getDefinition(); +    if (Type->isReferenceType() && VDDef) { +      DSARefChecker Check(DSAStack); +      if (Check.Visit(VDDef->getInit())) { +        Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange; +        Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef; +        continue; +      } +    } +    // OpenMP [2.14.3.6, reduction clause, Restrictions] +    // The type of a list item that appears in a reduction clause must be valid +    // for the reduction-identifier. For a max or min reduction in C, the type +    // of the list item must be an allowed arithmetic data type: char, int, +    // float, double, or _Bool, possibly modified with long, short, signed, or +    // unsigned. For a max or min reduction in C++, the type of the list item +    // must be an allowed arithmetic data type: char, wchar_t, int, float, +    // double, or bool, possibly modified with long, short, signed, or unsigned. +    if ((BOK == BO_GT || BOK == BO_LT) && +        !(Type->isScalarType() || +          (getLangOpts().CPlusPlus && Type->isArithmeticType()))) { +      Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg) +          << getLangOpts().CPlusPlus; +      bool IsDecl = +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +      Diag(VD->getLocation(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD; +      continue; +    } +    if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) && +        !getLangOpts().CPlusPlus && Type->isFloatingType()) { +      Diag(ELoc, diag::err_omp_clause_floating_type_arg); +      bool IsDecl = +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +      Diag(VD->getLocation(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD; +      continue; +    } +    bool Suppress = getDiagnostics().getSuppressAllDiagnostics(); +    getDiagnostics().setSuppressAllDiagnostics(true); +    ExprResult ReductionOp = +        BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK, +                   RefExpr, RefExpr); +    getDiagnostics().setSuppressAllDiagnostics(Suppress); +    if (ReductionOp.isInvalid()) { +      Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type +                                                            << ReductionIdRange; +      bool IsDecl = +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +      Diag(VD->getLocation(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD; +      continue; +    } + +    // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced +    // in a Construct] +    //  Variables with the predetermined data-sharing attributes may not be +    //  listed in data-sharing attributes clauses, except for the cases +    //  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. +    // OpenMP [2.14.3.6, Restrictions, p.3] +    //  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, false); +    if (DVar.CKind == OMPC_reduction) { +      Diag(ELoc, diag::err_omp_once_referenced) +          << getOpenMPClauseName(OMPC_reduction); +      if (DVar.RefExpr) { +        Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced); +      } +    } else if (DVar.CKind != OMPC_unknown) { +      Diag(ELoc, diag::err_omp_wrong_dsa) +          << getOpenMPClauseName(DVar.CKind) +          << getOpenMPClauseName(OMPC_reduction); +      ReportOriginalDSA(*this, DSAStack, VD, DVar); +      continue; +    } + +    // OpenMP [2.14.3.6, Restrictions, p.1] +    //  A list item that appears in a reduction clause of a worksharing +    //  construct must be shared in the parallel regions to which any of the +    //  worksharing regions arising from the worksharing construct bind. +    OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); +    if (isOpenMPWorksharingDirective(CurrDir) && +        !isOpenMPParallelDirective(CurrDir)) { +      DVar = DSAStack->getImplicitDSA(VD, true); +      if (DVar.CKind != OMPC_shared) { +        Diag(ELoc, diag::err_omp_required_access) +            << getOpenMPClauseName(OMPC_reduction) +            << getOpenMPClauseName(OMPC_shared); +        ReportOriginalDSA(*this, DSAStack, VD, DVar); +        continue; +      } +    } + +    CXXRecordDecl *RD = getLangOpts().CPlusPlus +                            ? Type.getNonReferenceType()->getAsCXXRecordDecl() +                            : nullptr; +    // FIXME This code must be replaced by actual constructing/destructing of +    // the reduction variable. +    if (RD) { +      CXXConstructorDecl *CD = LookupDefaultConstructor(RD); +      PartialDiagnostic PD = +          PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); +      if (!CD || +          CheckConstructorAccess(ELoc, CD, +                                 InitializedEntity::InitializeTemporary(Type), +                                 CD->getAccess(), PD) == AR_inaccessible || +          CD->isDeleted()) { +        Diag(ELoc, diag::err_omp_required_method) +            << getOpenMPClauseName(OMPC_reduction) << 0; +        bool IsDecl = VD->isThisDeclarationADefinition(Context) == +                      VarDecl::DeclarationOnly; +        Diag(VD->getLocation(), +             IsDecl ? diag::note_previous_decl : diag::note_defined_here) +            << VD; +        Diag(RD->getLocation(), diag::note_previous_decl) << RD; +        continue; +      } +      MarkFunctionReferenced(ELoc, CD); +      DiagnoseUseOfDecl(CD, ELoc); + +      CXXDestructorDecl *DD = RD->getDestructor(); +      if (DD) { +        if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || +            DD->isDeleted()) { +          Diag(ELoc, diag::err_omp_required_method) +              << getOpenMPClauseName(OMPC_reduction) << 4; +          bool IsDecl = VD->isThisDeclarationADefinition(Context) == +                        VarDecl::DeclarationOnly; +          Diag(VD->getLocation(), +               IsDecl ? diag::note_previous_decl : diag::note_defined_here) +              << VD; +          Diag(RD->getLocation(), diag::note_previous_decl) << RD; +          continue; +        } +        MarkFunctionReferenced(ELoc, DD); +        DiagnoseUseOfDecl(DD, ELoc); +      } +    } + +    DSAStack->addDSA(VD, DE, OMPC_reduction); +    Vars.push_back(DE); +  } + +  if (Vars.empty()) +    return nullptr; + +  return OMPReductionClause::Create( +      Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars, +      ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId); +} + +OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, +                                         SourceLocation StartLoc, +                                         SourceLocation LParenLoc, +                                         SourceLocation ColonLoc, +                                         SourceLocation EndLoc) { +  SmallVector<Expr *, 8> Vars; +  for (auto &RefExpr : VarList) { +    assert(RefExpr && "NULL expr in OpenMP linear clause."); +    if (isa<DependentScopeDeclRefExpr>(RefExpr)) { +      // It will be analyzed later. +      Vars.push_back(RefExpr); +      continue; +    } + +    // OpenMP [2.14.3.7, linear clause] +    // A list item that appears in a linear clause is subject to the private +    // clause semantics described in Section 2.14.3.3 on page 159 except as +    // noted. In addition, the value of the new list item on each iteration +    // of the associated loop(s) corresponds to the value of the original +    // list item before entering the construct plus the logical number of +    // the iteration times linear-step. + +    SourceLocation ELoc = RefExpr->getExprLoc(); +    // OpenMP [2.1, C/C++] +    //  A list item is a variable name. +    // OpenMP  [2.14.3.3, Restrictions, p.1] +    //  A variable that is part of another variable (as an array or +    //  structure element) cannot appear in a private clause. +    DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); +    if (!DE || !isa<VarDecl>(DE->getDecl())) { +      Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); +      continue; +    } + +    VarDecl *VD = cast<VarDecl>(DE->getDecl()); + +    // OpenMP [2.14.3.7, linear clause] +    //  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, false); +    if (DVar.RefExpr) { +      Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) +                                          << getOpenMPClauseName(OMPC_linear); +      ReportOriginalDSA(*this, DSAStack, VD, DVar); +      continue; +    } + +    QualType QType = VD->getType(); +    if (QType->isDependentType() || QType->isInstantiationDependentType()) { +      // It will be analyzed later. +      Vars.push_back(DE); +      continue; +    } + +    // A variable must not have an incomplete type or a reference type. +    if (RequireCompleteType(ELoc, QType, +                            diag::err_omp_linear_incomplete_type)) { +      continue; +    } +    if (QType->isReferenceType()) { +      Diag(ELoc, diag::err_omp_clause_ref_type_arg) +          << getOpenMPClauseName(OMPC_linear) << QType; +      bool IsDecl = +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +      Diag(VD->getLocation(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD; +      continue; +    } + +    // A list item must not be const-qualified. +    if (QType.isConstant(Context)) { +      Diag(ELoc, diag::err_omp_const_variable) +          << getOpenMPClauseName(OMPC_linear); +      bool IsDecl = +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +      Diag(VD->getLocation(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD; +      continue; +    } + +    // A list item must be of integral or pointer type. +    QType = QType.getUnqualifiedType().getCanonicalType(); +    const Type *Ty = QType.getTypePtrOrNull(); +    if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) && +                !Ty->isPointerType())) { +      Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << QType; +      bool IsDecl = +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +      Diag(VD->getLocation(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD; +      continue; +    } + +    DSAStack->addDSA(VD, DE, OMPC_linear); +    Vars.push_back(DE); +  } + +  if (Vars.empty()) +    return nullptr; + +  Expr *StepExpr = Step; +  if (Step && !Step->isValueDependent() && !Step->isTypeDependent() && +      !Step->isInstantiationDependent() && +      !Step->containsUnexpandedParameterPack()) { +    SourceLocation StepLoc = Step->getLocStart(); +    ExprResult Val = PerformOpenMPImplicitIntegerConversion(StepLoc, Step); +    if (Val.isInvalid()) +      return nullptr; +    StepExpr = Val.get(); + +    // Warn about zero linear step (it would be probably better specified as +    // making corresponding variables 'const'). +    llvm::APSInt Result; +    if (StepExpr->isIntegerConstantExpr(Result, Context) && +        !Result.isNegative() && !Result.isStrictlyPositive()) +      Diag(StepLoc, diag::warn_omp_linear_step_zero) << Vars[0] +                                                     << (Vars.size() > 1); +  } + +  return OMPLinearClause::Create(Context, StartLoc, LParenLoc, ColonLoc, EndLoc, +                                 Vars, StepExpr); +} + +OMPClause *Sema::ActOnOpenMPAlignedClause( +    ArrayRef<Expr *> VarList, Expr *Alignment, SourceLocation StartLoc, +    SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc) { + +  SmallVector<Expr *, 8> Vars; +  for (auto &RefExpr : VarList) { +    assert(RefExpr && "NULL expr in OpenMP aligned clause."); +    if (isa<DependentScopeDeclRefExpr>(RefExpr)) { +      // It will be analyzed later. +      Vars.push_back(RefExpr); +      continue; +    } + +    SourceLocation ELoc = RefExpr->getExprLoc(); +    // OpenMP [2.1, C/C++] +    //  A list item is a variable name. +    DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); +    if (!DE || !isa<VarDecl>(DE->getDecl())) { +      Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); +      continue; +    } + +    VarDecl *VD = cast<VarDecl>(DE->getDecl()); + +    // OpenMP  [2.8.1, simd construct, Restrictions] +    // The type of list items appearing in the aligned clause must be +    // array, pointer, reference to array, or reference to pointer. +    QualType QType = DE->getType() +                         .getNonReferenceType() +                         .getUnqualifiedType() +                         .getCanonicalType(); +    const Type *Ty = QType.getTypePtrOrNull(); +    if (!Ty || (!Ty->isDependentType() && !Ty->isArrayType() && +                !Ty->isPointerType())) { +      Diag(ELoc, diag::err_omp_aligned_expected_array_or_ptr) +          << QType << getLangOpts().CPlusPlus << RefExpr->getSourceRange(); +      bool IsDecl = +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; +      Diag(VD->getLocation(), +           IsDecl ? diag::note_previous_decl : diag::note_defined_here) +          << VD; +      continue; +    } + +    // OpenMP  [2.8.1, simd construct, Restrictions] +    // A list-item cannot appear in more than one aligned clause. +    if (DeclRefExpr *PrevRef = DSAStack->addUniqueAligned(VD, DE)) { +      Diag(ELoc, diag::err_omp_aligned_twice) << RefExpr->getSourceRange(); +      Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) +          << getOpenMPClauseName(OMPC_aligned); +      continue; +    } + +    Vars.push_back(DE); +  } + +  // OpenMP [2.8.1, simd construct, Description] +  // The parameter of the aligned clause, alignment, must be a constant +  // positive integer expression. +  // If no optional parameter is specified, implementation-defined default +  // alignments for SIMD instructions on the target platforms are assumed. +  if (Alignment != nullptr) { +    ExprResult AlignResult = +        VerifyPositiveIntegerConstantInClause(Alignment, OMPC_aligned); +    if (AlignResult.isInvalid()) +      return nullptr; +    Alignment = AlignResult.get(); +  } +  if (Vars.empty()) +    return nullptr; + +  return OMPAlignedClause::Create(Context, StartLoc, LParenLoc, ColonLoc, +                                  EndLoc, Vars, Alignment); +} + +OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, +                                         SourceLocation StartLoc, +                                         SourceLocation LParenLoc, +                                         SourceLocation EndLoc) { +  SmallVector<Expr *, 8> Vars; +  for (auto &RefExpr : VarList) { +    assert(RefExpr && "NULL expr in OpenMP copyin clause."); +    if (isa<DependentScopeDeclRefExpr>(RefExpr)) { +      // It will be analyzed later. +      Vars.push_back(RefExpr); +      continue; +    } + +    SourceLocation ELoc = RefExpr->getExprLoc(); +    // OpenMP [2.1, C/C++] +    //  A list item is a variable name. +    // OpenMP  [2.14.4.1, Restrictions, p.1] +    //  A list item that appears in a copyin clause must be threadprivate. +    DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); +    if (!DE || !isa<VarDecl>(DE->getDecl())) { +      Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); +      continue; +    } + +    Decl *D = DE->getDecl(); +    VarDecl *VD = cast<VarDecl>(D); + +    QualType Type = VD->getType(); +    if (Type->isDependentType() || Type->isInstantiationDependentType()) { +      // It will be analyzed later. +      Vars.push_back(DE); +      continue; +    } + +    // OpenMP [2.14.4.1, Restrictions, C/C++, p.1] +    //  A list item that appears in a copyin clause must be threadprivate. +    if (!DSAStack->isThreadPrivate(VD)) { +      Diag(ELoc, diag::err_omp_required_access) +          << getOpenMPClauseName(OMPC_copyin) +          << getOpenMPDirectiveName(OMPD_threadprivate); +      continue; +    } + +    // OpenMP [2.14.4.1, Restrictions, C/C++, p.2] +    //  A variable of class type (or array thereof) that appears in a +    //  copyin clause requires an accessible, unambiguous copy assignment +    //  operator for the class type. +    Type = Context.getBaseElementType(Type); +    CXXRecordDecl *RD = +        getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr; +    // FIXME This code must be replaced by actual assignment of the +    // threadprivate variable. +    if (RD) { +      CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0); +      DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess()); +      if (MD) { +        if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible || +            MD->isDeleted()) { +          Diag(ELoc, diag::err_omp_required_method) +              << getOpenMPClauseName(OMPC_copyin) << 2; +          bool IsDecl = VD->isThisDeclarationADefinition(Context) == +                        VarDecl::DeclarationOnly; +          Diag(VD->getLocation(), +               IsDecl ? diag::note_previous_decl : diag::note_defined_here) +              << VD; +          Diag(RD->getLocation(), diag::note_previous_decl) << RD; +          continue; +        } +        MarkFunctionReferenced(ELoc, MD); +        DiagnoseUseOfDecl(MD, ELoc); +      } +    } + +    DSAStack->addDSA(VD, DE, OMPC_copyin); +    Vars.push_back(DE); +  } + +  if (Vars.empty()) +    return nullptr; + +  return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); +} + +OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, +                                              SourceLocation StartLoc, +                                              SourceLocation LParenLoc, +                                              SourceLocation EndLoc) { +  SmallVector<Expr *, 8> Vars; +  for (auto &RefExpr : VarList) { +    assert(RefExpr && "NULL expr in OpenMP copyprivate clause."); +    if (isa<DependentScopeDeclRefExpr>(RefExpr)) { +      // It will be analyzed later. +      Vars.push_back(RefExpr); +      continue; +    } + +    SourceLocation ELoc = RefExpr->getExprLoc(); +    // OpenMP [2.1, C/C++] +    //  A list item is a variable name. +    // OpenMP  [2.14.4.1, Restrictions, p.1] +    //  A list item that appears in a copyin clause must be threadprivate. +    DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); +    if (!DE || !isa<VarDecl>(DE->getDecl())) { +      Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); +      continue; +    } + +    Decl *D = DE->getDecl(); +    VarDecl *VD = cast<VarDecl>(D); + +    QualType Type = VD->getType(); +    if (Type->isDependentType() || Type->isInstantiationDependentType()) { +      // It will be analyzed later. +      Vars.push_back(DE); +      continue; +    } + +    // OpenMP [2.14.4.2, Restrictions, p.2] +    //  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, false); +      if (DVar.CKind != OMPC_copyprivate && DVar.CKind != OMPC_unknown && +          !(DVar.CKind == OMPC_private && !DVar.RefExpr)) { +        Diag(ELoc, diag::err_omp_wrong_dsa) +            << getOpenMPClauseName(DVar.CKind) +            << getOpenMPClauseName(OMPC_copyprivate); +        ReportOriginalDSA(*this, DSAStack, VD, DVar); +        continue; +      } + +      // OpenMP [2.11.4.2, Restrictions, p.1] +      //  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, false); +        if (DVar.CKind == OMPC_shared) { +          Diag(ELoc, diag::err_omp_required_access) +              << getOpenMPClauseName(OMPC_copyprivate) +              << "threadprivate or private in the enclosing context"; +          ReportOriginalDSA(*this, DSAStack, VD, DVar); +          continue; +        } +      } +    } + +    // OpenMP [2.14.4.1, Restrictions, C/C++, p.2] +    //  A variable of class type (or array thereof) that appears in a +    //  copyin clause requires an accessible, unambiguous copy assignment +    //  operator for the class type. +    Type = Context.getBaseElementType(Type); +    CXXRecordDecl *RD = +        getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr; +    // FIXME This code must be replaced by actual assignment of the +    // threadprivate variable. +    if (RD) { +      CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0); +      DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess()); +      if (MD) { +        if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible || +            MD->isDeleted()) { +          Diag(ELoc, diag::err_omp_required_method) +              << getOpenMPClauseName(OMPC_copyprivate) << 2; +          bool IsDecl = VD->isThisDeclarationADefinition(Context) == +                        VarDecl::DeclarationOnly; +          Diag(VD->getLocation(), +               IsDecl ? diag::note_previous_decl : diag::note_defined_here) +              << VD; +          Diag(RD->getLocation(), diag::note_previous_decl) << RD; +          continue; +        } +        MarkFunctionReferenced(ELoc, MD); +        DiagnoseUseOfDecl(MD, ELoc); +      } +    } + +    // No need to mark vars as copyprivate, they are already threadprivate or +    // implicitly private. +    Vars.push_back(DE); +  } + +  if (Vars.empty()) +    return nullptr; + +  return OMPCopyprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); +} + +OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList, +                                        SourceLocation StartLoc, +                                        SourceLocation LParenLoc, +                                        SourceLocation EndLoc) { +  if (VarList.empty()) +    return nullptr; + +  return OMPFlushClause::Create(Context, StartLoc, LParenLoc, EndLoc, VarList); +} +  #undef DSAStack  | 
