[clang] e675d0d - [OpenACC][NFC] Refactor SemaOpenACC to use a visitor

via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 5 14:03:30 PDT 2024


Author: erichkeane
Date: 2024-06-05T13:27:10-07:00
New Revision: e675d0d5cd4047bcf4ec368d2b4c19a57e5347f3

URL: https://github.com/llvm/llvm-project/commit/e675d0d5cd4047bcf4ec368d2b4c19a57e5347f3
DIFF: https://github.com/llvm/llvm-project/commit/e675d0d5cd4047bcf4ec368d2b4c19a57e5347f3.diff

LOG: [OpenACC][NFC] Refactor SemaOpenACC to use a visitor

This code was getting unwieldy, so a quick patch to refactor it a bit.

Added: 
    

Modified: 
    clang/include/clang/AST/OpenACCClause.h
    clang/include/clang/Basic/OpenACCClauses.def
    clang/lib/AST/OpenACCClause.cpp
    clang/lib/Sema/SemaOpenACC.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h
index a4c82cdad87bd..ea1ffbc7fd08b 100644
--- a/clang/include/clang/AST/OpenACCClause.h
+++ b/clang/include/clang/AST/OpenACCClause.h
@@ -867,7 +867,7 @@ template <class Impl> class OpenACCClauseVisitor {
   case OpenACCClauseKind::CLAUSE_NAME:                                         \
     Visit##CLAUSE_NAME##Clause(*cast<OpenACC##CLAUSE_NAME##Clause>(C));        \
     return;
-#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME)                                  \
+#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME, DEPRECATED)                      \
   case OpenACCClauseKind::ALIAS_NAME:                                          \
     Visit##CLAUSE_NAME##Clause(*cast<OpenACC##CLAUSE_NAME##Clause>(C));        \
     return;

diff  --git a/clang/include/clang/Basic/OpenACCClauses.def b/clang/include/clang/Basic/OpenACCClauses.def
index 53f4cd103d142..85f4859925f0b 100644
--- a/clang/include/clang/Basic/OpenACCClauses.def
+++ b/clang/include/clang/Basic/OpenACCClauses.def
@@ -15,31 +15,31 @@
 //
 // VISIT_CLAUSE(CLAUSE_NAME)
 //
-// CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME)
+// CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME, DEPRECATED)
 
 #ifndef CLAUSE_ALIAS
-#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME)
+#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME, false)
 #endif
 
 VISIT_CLAUSE(Auto)
 VISIT_CLAUSE(Async)
 VISIT_CLAUSE(Attach)
 VISIT_CLAUSE(Copy)
-CLAUSE_ALIAS(PCopy, Copy)
-CLAUSE_ALIAS(PresentOrCopy, Copy)
+CLAUSE_ALIAS(PCopy, Copy, true)
+CLAUSE_ALIAS(PresentOrCopy, Copy, true)
 VISIT_CLAUSE(CopyIn)
-CLAUSE_ALIAS(PCopyIn, CopyIn)
-CLAUSE_ALIAS(PresentOrCopyIn, CopyIn)
+CLAUSE_ALIAS(PCopyIn, CopyIn, true)
+CLAUSE_ALIAS(PresentOrCopyIn, CopyIn, true)
 VISIT_CLAUSE(CopyOut)
-CLAUSE_ALIAS(PCopyOut, CopyOut)
-CLAUSE_ALIAS(PresentOrCopyOut, CopyOut)
+CLAUSE_ALIAS(PCopyOut, CopyOut, true)
+CLAUSE_ALIAS(PresentOrCopyOut, CopyOut, true)
 VISIT_CLAUSE(Create)
-CLAUSE_ALIAS(PCreate, Create)
-CLAUSE_ALIAS(PresentOrCreate, Create)
+CLAUSE_ALIAS(PCreate, Create, true)
+CLAUSE_ALIAS(PresentOrCreate, Create, true)
 VISIT_CLAUSE(Default)
 VISIT_CLAUSE(DevicePtr)
 VISIT_CLAUSE(DeviceType)
-CLAUSE_ALIAS(DType, DeviceType)
+CLAUSE_ALIAS(DType, DeviceType, false)
 VISIT_CLAUSE(FirstPrivate)
 VISIT_CLAUSE(If)
 VISIT_CLAUSE(Independent)

diff  --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp
index 403ce9a221571..95089a9b79e26 100644
--- a/clang/lib/AST/OpenACCClause.cpp
+++ b/clang/lib/AST/OpenACCClause.cpp
@@ -104,7 +104,7 @@ OpenACCClause::child_range OpenACCClause::children() {
 #define VISIT_CLAUSE(CLAUSE_NAME)                                              \
   case OpenACCClauseKind::CLAUSE_NAME:                                         \
     return cast<OpenACC##CLAUSE_NAME##Clause>(this)->children();
-#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME)                                  \
+#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME, DEPRECATED)                      \
   case OpenACCClauseKind::ALIAS_NAME:                                          \
     return cast<OpenACC##CLAUSE_NAME##Clause>(this)->children();
 

diff  --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 1320fd90b440b..97586a037eee4 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -424,617 +424,736 @@ bool checkValidAfterDeviceType(
   S.Diag(DeviceTypeClause.getBeginLoc(), diag::note_acc_previous_clause_here);
   return true;
 }
-} // namespace
 
-SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {}
+class SemaOpenACCClauseVisitor {
+  SemaOpenACC &SemaRef;
+  ASTContext &Ctx;
+  ArrayRef<const OpenACCClause *> ExistingClauses;
+  bool NotImplemented = false;
 
-SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII(SemaOpenACC &S,
-                                                    OpenACCDirectiveKind DK)
-    : SemaRef(S), WasInsideComputeConstruct(S.InsideComputeConstruct),
-      DirKind(DK) {
-  // Compute constructs end up taking their 'loop'.
-  if (DirKind == OpenACCDirectiveKind::Parallel ||
-      DirKind == OpenACCDirectiveKind::Serial ||
-      DirKind == OpenACCDirectiveKind::Kernels) {
-    SemaRef.InsideComputeConstruct = true;
-    SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs);
+  OpenACCClause *isNotImplemented() {
+    NotImplemented = true;
+    return nullptr;
   }
-}
 
-SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() {
-  SemaRef.InsideComputeConstruct = WasInsideComputeConstruct;
-  if (DirKind == OpenACCDirectiveKind::Parallel ||
-      DirKind == OpenACCDirectiveKind::Serial ||
-      DirKind == OpenACCDirectiveKind::Kernels) {
-    assert(SemaRef.ParentlessLoopConstructs.empty() &&
-           "Didn't consume loop construct list?");
-    SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs);
-  }
-}
+public:
+  SemaOpenACCClauseVisitor(SemaOpenACC &S,
+                           ArrayRef<const OpenACCClause *> ExistingClauses)
+      : SemaRef(S), Ctx(S.getASTContext()), ExistingClauses(ExistingClauses) {}
+  // Once we've implemented everything, we shouldn't need this infrastructure.
+  // But in the meantime, we use this to help decide whether the clause was
+  // handled for this directive.
+  bool diagNotImplemented() { return NotImplemented; }
+
+  OpenACCClause *Visit(SemaOpenACC::OpenACCParsedClause &Clause) {
+    switch (Clause.getClauseKind()) {
+  case OpenACCClauseKind::Gang:
+  case OpenACCClauseKind::Worker:
+  case OpenACCClauseKind::Vector: {
+    // TODO OpenACC: These are only implemented enough for the 'seq' diagnostic,
+    // otherwise treats itself as unimplemented.  When we implement these, we
+    // can remove them from here.
 
-OpenACCClause *
-SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
-                         OpenACCParsedClause &Clause) {
-  if (Clause.getClauseKind() == OpenACCClauseKind::Invalid)
-    return nullptr;
+    // OpenACC 3.3 2.9:
+    // A 'gang', 'worker', or 'vector' clause may not appear if a 'seq' clause
+    // appears.
+    const auto *Itr =
+        llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCSeqClause>);
 
-  // Diagnose that we don't support this clause on this directive.
-  if (!doesClauseApplyToDirective(Clause.getDirectiveKind(),
-                                  Clause.getClauseKind())) {
-    Diag(Clause.getBeginLoc(), diag::err_acc_clause_appertainment)
-        << Clause.getDirectiveKind() << Clause.getClauseKind();
-    return nullptr;
+    if (Itr != ExistingClauses.end()) {
+      SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine)
+          << Clause.getClauseKind() << (*Itr)->getClauseKind();
+      SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
+    }
+    return isNotImplemented();
   }
 
-  if (const auto *DevTypeClause =
-          llvm::find_if(ExistingClauses,
-                        [&](const OpenACCClause *C) {
-                          return isa<OpenACCDeviceTypeClause>(C);
-                        });
-      DevTypeClause != ExistingClauses.end()) {
-    if (checkValidAfterDeviceType(
-            *this, *cast<OpenACCDeviceTypeClause>(*DevTypeClause), Clause))
-      return nullptr;
+#define VISIT_CLAUSE(CLAUSE_NAME)                                              \
+  case OpenACCClauseKind::CLAUSE_NAME:                                         \
+    return Visit##CLAUSE_NAME##Clause(Clause);
+#define CLAUSE_ALIAS(ALIAS, CLAUSE_NAME, DEPRECATED)                           \
+  case OpenACCClauseKind::ALIAS:                                               \
+  if (DEPRECATED)                                                              \
+    SemaRef.Diag(Clause.getBeginLoc(), diag::warn_acc_deprecated_alias_name)   \
+        << Clause.getClauseKind() << OpenACCClauseKind::CLAUSE_NAME;           \
+  return Visit##CLAUSE_NAME##Clause(Clause);
+#include "clang/Basic/OpenACCClauses.def"
+    default:
+      return isNotImplemented();
+    }
+    llvm_unreachable("Invalid clause kind");
   }
 
-  switch (Clause.getClauseKind()) {
-  case OpenACCClauseKind::Default: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
+#define VISIT_CLAUSE(CLAUSE_NAME)                                              \
+  OpenACCClause *Visit##CLAUSE_NAME##Clause(                                   \
+      SemaOpenACC::OpenACCParsedClause &Clause);
+#include "clang/Basic/OpenACCClauses.def"
+};
 
