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
