[clang] e34cc7c - [OpenACC] Implement 'wait' construct

via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 18 15:06:07 PST 2024


Author: erichkeane
Date: 2024-12-18T15:06:01-08:00
New Revision: e34cc7c99375c43e1698c78ec9150fa40c88d486

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

LOG: [OpenACC] Implement 'wait' construct

The arguments to this are the same as for the 'wait' clause, so this
reuses all of that infrastructure. So all this has to do is support a
pair of clauses that are already implemented (if and async), plus create
an AST node.  This patch does so, and adds proper testing.

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

Modified: 
    clang/include/clang-c/Index.h
    clang/include/clang/AST/ASTNodeTraverser.h
    clang/include/clang/AST/RecursiveASTVisitor.h
    clang/include/clang/AST/StmtOpenACC.h
    clang/include/clang/AST/TextNodeDumper.h
    clang/include/clang/Basic/StmtNodes.td
    clang/include/clang/Parse/Parser.h
    clang/include/clang/Sema/SemaOpenACC.h
    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-wait-construct.c
    clang/test/SemaOpenACC/combined-construct-default-clause.c
    clang/test/SemaOpenACC/compute-construct-default-clause.c
    clang/test/SemaOpenACC/unimplemented-construct.c
    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 29858f00fad74e..122118b8f37638 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -2186,7 +2186,11 @@ enum CXCursorKind {
    */
   CXCursor_OpenACCHostDataConstruct = 326,
 
-  CXCursor_LastStmt = CXCursor_OpenACCHostDataConstruct,
+  /** OpenACC wait Construct.
+   */
+  CXCursor_OpenACCWaitConstruct = 327,
+
+  CXCursor_LastStmt = CXCursor_OpenACCWaitConstruct,
 
   /**
    * Cursor that represents the translation unit itself.

diff  --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index 3d63d581a9be60..f5652b295de168 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -159,7 +159,7 @@ class ASTNodeTraverser
 
       // Some statements have custom mechanisms for dumping their children.
       if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S) ||
-          isa<RequiresExpr>(S))
+          isa<RequiresExpr>(S) || isa<OpenACCWaitConstruct>(S))
         return;
 
       if (Traversal == TK_IgnoreUnlessSpelledInSource &&
@@ -825,6 +825,16 @@ class ASTNodeTraverser
       Visit(C);
   }
 
+  void VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *Node) {
+    // Needs custom child checking to put clauses AFTER the children, which are
+    // the expressions in the 'wait' construct. Others likely need this as well,
+    // and might need to do the associated statement after it.
+    for (const Stmt *S : Node->children())
+      Visit(S);
+    for (const auto *C : Node->clauses())
+      Visit(C);
+  }
+
   void VisitInitListExpr(const InitListExpr *ILE) {
     if (auto *Filler = ILE->getArrayFiller()) {
       Visit(Filler, "array_filler");

diff  --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 5d5c91ff91d553..d9a87b30062df8 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -4063,10 +4063,19 @@ DEF_TRAVERSE_STMT(OpenACCCombinedConstruct,
                   { TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); })
 DEF_TRAVERSE_STMT(OpenACCDataConstruct,
                   { TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); })
-DEF_TRAVERSE_STMT(OpenACCEnterDataConstruct, {})
-DEF_TRAVERSE_STMT(OpenACCExitDataConstruct, {})
+DEF_TRAVERSE_STMT(OpenACCEnterDataConstruct,
+                  { TRY_TO(VisitOpenACCClauseList(S->clauses())); })
+DEF_TRAVERSE_STMT(OpenACCExitDataConstruct,
+                  { TRY_TO(VisitOpenACCClauseList(S->clauses())); })
 DEF_TRAVERSE_STMT(OpenACCHostDataConstruct,
                   { TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); })
+DEF_TRAVERSE_STMT(OpenACCWaitConstruct, {
+  if (S->hasDevNumExpr())
+    TRY_TO(TraverseStmt(S->getDevNumExpr()));
+  for (auto *E : S->getQueueIdExprs())
+    TRY_TO(TraverseStmt(E));
+  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 a1903cd9e3a23a..093393a81be9c7 100644
--- a/clang/include/clang/AST/StmtOpenACC.h
+++ b/clang/include/clang/AST/StmtOpenACC.h
@@ -469,5 +469,128 @@ class OpenACCHostDataConstruct final
     return const_cast<OpenACCHostDataConstruct *>(this)->getStructuredBlock();
   }
 };
+
+// This class represents a 'wait' construct, which has some expressions plus a
+// clause list.
+class OpenACCWaitConstruct final
+    : public OpenACCConstructStmt,
+      private llvm::TrailingObjects<OpenACCWaitConstruct, Expr *,
+                                    OpenACCClause *> {
+  // FIXME: We should be storing a `const OpenACCClause *` to be consistent with
+  // the rest of the constructs, but TrailingObjects doesn't allow for mixing
+  // constness in its implementation of `getTrailingObjects`.
+
+  friend TrailingObjects;
+  friend class ASTStmtWriter;
+  friend class ASTStmtReader;
+  // Locations of the left and right parens of the 'wait-argument'
+  // expression-list.
+  SourceLocation LParenLoc, RParenLoc;
+  // Location of the 'queues' keyword, if present.
+  SourceLocation QueuesLoc;
+
+  // Number of the expressions being represented.  Index '0' is always the
+  // 'devnum' expression, even if it not present.
+  unsigned NumExprs = 0;
+
+  OpenACCWaitConstruct(unsigned NumExprs, unsigned NumClauses)
+      : OpenACCConstructStmt(OpenACCWaitConstructClass,
+                             OpenACCDirectiveKind::Wait, SourceLocation{},
+                             SourceLocation{}, SourceLocation{}),
+        NumExprs(NumExprs) {
+    assert(NumExprs >= 1 &&
+           "NumExprs should always be >= 1 because the 'devnum' "
+           "expr is represented by a null if necessary");
+    std::uninitialized_value_construct(getExprPtr(),
+                                       getExprPtr() + NumExprs);
+    std::uninitialized_value_construct(getTrailingObjects<OpenACCClause *>(),
+                                       getTrailingObjects<OpenACCClause *>() +
+                                           NumClauses);
+    setClauseList(MutableArrayRef(const_cast<const OpenACCClause **>(
+                                      getTrailingObjects<OpenACCClause *>()),
+                                  NumClauses));
+  }
+
+  OpenACCWaitConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
+                       SourceLocation LParenLoc, Expr *DevNumExpr,
+                       SourceLocation QueuesLoc, ArrayRef<Expr *> QueueIdExprs,
+                       SourceLocation RParenLoc, SourceLocation End,
+                       ArrayRef<const OpenACCClause *> Clauses)
+      : OpenACCConstructStmt(OpenACCWaitConstructClass,
+                             OpenACCDirectiveKind::Wait, Start, DirectiveLoc,
+                             End),
+        LParenLoc(LParenLoc), RParenLoc(RParenLoc), QueuesLoc(QueuesLoc),
+        NumExprs(QueueIdExprs.size() + 1) {
+    assert(NumExprs >= 1 &&
+           "NumExprs should always be >= 1 because the 'devnum' "
+           "expr is represented by a null if necessary");
+
+    std::uninitialized_copy(&DevNumExpr, &DevNumExpr + 1,
+                            getExprPtr());
+    std::uninitialized_copy(QueueIdExprs.begin(), QueueIdExprs.end(),
+                            getExprPtr() + 1);
+
+    std::uninitialized_copy(const_cast<OpenACCClause **>(Clauses.begin()),
+                            const_cast<OpenACCClause **>(Clauses.end()),
+                            getTrailingObjects<OpenACCClause *>());
+    setClauseList(MutableArrayRef(const_cast<const OpenACCClause **>(
+                                      getTrailingObjects<OpenACCClause *>()),
+                                  Clauses.size()));
+  }
+
+  size_t numTrailingObjects(OverloadToken<Expr *>) const { return NumExprs; }
+  size_t numTrailingObjects(OverloadToken<const OpenACCClause *>) const {
+    return clauses().size();
+  }
+
+  Expr **getExprPtr() const {
+    return const_cast<Expr**>(getTrailingObjects<Expr *>());
+  }
+
+  llvm::ArrayRef<Expr *> getExprs() const {
+    return llvm::ArrayRef<Expr *>(getExprPtr(), NumExprs);
+  }
+
+  llvm::ArrayRef<Expr *> getExprs() {
+    return llvm::ArrayRef<Expr *>(getExprPtr(), NumExprs);
+  }
+
+public:
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == OpenACCWaitConstructClass;
+  }
+
+  static OpenACCWaitConstruct *
+  CreateEmpty(const ASTContext &C, unsigned NumExprs, unsigned NumClauses);
+
+  static OpenACCWaitConstruct *
+  Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
+         SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc,
+         ArrayRef<Expr *> QueueIdExprs, SourceLocation RParenLoc,
+         SourceLocation End, ArrayRef<const OpenACCClause *> Clauses);
+
+  SourceLocation getLParenLoc() const { return LParenLoc; }
+  SourceLocation getRParenLoc() const { return RParenLoc; }
+  bool hasQueuesTag() const { return !QueuesLoc.isInvalid(); }
+  SourceLocation getQueuesLoc() const { return QueuesLoc; }
+
+  bool hasDevNumExpr() const { return getExprs()[0]; }
+  Expr *getDevNumExpr() const { return getExprs()[0]; }
+  llvm::ArrayRef<Expr *> getQueueIdExprs() { return getExprs().drop_front(); }
+  llvm::ArrayRef<Expr *> getQueueIdExprs() const {
+    return getExprs().drop_front();
+  }
+
+  child_range children() {
+    Stmt **Begin = reinterpret_cast<Stmt **>(getExprPtr());
+    return child_range(Begin, Begin + NumExprs);
+  }
+
+  const_child_range children() const {
+    Stmt *const *Begin =
+        reinterpret_cast<Stmt *const *>(getExprPtr());
+    return const_child_range(Begin, Begin + NumExprs);
+  }
+};
 } // 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 e54e7e527b8a36..b6f16be7a5b98f 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -415,6 +415,7 @@ class TextNodeDumper
   void VisitOpenACCEnterDataConstruct(const OpenACCEnterDataConstruct *S);
   void VisitOpenACCExitDataConstruct(const OpenACCExitDataConstruct *S);
   void VisitOpenACCHostDataConstruct(const OpenACCHostDataConstruct *S);
+  void VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S);
   void VisitOpenACCAsteriskSizeExpr(const OpenACCAsteriskSizeExpr *S);
   void VisitEmbedExpr(const EmbedExpr *S);
   void VisitAtomicExpr(const AtomicExpr *AE);

diff  --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index 0c3c580c218fd7..6c7314b06d858a 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -312,6 +312,7 @@ def OpenACCDataConstruct : StmtNode<OpenACCAssociatedStmtConstruct>;
 def OpenACCEnterDataConstruct : StmtNode<OpenACCConstructStmt>;
 def OpenACCExitDataConstruct : StmtNode<OpenACCConstructStmt>;
 def OpenACCHostDataConstruct : StmtNode<OpenACCAssociatedStmtConstruct>;
+def OpenACCWaitConstruct : StmtNode<OpenACCConstructStmt>;
 
 // OpenACC Additional Expressions.
 def OpenACCAsteriskSizeExpr : StmtNode<Expr>;

diff  --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index d3838a4cc8418c..e99d2cf2eaa409 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -3706,10 +3706,14 @@ class Parser : public CodeCompletionHandler {
     OpenACCDirectiveKind DirKind;
     SourceLocation StartLoc;
     SourceLocation DirLoc;
+    SourceLocation LParenLoc;
+    SourceLocation RParenLoc;
     SourceLocation EndLoc;
+    SourceLocation MiscLoc;
+    SmallVector<Expr *> Exprs;
     SmallVector<OpenACCClause *> Clauses;
-    // TODO OpenACC: As we implement support for the Atomic, Routine, Cache, and
-    // Wait constructs, we likely want to put that information in here as well.
+    // TODO OpenACC: As we implement support for the Atomic, Routine, and Cache
+    // constructs, we likely want to put that information in here as well.
   };
 
   struct OpenACCWaitParseInfo {
@@ -3717,6 +3721,13 @@ class Parser : public CodeCompletionHandler {
     Expr *DevNumExpr = nullptr;
     SourceLocation QueuesLoc;
     SmallVector<Expr *> QueueIdExprs;
+
+    SmallVector<Expr *> getAllExprs() {
+      SmallVector<Expr *> Out;
+      Out.push_back(DevNumExpr);
+      Out.insert(Out.end(), QueueIdExprs.begin(), QueueIdExprs.end());
+      return Out;
+    }
   };
 
   /// Represents the 'error' state of parsing an OpenACC Clause, and stores

diff  --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h
index 4b92af507af4ea..04ab1ac429a2dd 100644
--- a/clang/include/clang/Sema/SemaOpenACC.h
+++ b/clang/include/clang/Sema/SemaOpenACC.h
@@ -679,12 +679,18 @@ class SemaOpenACC : public SemaBase {
 
   /// Called after the directive has been completely parsed, including the
   /// declaration group or associated statement.
-  StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K,
-                                   SourceLocation StartLoc,
-                                   SourceLocation DirLoc,
-                                   SourceLocation EndLoc,
-                                   ArrayRef<OpenACCClause *> Clauses,
-                                   StmtResult AssocStmt);
+  /// LParenLoc: Location of the left paren, if it exists (not on all
+  /// constructs).
+  /// MiscLoc: First misc location, if necessary (not all constructs).
+  /// Exprs: List of expressions on the construct itself, if necessary (not all
+  /// constructs).
+  /// RParenLoc: Location of the right paren, if it exists (not on all
+  /// constructs).
+  StmtResult ActOnEndStmtDirective(
+      OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation DirLoc,
+      SourceLocation LParenLoc, SourceLocation MiscLoc, ArrayRef<Expr *> Exprs,
+      SourceLocation RParenLoc, SourceLocation EndLoc,
+      ArrayRef<OpenACCClause *> Clauses, StmtResult AssocStmt);
 
   /// Called after the directive has been completely parsed, including the
   /// declaration group or associated statement.

diff  --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index da0e5fdb117aa0..57e27c373bffa1 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -2021,6 +2021,7 @@ enum StmtCode {
   STMT_OPENACC_ENTER_DATA_CONSTRUCT,
   STMT_OPENACC_EXIT_DATA_CONSTRUCT,
   STMT_OPENACC_HOST_DATA_CONSTRUCT,
+  STMT_OPENACC_WAIT_CONSTRUCT,
 
   // HLSL Constructs
   EXPR_HLSL_OUT_ARG,

diff  --git a/clang/lib/AST/StmtOpenACC.cpp b/clang/lib/AST/StmtOpenACC.cpp
index fb73dfb3fa9dee..6d9f267702e37d 100644
--- a/clang/lib/AST/StmtOpenACC.cpp
+++ b/clang/lib/AST/StmtOpenACC.cpp
@@ -196,3 +196,32 @@ OpenACCHostDataConstruct *OpenACCHostDataConstruct::Create(
                                                   Clauses, StructuredBlock);
   return Inst;
 }
+
+OpenACCWaitConstruct *OpenACCWaitConstruct::CreateEmpty(const ASTContext &C,
+                                                        unsigned NumExprs,
+                                                        unsigned NumClauses) {
+  void *Mem = C.Allocate(
+      OpenACCWaitConstruct::totalSizeToAlloc<Expr *, OpenACCClause *>(
+          NumExprs, NumClauses));
+
+  auto *Inst = new (Mem) OpenACCWaitConstruct(NumExprs, NumClauses);
+  return Inst;
+}
+
+OpenACCWaitConstruct *OpenACCWaitConstruct::Create(
+    const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
+    SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc,
+    ArrayRef<Expr *> QueueIdExprs, SourceLocation RParenLoc, SourceLocation End,
+    ArrayRef<const OpenACCClause *> Clauses) {
+
+  assert(llvm::all_of(QueueIdExprs, [](Expr *E) { return E != nullptr; }));
+
+  void *Mem = C.Allocate(
+      OpenACCWaitConstruct::totalSizeToAlloc<Expr *, OpenACCClause *>(
+          QueueIdExprs.size() + 1, Clauses.size()));
+
+  auto *Inst = new (Mem)
+      OpenACCWaitConstruct(Start, DirectiveLoc, LParenLoc, DevNumExpr,
+                           QueuesLoc, QueueIdExprs, RParenLoc, End, Clauses);
+  return Inst;
+}

diff  --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 488419add5e79e..ecc9b6e35db72d 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1238,6 +1238,34 @@ void StmtPrinter::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) {
   PrintStmt(S->getStructuredBlock());
 }
 
+void StmtPrinter::VisitOpenACCWaitConstruct(OpenACCWaitConstruct *S) {
+  Indent() << "#pragma acc wait";
+  if (!S->getLParenLoc().isInvalid()) {
+    OS << "(";
+    if (S->hasDevNumExpr()) {
+      OS << "devnum: ";
+      S->getDevNumExpr()->printPretty(OS, nullptr, Policy);
+      OS << " : ";
+    }
+
+    if (S->hasQueuesTag())
+      OS << "queues: ";
+
+    llvm::interleaveComma(S->getQueueIdExprs(), OS, [&](const Expr *E) {
+      E->printPretty(OS, nullptr, Policy);
+    });
+
+    OS << ")";
+  }
+
+  if (!S->clauses().empty()) {
+    OS << ' ';
+    OpenACCClausePrinter Printer(OS, Policy);
+    Printer.VisitClauseList(S->clauses());
+  }
+  OS << '\n';
+}
+
 //===----------------------------------------------------------------------===//
 //  Expr printing methods.
 //===----------------------------------------------------------------------===//

diff  --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 1fb238720ffb13..fccd97dca23af2 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2743,6 +2743,14 @@ void StmtProfiler::VisitOpenACCHostDataConstruct(
   P.VisitOpenACCClauseList(S->clauses());
 }
 
+void StmtProfiler::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S) {
+  // VisitStmt covers 'children', so the exprs inside of it are covered.
+  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 b5af10dd00b77c..7cdffbe20e575a 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -2960,6 +2960,10 @@ void TextNodeDumper::VisitOpenACCHostDataConstruct(
   OS << " " << S->getDirectiveKind();
 }
 
+void TextNodeDumper::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S) {
+  OS << " " << S->getDirectiveKind();
+}
+
 void TextNodeDumper::VisitEmbedExpr(const EmbedExpr *S) {
   AddChild("begin", [=] { OS << S->getStartingElementPos(); });
   AddChild("number of elements", [=] { OS << S->getDataElementCount(); });

diff  --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 6c7a594fb10c4c..6c604f44e283be 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -470,6 +470,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
   case Stmt::OpenACCHostDataConstructClass:
     EmitOpenACCHostDataConstruct(cast<OpenACCHostDataConstruct>(*S));
     break;
+  case Stmt::OpenACCWaitConstructClass:
+    EmitOpenACCWaitConstruct(cast<OpenACCWaitConstruct>(*S));
+    break;
   }
 }
 

diff  --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 092d55355a0a17..847999cf1f28a0 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4118,6 +4118,11 @@ class CodeGenFunction : public CodeGenTypeCache {
     EmitStmt(S.getStructuredBlock());
   }
 
+  void EmitOpenACCWaitConstruct(const OpenACCWaitConstruct &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 af175a465eb79a..5da34a2f5db923 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -573,6 +573,7 @@ bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) {
   default:
   case OpenACCDirectiveKind::EnterData:
   case OpenACCDirectiveKind::ExitData:
+  case OpenACCDirectiveKind::Wait:
     return false;
   case OpenACCDirectiveKind::Parallel:
   case OpenACCDirectiveKind::Serial:
@@ -604,6 +605,7 @@ unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) {
   case OpenACCDirectiveKind::EnterData:
   case OpenACCDirectiveKind::ExitData:
   case OpenACCDirectiveKind::HostData:
+  case OpenACCDirectiveKind::Wait:
     return 0;
   case OpenACCDirectiveKind::Invalid:
     llvm_unreachable("Shouldn't be creating a scope for an invalid construct");
@@ -1288,7 +1290,8 @@ Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
       return Result;
     }
 
-    Result.QueueIdExprs.push_back(Res.first.get());
+    if (Res.first.isUsable())
+      Result.QueueIdExprs.push_back(Res.first.get());
   }
 
   return Result;
@@ -1422,6 +1425,7 @@ Parser::ParseOpenACCDirective() {
   SourceLocation StartLoc = ConsumeAnnotationToken();
   SourceLocation DirLoc = getCurToken().getLocation();
   OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this);
+  Parser::OpenACCWaitParseInfo WaitInfo;
 
   getActions().OpenACC().ActOnConstruct(DirKind, DirLoc);
 
@@ -1462,7 +1466,8 @@ Parser::ParseOpenACCDirective() {
       break;
     case OpenACCDirectiveKind::Wait:
       // OpenACC has an optional paren-wrapped 'wait-argument'.
-      if (ParseOpenACCWaitArgument(DirLoc, /*IsDirective=*/true).Failed)
+      WaitInfo = ParseOpenACCWaitArgument(DirLoc, /*IsDirective=*/true);
+      if (WaitInfo.Failed)
         T.skipToEnd();
       else
         T.consumeClose();