-    // Don't add an invalid clause to the AST.
-    if (Clause.getDefaultClauseKind() == OpenACCDefaultClauseKind::Invalid)
-      return nullptr;
-
-    // OpenACC 3.3, Section 2.5.4:
-    // At most one 'default' clause may appear, and it must have a value of
-    // either 'none' or 'present'.
-    // Second half of the sentence is diagnosed during parsing.
-    if (checkAlreadyHasClauseOfKind(*this, ExistingClauses, Clause))
-      return nullptr;
-
-    return OpenACCDefaultClause::Create(
-        getASTContext(), Clause.getDefaultClauseKind(), Clause.getBeginLoc(),
-        Clause.getLParenLoc(), Clause.getEndLoc());
-  }
+OpenACCClause *SemaOpenACCClauseVisitor::VisitDefaultClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+
+  // Don't add an invalid clause to the AST.
+  if (Clause.getDefaultClauseKind() == OpenACCDefaultClauseKind::Invalid)
+    return nullptr;
 
-  case OpenACCClauseKind::If: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
+  // OpenACC 3.3, Section 2.5.4:
+  // At most one 'default' clause may appear, and it must have a value of
+  // either 'none' or 'present'.
+  // Second half of the sentence is diagnosed during parsing.
+  if (checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause))
+    return nullptr;
 
-    // There is no prose in the standard that says duplicates aren't allowed,
-    // but this diagnostic is present in other compilers, as well as makes
-    // sense.
-    if (checkAlreadyHasClauseOfKind(*this, ExistingClauses, Clause))
-      return nullptr;
+  return OpenACCDefaultClause::Create(
+      Ctx, Clause.getDefaultClauseKind(), Clause.getBeginLoc(),
+      Clause.getLParenLoc(), Clause.getEndLoc());
+}
 
-    // The parser has ensured that we have a proper condition expr, so there
-    // isn't really much to do here.
+OpenACCClause *SemaOpenACCClauseVisitor::VisitIfClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+
+  // There is no prose in the standard that says duplicates aren't allowed,
+  // but this diagnostic is present in other compilers, as well as makes
+  // sense.
+  if (checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause))
+    return nullptr;
 
-    // If the 'if' clause is true, it makes the 'self' clause have no effect,
-    // diagnose that here.
-    // TODO OpenACC: When we add these two to other constructs, we might not
-    // want to warn on this (for example, 'update').
-    const auto *Itr =
-        llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCSelfClause>);
-    if (Itr != ExistingClauses.end()) {
-      Diag(Clause.getBeginLoc(), diag::warn_acc_if_self_conflict);
-      Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
-    }
+  // The parser has ensured that we have a proper condition expr, so there
+  // isn't really much to do here.
 
