[clang] [OpenACC] Implement Default clause for Compute Constructs (PR #88135)

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 9 11:09:36 PDT 2024


https://github.com/erichkeane updated https://github.com/llvm/llvm-project/pull/88135

>From b0595276f2b8d74d036ff9bf94c5baea86a57f17 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Mon, 8 Apr 2024 14:23:17 -0700
Subject: [PATCH 1/2] g This is a combination of 3 commits.

[OpenACC] Implement Default clause for Compute Constructs

As a followup to my previous commits, this is an implementation of a
single clause, in this case the 'default' clause.  This implements all
semantic analysis for it on compute clauses, and continues to leave it
rejected for all others (some as 'doesnt appertain', others as 'not
implemented' as appropriate).

This also implements and tests the TreeTransform as requested in the
previous patch.
---
 clang/include/clang/AST/OpenACCClause.h       | 38 ++++++++++
 .../clang/Basic/DiagnosticSemaKinds.td        |  4 +
 clang/include/clang/Basic/OpenACCKinds.h      | 23 ++++++
 clang/include/clang/Sema/SemaOpenACC.h        | 17 ++++-
 clang/lib/AST/OpenACCClause.cpp               | 19 +++++
 clang/lib/AST/StmtProfile.cpp                 |  5 ++
 clang/lib/AST/TextNodeDumper.cpp              | 11 +++
 clang/lib/Parse/ParseOpenACC.cpp              |  8 +-
 clang/lib/Sema/SemaOpenACC.cpp                | 65 ++++++++++++++--
 clang/lib/Sema/TreeTransform.h                | 42 ++++++++++-
 clang/lib/Serialization/ASTReader.cpp         |  7 +-
 clang/lib/Serialization/ASTWriter.cpp         |  7 +-
 clang/test/ParserOpenACC/parse-clauses.c      | 20 ++---
 .../SemaOpenACC/compute-construct-ast.cpp     | 14 +++-
 .../compute-construct-clause-ast.cpp          | 74 +++++++++++++++++++
 .../compute-construct-default-clause.c        | 55 ++++++++++++++
 .../compute-construct-default-clause.cpp      | 39 ++++++++++
 17 files changed, 415 insertions(+), 33 deletions(-)
 create mode 100644 clang/test/SemaOpenACC/compute-construct-clause-ast.cpp
 create mode 100644 clang/test/SemaOpenACC/compute-construct-default-clause.c
 create mode 100644 clang/test/SemaOpenACC/compute-construct-default-clause.cpp

diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h
index 06a0098bbda4cd..c979550ed00fc3 100644
--- a/clang/include/clang/AST/OpenACCClause.h
+++ b/clang/include/clang/AST/OpenACCClause.h
@@ -51,6 +51,36 @@ class OpenACCClauseWithParams : public OpenACCClause {
   SourceLocation getLParenLoc() const { return LParenLoc; }
 };
 
+// A 'default' clause, has the optional 'none' or 'present' argument.
+class OpenACCDefaultClause : public OpenACCClauseWithParams {
+  friend class ASTReaderStmt;
+  friend class ASTWriterStmt;
+
+  OpenACCDefaultClauseKind DefaultClauseKind;
+
+protected:
+  OpenACCDefaultClause(OpenACCDefaultClauseKind K, SourceLocation BeginLoc,
+                       SourceLocation LParenLoc, SourceLocation EndLoc)
+      : OpenACCClauseWithParams(OpenACCClauseKind::Default, BeginLoc, LParenLoc,
+                                EndLoc),
+        DefaultClauseKind(K) {
+    assert((DefaultClauseKind == OpenACCDefaultClauseKind::None ||
+            DefaultClauseKind == OpenACCDefaultClauseKind::Present) &&
+           "Invalid Clause Kind");
+  }
+
+public:
+  OpenACCDefaultClauseKind getDefaultClauseKind() const {
+    return DefaultClauseKind;
+  }
+
+  static OpenACCDefaultClause *Create(const ASTContext &C,
+                                      OpenACCDefaultClauseKind K,
+                                      SourceLocation BeginLoc,
+                                      SourceLocation LParenLoc,
+                                      SourceLocation EndLoc);
+};
+
 template <class Impl> class OpenACCClauseVisitor {
   Impl &getDerived() { return static_cast<Impl &>(*this); }
 
@@ -66,6 +96,8 @@ template <class Impl> class OpenACCClauseVisitor {
 
     switch (C->getClauseKind()) {
     case OpenACCClauseKind::Default:
+      VisitOpenACCDefaultClause(*static_cast<const OpenACCDefaultClause *>(C));
+      return;
     case OpenACCClauseKind::Finalize:
     case OpenACCClauseKind::IfPresent:
     case OpenACCClauseKind::Seq:
@@ -112,6 +144,10 @@ template <class Impl> class OpenACCClauseVisitor {
     }
     llvm_unreachable("Invalid Clause kind");
   }
+
+  void VisitOpenACCDefaultClause(const OpenACCDefaultClause &Clause) {
+    return getDerived().VisitOpenACCDefaultClause(Clause);
+  }
 };
 
 class OpenACCClausePrinter final
@@ -128,6 +164,8 @@ class OpenACCClausePrinter final
     }
   }
   OpenACCClausePrinter(raw_ostream &OS) : OS(OS) {}
+
+  void VisitOpenACCDefaultClause(const OpenACCDefaultClause &Clause);
 };
 
 } // namespace clang
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4fbbc42273ba93..ad9abd121bab6f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12254,6 +12254,10 @@ def err_acc_construct_appertainment
             "be used in a statement context">;
 def err_acc_clause_appertainment
     : Error<"OpenACC '%1' clause is not valid on '%0' directive">;
