llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Joshua Batista (bob80905)

<details>
<summary>Changes</summary>

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

---
Full diff: https://github.com/llvm/llvm-project/pull/176075.diff


3 Files Affected:

- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2) 
- (modified) clang/lib/Sema/SemaHLSL.cpp (+47) 
- (added) clang/test/SemaHLSL/Language/EmptyInitializers.hlsl (+96) 


``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5cbbc7d130c99..1f7a7a3640e27 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13354,6 +13354,8 @@ def err_hlsl_pointers_unsupported : Error<
   "%select{pointers|references}0 are unsupported in HLSL">;
 def err_hlsl_missing_resource_class : Error<"HLSL resource needs to have 
[[hlsl::resource_class()]] attribute">;
 def err_hlsl_attribute_needs_intangible_type: Error<"attribute %0 can be used 
only on HLSL intangible type %1">;
+def err_hlsl_incomplete_array_non_resource : Error<
+  "incomplete array type %0 is only permitted for resource types in HLSL">;
 def err_hlsl_incorrect_num_initializers: Error<
   "too %select{few|many}0 initializers in list for type %1 "
   "(expected %2 but found %3)">;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index f15b274a65a53..831b7c83d12e8 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;
+  }
+
+  // Only after validating legality do we infer size
   // 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 = {};
+}

``````````

</details>


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

Reply via email to