-    return OpenACCIfClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
-        Clause.getConditionExpr(), Clause.getEndLoc());
+  // If the 'if' clause is true, it makes the 'self' clause have no effect,
+  // diagnose that here.
+  // TODO OpenACC: When we add these two to other constructs, we might not
+  // want to warn on this (for example, 'update').
+  const auto *Itr =
+      llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCSelfClause>);
+  if (Itr != ExistingClauses.end()) {
+    SemaRef.Diag(Clause.getBeginLoc(), diag::warn_acc_if_self_conflict);
+    SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
   }
 
-  case OpenACCClauseKind::Self: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
-
-    // TODO OpenACC: When we implement this for 'update', this takes a
-    // 'var-list' instead of a condition expression, so semantics/handling has
-    // to happen 
diff erently here.
-
-    // There is no prose in the standard that says duplicates aren't allowed,
-    // but this diagnostic is present in other compilers, as well as makes
-    // sense.
-    if (checkAlreadyHasClauseOfKind(*this, ExistingClauses, Clause))
-      return nullptr;
+  return OpenACCIfClause::Create(Ctx, Clause.getBeginLoc(),
+                                 Clause.getLParenLoc(),
+                                 Clause.getConditionExpr(), Clause.getEndLoc());
+}
 
-    // If the 'if' clause is true, it makes the 'self' clause have no effect,
-    // diagnose that here.
-    // TODO OpenACC: When we add these two to other constructs, we might not
-    // want to warn on this (for example, 'update').
-    const auto *Itr =
-        llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCIfClause>);
-    if (Itr != ExistingClauses.end()) {
-      Diag(Clause.getBeginLoc(), diag::warn_acc_if_self_conflict);
-      Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
-    }
+OpenACCClause *SemaOpenACCClauseVisitor::VisitSelfClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+
+  // TODO OpenACC: When we implement this for 'update', this takes a
+  // 'var-list' instead of a condition expression, so semantics/handling has
+  // to happen 
diff erently here.
+
+  // There is no prose in the standard that says duplicates aren't allowed,
+  // but this diagnostic is present in other compilers, as well as makes
+  // sense.
+  if (checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause))
+    return nullptr;
 
-    return OpenACCSelfClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
-        Clause.getConditionExpr(), Clause.getEndLoc());
+  // If the 'if' clause is true, it makes the 'self' clause have no effect,
+  // diagnose that here.
+  // TODO OpenACC: When we add these two to other constructs, we might not
+  // want to warn on this (for example, 'update').
+  const auto *Itr =
+      llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCIfClause>);
+  if (Itr != ExistingClauses.end()) {
+    SemaRef.Diag(Clause.getBeginLoc(), diag::warn_acc_if_self_conflict);
+    SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
   }
-  case OpenACCClauseKind::NumGangs: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
+  return OpenACCSelfClause::Create(
+      Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(),
+      Clause.getConditionExpr(), Clause.getEndLoc());
+}
 
-    // There is no prose in the standard that says duplicates aren't allowed,
-    // but this diagnostic is present in other compilers, as well as makes
-    // sense.
-    if (checkAlreadyHasClauseOfKind(*this, ExistingClauses, Clause))
-      return nullptr;
+OpenACCClause *SemaOpenACCClauseVisitor::VisitNumGangsClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+
+  // There is no prose in the standard that says duplicates aren't allowed,
+  // but this diagnostic is present in other compilers, as well as makes
+  // sense.
+  if (checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause))
+    return nullptr;
 
-    if (Clause.getIntExprs().empty())
-      Diag(Clause.getBeginLoc(), diag::err_acc_num_gangs_num_args)
-          << /*NoArgs=*/0;
-
-    unsigned MaxArgs =
-        (Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel ||
-         Clause.getDirectiveKind() == OpenACCDirectiveKind::ParallelLoop)
-            ? 3
-            : 1;
-    if (Clause.getIntExprs().size() > MaxArgs)
-      Diag(Clause.getBeginLoc(), diag::err_acc_num_gangs_num_args)
-          << /*NoArgs=*/1 << Clause.getDirectiveKind() << MaxArgs
+  // num_gangs requires at least 1 int expr in all forms.  Diagnose here, but
+  // allow us to continue, an empty clause might be useful for future
+  // diagnostics.
+  if (Clause.getIntExprs().empty())
+    SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_num_gangs_num_args)
+        << /*NoArgs=*/0;
+
+  unsigned MaxArgs =
+      (Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel ||
+       Clause.getDirectiveKind() == OpenACCDirectiveKind::ParallelLoop)
+          ? 3
+          : 1;
+  // The max number of args 
diff ers between parallel and other constructs.
+  // Again, allow us to continue for the purposes of future diagnostics.
+  if (Clause.getIntExprs().size() > MaxArgs)
+    SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_num_gangs_num_args)
+        << /*NoArgs=*/1 << Clause.getDirectiveKind() << MaxArgs
+        << Clause.getIntExprs().size();
+
+  // OpenACC 3.3 Section 2.5.4:
+  // A reduction clause may not appear on a parallel construct with a
+  // num_gangs clause that has more than one argument.
+  if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel &&
+      Clause.getIntExprs().size() > 1) {
+    auto *Parallel =
+        llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCReductionClause>);
+
+    if (Parallel != ExistingClauses.end()) {
+      SemaRef.Diag(Clause.getBeginLoc(),
+                   diag::err_acc_reduction_num_gangs_conflict)
           << Clause.getIntExprs().size();
-
-    // OpenACC 3.3 Section 2.5.4:
-    // A reduction clause may not appear on a parallel construct with a
-    // num_gangs clause that has more than one argument.
-    if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel &&
-        Clause.getIntExprs().size() > 1) {
-      auto *Parallel =
-          llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCReductionClause>);
-
-      if (Parallel != ExistingClauses.end()) {
-        Diag(Clause.getBeginLoc(), diag::err_acc_reduction_num_gangs_conflict)
-            << Clause.getIntExprs().size();
-        Diag((*Parallel)->getBeginLoc(), diag::note_acc_previous_clause_here);
-        return nullptr;
-      }
+      SemaRef.Diag((*Parallel)->getBeginLoc(),
+                   diag::note_acc_previous_clause_here);
+      return nullptr;
     }
-
-    // Create the AST node for the clause even if the number of expressions is
-    // incorrect.
-    return OpenACCNumGangsClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
-        Clause.getIntExprs(), Clause.getEndLoc());
-    break;
   }
-  case OpenACCClauseKind::NumWorkers: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
+  return OpenACCNumGangsClause::Create(
+      Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getIntExprs(),
+      Clause.getEndLoc());
+}
 
