[clang] [Clang][OpenMP] Fix crash on a `braced-init-list` in the `init` or increment of a transformed loop (PR #233248)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Oct 18 09:22:35 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Akash Manna (akash-manna-sky)
<details>
<summary>Changes</summary>
Fixes #<!-- -->202562
The loop analysis kept the initializer of `int i = {0}` as the lower bound as written, a braced-init-list, and did the same with the step of `i += {1}`. Plain loop directives got away with that, but `unroll partial`, `reverse`, `interchange`, `flatten` and `fuse` copy the trip count through a `TreeTransform`, which rebuilds the list without a type, so `{0} - 1` fails to build and the transform asserts.
The analysis now looks through a list that merely wraps one expression of the counter's type, so `int i = {0}`, `int i{0}`, `i = {0}` and `i += {1}` are analysed as `0` and `1`. A list that wraps nothing, like `{}`, is rejected as a non-canonical init or increment.
Assisted-by : LLM tools, reviewed and testes by me.
---
Full diff: https://github.com/llvm/llvm-project/pull/233248.diff
6 Files Affected:
- (modified) clang/docs/ReleaseNotes.md (+2)
- (modified) clang/lib/Sema/SemaOpenMP.cpp (+26)
- (modified) clang/test/OpenMP/for_loop_messages.cpp (+11)
- (modified) clang/test/OpenMP/reverse_messages.cpp (+9)
- (added) clang/test/OpenMP/unroll_codegen_braced_init.cpp (+18)
- (modified) clang/test/OpenMP/unroll_messages.cpp (+61)
``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 3f0c48cf36644d..ae98d4dd777b9f 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -1318,6 +1318,8 @@ The `alpha.cplusplus.UseAfterLifetimeEnd` checker was renamed to `alpha.core.Use
matching the behavior of such maps outside a mapper.
- Fixed a crash when the `safelen` and `simdlen` clauses of an OpenMP directive
have arguments of different integer types. (#GH108367)
+- Fixed a crash when the init or increment of a loop under an OpenMP loop
+ transformation directive uses a braced list, such as `int i = {0}`. (#GH202562)
- The `holds` clause on the `assume` directive now lowers side-effect-free
conditions to `llvm.assume`, enabling downstream optimizations. Previously
the clause was parsed but its condition was discarded without effect.
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index a3be416d2da24f..7aa05e46f7bfaa 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -8674,6 +8674,15 @@ static const StmtExpr *findStmtExpr(const Expr *E) {
return nullptr;
}
+static Expr *ignoreTransparentInitLists(Expr *E) {
+ while (auto *ILE = dyn_cast<InitListExpr>(E)) {
+ if (!ILE->isTransparent())
+ break;
+ E = ILE->getInit(0);
+ }
+ return E;
+}
+
bool OpenMPIterationSpaceChecker::checkNonRectangularBound(
const Expr *E, bool IsInitializer) const {
// Such a bound is emitted at every use, its declarations cannot be.
@@ -8694,6 +8703,15 @@ bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl,
UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp);
if (!NewLCDecl || !NewLB || NewLB->containsErrors())
return true;
+ if (!SemaRef.CurContext->isDependentContext()) {
+ NewLB = ignoreTransparentInitLists(NewLB);
+ if (auto *ILE = dyn_cast<InitListExpr>(NewLB)) {
+ if (EmitDiags)
+ SemaRef.Diag(ILE->getBeginLoc(), diag::err_omp_loop_not_canonical_init)
+ << ILE->getSourceRange();
+ return true;
+ }
+ }
LCDecl = getCanonicalDecl(NewLCDecl);
LCRef = NewLCRefExpr;
if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(NewLB))
@@ -8738,6 +8756,14 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) {
assert(LCDecl != nullptr && LB != nullptr && Step == nullptr);
if (!NewStep || NewStep->containsErrors())
return true;
+ if (!SemaRef.CurContext->isDependentContext()) {
+ NewStep = ignoreTransparentInitLists(NewStep);
+ if (auto *ILE = dyn_cast<InitListExpr>(NewStep)) {
+ SemaRef.Diag(ILE->getBeginLoc(), diag::err_omp_loop_not_canonical_incr)
+ << ILE->getSourceRange() << LCDecl;
+ return true;
+ }
+ }
if (!NewStep->isValueDependent()) {
// Check that the step is integer expression.
SourceLocation StepLoc = NewStep->getBeginLoc();
diff --git a/clang/test/OpenMP/for_loop_messages.cpp b/clang/test/OpenMP/for_loop_messages.cpp
index d2fbeea106a513..e10952887b0759 100644
--- a/clang/test/OpenMP/for_loop_messages.cpp
+++ b/clang/test/OpenMP/for_loop_messages.cpp
@@ -414,6 +414,17 @@ int test_iteration_spaces() {
for (int a{0}; a < 10; ++a) {
}
+#pragma omp parallel
+#pragma omp for
+ for (int a = {0}; a < 10; ++a) {
+ }
+
+#pragma omp parallel
+// expected-error at +2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp for
+ for (int a = {}; a < 10; ++a) {
+ }
+
return 0;
}
diff --git a/clang/test/OpenMP/reverse_messages.cpp b/clang/test/OpenMP/reverse_messages.cpp
index 9636a70bf2753b..07a9010a584735 100644
--- a/clang/test/OpenMP/reverse_messages.cpp
+++ b/clang/test/OpenMP/reverse_messages.cpp
@@ -36,5 +36,14 @@ void func() {
for (int i = 0; i < 7; ++i)
;
+ #pragma omp reverse
+ for (int i = {0}; i < 7; ++i)
+ ;
+
+ // expected-error at +2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+ #pragma omp reverse
+ for (int i = {}; i < 7; ++i)
+ ;
+
}
diff --git a/clang/test/OpenMP/unroll_codegen_braced_init.cpp b/clang/test/OpenMP/unroll_codegen_braced_init.cpp
new file mode 100644
index 00000000000000..dae66b579b520d
--- /dev/null
+++ b/clang/test/OpenMP/unroll_codegen_braced_init.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp -emit-llvm %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+extern "C" void body(int);
+
+// CHECK-LABEL: define {{.*}}void @_Z11braced_initv(
+// CHECK: store i32 3, ptr %[[I:.+]], align 4
+// CHECK: icmp sgt i32 %{{.+}}, 1
+// CHECK: icmp slt i32 %{{.+}}, 4
+// CHECK: %[[MUL:.+]] = mul nsw i32 %{{.+}}, 1
+// CHECK-NEXT: %[[ADD:.+]] = add nsw i32 3, %[[MUL]]
+// CHECK-NEXT: store i32 %[[ADD]], ptr %[[I]], align 4
+void braced_init() {
+#pragma omp for
+#pragma omp unroll partial(2)
+ for (int i = {3}; i < 7; i++)
+ body(i);
+}
diff --git a/clang/test/OpenMP/unroll_messages.cpp b/clang/test/OpenMP/unroll_messages.cpp
index 17d5ed83e162f2..b21a71b37d2183 100644
--- a/clang/test/OpenMP/unroll_messages.cpp
+++ b/clang/test/OpenMP/unroll_messages.cpp
@@ -137,3 +137,64 @@ void f(void) {
;
}
}
+
+namespace GH202562 {
+void braced_init() {
+#pragma omp unroll partial
+ for (int i = {0}; i < 2; i++)
+ ;
+
+#pragma omp unroll partial(2)
+ for (int i = {0}; i < 2; i++)
+ ;
+
+ // expected-warning at +2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp unroll partial
+ for (int i{0}; i < 2; i++)
+ ;
+
+ // expected-warning at +2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp unroll partial
+ for (int i(0); i < 2; i++)
+ ;
+
+ int j;
+#pragma omp unroll partial
+ for (j = {0}; j < 2; j++)
+ ;
+
+ // expected-error at +2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp unroll partial
+ for (int i = {}; i < 2; i++)
+ ;
+
+ // expected-warning at +2 {{too many braces around scalar initializer}}
+#pragma omp unroll partial
+ for (int i = {{0}}; i < 2; i++)
+ ;
+
+#pragma omp unroll partial
+ for (int i = 0; i < 2; i += {1})
+ ;
+
+#pragma omp unroll partial
+ for (int i = 0; i < 2; i -= {-1})
+ ;
+
+ // expected-error at +2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'i'}}
+#pragma omp unroll partial
+ for (int i = 0; i < 2; i += {})
+ ;
+
+#pragma omp unroll partial
+ for (int i = 0; i < 2; i++)
+ ;
+}
+
+template <typename T> void braced_init_templ() {
+#pragma omp unroll partial
+ for (T i = {0}; i < 2; i++)
+ ;
+}
+void braced_init_inst() { braced_init_templ<int>(); }
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/233248
More information about the cfe-commits
mailing list