[clang] 4bbdb01 - [OpenACC] Implement 'init' and 'shutdown' constructs

via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 19 12:21:57 PST 2024


Author: erichkeane
Date: 2024-12-19T12:21:50-08:00
New Revision: 4bbdb018a6cb564783cfb9c65ca82b81c6006bb6

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

LOG: [OpenACC] Implement 'init' and 'shutdown' constructs

These two constructs are very simple and similar, and only support 3
different clauses, two of which are already implemented.  This patch
adds AST nodes for both constructs, and leaves the device_num clause
unimplemented, but enables the other two.

Added: 
    clang/test/AST/ast-print-openacc-init-construct.cpp
    clang/test/AST/ast-print-openacc-shutdown-construct.cpp
    clang/test/SemaOpenACC/init-construct-ast.cpp
    clang/test/SemaOpenACC/init-construct.cpp
    clang/test/SemaOpenACC/shutdown-construct-ast.cpp
    clang/test/SemaOpenACC/shutdown-construct.cpp

Modified: 
    clang/include/clang-c/Index.h
    clang/include/clang/AST/RecursiveASTVisitor.h
    clang/include/clang/AST/StmtOpenACC.h
    clang/include/clang/AST/TextNodeDumper.h
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Basic/StmtNodes.td
    clang/include/clang/Serialization/ASTBitCodes.h
    clang/lib/AST/StmtOpenACC.cpp
    clang/lib/AST/StmtPrinter.cpp
    clang/lib/AST/StmtProfile.cpp
    clang/lib/AST/TextNodeDumper.cpp
    clang/lib/CodeGen/CGStmt.cpp
    clang/lib/CodeGen/CodeGenFunction.h
    clang/lib/Parse/ParseOpenACC.cpp
    clang/lib/Sema/SemaExceptionSpec.cpp
    clang/lib/Sema/SemaOpenACC.cpp
    clang/lib/Sema/TreeTransform.h
    clang/lib/Serialization/ASTReaderStmt.cpp
    clang/lib/Serialization/ASTWriterStmt.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
    clang/test/ParserOpenACC/parse-clauses.c
    clang/test/ParserOpenACC/parse-constructs.c
    clang/test/SemaOpenACC/combined-construct-async-clause.cpp
    clang/test/SemaOpenACC/combined-construct-wait-clause.cpp
    clang/test/SemaOpenACC/compute-construct-async-clause.cpp
    clang/test/SemaOpenACC/compute-construct-num_gangs-clause.cpp
    clang/test/SemaOpenACC/compute-construct-num_workers-clause.cpp
    clang/test/SemaOpenACC/compute-construct-private-clause.c
    clang/test/SemaOpenACC/compute-construct-reduction-clause.c
    clang/test/SemaOpenACC/compute-construct-vector_length-clause.cpp
    clang/test/SemaOpenACC/compute-construct-wait-clause.cpp
    clang/test/SemaOpenACC/wait-construct.cpp
    clang/tools/libclang/CIndex.cpp
    clang/tools/libclang/CXCursor.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 122118b8f37638..dfc562da88afee 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -2190,7 +2190,15 @@ enum CXCursorKind {
    */
   CXCursor_OpenACCWaitConstruct = 327,
 
-  CXCursor_LastStmt = CXCursor_OpenACCWaitConstruct,
+  /** OpenACC init Construct.
+   */
+  CXCursor_OpenACCInitConstruct = 328,
+
+  /** OpenACC shutdown Construct.
+   */
+  CXCursor_OpenACCShutdownConstruct = 329,
+
+  CXCursor_LastStmt = CXCursor_OpenACCShutdownConstruct,
 
   /**
    * Cursor that represents the translation unit itself.

diff  --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index d9a87b30062df8..f5b32ed51698e0 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -4076,6 +4076,10 @@ DEF_TRAVERSE_STMT(OpenACCWaitConstruct, {
     TRY_TO(TraverseStmt(E));
   TRY_TO(VisitOpenACCClauseList(S->clauses()));
 })
+DEF_TRAVERSE_STMT(OpenACCInitConstruct,
+                  { TRY_TO(VisitOpenACCClauseList(S->clauses())); })
+DEF_TRAVERSE_STMT(OpenACCShutdownConstruct,
+                  { TRY_TO(VisitOpenACCClauseList(S->clauses())); })
 
 // Traverse HLSL: Out argument expression
 DEF_TRAVERSE_STMT(HLSLOutArgExpr, {})

diff  --git a/clang/include/clang/AST/StmtOpenACC.h b/clang/include/clang/AST/StmtOpenACC.h
index 093393a81be9c7..e311eded5599bb 100644
--- a/clang/include/clang/AST/StmtOpenACC.h
+++ b/clang/include/clang/AST/StmtOpenACC.h
@@ -592,5 +592,85 @@ class OpenACCWaitConstruct final
     return const_child_range(Begin, Begin + NumExprs);
   }
 };
+
+// This class represents an 'init' construct, which has just a clause list.
+class OpenACCInitConstruct final
+    : public OpenACCConstructStmt,
+      private llvm::TrailingObjects<OpenACCInitConstruct,
+                                    const OpenACCClause *> {
+  friend TrailingObjects;
+  OpenACCInitConstruct(unsigned NumClauses)
+      : OpenACCConstructStmt(OpenACCInitConstructClass,
+                             OpenACCDirectiveKind::Init, SourceLocation{},
+                             SourceLocation{}, SourceLocation{}) {
+    std::uninitialized_value_construct(
+        getTrailingObjects<const OpenACCClause *>(),
+        getTrailingObjects<const OpenACCClause *>() + NumClauses);
+    setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
+                                  NumClauses));
+  }
+  OpenACCInitConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
+                       SourceLocation End,
+                       ArrayRef<const OpenACCClause *> Clauses)
+      : OpenACCConstructStmt(OpenACCInitConstructClass,
+                             OpenACCDirectiveKind::Init, Start, DirectiveLoc,
+                             End) {
+    std::uninitialized_copy(Clauses.begin(), Clauses.end(),
+                            getTrailingObjects<const OpenACCClause *>());
+    setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
+                                  Clauses.size()));
+  }
+
+public:
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == OpenACCInitConstructClass;
+  }
+  static OpenACCInitConstruct *CreateEmpty(const ASTContext &C,
+                                           unsigned NumClauses);
+  static OpenACCInitConstruct *Create(const ASTContext &C, SourceLocation Start,
+                                      SourceLocation DirectiveLoc,
+                                      SourceLocation End,
+                                      ArrayRef<const OpenACCClause *> Clauses);
+};
+
+// This class represents a 'shutdown' construct, which has just a clause list.
+class OpenACCShutdownConstruct final
+    : public OpenACCConstructStmt,
+      private llvm::TrailingObjects<OpenACCShutdownConstruct,
+                                    const OpenACCClause *> {
+  friend TrailingObjects;
+  OpenACCShutdownConstruct(unsigned NumClauses)
+      : OpenACCConstructStmt(OpenACCShutdownConstructClass,
+                             OpenACCDirectiveKind::Shutdown, SourceLocation{},
+                             SourceLocation{}, SourceLocation{}) {
+    std::uninitialized_value_construct(
+        getTrailingObjects<const OpenACCClause *>(),
+        getTrailingObjects<const OpenACCClause *>() + NumClauses);
+    setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
+                                  NumClauses));
+  }
+  OpenACCShutdownConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
+                           SourceLocation End,
+                           ArrayRef<const OpenACCClause *> Clauses)
+      : OpenACCConstructStmt(OpenACCShutdownConstructClass,
+                             OpenACCDirectiveKind::Shutdown, Start,
+                             DirectiveLoc, End) {
+    std::uninitialized_copy(Clauses.begin(), Clauses.end(),
+                            getTrailingObjects<const OpenACCClause *>());
+    setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
+                                  Clauses.size()));
+  }
+
+public:
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == OpenACCShutdownConstructClass;
+  }
+  static OpenACCShutdownConstruct *CreateEmpty(const ASTContext &C,
+                                               unsigned NumClauses);
+  static OpenACCShutdownConstruct *
+  Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
+         SourceLocation End, ArrayRef<const OpenACCClause *> Clauses);
+};
+
 } // namespace clang
 #endif // LLVM_CLANG_AST_STMTOPENACC_H

diff  --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h
index b6f16be7a5b98f..5383b53fdc491b 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -416,6 +416,8 @@ class TextNodeDumper
   void VisitOpenACCExitDataConstruct(const OpenACCExitDataConstruct *S);
   void VisitOpenACCHostDataConstruct(const OpenACCHostDataConstruct *S);
   void VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S);
+  void VisitOpenACCInitConstruct(const OpenACCInitConstruct *S);
+  void VisitOpenACCShutdownConstruct(const OpenACCShutdownConstruct *S);
   void VisitOpenACCAsteriskSizeExpr(const OpenACCAsteriskSizeExpr *S);
   void VisitEmbedExpr(const EmbedExpr *S);
   void VisitAtomicExpr(const AtomicExpr *AE);

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index de34bcbf9ad4a6..8d19e9030ac2e3 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12669,8 +12669,8 @@ def err_acc_int_expr_requires_integer
 def err_acc_int_expr_incomplete_class_type
     : Error<"OpenACC integer expression has incomplete class type %0">;
 def err_acc_int_expr_explicit_conversion
-    : Error<"OpenACC integer expression type %0 requires explicit conversion "
-            "to %1">;
+    : Error<"OpenACC integer expression requires explicit conversion "
+            "from %0 to %1">;
 def note_acc_int_expr_conversion
     : Note<"conversion to %select{integral|enumeration}0 type %1">;
 def err_acc_int_expr_multiple_conversions

diff  --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index 6c7314b06d858a..31280df93e4c6e 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -313,6 +313,8 @@ def OpenACCEnterDataConstruct : StmtNode<OpenACCConstructStmt>;
 def OpenACCExitDataConstruct : StmtNode<OpenACCConstructStmt>;
 def OpenACCHostDataConstruct : StmtNode<OpenACCAssociatedStmtConstruct>;
 def OpenACCWaitConstruct : StmtNode<OpenACCConstructStmt>;
+def OpenACCInitConstruct : StmtNode<OpenACCConstructStmt>;
+def OpenACCShutdownConstruct : StmtNode<OpenACCConstructStmt>;
 
 // OpenACC Additional Expressions.
 def OpenACCAsteriskSizeExpr : StmtNode<Expr>;

diff  --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 57e27c373bffa1..dfd82afad40070 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -2022,6 +2022,8 @@ enum StmtCode {
   STMT_OPENACC_EXIT_DATA_CONSTRUCT,
   STMT_OPENACC_HOST_DATA_CONSTRUCT,
   STMT_OPENACC_WAIT_CONSTRUCT,
+  STMT_OPENACC_INIT_CONSTRUCT,
+  STMT_OPENACC_SHUTDOWN_CONSTRUCT,
 
   // HLSL Constructs
   EXPR_HLSL_OUT_ARG,

diff  --git a/clang/lib/AST/StmtOpenACC.cpp b/clang/lib/AST/StmtOpenACC.cpp
index 6d9f267702e37d..e6d76ea30f0294 100644
--- a/clang/lib/AST/StmtOpenACC.cpp
+++ b/clang/lib/AST/StmtOpenACC.cpp
@@ -225,3 +225,43 @@ OpenACCWaitConstruct *OpenACCWaitConstruct::Create(
                            QueuesLoc, QueueIdExprs, RParenLoc, End, Clauses);
   return Inst;
 }
+OpenACCInitConstruct *OpenACCInitConstruct::CreateEmpty(const ASTContext &C,
+                                                        unsigned NumClauses) {
+  void *Mem =
+      C.Allocate(OpenACCInitConstruct::totalSizeToAlloc<const OpenACCClause *>(
+          NumClauses));
+  auto *Inst = new (Mem) OpenACCInitConstruct(NumClauses);
+  return Inst;
+}
+
+OpenACCInitConstruct *
+OpenACCInitConstruct::Create(const ASTContext &C, SourceLocation Start,
+                             SourceLocation DirectiveLoc, SourceLocation End,
+                             ArrayRef<const OpenACCClause *> Clauses) {
+  void *Mem =
+      C.Allocate(OpenACCInitConstruct::totalSizeToAlloc<const OpenACCClause *>(
+          Clauses.size()));
+  auto *Inst =
+      new (Mem) OpenACCInitConstruct(Start, DirectiveLoc, End, Clauses);
+  return Inst;
+}
+OpenACCShutdownConstruct *
+OpenACCShutdownConstruct::CreateEmpty(const ASTContext &C,
+                                      unsigned NumClauses) {
+  void *Mem = C.Allocate(
+      OpenACCShutdownConstruct::totalSizeToAlloc<const OpenACCClause *>(
+          NumClauses));
+  auto *Inst = new (Mem) OpenACCShutdownConstruct(NumClauses);
+  return Inst;
+}
+
+OpenACCShutdownConstruct *OpenACCShutdownConstruct::Create(
+    const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
+    SourceLocation End, ArrayRef<const OpenACCClause *> Clauses) {
+  void *Mem = C.Allocate(
+      OpenACCShutdownConstruct::totalSizeToAlloc<const OpenACCClause *>(
+          Clauses.size()));
+  auto *Inst =
+      new (Mem) OpenACCShutdownConstruct(Start, DirectiveLoc, End, Clauses);
+  return Inst;
+}

diff  --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index ecc9b6e35db72d..c5d19f70fc6ea0 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -127,6 +127,8 @@ namespace {
     void PrintOMPExecutableDirective(OMPExecutableDirective *S,
                                      bool ForceNoStmt = false);
     void PrintFPPragmas(CompoundStmt *S);
+    void PrintOpenACCClauseList(OpenACCConstructStmt *S);
+    void PrintOpenACCConstruct(OpenACCConstructStmt *S);
 
     void PrintExpr(Expr *E) {
       if (E)
@@ -1155,87 +1157,52 @@ void StmtPrinter::VisitOMPTargetParallelGenericLoopDirective(
 //===----------------------------------------------------------------------===//
 //  OpenACC construct printing methods
 //===----------------------------------------------------------------------===//
-void StmtPrinter::VisitOpenACCComputeConstruct(OpenACCComputeConstruct *S) {
-  Indent() << "#pragma acc " << S->getDirectiveKind();
-
+void StmtPrinter::PrintOpenACCClauseList(OpenACCConstructStmt *S) {
   if (!S->clauses().empty()) {
     OS << ' ';
     OpenACCClausePrinter Printer(OS, Policy);
     Printer.VisitClauseList(S->clauses());
   }
+}
+void StmtPrinter::PrintOpenACCConstruct(OpenACCConstructStmt *S) {
+  Indent() << "#pragma acc " << S->getDirectiveKind();
+  PrintOpenACCClauseList(S);
   OS << '\n';
-
+}
+void StmtPrinter::VisitOpenACCComputeConstruct(OpenACCComputeConstruct *S) {
+  PrintOpenACCConstruct(S);
   PrintStmt(S->getStructuredBlock());
 }
 
 void StmtPrinter::VisitOpenACCLoopConstruct(OpenACCLoopConstruct *S) {
-  Indent() << "#pragma acc loop";
-
-  if (!S->clauses().empty()) {
-    OS << ' ';
-    OpenACCClausePrinter Printer(OS, Policy);
-    Printer.VisitClauseList(S->clauses());
-  }
-  OS << '\n';
-
+  PrintOpenACCConstruct(S);
   PrintStmt(S->getLoop());
 }
 
 void StmtPrinter::VisitOpenACCCombinedConstruct(OpenACCCombinedConstruct *S) {
-  Indent() << "#pragma acc " << S->getDirectiveKind();
-  if (!S->clauses().empty()) {
-    OS << ' ';
-    OpenACCClausePrinter Printer(OS, Policy);
-    Printer.VisitClauseList(S->clauses());
-  }
-  OS << '\n';
-
+  PrintOpenACCConstruct(S);
   PrintStmt(S->getLoop());
 }
 
 void StmtPrinter::VisitOpenACCDataConstruct(OpenACCDataConstruct *S) {
-  Indent() << "#pragma acc data";
-
-  if (!S->clauses().empty()) {
-    OS << ' ';
-    OpenACCClausePrinter Printer(OS, Policy);
-    Printer.VisitClauseList(S->clauses());
-  }
-  OS << '\n';
-
+  PrintOpenACCConstruct(S);
+  PrintStmt(S->getStructuredBlock());
+}
+void StmtPrinter::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) {
+  PrintOpenACCConstruct(S);
   PrintStmt(S->getStructuredBlock());
 }
 void StmtPrinter::VisitOpenACCEnterDataConstruct(OpenACCEnterDataConstruct *S) {
-  Indent() << "#pragma acc enter data";
-
-  if (!S->clauses().empty()) {
-    OS << ' ';
-    OpenACCClausePrinter Printer(OS, Policy);
-    Printer.VisitClauseList(S->clauses());
-  }
-  OS << '\n';
+  PrintOpenACCConstruct(S);
 }
 void StmtPrinter::VisitOpenACCExitDataConstruct(OpenACCExitDataConstruct *S) {
-  Indent() << "#pragma acc exit data";
-
-  if (!S->clauses().empty()) {
-    OS << ' ';
-    OpenACCClausePrinter Printer(OS, Policy);
-    Printer.VisitClauseList(S->clauses());
-  }
-  OS << '\n';
+  PrintOpenACCConstruct(S);
 }
-void StmtPrinter::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) {
-  Indent() << "#pragma acc host_data";
-
-  if (!S->clauses().empty()) {
-    OS << ' ';
-    OpenACCClausePrinter Printer(OS, Policy);
-    Printer.VisitClauseList(S->clauses());
-  }
-  OS << '\n';
-
-  PrintStmt(S->getStructuredBlock());
+void StmtPrinter::VisitOpenACCInitConstruct(OpenACCInitConstruct *S) {
+  PrintOpenACCConstruct(S);
+}
+void StmtPrinter::VisitOpenACCShutdownConstruct(OpenACCShutdownConstruct *S) {
+  PrintOpenACCConstruct(S);
 }
 
 void StmtPrinter::VisitOpenACCWaitConstruct(OpenACCWaitConstruct *S) {
@@ -1258,11 +1225,7 @@ void StmtPrinter::VisitOpenACCWaitConstruct(OpenACCWaitConstruct *S) {
     OS << ")";
   }
 
-  if (!S->clauses().empty()) {
-    OS << ' ';
-    OpenACCClausePrinter Printer(OS, Policy);
-    Printer.VisitClauseList(S->clauses());
-  }
+  PrintOpenACCClauseList(S);
   OS << '\n';
 }
 

diff  --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index fccd97dca23af2..4c4ecd791c48f2 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2751,6 +2751,19 @@ void StmtProfiler::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S) {
   P.VisitOpenACCClauseList(S->clauses());
 }
 
+void StmtProfiler::VisitOpenACCInitConstruct(const OpenACCInitConstruct *S) {
+  VisitStmt(S);
+  OpenACCClauseProfiler P{*this};
+  P.VisitOpenACCClauseList(S->clauses());
+}
+
+void StmtProfiler::VisitOpenACCShutdownConstruct(
+    const OpenACCShutdownConstruct *S) {
+  VisitStmt(S);
+  OpenACCClauseProfiler P{*this};
+  P.VisitOpenACCClauseList(S->clauses());
+}
+
 void StmtProfiler::VisitHLSLOutArgExpr(const HLSLOutArgExpr *S) {
   VisitStmt(S);
 }

diff  --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 7cdffbe20e575a..f9cbdf6916dcb1 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -2963,6 +2963,13 @@ void TextNodeDumper::VisitOpenACCHostDataConstruct(
 void TextNodeDumper::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S) {
   OS << " " << S->getDirectiveKind();
 }
+void TextNodeDumper::VisitOpenACCInitConstruct(const OpenACCInitConstruct *S) {
+  OS << " " << S->getDirectiveKind();
+}
+void TextNodeDumper::VisitOpenACCShutdownConstruct(
+    const OpenACCShutdownConstruct *S) {
+  OS << " " << S->getDirectiveKind();
+}
 
 void TextNodeDumper::VisitEmbedExpr(const EmbedExpr *S) {
   AddChild("begin", [=] { OS << S->getStartingElementPos(); });

diff  --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 6c604f44e283be..3974739d2abb47 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -473,6 +473,12 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
   case Stmt::OpenACCWaitConstructClass:
     EmitOpenACCWaitConstruct(cast<OpenACCWaitConstruct>(*S));
     break;
+  case Stmt::OpenACCInitConstructClass:
+    EmitOpenACCInitConstruct(cast<OpenACCInitConstruct>(*S));
+    break;
+  case Stmt::OpenACCShutdownConstructClass:
+    EmitOpenACCShutdownConstruct(cast<OpenACCShutdownConstruct>(*S));
+    break;
   }
 }
 

diff  --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 4d4139180e100f..1a5c42f8f974d0 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4123,6 +4123,16 @@ class CodeGenFunction : public CodeGenTypeCache {
     // but in the future we will implement some sort of IR.
   }
 
+  void EmitOpenACCInitConstruct(const OpenACCInitConstruct &S) {
+    // TODO OpenACC: Implement this.  It is currently implemented as a 'no-op',
+    // but in the future we will implement some sort of IR.
+  }
+
+  void EmitOpenACCShutdownConstruct(const OpenACCShutdownConstruct &S) {
+    // TODO OpenACC: Implement this.  It is currently implemented as a 'no-op',
+    // but in the future we will implement some sort of IR.
+  }
+
   //===--------------------------------------------------------------------===//
   //                         LValue Expression Emission
   //===--------------------------------------------------------------------===//

diff  --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index 5da34a2f5db923..31ec0c7c1d718d 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -574,6 +574,8 @@ bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) {
   case OpenACCDirectiveKind::EnterData:
   case OpenACCDirectiveKind::ExitData:
   case OpenACCDirectiveKind::Wait:
+  case OpenACCDirectiveKind::Init:
+  case OpenACCDirectiveKind::Shutdown:
     return false;
   case OpenACCDirectiveKind::Parallel:
   case OpenACCDirectiveKind::Serial:
@@ -606,6 +608,8 @@ unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) {
   case OpenACCDirectiveKind::ExitData:
   case OpenACCDirectiveKind::HostData:
   case OpenACCDirectiveKind::Wait:
+  case OpenACCDirectiveKind::Init:
+  case OpenACCDirectiveKind::Shutdown:
     return 0;
   case OpenACCDirectiveKind::Invalid:
     llvm_unreachable("Shouldn't be creating a scope for an invalid construct");

diff  --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 505cc5e153fa70..ac3666394d0e86 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1399,6 +1399,8 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
   case Stmt::OpenACCEnterDataConstructClass:
   case Stmt::OpenACCExitDataConstructClass:
   case Stmt::OpenACCWaitConstructClass:
+  case Stmt::OpenACCInitConstructClass:
+  case Stmt::OpenACCShutdownConstructClass:
     // These expressions can never throw.
     return CT_Cannot;
 

diff  --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index aa9097bfa17436..618c0f62576402 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -574,7 +574,9 @@ bool checkValidAfterDeviceType(
 bool isDirectiveKindImplemented(OpenACCDirectiveKind DK) {
   return isOpenACCComputeDirectiveKind(DK) ||
          isOpenACCCombinedDirectiveKind(DK) || isOpenACCDataDirectiveKind(DK) ||
-         DK == OpenACCDirectiveKind::Loop || DK == OpenACCDirectiveKind::Wait;
+         DK == OpenACCDirectiveKind::Loop || DK == OpenACCDirectiveKind::Wait ||
+         DK == OpenACCDirectiveKind::Init ||
+         DK == OpenACCDirectiveKind::Shutdown;
 }
 
 class SemaOpenACCClauseVisitor {
@@ -699,7 +701,10 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitIfClause(
   // sense. Prose DOES exist for 'data' and 'host_data', 'enter data' and 'exit
   // data' both don't, but other implmementations do this.  OpenACC issue 519
   // filed for the latter two.
-  if (checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause))
+  // GCC allows this on init/shutdown, presumably for good reason, so we do too.
+  if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Init &&
+      Clause.getDirectiveKind() != OpenACCDirectiveKind::Shutdown &&
+      checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause))
     return nullptr;
 
   // The parser has ensured that we have a proper condition expr, so there
@@ -1868,6 +1873,8 @@ bool PreserveLoopRAIIDepthInAssociatedStmtRAII(OpenACCDirectiveKind DK) {
   case OpenACCDirectiveKind::EnterData:
   case OpenACCDirectiveKind::ExitData:
   case OpenACCDirectiveKind::Wait:
+  case OpenACCDirectiveKind::Init:
+  case OpenACCDirectiveKind::Shutdown:
     llvm_unreachable("Doesn't have an associated stmt");
   default:
   case OpenACCDirectiveKind::Invalid:
@@ -2294,6 +2301,8 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K,
   case OpenACCDirectiveKind::EnterData:
   case OpenACCDirectiveKind::ExitData:
   case OpenACCDirectiveKind::HostData:
+  case OpenACCDirectiveKind::Init:
+  case OpenACCDirectiveKind::Shutdown:
     // Nothing to do here, there is no real legalization that needs to happen
     // here as these constructs do not take any arguments.
     break;
@@ -3682,6 +3691,14 @@ StmtResult SemaOpenACC::ActOnEndStmtDirective(
         getASTContext(), StartLoc, DirLoc, LParenLoc, Exprs.front(), MiscLoc,
         Exprs.drop_front(), RParenLoc, EndLoc, Clauses);
   }
+  case OpenACCDirectiveKind::Init: {
+    return OpenACCInitConstruct::Create(getASTContext(), StartLoc, DirLoc,
+                                        EndLoc, Clauses);
+  }
+  case OpenACCDirectiveKind::Shutdown: {
+    return OpenACCShutdownConstruct::Create(getASTContext(), StartLoc, DirLoc,
+                                            EndLoc, Clauses);
+  }
   }
   llvm_unreachable("Unhandled case in directive handling?");
 }
@@ -3695,6 +3712,8 @@ StmtResult SemaOpenACC::ActOnAssociatedStmt(
   case OpenACCDirectiveKind::EnterData:
   case OpenACCDirectiveKind::ExitData:
   case OpenACCDirectiveKind::Wait:
+  case OpenACCDirectiveKind::Init:
+  case OpenACCDirectiveKind::Shutdown:
     llvm_unreachable(
         "these don't have associated statements, so shouldn't get here");
   case OpenACCDirectiveKind::Parallel:

diff  --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index c097465374cba8..686132dbc5f5d4 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4151,6 +4151,24 @@ class TreeTransform {
         SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, StrBlock);
   }
 
+  StmtResult RebuildOpenACCInitConstruct(SourceLocation BeginLoc,
+                                         SourceLocation DirLoc,
+                                         SourceLocation EndLoc,
+                                         ArrayRef<OpenACCClause *> Clauses) {
+    return getSema().OpenACC().ActOnEndStmtDirective(
+        OpenACCDirectiveKind::Init, BeginLoc, DirLoc, SourceLocation{},
+        SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {});
+  }
+
+  StmtResult
+  RebuildOpenACCShutdownConstruct(SourceLocation BeginLoc,
+                                  SourceLocation DirLoc, SourceLocation EndLoc,
+                                  ArrayRef<OpenACCClause *> Clauses) {
+    return getSema().OpenACC().ActOnEndStmtDirective(
+        OpenACCDirectiveKind::Shutdown, BeginLoc, DirLoc, SourceLocation{},
+        SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {});
+  }
+
   StmtResult RebuildOpenACCWaitConstruct(
       SourceLocation BeginLoc, SourceLocation DirLoc, SourceLocation LParenLoc,
       Expr *DevNumExpr, SourceLocation QueuesLoc, ArrayRef<Expr *> QueueIdExprs,
@@ -12348,6 +12366,40 @@ StmtResult TreeTransform<Derived>::TransformOpenACCHostDataConstruct(
       TransformedClauses, StrBlock);
 }
 
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOpenACCInitConstruct(OpenACCInitConstruct *C) {
+  getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc());
+
+  llvm::SmallVector<OpenACCClause *> TransformedClauses =
+      getDerived().TransformOpenACCClauseList(C->getDirectiveKind(),
+                                              C->clauses());
+  if (getSema().OpenACC().ActOnStartStmtDirective(
+          C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses))
+    return StmtError();
+
+  return getDerived().RebuildOpenACCInitConstruct(
+      C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(),
+      TransformedClauses);
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOpenACCShutdownConstruct(
+    OpenACCShutdownConstruct *C) {
+  getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc());
+
+  llvm::SmallVector<OpenACCClause *> TransformedClauses =
+      getDerived().TransformOpenACCClauseList(C->getDirectiveKind(),
+                                              C->clauses());
+  if (getSema().OpenACC().ActOnStartStmtDirective(
+          C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses))
+    return StmtError();
+
+  return getDerived().RebuildOpenACCShutdownConstruct(
+      C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(),
+      TransformedClauses);
+}
+
 template <typename Derived>
 StmtResult
 TreeTransform<Derived>::TransformOpenACCWaitConstruct(OpenACCWaitConstruct *C) {

diff  --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 8fe0412706ce3e..9e8cf19a6f0f72 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2865,6 +2865,16 @@ void ASTStmtReader::VisitOpenACCExitDataConstruct(OpenACCExitDataConstruct *S) {
   VisitOpenACCConstructStmt(S);
 }
 
+void ASTStmtReader::VisitOpenACCInitConstruct(OpenACCInitConstruct *S) {
+  VisitStmt(S);
+  VisitOpenACCConstructStmt(S);
+}
+
+void ASTStmtReader::VisitOpenACCShutdownConstruct(OpenACCShutdownConstruct *S) {
+  VisitStmt(S);
+  VisitOpenACCConstructStmt(S);
+}
+
 void ASTStmtReader::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) {
   VisitStmt(S);
   VisitOpenACCAssociatedStmtConstruct(S);
@@ -4387,6 +4397,16 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
       S = OpenACCWaitConstruct::CreateEmpty(Context, NumExprs, NumClauses);
       break;
     }
+    case STMT_OPENACC_INIT_CONSTRUCT: {
+      unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+      S = OpenACCInitConstruct::CreateEmpty(Context, NumClauses);
+      break;
+    }
+    case STMT_OPENACC_SHUTDOWN_CONSTRUCT: {
+      unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+      S = OpenACCShutdownConstruct::CreateEmpty(Context, NumClauses);
+      break;
+    }
     case EXPR_REQUIRES: {
       unsigned numLocalParameters = Record[ASTStmtReader::NumExprFields];
       unsigned numRequirement = Record[ASTStmtReader::NumExprFields + 1];

diff  --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index f13443d18b612a..1d42b43c3e2ca0 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2945,6 +2945,18 @@ void ASTStmtWriter::VisitOpenACCExitDataConstruct(OpenACCExitDataConstruct *S) {
   Code = serialization::STMT_OPENACC_EXIT_DATA_CONSTRUCT;
 }
 
+void ASTStmtWriter::VisitOpenACCInitConstruct(OpenACCInitConstruct *S) {
+  VisitStmt(S);
+  VisitOpenACCConstructStmt(S);
+  Code = serialization::STMT_OPENACC_INIT_CONSTRUCT;
+}
+
+void ASTStmtWriter::VisitOpenACCShutdownConstruct(OpenACCShutdownConstruct *S) {
+  VisitStmt(S);
+  VisitOpenACCConstructStmt(S);
+  Code = serialization::STMT_OPENACC_SHUTDOWN_CONSTRUCT;
+}
+
 void ASTStmtWriter::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) {
   VisitStmt(S);
   VisitOpenACCAssociatedStmtConstruct(S);

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 0a74a80a6a62f9..db385e891e762f 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1830,6 +1830,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::OpenACCExitDataConstructClass:
     case Stmt::OpenACCHostDataConstructClass:
     case Stmt::OpenACCWaitConstructClass:
+    case Stmt::OpenACCInitConstructClass:
+    case Stmt::OpenACCShutdownConstructClass:
     case Stmt::OMPUnrollDirectiveClass:
     case Stmt::OMPMetaDirectiveClass:
     case Stmt::HLSLOutArgExprClass: {

diff  --git a/clang/test/AST/ast-print-openacc-init-construct.cpp b/clang/test/AST/ast-print-openacc-init-construct.cpp
new file mode 100644
index 00000000000000..8bee2d84118f55
--- /dev/null
+++ b/clang/test/AST/ast-print-openacc-init-construct.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fopenacc -ast-print %s -o - | FileCheck %s
+
+unsigned Int;
+
+void uses() {
+// CHECK: #pragma acc init device_type(*) if(Int == 5)
+#pragma acc init device_type(*) device_num(Int) if (Int == 5)
+// CHECK: #pragma acc init device_type(*)
+// CHECK-NOT: device_num(Int)
+#pragma acc init device_type(*) device_num(Int)
+// CHECK: #pragma acc init device_type(*) if(Int == 5)
+#pragma acc init device_type(*) if (Int == 5)
+// CHECK: #pragma acc init device_type(SomeName)
+#pragma acc init device_type(SomeName)
+}

diff  --git a/clang/test/AST/ast-print-openacc-shutdown-construct.cpp b/clang/test/AST/ast-print-openacc-shutdown-construct.cpp
new file mode 100644
index 00000000000000..c1da69dd82a237
--- /dev/null
+++ b/clang/test/AST/ast-print-openacc-shutdown-construct.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fopenacc -ast-print %s -o - | FileCheck %s
+
+unsigned Int;
+
+void uses() {
+// CHECK: #pragma acc shutdown device_type(*) if(Int == 5)
+#pragma acc shutdown device_type(*) device_num(Int) if (Int == 5)
+// CHECK: #pragma acc shutdown device_type(*)
+// CHECK-NOT: device_num(Int)
+#pragma acc shutdown device_type(*) device_num(Int)
+// CHECK: #pragma acc shutdown device_type(*) if(Int == 5)
+#pragma acc shutdown device_type(*) if (Int == 5)
+// CHECK: #pragma acc shutdown device_type(SomeName)
+#pragma acc shutdown device_type(SomeName)
+}

diff  --git a/clang/test/ParserOpenACC/parse-clauses.c b/clang/test/ParserOpenACC/parse-clauses.c
index 2e884c472c2ec1..7bd8edcee3db84 100644
--- a/clang/test/ParserOpenACC/parse-clauses.c
+++ b/clang/test/ParserOpenACC/parse-clauses.c
@@ -803,29 +803,23 @@ void IntExprParsing() {
 #pragma acc parallel num_workers(returns_int())
   {}
 
-  // expected-error at +2{{expected '('}}
-  // expected-warning at +1{{OpenACC construct 'init' not yet implemented, pragma ignored}}
+  // expected-error at +1{{expected '('}}
 #pragma acc init device_num
 
-  // expected-error at +2{{expected expression}}
-  // expected-warning at +1{{OpenACC construct 'init' not yet implemented, pragma ignored}}
+  // expected-error at +1{{expected expression}}
 #pragma acc init device_num()
 
-  // expected-error at +2{{use of undeclared identifier 'invalid'}}
-  // expected-warning at +1{{OpenACC construct 'init' not yet implemented, pragma ignored}}
+  // expected-error at +1{{use of undeclared identifier 'invalid'}}
 #pragma acc init device_num(invalid)
 
-  // expected-error at +3{{expected ')'}}
-  // expected-note at +2{{to match this '('}}
-  // expected-warning at +1{{OpenACC construct 'init' not yet implemented, pragma ignored}}
+  // expected-error at +2{{expected ')'}}
+  // expected-note at +1{{to match this '('}}
 #pragma acc init device_num(5, 4)
 
-  // expected-warning at +2{{OpenACC clause 'device_num' not yet implemented, clause ignored}}
-  // expected-warning at +1{{OpenACC construct 'init' not yet implemented, pragma ignored}}
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented, clause ignored}}
 #pragma acc init device_num(5)
 
-  // expected-warning at +2{{OpenACC clause 'device_num' not yet implemented, clause ignored}}
-  // expected-warning at +1{{OpenACC construct 'init' not yet implemented, pragma ignored}}
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented, clause ignored}}
 #pragma acc init device_num(returns_int())
 
   // expected-error at +2{{expected '('}}

diff  --git a/clang/test/ParserOpenACC/parse-constructs.c b/clang/test/ParserOpenACC/parse-constructs.c
index 4a6c31cc9b0a9d..878c38e8bedc72 100644
--- a/clang/test/ParserOpenACC/parse-constructs.c
+++ b/clang/test/ParserOpenACC/parse-constructs.c
@@ -141,12 +141,10 @@ void func() {
   // expected-warning at +1{{OpenACC construct 'declare' not yet implemented, pragma ignored}}
 #pragma acc declare clause list
   for(;;){}
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'init' not yet implemented, pragma ignored}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
 #pragma acc init clause list
   for(;;){}
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'shutdown' not yet implemented, pragma ignored}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
 #pragma acc shutdown clause list
   for(;;){}
   // expected-error at +2{{invalid OpenACC clause 'clause'}}

diff  --git a/clang/test/SemaOpenACC/combined-construct-async-clause.cpp b/clang/test/SemaOpenACC/combined-construct-async-clause.cpp
index 872586acbaffa2..c54f340cdfd964 100644
--- a/clang/test/SemaOpenACC/combined-construct-async-clause.cpp
+++ b/clang/test/SemaOpenACC/combined-construct-async-clause.cpp
@@ -48,7 +48,7 @@ void Test() {
 #pragma acc parallel loop async(Convert)
   for (int i = 5; i < 10; ++i);
 
-  // expected-error at +2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc kernels loop async(Explicit)
   for (int i = 5; i < 10; ++i);
@@ -94,12 +94,12 @@ void TestInst() {
 #pragma acc kernels loop async(T::ACValue)
   for (int i = 5; i < 10; ++i);
 
-  // expected-error at +2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc parallel loop async(HasInt::EXValue)
   for (int i = 5; i < 10; ++i);
 
-  // expected-error at +2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc kernels loop async(T::EXValue)
   for (int i = 5; i < 10; ++i);

diff  --git a/clang/test/SemaOpenACC/combined-construct-wait-clause.cpp b/clang/test/SemaOpenACC/combined-construct-wait-clause.cpp
index 9ce04290cbe5a7..e0411925e9f206 100644
--- a/clang/test/SemaOpenACC/combined-construct-wait-clause.cpp
+++ b/clang/test/SemaOpenACC/combined-construct-wait-clause.cpp
@@ -18,7 +18,7 @@ void Test() {
 #pragma acc parallel loop wait(Ambiguous)
   for (unsigned i = 0; i < 5; ++i);
 
-  // expected-error at +2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc parallel loop wait(4, Explicit, 5)
   for (unsigned i = 0; i < 5; ++i);
@@ -29,12 +29,12 @@ void Test() {
 #pragma acc parallel loop wait(queues: Ambiguous, 5)
   for (unsigned i = 0; i < 5; ++i);
 
-  // expected-error at +2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc parallel loop wait(devnum: Explicit: 5)
   for (unsigned i = 0; i < 5; ++i);
 
-  // expected-error at +2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc parallel loop wait(devnum: Explicit:queues:  5)
   for (unsigned i = 0; i < 5; ++i);
@@ -70,7 +70,7 @@ void TestInst() {
 #pragma acc parallel loop wait(devnum:T::value :queues:T::ACValue)
   for (unsigned i = 0; i < 5; ++i);
 
-  // expected-error at +5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +5{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
   // expected-error at +3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
   // expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
@@ -78,7 +78,7 @@ void TestInst() {
 #pragma acc parallel loop wait(devnum:T::EXValue :queues:T::ACValue)
   for (unsigned i = 0; i < 5; ++i);
 
-  // expected-error at +5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +5{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
   // expected-error at +3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
   // expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
@@ -86,7 +86,7 @@ void TestInst() {
 #pragma acc parallel loop wait(T::EXValue, T::ACValue)
   for (unsigned i = 0; i < 5; ++i);
 
-  // expected-error at +5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +5{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
   // expected-error at +3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
   // expected-note@#AMBIG_INT{{conversion to integral type 'int'}}

diff  --git a/clang/test/SemaOpenACC/compute-construct-async-clause.cpp b/clang/test/SemaOpenACC/compute-construct-async-clause.cpp
index a5da7c8f4e56ec..44b1540a934c29 100644
--- a/clang/test/SemaOpenACC/compute-construct-async-clause.cpp
+++ b/clang/test/SemaOpenACC/compute-construct-async-clause.cpp
@@ -46,7 +46,7 @@ void Test() {
 #pragma acc parallel async(Convert)
   while(1);
 
-  // expected-error at +2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc kernels async(Explicit)
   while(1);
@@ -92,12 +92,12 @@ void TestInst() {
 #pragma acc kernels async(T::ACValue)
   while (1);
 
-  // expected-error at +2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc parallel async(HasInt::EXValue)
   while (1);
 
-  // expected-error at +2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc kernels async(T::EXValue)
   while (1);

diff  --git a/clang/test/SemaOpenACC/compute-construct-num_gangs-clause.cpp b/clang/test/SemaOpenACC/compute-construct-num_gangs-clause.cpp
index c50f52afda7c1c..c6dbe4db2be647 100644
--- a/clang/test/SemaOpenACC/compute-construct-num_gangs-clause.cpp
+++ b/clang/test/SemaOpenACC/compute-construct-num_gangs-clause.cpp
@@ -74,20 +74,20 @@ void Test() {
 #pragma acc parallel num_gangs(SomeE, NC)
   while(1);
 
-  // expected-error at +3{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +3{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
   // expected-error at +1{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}}
 #pragma acc parallel num_gangs(Explicit, NC)
   while(1);
 
-  // expected-error at +4{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +4{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
   // expected-error at +2{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}}
   // expected-error at +1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}}
 #pragma acc serial num_gangs(Explicit, NC)
   while(1);
 
-  // expected-error at +6{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +6{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
   // expected-error at +4{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}}
   // expected-error at +3{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}}
@@ -96,7 +96,7 @@ void Test() {
 #pragma acc parallel num_gangs(Explicit, NC, Ambiguous)
   while(1);
 
-  // expected-error at +7{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +7{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
   // expected-error at +5{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}}
   // expected-error at +4{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}}

diff  --git a/clang/test/SemaOpenACC/compute-construct-num_workers-clause.cpp b/clang/test/SemaOpenACC/compute-construct-num_workers-clause.cpp
index 9449b77d092f4a..c73f421222e866 100644
--- a/clang/test/SemaOpenACC/compute-construct-num_workers-clause.cpp
+++ b/clang/test/SemaOpenACC/compute-construct-num_workers-clause.cpp
@@ -44,7 +44,7 @@ void Test() {
 #pragma acc parallel num_workers(Convert)
   while(1);
 
-  // expected-error at +2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc kernels num_workers(Explicit)
   while(1);
@@ -90,12 +90,12 @@ void TestInst() {
 #pragma acc kernels num_workers(T::ACValue)
   while (1);
 
-  // expected-error at +2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc parallel num_workers(HasInt::EXValue)
   while (1);
 
-  // expected-error at +2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc kernels num_workers(T::EXValue)
   while (1);

diff  --git a/clang/test/SemaOpenACC/compute-construct-private-clause.c b/clang/test/SemaOpenACC/compute-construct-private-clause.c
index d979fd909f11cf..a40d84c669d9ad 100644
--- a/clang/test/SemaOpenACC/compute-construct-private-clause.c
+++ b/clang/test/SemaOpenACC/compute-construct-private-clause.c
@@ -135,8 +135,7 @@ void uses(int IntParam, short *PointerParam, float ArrayParam[5], Complete Compo
 #pragma acc parallel private((float)ArrayParam[2])
   while(1);
 
-  // expected-error at +2{{OpenACC 'private' clause is not valid on 'init' directive}}
-  // expected-warning at +1{{OpenACC construct 'init' not yet implemented}}
+  // expected-error at +1{{OpenACC 'private' clause is not valid on 'init' directive}}
 #pragma acc init private(LocalInt)
   for(;;);
 }

diff  --git a/clang/test/SemaOpenACC/compute-construct-reduction-clause.c b/clang/test/SemaOpenACC/compute-construct-reduction-clause.c
index fcc4ca2655c20a..4d426cf189fca7 100644
--- a/clang/test/SemaOpenACC/compute-construct-reduction-clause.c
+++ b/clang/test/SemaOpenACC/compute-construct-reduction-clause.c
@@ -105,8 +105,7 @@ void uses(unsigned Parm) {
 #pragma acc parallel reduction(&:HA.array[1:2])
   while (1);
 
-  // expected-error at +2{{OpenACC 'reduction' clause is not valid on 'init' directive}}
-  // expected-warning at +1{{OpenACC construct 'init' not yet implemented}}
+  // expected-error at +1{{OpenACC 'reduction' clause is not valid on 'init' directive}}
 #pragma acc init reduction(+:I)
   for(;;);
 }

diff  --git a/clang/test/SemaOpenACC/compute-construct-vector_length-clause.cpp b/clang/test/SemaOpenACC/compute-construct-vector_length-clause.cpp
index f6c5dde1a02355..f2bbe0f022a07d 100644
--- a/clang/test/SemaOpenACC/compute-construct-vector_length-clause.cpp
+++ b/clang/test/SemaOpenACC/compute-construct-vector_length-clause.cpp
@@ -44,7 +44,7 @@ void Test() {
 #pragma acc parallel vector_length(Convert)
   while(1);
 
-  // expected-error at +2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc kernels vector_length(Explicit)
   while(1);
@@ -90,12 +90,12 @@ void TestInst() {
 #pragma acc kernels vector_length(T::ACValue)
   while (1);
 
-  // expected-error at +2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc parallel vector_length(HasInt::EXValue)
   while (1);
 
-  // expected-error at +2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc kernels vector_length(T::EXValue)
   while (1);

diff  --git a/clang/test/SemaOpenACC/compute-construct-wait-clause.cpp b/clang/test/SemaOpenACC/compute-construct-wait-clause.cpp
index 94f669be0f672d..fbe40ce5f31c15 100644
--- a/clang/test/SemaOpenACC/compute-construct-wait-clause.cpp
+++ b/clang/test/SemaOpenACC/compute-construct-wait-clause.cpp
@@ -18,7 +18,7 @@ void Test() {
 #pragma acc parallel wait(Ambiguous)
   while (true);
 
-  // expected-error at +2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc parallel wait(4, Explicit, 5)
   while (true);
@@ -29,12 +29,12 @@ void Test() {
 #pragma acc parallel wait(queues: Ambiguous, 5)
   while (true);
 
-  // expected-error at +2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc parallel wait(devnum: Explicit: 5)
   while (true);
 
-  // expected-error at +2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc parallel wait(devnum: Explicit:queues:  5)
   while (true);
@@ -70,7 +70,7 @@ void TestInst() {
 #pragma acc parallel wait(devnum:T::value :queues:T::ACValue)
   while (true);
 
-  // expected-error at +5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +5{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
   // expected-error at +3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
   // expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
@@ -78,7 +78,7 @@ void TestInst() {
 #pragma acc parallel wait(devnum:T::EXValue :queues:T::ACValue)
   while (true);
 
-  // expected-error at +5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +5{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
   // expected-error at +3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
   // expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
@@ -86,7 +86,7 @@ void TestInst() {
 #pragma acc parallel wait(T::EXValue, T::ACValue)
   while (true);
 
-  // expected-error at +5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +5{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
   // expected-error at +3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
   // expected-note@#AMBIG_INT{{conversion to integral type 'int'}}

diff  --git a/clang/test/SemaOpenACC/init-construct-ast.cpp b/clang/test/SemaOpenACC/init-construct-ast.cpp
new file mode 100644
index 00000000000000..793a4829d14b3f
--- /dev/null
+++ b/clang/test/SemaOpenACC/init-construct-ast.cpp
@@ -0,0 +1,125 @@
+// 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
+
+int some_int();
+long some_long();
+void NormalFunc() {
+  // CHECK-LABEL: NormalFunc
+  // CHECK-NEXT: CompoundStmt
+
+#pragma acc init
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+#pragma acc init if (some_int() < some_long())
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}} 'long'
+  // CHECK-NEXT: CallExpr
+  // CHECK-NEXT: ImplicitCastExpr
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()'
+  // CHECK-NEXT: CallExpr
+  // CHECK-NEXT: ImplicitCastExpr
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' 'long ()'
+#pragma acc init device_num(some_int())
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+#pragma acc init device_type(T)
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+  // CHECK-NEXT: device_type(T)
+#pragma acc init if (some_int() < some_long()) device_type(T) device_num(some_int())
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}} 'long'
+  // CHECK-NEXT: CallExpr
+  // CHECK-NEXT: ImplicitCastExpr
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()'
+  // CHECK-NEXT: CallExpr
+  // CHECK-NEXT: ImplicitCastExpr
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' 'long ()'
+  // CHECK-NEXT: device_type(T)
+}
+
+template<typename T>
+void TemplFunc(T t) {
+  // CHECK-LABEL: FunctionTemplateDecl {{.*}}TemplFunc
+  // CHECK-NEXT: TemplateTypeParmDecl
+  // CHECK-NEXT: FunctionDecl{{.*}}TemplFunc
+  // CHECK-NEXT: ParmVarDecl{{.*}} t 'T'
+  // CHECK-NEXT: CompoundStmt
+
+#pragma acc init
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+#pragma acc init if (T::value > t)
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} '<dependent type>' '>'
+  // CHECK-NEXT: DependentScopeDeclRefExpr
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T'
+  // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'T'
+#pragma acc init device_num(t)
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+#pragma acc init device_type(T)
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+  // CHECK-NEXT: device_type(T)
+#pragma acc init if (T::value > t) device_type(T) device_num(t)
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} '<dependent type>' '>'
+  // CHECK-NEXT: DependentScopeDeclRefExpr
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T'
+  // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'T'
+  // CHECK-NEXT: device_type(T)
+
+  // Instantiation:
+  // CHECK-NEXT: FunctionDecl{{.*}} TemplFunc 'void (SomeStruct)' implicit_instantiation
+  // CHECK-NEXT: TemplateArgument type 'SomeStruct'
+  // CHECK-NEXT: RecordType{{.*}} 'SomeStruct'
+  // CHECK-NEXT: CXXRecord{{.*}} 'SomeStruct'
+  // CHECK-NEXT: ParmVarDecl{{.*}} t 'SomeStruct'
+  // CHECK-NEXT: CompoundStmt
+
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '>'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int'
+  // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const unsigned int'
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'SomeStruct'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int'
+  // CHECK-NEXT: CXXMemberCallExpr{{.*}} 'unsigned int'
+  // CHECK-NEXT: MemberExpr{{.*}} .operator unsigned int
+  // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'SomeStruct'
+
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+  // CHECK-NEXT: device_type(T)
+
+  // CHECK-NEXT: OpenACCInitConstruct{{.*}}init
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '>'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int'
+  // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const unsigned int'
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'SomeStruct'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int'
+  // CHECK-NEXT: CXXMemberCallExpr{{.*}} 'unsigned int'
+  // CHECK-NEXT: MemberExpr{{.*}} .operator unsigned int
+  // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'SomeStruct'
+}
+
+struct SomeStruct{
+  static constexpr unsigned value = 5;
+  operator unsigned();
+};
+
+void use() {
+  TemplFunc(SomeStruct{});
+}
+#endif

diff  --git a/clang/test/SemaOpenACC/init-construct.cpp b/clang/test/SemaOpenACC/init-construct.cpp
new file mode 100644
index 00000000000000..152b27c0f3be1f
--- /dev/null
+++ b/clang/test/SemaOpenACC/init-construct.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 %s -fopenacc -verify
+
+struct NotConvertible{} NC;
+short getS();
+int getI();
+
+struct AmbiguousConvert{
+  operator int(); // #AMBIG_INT
+  operator short(); // #AMBIG_SHORT
+  operator float();
+} Ambiguous;
+
+struct ExplicitConvertOnly {
+  explicit operator int() const; // #EXPL_CONV
+} Explicit;
+
+void uses() {
+#pragma acc init
+#pragma acc init if (getI() < getS())
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc init device_num(getI())
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc init device_type(SOMETHING) device_num(getI())
+#pragma acc init device_type(SOMETHING) if (getI() < getS())
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc init device_type(SOMETHING) device_num(getI()) if (getI() < getS())
+
+  // expected-error at +1{{value of type 'struct NotConvertible' is not contextually convertible to 'bool'}}
+#pragma acc init if (NC)
+
+  // expected-error at +1{{OpenACC clause 'device_num' requires expression of integer type ('struct NotConvertible' invalid)}}
+#pragma acc init device_num(NC)
+  // expected-error at +3{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}}
+  // expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
+  // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
+#pragma acc init device_num(Ambiguous)
+  // expected-warning at +3{{OpenACC clause 'device_num' not yet implemented}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
+  // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
+#pragma acc init device_num(Explicit)
+}
+
+template<typename T>
+void TestInst() {
+  T t;
+#pragma acc init
+#pragma acc init if (T::value < T{})
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc init device_type(SOMETHING) device_num(getI()) if (getI() < getS())
+  // expected-warning at +1 2{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc init device_type(SOMETHING) device_type(T) device_num(t) if (t < T::value) device_num(getI()) if (getI() < getS())
+
+
+  // expected-error at +1{{value of type 'const NotConvertible' is not contextually convertible to 'bool'}}
+#pragma acc init if (T::NCValue)
+
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc init device_num(T::NCValue)
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc init device_num(T::ACValue)
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc init device_num(T::EXValue)
+}
+
+struct HasStuff {
+  static constexpr AmbiguousConvert ACValue;
+  static constexpr ExplicitConvertOnly EXValue;
+  static constexpr NotConvertible NCValue;
+  static constexpr unsigned value = 5;
+  operator char();
+};
+
+void Inst() {
+  TestInst<HasStuff>(); // expected-note {{in instantiation of function template specialization}}
+}

diff  --git a/clang/test/SemaOpenACC/shutdown-construct-ast.cpp b/clang/test/SemaOpenACC/shutdown-construct-ast.cpp
new file mode 100644
index 00000000000000..006f1c9e4c9968
--- /dev/null
+++ b/clang/test/SemaOpenACC/shutdown-construct-ast.cpp
@@ -0,0 +1,125 @@
+// 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
+
+int some_int();
+long some_long();
+void NormalFunc() {
+  // CHECK-LABEL: NormalFunc
+  // CHECK-NEXT: CompoundStmt
+
+#pragma acc shutdown
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+#pragma acc shutdown if (some_int() < some_long())
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}} 'long'
+  // CHECK-NEXT: CallExpr
+  // CHECK-NEXT: ImplicitCastExpr
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()'
+  // CHECK-NEXT: CallExpr
+  // CHECK-NEXT: ImplicitCastExpr
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' 'long ()'
+#pragma acc shutdown device_num(some_int())
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+#pragma acc shutdown device_type(T)
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+  // CHECK-NEXT: device_type(T)
+#pragma acc shutdown if (some_int() < some_long()) device_type(T) device_num(some_int())
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}} 'long'
+  // CHECK-NEXT: CallExpr
+  // CHECK-NEXT: ImplicitCastExpr
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()'
+  // CHECK-NEXT: CallExpr
+  // CHECK-NEXT: ImplicitCastExpr
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' 'long ()'
+  // CHECK-NEXT: device_type(T)
+}
+
+template<typename T>
+void TemplFunc(T t) {
+  // CHECK-LABEL: FunctionTemplateDecl {{.*}}TemplFunc
+  // CHECK-NEXT: TemplateTypeParmDecl
+  // CHECK-NEXT: FunctionDecl{{.*}}TemplFunc
+  // CHECK-NEXT: ParmVarDecl{{.*}} t 'T'
+  // CHECK-NEXT: CompoundStmt
+
+#pragma acc shutdown
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+#pragma acc shutdown if (T::value > t)
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} '<dependent type>' '>'
+  // CHECK-NEXT: DependentScopeDeclRefExpr
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T'
+  // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'T'
+#pragma acc shutdown device_num(t)
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+#pragma acc shutdown device_type(T)
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+  // CHECK-NEXT: device_type(T)
+#pragma acc shutdown if (T::value > t) device_type(T) device_num(t)
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} '<dependent type>' '>'
+  // CHECK-NEXT: DependentScopeDeclRefExpr
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T'
+  // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'T'
+  // CHECK-NEXT: device_type(T)
+
+  // Instantiation:
+  // CHECK-NEXT: FunctionDecl{{.*}} TemplFunc 'void (SomeStruct)' implicit_instantiation
+  // CHECK-NEXT: TemplateArgument type 'SomeStruct'
+  // CHECK-NEXT: RecordType{{.*}} 'SomeStruct'
+  // CHECK-NEXT: CXXRecord{{.*}} 'SomeStruct'
+  // CHECK-NEXT: ParmVarDecl{{.*}} t 'SomeStruct'
+  // CHECK-NEXT: CompoundStmt
+
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '>'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int'
+  // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const unsigned int'
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'SomeStruct'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int'
+  // CHECK-NEXT: CXXMemberCallExpr{{.*}} 'unsigned int'
+  // CHECK-NEXT: MemberExpr{{.*}} .operator unsigned int
+  // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'SomeStruct'
+
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+  // CHECK-NEXT: device_type(T)
+
+  // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '>'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int'
+  // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const unsigned int'
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'SomeStruct'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int'
+  // CHECK-NEXT: CXXMemberCallExpr{{.*}} 'unsigned int'
+  // CHECK-NEXT: MemberExpr{{.*}} .operator unsigned int
+  // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'SomeStruct'
+}
+
+struct SomeStruct{
+  static constexpr unsigned value = 5;
+  operator unsigned();
+};
+
+void use() {
+  TemplFunc(SomeStruct{});
+}
+#endif

diff  --git a/clang/test/SemaOpenACC/shutdown-construct.cpp b/clang/test/SemaOpenACC/shutdown-construct.cpp
new file mode 100644
index 00000000000000..e4305883376c70
--- /dev/null
+++ b/clang/test/SemaOpenACC/shutdown-construct.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 %s -fopenacc -verify
+
+struct NotConvertible{} NC;
+short getS();
+int getI();
+
+struct AmbiguousConvert{
+  operator int(); // #AMBIG_INT
+  operator short(); // #AMBIG_SHORT
+  operator float();
+} Ambiguous;
+
+struct ExplicitConvertOnly {
+  explicit operator int() const; // #EXPL_CONV
+} Explicit;
+
+void uses() {
+#pragma acc shutdown
+#pragma acc shutdown if (getI() < getS())
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc shutdown device_num(getI())
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc shutdown device_type(SOMETHING) device_num(getI())
+#pragma acc shutdown device_type(SOMETHING) if (getI() < getS())
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc shutdown device_type(SOMETHING) device_num(getI()) if (getI() < getS())
+
+  // expected-error at +1{{value of type 'struct NotConvertible' is not contextually convertible to 'bool'}}
+#pragma acc shutdown if (NC)
+
+  // expected-error at +1{{OpenACC clause 'device_num' requires expression of integer type ('struct NotConvertible' invalid)}}
+#pragma acc shutdown device_num(NC)
+  // expected-error at +3{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}}
+  // expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
+  // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
+#pragma acc shutdown device_num(Ambiguous)
+  // expected-warning at +3{{OpenACC clause 'device_num' not yet implemented}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
+  // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
+#pragma acc shutdown device_num(Explicit)
+}
+
+template<typename T>
+void TestInst() {
+  T t;
+#pragma acc shutdown
+#pragma acc shutdown if (T::value < T{})
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc shutdown device_type(SOMETHING) device_num(getI()) if (getI() < getS())
+  // expected-warning at +1 2{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc shutdown device_type(SOMETHING) device_type(T) device_num(t) if (t < T::value) device_num(getI()) if (getI() < getS())
+
+  // expected-error at +1{{value of type 'const NotConvertible' is not contextually convertible to 'bool'}}
+#pragma acc shutdown if (T::NCValue)
+
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc shutdown device_num(T::NCValue)
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc shutdown device_num(T::ACValue)
+  // expected-warning at +1{{OpenACC clause 'device_num' not yet implemented}}
+#pragma acc shutdown device_num(T::EXValue)
+}
+
+struct HasStuff {
+  static constexpr AmbiguousConvert ACValue;
+  static constexpr ExplicitConvertOnly EXValue;
+  static constexpr NotConvertible NCValue;
+  static constexpr unsigned value = 5;
+  operator char();
+};
+
+void Inst() {
+  TestInst<HasStuff>(); // expected-note {{in instantiation of function template specialization}}
+}

diff  --git a/clang/test/SemaOpenACC/wait-construct.cpp b/clang/test/SemaOpenACC/wait-construct.cpp
index a68fc54b6e8f27..2de98762ea6007 100644
--- a/clang/test/SemaOpenACC/wait-construct.cpp
+++ b/clang/test/SemaOpenACC/wait-construct.cpp
@@ -35,7 +35,7 @@ void uses() {
   // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
 #pragma acc wait(Ambiguous)
 
-  // expected-error at +2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
 #pragma acc wait(4, Explicit, 5)
 
@@ -61,7 +61,7 @@ void TestInst() {
   // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
 #pragma acc wait(devnum:T::value :queues:T::ACValue)
 
-  // expected-error at +5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-error at +5{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}}
   // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
   // expected-error at +3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
   // expected-note@#AMBIG_INT{{conversion to integral type 'int'}}

diff  --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 9bdc4c9f8ce238..140200a52b80b7 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -2190,6 +2190,8 @@ class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void>,
   void VisitOpenACCExitDataConstruct(const OpenACCExitDataConstruct *D);
   void VisitOpenACCHostDataConstruct(const OpenACCHostDataConstruct *D);
   void VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *D);
+  void VisitOpenACCInitConstruct(const OpenACCInitConstruct *D);
+  void VisitOpenACCShutdownConstruct(const OpenACCShutdownConstruct *D);
   void VisitOMPExecutableDirective(const OMPExecutableDirective *D);
   void VisitOMPLoopBasedDirective(const OMPLoopBasedDirective *D);
   void VisitOMPLoopDirective(const OMPLoopDirective *D);
@@ -3639,6 +3641,19 @@ void EnqueueVisitor::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *C) {
     EnqueueChildren(Clause);
 }
 
+void EnqueueVisitor::VisitOpenACCInitConstruct(const OpenACCInitConstruct *C) {
+  EnqueueChildren(C);
+  for (auto *Clause : C->clauses())
+    EnqueueChildren(Clause);
+}
+
+void EnqueueVisitor::VisitOpenACCShutdownConstruct(
+    const OpenACCShutdownConstruct *C) {
+  EnqueueChildren(C);
+  for (auto *Clause : C->clauses())
+    EnqueueChildren(Clause);
+}
+
 void EnqueueVisitor::VisitAnnotateAttr(const AnnotateAttr *A) {
   EnqueueChildren(A);
 }
@@ -6403,6 +6418,10 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
     return cxstring::createRef("OpenACCHostDataConstruct");
   case CXCursor_OpenACCWaitConstruct:
     return cxstring::createRef("OpenACCWaitConstruct");
+  case CXCursor_OpenACCInitConstruct:
+    return cxstring::createRef("OpenACCInitConstruct");
+  case CXCursor_OpenACCShutdownConstruct:
+    return cxstring::createRef("OpenACCShutdownConstruct");
   }
 
   llvm_unreachable("Unhandled CXCursorKind");

diff  --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index b9fd3b4c7f3645..f56e77b42f9d73 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -903,6 +903,12 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
   case Stmt::OpenACCWaitConstructClass:
     K = CXCursor_OpenACCWaitConstruct;
     break;
+  case Stmt::OpenACCInitConstructClass:
+    K = CXCursor_OpenACCInitConstruct;
+    break;
+  case Stmt::OpenACCShutdownConstructClass:
+    K = CXCursor_OpenACCShutdownConstruct;
+    break;
   case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
     K = CXCursor_OMPTargetParallelGenericLoopDirective;
     break;


        


More information about the cfe-commits mailing list