+def err_acc_duplicate_clause_diallowed
+    : Error<"OpenACC '%1' clause cannot appear more than once on a '%0' "
+            "directive">;
+def note_acc_previous_clause_here : Note<"previous clause is here">;
 def err_acc_branch_in_out_compute_construct
     : Error<"invalid %select{branch|return|throw}0 %select{out of|into}1 "
             "OpenACC Compute Construct">;
diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h
index 4456f4afd142df..eba2a642f4dc0b 100644
--- a/clang/include/clang/Basic/OpenACCKinds.h
+++ b/clang/include/clang/Basic/OpenACCKinds.h
@@ -419,6 +419,29 @@ enum class OpenACCDefaultClauseKind {
   Invalid,
 };
 
+template <typename StreamTy>
+inline StreamTy &PrintOpenACCDefaultClauseKind(StreamTy &Out,
+                                               OpenACCDefaultClauseKind K) {
+  switch (K) {
+  case OpenACCDefaultClauseKind::None:
+    return Out << "none";
+  case OpenACCDefaultClauseKind::Present:
+    return Out << "present";
+  case OpenACCDefaultClauseKind::Invalid:
+    return Out << "<invalid>";
+  }
+}
+
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
+                                             OpenACCDefaultClauseKind K) {
+  return PrintOpenACCDefaultClauseKind(Out, K);
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out,
+                                     OpenACCDefaultClauseKind K) {
+  return PrintOpenACCDefaultClauseKind(Out, K);
+}
+
 enum class OpenACCReductionOperator {
   /// '+'.
   Addition,
diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h
index 45929e4a9db3f1..3b27e45e240772 100644
--- a/clang/include/clang/Sema/SemaOpenACC.h
+++ b/clang/include/clang/Sema/SemaOpenACC.h
@@ -19,6 +19,7 @@
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Sema/Ownership.h"
 #include "clang/Sema/SemaBase.h"
+#include <variant>
 
 namespace clang {
 class OpenACCClause;
@@ -35,7 +36,11 @@ class SemaOpenACC : public SemaBase {
     SourceRange ClauseRange;
     SourceLocation LParenLoc;
 
-    // TODO OpenACC: Add variant here to store details of individual clauses.
+    struct DefaultDetails {
+      OpenACCDefaultClauseKind DefaultClauseKind;
+    };
+
+    std::variant<DefaultDetails> Details;
 
   public:
     OpenACCParsedClause(OpenACCDirectiveKind DirKind,
@@ -52,8 +57,18 @@ class SemaOpenACC : public SemaBase {
 
     SourceLocation getEndLoc() const { return ClauseRange.getEnd(); }
 
+    OpenACCDefaultClauseKind getDefaultClauseKind() const {
+      assert(ClauseKind == OpenACCClauseKind::Default);
+      return std::get<DefaultDetails>(Details).DefaultClauseKind;
+    }
+
     void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; }
     void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); }
+
+    void setDefaultDetails(OpenACCDefaultClauseKind DefKind) {
+      assert(ClauseKind == OpenACCClauseKind::Default);
+      Details = DefaultDetails{DefKind};
+    }
   };
 
   SemaOpenACC(Sema &S);
diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp
index e1db872f25c322..24d667d8ba5665 100644
--- a/clang/lib/AST/OpenACCClause.cpp
+++ b/clang/lib/AST/OpenACCClause.cpp
@@ -15,3 +15,22 @@
 #include "clang/AST/ASTContext.h"
 
 using namespace clang;
+
+OpenACCDefaultClause *OpenACCDefaultClause::Create(const ASTContext &C,
+                                                   OpenACCDefaultClauseKind K,
+                                                   SourceLocation BeginLoc,
+                                                   SourceLocation LParenLoc,
+                                                   SourceLocation EndLoc) {
+  void *Mem =
+      C.Allocate(sizeof(OpenACCDefaultClause), alignof(OpenACCDefaultClause));
+
+  return new (Mem) OpenACCDefaultClause(K, BeginLoc, LParenLoc, EndLoc);
+}
+
+//===----------------------------------------------------------------------===//
+//  OpenACC clauses printing methods
+//===----------------------------------------------------------------------===//
+void OpenACCClausePrinter::VisitOpenACCDefaultClause(
+    const OpenACCDefaultClause &C) {
+  OS << "default(" << C.getDefaultClauseKind();
+}
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index bec8bc71f5554c..be3dd4b673cf98 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2456,7 +2456,12 @@ class OpenACCClauseProfiler
       Visit(Clause);
     }
   }