@@ -1476,8 +1481,14 @@ Parser::ParseOpenACCDirective() {
   }
 
   // Parses the list of clauses, if present, plus set up return value.
-  OpenACCDirectiveParseInfo ParseInfo{DirKind, StartLoc, DirLoc,
-                                      SourceLocation{},
+  OpenACCDirectiveParseInfo ParseInfo{DirKind,
+                                      StartLoc,
+                                      DirLoc,
+                                      T.getOpenLocation(),
+                                      T.getCloseLocation(),
+                                      /*EndLoc=*/SourceLocation{},
+                                      WaitInfo.QueuesLoc,
+                                      WaitInfo.getAllExprs(),
                                       ParseOpenACCClauseList(DirKind)};
 
   assert(Tok.is(tok::annot_pragma_openacc_end) &&
@@ -1529,6 +1540,7 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() {
   }
 
   return getActions().OpenACC().ActOnEndStmtDirective(
-      DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.EndLoc,
+      DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.LParenLoc,
+      DirInfo.MiscLoc, DirInfo.Exprs, DirInfo.RParenLoc, DirInfo.EndLoc,
       DirInfo.Clauses, AssocStmt);
 }

diff  --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 2be6af293ed543..505cc5e153fa70 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1398,6 +1398,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
   case Expr::HLSLOutArgExprClass:
   case Stmt::OpenACCEnterDataConstructClass:
   case Stmt::OpenACCExitDataConstructClass:
+  case Stmt::OpenACCWaitConstructClass:
     // These expressions can never throw.
     return CT_Cannot;
 

diff  --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 11c18358a3aa01..aa9097bfa17436 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -41,6 +41,7 @@ bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K,
   case OpenACCDirectiveKind::EnterData:
   case OpenACCDirectiveKind::ExitData:
   case OpenACCDirectiveKind::HostData:
+  case OpenACCDirectiveKind::Wait:
     if (!IsStmt)
       return S.Diag(StartLoc, diag::err_acc_construct_appertainment) << K;
     break;
@@ -566,6 +567,16 @@ bool checkValidAfterDeviceType(
   return true;
 }
 
+// A temporary function that helps implement the 'not implemented' check at the
+// top of each clause checking function. This should only be used in conjunction
+// with the one being currently implemented/only updated after the entire
+// construct has been implemented.
+bool isDirectiveKindImplemented(OpenACCDirectiveKind DK) {
+  return isOpenACCComputeDirectiveKind(DK) ||
+         isOpenACCCombinedDirectiveKind(DK) || isOpenACCDataDirectiveKind(DK) ||
+         DK == OpenACCDirectiveKind::Loop || DK == OpenACCDirectiveKind::Wait;
+}
+
 class SemaOpenACCClauseVisitor {
   SemaOpenACC &SemaRef;
   ASTContext &Ctx;
@@ -680,9 +691,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitIfClause(
   // constructs, and 'compute'/'combined'/'data' constructs are the only
   // constructs that can do anything with this yet, so skip/treat as
   // unimplemented in this case.
-  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCDataDirectiveKind(Clause.getDirectiveKind()))
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
 
   // There is no prose in the standard that says duplicates aren't allowed,
@@ -717,8 +726,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitSelfClause(
   // Restrictions only properly implemented on 'compute' constructs, and
   // 'compute' constructs are the only construct that can do anything with
   // this yet, so skip/treat as unimplemented in this case.
-  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()))
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
 
   // TODO OpenACC: When we implement this for 'update', this takes a
@@ -915,9 +923,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitAsyncClause(
   // constructs, and 'compute'/'combined'/'data' constructs are the only
   // construct that can do anything with this yet, so skip/treat as
   // unimplemented in this case.
-  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCDataDirectiveKind(Clause.getDirectiveKind()))
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
 
   // There is no prose in the standard that says duplicates aren't allowed,
@@ -973,9 +979,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitPresentClause(
   // constructs, and 'compute'/'combined'/'data' constructs are the only
   // construct that can do anything with this yet, so skip/treat as
   // unimplemented in this case.
-  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCDataDirectiveKind(Clause.getDirectiveKind()))
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
   // ActOnVar ensured that everything is a valid variable reference, so there
   // really isn't anything to do here. GCC does some duplicate-finding, though
@@ -992,9 +996,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyClause(
   // constructs, and 'compute'/'combined'/'data' constructs are the only
   // construct that can do anything with this yet, so skip/treat as
   // unimplemented in this case.
-  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCDataDirectiveKind(Clause.getDirectiveKind()))
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
   // ActOnVar ensured that everything is a valid variable reference, so there
   // really isn't anything to do here. GCC does some duplicate-finding, though
@@ -1011,9 +1013,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyInClause(
   // constructs, and 'compute'/'combined'/'data' constructs are the only
   // construct that can do anything with this yet, so skip/treat as
   // unimplemented in this case.
-  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCDataDirectiveKind(Clause.getDirectiveKind()))
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
   // ActOnVar ensured that everything is a valid variable reference, so there
   // really isn't anything to do here. GCC does some duplicate-finding, though
@@ -1030,9 +1030,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyOutClause(
   // constructs, and 'compute'/'combined'/'data' constructs are the only
   // construct that can do anything with this yet, so skip/treat as
   // unimplemented in this case.
-  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCDataDirectiveKind(Clause.getDirectiveKind()))
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
   // ActOnVar ensured that everything is a valid variable reference, so there
   // really isn't anything to do here. GCC does some duplicate-finding, though
@@ -1109,9 +1107,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitDevicePtrClause(
   // constructs, and 'compute'/'combined'/'data' constructs are the only
   // construct that can do anything with this yet, so skip/treat as
   // unimplemented in this case.
-  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCDataDirectiveKind(Clause.getDirectiveKind()))
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
 
   // ActOnVar ensured that everything is a valid variable reference, but we
@@ -1134,9 +1130,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitWaitClause(
   // constructs, and 'compute'/'combined'/'data' constructs are the only
   // construct that can do anything with this yet, so skip/treat as
   // unimplemented in this case.
-  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) &&
-      !isOpenACCDataDirectiveKind(Clause.getDirectiveKind()))
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
 
   return OpenACCWaitClause::Create(
@@ -1150,10 +1144,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceTypeClause(
   // 'loop' constructs, and 'compute'/'combined'/'data'/'loop' constructs are
   // the only construct that can do anything with this yet, so skip/treat as
   // unimplemented in this case.
-  if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
-      Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop &&
-      Clause.getDirectiveKind() != OpenACCDirectiveKind::Data &&
-      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()))
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
 
   // TODO OpenACC: Once we get enough of the CodeGen implemented that we have
