[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