From: Alexey Bataev Date: Thu, 6 Mar 2014 06:15:19 +0000 (+0000) Subject: [OPENMP] Clause 'num_threads' X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a3eb9f5811b85ce1b5158ad6691ea0a61dbb247d;p=clang [OPENMP] Clause 'num_threads' git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@203087 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h index cbefbdc287..f3481c15bf 100644 --- a/include/clang/AST/DataRecursiveASTVisitor.h +++ b/include/clang/AST/DataRecursiveASTVisitor.h @@ -2370,6 +2370,13 @@ bool DataRecursiveASTVisitor::VisitOMPIfClause(OMPIfClause *C) { return true; } +template +bool DataRecursiveASTVisitor::VisitOMPNumThreadsClause( + OMPNumThreadsClause *C) { + TraverseStmt(C->getNumThreads()); + return true; +} + template bool DataRecursiveASTVisitor::VisitOMPDefaultClause(OMPDefaultClause *C) { return true; diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h index 4a3c9e0a49..c710cddf5a 100644 --- a/include/clang/AST/OpenMPClause.h +++ b/include/clang/AST/OpenMPClause.h @@ -186,6 +186,60 @@ public: StmtRange children() { return StmtRange(&Condition, &Condition + 1); } }; +/// \brief This represents 'num_threads' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp parallel num_threads(6) +/// \endcode +/// In this example directive '#pragma omp parallel' has simple 'num_threads' +/// clause with number of threads '6'. +/// +class OMPNumThreadsClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Condition of the 'num_threads' clause. + Stmt *NumThreads; + + /// \brief Set condition. + /// + void setNumThreads(Expr *NThreads) { NumThreads = NThreads; } + +public: + /// \brief Build 'num_threads' clause with condition \a NumThreads. + /// + /// \param NumThreads Number of threads for the construct. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// + OMPNumThreadsClause(Expr *NumThreads, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OMPClause(OMPC_num_threads, StartLoc, EndLoc), LParenLoc(LParenLoc), + NumThreads(NumThreads) {} + + /// \brief Build an empty clause. + /// + OMPNumThreadsClause() + : OMPClause(OMPC_num_threads, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), NumThreads(0) {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Returns number of threads. + Expr *getNumThreads() const { return cast_or_null(NumThreads); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_num_threads; + } + + StmtRange children() { return StmtRange(&NumThreads, &NumThreads + 1); } +}; + /// \brief This represents 'default' clause in the '#pragma omp ...' directive. /// /// \code diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 8e3c9f724d..92c26c4235 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -2394,6 +2394,13 @@ bool RecursiveASTVisitor::VisitOMPIfClause(OMPIfClause *C) { return true; } +template +bool RecursiveASTVisitor::VisitOMPNumThreadsClause( + OMPNumThreadsClause *C) { + TraverseStmt(C->getNumThreads()); + return true; +} + template bool RecursiveASTVisitor::VisitOMPDefaultClause(OMPDefaultClause *C) { return true; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 1e2a5aae80..36ebc82af4 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -6866,6 +6866,20 @@ def note_omp_predetermined_dsa : Note< "predetermined as %0">; def err_omp_not_for : Error< "statement after '#pragma omp %0' must be a for loop">; +def err_omp_negative_expression_in_clause : Error< + "argument to '%0' clause must be a positive integer value">; +def err_omp_not_integral : Error< + "expression must have integral or unscoped enumeration " + "type, not %0">; +def err_omp_incomplete_type : Error< + "expression has incomplete class type %0">; +def err_omp_explicit_conversion : Error< + "expression requires explicit conversion from %0 to %1">; +def note_omp_conversion_here : Note< + "conversion to %select{integral|enumeration}0 type %1 declared here">; +def err_omp_ambiguous_conversion : Error< + "ambiguous conversion from type %0 to an integral or unscoped " + "enumeration type">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def index 41b77ef843..da43a58d17 100644 --- a/include/clang/Basic/OpenMPKinds.def +++ b/include/clang/Basic/OpenMPKinds.def @@ -36,6 +36,7 @@ OPENMP_DIRECTIVE(simd) // OpenMP clauses. OPENMP_CLAUSE(if, OMPIfClause) +OPENMP_CLAUSE(num_threads, OMPNumThreadsClause) OPENMP_CLAUSE(default, OMPDefaultClause) OPENMP_CLAUSE(private, OMPPrivateClause) OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause) @@ -43,6 +44,7 @@ OPENMP_CLAUSE(shared, OMPSharedClause) // Clauses allowed for OpenMP directives. OPENMP_PARALLEL_CLAUSE(if) +OPENMP_PARALLEL_CLAUSE(num_threads) OPENMP_PARALLEL_CLAUSE(default) OPENMP_PARALLEL_CLAUSE(private) OPENMP_PARALLEL_CLAUSE(firstprivate) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index b56995ba82..ffbaa48cc9 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -7078,6 +7078,7 @@ private: /// \brief Initialization of data-sharing attributes stack. void InitDataSharingAttributesStack(); void DestroyDataSharingAttributesStack(); + ExprResult PerformImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op); public: /// \brief Called on start of new data sharing attribute block. void StartOpenMPDSABlock(OpenMPDirectiveKind K, @@ -7128,6 +7129,11 @@ public: OMPClause *ActOnOpenMPIfClause(Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'num_threads' clause. + OMPClause *ActOnOpenMPNumThreadsClause(Expr *NumThreads, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, unsigned Argument, diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index eb983b2db0..748a40160d 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -612,6 +612,12 @@ void OMPClausePrinter::VisitOMPIfClause(OMPIfClause *Node) { OS << ")"; } +void OMPClausePrinter::VisitOMPNumThreadsClause(OMPNumThreadsClause *Node) { + OS << "num_threads("; + Node->getNumThreads()->printPretty(OS, 0, Policy, 0); + OS << ")"; +} + void OMPClausePrinter::VisitOMPDefaultClause(OMPDefaultClause *Node) { OS << "default(" << getOpenMPSimpleClauseTypeName(OMPC_default, Node->getDefaultKind()) diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index e9b1da49dd..b871ffb73b 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -270,6 +270,11 @@ void OMPClauseProfiler::VisitOMPIfClause(const OMPIfClause *C) { Profiler->VisitStmt(C->getCondition()); } +void OMPClauseProfiler::VisitOMPNumThreadsClause(const OMPNumThreadsClause *C) { + if (C->getNumThreads()) + Profiler->VisitStmt(C->getNumThreads()); +} + void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { } template diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp index 99c2fd2ebd..0a25b240cb 100644 --- a/lib/Basic/OpenMPKinds.cpp +++ b/lib/Basic/OpenMPKinds.cpp @@ -78,6 +78,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: + case OMPC_num_threads: case OMPC_private: case OMPC_firstprivate: case OMPC_shared: @@ -102,6 +103,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: + case OMPC_num_threads: case OMPC_private: case OMPC_firstprivate: case OMPC_shared: diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index df8f17bd13..037dd36fc7 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -272,8 +272,10 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, switch (CKind) { case OMPC_if: + case OMPC_num_threads: // OpenMP [2.5, Restrictions] // At most one if clause can appear on the directive. + // At most one num_threads clause can appear on the directive. if (!FirstClause) { Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind); diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 9ee89a3169..a377815ffa 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -758,6 +758,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, case OMPC_if: Res = ActOnOpenMPIfClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_num_threads: + Res = ActOnOpenMPNumThreadsClause(Expr, StartLoc, LParenLoc, EndLoc); + break; case OMPC_default: case OMPC_private: case OMPC_firstprivate: @@ -790,6 +793,81 @@ OMPClause *Sema::ActOnOpenMPIfClause(Expr *Condition, return new (Context) OMPIfClause(ValExpr, StartLoc, LParenLoc, EndLoc); } +ExprResult Sema::PerformImplicitIntegerConversion(SourceLocation Loc, + Expr *Op) { + if (!Op) + return ExprError(); + + class IntConvertDiagnoser : public ICEConvertDiagnoser { + public: + IntConvertDiagnoser() + : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false, + false, true) {} + virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_omp_not_integral) << T; + } + virtual SemaDiagnosticBuilder diagnoseIncomplete( + Sema &S, SourceLocation Loc, QualType T) { + return S.Diag(Loc, diag::err_omp_incomplete_type) << T; + } + virtual SemaDiagnosticBuilder diagnoseExplicitConv( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) { + return S.Diag(Loc, diag::err_omp_explicit_conversion) << T << ConvTy; + } + virtual SemaDiagnosticBuilder noteExplicitConv( + Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_omp_conversion_here) + << ConvTy->isEnumeralType() << ConvTy; + } + virtual SemaDiagnosticBuilder diagnoseAmbiguous( + Sema &S, SourceLocation Loc, QualType T) { + return S.Diag(Loc, diag::err_omp_ambiguous_conversion) << T; + } + virtual SemaDiagnosticBuilder noteAmbiguous( + Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_omp_conversion_here) + << ConvTy->isEnumeralType() << ConvTy; + } + virtual SemaDiagnosticBuilder diagnoseConversion( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) { + llvm_unreachable("conversion functions are permitted"); + } + } ConvertDiagnoser; + return PerformContextualImplicitConversion(Loc, Op, ConvertDiagnoser); +} + +OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + Expr *ValExpr = NumThreads; + if (!NumThreads->isValueDependent() && !NumThreads->isTypeDependent() && + !NumThreads->isInstantiationDependent() && + !NumThreads->containsUnexpandedParameterPack()) { + SourceLocation NumThreadsLoc = NumThreads->getLocStart(); + ExprResult Val = + PerformImplicitIntegerConversion(NumThreadsLoc, NumThreads); + if (Val.isInvalid()) + return 0; + + ValExpr = Val.take(); + + // OpenMP [2.5, Restrictions] + // The num_threads expression must evaluate to a positive integer value. + llvm::APSInt Result; + if (ValExpr->isIntegerConstantExpr(Result, Context) && + Result.isSigned() && !Result.isStrictlyPositive()) { + Diag(NumThreadsLoc, diag::err_omp_negative_expression_in_clause) + << "num_threads" << NumThreads->getSourceRange(); + return 0; + } + } + + return new (Context) OMPNumThreadsClause(ValExpr, StartLoc, LParenLoc, + EndLoc); +} + OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc, @@ -804,6 +882,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_if: + case OMPC_num_threads: case OMPC_private: case OMPC_firstprivate: case OMPC_shared: @@ -876,6 +955,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_if: + case OMPC_num_threads: case OMPC_default: case OMPC_threadprivate: case OMPC_unknown: diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index d164bdd650..ac5a678eeb 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1312,6 +1312,18 @@ public: LParenLoc, EndLoc); } + /// \brief Build a new OpenMP 'num_threads' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPNumThreadsClause(Expr *NumThreads, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPNumThreadsClause(NumThreads, StartLoc, + LParenLoc, EndLoc); + } + /// \brief Build a new OpenMP 'default' clause. /// /// By default, performs semantic analysis to build the new statement. @@ -6316,6 +6328,18 @@ TreeTransform::TransformOMPIfClause(OMPIfClause *C) { C->getLParenLoc(), C->getLocEnd()); } +template +OMPClause * +TreeTransform::TransformOMPNumThreadsClause(OMPNumThreadsClause *C) { + ExprResult NumThreads = getDerived().TransformExpr(C->getNumThreads()); + if (NumThreads.isInvalid()) + return 0; + return getDerived().RebuildOMPNumThreadsClause(NumThreads.take(), + C->getLocStart(), + C->getLParenLoc(), + C->getLocEnd()); +} + template OMPClause * TreeTransform::TransformOMPDefaultClause(OMPDefaultClause *C) { diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 3f83beb0a0..b83e8fa5ca 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1676,6 +1676,9 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_if: C = new (Context) OMPIfClause(); break; + case OMPC_num_threads: + C = new (Context) OMPNumThreadsClause(); + break; case OMPC_default: C = new (Context) OMPDefaultClause(); break; @@ -1701,6 +1704,11 @@ void OMPClauseReader::VisitOMPIfClause(OMPIfClause *C) { C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); } +void OMPClauseReader::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { + C->setNumThreads(Reader->Reader.ReadSubExpr()); + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); +} + void OMPClauseReader::VisitOMPDefaultClause(OMPDefaultClause *C) { C->setDefaultKind( static_cast(Record[Idx++])); diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 08228d0754..eb25d060e4 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1684,6 +1684,11 @@ void OMPClauseWriter::VisitOMPIfClause(OMPIfClause *C) { Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); } +void OMPClauseWriter::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { + Writer->Writer.AddStmt(C->getNumThreads()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); +} + void OMPClauseWriter::VisitOMPDefaultClause(OMPDefaultClause *C) { Record.push_back(C->getDefaultKind()); Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); diff --git a/test/OpenMP/parallel_ast_print.cpp b/test/OpenMP/parallel_ast_print.cpp index bd5171435e..beb29ec15a 100644 --- a/test/OpenMP/parallel_ast_print.cpp +++ b/test/OpenMP/parallel_ast_print.cpp @@ -8,61 +8,72 @@ void foo() {} +template +struct S { + operator T() {return T();} +}; template T tmain(T argc, T *argv) { T b = argc, c, d, e, f, g; static T a; + S s; #pragma omp parallel a=2; -#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (argc > 0) +#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (argc > 0) num_threads(C) foo(); -#pragma omp parallel if (C) +#pragma omp parallel if (C) num_threads(s) foo(); return 0; } -// CHECK: template int tmain(int argc, int *argv) { +// CHECK: template int tmain(int argc, int *argv) { // CHECK-NEXT: int b = argc, c, d, e, f, g; // CHECK-NEXT: static int a; +// CHECK-NEXT: S s; // CHECK-NEXT: #pragma omp parallel // CHECK-NEXT: a = 2; -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(5) // CHECK-NEXT: foo() -// CHECK-NEXT: #pragma omp parallel if(2) +// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) // CHECK-NEXT: foo() -// CHECK: template float tmain(float argc, float *argv) { -// CHECK-NEXT: float b = argc, c, d, e, f, g; -// CHECK-NEXT: static float a; +// CHECK: template long tmain(long argc, long *argv) { +// CHECK-NEXT: long b = argc, c, d, e, f, g; +// CHECK-NEXT: static long a; +// CHECK-NEXT: S s; // CHECK-NEXT: #pragma omp parallel // CHECK-NEXT: a = 2; -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(1) // CHECK-NEXT: foo() -// CHECK-NEXT: #pragma omp parallel if(0) +// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) // CHECK-NEXT: foo() // CHECK: template T tmain(T argc, T *argv) { // CHECK-NEXT: T b = argc, c, d, e, f, g; // CHECK-NEXT: static T a; +// CHECK-NEXT: S s; // CHECK-NEXT: #pragma omp parallel // CHECK-NEXT: a = 2; -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(C) // CHECK-NEXT: foo() -// CHECK-NEXT: #pragma omp parallel if(C) +// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) // CHECK-NEXT: foo() +enum Enum { }; + int main (int argc, char **argv) { - float x; + long x; int b = argc, c, d, e, f, g; static int a; -// CHECK: static int a; + Enum ee; +// CHECK: Enum ee; #pragma omp parallel // CHECK-NEXT: #pragma omp parallel a=2; // CHECK-NEXT: a = 2; -#pragma omp parallel default(none), private(argc,b) firstprivate(argv) if (argc > 0) -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(argc > 0) +#pragma omp parallel default(none), private(argc,b) firstprivate(argv) if (argc > 0) num_threads(ee) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(argc > 0) num_threads(ee) foo(); // CHECK-NEXT: foo(); - return tmain(b, &b) + tmain(x, &x); + return tmain(b, &b) + tmain(x, &x); } #endif diff --git a/test/OpenMP/parallel_num_threads_messages.cpp b/test/OpenMP/parallel_num_threads_messages.cpp new file mode 100644 index 0000000000..facca5e358 --- /dev/null +++ b/test/OpenMP/parallel_num_threads_messages.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +template // expected-note {{declared here}} +T tmain(T argc, S **argv) { + #pragma omp parallel num_threads // expected-error {{expected '(' after 'num_threads'}} + #pragma omp parallel num_threads ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel num_threads () // expected-error {{expected expression}} + #pragma omp parallel num_threads (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel num_threads (argc)) // expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}} + #pragma omp parallel num_threads ((argc > 0) ? argv[1] : argv[2]) // expected-error 2 {{expression must have integral or unscoped enumeration type, not 'char *'}} + #pragma omp parallel num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a positive integer value}} + #pragma omp parallel num_threads (S) // expected-error {{'S' does not refer to a value}} + #pragma omp parallel num_threads (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2 {{expression must have integral or unscoped enumeration type, not 'char *'}} + #pragma omp parallel num_threads (argc) + #pragma omp parallel num_threads (N) // expected-error {{argument to 'num_threads' clause must be a positive integer value}} + foo(); + + return argc; +} + +int main(int argc, char **argv) { + #pragma omp parallel num_threads // expected-error {{expected '(' after 'num_threads'}} + #pragma omp parallel num_threads ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel num_threads () // expected-error {{expected expression}} + #pragma omp parallel num_threads (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel num_threads (argc)) // expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}} + #pragma omp parallel num_threads (argc > 0 ? argv[1] : argv[2]) // expected-error {{integral }} + #pragma omp parallel num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a positive integer value}} + #pragma omp parallel num_threads (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp parallel num_threads (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} + #pragma omp parallel num_threads (num_threads(tmain(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}} expected-note {{in instantiation of function template specialization 'tmain' requested here}} + foo(); + + return tmain(argc, argv); // expected-note {{in instantiation of function template specialization 'tmain' requested here}} +} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index b5507a6349..1c24e6b7b2 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1936,6 +1936,10 @@ void OMPClauseEnqueue::VisitOMPIfClause(const OMPIfClause *C) { Visitor->AddStmt(C->getCondition()); } +void OMPClauseEnqueue::VisitOMPNumThreadsClause(const OMPNumThreadsClause *C) { + Visitor->AddStmt(C->getNumThreads()); +} + void OMPClauseEnqueue::VisitOMPDefaultClause(const OMPDefaultClause *C) { } template