https://github.com/zeyi2 created 
https://github.com/llvm/llvm-project/pull/203865

None

>From 6921b5d464bbbbc0ae9950746076bcb2f35eee93 Mon Sep 17 00:00:00 2001
From: Zeyi Xu <[email protected]>
Date: Mon, 15 Jun 2026 17:50:58 +0800
Subject: [PATCH] [clang-tidy] Fix altera-unroll-loops crash on multi-decl for
 init

---
 .../clang-tidy/altera/UnrollLoopsCheck.cpp    |  6 ++-
 clang-tools-extra/docs/ReleaseNotes.rst       |  5 ++
 .../checkers/altera/unroll-loops.cpp          | 53 +++++++++++++++++++
 3 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/altera/UnrollLoopsCheck.cpp 
b/clang-tools-extra/clang-tidy/altera/UnrollLoopsCheck.cpp
index 15fa75f19ef28..eb41acaf4650a 100644
--- a/clang-tools-extra/clang-tidy/altera/UnrollLoopsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/altera/UnrollLoopsCheck.cpp
@@ -124,7 +124,8 @@ bool UnrollLoopsCheck::hasKnownBounds(const Stmt *Statement,
   if (!Initializer || !Conditional || !Increment)
     return false;
   // If the loop variable value isn't known, loop bounds are unknown.
-  if (const auto *InitDeclStatement = dyn_cast<DeclStmt>(Initializer)) {
+  if (const auto *InitDeclStatement = dyn_cast<DeclStmt>(Initializer);
+      InitDeclStatement && InitDeclStatement->isSingleDecl()) {
     if (const auto *VariableDecl =
             dyn_cast<VarDecl>(InitDeclStatement->getSingleDecl())) {
       const APValue *Evaluation = VariableDecl->evaluateValue();
@@ -173,7 +174,8 @@ bool UnrollLoopsCheck::hasLargeNumIterations(const Stmt 
*Statement,
   const Expr *Increment = ForLoop->getInc();
   int InitValue = 0;
   // If the loop variable value isn't known, we can't know the loop bounds.
-  if (const auto *InitDeclStatement = dyn_cast<DeclStmt>(Initializer)) {
+  if (const auto *InitDeclStatement = dyn_cast<DeclStmt>(Initializer);
+      InitDeclStatement && InitDeclStatement->isSingleDecl()) {
     if (const auto *VariableDecl =
             dyn_cast<VarDecl>(InitDeclStatement->getSingleDecl())) {
       APValue *Evaluation = VariableDecl->evaluateValue();
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 9703bb8f17208..5b1c3fb169fa6 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -343,6 +343,11 @@ Changes in existing checks
   positives when ordinary variable or field assignments are used in loop
   conditions and note locations for inferred ID-dependent fields.
 
+- Improved :doc:`altera-unroll-loops
+  <clang-tidy/checks/altera/unroll-loops>` check by fixing a crash when
+  analyzing a ``for`` loop whose initialization statement declares multiple
+  variables.
+
 - Improved :doc:`bugprone-argument-comment
   <clang-tidy/checks/bugprone/argument-comment>`:
 
diff --git a/clang-tools-extra/test/clang-tidy/checkers/altera/unroll-loops.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/altera/unroll-loops.cpp
index c06cec794e8eb..05a9e1b21c011 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/altera/unroll-loops.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/altera/unroll-loops.cpp
@@ -125,6 +125,30 @@ void for_loops(int *A, int size) {
     A[i]++;
   }
 
+#pragma unroll
+  for (int i = 0, j = 0; i < 50; ++i) {
+    A[i] += j;
+  }
+
+#pragma unroll
+  for (int i = 0, j = 0; i < 50; ++i, ++j) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: loop likely has a large number 
of iterations and thus cannot be fully unrolled; to partially unroll this loop, 
use the '#pragma unroll <num>' directive
+    // FIXME: This is a false positive.
+    A[i] += j;
+  }
+
+#pragma unroll
+  for (int j = size, i = 0; i < 50; ++i) {
+    A[i] += j;
+  }
+
+#pragma unroll
+  for (int j = 0, i = 100; i < 150; ++i) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: loop likely has a large number 
of iterations and thus cannot be fully unrolled; to partially unroll this loop, 
use the '#pragma unroll <num>' directive
+    // FIXME: This is a false positive.
+    A[i] += j;
+  }
+
 // Loop with unknown size should be partially unrolled.
 #pragma unroll
   for (int i = 0; i < size; ++i) {
@@ -132,6 +156,18 @@ void for_loops(int *A, int size) {
     A[i]++;
   }
 
+#pragma unroll
+  for (int i = 0, j = 0; i < size; ++i) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but 
loop bounds are not known; to partially unroll this loop, use the '#pragma 
unroll <num>' directive
+    A[i] += j;
+  }
+
+#pragma unroll
+  for (int j = 0, i = size; i < 50; ++i) {
+    // FIXME: This is a false negative.
+    A[i] += j;
+  }
+
 #pragma unroll
   for (;;) {
     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but 
loop bounds are not known; to partially unroll this loop, use the '#pragma 
unroll <num>' directive [altera-unroll-loops]
@@ -181,6 +217,11 @@ void for_loops(int *A, int size) {
     A[i]++;
   }
 
+#pragma unroll 5
+  for (int i = 0, j = 0; i < size; ++i) {
+    A[i] += j;
+  }
+
 // Loop with large size should be partially unrolled.
 #pragma unroll
   for (int i = 0; i < 51; ++i) {
@@ -188,6 +229,18 @@ void for_loops(int *A, int size) {
     A[i]++;
   }
 
+#pragma unroll
+  for (int i = 0, j = 0; i < 51; ++i) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: loop likely has a large number 
of iterations and thus cannot be fully unrolled; to partially unroll this loop, 
use the '#pragma unroll <num>' directive
+    A[i] += j;
+  }
+
+#pragma unroll
+  for (int j = 100, i = 0; i < 51; ++i) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: loop likely has a large number 
of iterations and thus cannot be fully unrolled; to partially unroll this loop, 
use the '#pragma unroll <num>' directive
+    A[i] += j;
+  }
+
 // Loop with large size correctly unrolled.
 #pragma unroll 5
   for (int i = 0; i < 51; ++i) {

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

Reply via email to