[clang] [clang] Fix constant-evaluator crash on array new with no size (PR #207730)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 6 06:10:02 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: DaanishD20
<details>
<summary>Changes</summary>
Fixes #<!-- -->200139.
## Summary
An array new-expression whose bound is neither specified nor deducible
from its initializer (for example `new int[]()`) is ill-formed and is
already diagnosed by Sema with `err: cannot determine allocated array
size from initializer`. However, the constant evaluator still tried to
evaluate the recovery expression. In `PointerExprEvaluator::VisitCXXNewExpr`
the array size is unavailable (`E->getArraySize()` is `nullopt`), so the
allocation fell through to the scalar-new path, producing an array
`APValue` stored under a scalar type. Reading that object later asserted
in `Type::castAsArrayTypeUnsafe()` (`isa<ArrayType>(CanonicalType)`) from
`CheckEvaluationResult`.
This patch detects an array new-expression whose size could not be
determined and bails out of constant evaluation, so the already-emitted
diagnostic stands and no crash occurs. Well-formed array new-expressions
are unaffected: an explicit bound (`new int[3]()`) or a bound deduced from
a braced initializer (`new int[]{1, 2, 3}`) both keep a non-null array
size and continue to evaluate as before.
## Reproducer (reduced by @<!-- -->efriedma-quic in the issue)
```c++
static_assert((new int[]())[0] == 0);
```
Before this change, an assertions build of clang crashed in
`Type::castAsArrayTypeUnsafe()`. After it, clang reports the error and
exits cleanly.
## Testing
- Added a regression test to `clang/test/SemaCXX/constant-expression-cxx2a.cpp`.
- Confirmed the reduced and the original fuzzer reproducers from the issue
no longer crash.
- `llvm-lit clang/test/SemaCXX/constant-expression-cxx2a.cpp clang/test/SemaCXX/new-delete.cpp clang/test/AST/ByteCode/new-delete.cpp` all pass.
---
Full diff: https://github.com/llvm/llvm-project/pull/207730.diff
3 Files Affected:
- (modified) clang/docs/ReleaseNotes.md (+1)
- (modified) clang/lib/AST/ExprConstant.cpp (+7)
- (modified) clang/test/SemaCXX/constant-expression-cxx2a.cpp (+6)
``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index b7142ecb072ff..e38b7c3b02caf 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -750,6 +750,7 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
- Fixed an assertion where we improperly handled implicit conversions to integral types from an atomic-type with a conversion function. (#GH201770)
- Fixed assertion failures involving code completion with delayed default arguments and exception specifications. (#GH200879)
- Fixed a regression where calling a function that takes a class-type parameter by value inside `decltype` of a concept could be incorrectly rejected when used as a non-type template argument. (#GH175831)
+- Fixed a crash in the constant evaluator when an ill-formed array new-expression whose bound could not be determined (e.g. `new int[]()`) was used in a constant expression. (#GH200139)
#### Bug Fixes to Compiler Builtins
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index fb82e0addfdac..bd188cd10f82f 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -10863,6 +10863,13 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
AllocType = Info.Ctx.getConstantArrayType(AllocType, ArrayBound, nullptr,
ArraySizeModifier::Normal, 0);
+ } else if (E->isArray()) {
+ // We have an array new-expression whose array size could not be
+ // determined, e.g. 'new int[]()', where the bound is neither given nor
+ // deducible from the initializer. This is ill-formed and already
+ // diagnosed, so bail out rather than mis-evaluating a scalar allocation
+ // as an array (which would later crash the evaluator).
+ return false;
} else {
assert(!AllocType->isArrayType() &&
"array allocation with non-array new");
diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index 396a8df21a3e3..94ecafc081302 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -898,6 +898,12 @@ namespace dynamic_alloc {
static_assert(erroneous_array_bound(-1)); // expected-error {{constant expression}} expected-note {{in call}}
static_assert(erroneous_array_bound(1LL << 62)); // expected-error {{constant expression}} expected-note {{in call}}
+ // An array new-expression whose bound is neither given nor deducible from the
+ // initializer is ill-formed; the constant evaluator must reject it gracefully
+ // rather than crash. See GH200139.
+ static_assert((new int[]())[0] == 0); // expected-error {{cannot determine allocated array size from initializer}} \
+ // expected-error {{static assertion expression is not an integral constant expression}}
+
constexpr bool erroneous_array_bound_nothrow(long long n) {
int *p = new (std::nothrow) int[n];
bool result = p != 0;
``````````
</details>
https://github.com/llvm/llvm-project/pull/207730
More information about the cfe-commits
mailing list