+  void VisitOpenACCDefaultClause(const OpenACCDefaultClause &Clause);
 };
+
+/// Nothing to do here, there are no sub-statements.
+void OpenACCClauseProfiler::VisitOpenACCDefaultClause(
+    const OpenACCDefaultClause &Clause) {}
 } // namespace
 
 void StmtProfiler::VisitOpenACCComputeConstruct(
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 431f5d8bdb2b5f..085a7f51ce99ad 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -390,6 +390,17 @@ void TextNodeDumper::Visit(const OpenACCClause *C) {
   {
     ColorScope Color(OS, ShowColors, AttrColor);
     OS << C->getClauseKind();
+
+    // Handle clauses with parens for types that have no children, likely
+    // because there is no sub expression.
+    switch (C->getClauseKind()) {
+    case OpenACCClauseKind::Default:
+      OS << '(' << cast<OpenACCDefaultClause>(C)->getDefaultClauseKind() << ')';
+      break;
+    default:
+      // Nothing to do here.
+      break;
+    }
   }
   dumpPointer(C);
   dumpSourceRange(SourceRange(C->getBeginLoc(), C->getEndLoc()));
diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index f434e1542c801f..59a4a5f5346762 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -831,9 +831,13 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
 
       ConsumeToken();
 
-      if (getOpenACCDefaultClauseKind(DefKindTok) ==
-          OpenACCDefaultClauseKind::Invalid)
+      OpenACCDefaultClauseKind DefKind =
+          getOpenACCDefaultClauseKind(DefKindTok);
+
+      if (DefKind == OpenACCDefaultClauseKind::Invalid)
         Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);
+      else
+        ParsedClause.setDefaultDetails(DefKind);
 
       break;
     }
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 2ba1e49b5739db..2c806f5f72b7b3 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -39,11 +39,27 @@ bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K,
 
 bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind,
                                 OpenACCClauseKind ClauseKind) {
-  // FIXME: For each clause as we implement them, we can add the
-  // 'legalization' list here.
-
-  // Do nothing so we can go to the 'unimplemented' diagnostic instead.
-  return true;
+  switch (ClauseKind) {
+    // FIXME: For each clause as we implement them, we can add the
+    // 'legalization' list here.
+  case OpenACCClauseKind::Default:
+    switch (DirectiveKind) {
+    case OpenACCDirectiveKind::Parallel:
+    case OpenACCDirectiveKind::Serial:
+    case OpenACCDirectiveKind::Kernels:
+    case OpenACCDirectiveKind::ParallelLoop:
+    case OpenACCDirectiveKind::SerialLoop:
+    case OpenACCDirectiveKind::KernelsLoop:
+    case OpenACCDirectiveKind::Data:
+      return true;
+    default:
+      return false;
+    }
+  default:
+    // Do nothing so we can go to the 'unimplemented' diagnostic instead.
+    return true;
+  }
+  llvm_unreachable("Invalid clause kind");
 }
 } // namespace
 
@@ -63,8 +79,43 @@ SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
     return nullptr;
   }
 