-    // There is no prose in the standard that says duplicates aren't allowed,
-    // but this diagnostic is present in other compilers, as well as makes
-    // sense.
-    if (checkAlreadyHasClauseOfKind(*this, ExistingClauses, Clause))
-      return nullptr;
+OpenACCClause *SemaOpenACCClauseVisitor::VisitNumWorkersClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+
+  // There is no prose in the standard that says duplicates aren't allowed,
+  // but this diagnostic is present in other compilers, as well as makes
+  // sense.
+  if (checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause))
+    return nullptr;
 
-    assert(Clause.getIntExprs().size() == 1 &&
-           "Invalid number of expressions for NumWorkers");
-    return OpenACCNumWorkersClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
-        Clause.getIntExprs()[0], Clause.getEndLoc());
-  }
-  case OpenACCClauseKind::VectorLength: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
+  assert(Clause.getIntExprs().size() == 1 &&
+         "Invalid number of expressions for NumWorkers");
+  return OpenACCNumWorkersClause::Create(
+      Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getIntExprs()[0],
+      Clause.getEndLoc());
+}
 
-    // There is no prose in the standard that says duplicates aren't allowed,
-    // but this diagnostic is present in other compilers, as well as makes
-    // sense.
-    if (checkAlreadyHasClauseOfKind(*this, ExistingClauses, Clause))
-      return nullptr;
+OpenACCClause *SemaOpenACCClauseVisitor::VisitVectorLengthClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+
+  // There is no prose in the standard that says duplicates aren't allowed,
+  // but this diagnostic is present in other compilers, as well as makes
+  // sense.
+  if (checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause))
+    return nullptr;
 
-    assert(Clause.getIntExprs().size() == 1 &&
-           "Invalid number of expressions for VectorLength");
-    return OpenACCVectorLengthClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
-        Clause.getIntExprs()[0], Clause.getEndLoc());
-  }
-  case OpenACCClauseKind::Async: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
+  assert(Clause.getIntExprs().size() == 1 &&
+         "Invalid number of expressions for NumWorkers");
+  return OpenACCVectorLengthClause::Create(
+      Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getIntExprs()[0],
+      Clause.getEndLoc());
+}
 
-    // There is no prose in the standard that says duplicates aren't allowed,
-    // but this diagnostic is present in other compilers, as well as makes
-    // sense.
-    if (checkAlreadyHasClauseOfKind(*this, ExistingClauses, Clause))
-      return nullptr;
+OpenACCClause *SemaOpenACCClauseVisitor::VisitAsyncClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+
+  // There is no prose in the standard that says duplicates aren't allowed,
+  // but this diagnostic is present in other compilers, as well as makes
+  // sense.
+  if (checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause))
+    return nullptr;
 
-    assert(Clause.getNumIntExprs() < 2 &&
-           "Invalid number of expressions for Async");
+  assert(Clause.getNumIntExprs() < 2 &&
+         "Invalid number of expressions for Async");
+  return OpenACCAsyncClause::Create(
+      Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(),
+      Clause.getNumIntExprs() != 0 ? Clause.getIntExprs()[0] : nullptr,
+      Clause.getEndLoc());
+}
 
-    return OpenACCAsyncClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
-        Clause.getNumIntExprs() != 0 ? Clause.getIntExprs()[0] : nullptr,
-        Clause.getEndLoc());
-  }
-  case OpenACCClauseKind::Private: {
-    // Restrictions only properly implemented on 'compute' and 'loop'
-    // constructs, and 'compute'/'loop' constructs are the only construct that
-    // can do anything with this yet, so skip/treat as unimplemented in this
-    // case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
-        Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
-      break;
+OpenACCClause *SemaOpenACCClauseVisitor::VisitPrivateClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' and 'loop'
+  // constructs, and 'compute'/'loop' constructs are the only construct that
+  // can do anything with this yet, so skip/treat as unimplemented in this
+  // case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
+      Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
+    return isNotImplemented();
+
+  // ActOnVar ensured that everything is a valid variable reference, so there
+  // really isn't anything to do here. GCC does some duplicate-finding, though
+  // it isn't apparent in the standard where this is justified.
+
+  return OpenACCPrivateClause::Create(Ctx, Clause.getBeginLoc(),
+                                      Clause.getLParenLoc(),
+                                      Clause.getVarList(), Clause.getEndLoc());
+}
 
-    // ActOnVar ensured that everything is a valid variable reference, so there
-    // really isn't anything to do here. GCC does some duplicate-finding, though
-    // it isn't apparent in the standard where this is justified.
+OpenACCClause *SemaOpenACCClauseVisitor::VisitFirstPrivateClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+
+  // ActOnVar ensured that everything is a valid variable reference, so there
+  // really isn't anything to do here. GCC does some duplicate-finding, though
+  // it isn't apparent in the standard where this is justified.
+
+  return OpenACCFirstPrivateClause::Create(
+      Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(),
+      Clause.getEndLoc());
+}
 
-    return OpenACCPrivateClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
-        Clause.getVarList(), Clause.getEndLoc());
-  }
-  case OpenACCClauseKind::FirstPrivate: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
+OpenACCClause *SemaOpenACCClauseVisitor::VisitNoCreateClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+  // ActOnVar ensured that everything is a valid variable reference, so there
+  // really isn't anything to do here. GCC does some duplicate-finding, though
+  // it isn't apparent in the standard where this is justified.
+
+  return OpenACCNoCreateClause::Create(Ctx, Clause.getBeginLoc(),
+                                       Clause.getLParenLoc(),
+                                       Clause.getVarList(), Clause.getEndLoc());
+}
 
-    // ActOnVar ensured that everything is a valid variable reference, so there
-    // really isn't anything to do here. GCC does some duplicate-finding, though
-    // it isn't apparent in the standard where this is justified.
+OpenACCClause *SemaOpenACCClauseVisitor::VisitPresentClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+  // ActOnVar ensured that everything is a valid variable reference, so there
+  // really isn't anything to do here. GCC does some duplicate-finding, though
+  // it isn't apparent in the standard where this is justified.
+
+  return OpenACCPresentClause::Create(Ctx, Clause.getBeginLoc(),
+                                      Clause.getLParenLoc(),
+                                      Clause.getVarList(), Clause.getEndLoc());
+}
 
-    return OpenACCFirstPrivateClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
-        Clause.getVarList(), Clause.getEndLoc());
-  }
-  case OpenACCClauseKind::NoCreate: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
+OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+  // ActOnVar ensured that everything is a valid variable reference, so there
+  // really isn't anything to do here. GCC does some duplicate-finding, though
+  // it isn't apparent in the standard where this is justified.
+
+  return OpenACCCopyClause::Create(
+      Ctx, Clause.getClauseKind(), Clause.getBeginLoc(), Clause.getLParenLoc(),
+      Clause.getVarList(), Clause.getEndLoc());
+}
 
-    // ActOnVar ensured that everything is a valid variable reference, so there
-    // really isn't anything to do here. GCC does some duplicate-finding, though
-    // it isn't apparent in the standard where this is justified.
+OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyInClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+  // ActOnVar ensured that everything is a valid variable reference, so there
+  // really isn't anything to do here. GCC does some duplicate-finding, though
+  // it isn't apparent in the standard where this is justified.
+
+  return OpenACCCopyInClause::Create(
+      Ctx, Clause.getClauseKind(), Clause.getBeginLoc(), Clause.getLParenLoc(),
+      Clause.isReadOnly(), Clause.getVarList(), Clause.getEndLoc());
+}
 
-    return OpenACCNoCreateClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
-        Clause.getVarList(), Clause.getEndLoc());
-  }
-  case OpenACCClauseKind::Present: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
+OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyOutClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+  // ActOnVar ensured that everything is a valid variable reference, so there
+  // really isn't anything to do here. GCC does some duplicate-finding, though
+  // it isn't apparent in the standard where this is justified.
+
+  return OpenACCCopyOutClause::Create(
+      Ctx, Clause.getClauseKind(), Clause.getBeginLoc(), Clause.getLParenLoc(),
+      Clause.isZero(), Clause.getVarList(), Clause.getEndLoc());
+}
 
-    // ActOnVar ensured that everything is a valid variable reference, so there
-    // really isn't anything to do here. GCC does some duplicate-finding, though
-    // it isn't apparent in the standard where this is justified.
+OpenACCClause *SemaOpenACCClauseVisitor::VisitCreateClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+  // ActOnVar ensured that everything is a valid variable reference, so there
+  // really isn't anything to do here. GCC does some duplicate-finding, though
+  // it isn't apparent in the standard where this is justified.
+
+  return OpenACCCreateClause::Create(
+      Ctx, Clause.getClauseKind(), Clause.getBeginLoc(), Clause.getLParenLoc(),
+      Clause.isZero(), Clause.getVarList(), Clause.getEndLoc());
+}
 
-    return OpenACCPresentClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
-        Clause.getVarList(), Clause.getEndLoc());
-  }
-  case OpenACCClauseKind::PresentOrCopy:
-  case OpenACCClauseKind::PCopy:
-    Diag(Clause.getBeginLoc(), diag::warn_acc_deprecated_alias_name)
-        << Clause.getClauseKind() << OpenACCClauseKind::Copy;
-    LLVM_FALLTHROUGH;
-  case OpenACCClauseKind::Copy: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
+OpenACCClause *SemaOpenACCClauseVisitor::VisitAttachClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+
+  // ActOnVar ensured that everything is a valid variable reference, but we
+  // still have to make sure it is a pointer type.
+  llvm::SmallVector<Expr *> VarList{Clause.getVarList().begin(),
+                                    Clause.getVarList().end()};
+  VarList.erase(std::remove_if(VarList.begin(), VarList.end(),
+                               [&](Expr *E) {
+                                 return SemaRef.CheckVarIsPointerType(
+                                     OpenACCClauseKind::Attach, E);
+                               }),
+                VarList.end());
+  Clause.setVarListDetails(VarList,
+                           /*IsReadOnly=*/false, /*IsZero=*/false);
+  return OpenACCAttachClause::Create(Ctx, Clause.getBeginLoc(),
+                                     Clause.getLParenLoc(), Clause.getVarList(),
+                                     Clause.getEndLoc());
+}
 
-    // ActOnVar ensured that everything is a valid variable reference, so there
-    // really isn't anything to do here. GCC does some duplicate-finding, though
-    // it isn't apparent in the standard where this is justified.
+OpenACCClause *SemaOpenACCClauseVisitor::VisitDevicePtrClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+
+  // ActOnVar ensured that everything is a valid variable reference, but we
+  // still have to make sure it is a pointer type.
+  llvm::SmallVector<Expr *> VarList{Clause.getVarList().begin(),
+                                    Clause.getVarList().end()};
+  VarList.erase(std::remove_if(VarList.begin(), VarList.end(),
+                               [&](Expr *E) {
+                                 return SemaRef.CheckVarIsPointerType(
+                                     OpenACCClauseKind::DevicePtr, E);
+                               }),
+                VarList.end());
+  Clause.setVarListDetails(VarList,
+                           /*IsReadOnly=*/false, /*IsZero=*/false);
+
+  return OpenACCDevicePtrClause::Create(
+      Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(),
+      Clause.getEndLoc());
+}
 
-    return OpenACCCopyClause::Create(
-        getASTContext(), Clause.getClauseKind(), Clause.getBeginLoc(),
-        Clause.getLParenLoc(), Clause.getVarList(), Clause.getEndLoc());
-  }
-  case OpenACCClauseKind::PresentOrCopyIn:
-  case OpenACCClauseKind::PCopyIn:
-    Diag(Clause.getBeginLoc(), diag::warn_acc_deprecated_alias_name)
-        << Clause.getClauseKind() << OpenACCClauseKind::CopyIn;
-    LLVM_FALLTHROUGH;
-  case OpenACCClauseKind::CopyIn: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
+OpenACCClause *SemaOpenACCClauseVisitor::VisitWaitClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+
+  return OpenACCWaitClause::Create(
+      Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getDevNumExpr(),
+      Clause.getQueuesLoc(), Clause.getQueueIdExprs(), Clause.getEndLoc());
+}
 
-    // ActOnVar ensured that everything is a valid variable reference, so there
-    // really isn't anything to do here. GCC does some duplicate-finding, though
-    // it isn't apparent in the standard where this is justified.
+OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceTypeClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' and 'loop'
+  // constructs, and 'compute'/'loop' constructs are the only construct that
+  // can do anything with this yet, so skip/treat as unimplemented in this
+  // case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
+      Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
+    return isNotImplemented();
+
+  // TODO OpenACC: Once we get enough of the CodeGen implemented that we have
+  // a source for the list of valid architectures, we need to warn on unknown
+  // identifiers here.
+
+  return OpenACCDeviceTypeClause::Create(
+      Ctx, Clause.getClauseKind(), Clause.getBeginLoc(), Clause.getLParenLoc(),
+      Clause.getDeviceTypeArchitectures(), Clause.getEndLoc());
+}
 
