[clang] [clang] Fix handling of certain new-expression corner cases (PR #131295)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 14 01:53:43 PDT 2025
https://github.com/offsetof created https://github.com/llvm/llvm-project/pull/131295
* Fix array bound not being deduced from the initializer when the new-expression does not directly contain the array declarator (e.g. because a typedef is used)
* Fix initialization of character arrays from parenthesized string literals not working before C++20
>From 78b3095b0e3ca4af1cd015bacd6173d3f4ab1777 Mon Sep 17 00:00:00 2001
From: offsetof <offsetof at mailo.com>
Date: Fri, 14 Mar 2025 08:38:58 +0000
Subject: [PATCH] [clang] Fix handling of certain new-expression corner cases
* Fix array bound not being deduced from the initializer when the
new-expression does not directly contain the array declarator
(e.g. because a typedef is used)
* Fix initialization of character arrays from parenthesized string
literals not working before C++20
---
clang/lib/Sema/SemaExprCXX.cpp | 33 ++++++++++++--------
clang/test/SemaCXX/P1009R2.cpp | 55 ++++++++++++++++++++++++++++++++++
2 files changed, 75 insertions(+), 13 deletions(-)
create mode 100644 clang/test/SemaCXX/P1009R2.cpp
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 34219e0235a74..638f5dd9e9c2d 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1939,7 +1939,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size)
<< D.getSourceRange());
- ArraySize = static_cast<Expr*>(Chunk.Arr.NumElts);
+ ArraySize = Chunk.Arr.NumElts;
D.DropFirstTypeObject();
}
@@ -1950,7 +1950,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
break;
DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr;
- if (Expr *NumElts = (Expr *)Array.NumElts) {
+ if (Expr *NumElts = Array.NumElts) {
if (!NumElts->isTypeDependent() && !NumElts->isValueDependent()) {
// FIXME: GCC permits constant folding here. We should either do so consistently
// or not do so at all, rather than changing behavior in C++14 onwards.
@@ -1996,13 +1996,15 @@ static bool isLegalArrayNewInitializer(CXXNewInitializationStyle Style,
if (!Init)
return true;
if (ParenListExpr *PLE = dyn_cast<ParenListExpr>(Init))
- return IsCPlusPlus20 || PLE->getNumExprs() == 0;
+ return IsCPlusPlus20 || PLE->getNumExprs() == 0 ||
+ (PLE->getNumExprs() == 1 &&
+ isa<StringLiteral>(PLE->getExpr(0)->IgnoreParens()));
if (isa<ImplicitValueInitExpr>(Init))
return true;
- else if (CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init))
+ if (CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init))
return !CCE->isListInitialization() &&
CCE->getConstructor()->isDefaultConstructor();
- else if (Style == CXXNewInitializationStyle::Braces) {
+ if (Style == CXXNewInitializationStyle::Braces) {
assert(isa<InitListExpr>(Init) &&
"Shouldn't create list CXXConstructExprs for arrays.");
return true;
@@ -2159,12 +2161,15 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// typedef of an array type.
// Dependent case will be handled separately.
if (!ArraySize && !AllocType->isDependentType()) {
- if (const ConstantArrayType *Array
- = Context.getAsConstantArrayType(AllocType)) {
- ArraySize = IntegerLiteral::Create(Context, Array->getSize(),
- Context.getSizeType(),
- TypeRange.getEnd());
- AllocType = Array->getElementType();
+ if (auto *Array = Context.getAsArrayType(AllocType)) {
+ auto *CAT = dyn_cast<ConstantArrayType>(Array);
+ if (CAT || isa<IncompleteArrayType>(Array)) {
+ ArraySize = CAT ? IntegerLiteral::Create(Context, CAT->getSize(),
+ Context.getSizeType(),
+ TypeRange.getEnd())
+ : nullptr;
+ AllocType = Array->getElementType();
+ }
}
}
@@ -2497,8 +2502,10 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// initializer is no greater than that constant value.
if (ArraySize && !*ArraySize) {
- auto *CAT = Context.getAsConstantArrayType(Initializer->getType());
- if (CAT) {
+ if (!Initializer)
+ Diag(TypeRange.getEnd(), diag::err_array_new_needs_size) << TypeRange;
+ else if (auto *CAT =
+ Context.getAsConstantArrayType(Initializer->getType())) {
// FIXME: Track that the array size was inferred rather than explicitly
// specified.
ArraySize = IntegerLiteral::Create(
diff --git a/clang/test/SemaCXX/P1009R2.cpp b/clang/test/SemaCXX/P1009R2.cpp
new file mode 100644
index 0000000000000..c89d912b29149
--- /dev/null
+++ b/clang/test/SemaCXX/P1009R2.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 %s -fsyntax-only -std=c++11 -verify=expected,until-cxx20
+// RUN: %clang_cc1 %s -fsyntax-only -std=c++20 -verify
+
+void f() {
+ new int[]; // expected-error {{array size must be specified in new expression with no initializer}}
+ new int[](); // expected-error {{cannot determine allocated array size from initializer}}
+ int* a = new int[](1, 2); // until-cxx20-error {{array 'new' cannot have initialization arguments}}
+ int* b = new int[] {};
+ int* c = new int[] {1, 2};
+
+ int* d = new (int[])(1, 2); // until-cxx20-error {{array 'new' cannot have initialization arguments}}
+ int* e = new (int[]) {1, 2};
+
+ using IA = int[];
+ new IA; // expected-error {{array size must be specified in new expression with no initializer}}
+ new IA(); // expected-error {{cannot determine allocated array size from initializer}}
+ int* f = new IA(1, 2); // until-cxx20-error {{array 'new' cannot have initialization arguments}}
+ int* g = new IA {};
+ int* h = new IA {1, 2};
+
+ extern int ia[];
+ int* i = new decltype(ia)(1, 2); // until-cxx20-error {{array 'new' cannot have initialization arguments}}
+ int* j = new decltype(ia) {1, 2};
+
+ char* k = new char[]("hello");
+ char* l = new char[] {"hello"};
+
+ using C = char;
+ char* m = new C[]("hello");
+ char* n = new C[] {"hello"};
+
+ using CA = char[];
+ char* o = new CA("hello");
+ char* p = new CA {"hello"};
+
+ extern wchar_t wa[];
+ wchar_t* q = new decltype(wa)(L"hello");
+ wchar_t* r = new decltype(wa) {L"hello"};
+}
+
+template<class IA = int[], class C = char, class CA = char[]>
+void g() {
+ new IA; // expected-error {{array size must be specified in new expression with no initializer}}
+ new IA(); // expected-error {{cannot determine allocated array size from initializer}}
+ int* a = new IA(1, 2); // until-cxx20-error {{array 'new' cannot have initialization arguments}}
+ int* b = new IA {1, 2};
+
+ char* c = new C[]("hello");
+ char* d = new C[] {"hello"};
+
+ char* e = new CA("hello");
+ char* f = new CA {"hello"};
+}
+
+template void g(); // expected-note {{in instantiation of function template specialization}}
More information about the cfe-commits
mailing list