[clang-tools-extra] [clang-tidy] Fix altera-unroll-loops crash on multi-decl for init (PR #203865)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 15 02:57:21 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tidy
Author: Zeyi Xu (zeyi2)
<details>
<summary>Changes</summary>
Avoid calling `DeclStmt::getSingleDecl()` unless the declaration statement contains a single declaration.
Closes https://github.com/llvm/llvm-project/issues/203856
---
Full diff: https://github.com/llvm/llvm-project/pull/203865.diff
3 Files Affected:
- (modified) clang-tools-extra/clang-tidy/altera/UnrollLoopsCheck.cpp (+4-2)
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+5)
- (modified) clang-tools-extra/test/clang-tidy/checkers/altera/unroll-loops.cpp (+53)
``````````diff
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) {
``````````
</details>
https://github.com/llvm/llvm-project/pull/203865
More information about the cfe-commits
mailing list