https://github.com/akash-manna-sky updated https://github.com/llvm/llvm-project/pull/219817
>From 0173717b091555434bd5b96ced13cd1d638d0132 Mon Sep 17 00:00:00 2001 From: Akash Manna <[email protected]> Date: Sun, 30 Aug 2026 21:15:11 +0530 Subject: [PATCH 1/3] [clang][Sema] Recheck array size once the element type is complete BuildArrayType can only check the element count when the element type is still incomplete, e.g. an uninstantiated class template specialization, and nothing revalidated the array once the element type was completed. An array whose total size overflows could therefore end up as a valid field or variable, and the first size query asserted in ASTContext::getTypeInfoImpl. Perform the check in RequireCompleteType once a constant array type is complete, using the same limit and diagnostic as BuildArrayType, and require the whole array type rather than just the base element type to be complete for uninitialized variable definitions. Fixes #213855 --- clang/docs/ReleaseNotes.md | 6 +++++ clang/include/clang/Sema/Sema.h | 3 ++- clang/lib/Sema/SemaDecl.cpp | 7 ++++++ clang/lib/Sema/SemaType.cpp | 36 ++++++++++++++++++++++++++++ clang/test/SemaTemplate/GH213855.cpp | 33 +++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 clang/test/SemaTemplate/GH213855.cpp diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index bdbabf2cd98d0..5de035d9a78a6 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -551,6 +551,12 @@ features cannot lower the translation-unit ABI level; inside a union caused the union to be treated as a polymorphic class. (#GH213854) +- Fixed an assertion failure when an array whose element type was still + incomplete when the array type was formed (for example, an array of a class + template specialization that is only instantiated later) turned out to be too + large once the element type was completed. Clang now diagnoses the oversized + array instead of asserting. (#GH213855) + #### Bug Fixes to AST Handling - Fixed a non-deterministic ordering of unused local typedefs that made diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4650bd53775f7..05ad0eb1ab3e5 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -15601,7 +15601,8 @@ class Sema final : public SemaBase { /// this routine then attempts to perform class template /// instantiation. If instantiation fails, or if @p T is incomplete /// and cannot be completed, issues the diagnostic @p diag (giving it - /// the type @p T) and returns true. + /// the type @p T) and returns true. The same applies to an array type + /// that turns out to be too large once its element type is complete. /// /// @param Loc The location in the source that the incomplete type /// diagnostic should refer to. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 07c6157ab8f31..7a1f79a64c841 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -14857,6 +14857,13 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { Var->setInvalidDecl(); return; } + // Completing the element type may reveal that the array is too large. + if (Type->isConstantArrayType() && + RequireCompleteType(Var->getLocation(), Type, + diag::err_typecheck_decl_incomplete_type)) { + Var->setInvalidDecl(); + return; + } } else { return; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index ad9204b12524b..270cf22ba4369 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -9687,6 +9687,28 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { } } +/// Return the (possibly nested) constant array type in \p T whose size cannot +/// be represented, if any. BuildArrayType can only check the element count if +/// the element type is still incomplete when the array type is formed. +static const ConstantArrayType *findArrayTypeTooLarge(const ASTContext &Context, + QualType T) { + const auto *CAT = dyn_cast<ConstantArrayType>(T.getCanonicalType()); + if (!CAT) + return nullptr; + + // Check nested arrays from the inside out. + QualType ElementType = CAT->getElementType(); + if (const ConstantArrayType *Inner = + findArrayTypeTooLarge(Context, ElementType)) + return Inner; + + if (ConstantArrayType::getNumAddressingBits(Context, ElementType, + CAT->getSize()) > + ConstantArrayType::getMaxSizeBits(Context)) + return CAT; + return nullptr; +} + bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, CompleteTypeKind Kind, TypeDiagnoser *Diagnoser) { @@ -9738,6 +9760,20 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, /*Recover*/ TreatAsComplete); return !TreatAsComplete; } + + // The element type may have been incomplete when the array type was + // formed, in which case BuildArrayType could not check the array's size. + if (T->isConstantArrayType() && !T->isDependentType() && + !T->isVariablyModifiedType() && !T->isUndeducedType()) { + if (const ConstantArrayType *CAT = findArrayTypeTooLarge(Context, T)) { + if (Diagnoser) + Diag(Loc, diag::err_array_too_large) + << toString(CAT->getSize(), 10, /*Signed=*/false, + /*formatAsCLiteral=*/false, /*UpperCase=*/false, + /*InsertSeparators=*/true); + return true; + } + } return false; } diff --git a/clang/test/SemaTemplate/GH213855.cpp b/clang/test/SemaTemplate/GH213855.cpp new file mode 100644 index 0000000000000..de4bea8b05907 --- /dev/null +++ b/clang/test/SemaTemplate/GH213855.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux-gnu %s + +// An array whose element type is incomplete when the array type is formed can +// only have its size checked once the element type is completed. + +namespace GH213855 { +template <unsigned Size> struct S : public CBdVfsImpl { // expected-error {{expected class name}} + double A[Size]; +}; +template <unsigned Size> struct SS { + S<Size> A[Size]; // expected-error {{array is too large (4'294'967'173 elements)}} +void foo() { SS<-123> ss; } // expected-error {{non-type template argument evaluates to -123, which cannot be narrowed to type 'unsigned int'}} \ + // expected-note {{in instantiation of template class 'GH213855::SS<4294967173>' requested here}} +}; +} // namespace GH213855 + +namespace array_variable { +template <unsigned Size> struct S { double A[Size]; }; +S<4294967173u> arr[4294967173u]; // expected-error {{array is too large (4'294'967'173 elements)}} +} // namespace array_variable + +namespace incomplete_element_type { +struct Incomplete; +extern Incomplete ok[2]; +extern Incomplete arr[4294967173]; +extern Incomplete arr2[2][4294967173]; +struct Incomplete { double A[4294967173]; }; +Incomplete arr3[4294967173]; // expected-error {{array is too large (4'294'967'173 elements)}} + +unsigned long n0 = sizeof(ok); +unsigned long n1 = sizeof(arr); // expected-error {{array is too large (4'294'967'173 elements)}} +unsigned long n2 = sizeof(arr2); // expected-error {{array is too large (4'294'967'173 elements)}} +} // namespace incomplete_element_type >From 5e7d3f32d7626bb30f30345ed4812d68372d5a1a Mon Sep 17 00:00:00 2001 From: Akash Manna <[email protected]> Date: Thu, 10 Sep 2026 19:55:05 +0530 Subject: [PATCH 2/3] [clang][Sema] Recheck array size once the element type is complete Report the deferred array-size diagnostic in bytes via a new err_array_size_too_large, since the element count was already accepted when the array type was formed. Rename the helper to getOversizedConstantArray, fold its preconditions into it, use getAsConstantArrayType instead of dyn_cast, and stream the APInt directly. Test that a non-dependent oversized array in a dependent context is diagnosed once, at the template definition. --- .../clang/Basic/DiagnosticSemaKinds.td | 3 ++ clang/lib/Sema/SemaType.cpp | 43 +++++++++++-------- clang/test/SemaTemplate/GH213855.cpp | 30 +++++++++++-- 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 9bd0a526654c7..99f4c36e5f7d9 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6727,6 +6727,9 @@ def err_vm_func_decl : Error< "function declaration cannot have variably modified type">; def err_array_too_large : Error< "array is too large (%0 elements)">; +def err_array_size_too_large : Error< + "array is too large (%0 bytes), which exceeds maximum allowed size of " + "%1 bytes">; def err_type_too_large_for_address_space : Error< "%0 is too large for the address space (maximum allowed size of %1 bytes)">; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 465b525ae3287..a04618d19095d 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -9688,19 +9688,26 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { } } -/// Return the (possibly nested) constant array type in \p T whose size cannot -/// be represented, if any. BuildArrayType can only check the element count if -/// the element type is still incomplete when the array type is formed. -static const ConstantArrayType *findArrayTypeTooLarge(const ASTContext &Context, - QualType T) { - const auto *CAT = dyn_cast<ConstantArrayType>(T.getCanonicalType()); +/// If \p T is (or contains) a constant array type whose size in bytes cannot +/// be represented within ConstantArrayType::getMaxSizeBits, return the +/// offending array type. Nested arrays are checked from the inside out, since +/// the size of an outer array can only be computed once its element's size is +/// known to fit. BuildArrayType can only check the element count if the +/// element type is still incomplete when the array type is formed, so the +/// size has to be rechecked once the element type is completed. +static const ConstantArrayType * +getOversizedConstantArray(const ASTContext &Context, QualType T) { + if (T->isDependentType() || T->isVariablyModifiedType() || + T->isUndeducedType()) + return nullptr; + + const ConstantArrayType *CAT = Context.getAsConstantArrayType(T); if (!CAT) return nullptr; - // Check nested arrays from the inside out. QualType ElementType = CAT->getElementType(); if (const ConstantArrayType *Inner = - findArrayTypeTooLarge(Context, ElementType)) + getOversizedConstantArray(Context, ElementType)) return Inner; if (ConstantArrayType::getNumAddressingBits(Context, ElementType, @@ -9764,16 +9771,18 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // The element type may have been incomplete when the array type was // formed, in which case BuildArrayType could not check the array's size. - if (T->isConstantArrayType() && !T->isDependentType() && - !T->isVariablyModifiedType() && !T->isUndeducedType()) { - if (const ConstantArrayType *CAT = findArrayTypeTooLarge(Context, T)) { - if (Diagnoser) - Diag(Loc, diag::err_array_too_large) - << toString(CAT->getSize(), 10, /*Signed=*/false, - /*formatAsCLiteral=*/false, /*UpperCase=*/false, - /*InsertSeparators=*/true); - return true; + if (const ConstantArrayType *CAT = getOversizedConstantArray(Context, T)) { + if (Diagnoser) { + CharUnits ElementSize = + Context.getTypeSizeInChars(CAT->getElementType()); + llvm::APInt SizeInBytes = CAT->getSize().zext(128) * + llvm::APInt(128, ElementSize.getQuantity()); + uint64_t MaxSizeInBytes = uint64_t(1) + << ConstantArrayType::getMaxSizeBits(Context); + Diag(Loc, diag::err_array_size_too_large) + << SizeInBytes << llvm::APInt(64, MaxSizeInBytes); } + return true; } return false; } diff --git a/clang/test/SemaTemplate/GH213855.cpp b/clang/test/SemaTemplate/GH213855.cpp index de4bea8b05907..bf47564560a03 100644 --- a/clang/test/SemaTemplate/GH213855.cpp +++ b/clang/test/SemaTemplate/GH213855.cpp @@ -8,7 +8,7 @@ template <unsigned Size> struct S : public CBdVfsImpl { // expected-error {{expe double A[Size]; }; template <unsigned Size> struct SS { - S<Size> A[Size]; // expected-error {{array is too large (4'294'967'173 elements)}} + S<Size> A[Size]; // expected-error {{array is too large (147'573'944'137'180'895'432 bytes), which exceeds maximum allowed size of 2'305'843'009'213'693'952 bytes}} void foo() { SS<-123> ss; } // expected-error {{non-type template argument evaluates to -123, which cannot be narrowed to type 'unsigned int'}} \ // expected-note {{in instantiation of template class 'GH213855::SS<4294967173>' requested here}} }; @@ -16,9 +16,31 @@ void foo() { SS<-123> ss; } // expected-error {{non-type template argument evalu namespace array_variable { template <unsigned Size> struct S { double A[Size]; }; -S<4294967173u> arr[4294967173u]; // expected-error {{array is too large (4'294'967'173 elements)}} +S<4294967173u> arr[4294967173u]; // expected-error {{array is too large (147'573'944'137'180'895'432 bytes)}} } // namespace array_variable +namespace dependent_context { +template <unsigned Size> struct S { double A[Size]; }; + +// Diagnosed once, at the template definition, not once per instantiation. +template <typename T> struct Parent { + S<4294967173u> A[4294967173u]; // expected-error {{array is too large (147'573'944'137'180'895'432 bytes)}} +}; +Parent<int> p1; +Parent<long> p2; + +template <typename T> struct Parent2 { + double A[2305843009213693952u]; // expected-error {{array is too large (2'305'843'009'213'693'952 elements)}} +}; +Parent2<int> p3; +Parent2<long> p4; + +template <typename T> struct ParentOK { + double A[4294967173u]; // ~2^35 bytes, still representable. +}; +ParentOK<int> ok; +} // namespace dependent_context + namespace incomplete_element_type { struct Incomplete; extern Incomplete ok[2]; @@ -28,6 +50,6 @@ struct Incomplete { double A[4294967173]; }; Incomplete arr3[4294967173]; // expected-error {{array is too large (4'294'967'173 elements)}} unsigned long n0 = sizeof(ok); -unsigned long n1 = sizeof(arr); // expected-error {{array is too large (4'294'967'173 elements)}} -unsigned long n2 = sizeof(arr2); // expected-error {{array is too large (4'294'967'173 elements)}} +unsigned long n1 = sizeof(arr); // expected-error {{array is too large (147'573'944'137'180'895'432 bytes)}} +unsigned long n2 = sizeof(arr2); // expected-error {{array is too large (147'573'944'137'180'895'432 bytes)}} } // namespace incomplete_element_type >From 9eafed710f24ce76740e25d187bccdb04b364685 Mon Sep 17 00:00:00 2001 From: Akash Manna <[email protected]> Date: Fri, 11 Sep 2026 14:17:43 +0530 Subject: [PATCH 3/3] simplify diagnostic wording, rename test to SemaCXX/array-size.cpp --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 +-- clang/lib/Sema/SemaType.cpp | 5 +---- .../{SemaTemplate/GH213855.cpp => SemaCXX/array-size.cpp} | 4 ++-- 3 files changed, 4 insertions(+), 8 deletions(-) rename clang/test/{SemaTemplate/GH213855.cpp => SemaCXX/array-size.cpp} (95%) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 99f4c36e5f7d9..552b3c55f8c2d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6728,8 +6728,7 @@ def err_vm_func_decl : Error< def err_array_too_large : Error< "array is too large (%0 elements)">; def err_array_size_too_large : Error< - "array is too large (%0 bytes), which exceeds maximum allowed size of " - "%1 bytes">; + "array is too large (%0 bytes)">; def err_type_too_large_for_address_space : Error< "%0 is too large for the address space (maximum allowed size of %1 bytes)">; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index a04618d19095d..b6ccecec29965 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -9777,10 +9777,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, Context.getTypeSizeInChars(CAT->getElementType()); llvm::APInt SizeInBytes = CAT->getSize().zext(128) * llvm::APInt(128, ElementSize.getQuantity()); - uint64_t MaxSizeInBytes = uint64_t(1) - << ConstantArrayType::getMaxSizeBits(Context); - Diag(Loc, diag::err_array_size_too_large) - << SizeInBytes << llvm::APInt(64, MaxSizeInBytes); + Diag(Loc, diag::err_array_size_too_large) << SizeInBytes; } return true; } diff --git a/clang/test/SemaTemplate/GH213855.cpp b/clang/test/SemaCXX/array-size.cpp similarity index 95% rename from clang/test/SemaTemplate/GH213855.cpp rename to clang/test/SemaCXX/array-size.cpp index bf47564560a03..02ec4af7d4b07 100644 --- a/clang/test/SemaTemplate/GH213855.cpp +++ b/clang/test/SemaCXX/array-size.cpp @@ -1,14 +1,14 @@ // RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux-gnu %s // An array whose element type is incomplete when the array type is formed can -// only have its size checked once the element type is completed. +// only have its size checked once the element type is completed (#GH213855). namespace GH213855 { template <unsigned Size> struct S : public CBdVfsImpl { // expected-error {{expected class name}} double A[Size]; }; template <unsigned Size> struct SS { - S<Size> A[Size]; // expected-error {{array is too large (147'573'944'137'180'895'432 bytes), which exceeds maximum allowed size of 2'305'843'009'213'693'952 bytes}} + S<Size> A[Size]; // expected-error {{array is too large (147'573'944'137'180'895'432 bytes)}} void foo() { SS<-123> ss; } // expected-error {{non-type template argument evaluates to -123, which cannot be narrowed to type 'unsigned int'}} \ // expected-note {{in instantiation of template class 'GH213855::SS<4294967173>' requested here}} }; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
