[clang] [clang][SemaOpenACC] Avoid assertion on VLA reduction operand (PR #199178)
Fan Mo via cfe-commits
cfe-commits at lists.llvm.org
Sat May 23 22:09:27 PDT 2026
https://github.com/w007878 updated https://github.com/llvm/llvm-project/pull/199178
>From ad62385ed3789411409beaccdb9515f179cc8206 Mon Sep 17 00:00:00 2001
From: Fan Mo <w007878 at hotmail.com>
Date: Fri, 22 May 2026 01:42:44 -0500
Subject: [PATCH 1/6] fix: array type to avoid VLA reduction operand
---
clang/lib/Sema/SemaOpenACC.cpp | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index a228d224e2308..48e43bfbc23bd 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -2688,6 +2688,14 @@ Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
return nullptr;
}
+ } else if (Ty->isArrayType()) {
+ // Non-constant arrays (VLAs and incomplete arrays) cannot be statically
+ // enumerated to build an InitListExpr.
+ // Punt the same way we do for pointers below; codegen is responsible for
+ // handling these cases (or emitting a NYI). Without this, a variable-length
+ // array reduction operand falls through to the scalar branch and trips the
+ // 'isScalarType()' assertion (llvm/llvm-project#199162).
+ return nullptr;
} else if (Ty->isPointerType()) {
// For now, we are going to punt/not initialize pointer types, as
// discussions/designs are ongoing on how to express this behavior,
>From 2bdd83184b008b2d42d026625c4948805b2babcc Mon Sep 17 00:00:00 2001
From: Fan Mo <w007878 at hotmail.com>
Date: Fri, 22 May 2026 01:46:42 -0500
Subject: [PATCH 2/6] fix: check ArrayType for OpenACC
---
clang/lib/Sema/SemaOpenACC.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 48e43bfbc23bd..c4c53a0213869 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -2690,7 +2690,7 @@ Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
} else if (Ty->isArrayType()) {
// Non-constant arrays (VLAs and incomplete arrays) cannot be statically
- // enumerated to build an InitListExpr.
+ // enumerated to build an InitListExpr.
// Punt the same way we do for pointers below; codegen is responsible for
// handling these cases (or emitting a NYI). Without this, a variable-length
// array reduction operand falls through to the scalar branch and trips the
>From 4250bae10f9922428b3353c825282dd76716dc92 Mon Sep 17 00:00:00 2001
From: Fan Mo <w007878 at hotmail.com>
Date: Fri, 22 May 2026 01:54:25 -0500
Subject: [PATCH 3/6] add regression tests
---
.../compute-construct-reduction-vla.c | 70 ++++++++++++++
.../compute-construct-reduction-vla.cpp | 92 +++++++++++++++++++
2 files changed, 162 insertions(+)
create mode 100644 clang/test/SemaOpenACC/compute-construct-reduction-vla.c
create mode 100644 clang/test/SemaOpenACC/compute-construct-reduction-vla.cpp
diff --git a/clang/test/SemaOpenACC/compute-construct-reduction-vla.c b/clang/test/SemaOpenACC/compute-construct-reduction-vla.c
new file mode 100644
index 0000000000000..f51f28d3751ca
--- /dev/null
+++ b/clang/test/SemaOpenACC/compute-construct-reduction-vla.c
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 %s -fopenacc -verify
+
+// Regression test for llvm/llvm-project#199162:
+//
+// A variable-length array operand to an OpenACC 'reduction' clause used to
+// trip the assertion `Ty->isScalarType()` inside
+// GenerateReductionInitRecipeExpr (clang/lib/Sema/SemaOpenACC.cpp).
+//
+// VLAs cannot be statically enumerated to build an InitListExpr, so we now
+// punt (the same way we already do for pointer types) and let codegen handle
+// it. This test makes sure none of the variations below crash in Sema and
+// that they parse cleanly without spurious diagnostics.
+
+// expected-no-diagnostics
+
+void vla_reduction_bitand(int i) {
+ int arr[i + 1];
+#pragma acc parallel reduction(& : arr)
+ while (1)
+ ;
+}
+
+void vla_reduction_add(int i) {
+ int arr[i + 1];
+#pragma acc parallel reduction(+ : arr)
+ while (1)
+ ;
+}
+
+void vla_reduction_max(int i) {
+ int arr[i + 1];
+#pragma acc parallel reduction(max : arr)
+ while (1)
+ ;
+}
+
+void vla_reduction_min(int i) {
+ int arr[i + 1];
+#pragma acc parallel reduction(min : arr)
+ while (1)
+ ;
+}
+
+void vla_reduction_mul(int i) {
+ int arr[i + 1];
+#pragma acc parallel reduction(* : arr)
+ while (1)
+ ;
+}
+
+void vla_reduction_bitor(int i) {
+ unsigned arr[i + 1];
+#pragma acc parallel reduction(| : arr)
+ while (1)
+ ;
+}
+
+void vla_reduction_bitxor(int i) {
+ unsigned arr[i + 1];
+#pragma acc parallel reduction(^ : arr)
+ while (1)
+ ;
+}
+
+void vla_reduction_serial(int i) {
+ int arr[i + 1];
+#pragma acc serial reduction(| : arr)
+ while (1)
+ ;
+}
diff --git a/clang/test/SemaOpenACC/compute-construct-reduction-vla.cpp b/clang/test/SemaOpenACC/compute-construct-reduction-vla.cpp
new file mode 100644
index 0000000000000..f1b13384dcb03
--- /dev/null
+++ b/clang/test/SemaOpenACC/compute-construct-reduction-vla.cpp
@@ -0,0 +1,92 @@
+// RUN: %clang_cc1 %s -fopenacc -verify -Wno-vla-cxx-extension
+
+// C++ companion to compute-construct-reduction-vla.c.
+//
+// Regression test for llvm/llvm-project#199162. The original reproducer in
+// that issue was driven through clang++, so we keep an explicit C++
+// counterpart that exercises the same Sema path on:
+// * a bare VLA declared in a function body (clang accepts as a GNU
+// extension in C++; gated by -Wno-vla-cxx-extension above),
+// * references to VLAs,
+// * VLAs reached through a function template (dependent then concrete
+// after instantiation),
+// * an array section over a VLA.
+//
+// All cases must parse cleanly without crashing in
+// GenerateReductionInitRecipeExpr.
+
+// expected-no-diagnostics
+
+void vla_reduction_bitand_cxx(int i) {
+ int arr[i + 1];
+#pragma acc parallel reduction(& : arr)
+ while (1)
+ ;
+}
+
+void vla_reduction_add_cxx(int i) {
+ int arr[i + 1];
+#pragma acc parallel reduction(+ : arr)
+ while (1)
+ ;
+}
+
+void vla_reduction_serial_cxx(int i) {
+ unsigned arr[i + 1];
+#pragma acc serial reduction(| : arr)
+ while (1)
+ ;
+}
+
+// A reference binding to a VLA — VarTy after getNonReferenceType() is
+// still a VariableArrayType, so the recipe builder runs the same path.
+void vla_reduction_reference(int i) {
+ int storage[i + 1];
+ int(&arr)[i + 1] = storage;
+#pragma acc parallel reduction(+ : arr)
+ while (1)
+ ;
+}
+
+// Template — the VLA size depends on a non-type template parameter, so
+// the operand type is dependent at template-definition time and
+// CreateReductionInitRecipe should bail out early via the
+// isDependentType() guard. After instantiation the type becomes
+// concrete (still a VLA: the runtime size depends on 'n' below), and
+// the recipe builder runs the punt branch we added.
+template <int Pad>
+void vla_reduction_template(int n) {
+ int arr[n + Pad];
+#pragma acc parallel reduction(+ : arr)
+ while (1)
+ ;
+}
+
+void instantiate_template(int n) {
+ vla_reduction_template<1>(n);
+ vla_reduction_template<8>(n);
+}
+
+// 2D VLA, in C++.
+void vla_reduction_2d_cxx(int i, int j) {
+ int arr[i + 1][j + 1];
+#pragma acc parallel reduction(+ : arr)
+ while (1)
+ ;
+}
+
+// Array section on a VLA, in C++.
+void vla_reduction_array_section_cxx(int i) {
+ int arr[i + 1];
+#pragma acc parallel reduction(+ : arr[0:i])
+ while (1)
+ ;
+}
+
+// Combined construct.
+void vla_reduction_combined_cxx(int i) {
+ int arr[i + 1];
+#pragma acc parallel loop reduction(+ : arr)
+ for (int k = 0; k < 10; ++k)
+ ;
+}
>From 73c50a377a8f064b04987724fb950f6768e5be93 Mon Sep 17 00:00:00 2001
From: Fan Mo <w007878 at hotmail.com>
Date: Sun, 24 May 2026 01:00:18 -0400
Subject: [PATCH 4/6] reject VLA and consolidate tests
---
.../clang/Basic/DiagnosticSemaKinds.td | 3 +
clang/lib/Sema/SemaOpenACC.cpp | 8 --
clang/lib/Sema/SemaOpenACCClause.cpp | 6 ++
.../compute-construct-reduction-vla.c | 66 ++--------------
.../compute-construct-reduction-vla.cpp | 76 ++++---------------
5 files changed, 30 insertions(+), 129 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index dbe6cb2c3a41c..80ca61491eca6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -14002,6 +14002,9 @@ def note_acc_reduction_type_summary
"or a "
"composite of scalars, or an array, sub-array, or element of scalar "
"types">;
+def err_acc_reduction_vla
+ : Error<"variable length array cannot be used in OpenACC 'reduction' "
+ "clause">;
def err_acc_loop_not_for_loop
: Error<"OpenACC '%0' construct can only be applied to a 'for' loop">;
def note_acc_construct_here : Note<"'%0' construct is here">;
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 981e8169dbe4e..79edb8093c368 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -2689,14 +2689,6 @@ Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
return nullptr;
}
- } else if (Ty->isArrayType()) {
- // Non-constant arrays (VLAs and incomplete arrays) cannot be statically
- // enumerated to build an InitListExpr.
- // Punt the same way we do for pointers below; codegen is responsible for
- // handling these cases (or emitting a NYI). Without this, a variable-length
- // array reduction operand falls through to the scalar branch and trips the
- // 'isScalarType()' assertion (llvm/llvm-project#199162).
- return nullptr;
} else if (Ty->isPointerType()) {
// For now, we are going to punt/not initialize pointer types, as
// discussions/designs are ongoing on how to express this behavior,
diff --git a/clang/lib/Sema/SemaOpenACCClause.cpp b/clang/lib/Sema/SemaOpenACCClause.cpp
index c27c05c137eab..186fa7a0830d4 100644
--- a/clang/lib/Sema/SemaOpenACCClause.cpp
+++ b/clang/lib/Sema/SemaOpenACCClause.cpp
@@ -1898,6 +1898,12 @@ bool SemaOpenACC::CheckReductionVarType(Expr *VarExpr) {
// array. The standard isn't clear here whether this is allowed, but
// array-of-valid-things makes sense.
if (auto *AT = getASTContext().getAsArrayType(CurType)) {
+ // Reject VLA as reduction type, as we don't have any reasonable IR to generate
+ // See https://github.com/llvm/llvm-project/issues/199162
+ if (isa<VariableArrayType>(AT)) {
+ Diag(VarLoc, diag::err_acc_reduction_vla);
+ return true;
+ }
// If we're already the array type, peel off the array and leave the element
// type.
PartialDiagnostic PD = PDiag(diag::note_acc_reduction_array)
diff --git a/clang/test/SemaOpenACC/compute-construct-reduction-vla.c b/clang/test/SemaOpenACC/compute-construct-reduction-vla.c
index f51f28d3751ca..3801197245ea2 100644
--- a/clang/test/SemaOpenACC/compute-construct-reduction-vla.c
+++ b/clang/test/SemaOpenACC/compute-construct-reduction-vla.c
@@ -1,70 +1,20 @@
// RUN: %clang_cc1 %s -fopenacc -verify
// Regression test for llvm/llvm-project#199162:
-//
-// A variable-length array operand to an OpenACC 'reduction' clause used to
-// trip the assertion `Ty->isScalarType()` inside
-// GenerateReductionInitRecipeExpr (clang/lib/Sema/SemaOpenACC.cpp).
-//
-// VLAs cannot be statically enumerated to build an InitListExpr, so we now
-// punt (the same way we already do for pointer types) and let codegen handle
-// it. This test makes sure none of the variations below crash in Sema and
-// that they parse cleanly without spurious diagnostics.
+// Variable-length arrays cannot be used in OpenACC 'reduction' clauses.
-// expected-no-diagnostics
-
-void vla_reduction_bitand(int i) {
- int arr[i + 1];
-#pragma acc parallel reduction(& : arr)
- while (1)
- ;
-}
-
-void vla_reduction_add(int i) {
- int arr[i + 1];
+void vla_reduction(int n) {
+ int arr[n];
+ // expected-error at +1{{variable length array cannot be used in OpenACC 'reduction' clause}}
#pragma acc parallel reduction(+ : arr)
while (1)
;
}
-void vla_reduction_max(int i) {
- int arr[i + 1];
-#pragma acc parallel reduction(max : arr)
- while (1)
- ;
-}
-
-void vla_reduction_min(int i) {
- int arr[i + 1];
-#pragma acc parallel reduction(min : arr)
- while (1)
- ;
-}
-
-void vla_reduction_mul(int i) {
- int arr[i + 1];
-#pragma acc parallel reduction(* : arr)
- while (1)
- ;
-}
-
-void vla_reduction_bitor(int i) {
- unsigned arr[i + 1];
-#pragma acc parallel reduction(| : arr)
- while (1)
- ;
-}
-
-void vla_reduction_bitxor(int i) {
- unsigned arr[i + 1];
-#pragma acc parallel reduction(^ : arr)
- while (1)
- ;
-}
-
-void vla_reduction_serial(int i) {
- int arr[i + 1];
-#pragma acc serial reduction(| : arr)
+void vla_reduction_serial(int n) {
+ int arr[n];
+ // expected-error at +1{{variable length array cannot be used in OpenACC 'reduction' clause}}
+#pragma acc serial reduction(& : arr)
while (1)
;
}
diff --git a/clang/test/SemaOpenACC/compute-construct-reduction-vla.cpp b/clang/test/SemaOpenACC/compute-construct-reduction-vla.cpp
index f1b13384dcb03..6507ba4a7f44d 100644
--- a/clang/test/SemaOpenACC/compute-construct-reduction-vla.cpp
+++ b/clang/test/SemaOpenACC/compute-construct-reduction-vla.cpp
@@ -1,91 +1,41 @@
// RUN: %clang_cc1 %s -fopenacc -verify -Wno-vla-cxx-extension
// C++ companion to compute-construct-reduction-vla.c.
-//
-// Regression test for llvm/llvm-project#199162. The original reproducer in
-// that issue was driven through clang++, so we keep an explicit C++
-// counterpart that exercises the same Sema path on:
-// * a bare VLA declared in a function body (clang accepts as a GNU
-// extension in C++; gated by -Wno-vla-cxx-extension above),
-// * references to VLAs,
-// * VLAs reached through a function template (dependent then concrete
-// after instantiation),
-// * an array section over a VLA.
-//
-// All cases must parse cleanly without crashing in
-// GenerateReductionInitRecipeExpr.
+// Regression test for llvm/llvm-project#199162.
-// expected-no-diagnostics
-
-void vla_reduction_bitand_cxx(int i) {
- int arr[i + 1];
-#pragma acc parallel reduction(& : arr)
- while (1)
- ;
-}
-
-void vla_reduction_add_cxx(int i) {
- int arr[i + 1];
+void vla_reduction_cxx(int n) {
+ int arr[n];
+ // expected-error at +1{{variable length array cannot be used in OpenACC 'reduction' clause}}
#pragma acc parallel reduction(+ : arr)
while (1)
;
}
-void vla_reduction_serial_cxx(int i) {
- unsigned arr[i + 1];
-#pragma acc serial reduction(| : arr)
- while (1)
- ;
-}
-
-// A reference binding to a VLA — VarTy after getNonReferenceType() is
-// still a VariableArrayType, so the recipe builder runs the same path.
-void vla_reduction_reference(int i) {
- int storage[i + 1];
- int(&arr)[i + 1] = storage;
+void vla_reduction_reference(int n) {
+ int storage[n];
+ int(&arr)[n] = storage;
+ // expected-error at +1{{variable length array cannot be used in OpenACC 'reduction' clause}}
#pragma acc parallel reduction(+ : arr)
while (1)
;
}
-// Template — the VLA size depends on a non-type template parameter, so
-// the operand type is dependent at template-definition time and
-// CreateReductionInitRecipe should bail out early via the
-// isDependentType() guard. After instantiation the type becomes
-// concrete (still a VLA: the runtime size depends on 'n' below), and
-// the recipe builder runs the punt branch we added.
template <int Pad>
void vla_reduction_template(int n) {
int arr[n + Pad];
+ // expected-error at +1{{variable length array cannot be used in OpenACC 'reduction' clause}}
#pragma acc parallel reduction(+ : arr)
while (1)
;
}
void instantiate_template(int n) {
- vla_reduction_template<1>(n);
- vla_reduction_template<8>(n);
-}
-
-// 2D VLA, in C++.
-void vla_reduction_2d_cxx(int i, int j) {
- int arr[i + 1][j + 1];
-#pragma acc parallel reduction(+ : arr)
- while (1)
- ;
-}
-
-// Array section on a VLA, in C++.
-void vla_reduction_array_section_cxx(int i) {
- int arr[i + 1];
-#pragma acc parallel reduction(+ : arr[0:i])
- while (1)
- ;
+ vla_reduction_template<1>(n); // expected-note{{in instantiation of function template specialization}}
}
-// Combined construct.
-void vla_reduction_combined_cxx(int i) {
- int arr[i + 1];
+void vla_reduction_combined(int n) {
+ int arr[n];
+ // expected-error at +1{{variable length array cannot be used in OpenACC 'reduction' clause}}
#pragma acc parallel loop reduction(+ : arr)
for (int k = 0; k < 10; ++k)
;
>From c7674acd998c516f0fb24d603f1acbd8163237f9 Mon Sep 17 00:00:00 2001
From: Fan Mo <w007878 at hotmail.com>
Date: Sun, 24 May 2026 01:08:25 -0400
Subject: [PATCH 5/6] check original type
---
clang/lib/Sema/SemaOpenACCClause.cpp | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Sema/SemaOpenACCClause.cpp b/clang/lib/Sema/SemaOpenACCClause.cpp
index 186fa7a0830d4..5e745725e7958 100644
--- a/clang/lib/Sema/SemaOpenACCClause.cpp
+++ b/clang/lib/Sema/SemaOpenACCClause.cpp
@@ -1894,16 +1894,17 @@ bool SemaOpenACC::CheckReductionVarType(Expr *VarExpr) {
if (CurType.isNull())
return false;
+ // Reject VLAs in reduction clauses since lowering is unsupported.
+ // See https://github.com/llvm/llvm-project/issues/199162
+ if (CurType->isVariableArrayType()) {
+ Diag(VarLoc, diag::err_acc_reduction_vla);
+ return true;
+ }
+
// If we are still an array type, we allow 1 level of 'unpeeling' of the
// array. The standard isn't clear here whether this is allowed, but
// array-of-valid-things makes sense.
if (auto *AT = getASTContext().getAsArrayType(CurType)) {
- // Reject VLA as reduction type, as we don't have any reasonable IR to generate
- // See https://github.com/llvm/llvm-project/issues/199162
- if (isa<VariableArrayType>(AT)) {
- Diag(VarLoc, diag::err_acc_reduction_vla);
- return true;
- }
// If we're already the array type, peel off the array and leave the element
// type.
PartialDiagnostic PD = PDiag(diag::note_acc_reduction_array)
>From 4f485fca19f82d3d120965bae9b71c3a1aedaa99 Mon Sep 17 00:00:00 2001
From: Fan Mo <w007878 at hotmail.com>
Date: Sun, 24 May 2026 01:09:06 -0400
Subject: [PATCH 6/6] fix: not pointer
---
clang/lib/Sema/SemaOpenACCClause.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaOpenACCClause.cpp b/clang/lib/Sema/SemaOpenACCClause.cpp
index 5e745725e7958..e91308173c86b 100644
--- a/clang/lib/Sema/SemaOpenACCClause.cpp
+++ b/clang/lib/Sema/SemaOpenACCClause.cpp
@@ -1896,7 +1896,7 @@ bool SemaOpenACC::CheckReductionVarType(Expr *VarExpr) {
// Reject VLAs in reduction clauses since lowering is unsupported.
// See https://github.com/llvm/llvm-project/issues/199162
- if (CurType->isVariableArrayType()) {
+ if (CurType.isVariableArrayType()) {
Diag(VarLoc, diag::err_acc_reduction_vla);
return true;
}
More information about the cfe-commits
mailing list