]> granicus.if.org Git - clang/commitdiff
[OPENMP 4.0] Add 'if' clause for 'cancel' directive.
authorAlexey Bataev <a.bataev@hotmail.com>
Fri, 18 Sep 2015 08:07:34 +0000 (08:07 +0000)
committerAlexey Bataev <a.bataev@hotmail.com>
Fri, 18 Sep 2015 08:07:34 +0000 (08:07 +0000)
Add parsing, sema analysis and codegen for 'if' clause in 'cancel' directive.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@247976 91177308-0d34-0410-b5e6-96231b3b80d8

15 files changed:
include/clang/AST/StmtOpenMP.h
include/clang/Basic/OpenMPKinds.def
include/clang/Sema/Sema.h
lib/AST/Stmt.cpp
lib/AST/StmtPrinter.cpp
lib/Basic/OpenMPKinds.cpp
lib/CodeGen/CGOpenMPRuntime.cpp
lib/CodeGen/CGOpenMPRuntime.h
lib/CodeGen/CGStmtOpenMP.cpp
lib/Sema/SemaOpenMP.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
test/OpenMP/cancel_ast_print.cpp
test/OpenMP/cancel_codegen.cpp
test/OpenMP/cancel_if_messages.cpp [new file with mode: 0644]

index 3ab26cd05d1bbb430cd7b4433ffbfc790fba7e02..7f4ac86a029f2571eab70f80a7615f832abcb6d6 100644 (file)
@@ -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<OMPClause *> 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; }
index 1d274c84c946d05fd23e038a4d847b8863726b2a..a1bcc13404dd4e2beb291fd26c44f5f65a8e115c 100644 (file)
@@ -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
index 273c729a8c3604b8d96c2235b4de44567b47dcc4..a7b74172a7e76b3c8e0e31081c35f189bccb6dd7 100644 (file)
@@ -7884,7 +7884,8 @@ public:
                                         SourceLocation EndLoc,
                                         OpenMPDirectiveKind CancelRegion);
   /// \brief Called on well-formed '\#pragma omp cancel'.
-  StmtResult ActOnOpenMPCancelDirective(SourceLocation StartLoc,
+  StmtResult ActOnOpenMPCancelDirective(ArrayRef<OMPClause *> Clauses,
+                                        SourceLocation StartLoc,
                                         SourceLocation EndLoc,
                                         OpenMPDirectiveKind CancelRegion);
 
index 265b72904069f5eeefe97c1c1ec1290f775f0f85..58996cd6e68efc0c3866e2c199cfb97e0e335c57 100644 (file)
@@ -2128,22 +2128,27 @@ OMPCancellationPointDirective::CreateEmpty(const ASTContext &C, EmptyShell) {
 
 OMPCancelDirective *
 OMPCancelDirective::Create(const ASTContext &C, SourceLocation StartLoc,
-                           SourceLocation EndLoc,
+                           SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses,
                            OpenMPDirectiveKind CancelRegion) {
-  unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPCancelDirective),
-                                           llvm::alignOf<Stmt *>());
+  unsigned Size = llvm::RoundUpToAlignment(
+      sizeof(OMPCancelDirective) + sizeof(OMPClause *) * Clauses.size(),
+      llvm::alignOf<Stmt *>());
   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<Stmt *>());
   void *Mem = C.Allocate(Size);
-  return new (Mem) OMPCancelDirective();
+  return new (Mem) OMPCancelDirective(NumClauses);
 }
 
 OMPFlushDirective *OMPFlushDirective::Create(const ASTContext &C,
index 173b5c7fcfa504b3be493be3ddb6c19d18c45c3b..4a29d38d5b8f4533accc58d3058470864dc3abdf 100644 (file)
@@ -991,7 +991,7 @@ void StmtPrinter::VisitOMPCancellationPointDirective(
 
 void StmtPrinter::VisitOMPCancelDirective(OMPCancelDirective *Node) {
   Indent() << "#pragma omp cancel "
-           << getOpenMPDirectiveName(Node->getCancelRegion());
+           << getOpenMPDirectiveName(Node->getCancelRegion()) << " ";
   PrintOMPExecutableDirective(Node);
 }
 //===----------------------------------------------------------------------===//
index e09c0a9e7f7e5b02644934af60b18979ee672574..30ea09a9f59d7e3774dee00244399de537b7b8e4 100644 (file)
@@ -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;
   }
index f7e1d03e7e9b43653e912d5ef509bcda735c43ce..7251bd3ef66677d6b537f9be45b21898d4e00c0a 100644 (file)
@@ -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<CGOpenMPRegionInfo>(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);
   }
 }
index b9ad6432e9aff05e9425b6cc53f262789f22370a..011006a3f81559facdc24d4b0ae33a58a5c047a1 100644 (file)
@@ -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);
 };
 
index 70f86385d572543ae6b2bdfb35d6dc3f2c3b69c2..51136413e0533b5e195b4ca38d972a1bcb484823 100644 (file)
@@ -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<OMPIfClause>()) {
+    if (C->getNameModifier() == OMPD_unknown ||
+        C->getNameModifier() == OMPD_cancel) {
+      IfCond = C->getCondition();
+      break;
+    }
+  }
+  CGM.getOpenMPRuntime().emitCancelCall(*this, S.getLocStart(), IfCond,
                                         S.getCancelRegion());
 }
 
index ed58e475fe718ae098129814208abed5e6828352..3865f2773f98bded43296bda52c09c06f666ce33 100644 (file)
@@ -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<OMPClause *> 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,
index 5322a406168df3050cf1813ad00d9dec6279c075..1bdd65cdf82fa75d24dab1f8ba9d2dc9b1b21da4 100644 (file)
@@ -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<OpenMPDirectiveKind>(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:
index 7c0424cc878c3a892d6c874cf6ae8263267f22ce..41e9f9699218125f4a882870dc00a5d5e5c0d61a 100644 (file)
@@ -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;
index f244c784e86e911fd818fa4c64ca01ed1699c850..007237a7fb98bf9097dcb03a0653367255136b51 100644 (file)
@@ -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
 {
index 9a99826217f41875e8fc2029d74d3a4604c963c2..c7eaa1a4a9f0dd7abf3566dd02070c515655e39a 100644 (file)
@@ -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/test/OpenMP/cancel_if_messages.cpp b/test/OpenMP/cancel_if_messages.cpp
new file mode 100644 (file)
index 0000000..8d1afc9
--- /dev/null
@@ -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 <class T, class S> // 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);
+}