Author: Zahira Ammarguellat
Date: 2026-05-22T05:22:37-07:00
New Revision: b4d42cf8e22126c2985e177bfe6130bfbfedb72a

URL: 
https://github.com/llvm/llvm-project/commit/b4d42cf8e22126c2985e177bfe6130bfbfedb72a
DIFF: 
https://github.com/llvm/llvm-project/commit/b4d42cf8e22126c2985e177bfe6130bfbfedb72a.diff

LOG: [OpenMP] Prevent parser infinite loop on unimplemented clauses (#198796)

This is to fix an infinite loop in the parser when using un-implemented
clauses. See https://godbolt.org/z/f775asrea .
This patch also fixes this crash: https://godbolt.org/z/WKrsbTGGe .

Added: 
    clang/test/OpenMP/unimplemented_clause_messages.cpp

Modified: 
    clang/lib/Basic/OpenMPKinds.cpp
    clang/lib/Parse/ParseOpenMP.cpp
    clang/lib/Sema/SemaOpenMP.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 287eb217ba458..675d86349c933 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -965,6 +965,7 @@ void clang::getOpenMPCaptureRegions(
     case OMPD_simd:
     case OMPD_single:
     case OMPD_target_data:
+    case OMPD_taskgraph:
     case OMPD_taskgroup:
     case OMPD_stripe:
       // These directives (when standalone) use OMPD_unknown as the region,

diff  --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 7f3c575fb68bb..c4177c1622521 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -2388,6 +2388,8 @@ StmtResult Parser::ParseOpenMPExecutableDirective(
     ImplicitClauseAllowed = false;
     Actions.OpenMP().StartOpenMPClause(CKind);
     HasImplicitClause = false;
+    SourceLocation ClauseLoc = Tok.getLocation();
+
     OMPClause *Clause =
         ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]);
     SeenClauses[unsigned(CKind)] = true;
@@ -2398,6 +2400,13 @@ StmtResult Parser::ParseOpenMPExecutableDirective(
     if (Tok.is(tok::comma))
       ConsumeToken();
     Actions.OpenMP().EndOpenMPClause();
+
+    // If ParseOpenMPClause returned without consuming any tokens, skip
+    // to end to avoid an infinite loop.
+    if (Tok.getLocation() == ClauseLoc) {
+      skipUntilPragmaOpenMPEnd(DKind);
+      break;
+    }
   }
   // End location of the directive.
   EndLoc = Tok.getLocation();

diff  --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index d6f6bc919a31b..76b40a5039180 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -6778,6 +6778,10 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
   case OMPD_begin_declare_variant:
   case OMPD_end_declare_variant:
     llvm_unreachable("OpenMP Directive is not allowed");
+  case OMPD_taskgraph:
+    Diag(StartLoc, diag::err_omp_unexpected_directive)
+        << 1 << getOpenMPDirectiveName(OMPD_taskgraph);
+    return StmtError();
   case OMPD_unknown:
   default:
     llvm_unreachable("Unknown OpenMP directive");

diff  --git a/clang/test/OpenMP/unimplemented_clause_messages.cpp 
b/clang/test/OpenMP/unimplemented_clause_messages.cpp
new file mode 100644
index 0000000000000..172203ea5d040
--- /dev/null
+++ b/clang/test/OpenMP/unimplemented_clause_messages.cpp
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -verify=expected,omp60 -fopenmp -fopenmp-version=60 %s
+// RUN: %clang_cc1 -verify=expected,omp51 -fopenmp -fopenmp-version=51 %s
+// RUN: %clang_cc1 -verify=expected,omp60 -fopenmp-simd -fopenmp-version=60 %s
+// RUN: %clang_cc1 -verify=expected,omp51 -fopenmp-simd -fopenmp-version=51 %s
+
+
+void test_induction_basic() {
+  int i;
+  // omp60-warning@+4{{extra tokens at the end of '#pragma omp parallel for' 
are ignored}}
+  // omp60-error@+3{{unexpected OpenMP clause 'induction' in directive 
'#pragma omp parallel for'}}
+  // omp51-warning@+2{{extra tokens at the end of '#pragma omp parallel for' 
are ignored}}
+  // omp51-error@+1{{unexpected OpenMP clause 'induction' in directive 
'#pragma omp parallel for'}}
+#pragma omp parallel for induction(i)
+  for (i = 0; i < 10; ++i)
+    ;
+}
+
+void test_apply() {
+  // omp60-warning@+4{{extra tokens at the end of '#pragma omp tile' are 
ignored}}
+  // omp60-error@+3{{unexpected OpenMP clause 'apply' in directive '#pragma 
omp tile'}}
+  // omp51-error@+2{{unexpected OpenMP clause 'apply' in directive '#pragma 
omp tile'}}
+  // omp51-warning@+1{{extra tokens at the end of '#pragma omp tile' are 
ignored}}
+#pragma omp tile sizes(10) apply(intratile: unroll)
+  for (int i = 0; i < 10; ++i)
+    ;
+}
+
+void test_empty_apply() {
+ // omp60-warning@+4{{extra tokens at the end of '#pragma omp tile' are 
ignored}}
+  // omp60-error@+3{{unexpected OpenMP clause 'apply' in directive '#pragma 
omp tile'}}
+  // omp51-error@+2{{unexpected OpenMP clause 'apply' in directive '#pragma 
omp tile'}}
+  // omp51-warning@+1{{extra tokens at the end of '#pragma omp tile' are 
ignored}}
+#pragma omp tile sizes(10) apply()
+  for (int i = 0; i < 10; ++i)
+    ;
+}
+
+void test_nested_apply()
+{
+  // omp60-error@+5{{unexpected OpenMP clause 'apply' in directive '#pragma 
omp tile'}}
+  // omp60-warning@+4{{extra tokens at the end of '#pragma omp tile' are 
ignored}}
+  //omp51-error@+3{{unexpected OpenMP clause 'apply' in directive '#pragma omp 
tile'}}
+  // omp51-warning@+2{{extra tokens at the end of '#pragma omp tile' are 
ignored}}
+#pragma omp tile sizes(10) \
+            apply(intratile: unroll partial(2) apply(reverse))
+  for (int i = 0; i < 100; ++i)
+    ;
+}
+
+void test_induction_with_following_clause() {
+  int i;
+  // omp60-warning@+4{{extra tokens at the end of '#pragma omp parallel for' 
are ignored}}
+  // omp60-error@+3{{unexpected OpenMP clause 'induction' in directive 
'#pragma omp parallel for'}}
+  // omp51-error@+2{{unexpected OpenMP clause 'induction' in directive 
'#pragma omp parallel for'}}
+  // omp51-warning@+1{{extra tokens at the end of '#pragma omp parallel for' 
are ignored}}
+#pragma omp parallel for induction(i) num_threads(4)
+  for (i = 0; i < 10; ++i)
+    ;
+}
+
+class Point {
+  float x, y, m;
+  char color;
+
+};
+
+void processPointsInLine() {
+  float separation;
+  // omp60-error@+4{{unexpected OpenMP clause 'induction' in directive 
'#pragma omp parallel for'}}
+  // omp60-warning@+3{{extra tokens at the end of '#pragma omp parallel for' 
are ignored}}
+  // omp51-error@+2{{unexpected OpenMP clause 'induction' in directive 
'#pragma omp parallel for'}}
+  // omp51-warning@+1{{extra tokens at the end of '#pragma omp parallel for' 
are ignored}}
+#pragma omp parallel for induction(step(Separation))
+  for (int i = 0; i < 10; ++i) {
+    ;
+  }
+}
+
+// Make sure test doesn't crash.
+void test_tasgraph()
+{
+  // omp60-error@+2{{unexpected OpenMP directive '#pragma omp taskgraph'}}
+  // omp51-error@+1{{unexpected OpenMP directive '#pragma omp taskgraph'}}
+#pragma omp taskgraph
+  for (int i = 0; i < 10; ++i)
+    ;
+}
+
+void test_implemented_clause() {
+#pragma omp tile sizes(10)
+  for (int i = 0; i < 10; ++i)
+    ;
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to