From 63828a35da6f790f448b87b3eec61d294df31ccc Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Mon, 23 Mar 2020 10:41:08 -0400 Subject: [PATCH] [OPENMP50]Bassic support for exclusive clause. Added basic support (parsing/sema/serialization) for exclusive clause in scan directives. --- clang/include/clang/AST/OpenMPClause.h | 74 +++++++++++++++++++++++++++ clang/include/clang/AST/RecursiveASTVisitor.h | 7 +++ clang/include/clang/Basic/OpenMPKinds.def | 2 + clang/include/clang/Sema/Sema.h | 5 ++ clang/lib/AST/OpenMPClause.cpp | 28 ++++++++++ clang/lib/AST/StmtProfile.cpp | 3 ++ clang/lib/Basic/OpenMPKinds.cpp | 2 + clang/lib/CodeGen/CGStmtOpenMP.cpp | 1 + clang/lib/Parse/ParseOpenMP.cpp | 8 ++- clang/lib/Sema/SemaOpenMP.cpp | 37 ++++++++++++++ clang/lib/Sema/TreeTransform.h | 27 ++++++++++ clang/lib/Serialization/ASTReader.cpp | 13 +++++ clang/lib/Serialization/ASTWriter.cpp | 7 +++ clang/test/OpenMP/scan_ast_print.cpp | 4 +- clang/test/OpenMP/scan_messages.cpp | 30 +++++++---- clang/tools/libclang/CIndex.cpp | 3 ++ 16 files changed, 237 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index a781797..acf450f 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -6985,6 +6985,80 @@ public: } }; +/// This represents clause 'exclusive' in the '#pragma omp scan' directive. +/// +/// \code +/// #pragma omp scan exclusive(a,b) +/// \endcode +/// In this example directive '#pragma omp scan' has clause 'exclusive' +/// with the variables 'a' and 'b'. +class OMPExclusiveClause final + : public OMPVarListClause, + private llvm::TrailingObjects { + friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; + + /// Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + OMPExclusiveClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause(OMPC_exclusive, StartLoc, + LParenLoc, EndLoc, N) {} + + /// Build an empty clause. + /// + /// \param N Number of variables. + explicit OMPExclusiveClause(unsigned N) + : OMPVarListClause(OMPC_exclusive, SourceLocation(), + SourceLocation(), SourceLocation(), + N) {} + +public: + /// Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the original variables. + static OMPExclusiveClause *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef VL); + + /// Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + static OMPExclusiveClause *CreateEmpty(const ASTContext &C, unsigned N); + + child_range children() { + return child_range(reinterpret_cast(varlist_begin()), + reinterpret_cast(varlist_end())); + } + + const_child_range children() const { + auto Children = const_cast(this)->children(); + return const_child_range(Children.begin(), Children.end()); + } + + child_range used_children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range used_children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_exclusive; + } +}; + /// This class implements a simple visitor for OMPClause /// subclasses. template class Ptr, typename RetTy> diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 94f68f5..4bd489f 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3191,6 +3191,13 @@ bool RecursiveASTVisitor::VisitOMPInclusiveClause( } template +bool RecursiveASTVisitor::VisitOMPExclusiveClause( + OMPExclusiveClause *C) { + TRY_TO(VisitOMPClauseList(C)); + return true; +} + +template bool RecursiveASTVisitor::VisitOMPPrivateClause(OMPPrivateClause *C) { TRY_TO(VisitOMPClauseList(C)); for (auto *E : C->private_copies()) { diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index 1e4b2b1..ffffed5 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -285,9 +285,11 @@ OPENMP_CLAUSE(depobj, OMPDepobjClause) OPENMP_CLAUSE(destroy, OMPDestroyClause) OPENMP_CLAUSE(detach, OMPDetachClause) OPENMP_CLAUSE(inclusive, OMPInclusiveClause) +OPENMP_CLAUSE(exclusive, OMPExclusiveClause) // Clauses allowed for OpenMP directive 'scan'. OPENMP_SCAN_CLAUSE(inclusive) +OPENMP_SCAN_CLAUSE(exclusive) // Clauses allowed for OpenMP directive 'parallel'. OPENMP_PARALLEL_CLAUSE(if) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 03f3a1b..90ba856 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10506,6 +10506,11 @@ public: SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on well-formed 'exclusive' clause. + OMPClause *ActOnOpenMPExclusiveClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); /// Called on well-formed 'allocate' clause. OMPClause * ActOnOpenMPAllocateClause(Expr *Allocator, ArrayRef VarList, diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index de8fd67..5f9da85 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -147,6 +147,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: break; } @@ -235,6 +236,7 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: break; } @@ -1268,6 +1270,24 @@ OMPInclusiveClause *OMPInclusiveClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPInclusiveClause(N); } +OMPExclusiveClause *OMPExclusiveClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef VL) { + void *Mem = C.Allocate(totalSizeToAlloc(VL.size())); + auto *Clause = + new (Mem) OMPExclusiveClause(StartLoc, LParenLoc, EndLoc, VL.size()); + Clause->setVarRefs(VL); + return Clause; +} + +OMPExclusiveClause *OMPExclusiveClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(totalSizeToAlloc(N)); + return new (Mem) OMPExclusiveClause(N); +} + //===----------------------------------------------------------------------===// // OpenMP clauses printing methods //===----------------------------------------------------------------------===// @@ -1833,6 +1853,14 @@ void OMPClausePrinter::VisitOMPInclusiveClause(OMPInclusiveClause *Node) { } } +void OMPClausePrinter::VisitOMPExclusiveClause(OMPExclusiveClause *Node) { + if (!Node->varlist_empty()) { + OS << "exclusive"; + VisitOMPClauseList(Node, '('); + OS << ")"; + } +} + void OMPTraitInfo::getAsVariantMatchInfo( ASTContext &ASTCtx, llvm::omp::VariantMatchInfo &VMI) const { for (const OMPTraitSet &Set : Sets) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index a31a65f..cd39024 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -798,6 +798,9 @@ void OMPClauseProfiler::VisitOMPNontemporalClause( void OMPClauseProfiler::VisitOMPInclusiveClause(const OMPInclusiveClause *C) { VisitOMPClauseList(C); } +void OMPClauseProfiler::VisitOMPExclusiveClause(const OMPExclusiveClause *C) { + VisitOMPClauseList(C); +} void OMPClauseProfiler::VisitOMPOrderClause(const OMPOrderClause *C) {} } // namespace diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index a905dff..36e7f45 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -213,6 +213,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); @@ -449,6 +450,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index e05829f..bef36bf 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -4617,6 +4617,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index bb239c8..acc1e55 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2344,7 +2344,8 @@ bool Parser::ParseOpenMPSimpleVarList( /// from-clause | is_device_ptr-clause | task_reduction-clause | /// in_reduction-clause | allocator-clause | allocate-clause | /// acq_rel-clause | acquire-clause | release-clause | relaxed-clause | -/// depobj-clause | destroy-clause | detach-clause | inclusive-clause +/// depobj-clause | destroy-clause | detach-clause | inclusive-clause | +/// exclusive-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { @@ -2514,6 +2515,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_allocate: case OMPC_nontemporal: case OMPC_inclusive: + case OMPC_exclusive: Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective); break; case OMPC_device_type: @@ -3239,7 +3241,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, /// Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate', /// 'shared', 'copyin', 'copyprivate', 'flush', 'reduction', 'task_reduction', -/// 'in_reduction', 'nontemporal' or 'inclusive'. +/// 'in_reduction', 'nontemporal', 'exclusive' or 'inclusive'. /// /// private-clause: /// 'private' '(' list ')' @@ -3283,6 +3285,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, /// 'nontemporal' '(' list ')' /// inclusive-clause: /// 'inclusive' '(' list ')' +/// exclusive-clause: +/// 'exclusive' '(' list ')' /// /// For 'linear' clause linear-list may have the following forms: /// list diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 8c488da..d9a4a17 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -5100,6 +5100,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_order: case OMPC_destroy: case OMPC_inclusive: + case OMPC_exclusive: continue; case OMPC_allocator: case OMPC_flush: @@ -11084,6 +11085,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_order: case OMPC_destroy: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed."); } return Res; @@ -11820,6 +11822,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Unexpected OpenMP clause."); } return CaptureRegion; @@ -12258,6 +12261,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12482,6 +12486,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12713,6 +12718,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_order: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12923,6 +12929,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_inclusive: Res = ActOnOpenMPInclusiveClause(VarList, StartLoc, LParenLoc, EndLoc); break; + case OMPC_exclusive: + Res = ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_depobj: case OMPC_final: @@ -18008,3 +18017,31 @@ OMPClause *Sema::ActOnOpenMPInclusiveClause(ArrayRef VarList, return OMPInclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); } + +OMPClause *Sema::ActOnOpenMPExclusiveClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector Vars; + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + if (Res.second) + // It will be analyzed later. + Vars.push_back(RefExpr); + ValueDecl *D = Res.first; + if (!D) + continue; + + Vars.push_back(RefExpr); + } + + if (Vars.empty()) + return nullptr; + + return OMPExclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); +} diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 8a22eb8..3e6d67d 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2065,6 +2065,18 @@ public: EndLoc); } + /// Build a new OpenMP 'exclusive' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPExclusiveClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc, + EndLoc); + } + /// Build a new OpenMP 'order' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. @@ -9550,6 +9562,21 @@ TreeTransform::TransformOMPInclusiveClause(OMPInclusiveClause *C) { template OMPClause * +TreeTransform::TransformOMPExclusiveClause(OMPExclusiveClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPExclusiveClause( + Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); +} + +template +OMPClause * TreeTransform::TransformOMPOrderClause(OMPOrderClause *C) { return getDerived().RebuildOMPOrderClause(C->getKind(), C->getKindKwLoc(), C->getBeginLoc(), C->getLParenLoc(), diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index ac11177..77f15bc 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -11845,6 +11845,9 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_inclusive: C = OMPInclusiveClause::CreateEmpty(Context, Record.readInt()); break; + case OMPC_exclusive: + C = OMPExclusiveClause::CreateEmpty(Context, Record.readInt()); + break; case OMPC_order: C = new (Context) OMPOrderClause(); break; @@ -12665,6 +12668,16 @@ void OMPClauseReader::VisitOMPInclusiveClause(OMPInclusiveClause *C) { C->setVarRefs(Vars); } +void OMPClauseReader::VisitOMPExclusiveClause(OMPExclusiveClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); +} + void OMPClauseReader::VisitOMPOrderClause(OMPOrderClause *C) { C->setKind(Record.readEnum()); C->setLParenLoc(Record.readSourceLocation()); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index a5d5b0f..9ccebae 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6611,6 +6611,13 @@ void OMPClauseWriter::VisitOMPInclusiveClause(OMPInclusiveClause *C) { Record.AddStmt(VE); } +void OMPClauseWriter::VisitOMPExclusiveClause(OMPExclusiveClause *C) { + Record.push_back(C->varlist_size()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); +} + void OMPClauseWriter::VisitOMPOrderClause(OMPOrderClause *C) { Record.writeEnum(C->getKind()); Record.AddSourceLocation(C->getLParenLoc()); diff --git a/clang/test/OpenMP/scan_ast_print.cpp b/clang/test/OpenMP/scan_ast_print.cpp index efcaa2d..4b9eca6 100644 --- a/clang/test/OpenMP/scan_ast_print.cpp +++ b/clang/test/OpenMP/scan_ast_print.cpp @@ -39,11 +39,11 @@ int main(int argc, char **argv) { // CHECK: static int a; #pragma omp for simd for (int i = 0; i < 10; ++i) { -#pragma omp scan inclusive(a) +#pragma omp scan exclusive(a, argc) } // CHECK-NEXT: #pragma omp for simd // CHECK-NEXT: for (int i = 0; i < 10; ++i) { -// CHECK-NEXT: #pragma omp scan inclusive(a){{$}} +// CHECK-NEXT: #pragma omp scan exclusive(a,argc){{$}} return tmain(argc) + tmain(argv[0][0]) + a; } diff --git a/clang/test/OpenMP/scan_messages.cpp b/clang/test/OpenMP/scan_messages.cpp index 3be998d..9f09385 100644 --- a/clang/test/OpenMP/scan_messages.cpp +++ b/clang/test/OpenMP/scan_messages.cpp @@ -54,25 +54,25 @@ T tmain(T argc) { #pragma omp simd for (int i = 0; i < 10; ++i) switch (argc) { -#pragma omp scan inclusive(argc) // expected-note 2 {{previous 'scan' directive used here}} +#pragma omp scan exclusive(argc) // expected-note 2 {{previous 'scan' directive used here}} case 1: -#pragma omp scan inclusive(argc) // expected-error {{exactly one 'scan' directive must appear in the loop body of an enclosing directive}} +#pragma omp scan exclusive(argc) // expected-error {{exactly one 'scan' directive must appear in the loop body of an enclosing directive}} break; default: { -#pragma omp scan inclusive(argc) // expected-error {{exactly one 'scan' directive must appear in the loop body of an enclosing directive}} +#pragma omp scan exclusive(argc) // expected-error {{exactly one 'scan' directive must appear in the loop body of an enclosing directive}} } break; } #pragma omp simd for (int i = 0; i < 10; ++i) for (;;) -#pragma omp scan inclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} +#pragma omp scan exclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} for (;;) { -#pragma omp scan inclusive(argc) +#pragma omp scan exclusive(argc) } #pragma omp simd for (int i = 0; i < 10; ++i) { label: -#pragma omp scan inclusive(argc) +#pragma omp scan exclusive(argc) } #pragma omp simd for (int i = 0; i < 10; ++i) { @@ -91,6 +91,16 @@ int main(int argc, char **argv) { } #pragma omp simd for (int i = 0; i < 10; ++i) { +#pragma omp scan exclusive(argc) inclusive(argc) // expected-error {{exactly one of 'inclusive' or 'exclusive' clauses is expected}} + ; + } +#pragma omp simd + for (int i = 0; i < 10; ++i) { +#pragma omp scan exclusive(argc) exclusive(argc) // expected-error {{exactly one of 'inclusive' or 'exclusive' clauses is expected}} + ; + } +#pragma omp simd + for (int i = 0; i < 10; ++i) { #pragma omp scan untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp scan'}} expected-error {{exactly one of 'inclusive' or 'exclusive' clauses is expected}} #pragma omp scan unknown // expected-warning {{extra tokens at the end of '#pragma omp scan' are ignored}} expected-error {{exactly one of 'inclusive' or 'exclusive' clauses is expected}} } @@ -117,18 +127,18 @@ int main(int argc, char **argv) { #pragma omp simd for (int i = 0; i < 10; ++i) do { -#pragma omp scan inclusive(argc) +#pragma omp scan exclusive(argc) } while (argc); #pragma omp simd for (int i = 0; i < 10; ++i) switch (argc) -#pragma omp scan inclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} +#pragma omp scan exclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} switch (argc) case 1: -#pragma omp scan inclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} +#pragma omp scan exclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} switch (argc) case 1: { -#pragma omp scan inclusive(argc) +#pragma omp scan exclusive(argc) } #pragma omp simd for (int i = 0; i < 10; ++i) diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 31a0f36..ae7fd42 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2312,6 +2312,9 @@ void OMPClauseEnqueue::VisitOMPClauseList(T *Node) { void OMPClauseEnqueue::VisitOMPInclusiveClause(const OMPInclusiveClause *C) { VisitOMPClauseList(C); } +void OMPClauseEnqueue::VisitOMPExclusiveClause(const OMPExclusiveClause *C) { + VisitOMPClauseList(C); +} void OMPClauseEnqueue::VisitOMPAllocateClause(const OMPAllocateClause *C) { VisitOMPClauseList(C); Visitor->AddStmt(C->getAllocator()); -- 2.7.4