-    return OpenACCCopyInClause::Create(
-        getASTContext(), Clause.getClauseKind(), Clause.getBeginLoc(),
-        Clause.getLParenLoc(), Clause.isReadOnly(), Clause.getVarList(),
-        Clause.getEndLoc());
+OpenACCClause *SemaOpenACCClauseVisitor::VisitAutoClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'loop' constructs, and it is
+  // the only construct that can do anything with this, so skip/treat as
+  // unimplemented for the combined constructs.
+  if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
+    return isNotImplemented();
+
+  // OpenACC 3.3 2.9:
+  // Only one of the seq, independent, and auto clauses may appear.
+  const auto *Itr =
+      llvm::find_if(ExistingClauses,
+                    llvm::IsaPred<OpenACCIndependentClause, OpenACCSeqClause>);
+  if (Itr != ExistingClauses.end()) {
+    SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_loop_spec_conflict)
+        << Clause.getClauseKind() << Clause.getDirectiveKind();
+    SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
+    return nullptr;
   }
-  case OpenACCClauseKind::PresentOrCopyOut:
-  case OpenACCClauseKind::PCopyOut:
-    Diag(Clause.getBeginLoc(), diag::warn_acc_deprecated_alias_name)
-        << Clause.getClauseKind() << OpenACCClauseKind::CopyOut;
-    LLVM_FALLTHROUGH;
-  case OpenACCClauseKind::CopyOut: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
 
-    // ActOnVar ensured that everything is a valid variable reference, so there
-    // really isn't anything to do here. GCC does some duplicate-finding, though
-    // it isn't apparent in the standard where this is justified.
+  return OpenACCAutoClause::Create(Ctx, Clause.getBeginLoc(),
+                                   Clause.getEndLoc());
+}
 
-    return OpenACCCopyOutClause::Create(
-        getASTContext(), Clause.getClauseKind(), Clause.getBeginLoc(),
-        Clause.getLParenLoc(), Clause.isZero(), Clause.getVarList(),
-        Clause.getEndLoc());
+OpenACCClause *SemaOpenACCClauseVisitor::VisitIndependentClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'loop' constructs, and it is
+  // the only construct that can do anything with this, so skip/treat as
+  // unimplemented for the combined constructs.
+  if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
+    return isNotImplemented();
+
+  // OpenACC 3.3 2.9:
+  // Only one of the seq, independent, and auto clauses may appear.
+  const auto *Itr = llvm::find_if(
+      ExistingClauses, llvm::IsaPred<OpenACCAutoClause, OpenACCSeqClause>);
+  if (Itr != ExistingClauses.end()) {
+    SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_loop_spec_conflict)
+        << Clause.getClauseKind() << Clause.getDirectiveKind();
+    SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
+    return nullptr;
   }
-  case OpenACCClauseKind::PresentOrCreate:
-  case OpenACCClauseKind::PCreate:
-    Diag(Clause.getBeginLoc(), diag::warn_acc_deprecated_alias_name)
-        << Clause.getClauseKind() << OpenACCClauseKind::Create;
-    LLVM_FALLTHROUGH;
-  case OpenACCClauseKind::Create: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
-
-    // ActOnVar ensured that everything is a valid variable reference, so there
-    // really isn't anything to do here. GCC does some duplicate-finding, though
-    // it isn't apparent in the standard where this is justified.
 
-    return OpenACCCreateClause::Create(getASTContext(), Clause.getClauseKind(),
-                                       Clause.getBeginLoc(),
-                                       Clause.getLParenLoc(), Clause.isZero(),
-                                       Clause.getVarList(), Clause.getEndLoc());
-  }
-  case OpenACCClauseKind::Attach: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
+  return OpenACCIndependentClause::Create(Ctx, Clause.getBeginLoc(),
+                                          Clause.getEndLoc());
+}
 
-    // ActOnVar ensured that everything is a valid variable reference, but we
-    // still have to make sure it is a pointer type.
-    llvm::SmallVector<Expr *> VarList{Clause.getVarList().begin(),
-                                      Clause.getVarList().end()};
-    VarList.erase(std::remove_if(VarList.begin(), VarList.end(), [&](Expr *E) {
-      return CheckVarIsPointerType(OpenACCClauseKind::Attach, E);
-    }), VarList.end());
-    Clause.setVarListDetails(VarList,
-                             /*IsReadOnly=*/false, /*IsZero=*/false);
-
-    return OpenACCAttachClause::Create(getASTContext(), Clause.getBeginLoc(),
-                                       Clause.getLParenLoc(),
-                                       Clause.getVarList(), Clause.getEndLoc());
+OpenACCClause *SemaOpenACCClauseVisitor::VisitSeqClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'loop' constructs, and it is
+  // the only construct that can do anything with this, so skip/treat as
+  // unimplemented for the combined constructs.
+  if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
+    return isNotImplemented();
+
+  // OpenACC 3.3 2.9:
+  // Only one of the seq, independent, and auto clauses may appear.
+  const auto *Itr =
+      llvm::find_if(ExistingClauses,
+                    llvm::IsaPred<OpenACCAutoClause, OpenACCIndependentClause>);
+  if (Itr != ExistingClauses.end()) {
+    SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_loop_spec_conflict)
+        << Clause.getClauseKind() << Clause.getDirectiveKind();
+    SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
+    return nullptr;
   }
-  case OpenACCClauseKind::DevicePtr: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
 
-    // ActOnVar ensured that everything is a valid variable reference, but we
-    // still have to make sure it is a pointer type.
-    llvm::SmallVector<Expr *> VarList{Clause.getVarList().begin(),
-                                      Clause.getVarList().end()};
-    VarList.erase(std::remove_if(VarList.begin(), VarList.end(), [&](Expr *E) {
-      return CheckVarIsPointerType(OpenACCClauseKind::DevicePtr, E);
-    }), VarList.end());
-    Clause.setVarListDetails(VarList,
-                             /*IsReadOnly=*/false, /*IsZero=*/false);
-
-    return OpenACCDevicePtrClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
-        Clause.getVarList(), Clause.getEndLoc());
-  }
-  case OpenACCClauseKind::Wait: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
+  // OpenACC 3.3 2.9:
+  // A 'gang', 'worker', or 'vector' clause may not appear if a 'seq' clause
+  // appears.
+  Itr = llvm::find_if(ExistingClauses,
+                      llvm::IsaPred<OpenACCGangClause, OpenACCWorkerClause,
+                                    OpenACCVectorClause>);
 
