[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