[clang] [clang][bytecode] Handle negative array sizes in constexpr `new` instead of asserting (PR #155737)
Samarth Narang via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 27 20:43:12 PDT 2025
https://github.com/snarang181 updated https://github.com/llvm/llvm-project/pull/155737
>From 0b13b0e77e184666d46450b264e1237e6c41a1de Mon Sep 17 00:00:00 2001
From: Samarth Narang <snarang at umass.edu>
Date: Wed, 27 Aug 2025 22:45:25 -0400
Subject: [PATCH 1/3] Enable nullptr handle with negative elemsize in a dynamic
allocation
---
clang/lib/AST/ByteCode/Interp.h | 7 ++++++-
clang/test/SemaCXX/new-neg-size.cpp | 15 +++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
create mode 100644 clang/test/SemaCXX/new-neg-size.cpp
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 92e60b6b88e6a..e505712b60dd3 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -3490,7 +3490,12 @@ inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
S.Stk.push<Pointer>(0, nullptr);
return true;
}
- assert(NumElements.isPositive());
+ if (!NumElements.isPositive()) {
+ if (!IsNoThrow)
+ return false;
+ S.Stk.push<Pointer>(0, nullptr);
+ return true;
+ }
if (!CheckArraySize(S, OpPC, static_cast<uint64_t>(NumElements)))
return false;
diff --git a/clang/test/SemaCXX/new-neg-size.cpp b/clang/test/SemaCXX/new-neg-size.cpp
new file mode 100644
index 0000000000000..4b5a0d4bfe228
--- /dev/null
+++ b/clang/test/SemaCXX/new-neg-size.cpp
@@ -0,0 +1,15 @@
+// RUN: not %clang_cc1 -std=c++20 -fsyntax-only %s 2>&1 \
+// RUN: | FileCheck %s --implicit-check-not='Assertion `NumElements.isPositive()` failed'
+
+// In C++20, constexpr dynamic allocation is permitted *only* if valid.
+// A negative element count must be diagnosed (and must not crash).
+
+constexpr void f_bad_neg() {
+ int a = -1;
+ (void) new int[a]; // triggers negative-size path in the interpreter
+}
+
+// Force evaluation so we definitely run the constexpr interpreter.
+constexpr bool force_eval = (f_bad_neg(), true);
+
+// CHECK: error: constexpr function never produces a constant expression
>From 6d28107ebb963803b3bf6c4ae09734ec1ec6b526 Mon Sep 17 00:00:00 2001
From: Samarth Narang <snarang at umass.edu>
Date: Wed, 27 Aug 2025 23:10:05 -0400
Subject: [PATCH 2/3] Add test case
---
clang/test/SemaCXX/new-neg-size.cpp | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/clang/test/SemaCXX/new-neg-size.cpp b/clang/test/SemaCXX/new-neg-size.cpp
index 4b5a0d4bfe228..e03f34c183809 100644
--- a/clang/test/SemaCXX/new-neg-size.cpp
+++ b/clang/test/SemaCXX/new-neg-size.cpp
@@ -1,7 +1,7 @@
// RUN: not %clang_cc1 -std=c++20 -fsyntax-only %s 2>&1 \
// RUN: | FileCheck %s --implicit-check-not='Assertion `NumElements.isPositive()` failed'
-// In C++20, constexpr dynamic allocation is permitted *only* if valid.
+// In C++20, constexpr dynamic allocation is permitted only if valid.
// A negative element count must be diagnosed (and must not crash).
constexpr void f_bad_neg() {
@@ -9,7 +9,17 @@ constexpr void f_bad_neg() {
(void) new int[a]; // triggers negative-size path in the interpreter
}
-// Force evaluation so we definitely run the constexpr interpreter.
-constexpr bool force_eval = (f_bad_neg(), true);
+struct __nothrow_t { };
+extern const __nothrow_t __nothrow_dummy;
+void* operator new[](unsigned long, const __nothrow_t&) noexcept;
-// CHECK: error: constexpr function never produces a constant expression
+// Ensure we take the nothrow overload.
+constexpr void f_bad_neg_nothrow() {
+ (void) new (__nothrow_dummy) int[-7]; // should evaluate to nullptr (no crash)
+}
+
+// Force evaluation so the constexpr interpreter actually runs both cases.
+constexpr bool force_eval1 = (f_bad_neg(), true);
+constexpr bool force_eval2 = (f_bad_neg_nothrow(), true);
+
+// CHECK: error: constexpr function {{(never produces|is not a)}} constant expression
\ No newline at end of file
>From 204c5995105abf8aa8c7949754ddecda2dd3e95e Mon Sep 17 00:00:00 2001
From: Samarth Narang <snarang at umass.edu>
Date: Wed, 27 Aug 2025 23:42:39 -0400
Subject: [PATCH 3/3] Revert "Add test case"
This reverts commit 6d28107ebb963803b3bf6c4ae09734ec1ec6b526.
---
clang/test/SemaCXX/new-neg-size.cpp | 18 ++++--------------
1 file changed, 4 insertions(+), 14 deletions(-)
diff --git a/clang/test/SemaCXX/new-neg-size.cpp b/clang/test/SemaCXX/new-neg-size.cpp
index e03f34c183809..4b5a0d4bfe228 100644
--- a/clang/test/SemaCXX/new-neg-size.cpp
+++ b/clang/test/SemaCXX/new-neg-size.cpp
@@ -1,7 +1,7 @@
// RUN: not %clang_cc1 -std=c++20 -fsyntax-only %s 2>&1 \
// RUN: | FileCheck %s --implicit-check-not='Assertion `NumElements.isPositive()` failed'
-// In C++20, constexpr dynamic allocation is permitted only if valid.
+// In C++20, constexpr dynamic allocation is permitted *only* if valid.
// A negative element count must be diagnosed (and must not crash).
constexpr void f_bad_neg() {
@@ -9,17 +9,7 @@ constexpr void f_bad_neg() {
(void) new int[a]; // triggers negative-size path in the interpreter
}
-struct __nothrow_t { };
-extern const __nothrow_t __nothrow_dummy;
-void* operator new[](unsigned long, const __nothrow_t&) noexcept;
+// Force evaluation so we definitely run the constexpr interpreter.
+constexpr bool force_eval = (f_bad_neg(), true);
-// Ensure we take the nothrow overload.
-constexpr void f_bad_neg_nothrow() {
- (void) new (__nothrow_dummy) int[-7]; // should evaluate to nullptr (no crash)
-}
-
-// Force evaluation so the constexpr interpreter actually runs both cases.
-constexpr bool force_eval1 = (f_bad_neg(), true);
-constexpr bool force_eval2 = (f_bad_neg_nothrow(), true);
-
-// CHECK: error: constexpr function {{(never produces|is not a)}} constant expression
\ No newline at end of file
+// CHECK: error: constexpr function never produces a constant expression
More information about the cfe-commits
mailing list