-    return OpenACCWaitClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
-        Clause.getDevNumExpr(), Clause.getQueuesLoc(), Clause.getQueueIdExprs(),
-        Clause.getEndLoc());
+  if (Itr != ExistingClauses.end()) {
+    SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine)
+        << Clause.getClauseKind() << (*Itr)->getClauseKind();
+    SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
+    return nullptr;
   }
-  case OpenACCClauseKind::DType:
-  case OpenACCClauseKind::DeviceType: {
-    // Restrictions only properly implemented on 'compute' and 'loop'
-    // constructs, and 'compute'/'loop' constructs are the only construct that
-    // can do anything with this yet, so skip/treat as unimplemented in this
-    // case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
-        Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
-      break;
 
-    // TODO OpenACC: Once we get enough of the CodeGen implemented that we have
-    // a source for the list of valid architectures, we need to warn on unknown
-    // identifiers here.
-
-    return OpenACCDeviceTypeClause::Create(
-        getASTContext(), Clause.getClauseKind(), Clause.getBeginLoc(),
-        Clause.getLParenLoc(), Clause.getDeviceTypeArchitectures(),
-        Clause.getEndLoc());
-  }
-  case OpenACCClauseKind::Auto: {
-    // Restrictions only properly implemented on 'loop' constructs, and it is
-    // the only construct that can do anything with this, so skip/treat as
-    // unimplemented for the combined constructs.
-    if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
-      break;
+  // TODO OpenACC: 2.9 ~ line 2010 specifies that the associated loop has some
+  // restrictions when there is a 'seq' clause in place. We probably need to
+  // implement that.
+  return OpenACCSeqClause::Create(Ctx, Clause.getBeginLoc(),
+                                  Clause.getEndLoc());
+}
 
-    // OpenACC 3.3 2.9:
-    // Only one of the seq, independent, and auto clauses may appear.
-    const auto *Itr = llvm::find_if(
-        ExistingClauses,
-        llvm::IsaPred<OpenACCIndependentClause, OpenACCSeqClause>);
-    if (Itr != ExistingClauses.end()) {
-      Diag(Clause.getBeginLoc(), diag::err_acc_loop_spec_conflict)
-          << Clause.getClauseKind() << Clause.getDirectiveKind();
-      Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
+OpenACCClause *SemaOpenACCClauseVisitor::VisitReductionClause(
+    SemaOpenACC::OpenACCParsedClause &Clause) {
+  // Restrictions only properly implemented on 'compute' constructs, and
+  // 'compute' constructs are the only construct that can do anything with
+  // this yet, so skip/treat as unimplemented in this case.
+  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
+    return isNotImplemented();
+
+  // OpenACC 3.3 Section 2.5.4:
+  // A reduction clause may not appear on a parallel construct with a
+  // num_gangs clause that has more than one argument.
+  if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel) {
+    auto NumGangsClauses = llvm::make_filter_range(
+        ExistingClauses, llvm::IsaPred<OpenACCNumGangsClause>);
+
+    for (auto *NGC : NumGangsClauses) {
+      unsigned NumExprs =
+          cast<OpenACCNumGangsClause>(NGC)->getIntExprs().size();
+
+      if (NumExprs > 1) {
+        SemaRef.Diag(Clause.getBeginLoc(),
+                     diag::err_acc_reduction_num_gangs_conflict)
+            << NumExprs;
+        SemaRef.Diag(NGC->getBeginLoc(), diag::note_acc_previous_clause_here);
+        return nullptr;
+      }
     }
-
-    return OpenACCAutoClause::Create(getASTContext(), Clause.getBeginLoc(),
-                                     Clause.getEndLoc());
   }
-  case OpenACCClauseKind::Independent: {
-    // Restrictions only properly implemented on 'loop' constructs, and it is
-    // the only construct that can do anything with this, so skip/treat as
-    // unimplemented for the combined constructs.
-    if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
-      break;
 
-    // OpenACC 3.3 2.9:
-    // Only one of the seq, independent, and auto clauses may appear.
-    const auto *Itr = llvm::find_if(
-        ExistingClauses, llvm::IsaPred<OpenACCAutoClause, OpenACCSeqClause>);
-    if (Itr != ExistingClauses.end()) {
-      Diag(Clause.getBeginLoc(), diag::err_acc_loop_spec_conflict)
-          << Clause.getClauseKind() << Clause.getDirectiveKind();
-      Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
-    }
+  SmallVector<Expr *> ValidVars;
+
+  for (Expr *Var : Clause.getVarList()) {
+    ExprResult Res = SemaRef.CheckReductionVar(Var);
 
-    return OpenACCIndependentClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getEndLoc());
+    if (Res.isUsable())
+      ValidVars.push_back(Res.get());
   }
-  case OpenACCClauseKind::Seq: {
-    // Restrictions only properly implemented on 'loop' constructs, and it is
-    // the only construct that can do anything with this, so skip/treat as
-    // unimplemented for the combined constructs.
-    if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
-      break;
 
-    // OpenACC 3.3 2.9:
-    // Only one of the seq, independent, and auto clauses may appear.
-    const auto *Itr = llvm::find_if(
-        ExistingClauses,
-        llvm::IsaPred<OpenACCAutoClause, OpenACCIndependentClause>);
-    if (Itr != ExistingClauses.end()) {
-      Diag(Clause.getBeginLoc(), diag::err_acc_loop_spec_conflict)
-          << Clause.getClauseKind() << Clause.getDirectiveKind();
-      Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
-    }
+  return OpenACCReductionClause::Create(
+      Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getReductionOp(),
+      ValidVars, Clause.getEndLoc());
+}
 
-    // OpenACC 3.3 2.9:
-    // A 'gang', 'worker', or 'vector' clause may not appear if a 'seq' clause
-    // appears.
-    Itr = llvm::find_if(ExistingClauses,
-                        llvm::IsaPred<OpenACCGangClause, OpenACCWorkerClause,
-                                      OpenACCVectorClause>);
+} // namespace
 
-    if (Itr != ExistingClauses.end()) {
-      Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine)
-          << Clause.getClauseKind() << (*Itr)->getClauseKind();
-      Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
-    }
+SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {}
 
