[clang] [clang] Fix crash constant-evaluating huge arrays of zero-sized elements (PR #226899)
Akash Manna via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 29 09:47:32 PDT 2026
https://github.com/akash-manna-sky updated https://github.com/llvm/llvm-project/pull/226899
>From 7fa7a3ec8b0f286948cc4369196a2da1d93d77da Mon Sep 17 00:00:00 2001
From: Akash Manna <akash.manna.mymail at gmail.com>
Date: Mon, 28 Sep 2026 12:31:57 +0530
Subject: [PATCH 1/3] [clang] Fix crash constant-evaluating huge arrays of
zero-sized elements
The array size limit in Sema only considered the total size in bytes, so
an array of zero-sized elements such as `T s[-sizeof(0)][0]` was accepted
with any element count. When the constant evaluator later default-
constructed or copied such an array, it truncated the element count to
unsigned and tried to allocate an APValue for every element, running out
of memory, or asserted in SubobjectDesignator::adjustIndex.
Check the element count against the limit as well, and route the array
construction and ArrayInitLoopExpr paths in the evaluator through the
existing CheckArraySize guard.
Fixes #173728
---
clang/docs/ReleaseNotes.md | 4 ++
clang/lib/AST/ExprConstant.cpp | 4 ++
clang/lib/Sema/SemaType.cpp | 14 +++---
clang/test/CodeGenCXX/stmtexpr.cpp | 5 +++
clang/test/Sema/array-size-64.c | 7 +++
.../cxx2a-constexpr-dynalloc-limits.cpp | 34 +++++++++++++++
clang/test/SemaCXX/zero-length-arrays.cpp | 43 ++++++++++++++++++-
7 files changed, 103 insertions(+), 8 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 3c6acf353f93f..9e1006db2c423 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -792,6 +792,10 @@ features cannot lower the translation-unit ABI level;
that was inherited from a different declarator, for example when
``__typeof__`` resolves to the type of another, already-processed
declaration. (#GH217489)
+- Fixed a crash when constant-evaluating a default-constructed or copied local
+ array with a huge number of zero-sized elements, e.g. ``T s[N][0]``. Such
+ arrays are now also diagnosed as too large when their element count exceeds
+ the limit that already applies to their size in bytes. (#GH173728)
- Fixed an assertion failure when instantiating a block that captures
`this` via a member access through a dependent base class.
- Fixed `DiagnoseUnguardedAvailability::TraverseIfStmt` dereferencing a nullptr
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 2df754dc9007f..5e3cfb6edba85 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -15860,6 +15860,8 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
return false;
auto *CAT = cast<ConstantArrayType>(E->getType()->castAsArrayTypeUnsafe());
+ if (!CheckArraySize(Info, CAT, E->getExprLoc()))
+ return false;
uint64_t Elements = CAT->getZExtSize();
Result = APValue(APValue::UninitArray(), Elements, Elements);
@@ -15906,6 +15908,8 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
bool HadZeroInit = Value->hasValue();
if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) {
+ if (!CheckArraySize(Info, CAT, E->getExprLoc()))
+ return false;
unsigned FinalSize = CAT->getZExtSize();
// Preserve the array filler if we had prior zero-initialization.
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index b5c71d72a23ff..85139ec4dd145 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2307,12 +2307,14 @@ QualType Sema::BuildArrayType(QualType T, ArraySizeModifier ASM,
return QualType();
}
- // Is the array too large?
- unsigned ActiveSizeBits =
- (!T->isDependentType() && !T->isVariablyModifiedType() &&
- !T->isIncompleteType() && !T->isUndeducedType())
- ? ConstantArrayType::getNumAddressingBits(Context, T, ConstVal)
- : ConstVal.getActiveBits();
+ // Is the array too large? Check the element count too, for zero-sized
+ // elements.
+ unsigned ActiveSizeBits = ConstVal.getActiveBits();
+ if (!T->isDependentType() && !T->isVariablyModifiedType() &&
+ !T->isIncompleteType() && !T->isUndeducedType())
+ ActiveSizeBits = std::max(
+ ActiveSizeBits,
+ ConstantArrayType::getNumAddressingBits(Context, T, ConstVal));
if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
Diag(ArraySize->getBeginLoc(), diag::err_array_too_large)
<< toString(ConstVal, 10, ConstVal.isSigned(),
diff --git a/clang/test/CodeGenCXX/stmtexpr.cpp b/clang/test/CodeGenCXX/stmtexpr.cpp
index 6e19ce864813f..ff3802b417c1c 100644
--- a/clang/test/CodeGenCXX/stmtexpr.cpp
+++ b/clang/test/CodeGenCXX/stmtexpr.cpp
@@ -78,6 +78,11 @@ int foo5(bool b) {
G: return y;
}
+// CHECK-LABEL: define{{.*}} i32 @gh173728()
+extern "C" int gh173728() {
+ return ({ struct T {} s[0xFFFFFFFFu][0]; 0; });
+}
+
// When we emit a full expression with cleanups that contains branches out of
// the full expression, the result of the inner expression (the call to
// call_with_cleanups in this case) may not dominate the fallthrough destination
diff --git a/clang/test/Sema/array-size-64.c b/clang/test/Sema/array-size-64.c
index 3e6339bd6a640..1a0c1923ab3f5 100644
--- a/clang/test/Sema/array-size-64.c
+++ b/clang/test/Sema/array-size-64.c
@@ -10,3 +10,10 @@ void pr8256(void) {
typedef char b[(long long)sizeof(a)-1];
}
+void gh173728(void) {
+ struct S {} a[-sizeof(0)][0]; // expected-error {{array is too large}}
+ int b[1ULL << 61][0]; // expected-error {{array is too large}}
+ int c[(1ULL << 61) - 1][0];
+ int d[1ULL << 40][0];
+}
+
diff --git a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
index 7537b47780aeb..73ce6d14108f3 100644
--- a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
+++ b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
@@ -99,3 +99,37 @@ void ohno() {
}
}
+
+namespace GH173728 {
+struct T {};
+
+template <auto N>
+constexpr int default_construct() {
+ T s[N][0]; // #gh173728-construct
+ return 0;
+}
+
+template <auto N>
+constexpr int capture_copy() {
+ T s[N][0] = {};
+ return [s] { return 0; }(); // #gh173728-capture
+}
+
+static_assert(default_construct<4>() == 0);
+static_assert(capture_copy<4>() == 0);
+
+static_assert(default_construct<1025>() == 0); // expected-error {{static assertion expression is not an integral constant expression}} \
+ // expected-note {{in call}}
+// expected-note@#gh173728-construct {{cannot allocate array; evaluated array bound 1025 exceeds the limit (1024)}}
+// expected-note@#gh173728-construct {{use -fconstexpr-steps}}
+
+#if __SIZEOF_SIZE_T__ == 8
+static_assert(default_construct<(1ULL << 33) - 1>() == 0); // expected-error {{static assertion expression is not an integral constant expression}} \
+ // expected-note {{in call}}
+// expected-note@#gh173728-construct {{cannot allocate array; evaluated array bound 8589934591 is too large}}
+
+static_assert(capture_copy<(1ULL << 33) - 1>() == 0); // expected-error {{static assertion expression is not an integral constant expression}} \
+ // expected-note {{in call}}
+// expected-note@#gh173728-capture {{cannot allocate array; evaluated array bound 8589934591 is too large}}
+#endif
+}
diff --git a/clang/test/SemaCXX/zero-length-arrays.cpp b/clang/test/SemaCXX/zero-length-arrays.cpp
index 6bfc7a5fd2e35..af1b61d4c0dd5 100644
--- a/clang/test/SemaCXX/zero-length-arrays.cpp
+++ b/clang/test/SemaCXX/zero-length-arrays.cpp
@@ -29,8 +29,6 @@ void testBar() {
Bar b2(b);
#if __cplusplus >= 201103L
// expected-error at -2 {{call to implicitly-deleted copy constructor of 'Bar}}
-#else
-// expected-no-diagnostics
#endif
b = b2;
}
@@ -48,3 +46,44 @@ void test () {
}
#endif
}
+
+namespace GH173728 {
+#if __SIZEOF_SIZE_T__ == 8
+int reduced() {
+ int i;
+ return ({
+ struct T {
+ } s[-sizeof(0)][0 == sizeof(i < 0)]; // expected-error {{array is too large}}
+ 0;
+ });
+}
+
+int original() {
+ int i = 0;
+ return 1 + ({
+ struct tree_el {
+ int val;
+ struct tree_el **right, *left;
+ } state_t[1 + -(sizeof(0x1c))][0 == sizeof(sizeof(i))]; // expected-error {{array is too large}}
+ 0x97 < 10000;
+ });
+}
+
+int too_large() {
+ return 1 + ({ struct T {} s[(1ULL << 33) - 1][0]; 0x97 < 10000; });
+}
+
+signed char too_large_no_fold() {
+ return ({ struct T {} s[(1ULL << 33) - 1][0]; 1000; });
+}
+#endif
+
+int over_limit() {
+ return 1 + ({ struct T {} s[0xFFFFFFFFu][0]; 0x97 < 10000; });
+}
+
+void small() {
+ signed char a = ({ struct T {} s[4]; 1000; }); // expected-warning {{implicit conversion from 'int' to 'signed char' changes value from 1000 to -24}}
+ signed char b = ({ struct T {} s[4][0]; 1000; }); // expected-warning {{implicit conversion from 'int' to 'signed char' changes value from 1000 to -24}}
+}
+}
>From d61846b73bd709c2fff4eba830f8d8424a519d44 Mon Sep 17 00:00:00 2001
From: Akash Manna <akash.manna.mymail at gmail.com>
Date: Mon, 28 Sep 2026 23:52:40 +0530
Subject: [PATCH 2/3] Drop the constant evaluator changes
Keep this PR to the Sema check. The evaluator guard for huge arrays that
Sema still accepts will be a separate PR, together with the bytecode
interpreter side.
---
clang/docs/ReleaseNotes.md | 8 ++--
clang/lib/AST/ExprConstant.cpp | 4 --
clang/test/CodeGenCXX/stmtexpr.cpp | 5 ---
clang/test/SemaCXX/GH173728.cpp | 21 +++++++++
.../cxx2a-constexpr-dynalloc-limits.cpp | 34 ---------------
clang/test/SemaCXX/zero-length-arrays.cpp | 43 +------------------
6 files changed, 27 insertions(+), 88 deletions(-)
create mode 100644 clang/test/SemaCXX/GH173728.cpp
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 9e1006db2c423..6074709fb11d2 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -792,10 +792,10 @@ features cannot lower the translation-unit ABI level;
that was inherited from a different declarator, for example when
``__typeof__`` resolves to the type of another, already-processed
declaration. (#GH217489)
-- Fixed a crash when constant-evaluating a default-constructed or copied local
- array with a huge number of zero-sized elements, e.g. ``T s[N][0]``. Such
- arrays are now also diagnosed as too large when their element count exceeds
- the limit that already applies to their size in bytes. (#GH173728)
+- Fixed a crash on arrays of zero-sized elements with a huge element count,
+ e.g. ``T s[-sizeof(0)][0]``. Such arrays are now diagnosed as too large when
+ their element count exceeds the limit that already applies to their size in
+ bytes. (#GH173728)
- Fixed an assertion failure when instantiating a block that captures
`this` via a member access through a dependent base class.
- Fixed `DiagnoseUnguardedAvailability::TraverseIfStmt` dereferencing a nullptr
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 5e3cfb6edba85..2df754dc9007f 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -15860,8 +15860,6 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
return false;
auto *CAT = cast<ConstantArrayType>(E->getType()->castAsArrayTypeUnsafe());
- if (!CheckArraySize(Info, CAT, E->getExprLoc()))
- return false;
uint64_t Elements = CAT->getZExtSize();
Result = APValue(APValue::UninitArray(), Elements, Elements);
@@ -15908,8 +15906,6 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
bool HadZeroInit = Value->hasValue();
if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) {
- if (!CheckArraySize(Info, CAT, E->getExprLoc()))
- return false;
unsigned FinalSize = CAT->getZExtSize();
// Preserve the array filler if we had prior zero-initialization.
diff --git a/clang/test/CodeGenCXX/stmtexpr.cpp b/clang/test/CodeGenCXX/stmtexpr.cpp
index ff3802b417c1c..6e19ce864813f 100644
--- a/clang/test/CodeGenCXX/stmtexpr.cpp
+++ b/clang/test/CodeGenCXX/stmtexpr.cpp
@@ -78,11 +78,6 @@ int foo5(bool b) {
G: return y;
}
-// CHECK-LABEL: define{{.*}} i32 @gh173728()
-extern "C" int gh173728() {
- return ({ struct T {} s[0xFFFFFFFFu][0]; 0; });
-}
-
// When we emit a full expression with cleanups that contains branches out of
// the full expression, the result of the inner expression (the call to
// call_with_cleanups in this case) may not dominate the fallthrough destination
diff --git a/clang/test/SemaCXX/GH173728.cpp b/clang/test/SemaCXX/GH173728.cpp
new file mode 100644
index 0000000000000..023d82856b739
--- /dev/null
+++ b/clang/test/SemaCXX/GH173728.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify %s
+
+int main() {
+ int i;
+ return ({
+ struct T {
+ } s[-sizeof(0)][0 == sizeof(i < 0)]; // expected-error {{array is too large (18'446'744'073'709'551'612 elements)}}
+ 0;
+ });
+}
+
+int original() {
+ int i = 0;
+ return 1 + ({
+ struct tree_el {
+ int val;
+ struct tree_el **right, *left;
+ } state_t[1 + -(sizeof(0x1c))][0 == sizeof(sizeof(i))]; // expected-error {{array is too large (18'446'744'073'709'551'613 elements)}}
+ 0x97 < 10000;
+ });
+}
diff --git a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
index 73ce6d14108f3..7537b47780aeb 100644
--- a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
+++ b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
@@ -99,37 +99,3 @@ void ohno() {
}
}
-
-namespace GH173728 {
-struct T {};
-
-template <auto N>
-constexpr int default_construct() {
- T s[N][0]; // #gh173728-construct
- return 0;
-}
-
-template <auto N>
-constexpr int capture_copy() {
- T s[N][0] = {};
- return [s] { return 0; }(); // #gh173728-capture
-}
-
-static_assert(default_construct<4>() == 0);
-static_assert(capture_copy<4>() == 0);
-
-static_assert(default_construct<1025>() == 0); // expected-error {{static assertion expression is not an integral constant expression}} \
- // expected-note {{in call}}
-// expected-note@#gh173728-construct {{cannot allocate array; evaluated array bound 1025 exceeds the limit (1024)}}
-// expected-note@#gh173728-construct {{use -fconstexpr-steps}}
-
-#if __SIZEOF_SIZE_T__ == 8
-static_assert(default_construct<(1ULL << 33) - 1>() == 0); // expected-error {{static assertion expression is not an integral constant expression}} \
- // expected-note {{in call}}
-// expected-note@#gh173728-construct {{cannot allocate array; evaluated array bound 8589934591 is too large}}
-
-static_assert(capture_copy<(1ULL << 33) - 1>() == 0); // expected-error {{static assertion expression is not an integral constant expression}} \
- // expected-note {{in call}}
-// expected-note@#gh173728-capture {{cannot allocate array; evaluated array bound 8589934591 is too large}}
-#endif
-}
diff --git a/clang/test/SemaCXX/zero-length-arrays.cpp b/clang/test/SemaCXX/zero-length-arrays.cpp
index af1b61d4c0dd5..6bfc7a5fd2e35 100644
--- a/clang/test/SemaCXX/zero-length-arrays.cpp
+++ b/clang/test/SemaCXX/zero-length-arrays.cpp
@@ -29,6 +29,8 @@ void testBar() {
Bar b2(b);
#if __cplusplus >= 201103L
// expected-error at -2 {{call to implicitly-deleted copy constructor of 'Bar}}
+#else
+// expected-no-diagnostics
#endif
b = b2;
}
@@ -46,44 +48,3 @@ void test () {
}
#endif
}
-
-namespace GH173728 {
-#if __SIZEOF_SIZE_T__ == 8
-int reduced() {
- int i;
- return ({
- struct T {
- } s[-sizeof(0)][0 == sizeof(i < 0)]; // expected-error {{array is too large}}
- 0;
- });
-}
-
-int original() {
- int i = 0;
- return 1 + ({
- struct tree_el {
- int val;
- struct tree_el **right, *left;
- } state_t[1 + -(sizeof(0x1c))][0 == sizeof(sizeof(i))]; // expected-error {{array is too large}}
- 0x97 < 10000;
- });
-}
-
-int too_large() {
- return 1 + ({ struct T {} s[(1ULL << 33) - 1][0]; 0x97 < 10000; });
-}
-
-signed char too_large_no_fold() {
- return ({ struct T {} s[(1ULL << 33) - 1][0]; 1000; });
-}
-#endif
-
-int over_limit() {
- return 1 + ({ struct T {} s[0xFFFFFFFFu][0]; 0x97 < 10000; });
-}
-
-void small() {
- signed char a = ({ struct T {} s[4]; 1000; }); // expected-warning {{implicit conversion from 'int' to 'signed char' changes value from 1000 to -24}}
- signed char b = ({ struct T {} s[4][0]; 1000; }); // expected-warning {{implicit conversion from 'int' to 'signed char' changes value from 1000 to -24}}
-}
-}
>From 253061eff9d00d484e1d5e84ad7847e26ff5dd08 Mon Sep 17 00:00:00 2001
From: Akash Manna <akash.manna.mymail at gmail.com>
Date: Tue, 29 Sep 2026 22:16:46 +0530
Subject: [PATCH 3/3] Fix the crash in the constant evaluators instead of Sema
Revert the Sema array size change, which only rejected the reproducer's
wrapped-around count. Route array default construction and
ArrayInitLoopExpr through the existing CheckArraySize guard in
ExprConstant, and emit the matching CheckArraySize opcode on the same
paths in the bytecode compiler.
---
clang/docs/ReleaseNotes.md | 8 ++--
clang/lib/AST/ByteCode/Compiler.cpp | 8 +++-
clang/lib/AST/ExprConstant.cpp | 4 ++
clang/lib/Sema/SemaType.cpp | 14 +++----
clang/test/AST/ByteCode/dynalloc-limits.cpp | 42 +++++++++++++++++++++
clang/test/Sema/array-size-64.c | 7 ----
clang/test/SemaCXX/GH173728.cpp | 21 -----------
7 files changed, 62 insertions(+), 42 deletions(-)
delete mode 100644 clang/test/SemaCXX/GH173728.cpp
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 6074709fb11d2..35dab3acbfa5b 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -792,10 +792,10 @@ features cannot lower the translation-unit ABI level;
that was inherited from a different declarator, for example when
``__typeof__`` resolves to the type of another, already-processed
declaration. (#GH217489)
-- Fixed a crash on arrays of zero-sized elements with a huge element count,
- e.g. ``T s[-sizeof(0)][0]``. Such arrays are now diagnosed as too large when
- their element count exceeds the limit that already applies to their size in
- bytes. (#GH173728)
+- Fixed a crash when the constant evaluator default-constructed or copied a
+ very large array, such as a local ``T s[0xFFFFFFFF][0]`` of an empty class
+ ``T``. Such evaluations now fail once the element count exceeds the
+ ``-fconstexpr-steps`` limit, as they already did for ``new``. (#GH173728)
- Fixed an assertion failure when instantiating a block that captures
`this` via a member access through a dependent base class.
- Fixed `DiagnoseUnguardedAvailability::TraverseIfStmt` dereferencing a nullptr
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 81c8fb0b9f17d..f204750afe84b 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -3033,6 +3033,8 @@ bool Compiler<Emitter>::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
const Expr *SubExpr = E->getSubExpr();
OptPrimType SubExprT = classify(SubExpr);
size_t Size = E->getArraySize().getZExtValue();
+ if (!this->emitCheckArraySize(Size, E))
+ return false;
if (SubExprT) {
// Unwrap the OpaqueValueExpr so we don't cache something we won't reuse.
@@ -4032,8 +4034,10 @@ bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) {
if (!CAT)
return false;
QualType ElemTy = CAT->getElementType();
- unsigned NumElems = CAT->getZExtSize();
- for (size_t I = 0; I != NumElems; ++I) {
+ uint64_t NumElems = CAT->getZExtSize();
+ if (!this->emitCheckArraySize(NumElems, E))
+ return false;
+ for (uint64_t I = 0; I != NumElems; ++I) {
if (!this->emitConstUint64(I, E))
return false;
if (!this->emitArrayElemPtrUint64(E))
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 2df754dc9007f..5e3cfb6edba85 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -15860,6 +15860,8 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
return false;
auto *CAT = cast<ConstantArrayType>(E->getType()->castAsArrayTypeUnsafe());
+ if (!CheckArraySize(Info, CAT, E->getExprLoc()))
+ return false;
uint64_t Elements = CAT->getZExtSize();
Result = APValue(APValue::UninitArray(), Elements, Elements);
@@ -15906,6 +15908,8 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
bool HadZeroInit = Value->hasValue();
if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) {
+ if (!CheckArraySize(Info, CAT, E->getExprLoc()))
+ return false;
unsigned FinalSize = CAT->getZExtSize();
// Preserve the array filler if we had prior zero-initialization.
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 85139ec4dd145..b5c71d72a23ff 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2307,14 +2307,12 @@ QualType Sema::BuildArrayType(QualType T, ArraySizeModifier ASM,
return QualType();
}
- // Is the array too large? Check the element count too, for zero-sized
- // elements.
- unsigned ActiveSizeBits = ConstVal.getActiveBits();
- if (!T->isDependentType() && !T->isVariablyModifiedType() &&
- !T->isIncompleteType() && !T->isUndeducedType())
- ActiveSizeBits = std::max(
- ActiveSizeBits,
- ConstantArrayType::getNumAddressingBits(Context, T, ConstVal));
+ // Is the array too large?
+ unsigned ActiveSizeBits =
+ (!T->isDependentType() && !T->isVariablyModifiedType() &&
+ !T->isIncompleteType() && !T->isUndeducedType())
+ ? ConstantArrayType::getNumAddressingBits(Context, T, ConstVal)
+ : ConstVal.getActiveBits();
if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
Diag(ArraySize->getBeginLoc(), diag::err_array_too_large)
<< toString(ConstVal, 10, ConstVal.isSigned(),
diff --git a/clang/test/AST/ByteCode/dynalloc-limits.cpp b/clang/test/AST/ByteCode/dynalloc-limits.cpp
index 85d66ac88ee2c..304c3248a5aa4 100644
--- a/clang/test/AST/ByteCode/dynalloc-limits.cpp
+++ b/clang/test/AST/ByteCode/dynalloc-limits.cpp
@@ -73,3 +73,45 @@ int d = stack_array<1025>();
constexpr int e = stack_array<1024>();
constexpr int f = stack_array<1025>(); // both-error {{constexpr variable 'f' must be initialized by a constant expression}} \
// both-note {{in call}}
+
+namespace GH173728 {
+struct T {};
+
+int stmt_expr() { return 1 + ({ T s[0xFFFFFFFFu][0]; 0x97 < 10000; }); }
+#if __SIZEOF_SIZE_T__ == 8
+int stmt_expr_truncated() {
+ return 1 + ({ T s[(1ULL << 33) - 1][0]; 0x97 < 10000; });
+}
+#endif
+
+template <auto N>
+constexpr int default_construct() {
+ T s[N][0]; // #gh173728-construct
+ return 0;
+}
+
+constexpr int construct_ok = default_construct<1024>();
+constexpr int construct_limit = default_construct<1025>(); // both-error {{constexpr variable 'construct_limit' must be initialized by a constant expression}} \
+ // both-note {{in call}}
+// both-note@#gh173728-construct {{cannot allocate array; evaluated array bound 1025 exceeds the limit (1024)}}
+// both-note@#gh173728-construct {{use -fconstexpr-steps}}
+
+#if __SIZEOF_SIZE_T__ == 8
+constexpr int construct_huge = default_construct<(1ULL << 33) - 1>(); // both-error {{constexpr variable 'construct_huge' must be initialized by a constant expression}} \
+ // ref-note {{in call}}
+// ref-note@#gh173728-construct {{cannot allocate array; evaluated array bound 8589934591 is too large}}
+#endif
+
+template <typename A>
+constexpr int capture_copy(const A &a) {
+ return [a] { return 0; }(); // #gh173728-capture
+}
+
+constexpr T src_ok[1024][0] = {};
+constexpr T src_limit[1025][0] = {};
+constexpr int capture_ok = capture_copy(src_ok);
+constexpr int capture_limit = capture_copy(src_limit); // both-error {{constexpr variable 'capture_limit' must be initialized by a constant expression}} \
+ // both-note {{in call}}
+// both-note@#gh173728-capture {{cannot allocate array; evaluated array bound 1025 exceeds the limit (1024)}}
+// both-note@#gh173728-capture {{use -fconstexpr-steps}}
+}
diff --git a/clang/test/Sema/array-size-64.c b/clang/test/Sema/array-size-64.c
index 1a0c1923ab3f5..3e6339bd6a640 100644
--- a/clang/test/Sema/array-size-64.c
+++ b/clang/test/Sema/array-size-64.c
@@ -10,10 +10,3 @@ void pr8256(void) {
typedef char b[(long long)sizeof(a)-1];
}
-void gh173728(void) {
- struct S {} a[-sizeof(0)][0]; // expected-error {{array is too large}}
- int b[1ULL << 61][0]; // expected-error {{array is too large}}
- int c[(1ULL << 61) - 1][0];
- int d[1ULL << 40][0];
-}
-
diff --git a/clang/test/SemaCXX/GH173728.cpp b/clang/test/SemaCXX/GH173728.cpp
deleted file mode 100644
index 023d82856b739..0000000000000
--- a/clang/test/SemaCXX/GH173728.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify %s
-
-int main() {
- int i;
- return ({
- struct T {
- } s[-sizeof(0)][0 == sizeof(i < 0)]; // expected-error {{array is too large (18'446'744'073'709'551'612 elements)}}
- 0;
- });
-}
-
-int original() {
- int i = 0;
- return 1 + ({
- struct tree_el {
- int val;
- struct tree_el **right, *left;
- } state_t[1 + -(sizeof(0x1c))][0 == sizeof(sizeof(i))]; // expected-error {{array is too large (18'446'744'073'709'551'613 elements)}}
- 0x97 < 10000;
- });
-}
More information about the cfe-commits
mailing list