@@ -1347,8 +1338,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitVectorClause(
   // Restrictions only properly implemented on 'loop'/'combined' constructs, and
   // it is the only construct that can do anything with this, so skip/treat as
   // unimplemented for the routine constructs.
-  if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop &&
-      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()))
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
 
   Expr *IntExpr =
@@ -1446,8 +1436,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitWorkerClause(
   // Restrictions only properly implemented on 'loop'/'combined' constructs, and
   // it is the only construct that can do anything with this, so skip/treat as
   // unimplemented for the routine constructs.
-  if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop &&
-      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()))
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
 
   Expr *IntExpr =
@@ -1559,8 +1548,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitGangClause(
   // Restrictions only properly implemented on 'loop' constructs, and it is
   // the only construct that can do anything with this, so skip/treat as
   // unimplemented for the combined constructs.
-  if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop &&
-      !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()))
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
 
   // OpenACC 3.3 Section 2.9.11: A reduction clause may not appear on a loop
@@ -1691,7 +1679,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitFinalizeClause(
 
 OpenACCClause *SemaOpenACCClauseVisitor::VisitIfPresentClause(
     SemaOpenACC::OpenACCParsedClause &Clause) {
-  if (Clause.getDirectiveKind() != OpenACCDirectiveKind::HostData)
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
   // There isn't anything to do here, this is only valid on one construct, and
   // has no associated rules.
@@ -1704,7 +1692,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitSeqClause(
   // Restrictions only properly implemented on 'loop' constructs and combined ,
   // and it is the only construct that can do anything with this, so skip/treat
   // as unimplemented for the routine constructs.
-  if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Routine)
+  if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
     return isNotImplemented();
 
   // OpenACC 3.3 2.9:
@@ -1879,6 +1867,7 @@ bool PreserveLoopRAIIDepthInAssociatedStmtRAII(OpenACCDirectiveKind DK) {
     return true;
   case OpenACCDirectiveKind::EnterData:
   case OpenACCDirectiveKind::ExitData:
+  case OpenACCDirectiveKind::Wait:
     llvm_unreachable("Doesn't have an associated stmt");
   default:
   case OpenACCDirectiveKind::Invalid:
@@ -2308,6 +2297,10 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K,
     // Nothing to do here, there is no real legalization that needs to happen
     // here as these constructs do not take any arguments.
     break;
+  case OpenACCDirectiveKind::Wait:
+    // Nothing really to do here, the arguments to the 'wait' should have
+    // already been handled by the time we get here.
+    break;
   default:
     Diag(DirLoc, diag::warn_acc_construct_unimplemented) << K;
     break;
@@ -3637,12 +3630,11 @@ bool SemaOpenACC::ActOnStartStmtDirective(
   return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/true);
 }
 
-StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K,
-                                              SourceLocation StartLoc,
-                                              SourceLocation DirLoc,
-                                              SourceLocation EndLoc,
-                                              ArrayRef<OpenACCClause *> Clauses,
-                                              StmtResult AssocStmt) {
+StmtResult SemaOpenACC::ActOnEndStmtDirective(
+    OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation DirLoc,
+    SourceLocation LParenLoc, SourceLocation MiscLoc, ArrayRef<Expr *> Exprs,
+    SourceLocation RParenLoc, SourceLocation EndLoc,
+    ArrayRef<OpenACCClause *> Clauses, StmtResult AssocStmt) {
   switch (K) {
   default:
     return StmtEmpty();
@@ -3685,6 +3677,11 @@ StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K,
         getASTContext(), StartLoc, DirLoc, EndLoc, Clauses,
         AssocStmt.isUsable() ? AssocStmt.get() : nullptr);
   }
+  case OpenACCDirectiveKind::Wait: {
+    return OpenACCWaitConstruct::Create(
+        getASTContext(), StartLoc, DirLoc, LParenLoc, Exprs.front(), MiscLoc,
+        Exprs.drop_front(), RParenLoc, EndLoc, Clauses);
+  }
   }
   llvm_unreachable("Unhandled case in directive handling?");
 }
