https://github.com/zahiraam updated 
https://github.com/llvm/llvm-project/pull/203252

>From b925b2c3fa0f15b20898bd6456329eddfdb027ea Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <[email protected]>
Date: Wed, 20 May 2026 05:48:13 -0700
Subject: [PATCH 1/6] [OpenMP] Prevent parser infinite loop on unimplemented
 clauses

---
 clang/lib/Basic/OpenMPKinds.cpp               |  1 +
 clang/lib/Parse/ParseOpenMP.cpp               |  9 ++
 clang/lib/Sema/SemaOpenMP.cpp                 |  4 +
 .../OpenMP/unimplemented_clause_messages.cpp  | 93 +++++++++++++++++++
 4 files changed, 107 insertions(+)
 create mode 100644 clang/test/OpenMP/unimplemented_clause_messages.cpp

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 45a47ec797f01..ba3d3113700ff 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)
+    ;
+}

>From c5a58c9381dedf5ea55ecf048394bc704797c127 Mon Sep 17 00:00:00 2001
From: Ammarguellat <[email protected]>
Date: Thu, 11 Jun 2026 05:16:12 -0700
Subject: [PATCH 2/6] [OpenMP] Pointer dereference collapse loop

---
 clang/lib/Sema/SemaOpenMP.cpp                   |  2 +-
 clang/test/OpenMP/collapse_extern_ref_crash.cpp | 17 +++++++++++++++++
 2 files changed, 18 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/OpenMP/collapse_extern_ref_crash.cpp

diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 113c8f3cb3016..79a0c396f787e 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -8044,7 +8044,7 @@ class ForSubExprChecker : public 
DynamicRecursiveASTVisitor {
     VarDecl *V = VD->getPotentiallyDecomposedVarDecl();
     if (V->getType()->isReferenceType()) {
       VarDecl *VD = V->getDefinition();
-      if (VD->hasInit()) {
+      if (VD && VD->hasInit()) {
         Expr *I = VD->getInit();
         DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(I);
         if (!DRE)
diff --git a/clang/test/OpenMP/collapse_extern_ref_crash.cpp 
b/clang/test/OpenMP/collapse_extern_ref_crash.cpp
new file mode 100644
index 0000000000000..4cc1a56115c73
--- /dev/null
+++ b/clang/test/OpenMP/collapse_extern_ref_crash.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=51 %s
+// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=51 %s
+
+// Verify no crash when collapsing a loop nest where the induction variable
+// is an extern reference type. PR/issue: null dereference in getInitLCDecl
+// when VarDecl::getDefinition() returns nullptr.
+
+extern int &dim;
+auto test() {
+  // expected-error@+1 {{expected-error for malformed collapse}}
+#pragma omp parallel for collapse(2)
+  for (int i = 0; i < dim; ++i) {
+    for (i = 0; i < 10; i++) {
+      int dummy;
+    }
+  }
+}

>From 2f48e43b7c6378862830683d1e662759e5eac1ac Mon Sep 17 00:00:00 2001
From: Ammarguellat <[email protected]>
Date: Thu, 11 Jun 2026 05:43:06 -0700
Subject: [PATCH 3/6] Fixed LIT test

---
 clang/test/OpenMP/collapse_extern_ref_crash.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/test/OpenMP/collapse_extern_ref_crash.cpp 
b/clang/test/OpenMP/collapse_extern_ref_crash.cpp
index 4cc1a56115c73..432fd91ef5852 100644
--- a/clang/test/OpenMP/collapse_extern_ref_crash.cpp
+++ b/clang/test/OpenMP/collapse_extern_ref_crash.cpp
@@ -1,13 +1,14 @@
 // RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=51 %s
 // RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=51 %s
 
+// expected-no-diagnostics
+
 // Verify no crash when collapsing a loop nest where the induction variable
 // is an extern reference type. PR/issue: null dereference in getInitLCDecl
 // when VarDecl::getDefinition() returns nullptr.
 
 extern int &dim;
 auto test() {
-  // expected-error@+1 {{expected-error for malformed collapse}}
 #pragma omp parallel for collapse(2)
   for (int i = 0; i < dim; ++i) {
     for (i = 0; i < 10; i++) {

>From c74662a207430405550212076e96b7e34c1d52b9 Mon Sep 17 00:00:00 2001
From: Ammarguellat <[email protected]>
Date: Thu, 11 Jun 2026 12:02:49 -0700
Subject: [PATCH 4/6] Added diag

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 +
 clang/lib/Sema/SemaOpenMP.cpp                 | 46 +++++++++++++++----
 .../test/OpenMP/collapse_extern_ref_crash.cpp | 31 ++++++++++---
 3 files changed, 64 insertions(+), 15 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a3b575b7ee63a..9abbcb7fd2c3d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12255,6 +12255,8 @@ def err_omp_loop_cannot_use_stmt : Error<
   "'%0' statement cannot be used in OpenMP for loop">;
 def err_omp_loop_bad_collapse_var : Error<
   "cannot use variable %1 in collapsed imperfectly-nested loop 
%select{init|condition|increment}0 statement">;
+def err_omp_loop_var_reused_in_collapsed_loop : Error<
+  "loop iteration variable %0 cannot be reused in a nested loop of a collapsed 
loop nest">;
 def err_omp_simd_region_cannot_use_stmt : Error<
   "'%0' statement cannot be used in OpenMP simd region">;
 def warn_omp_loop_64_bit_var : Warning<
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 79a0c396f787e..f94f5657a3998 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -8082,6 +8082,8 @@ class OpenMPIterationSpaceChecker {
   SourceLocation ConditionLoc;
   /// The set of variables declared within the (to be collapsed) loop nest.
   const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopVarDecls;
+  /// The set of induction variables from outer collapsed loops.
+  const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopInductionVars;
   /// A source location for referring to loop init later.
   SourceRange InitSrcRange;
   /// A source location for referring to condition later.
@@ -8128,10 +8130,12 @@ class OpenMPIterationSpaceChecker {
   OpenMPIterationSpaceChecker(
       Sema &SemaRef, bool SupportsNonRectangular, DSAStackTy &Stack,
       SourceLocation DefaultLoc,
-      const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopDecls)
+      const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopDecls,
+      const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopInductionVars)
       : SemaRef(SemaRef), SupportsNonRectangular(SupportsNonRectangular),
         Stack(Stack), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc),
-        CollapsedLoopVarDecls(CollapsedLoopDecls) {}
+        CollapsedLoopVarDecls(CollapsedLoopDecls),
+        CollapsedLoopInductionVars(CollapsedLoopInductionVars) {}
   /// Check init-expr for canonical loop form and save loop counter
   /// variable - #Var and its initialization value - #LB.
   bool checkAndSetInit(Stmt *S, bool EmitDiags = true);
@@ -8473,7 +8477,17 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt 
*S, bool EmitDiags) {
           if (auto *ME = 
dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
             return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
                                   EmitDiags);
-        return setLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS(), EmitDiags);
+        // Check if this variable is already used as an induction variable
+        // in an outer collapsed loop.
+        ValueDecl *LoopVar = DRE->getDecl();
+        if (!CollapsedLoopInductionVars.empty() &&
+            CollapsedLoopInductionVars.count(LoopVar) && EmitDiags) {
+          SemaRef.Diag(DRE->getLocation(),
+                       diag::err_omp_loop_var_reused_in_collapsed_loop)
+              << LoopVar;
+          return true;
+        }
+        return setLCDeclAndLB(LoopVar, DRE, BO->getRHS(), EmitDiags);
       }
       if (auto *ME = dyn_cast<MemberExpr>(LHS)) {
         if (ME->isArrow() &&
@@ -9435,7 +9449,8 @@ void 
SemaOpenMP::ActOnOpenMPLoopInitialization(SourceLocation ForLoc,
   DSAStack->loopStart();
   llvm::SmallPtrSet<const Decl *, 1> EmptyDeclSet;
   OpenMPIterationSpaceChecker ISC(SemaRef, /*SupportsNonRectangular=*/true,
-                                  *DSAStack, ForLoc, EmptyDeclSet);
+                                  *DSAStack, ForLoc, EmptyDeclSet,
+                                  EmptyDeclSet);
   if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) {
     if (ValueDecl *D = ISC.getLoopDecl()) {
       auto *VD = dyn_cast<VarDecl>(D);
@@ -9535,7 +9550,8 @@ static bool checkOpenMPIterationSpace(
     SemaOpenMP::VarsWithInheritedDSAType &VarsWithImplicitDSA,
     llvm::MutableArrayRef<LoopIterationSpace> ResultIterSpaces,
     llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
-    const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopVarDecls) {
+    const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopVarDecls,
+    const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopInductionVars) {
   bool SupportsNonRectangular = !isOpenMPLoopTransformationDirective(DKind);
   // OpenMP [2.9.1, Canonical Loop Form]
   //   for (init-expr; test-expr; incr-expr) structured-block
@@ -9576,7 +9592,8 @@ static bool checkOpenMPIterationSpace(
 
   OpenMPIterationSpaceChecker ISC(SemaRef, SupportsNonRectangular, DSA,
                                   For ? For->getForLoc() : CXXFor->getForLoc(),
-                                  CollapsedLoopVarDecls);
+                                  CollapsedLoopVarDecls,
+                                  CollapsedLoopInductionVars);
 
   // Check init.
   Stmt *Init = For ? For->getInit() : CXXFor->getBeginStmt();
@@ -9999,6 +10016,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr 
*CollapseLoopCountExpr,
   bool SupportsNonPerfectlyNested = (SemaRef.LangOpts.OpenMP >= 50) &&
                                     
!isOpenMPLoopTransformationDirective(DKind);
   llvm::SmallPtrSet<const Decl *, 4> CollapsedLoopVarDecls;
+  llvm::SmallPtrSet<const Decl *, 4> CollapsedLoopInductionVars;
 
   if (CollapseLoopCountExpr) {
     // Found 'collapse' clause - calculate collapse number.
@@ -10047,14 +10065,24 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr 
*CollapseLoopCountExpr,
           SupportsNonPerfectlyNested, NumLoops,
           [DKind, &SemaRef, &DSA, NumLoops, NestedLoopCount,
            CollapseLoopCountExpr, OrderedLoopCountExpr, &VarsWithImplicitDSA,
-           &IterSpaces, &Captures,
-           &CollapsedLoopVarDecls](unsigned Cnt, Stmt *CurStmt) {
+           &IterSpaces, &Captures, &CollapsedLoopVarDecls,
+           &CollapsedLoopInductionVars](unsigned Cnt, Stmt *CurStmt) {
             if (checkOpenMPIterationSpace(
                     DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount,
                     NumLoops, CollapseLoopCountExpr, OrderedLoopCountExpr,
                     VarsWithImplicitDSA, IterSpaces, Captures,
-                    CollapsedLoopVarDecls))
+                    CollapsedLoopVarDecls, CollapsedLoopInductionVars))
               return true;
+            // Add the current loop's induction variable to the set so nested
+            // loops can check against it.
+            if (Cnt < NestedLoopCount && IterSpaces[Cnt].CounterVar) {
+              if (auto *DRE =
+                      dyn_cast<DeclRefExpr>(IterSpaces[Cnt].CounterVar)) {
+                if (ValueDecl *VD = DRE->getDecl()) {
+                  CollapsedLoopInductionVars.insert(VD->getCanonicalDecl());
+                }
+              }
+            }
             if (Cnt > 0 && Cnt >= NestedLoopCount &&
                 IterSpaces[Cnt].CounterVar) {
               // Handle initialization of captured loop iterator variables.
diff --git a/clang/test/OpenMP/collapse_extern_ref_crash.cpp 
b/clang/test/OpenMP/collapse_extern_ref_crash.cpp
index 432fd91ef5852..a8ffcae2fe262 100644
--- a/clang/test/OpenMP/collapse_extern_ref_crash.cpp
+++ b/clang/test/OpenMP/collapse_extern_ref_crash.cpp
@@ -1,18 +1,37 @@
 // RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=51 %s
 // RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=51 %s
 
-// expected-no-diagnostics
+// This test verify two behaviors:
+// 1. No crash when the loop bound is an extern reference (fixed null pointer
+// dereference).
+// 2. Proper diagnostic when a nested loop reuses the outer loop's induction
+// variable
 
-// Verify no crash when collapsing a loop nest where the induction variable
-// is an extern reference type. PR/issue: null dereference in getInitLCDecl
-// when VarDecl::getDefinition() returns nullptr.
 
 extern int &dim;
-auto test() {
+auto test1() {
 #pragma omp parallel for collapse(2)
   for (int i = 0; i < dim; ++i) {
+    // expected-error@+1{{loop iteration variable 'i' cannot be reused in a 
nested loop of a collapsed loop nest}}
     for (i = 0; i < 10; i++) {
-      int dummy;
+    }
+  }
+}
+
+auto test2() {
+#pragma omp parallel for collapse(2)
+  for (int i = 0; i < dim; ++i) {
+    for (int i = 0; i < 10; i++) {
+    }
+  }
+}
+
+int dim_storage = 10;
+int &dim = dim_storage;
+auto test3() {
+#pragma omp parallel for collapse(2)
+  for (int i = 0; i < dim; ++i) {
+    for (int j = 0; j < 10; j++) {
     }
   }
 }

>From facedb15772056a092b487da0ed5b53bcaf6aa54 Mon Sep 17 00:00:00 2001
From: Ammarguellat <[email protected]>
Date: Thu, 11 Jun 2026 14:03:33 -0700
Subject: [PATCH 5/6] Addressed review comments

---
 clang/lib/Sema/SemaOpenMP.cpp                   | 3 ++-
 clang/test/OpenMP/collapse_extern_ref_crash.cpp | 3 +++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index f94f5657a3998..918717b45b0d3 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -8481,7 +8481,8 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt 
*S, bool EmitDiags) {
         // in an outer collapsed loop.
         ValueDecl *LoopVar = DRE->getDecl();
         if (!CollapsedLoopInductionVars.empty() &&
-            CollapsedLoopInductionVars.count(LoopVar) && EmitDiags) {
+            CollapsedLoopInductionVars.count(LoopVar->getCanonicalDecl()) &&
+            EmitDiags) {
           SemaRef.Diag(DRE->getLocation(),
                        diag::err_omp_loop_var_reused_in_collapsed_loop)
               << LoopVar;
diff --git a/clang/test/OpenMP/collapse_extern_ref_crash.cpp 
b/clang/test/OpenMP/collapse_extern_ref_crash.cpp
index a8ffcae2fe262..52192e648044d 100644
--- a/clang/test/OpenMP/collapse_extern_ref_crash.cpp
+++ b/clang/test/OpenMP/collapse_extern_ref_crash.cpp
@@ -14,6 +14,7 @@ auto test1() {
   for (int i = 0; i < dim; ++i) {
     // expected-error@+1{{loop iteration variable 'i' cannot be reused in a 
nested loop of a collapsed loop nest}}
     for (i = 0; i < 10; i++) {
+      int dummy;
     }
   }
 }
@@ -22,6 +23,7 @@ auto test2() {
 #pragma omp parallel for collapse(2)
   for (int i = 0; i < dim; ++i) {
     for (int i = 0; i < 10; i++) {
+      int dummy;
     }
   }
 }
@@ -32,6 +34,7 @@ auto test3() {
 #pragma omp parallel for collapse(2)
   for (int i = 0; i < dim; ++i) {
     for (int j = 0; j < 10; j++) {
+      int dummy;
     }
   }
 }

>From e673f026fcba9afeadab5b7dacf65731c1ab3700 Mon Sep 17 00:00:00 2001
From: Ammarguellat <[email protected]>
Date: Fri, 12 Jun 2026 08:22:11 -0700
Subject: [PATCH 6/6] Added CXXOperatorCallExpr/OO_Equal test

---
 clang/lib/Sema/SemaOpenMP.cpp                 | 13 +++++++-
 .../test/OpenMP/collapse_extern_ref_crash.cpp | 28 ++++++++++++++++
 clang/test/OpenMP/t1.cpp                      | 32 +++++++++++++++++++
 3 files changed, 72 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/OpenMP/t1.cpp

diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 918717b45b0d3..d3c66072239fa 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -8523,7 +8523,18 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt 
*S, bool EmitDiags) {
           if (auto *ME = 
dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
             return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
                                   EmitDiags);
-        return setLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1), EmitDiags);
+        // Check if this variable is already used as an induction variable
+        // in an outer collapsed loop.
+        ValueDecl *LoopVar = DRE->getDecl();
+        if (!CollapsedLoopInductionVars.empty() &&
+            CollapsedLoopInductionVars.count(LoopVar->getCanonicalDecl()) &&
+            EmitDiags) {
+          SemaRef.Diag(DRE->getLocation(),
+                       diag::err_omp_loop_var_reused_in_collapsed_loop)
+              << LoopVar;
+          return true;
+        }
+        return setLCDeclAndLB(LoopVar, DRE, CE->getArg(1), EmitDiags);
       }
       if (auto *ME = dyn_cast<MemberExpr>(LHS)) {
         if (ME->isArrow() &&
diff --git a/clang/test/OpenMP/collapse_extern_ref_crash.cpp 
b/clang/test/OpenMP/collapse_extern_ref_crash.cpp
index 52192e648044d..8995efc43e59f 100644
--- a/clang/test/OpenMP/collapse_extern_ref_crash.cpp
+++ b/clang/test/OpenMP/collapse_extern_ref_crash.cpp
@@ -38,3 +38,31 @@ auto test3() {
     }
   }
 }
+
+struct Iterator {
+  int value;
+  Iterator& operator=(int v) { value = v; return *this; }
+  bool operator<(int n) const { return value < n; }
+  Iterator& operator++() { ++value; return *this; }
+};
+
+Iterator i;
+auto test4() {
+#pragma omp parallel for collapse(2)
+  for (i = 0; i < dim; ++i) {
+    // expected-error@+1{{loop iteration variable 'i' cannot be reused in a 
nested loop of a collapsed loop nest}}
+    for (i = 0; i < 10; ++i) {
+      int dummy;
+    }
+  }
+}
+
+auto test5() {
+#pragma omp parallel for collapse(2)
+  for (i = 0; i < dim; ++i) {
+    // expected-error@+1{{loop iteration variable 'i' cannot be reused in a 
nested loop of a collapsed loop nest}}
+    for (i = 0; i < 10; ++i) {
+      int dummy;
+    }
+  }
+}
diff --git a/clang/test/OpenMP/t1.cpp b/clang/test/OpenMP/t1.cpp
new file mode 100644
index 0000000000000..c50f878d52e7a
--- /dev/null
+++ b/clang/test/OpenMP/t1.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=51 %s
+// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=51 %s
+
+// Test 4: Reuse with overloaded operator= (should error)
+struct Iterator {
+  int value;
+  Iterator& operator=(int v) { value = v; return *this; }
+  bool operator<(int n) const { return value < n; }
+  Iterator& operator++() { ++value; return *this; }                           
+}; 
+
+Iterator i;
+extern int &dim;
+auto test4() {  
+  #pragma omp parallel for collapse(2)                                         
 
+    for (i = 0; i < dim; ++i) {                              
+      // expected-error@+1{{loop iteration variable 'i' cannot be reused in a 
nested loop of a collapsed loop nest}}                                        
+      for (i = 0; i < 10; ++i) {                                      
+        int dummy;                                                             
 
+      }           
+    }                                                                          
 
+  } 
+
+auto test5() {
+#pragma omp parallel for collapse(2)                                          
+  for (i = 0; i < dim; ++i) {                              
+    // expected-error@+1{{loop iteration variable 'i' cannot be reused in a 
nested loop of a collapsed loop nest}}                                        
+    for (i = 0; i < 10; ++i) {                             
+      int dummy;                                                              
+    }                                                                         
+  }                                                                           
+} 

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

Reply via email to