From 87933c7ced4fb99bb9cf6cea4d87cec2825aea7c Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Fri, 18 Sep 2015 08:07:34 +0000 Subject: [PATCH] [OPENMP 4.0] Add 'if' clause for 'cancel' directive. Add parsing, sema analysis and codegen for 'if' clause in 'cancel' directive. llvm-svn: 247976 --- clang/include/clang/AST/StmtOpenMP.h | 24 +++++---- clang/include/clang/Basic/OpenMPKinds.def | 7 +++ clang/include/clang/Sema/Sema.h | 3 +- clang/lib/AST/Stmt.cpp | 17 +++--- clang/lib/AST/StmtPrinter.cpp | 2 +- clang/lib/Basic/OpenMPKinds.cpp | 11 +++- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 52 ++++++++++-------- clang/lib/CodeGen/CGOpenMPRuntime.h | 3 ++ clang/lib/CodeGen/CGStmtOpenMP.cpp | 10 +++- clang/lib/Sema/SemaOpenMP.cpp | 12 +++-- clang/lib/Serialization/ASTReaderStmt.cpp | 5 +- clang/lib/Serialization/ASTWriterStmt.cpp | 1 + clang/test/OpenMP/cancel_ast_print.cpp | 8 +-- clang/test/OpenMP/cancel_codegen.cpp | 18 ++++++- clang/test/OpenMP/cancel_if_messages.cpp | 66 +++++++++++++++++++++++ 15 files changed, 186 insertions(+), 53 deletions(-) create mode 100644 clang/test/OpenMP/cancel_if_messages.cpp diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index 3ab26cd05d1b..7f4ac86a029f 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -2127,17 +2127,21 @@ class OMPCancelDirective : public OMPExecutableDirective { /// /// \param StartLoc Starting location of the directive kind. /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. /// - OMPCancelDirective(SourceLocation StartLoc, SourceLocation EndLoc) + OMPCancelDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) : OMPExecutableDirective(this, OMPCancelDirectiveClass, OMPD_cancel, - StartLoc, EndLoc, 0, 0), + StartLoc, EndLoc, NumClauses, 0), CancelRegion(OMPD_unknown) {} /// \brief Build an empty directive. /// - explicit OMPCancelDirective() + /// \param NumClauses Number of clauses. + explicit OMPCancelDirective(unsigned NumClauses) : OMPExecutableDirective(this, OMPCancelDirectiveClass, OMPD_cancel, - SourceLocation(), SourceLocation(), 0, 0), + SourceLocation(), SourceLocation(), NumClauses, + 0), CancelRegion(OMPD_unknown) {} /// \brief Set cancel region for current cancellation point. @@ -2150,17 +2154,19 @@ public: /// \param C AST context. /// \param StartLoc Starting location of the directive kind. /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. /// - static OMPCancelDirective *Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation EndLoc, - OpenMPDirectiveKind CancelRegion); + static OMPCancelDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, OpenMPDirectiveKind CancelRegion); /// \brief Creates an empty directive. /// /// \param C AST context. + /// \param NumClauses Number of clauses. /// - static OMPCancelDirective *CreateEmpty(const ASTContext &C, EmptyShell); + static OMPCancelDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); /// \brief Get cancellation region for the current cancellation point. OpenMPDirectiveKind getCancelRegion() const { return CancelRegion; } diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index 1d274c84c946..a1bcc13404dd 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -63,6 +63,9 @@ #ifndef OPENMP_TEAMS_CLAUSE # define OPENMP_TEAMS_CLAUSE(Name) #endif +#ifndef OPENMP_CANCEL_CLAUSE +# define OPENMP_CANCEL_CLAUSE(Name) +#endif #ifndef OPENMP_DEFAULT_KIND # define OPENMP_DEFAULT_KIND(Name) #endif @@ -197,6 +200,9 @@ OPENMP_SINGLE_CLAUSE(firstprivate) OPENMP_SINGLE_CLAUSE(copyprivate) OPENMP_SINGLE_CLAUSE(nowait) +// Clauses allowed for OpenMP directive 'cancel'. +OPENMP_CANCEL_CLAUSE(if) + // Static attributes for 'default' clause. OPENMP_DEFAULT_KIND(none) OPENMP_DEFAULT_KIND(shared) @@ -313,6 +319,7 @@ OPENMP_TEAMS_CLAUSE(reduction) #undef OPENMP_DIRECTIVE #undef OPENMP_DIRECTIVE_EXT #undef OPENMP_CLAUSE +#undef OPENMP_CANCEL_CLAUSE #undef OPENMP_SINGLE_CLAUSE #undef OPENMP_SECTIONS_CLAUSE #undef OPENMP_PARALLEL_CLAUSE diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 273c729a8c36..a7b74172a7e7 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7884,7 +7884,8 @@ public: SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); /// \brief Called on well-formed '\#pragma omp cancel'. - StmtResult ActOnOpenMPCancelDirective(SourceLocation StartLoc, + StmtResult ActOnOpenMPCancelDirective(ArrayRef Clauses, + SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 265b72904069..58996cd6e68e 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -2128,22 +2128,27 @@ OMPCancellationPointDirective::CreateEmpty(const ASTContext &C, EmptyShell) { OMPCancelDirective * OMPCancelDirective::Create(const ASTContext &C, SourceLocation StartLoc, - SourceLocation EndLoc, + SourceLocation EndLoc, ArrayRef Clauses, OpenMPDirectiveKind CancelRegion) { - unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPCancelDirective), - llvm::alignOf()); + unsigned Size = llvm::RoundUpToAlignment( + sizeof(OMPCancelDirective) + sizeof(OMPClause *) * Clauses.size(), + llvm::alignOf()); void *Mem = C.Allocate(Size); - OMPCancelDirective *Dir = new (Mem) OMPCancelDirective(StartLoc, EndLoc); + OMPCancelDirective *Dir = + new (Mem) OMPCancelDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); Dir->setCancelRegion(CancelRegion); return Dir; } OMPCancelDirective *OMPCancelDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell) { - unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPCancelDirective), + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPCancelDirective) + + sizeof(OMPClause *) * NumClauses, llvm::alignOf()); void *Mem = C.Allocate(Size); - return new (Mem) OMPCancelDirective(); + return new (Mem) OMPCancelDirective(NumClauses); } OMPFlushDirective *OMPFlushDirective::Create(const ASTContext &C, diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 173b5c7fcfa5..4a29d38d5b8f 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -991,7 +991,7 @@ void StmtPrinter::VisitOMPCancellationPointDirective( void StmtPrinter::VisitOMPCancelDirective(OMPCancelDirective *Node) { Indent() << "#pragma omp cancel " - << getOpenMPDirectiveName(Node->getCancelRegion()); + << getOpenMPDirectiveName(Node->getCancelRegion()) << " "; PrintOMPExecutableDirective(Node); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index e09c0a9e7f7e..30ea09a9f59d 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -360,6 +360,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, #define OPENMP_TEAMS_CLAUSE(Name) \ case OMPC_##Name: \ return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_cancel: + switch (CKind) { +#define OPENMP_CANCEL_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; #include "clang/Basic/OpenMPKinds.def" default: break; @@ -375,7 +385,6 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, case OMPD_taskwait: case OMPD_taskgroup: case OMPD_cancellation_point: - case OMPD_cancel: case OMPD_ordered: break; } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index f7e1d03e7e9b..7251bd3ef666 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -2914,6 +2914,7 @@ void CGOpenMPRuntime::emitCancellationPointCall( } void CGOpenMPRuntime::emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc, + const Expr *IfCond, OpenMPDirectiveKind CancelRegion) { // Build call kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid, // kmp_int32 cncl_kind); @@ -2921,27 +2922,34 @@ void CGOpenMPRuntime::emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc, dyn_cast_or_null(CGF.CapturedStmtInfo)) { if (OMPRegionInfo->getDirectiveKind() == OMPD_single) return; - llvm::Value *Args[] = { - emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), - CGF.Builder.getInt32(getCancellationKind(CancelRegion))}; - // Ignore return result until untied tasks are supported. - auto *Result = - CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_cancel), Args); - // if (__kmpc_cancel()) { - // __kmpc_cancel_barrier(); - // exit from construct; - // } - auto *ExitBB = CGF.createBasicBlock(".cancel.exit"); - auto *ContBB = CGF.createBasicBlock(".cancel.continue"); - auto *Cmp = CGF.Builder.CreateIsNotNull(Result); - CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB); - CGF.EmitBlock(ExitBB); - // __kmpc_cancel_barrier(); - emitBarrierCall(CGF, Loc, OMPD_unknown, /*EmitChecks=*/false); - // exit from construct; - auto CancelDest = - CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind()); - CGF.EmitBranchThroughCleanup(CancelDest); - CGF.EmitBlock(ContBB, /*IsFinished=*/true); + auto &&ThenGen = [this, Loc, CancelRegion, + OMPRegionInfo](CodeGenFunction &CGF) { + llvm::Value *Args[] = { + emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), + CGF.Builder.getInt32(getCancellationKind(CancelRegion))}; + // Ignore return result until untied tasks are supported. + auto *Result = + CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_cancel), Args); + // if (__kmpc_cancel()) { + // __kmpc_cancel_barrier(); + // exit from construct; + // } + auto *ExitBB = CGF.createBasicBlock(".cancel.exit"); + auto *ContBB = CGF.createBasicBlock(".cancel.continue"); + auto *Cmp = CGF.Builder.CreateIsNotNull(Result); + CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB); + CGF.EmitBlock(ExitBB); + // __kmpc_cancel_barrier(); + emitBarrierCall(CGF, Loc, OMPD_unknown, /*EmitChecks=*/false); + // exit from construct; + auto CancelDest = + CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind()); + CGF.EmitBranchThroughCleanup(CancelDest); + CGF.EmitBlock(ContBB, /*IsFinished=*/true); + }; + if (IfCond) + emitOMPIfClause(CGF, IfCond, ThenGen, [](CodeGenFunction &) {}); + else + ThenGen(CGF); } } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h index b9ad6432e9af..011006a3f815 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -718,9 +718,12 @@ public: OpenMPDirectiveKind CancelRegion); /// \brief Emit code for 'cancel' construct. + /// \param IfCond Condition in the associated 'if' clause, if it was + /// specified, nullptr otherwise. /// \param CancelRegion Region kind for which the cancel must be emitted. /// virtual void emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc, + const Expr *IfCond, OpenMPDirectiveKind CancelRegion); }; diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 70f86385d572..51136413e053 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -2262,7 +2262,15 @@ void CodeGenFunction::EmitOMPCancellationPointDirective( } void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) { - CGM.getOpenMPRuntime().emitCancelCall(*this, S.getLocStart(), + const Expr *IfCond = nullptr; + for (const auto *C : S.getClausesOfKind()) { + if (C->getNameModifier() == OMPD_unknown || + C->getNameModifier() == OMPD_cancel) { + IfCond = C->getCondition(); + break; + } + } + CGM.getOpenMPRuntime().emitCancelCall(*this, S.getLocStart(), IfCond, S.getCancelRegion()); } diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index ed58e475fe71..3865f2773f98 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -2245,11 +2245,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Res = ActOnOpenMPCancellationPointDirective(StartLoc, EndLoc, CancelRegion); break; case OMPD_cancel: - assert(ClausesWithImplicit.empty() && - "No clauses are allowed for 'omp cancel' directive"); assert(AStmt == nullptr && "No associated statement allowed for 'omp cancel' directive"); - Res = ActOnOpenMPCancelDirective(StartLoc, EndLoc, CancelRegion); + Res = ActOnOpenMPCancelDirective(ClausesWithImplicit, StartLoc, EndLoc, + CancelRegion); + AllowedNameModifiers.push_back(OMPD_cancel); break; case OMPD_target_data: Res = ActOnOpenMPTargetDataDirective(ClausesWithImplicit, AStmt, StartLoc, @@ -4909,7 +4909,8 @@ Sema::ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc, CancelRegion); } -StmtResult Sema::ActOnOpenMPCancelDirective(SourceLocation StartLoc, +StmtResult Sema::ActOnOpenMPCancelDirective(ArrayRef Clauses, + SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion) { if (CancelRegion != OMPD_parallel && CancelRegion != OMPD_for && @@ -4927,7 +4928,8 @@ StmtResult Sema::ActOnOpenMPCancelDirective(SourceLocation StartLoc, return StmtError(); } DSAStack->setParentCancelRegion(/*Cancel=*/true); - return OMPCancelDirective::Create(Context, StartLoc, EndLoc, CancelRegion); + return OMPCancelDirective::Create(Context, StartLoc, EndLoc, Clauses, + CancelRegion); } OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 5322a406168d..1bdd65cdf82f 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2317,6 +2317,8 @@ void ASTStmtReader::VisitOMPCancellationPointDirective( void ASTStmtReader::VisitOMPCancelDirective(OMPCancelDirective *D) { VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + ++Idx; VisitOMPExecutableDirective(D); D->setCancelRegion(static_cast(Record[Idx++])); } @@ -2938,7 +2940,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; case STMT_OMP_CANCEL_DIRECTIVE: - S = OMPCancelDirective::CreateEmpty(Context, Empty); + S = OMPCancelDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); break; case EXPR_CXX_OPERATOR_CALL: diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 7c0424cc878c..41e9f9699218 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2169,6 +2169,7 @@ void ASTStmtWriter::VisitOMPCancellationPointDirective( void ASTStmtWriter::VisitOMPCancelDirective(OMPCancelDirective *D) { VisitStmt(D); + Record.push_back(D->getNumClauses()); VisitOMPExecutableDirective(D); Record.push_back(D->getCancelRegion()); Code = serialization::STMT_OMP_CANCEL_DIRECTIVE; diff --git a/clang/test/OpenMP/cancel_ast_print.cpp b/clang/test/OpenMP/cancel_ast_print.cpp index f244c784e86e..007237a7fb98 100644 --- a/clang/test/OpenMP/cancel_ast_print.cpp +++ b/clang/test/OpenMP/cancel_ast_print.cpp @@ -10,11 +10,11 @@ int main (int argc, char **argv) { // CHECK: int main(int argc, char **argv) { #pragma omp parallel { -#pragma omp cancel parallel +#pragma omp cancel parallel if(argc) } // CHECK: #pragma omp parallel // CHECK-NEXT: { -// CHECK-NEXT: #pragma omp cancel parallel +// CHECK-NEXT: #pragma omp cancel parallel if(argc) // CHECK-NEXT: } #pragma omp sections { @@ -26,11 +26,11 @@ int main (int argc, char **argv) { // CHECK: } #pragma omp for for (int i = 0; i < argc; ++i) { -#pragma omp cancel for +#pragma omp cancel for if(cancel:argc) } // CHECK: #pragma omp for // CHECK-NEXT: for (int i = 0; i < argc; ++i) { -// CHECK-NEXT: #pragma omp cancel for +// CHECK-NEXT: #pragma omp cancel for if(cancel: argc) // CHECK-NEXT: } #pragma omp task { diff --git a/clang/test/OpenMP/cancel_codegen.cpp b/clang/test/OpenMP/cancel_codegen.cpp index 9a99826217f4..c7eaa1a4a9f0 100644 --- a/clang/test/OpenMP/cancel_codegen.cpp +++ b/clang/test/OpenMP/cancel_codegen.cpp @@ -6,11 +6,12 @@ #ifndef HEADER #define HEADER +float flag; int main (int argc, char **argv) { // CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num( #pragma omp parallel { -#pragma omp cancel parallel +#pragma omp cancel parallel if(flag) argv[0][0] = argc; } // CHECK: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call( @@ -50,9 +51,13 @@ int main (int argc, char **argv) { // CHECK: call void @__kmpc_for_static_fini( #pragma omp for for (int i = 0; i < argc; ++i) { -#pragma omp cancel for +#pragma omp cancel for if(cancel: flag) } // CHECK: call void @__kmpc_for_static_init_4( +// CHECK: [[FLAG:%.+]] = load float, float* @{{.+}}, +// CHECK: [[BOOL:%.+]] = fcmp une float [[FLAG]], 0.000000e+00 +// CHECK: br i1 [[BOOL]], label %[[THEN:[^,]+]], label %[[ELSE:[^,]+]] +// CHECK: [[THEN]] // CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 [[GTID]], i32 2) // CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 // CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]] @@ -61,6 +66,8 @@ for (int i = 0; i < argc; ++i) { // CHECK: br label // CHECK: [[CONTINUE]] // CHECK: br label +// CHECK: [[ELSE]] +// CHECK: br label // CHECK: call void @__kmpc_for_static_fini( // CHECK: call void @__kmpc_barrier(%ident_t* #pragma omp task @@ -92,12 +99,19 @@ for (int i = 0; i < argc; ++i) { } // CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}}, +// CHECK: [[FLAG:%.+]] = load float, float* @{{.+}}, +// CHECK: [[BOOL:%.+]] = fcmp une float [[FLAG]], 0.000000e+00 +// CHECK: br i1 [[BOOL]], label %[[THEN:[^,]+]], label %[[ELSE:[^,]+]] +// CHECK: [[THEN]] // CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 1) // CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 // CHECK: br i1 [[CMP]], label %[[EXIT:[^,]+]], // CHECK: [[EXIT]] // CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* // CHECK: br label %[[RETURN:.+]] +// CHECK: [[ELSE]] +// CHECK: br label +// CHECK: call void @__kmpc_barrier // CHECK: [[RETURN]] // CHECK: ret void diff --git a/clang/test/OpenMP/cancel_if_messages.cpp b/clang/test/OpenMP/cancel_if_messages.cpp new file mode 100644 index 000000000000..8d1afc9ecddf --- /dev/null +++ b/clang/test/OpenMP/cancel_if_messages.cpp @@ -0,0 +1,66 @@ +// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +template // expected-note {{declared here}} +int tmain(T argc, S **argv) { + #pragma omp parallel + { + #pragma omp cancel parallel if // expected-error {{expected '(' after 'if'}} + #pragma omp cancel parallel if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if () // expected-error {{expected expression}} + #pragma omp cancel parallel if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp cancel' are ignored}} + #pragma omp cancel parallel if (argc > 0 ? argv[1] : argv[2]) + #pragma omp cancel parallel if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp cancel' cannot contain more than one 'if' clause}} + #pragma omp cancel parallel if (S) // expected-error {{'S' does not refer to a value}} + #pragma omp cancel parallel if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if(argc) + #pragma omp cancel parallel if(cancel // expected-warning {{missing ':' after directive name modifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if(cancel : // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if(cancel : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if(cancel : argc) + #pragma omp cancel parallel if(cancel : argc) if (for:argc) // expected-error {{directive name modifier 'for' is not allowed for '#pragma omp cancel'}} + #pragma omp cancel parallel if(cancel : argc) if (cancel:argc) // expected-error {{directive '#pragma omp cancel' cannot contain more than one 'if' clause with 'cancel' name modifier}} + #pragma omp cancel parallel if(cancel : argc) if (argc) // expected-error {{no more 'if' clause is allowed}} expected-note {{previous clause with directive name modifier specified here}} + foo(); + } + + return 0; +} + +int main(int argc, char **argv) { + #pragma omp parallel + { + #pragma omp cancel parallel if // expected-error {{expected '(' after 'if'}} + #pragma omp cancel parallel if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if () // expected-error {{expected expression}} + #pragma omp cancel parallel if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp cancel' are ignored}} + #pragma omp cancel parallel if (argc > 0 ? argv[1] : argv[2]) + #pragma omp cancel parallel if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp cancel' cannot contain more than one 'if' clause}} + #pragma omp cancel parallel if (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp cancel parallel if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if(if(tmain(argc, argv) // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if(cancel // expected-warning {{missing ':' after directive name modifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if(cancel : // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if(cancel : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp cancel parallel if(cancel : argc) + #pragma omp cancel parallel if(cancel : argc) if (for:argc) // expected-error {{directive name modifier 'for' is not allowed for '#pragma omp cancel'}} + #pragma omp cancel parallel if(cancel : argc) if (cancel:argc) // expected-error {{directive '#pragma omp cancel' cannot contain more than one 'if' clause with 'cancel' name modifier}} + #pragma omp cancel parallel if(cancel : argc) if (argc) // expected-error {{no more 'if' clause is allowed}} expected-note {{previous clause with directive name modifier specified here}} + foo(); + } + + return tmain(argc, argv); +}