@@ -3697,6 +3694,7 @@ StmtResult SemaOpenACC::ActOnAssociatedStmt(
     llvm_unreachable("Unimplemented associated statement application");
   case OpenACCDirectiveKind::EnterData:
   case OpenACCDirectiveKind::ExitData:
+  case OpenACCDirectiveKind::Wait:
     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 04167e71d33f8a..c097465374cba8 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4087,8 +4087,9 @@ class TreeTransform {
                                             SourceLocation EndLoc,
                                             ArrayRef<OpenACCClause *> Clauses,
                                             StmtResult StrBlock) {
-    return getSema().OpenACC().ActOnEndStmtDirective(K, BeginLoc, DirLoc,
-                                                     EndLoc, Clauses, StrBlock);
+    return getSema().OpenACC().ActOnEndStmtDirective(
+        K, BeginLoc, DirLoc, SourceLocation{}, SourceLocation{}, {},
+        SourceLocation{}, EndLoc, Clauses, StrBlock);
   }
 
   StmtResult RebuildOpenACCLoopConstruct(SourceLocation BeginLoc,
@@ -4097,7 +4098,8 @@ class TreeTransform {
                                          ArrayRef<OpenACCClause *> Clauses,
                                          StmtResult Loop) {
     return getSema().OpenACC().ActOnEndStmtDirective(
-        OpenACCDirectiveKind::Loop, BeginLoc, DirLoc, EndLoc, Clauses, Loop);
+        OpenACCDirectiveKind::Loop, BeginLoc, DirLoc, SourceLocation{},
+        SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, Loop);
   }
 
   StmtResult RebuildOpenACCCombinedConstruct(OpenACCDirectiveKind K,
@@ -4106,8 +4108,9 @@ class TreeTransform {
                                              SourceLocation EndLoc,
                                              ArrayRef<OpenACCClause *> Clauses,
                                              StmtResult Loop) {
-    return getSema().OpenACC().ActOnEndStmtDirective(K, BeginLoc, DirLoc,
-                                                     EndLoc, Clauses, Loop);
+    return getSema().OpenACC().ActOnEndStmtDirective(
+        K, BeginLoc, DirLoc, SourceLocation{}, SourceLocation{}, {},
+        SourceLocation{}, EndLoc, Clauses, Loop);
   }
 
   StmtResult RebuildOpenACCDataConstruct(SourceLocation BeginLoc,
@@ -4115,9 +4118,9 @@ class TreeTransform {
                                          SourceLocation EndLoc,
                                          ArrayRef<OpenACCClause *> Clauses,
                                          StmtResult StrBlock) {
-    return getSema().OpenACC().ActOnEndStmtDirective(OpenACCDirectiveKind::Data,
-                                                     BeginLoc, DirLoc, EndLoc,
-                                                     Clauses, StrBlock);
+    return getSema().OpenACC().ActOnEndStmtDirective(
+        OpenACCDirectiveKind::Data, BeginLoc, DirLoc, SourceLocation{},
+        SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, StrBlock);
   }
 
   StmtResult
@@ -4125,7 +4128,8 @@ class TreeTransform {
                                    SourceLocation DirLoc, SourceLocation EndLoc,
                                    ArrayRef<OpenACCClause *> Clauses) {
     return getSema().OpenACC().ActOnEndStmtDirective(
-        OpenACCDirectiveKind::EnterData, BeginLoc, DirLoc, EndLoc, Clauses, {});
+        OpenACCDirectiveKind::EnterData, BeginLoc, DirLoc, SourceLocation{},
+        SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {});
   }
 
   StmtResult
@@ -4133,7 +4137,8 @@ class TreeTransform {
                                   SourceLocation DirLoc, SourceLocation EndLoc,
                                   ArrayRef<OpenACCClause *> Clauses) {
     return getSema().OpenACC().ActOnEndStmtDirective(
-        OpenACCDirectiveKind::ExitData, BeginLoc, DirLoc, EndLoc, Clauses, {});
+        OpenACCDirectiveKind::ExitData, BeginLoc, DirLoc, SourceLocation{},
+        SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {});
   }
 
   StmtResult RebuildOpenACCHostDataConstruct(SourceLocation BeginLoc,
@@ -4142,8 +4147,21 @@ class TreeTransform {
                                              ArrayRef<OpenACCClause *> Clauses,
                                              StmtResult StrBlock) {
     return getSema().OpenACC().ActOnEndStmtDirective(
-        OpenACCDirectiveKind::HostData, BeginLoc, DirLoc, EndLoc, Clauses,
-        StrBlock);
+        OpenACCDirectiveKind::HostData, BeginLoc, DirLoc, SourceLocation{},
+        SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, StrBlock);
+  }
+
+  StmtResult RebuildOpenACCWaitConstruct(
+      SourceLocation BeginLoc, SourceLocation DirLoc, SourceLocation LParenLoc,
+      Expr *DevNumExpr, SourceLocation QueuesLoc, ArrayRef<Expr *> QueueIdExprs,
+      SourceLocation RParenLoc, SourceLocation EndLoc,
+      ArrayRef<OpenACCClause *> Clauses) {
+    llvm::SmallVector<Expr *> Exprs;
+    Exprs.push_back(DevNumExpr);
+    Exprs.insert(Exprs.end(), QueueIdExprs.begin(), QueueIdExprs.end());
+    return getSema().OpenACC().ActOnEndStmtDirective(
+        OpenACCDirectiveKind::Wait, BeginLoc, DirLoc, LParenLoc, QueuesLoc,
+        Exprs, RParenLoc, EndLoc, Clauses, {});
   }
 
   ExprResult RebuildOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) {
@@ -12330,6 +12348,50 @@ StmtResult TreeTransform<Derived>::TransformOpenACCHostDataConstruct(
       TransformedClauses, StrBlock);
 }
 
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOpenACCWaitConstruct(OpenACCWaitConstruct *C) {
+  getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc());
+
+  ExprResult DevNumExpr;
+  if (C->hasDevNumExpr()) {
+    DevNumExpr = getDerived().TransformExpr(C->getDevNumExpr());
+
+    if (DevNumExpr.isUsable())
+      DevNumExpr = getSema().OpenACC().ActOnIntExpr(
+          OpenACCDirectiveKind::Wait, OpenACCClauseKind::Invalid,
+          C->getBeginLoc(), DevNumExpr.get());
+  }
+
+  llvm::SmallVector<Expr *> QueueIdExprs;
+
+  for (Expr *QE : C->getQueueIdExprs()) {
+    assert(QE && "Null queue id expr?");
+    ExprResult NewEQ = getDerived().TransformExpr(QE);
+
+    if (!NewEQ.isUsable())
+      break;
+    NewEQ = getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Wait,
+                                             OpenACCClauseKind::Invalid,
+                                             C->getBeginLoc(), NewEQ.get());
+    if (NewEQ.isUsable())
+      QueueIdExprs.push_back(NewEQ.get());
+  }
+
+  llvm::SmallVector<OpenACCClause *> TransformedClauses =
+      getDerived().TransformOpenACCClauseList(C->getDirectiveKind(),
+                                              C->clauses());
+
+  if (getSema().OpenACC().ActOnStartStmtDirective(
+          C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses))
+    return StmtError();
+
+  return getDerived().RebuildOpenACCWaitConstruct(
+      C->getBeginLoc(), C->getDirectiveLoc(), C->getLParenLoc(),
+      DevNumExpr.isUsable() ? DevNumExpr.get() : nullptr, C->getQueuesLoc(),
+      QueueIdExprs, C->getRParenLoc(), C->getEndLoc(), TransformedClauses);
+}
+
 template <typename Derived>
 ExprResult TreeTransform<Derived>::TransformOpenACCAsteriskSizeExpr(
     OpenACCAsteriskSizeExpr *E) {

diff  --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 21ad6c5a9faa33..8fe0412706ce3e 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2870,6 +2870,22 @@ void ASTStmtReader::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) {
   VisitOpenACCAssociatedStmtConstruct(S);
 }
 
