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@+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@+1{{too few initializers in list for type 'int[][2]' 
(expected 2 but found 0)}}
+  int a[][2] = {};
+
+  // Incomplete middle dimension
+  // expected-error@+1{{array has incomplete element type 'int[][3]'}}
+  int b[2][][3] = {};
+
+  // Incomplete inner dimension
+  // expected-error@+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@+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@+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@+1{{base class 'Base' has a flexible array member}}
+struct Derived : Base {
+  int d;
+};
+
+export void fn_derived() {
+  // expected-error@+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@+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@+1{{too few initializers in list for type 'Final' 
(expected 2 but found 0)}}
+  Final f = {};
+}


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

Reply via email to