[clang] 6fdccdb - [Sema][HLSL] Reject empty initializer lists for LHS containing an incomplete array. (#176075)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 20 10:11:19 PST 2026
Author: Joshua Batista
Date: 2026-01-20T10:11:15-08:00
New Revision: 6fdccdbe911580106b5011fb5d82cb5735da8922
URL: https://github.com/llvm/llvm-project/commit/6fdccdbe911580106b5011fb5d82cb5735da8922
DIFF: https://github.com/llvm/llvm-project/commit/6fdccdbe911580106b5011fb5d82cb5735da8922.diff
LOG: [Sema][HLSL] Reject empty initializer lists for LHS containing an incomplete array. (#176075)
This PR rejects empty initializer lists when the LHS is or contains an
incomplete array type.
Without this early validation, an assumption would be made that there
was an argument in the initializer list.
This would cause an assertion failure.
Fixes https://github.com/llvm/llvm-project/issues/173076
Added:
clang/test/SemaHLSL/Language/EmptyInitializers.hlsl
Modified:
clang/lib/Sema/SemaHLSL.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index f15b274a65a53..4d31e26d56e6b 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -4737,6 +4737,40 @@ class InitListTransformer {
};
} // namespace
+// Recursively detect any incomplete array anywhere in the type graph,
+// including arrays, struct fields, and base classes.
+static bool containsIncompleteArrayType(QualType Ty) {
+ Ty = Ty.getCanonicalType();
+
+ // Array types
+ if (const ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
+ if (isa<IncompleteArrayType>(AT))
+ return true;
+ return containsIncompleteArrayType(AT->getElementType());
+ }
+
+ // Record (struct/class) types
+ if (const auto *RT = Ty->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+
+ // Walk base classes (for C++ / HLSL structs with inheritance)
+ if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (const CXXBaseSpecifier &Base : CXXRD->bases()) {
+ if (containsIncompleteArrayType(Base.getType()))
+ return true;
+ }
+ }
+
+ // Walk fields
+ for (const FieldDecl *F : RD->fields()) {
+ if (containsIncompleteArrayType(F->getType()))
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool SemaHLSL::transformInitList(const InitializedEntity &Entity,
InitListExpr *Init) {
// If the initializer is a scalar, just return it.
@@ -4763,6 +4797,19 @@ bool SemaHLSL::transformInitList(const InitializedEntity &Entity,
if (ExpectedSize == 0 && ActualSize == 0)
return true;
+ // Reject empty initializer if *any* incomplete array exists structurally
+ if (ActualSize == 0 && containsIncompleteArrayType(Entity.getType())) {
+ QualType InitTy = Entity.getType().getNonReferenceType();
+ if (InitTy.hasAddressSpace())
+ InitTy = SemaRef.getASTContext().removeAddrSpaceQualType(InitTy);
+
+ SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
+ << /*TooManyOrFew=*/(int)(ExpectedSize < ActualSize) << InitTy
+ << /*ExpectedSize=*/ExpectedSize << /*ActualSize=*/ActualSize;
+ return false;
+ }
+
+ // We infer size after validating legality.
// For incomplete arrays it is completely arbitrary to choose whether we think
// the user intended fewer or more elements. This implementation assumes that
// the user intended more, and errors that there are too few initializers to
diff --git a/clang/test/SemaHLSL/Language/EmptyInitializers.hlsl b/clang/test/SemaHLSL/Language/EmptyInitializers.hlsl
new file mode 100644
index 0000000000000..8a3406e92843a
--- /dev/null
+++ b/clang/test/SemaHLSL/Language/EmptyInitializers.hlsl
@@ -0,0 +1,96 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
+
+//===----------------------------------------------------------------------===//
+// Baseline: struct with direct incomplete array
+//===----------------------------------------------------------------------===//
+struct S {
+ int a[];
+};
+
+export void fn(int A) {
+ // expected-error at +1{{too few initializers in list for type 'S' (expected 1 but found 0)}}
+ S s = {};
+}
+
+//===----------------------------------------------------------------------===//
+// Multidimensional arrays with at least one incomplete dimension
+//===----------------------------------------------------------------------===//
+export void fn_multi_arrays() {
+ // Incomplete outer dimension
+ // expected-error at +1{{too few initializers in list for type 'int[][2]' (expected 2 but found 0)}}
+ int a[][2] = {};
+
+ // Incomplete middle dimension
+ // expected-error at +1{{array has incomplete element type 'int[][3]'}}
+ int b[2][][3] = {};
+
+ // Incomplete inner dimension
+ // expected-error at +1{{array has incomplete element type 'int[]'}}
+ int c[2][3][] = {};
+}
+
+//===----------------------------------------------------------------------===//
+// Struct containing multidimensional incomplete arrays
+//===----------------------------------------------------------------------===//
+struct S2 {
+ int m[][4];
+};
+
+export void fn_struct_multi() {
+ // expected-error at +1{{too few initializers in list for type 'S2' (expected 1 but found 0)}}
+ S2 s = {};
+}
+
+//===----------------------------------------------------------------------===//
+// Nested structs with incomplete arrays
+//===----------------------------------------------------------------------===//
+struct Inner {
+ int x[];
+};
+
+struct Outer {
+ Inner I;
+};
+
+export void fn_nested_struct() {
+ // expected-error at +1{{too few initializers in list for type 'Outer' (expected 1 but found 0)}}
+ Outer o = {};
+}
+
+//===----------------------------------------------------------------------===//
+// Base-class inheritance containing incomplete arrays
+//===----------------------------------------------------------------------===//
+struct Base {
+ int b[];
+};
+
+// expected-error at +1{{base class 'Base' has a flexible array member}}
+struct Derived : Base {
+ int d;
+};
+
+export void fn_derived() {
+ // expected-error at +1{{too few initializers in list for type 'Derived' (expected 1 but found 0)}}
+ Derived d = {};
+}
+
+//===----------------------------------------------------------------------===//
+// Deep inheritance chain with incomplete array in base
+//===----------------------------------------------------------------------===//
+struct Base2 {
+ int x[];
+};
+
+// expected-error at +1{{base class 'Base2' has a flexible array member}}
+struct Mid : Base2 {
+ int y;
+};
+
+struct Final : Mid {
+ int z;
+};
+
+export void fn_deep_inheritance() {
+ // expected-error at +1{{too few initializers in list for type 'Final' (expected 2 but found 0)}}
+ Final f = {};
+}
More information about the cfe-commits
mailing list