+void ASTStmtReader::VisitOpenACCWaitConstruct(OpenACCWaitConstruct *S) {
+  VisitStmt(S);
+  // Consume the count of Expressions.
+  (void)Record.readInt();
+  VisitOpenACCConstructStmt(S);
+  S->LParenLoc = Record.readSourceLocation();
+  S->RParenLoc = Record.readSourceLocation();
+  S->QueuesLoc = Record.readSourceLocation();
+
+  for (unsigned I = 0; I < S->NumExprs; ++I) {
+    S->getExprPtr()[I] = cast_if_present<Expr>(Record.readSubStmt());
+    assert((I == 0 || S->getExprPtr()[I] != nullptr) &&
+           "Only first expression should be null");
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // HLSL Constructs/Directives.
 //===----------------------------------------------------------------------===//
@@ -4365,6 +4381,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
       S = OpenACCHostDataConstruct::CreateEmpty(Context, NumClauses);
       break;
     }
+    case STMT_OPENACC_WAIT_CONSTRUCT: {
+      unsigned NumExprs = Record[ASTStmtReader::NumStmtFields];
+      unsigned NumClauses = Record[ASTStmtReader::NumStmtFields + 1];
+      S = OpenACCWaitConstruct::CreateEmpty(Context, NumExprs, 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 e55cbe1f6ecce6..f13443d18b612a 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2951,6 +2951,20 @@ void ASTStmtWriter::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) {
   Code = serialization::STMT_OPENACC_HOST_DATA_CONSTRUCT;
 }
 
+void ASTStmtWriter::VisitOpenACCWaitConstruct(OpenACCWaitConstruct *S) {
+  VisitStmt(S);
+  Record.push_back(S->getExprs().size());
+  VisitOpenACCConstructStmt(S);
+  Record.AddSourceLocation(S->LParenLoc);
+  Record.AddSourceLocation(S->RParenLoc);
+  Record.AddSourceLocation(S->QueuesLoc);
+
+  for(Expr *E : S->getExprs())
+    Record.AddStmt(E);
+
+  Code = serialization::STMT_OPENACC_WAIT_CONSTRUCT;
+}
+
 //===----------------------------------------------------------------------===//
 // HLSL Constructs/Directives.
 //===----------------------------------------------------------------------===//

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

diff  --git a/clang/test/AST/ast-print-openacc-wait-construct.cpp b/clang/test/AST/ast-print-openacc-wait-construct.cpp
new file mode 100644
index 00000000000000..35354596be8d03
--- /dev/null
+++ b/clang/test/AST/ast-print-openacc-wait-construct.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fopenacc -ast-print %s -o - | FileCheck %s
+
+void uses() {
+  int *iPtr;
+  int I;
+  float array[5];
+
+// CHECK: #pragma acc wait() if(I == array[I])
+#pragma acc wait() if(I == array[I])
+
+// CHECK: #pragma acc wait(*iPtr, I) async
+#pragma acc wait(*iPtr, I) async
+
+// CHECK: #pragma acc wait(queues: *iPtr, I) async(*iPtr)
+#pragma acc wait(queues:*iPtr, I) async(*iPtr)
+
+// CHECK: #pragma acc wait(devnum: I : *iPtr, I) async(I)
+#pragma acc wait(devnum:I:*iPtr, I) async(I)
+
+// CHECK: #pragma acc wait(devnum: I : queues: *iPtr, I) if(I == array[I]) async(I)
+#pragma acc wait(devnum:I:queues:*iPtr, I) if(I == array[I]) async(I)
+}

diff  --git a/clang/test/ParserOpenACC/parse-wait-construct.c b/clang/test/ParserOpenACC/parse-wait-construct.c
index 8f7ea8efd57668..17b7ecbde7856d 100644
--- a/clang/test/ParserOpenACC/parse-wait-construct.c
+++ b/clang/test/ParserOpenACC/parse-wait-construct.c
@@ -3,171 +3,135 @@
 void func() {
   int i, j;
 
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
   #pragma acc wait
 
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
   #pragma acc wait clause-list
 
-  // expected-error at +3{{expected ')'}}
-  // expected-note at +2{{to match this '('}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +2{{expected ')'}}
+  // expected-note at +1{{to match this '('}}
   #pragma acc wait (
 
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
   #pragma acc wait ()
 
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
   #pragma acc wait () clause-list
 
-  // expected-error at +4{{expected expression}}
-  // expected-error at +3{{expected ')'}}
-  // expected-note at +2{{to match this '('}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +3{{expected expression}}
+  // expected-error at +2{{expected ')'}}
+  // expected-note at +1{{to match this '('}}
   #pragma acc wait (devnum:
 
-  // expected-error at +2{{expected expression}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +1{{expected expression}}
   #pragma acc wait (devnum:)
 
-  // expected-error at +3{{expected expression}}
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +2{{expected expression}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
   #pragma acc wait (devnum:) clause-list
 
-  // expected-error at +4{{expected ':'}}
-  // expected-error at +3{{expected ')'}}
-  // expected-note at +2{{to match this '('}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +3{{expected ':'}}
+  // expected-error at +2{{expected ')'}}
+  // expected-note at +1{{to match this '('}}
   #pragma acc wait (devnum: i + j
 
-  // expected-error at +2{{expected ':'}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +1{{expected ':'}}
   #pragma acc wait (devnum: i + j)
 
-  // expected-error at +3{{expected ':'}}
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +2{{expected ':'}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
   #pragma acc wait (devnum: i + j) clause-list
 
-  // expected-error at +3{{expected ')'}}
-  // expected-note at +2{{to match this '('}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +2{{expected ')'}}
+  // expected-note at +1{{to match this '('}}
   #pragma acc wait (queues:
 
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
   #pragma acc wait (queues:)
 
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
   #pragma acc wait (queues:) clause-list
 
-  // expected-error at +3{{expected ')'}}
-  // expected-note at +2{{to match this '('}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +2{{expected ')'}}
+  // expected-note at +1{{to match this '('}}
   #pragma acc wait (devnum: i + j:queues:
 
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
   #pragma acc wait (devnum: i + j:queues:)
 
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
   #pragma acc wait (devnum: i + j:queues:) clause-list
 
-  // expected-error at +5{{use of undeclared identifier 'devnum'}}
-  // expected-error at +4{{expected ','}}
-  // expected-error at +3{{expected ')'}}
-  // expected-note at +2{{to match this '('}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +4{{use of undeclared identifier 'devnum'}}
+  // expected-error at +3{{expected ','}}
+  // expected-error at +2{{expected ')'}}
+  // expected-note at +1{{to match this '('}}
   #pragma acc wait (queues:devnum: i + j
 
-  // expected-error at +3{{use of undeclared identifier 'devnum'}}
-  // expected-error at +2{{expected ','}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +2{{use of undeclared identifier 'devnum'}}
+  // expected-error at +1{{expected ','}}
   #pragma acc wait (queues:devnum: i + j)
 
-  // expected-error at +4{{use of undeclared identifier 'devnum'}}
-  // expected-error at +3{{expected ','}}
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +3{{use of undeclared identifier 'devnum'}}
+  // expected-error at +2{{expected ','}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
   #pragma acc wait (queues:devnum: i + j) clause-list
 
-  // expected-error at +4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
-  // expected-error at +3{{expected ')'}}
-  // expected-note at +2{{to match this '('}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
+  // expected-error at +2{{expected ')'}}
+  // expected-note at +1{{to match this '('}}
   #pragma acc wait(i, j, 1+1, 3.3
 
-  // expected-error at +2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +1{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
   #pragma acc wait(i, j, 1+1, 3.3)
-  // expected-error at +3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
   #pragma acc wait(i, j, 1+1, 3.3) clause-list
 
-  // expected-error at +4{{expected expression}}
-  // expected-error at +3{{expected ')'}}
-  // expected-note at +2{{to match this '('}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +3{{expected expression}}
+  // expected-error at +2{{expected ')'}}
+  // expected-note at +1{{to match this '('}}
   #pragma acc wait(,
 
-  // expected-error at +2{{expected expression}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +1{{expected expression}}
   #pragma acc wait(,)
 
-  // expected-error at +3{{expected expression}}
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +2{{expected expression}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
   #pragma acc wait(,) clause-list
 
-  // expected-error at +4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
-  // expected-error at +3{{expected ')'}}
-  // expected-note at +2{{to match this '('}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
+  // expected-error at +2{{expected ')'}}
+  // expected-note at +1{{to match this '('}}
   #pragma acc wait(queues:i, j, 1+1, 3.3
 
-  // expected-error at +5{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
-  // expected-error at +4{{expected expression}}
-  // expected-error at +3{{expected ')'}}
-  // expected-note at +2{{to match this '('}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
+  // expected-error at +3{{expected expression}}
+  // expected-error at +2{{expected ')'}}
+  // expected-note at +1{{to match this '('}}
   #pragma acc wait(queues:i, j, 1+1, 3.3,
 
-  // expected-error at +2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +1{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
   #pragma acc wait(queues:i, j, 1+1, 3.3)
 
-  // expected-error at +3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
   #pragma acc wait(queues:i, j, 1+1, 3.3) clause-list
 
-  // expected-error at +4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
-  // expected-error at +3{{expected ')'}}
-  // expected-note at +2{{to match this '('}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
+  // expected-error at +2{{expected ')'}}
+  // expected-note at +1{{to match this '('}}
   #pragma acc wait(devnum:3:i, j, 1+1, 3.3
-  // expected-error at +2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +1{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
   #pragma acc wait(devnum:3:i, j, 1+1, 3.3)
-  // expected-error at +3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
   #pragma acc wait(devnum:3:i, j, 1+1, 3.3) clause-list
 
-  // expected-error at +4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
-  // expected-error at +3{{expected ')'}}
-  // expected-note at +2{{to match this '('}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
+  // expected-error at +2{{expected ')'}}
+  // expected-note at +1{{to match this '('}}
   #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3
-  // expected-error at +2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +1{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
   #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3)
-  // expected-error at +3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
-  // expected-error at +2{{invalid OpenACC clause 'clause'}}
-  // expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
+  // expected-error at +2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}}
+  // expected-error at +1{{invalid OpenACC clause 'clause'}}
   #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3) clause-list
 }

diff  --git a/clang/test/SemaOpenACC/combined-construct-default-clause.c b/clang/test/SemaOpenACC/combined-construct-default-clause.c
index 43c2883f131845..2d77faa442a62f 100644
--- a/clang/test/SemaOpenACC/combined-construct-default-clause.c
+++ b/clang/test/SemaOpenACC/combined-construct-default-clause.c
@@ -35,7 +35,6 @@ void SingleOnly() {
   #pragma acc loop default(none)
   for(int i = 5; i < 10;++i);
 
-  // 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.c b/clang/test/SemaOpenACC/compute-construct-default-clause.c
index dfa5cd3f1c0d3e..86a758779fdf6d 100644
--- a/clang/test/SemaOpenACC/compute-construct-default-clause.c
+++ b/clang/test/SemaOpenACC/compute-construct-default-clause.c
@@ -35,7 +35,6 @@ void SingleOnly() {
   #pragma acc loop default(none)
   for(int i = 5; i < 10;++i);
 
-  // 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/unimplemented-construct.c b/clang/test/SemaOpenACC/unimplemented-construct.c
index 3f4bc375cff800..42737eb08d93fe 100644
--- a/clang/test/SemaOpenACC/unimplemented-construct.c
+++ b/clang/test/SemaOpenACC/unimplemented-construct.c
@@ -4,8 +4,8 @@
 #pragma acc routine
 
 struct S {
-// expected-warning at +1{{OpenACC construct 'wait' not yet implemented, pragma ignored}}
-#pragma acc wait
+// expected-warning at +1{{OpenACC construct 'set' not yet implemented, pragma ignored}}
+#pragma acc set
 int foo;
 };
 

diff  --git a/clang/test/SemaOpenACC/wait-construct-ast.cpp b/clang/test/SemaOpenACC/wait-construct-ast.cpp
new file mode 100644
index 00000000000000..58214f1f7c8867
--- /dev/null
+++ b/clang/test/SemaOpenACC/wait-construct-ast.cpp
@@ -0,0 +1,225 @@
+// 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 wait async(some_int())
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: <<<NULL>>
+  // CHECK-NEXT: async clause
+  // CHECK-NEXT: CallExpr{{.*}}'int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int'
+#pragma acc wait() async
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: <<<NULL>>
+  // CHECK-NEXT: async clause
+#pragma acc wait(some_int(), some_long()) if (some_int() < some_long())
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: <<<NULL>>
+  // CHECK-NEXT: CallExpr{{.*}}'int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int'
+  // CHECK-NEXT: CallExpr{{.*}}'long'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_long'
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}} 'long'
+  // CHECK-NEXT: CallExpr{{.*}}'int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int'
+  // CHECK-NEXT: CallExpr{{.*}}'long'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_long'
+#pragma acc wait(queues:some_int(), some_long())
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: <<<NULL>>
+  // CHECK-NEXT: CallExpr{{.*}}'int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int'
+  // CHECK-NEXT: CallExpr{{.*}}'long'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_long'
+#pragma acc wait(devnum:some_int() : queues:some_int(), some_long())
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: CallExpr{{.*}}'int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int'
+  // CHECK-NEXT: CallExpr{{.*}}'int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int'
+  // CHECK-NEXT: CallExpr{{.*}}'long'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_long'
+#pragma acc wait(devnum:some_int() : some_int(), some_long())
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: CallExpr{{.*}}'int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int'
+  // CHECK-NEXT: CallExpr{{.*}}'int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int'
+  // CHECK-NEXT: CallExpr{{.*}}'long'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_long'
+}
+
+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 wait async(T::value)
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: <<<NULL>>
+  // CHECK-NEXT: async clause
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>'
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T'
+#pragma acc wait() async
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: <<<NULL>>
+  // CHECK-NEXT: async clause
+#pragma acc wait(t, T::value) if (T::value > t)
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: <<<NULL>>
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'T' lvalue ParmVar{{.*}} 't' 'T'
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>'
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T'
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} '<dependent type>' '>'
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>'
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T'
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'T' lvalue ParmVar{{.*}} 't' 'T'
+#pragma acc wait(queues:typename T::IntTy{}, T::value) if (typename T::IntTy{} < typename T::ShortTy{})
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: <<<NULL>>
+  // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::IntTy' list
+  // CHECK-NEXT: InitListExpr
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>'
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T'
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} '<dependent type>' '<'
+  // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::IntTy' list
+  // CHECK-NEXT: InitListExpr
+  // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::ShortTy' list
+  // CHECK-NEXT: InitListExpr
+#pragma acc wait(devnum:typename T::ShortTy{} : queues:some_int(), T::value)
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::ShortTy' list
+  // CHECK-NEXT: InitListExpr
+  // CHECK-NEXT: CallExpr{{.*}}'int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int'
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>'
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T'
+#pragma acc wait(devnum:typename T::ShortTy{} : T::value, some_long())
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::ShortTy' list
+  // CHECK-NEXT: InitListExpr
+  // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>'
+  // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T'
+  // CHECK-NEXT: CallExpr{{.*}}'long'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_long'
+
+  // Instantiation:
+  // CHECK-NEXT: FunctionDecl{{.*}} TemplFunc 'void (HasInt)' implicit_instantiation
+  // CHECK-NEXT: TemplateArgument type 'HasInt'
+  // CHECK-NEXT: RecordType{{.*}} 'HasInt'
+  // CHECK-NEXT: CXXRecord{{.*}} 'HasInt'
+  // CHECK-NEXT: ParmVarDecl{{.*}} t 'HasInt'
+  // CHECK-NEXT: CompoundStmt
+
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: <<<NULL>>
+  // CHECK-NEXT: async clause
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int'
+  // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int'
+  // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt'
+  //
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: <<<NULL>>
+  // CHECK-NEXT: async clause
+  //
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: <<<NULL>>
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'char' <UserDefinedConversion>
+  // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char'
+  // CHECK-NEXT: MemberExpr{{.*}}.operator char
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar{{.*}} 't' 'HasInt'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int'
+  // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int'
+  // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt'
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '>'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int'
+  // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int'
+  // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' <IntegralCast>
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'char' <UserDefinedConversion>
+  // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char'
+  // CHECK-NEXT: MemberExpr{{.*}}.operator char
+  // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar{{.*}} 't' 'HasInt'
+  //
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: <<<NULL>>
+  // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::IntTy':'int'
+  // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::IntTy':'int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int'
+  // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int'
+  // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt'
+  // CHECK-NEXT: if clause
+  // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<'
+  // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::IntTy':'int'
+  // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::IntTy':'int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int'
+  // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::ShortTy':'short'
+  // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::ShortTy':'short'
+  //
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::ShortTy':'short'
+  // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::ShortTy':'short'
+  // CHECK-NEXT: CallExpr{{.*}}'int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_int'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int'
+  // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int'
+  // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt'
+  //
+  // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait
+  // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::ShortTy':'short'
+  // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::ShortTy':'short'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'int'
+  // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int'
+  // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt'
+  // CHECK-NEXT: CallExpr{{.*}}'long'
+  // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr{{.*}}'some_long'
+}
+
+struct HasInt {
+  using IntTy = int;
+  using ShortTy = short;
+  static constexpr int value = 1;
+
+  operator char();
+};
+void use() {
+  TemplFunc(HasInt{});
+}
+#endif

diff  --git a/clang/test/SemaOpenACC/wait-construct.cpp b/clang/test/SemaOpenACC/wait-construct.cpp
new file mode 100644
index 00000000000000..a68fc54b6e8f27
--- /dev/null
+++ b/clang/test/SemaOpenACC/wait-construct.cpp
@@ -0,0 +1,95 @@
+// 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() {
+  int arr[5];
+#pragma acc wait(getS(), getI())
+#pragma acc wait(devnum:getS(): getI())
+#pragma acc wait(devnum:getS(): queues: getI(), getS())
+#pragma acc wait(devnum:getS(): getI(), getS())
+
+  // expected-error at +1{{OpenACC directive 'wait' requires expression of integer type ('struct NotConvertible' invalid)}}
+#pragma acc wait(devnum:NC : 5)
+  // expected-error at +1{{OpenACC directive 'wait' requires expression of integer type ('struct NotConvertible' invalid)}}
+#pragma acc wait(devnum:5 : NC)
+  // expected-error at +3{{OpenACC directive 'wait' requires expression of integer type ('int[5]' invalid)}}
+  // expected-error at +2{{OpenACC directive 'wait' requires expression of integer type ('int[5]' invalid)}}
+  // expected-error at +1{{OpenACC directive 'wait' requires expression of integer type ('struct NotConvertible' invalid)}}
+#pragma acc wait(devnum:arr : queues: arr, NC, 5)
+
+  // 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 wait(Ambiguous)
+
+  // expected-error at +2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
+  // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
+#pragma acc wait(4, Explicit, 5)
+
+  // expected-error at +1{{use of undeclared identifier 'queues'}}
+#pragma acc wait(devnum: queues:  5)
+
+#pragma acc wait async
+#pragma acc wait async(getI())
+  // expected-error at +1{{OpenACC clause 'async' requires expression of integer type ('struct NotConvertible' invalid)}}
+#pragma acc wait async(NC)
+
+#pragma acc wait if(getI() < getS())
+  // expected-error at +1{{value of type 'struct NotConvertible' is not contextually convertible to 'bool'}}
+#pragma acc wait if(NC)
+
+}
+
+template<typename T>
+void TestInst() {
+  // expected-error at +4{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
+  // expected-note@#INST{{in instantiation of function template specialization}}
+  // expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
+  // 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-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'}}
+  // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
+#pragma acc wait(devnum:T::EXValue :queues:T::ACValue)
+
+  // expected-error at +1{{no member named 'Invalid' in 'HasInt'}}
+#pragma acc wait(queues: T::Invalid, T::Invalid2)
+
+  // expected-error at +3{{multiple conversions from expression type 'const 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 wait async(T::ACValue)
+
+#pragma acc wait if(T::value < T{})
+  // expected-error at +1{{value of type 'const ExplicitConvertOnly' is not contextually convertible to 'bool'}}
+#pragma acc wait if(T::EXValue)
+}
+
+struct HasInt {
+  using IntTy = int;
+  using ShortTy = short;
+  static constexpr int value = 1;
+  static constexpr AmbiguousConvert ACValue;
+  static constexpr ExplicitConvertOnly EXValue;
+
+  operator char();
+};
+void Inst() {
+  TestInst<HasInt>(); // #INST
+}