-  // TODO OpenACC: Switch over the clauses we implement here and 'create'
-  // them.
+  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 (Clause.getDirectiveKind() != OpenACCDirectiveKind::Parallel &&
+        Clause.getDirectiveKind() != OpenACCDirectiveKind::Serial &&
+        Clause.getDirectiveKind() != OpenACCDirectiveKind::Kernels)
+      break;
+
+    // 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.
+    auto Itr = llvm::find_if(ExistingClauses, [](const OpenACCClause *C) {
+      return C->getClauseKind() == OpenACCClauseKind::Default;
+    });
+
+    if (Itr != ExistingClauses.end()) {
+      SemaRef.Diag(Clause.getBeginLoc(),
+                   diag::err_acc_duplicate_clause_diallowed)
+          << Clause.getDirectiveKind() << Clause.getClauseKind();
+      SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
+      return nullptr;
+    }
+
+    return OpenACCDefaultClause::Create(
+        getASTContext(), Clause.getDefaultClauseKind(), Clause.getBeginLoc(),
+        Clause.getLParenLoc(), Clause.getEndLoc());
+  }
+  default:
+    break;
+  }
 
   Diag(Clause.getBeginLoc(), diag::warn_acc_clause_unimplemented)
       << Clause.getClauseKind();
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 13d7b00430d523..25e011a8ba6d84 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4034,6 +4034,11 @@ class TreeTransform {
   llvm::SmallVector<OpenACCClause *>
   TransformOpenACCClauseList(OpenACCDirectiveKind DirKind,
                              ArrayRef<const OpenACCClause *> OldClauses);
+
+  OpenACCClause *
+  TransformOpenACCClause(ArrayRef<const OpenACCClause *> ExistingClauses,
+                         OpenACCDirectiveKind DirKind,
+                         const OpenACCClause *OldClause);
 };
 
 template <typename Derived>