-    // TODO OpenACC: 2.9 ~ line 2010 specifies that the associated loop has some
-    // restrictions when there is a 'seq' clause in place. We probably need to
-    // implement that.
-    return OpenACCSeqClause::Create(getASTContext(), Clause.getBeginLoc(),
-                                    Clause.getEndLoc());
+SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII(SemaOpenACC &S,
+                                                    OpenACCDirectiveKind DK)
+    : SemaRef(S), WasInsideComputeConstruct(S.InsideComputeConstruct),
+      DirKind(DK) {
+  // Compute constructs end up taking their 'loop'.
+  if (DirKind == OpenACCDirectiveKind::Parallel ||
+      DirKind == OpenACCDirectiveKind::Serial ||
+      DirKind == OpenACCDirectiveKind::Kernels) {
+    SemaRef.InsideComputeConstruct = true;
+    SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs);
   }
-  case OpenACCClauseKind::Gang:
-  case OpenACCClauseKind::Worker:
-  case OpenACCClauseKind::Vector: {
-    // OpenACC 3.3 2.9:
-    // A 'gang', 'worker', or 'vector' clause may not appear if a 'seq' clause
-    // appears.
-    const auto *Itr =
-        llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCSeqClause>);
+}
 
-    if (Itr != ExistingClauses.end()) {
-      Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine)
-          << Clause.getClauseKind() << (*Itr)->getClauseKind();
-      Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
-    }
-    // Not yet implemented, so immediately drop to the 'not yet implemented'
-    // diagnostic.
-    break;
+SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() {
+  SemaRef.InsideComputeConstruct = WasInsideComputeConstruct;
+  if (DirKind == OpenACCDirectiveKind::Parallel ||
+      DirKind == OpenACCDirectiveKind::Serial ||
+      DirKind == OpenACCDirectiveKind::Kernels) {
+    assert(SemaRef.ParentlessLoopConstructs.empty() &&
+           "Didn't consume loop construct list?");
+    SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs);
   }
-  case OpenACCClauseKind::Reduction: {
-    // Restrictions only properly implemented on 'compute' constructs, and
-    // 'compute' constructs are the only construct that can do anything with
-    // this yet, so skip/treat as unimplemented in this case.
-    if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
-      break;
-
-    // OpenACC 3.3 Section 2.5.4:
-    // A reduction clause may not appear on a parallel construct with a
-    // num_gangs clause that has more than one argument.
-    if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel) {
-      auto NumGangsClauses = llvm::make_filter_range(
-          ExistingClauses, llvm::IsaPred<OpenACCNumGangsClause>);
-
-      for (auto *NGC : NumGangsClauses) {
-        unsigned NumExprs =
-            cast<OpenACCNumGangsClause>(NGC)->getIntExprs().size();
-
-        if (NumExprs > 1) {
-          Diag(Clause.getBeginLoc(), diag::err_acc_reduction_num_gangs_conflict)
-              << NumExprs;
-          Diag(NGC->getBeginLoc(), diag::note_acc_previous_clause_here);
-          return nullptr;
-        }
-      }
-    }
-
-    SmallVector<Expr *> ValidVars;
-
-    for (Expr *Var : Clause.getVarList()) {
-      ExprResult Res = CheckReductionVar(Var);
+}
 
-      if (Res.isUsable())
-        ValidVars.push_back(Res.get());
-    }
+OpenACCClause *
+SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
+                         OpenACCParsedClause &Clause) {
+  if (Clause.getClauseKind() == OpenACCClauseKind::Invalid)
+    return nullptr;
 
-    return OpenACCReductionClause::Create(
-        getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
-        Clause.getReductionOp(), ValidVars, Clause.getEndLoc());
+  // Diagnose that we don't support this clause on this directive.
+  if (!doesClauseApplyToDirective(Clause.getDirectiveKind(),
+                                  Clause.getClauseKind())) {
+    Diag(Clause.getBeginLoc(), diag::err_acc_clause_appertainment)
+        << Clause.getDirectiveKind() << Clause.getClauseKind();
+    return nullptr;
   }
-  default:
-    break;
+
+  if (const auto *DevTypeClause =
+          llvm::find_if(ExistingClauses,
+                        [&](const OpenACCClause *C) {
+                          return isa<OpenACCDeviceTypeClause>(C);
+                        });
+      DevTypeClause != ExistingClauses.end()) {
+    if (checkValidAfterDeviceType(
+            *this, *cast<OpenACCDeviceTypeClause>(*DevTypeClause), Clause))
+      return nullptr;
   }
 
-  Diag(Clause.getBeginLoc(), diag::warn_acc_clause_unimplemented)
-      << Clause.getClauseKind();
-  return nullptr;
+  SemaOpenACCClauseVisitor Visitor{*this, ExistingClauses};
+  OpenACCClause *Result = Visitor.Visit(Clause);
+  assert((!Result || Result->getClauseKind() == Clause.getClauseKind()) &&
+         "Created wrong clause?");
+
+  if (Visitor.diagNotImplemented())
+    Diag(Clause.getBeginLoc(), diag::warn_acc_clause_unimplemented)
+        << Clause.getClauseKind();
+
+  return Result;
+
+  //  switch (Clause.getClauseKind()) {
+  //  case OpenACCClauseKind::PresentOrCopy:
+  //  case OpenACCClauseKind::PCopy:
+  //    Diag(Clause.getBeginLoc(), diag::warn_acc_deprecated_alias_name)
+  //        << Clause.getClauseKind() << OpenACCClauseKind::Copy;
+  //    LLVM_FALLTHROUGH;
+  //  case OpenACCClauseKind::PresentOrCreate:
+  //  case OpenACCClauseKind::PCreate:
+  //    Diag(Clause.getBeginLoc(), diag::warn_acc_deprecated_alias_name)
+  //        << Clause.getClauseKind() << OpenACCClauseKind::Create;
+  //    LLVM_FALLTHROUGH;
+  //
+  //
+  //
+  //
+  //  case OpenACCClauseKind::DType:
+  //
+  //
+  //
+  //
+  //
+  //
+  //
+  //
+  //  case OpenACCClauseKind::Gang:
+  //  case OpenACCClauseKind::Worker:
+  //  case OpenACCClauseKind::Vector: {
+  //    // OpenACC 3.3 2.9:
+  //    // A 'gang', 'worker', or 'vector' clause may not appear if a 'seq'
+  //    clause
+  //    // appears.
+  //    const auto *Itr =
+  //        llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCSeqClause>);
+  //
+  //    if (Itr != ExistingClauses.end()) {
+  //      Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine)
+  //          << Clause.getClauseKind() << (*Itr)->getClauseKind();
+  //      Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
+  //    }
+  //    // Not yet implemented, so immediately drop to the 'not yet implemented'
+  //    // diagnostic.
+  //    break;
+  //  }
+  //  */
+
 }
 
 /// OpenACC 3.3 section 2.5.15:


        


More information about the cfe-commits mailing list