diff  --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 701582138e053d..9bdc4c9f8ce238 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -2189,6 +2189,7 @@ class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void>,
   void VisitOpenACCEnterDataConstruct(const OpenACCEnterDataConstruct *D);
   void VisitOpenACCExitDataConstruct(const OpenACCExitDataConstruct *D);
   void VisitOpenACCHostDataConstruct(const OpenACCHostDataConstruct *D);
+  void VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *D);
   void VisitOMPExecutableDirective(const OMPExecutableDirective *D);
   void VisitOMPLoopBasedDirective(const OMPLoopBasedDirective *D);
   void VisitOMPLoopDirective(const OMPLoopDirective *D);
@@ -3632,6 +3633,12 @@ void EnqueueVisitor::VisitOpenACCHostDataConstruct(
     EnqueueChildren(Clause);
 }
 
+void EnqueueVisitor::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *C) {
+  EnqueueChildren(C);
+  for (auto *Clause : C->clauses())
+    EnqueueChildren(Clause);
+}
+
 void EnqueueVisitor::VisitAnnotateAttr(const AnnotateAttr *A) {
   EnqueueChildren(A);
 }
@@ -6394,6 +6401,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
     return cxstring::createRef("OpenACCExitDataConstruct");
   case CXCursor_OpenACCHostDataConstruct:
     return cxstring::createRef("OpenACCHostDataConstruct");
+  case CXCursor_OpenACCWaitConstruct:
+    return cxstring::createRef("OpenACCWaitConstruct");
   }
 
   llvm_unreachable("Unhandled CXCursorKind");

diff  --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index 26935c45ce5f83..b9fd3b4c7f3645 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -900,6 +900,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
   case Stmt::OpenACCHostDataConstructClass:
     K = CXCursor_OpenACCHostDataConstruct;
     break;
+  case Stmt::OpenACCWaitConstructClass:
+    K = CXCursor_OpenACCWaitConstruct;
+    break;
   case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
     K = CXCursor_OMPTargetParallelGenericLoopDirective;
     break;


        


More information about the cfe-commits mailing list