@@ -11074,13 +11079,44 @@ OMPClause *TreeTransform<Derived>::TransformOMPXBareClause(OMPXBareClause *C) {
 //===----------------------------------------------------------------------===//
 // OpenACC transformation
 //===----------------------------------------------------------------------===//
+template <typename Derived>
+OpenACCClause *TreeTransform<Derived>::TransformOpenACCClause(
+    ArrayRef<const OpenACCClause *> ExistingClauses,
+    OpenACCDirectiveKind DirKind, const OpenACCClause *OldClause) {
+
+  SemaOpenACC::OpenACCParsedClause ParsedClause(
+      DirKind, OldClause->getClauseKind(), OldClause->getBeginLoc());
+  ParsedClause.setEndLoc(OldClause->getEndLoc());
+
+  if (const auto *WithParms = dyn_cast<OpenACCClauseWithParams>(OldClause))
+    ParsedClause.setLParenLoc(WithParms->getLParenLoc());
+
+  switch (OldClause->getClauseKind()) {
+  case OpenACCClauseKind::Default:
+    // There is nothing to do here as nothing dependent can appear in this
+    // clause. So just set the values so Sema can set the right value.
+    ParsedClause.setDefaultDetails(
+        cast<OpenACCDefaultClause>(OldClause)->getDefaultClauseKind());
+    break;
+  default:
+    assert(false && "Unhandled OpenACC clause in TreeTransform");
+    return nullptr;
+  }
+
+  return getSema().OpenACC().ActOnClause(ExistingClauses, ParsedClause);
+}
+
 template <typename Derived>
 llvm::SmallVector<OpenACCClause *>
 TreeTransform<Derived>::TransformOpenACCClauseList(
     OpenACCDirectiveKind DirKind, ArrayRef<const OpenACCClause *> OldClauses) {
-  // TODO OpenACC: Ensure we loop through the list and transform the individual
-  // clauses.
-  return {};
+  llvm::SmallVector<OpenACCClause *> TransformedClauses;
+  for (const auto *Clause : OldClauses) {
+    if (OpenACCClause *TransformedClause = getDerived().TransformOpenACCClause(
+            TransformedClauses, DirKind, Clause))
+      TransformedClauses.push_back(TransformedClause);
+  }
+  return TransformedClauses;
 }
 
 template <typename Derived>
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index fa5bb9f2d5435a..679302e7a838f1 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -11763,7 +11763,12 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
   [[maybe_unused]] SourceLocation EndLoc = readSourceLocation();
 
   switch (ClauseKind) {
-  case OpenACCClauseKind::Default:
+  case OpenACCClauseKind::Default: {
+    SourceLocation LParenLoc = readSourceLocation();
+    OpenACCDefaultClauseKind DCK = readEnum<OpenACCDefaultClauseKind>();
+    return OpenACCDefaultClause::Create(getContext(), DCK, BeginLoc, LParenLoc,
+                                        EndLoc);
+  }
   case OpenACCClauseKind::Finalize:
   case OpenACCClauseKind::IfPresent:
   case OpenACCClauseKind::Seq:
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index baf03f69d73065..4cd74b1ba9d72d 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -7406,7 +7406,12 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
   writeSourceLocation(C->getEndLoc());
 
   switch (C->getClauseKind()) {
-  case OpenACCClauseKind::Default:
+  case OpenACCClauseKind::Default: {
+    const auto *DC = cast<OpenACCDefaultClause>(C);
+    writeSourceLocation(DC->getLParenLoc());
+    writeEnum(DC->getDefaultClauseKind());
+    return;
+  }
   case OpenACCClauseKind::Finalize:
   case OpenACCClauseKind::IfPresent:
   case OpenACCClauseKind::Seq:
diff --git a/clang/test/ParserOpenACC/parse-clauses.c b/clang/test/ParserOpenACC/parse-clauses.c
index b58b332ad3245c..b363a0cb1362b0 100644
--- a/clang/test/ParserOpenACC/parse-clauses.c
+++ b/clang/test/ParserOpenACC/parse-clauses.c
@@ -173,45 +173,37 @@ void DefaultClause() {
 #pragma acc serial default), seq
   for(;;){}
 
-  // expected-error at +2{{expected identifier}}
-  // expected-warning at +1{{OpenACC clause 'default' not yet implemented, clause ignored}}
+  // expected-error at +1{{expected identifier}}
 #pragma acc serial default()
   for(;;){}
 
-  // expected-error at +3{{expected identifier}}
-  // expected-warning at +2{{OpenACC clause 'default' not yet implemented, clause ignored}}
+  // expected-error at +2{{expected identifier}}
   // expected-warning at +1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
 #pragma acc serial default() seq
   for(;;){}
 
-  // expected-error at +3{{expected identifier}}
-  // expected-warning at +2{{OpenACC clause 'default' not yet implemented, clause ignored}}
+  // expected-error at +2{{expected identifier}}
   // expected-warning at +1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
 #pragma acc serial default(), seq
   for(;;){}
 
-  // expected-error at +2{{invalid value for 'default' clause; expected 'present' or 'none'}}
-  // expected-warning at +1{{OpenACC clause 'default' not yet implemented, clause ignored}}
+  // expected-error at +1{{invalid value for 'default' clause; expected 'present' or 'none'}}
 #pragma acc serial default(invalid)
   for(;;){}
 
-  // expected-error at +3{{invalid value for 'default' clause; expected 'present' or 'none'}}
-  // expected-warning at +2{{OpenACC clause 'default' not yet implemented, clause ignored}}
+  // expected-error at +2{{invalid value for 'default' clause; expected 'present' or 'none'}}
   // expected-warning at +1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
 #pragma acc serial default(auto) seq
   for(;;){}
 
-  // expected-error at +3{{invalid value for 'default' clause; expected 'present' or 'none'}}
-  // expected-warning at +2{{OpenACC clause 'default' not yet implemented, clause ignored}}
+  // expected-error at +2{{invalid value for 'default' clause; expected 'present' or 'none'}}
   // expected-warning at +1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
 #pragma acc serial default(invalid), seq
   for(;;){}
 
-  // expected-warning at +1{{OpenACC clause 'default' not yet implemented, clause ignored}}
 #pragma acc serial default(none)
   for(;;){}
 
-  // expected-warning at +2{{OpenACC clause 'default' not yet implemented, clause ignored}}
   // expected-warning at +1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
 #pragma acc serial default(present), seq
   for(;;){}
diff --git a/clang/test/SemaOpenACC/compute-construct-ast.cpp b/clang/test/SemaOpenACC/compute-construct-ast.cpp
index 55c080838a1886..e632522f877b53 100644
--- a/clang/test/SemaOpenACC/compute-construct-ast.cpp
+++ b/clang/test/SemaOpenACC/compute-construct-ast.cpp
@@ -12,14 +12,16 @@ void NormalFunc() {
   // CHECK-LABEL: NormalFunc
   // CHECK-NEXT: CompoundStmt
   // CHECK-NEXT: OpenACCComputeConstruct {{.*}}parallel
+  // CHECK-NEXT: default(none)
   // CHECK-NEXT: CompoundStmt
-#pragma acc parallel
+#pragma acc parallel default(none)
   {
 #pragma acc parallel
   // CHECK-NEXT: OpenACCComputeConstruct {{.*}}parallel
   // CHECK-NEXT: OpenACCComputeConstruct {{.*}}parallel
+  // CHECK-NEXT: default(present)
   // CHECK-NEXT: CompoundStmt
-#pragma acc parallel
+#pragma acc parallel default(present)
     {}
   }
   // FIXME: Add a test once we have clauses for this.
@@ -50,12 +52,12 @@ void NormalFunc() {
 
 template<typename T>
 void TemplFunc() {
-#pragma acc parallel
+#pragma acc parallel default(none)
   {
     typename T::type I;
   }
 
-#pragma acc serial
+#pragma acc serial default(present)
   {
     typename T::type I;
   }
@@ -72,10 +74,12 @@ void TemplFunc() {
   // CHECK-NEXT: FunctionDecl
   // CHECK-NEXT: CompoundStmt
   // CHECK-NEXT: OpenACCComputeConstruct {{.*}}parallel
+  // CHECK-NEXT: default(none)
   // CHECK-NEXT: CompoundStmt
   // CHECK-NEXT: DeclStmt
   // CHECK-NEXT: VarDecl{{.*}} I 'typename T::type'
   // CHECK-NEXT: OpenACCComputeConstruct {{.*}}serial
+  // CHECK-NEXT: default(present)
   // CHECK-NEXT: CompoundStmt
   // CHECK-NEXT: DeclStmt
   // CHECK-NEXT: VarDecl{{.*}} I 'typename T::type'
@@ -91,10 +95,12 @@ void TemplFunc() {
   // CHECK-NEXT: CXXRecord
   // CHECK-NEXT: CompoundStmt
   // CHECK-NEXT: OpenACCComputeConstruct {{.*}}parallel
+  // CHECK-NEXT: default(none)
   // CHECK-NEXT: CompoundStmt
   // CHECK-NEXT: DeclStmt
   // CHECK-NEXT: VarDecl{{.*}} I 'typename S::type':'int'
   // CHECK-NEXT: OpenACCComputeConstruct {{.*}}serial
+  // CHECK-NEXT: default(present)
   // CHECK-NEXT: CompoundStmt
   // CHECK-NEXT: DeclStmt
   // CHECK-NEXT: VarDecl{{.*}} I 'typename S::type':'int'
diff --git a/clang/test/SemaOpenACC/compute-construct-clause-ast.cpp b/clang/test/SemaOpenACC/compute-construct-clause-ast.cpp
new file mode 100644
index 00000000000000..bd80103445028a
--- /dev/null
+++ b/clang/test/SemaOpenACC/compute-construct-clause-ast.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s
+
+// Test this with PCH.
+// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s
+// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s
+
+#ifndef PCH_HELPER
+#define PCH_HELPER
+void NormalFunc() {
+  // CHECK: FunctionDecl{{.*}}NormalFunc
+  // CHECK-NEXT: CompoundStmt
+#pragma acc parallel default(none)
+  while(true);
+  // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
+  // CHECK-NEXT: default(none)
+  // CHECK-NEXT: WhileStmt
+  // CHECK-NEXT: CXXBoolLiteralExpr
+  // CHECK-NEXT: NullStmt
+
+#pragma acc serial default(present)
+  while(true);
+  // CHECK-NEXT: OpenACCComputeConstruct{{.*}}serial
+  // CHECK-NEXT: default(present)
+  // CHECK-NEXT: WhileStmt
+  // CHECK-NEXT: CXXBoolLiteralExpr
+  // CHECK-NEXT: NullStmt
+}
+
+template<typename T>
+void TemplFunc() {
+  // CHECK: FunctionTemplateDecl{{.*}}TemplFunc
+  // CHECK-NEXT: TemplateTypeParmDecl
+
+  // Match the prototype:
+  // CHECK-NEXT: FunctionDecl{{.*}}TemplFunc
+  // CHECK-NEXT: CompoundStmt
+
+#pragma acc kernels default(none)
+  while(true);
+  // CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
+  // CHECK-NEXT: default(none)
+  // CHECK-NEXT: WhileStmt
+  // CHECK-NEXT: CXXBoolLiteralExpr
+  // CHECK-NEXT: NullStmt
+
+#pragma acc parallel default(present)
+  while(true);
+  // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
+  // CHECK-NEXT: default(present)
+  // CHECK-NEXT: WhileStmt
+  // CHECK-NEXT: CXXBoolLiteralExpr
+  // CHECK-NEXT: NullStmt
+
+  // Match the instantiation:
+  // CHECK: FunctionDecl{{.*}}TemplFunc{{.*}}implicit_instantiation
+  // CHECK-NEXT: TemplateArgument type 'int'
+  // CHECK-NEXT: BuiltinType
+  // CHECK-NEXT: CompoundStmt
+  // CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
+  // CHECK-NEXT: default(none)
+  // CHECK-NEXT: WhileStmt
+  // CHECK-NEXT: CXXBoolLiteralExpr
+  // CHECK-NEXT: NullStmt
+  // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
+  // CHECK-NEXT: default(present)
+  // CHECK-NEXT: WhileStmt
+  // CHECK-NEXT: CXXBoolLiteralExpr
+  // CHECK-NEXT: NullStmt
+}
+
+void Instantiate() {
+  TemplFunc<int>();
+}
+#endif
diff --git a/clang/test/SemaOpenACC/compute-construct-default-clause.c b/clang/test/SemaOpenACC/compute-construct-default-clause.c
new file mode 100644
index 00000000000000..b1235fcca1f6a1
--- /dev/null
+++ b/clang/test/SemaOpenACC/compute-construct-default-clause.c
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 %s -fopenacc -verify
+
+void SingleOnly() {
+  #pragma acc parallel default(none)
+  while(0);
+
+  // expected-warning at +3{{OpenACC clause 'seq' not yet implemented}}
+  // expected-error at +2{{OpenACC 'default' clause cannot appear more than once on a 'serial' directive}}
+  // expected-note at +1{{previous clause is here}}
+  #pragma acc serial default(present) seq default(none)
+  while(0);
+
+  // expected-warning at +5{{OpenACC clause 'seq' not yet implemented}}
+  // expected-warning at +4{{OpenACC clause 'seq' not yet implemented}}
+  // expected-warning at +3{{OpenACC clause 'seq' not yet implemented}}
+  // expected-error at +2{{OpenACC 'default' clause cannot appear more than once on a 'kernels' directive}}
+  // expected-note at +1{{previous clause is here}}
+  #pragma acc kernels seq default(present) seq default(none) seq
+  while(0);
+
+  // expected-warning at +6{{OpenACC construct 'parallel loop' not yet implemented}}
+  // expected-warning at +5{{OpenACC clause 'seq' not yet implemented}}
+  // expected-warning at +4{{OpenACC clause 'seq' not yet implemented}}
+  // expected-warning at +3{{OpenACC clause 'seq' not yet implemented}}
+  // expected-warning at +2{{OpenACC clause 'default' not yet implemented}}
+  // expected-warning at +1{{OpenACC clause 'default' not yet implemented}}
+  #pragma acc parallel loop seq default(present) seq default(none) seq
+  while(0);
+
+  // expected-warning at +3{{OpenACC construct 'serial loop' not yet implemented}}
+  // expected-warning at +2{{OpenACC clause 'seq' not yet implemented}}
+  // expected-error at +1{{expected '('}}
+  #pragma acc serial loop seq default seq default(none) seq
+  while(0);
+
+  // expected-warning at +2{{OpenACC construct 'kernels loop' not yet implemented}}
+  // expected-warning at +1{{OpenACC clause 'default' not yet implemented}}
+  #pragma acc kernels loop default(none)
+  while(0);
+
+  // expected-warning at +2{{OpenACC construct 'data' not yet implemented}}
+  // expected-warning at +1{{OpenACC clause 'default' not yet implemented}}
+  #pragma acc data default(none)
+  while(0);
+
+  // expected-warning at +2{{OpenACC construct 'loop' not yet implemented}}
+  // expected-error at +1{{OpenACC 'default' clause is not valid on 'loop' directive}}
+  #pragma acc loop default(none)
+  while(0);
+
+  // expected-warning at +2{{OpenACC construct 'wait' not yet implemented}}
+  // expected-error at +1{{OpenACC 'default' clause is not valid on 'wait' directive}}
+  #pragma acc wait default(none)
+  while(0);
+}
diff --git a/clang/test/SemaOpenACC/compute-construct-default-clause.cpp b/clang/test/SemaOpenACC/compute-construct-default-clause.cpp
new file mode 100644
index 00000000000000..2c3e711ffd0852
--- /dev/null
+++ b/clang/test/SemaOpenACC/compute-construct-default-clause.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 %s -fopenacc -verify
+
+template<typename T>
+void SingleOnly() {
+  #pragma acc parallel default(none)
+  while(false);
+
+  // expected-warning at +3{{OpenACC clause 'seq' not yet implemented}}
+  // expected-error at +2{{OpenACC 'default' clause cannot appear more than once on a 'parallel' directive}}
+  // expected-note at +1{{previous clause is here}}
+  #pragma acc parallel default(present) seq default(none)
+  while(false);
+
+  // expected-warning at +5{{OpenACC clause 'seq' not yet implemented}}
+  // expected-warning at +4{{OpenACC clause 'seq' not yet implemented}}
+  // expected-warning at +3{{OpenACC clause 'seq' not yet implemented}}
+  // expected-error at +2{{OpenACC 'default' clause cannot appear more than once on a 'serial' directive}}
+  // expected-note at +1{{previous clause is here}}
+  #pragma acc serial seq default(present) seq default(none) seq
+  while(false);
+
+  // expected-warning at +5{{OpenACC clause 'seq' not yet implemented}}
+  // expected-warning at +4{{OpenACC clause 'seq' not yet implemented}}
+  // expected-warning at +3{{OpenACC clause 'seq' not yet implemented}}
+  // expected-error at +2{{OpenACC 'default' clause cannot appear more than once on a 'kernels' directive}}
+  // expected-note at +1{{previous clause is here}}
+  #pragma acc kernels seq default(present) seq default(none) seq
+  while(false);
+
+  // expected-warning at +3{{OpenACC clause 'seq' not yet implemented}}
+  // expected-warning at +2{{OpenACC clause 'seq' not yet implemented}}
+  // expected-error at +1{{expected '('}}
+  #pragma acc parallel seq default(none) seq default seq
+  while(false);
+}
+
+void Instantiate() {
+  SingleOnly<int>();
+}

>From fea6a22a44be2f76bfdb79e4ca7936e0084e4b89 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Tue, 9 Apr 2024 11:09:21 -0700
Subject: [PATCH 2/2] Alexey's review comments

---
 clang/include/clang/AST/OpenACCClause.h  | 4 ++--
 clang/include/clang/Basic/OpenACCKinds.h | 6 +++---
 clang/include/clang/Sema/SemaOpenACC.h   | 6 ++++--
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h
index c979550ed00fc3..27e4e1a12c9837 100644
--- a/clang/include/clang/AST/OpenACCClause.h
+++ b/clang/include/clang/AST/OpenACCClause.h
@@ -51,7 +51,7 @@ class OpenACCClauseWithParams : public OpenACCClause {
   SourceLocation getLParenLoc() const { return LParenLoc; }
 };
 
-// A 'default' clause, has the optional 'none' or 'present' argument.
+/// A 'default' clause, has the optional 'none' or 'present' argument.
 class OpenACCDefaultClause : public OpenACCClauseWithParams {
   friend class ASTReaderStmt;
   friend class ASTWriterStmt;
@@ -96,7 +96,7 @@ template <class Impl> class OpenACCClauseVisitor {
 
     switch (C->getClauseKind()) {
     case OpenACCClauseKind::Default:
-      VisitOpenACCDefaultClause(*static_cast<const OpenACCDefaultClause *>(C));
+      VisitOpenACCDefaultClause(*cast<OpenACCDefaultClause>(C));
       return;
     case OpenACCClauseKind::Finalize:
     case OpenACCClauseKind::IfPresent:
diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h
index eba2a642f4dc0b..57dab78e6861f9 100644
--- a/clang/include/clang/Basic/OpenACCKinds.h
+++ b/clang/include/clang/Basic/OpenACCKinds.h
@@ -420,7 +420,7 @@ enum class OpenACCDefaultClauseKind {
 };
 
 template <typename StreamTy>
-inline StreamTy &PrintOpenACCDefaultClauseKind(StreamTy &Out,
+inline StreamTy &printOpenACCDefaultClauseKind(StreamTy &Out,
                                                OpenACCDefaultClauseKind K) {
   switch (K) {
   case OpenACCDefaultClauseKind::None:
@@ -434,12 +434,12 @@ inline StreamTy &PrintOpenACCDefaultClauseKind(StreamTy &Out,
 
 inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
                                              OpenACCDefaultClauseKind K) {
-  return PrintOpenACCDefaultClauseKind(Out, K);
+  return printOpenACCDefaultClauseKind(Out, K);
 }
 
 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out,
                                      OpenACCDefaultClauseKind K) {
-  return PrintOpenACCDefaultClauseKind(Out, K);
+  return printOpenACCDefaultClauseKind(Out, K);
 }
 
 enum class OpenACCReductionOperator {
diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h
index 3b27e45e240772..27aaee164a2880 100644
--- a/clang/include/clang/Sema/SemaOpenACC.h
+++ b/clang/include/clang/Sema/SemaOpenACC.h
@@ -58,7 +58,8 @@ class SemaOpenACC : public SemaBase {
     SourceLocation getEndLoc() const { return ClauseRange.getEnd(); }
 
     OpenACCDefaultClauseKind getDefaultClauseKind() const {
-      assert(ClauseKind == OpenACCClauseKind::Default);
+      assert(ClauseKind == OpenACCClauseKind::Default &&
+             "Parsed clause is not a default clause");
       return std::get<DefaultDetails>(Details).DefaultClauseKind;
     }
 
@@ -66,7 +67,8 @@ class SemaOpenACC : public SemaBase {
     void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); }
 
     void setDefaultDetails(OpenACCDefaultClauseKind DefKind) {
-      assert(ClauseKind == OpenACCClauseKind::Default);
+      assert(ClauseKind == OpenACCClauseKind::Default &&
+             "Parsed clause is not a default clause");
       Details = DefaultDetails{DefKind};
     }
   };



More information about the cfe-commits mailing list