https://github.com/yronglin created 
https://github.com/llvm/llvm-project/pull/197458

This PR implement [P2752R3 'Static storage for braced 
initializers'](https://wg21.link/P2752R3).

Fixes https://github.com/llvm/llvm-project/issues/104487



>From 345e312510c89e67d69d686c05345b8351159054 Mon Sep 17 00:00:00 2001
From: yronglin <[email protected]>
Date: Wed, 13 May 2026 02:27:01 -0700
Subject: [PATCH] [C++26] Implement P2752R3 'Static storage for braced
 initializers'

Signed-off-by: yronglin <[email protected]>
---
 clang/docs/ReleaseNotes.rst                   |   3 +
 clang/lib/CodeGen/CGExpr.cpp                  |  44 ++++
 clang/lib/CodeGen/CGExprAgg.cpp               |  14 +-
 clang/lib/CodeGen/CodeGenFunction.h           |   2 +
 clang/lib/CodeGen/CodeGenModule.cpp           |  22 ++
 clang/lib/CodeGen/CodeGenModule.h             |   6 +
 .../dcl.decl/dcl.init/dcl.init.list/p5.cpp    |  71 +++++++
 .../cxx0x-initializer-stdinitializerlist.cpp  |   4 +-
 .../ptrauth-member-function-pointer.cpp       |   6 +-
 .../static-storage-for-initializer-list.cpp   | 190 ++++++++++++++++++
 clang/www/cxx_status.html                     |   2 +-
 11 files changed, 356 insertions(+), 8 deletions(-)
 create mode 100644 clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p5.cpp
 create mode 100644 
clang/test/CodeGenCXX/static-storage-for-initializer-list.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index bd91b8723a5c6..5af44ca30aa0f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -149,6 +149,9 @@ C++ Language Changes
 
 - ``__is_trivially_equality_comparable`` no longer returns false for all enum 
types. (#GH132672)
 
+- Clang now emits eligible ``std::initializer_list`` backing arrays in static
+  storage by default, implementing `P2752R3 <https://wg21.link/P2752R3>`_.
+
 C++2c Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 5764b59e538ae..b694bff950a23 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -511,6 +511,50 @@ static RawAddress createReferenceTemporary(CodeGenFunction 
&CGF,
   llvm_unreachable("unknown storage duration");
 }
 
+std::optional<RawAddress> CodeGenFunction::tryEmitStaticInitListBackingArray(
+    const MaterializeTemporaryExpr *M) {
+  switch (M->getStorageDuration()) {
+  case SD_FullExpression:
+  case SD_Automatic:
+    break;
+  case SD_Thread:
+  case SD_Static:
+    return std::nullopt;
+  case SD_Dynamic:
+    llvm_unreachable("temporary can't have dynamic storage duration");
+  }
+
+  SmallVector<const Expr *, 2> CommaLHSs;
+  SmallVector<SubobjectAdjustment, 2> Adjustments;
+  const Expr *E =
+      M->getSubExpr()->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
+  if (!Adjustments.empty())
+    return std::nullopt;
+
+  QualType ArrayType = E->getType();
+  if (!getContext().getAsConstantArrayType(ArrayType))
+    return std::nullopt;
+
+  QualType BaseElementType = getContext().getBaseElementType(ArrayType);
+  if (BaseElementType.isVolatileQualified())
+    return std::nullopt;
+
+  if (!ArrayType.isConstantStorage(getContext(), /*ExcludeCtor=*/true,
+                                   /*ExcludeDtor=*/false))
+    return std::nullopt;
+
+  llvm::Constant *Initializer =
+      ConstantEmitter(*this).tryEmitAbstract(E, ArrayType);
+  if (!Initializer)
+    return std::nullopt;
+
+  for (const Expr *Ignored : CommaLHSs)
+    EmitIgnoredExpr(Ignored);
+
+  CharUnits Alignment = getContext().getTypeAlignInChars(ArrayType);
+  return CGM.EmitStaticInitListBackingArray(ArrayType, Initializer, Alignment);
+}
+
 /// Helper method to check if the underlying ABI is AAPCS
 static bool isAAPCS(const TargetInfo &TargetInfo) {
   return TargetInfo.getABI().starts_with("aapcs");
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index a4282c4f51199..7f362398382e4 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -432,9 +432,17 @@ void AggExprEmitter::VisitCXXStdInitializerListExpr(
   // Emit an array containing the elements.  The array is externally destructed
   // if the std::initializer_list object is.
   ASTContext &Ctx = CGF.getContext();
-  LValue Array = CGF.EmitLValue(E->getSubExpr());
-  assert(Array.isSimple() && "initializer_list array not a simple lvalue");
-  Address ArrayPtr = Array.getAddress();
+  Address ArrayPtr = Address::invalid();
+  if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E->getSubExpr())) {
+    if (std::optional<RawAddress> StaticArray =
+            CGF.tryEmitStaticInitListBackingArray(MTE))
+      ArrayPtr = Address(*StaticArray);
+  }
+  if (!ArrayPtr.isValid()) {
+    LValue Array = CGF.EmitLValue(E->getSubExpr());
+    assert(Array.isSimple() && "initializer_list array not a simple lvalue");
+    ArrayPtr = Array.getAddress();
+  }
 
   const ConstantArrayType *ArrayType =
       Ctx.getAsConstantArrayType(E->getSubExpr()->getType());
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index 464bdeb801a29..8c6b78b9a1a85 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4482,6 +4482,8 @@ class CodeGenFunction : public CodeGenTypeCache {
   LValue EmitConditionalOperatorLValue(const AbstractConditionalOperator *E);
   LValue EmitCastLValue(const CastExpr *E);
   LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
+  std::optional<RawAddress>
+  tryEmitStaticInitListBackingArray(const MaterializeTemporaryExpr *E);
   LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
   LValue EmitHLSLArrayAssignLValue(const BinaryOperator *E);
 
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index 72a1f771962b1..38fc933ec2917 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -7570,6 +7570,28 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
   return ConstantAddress(CV, Type, Align);
 }
 
+ConstantAddress
+CodeGenModule::EmitStaticInitListBackingArray(QualType /*ArrayType*/,
+                                              llvm::Constant *Initializer,
+                                              CharUnits Alignment) {
+  LangAS AddrSpace = GetGlobalConstantAddressSpace();
+  auto TargetAS = getContext().getTargetAddressSpace(AddrSpace);
+  auto *GV = new llvm::GlobalVariable(
+      getModule(), Initializer->getType(), /*isConstant=*/true,
+      llvm::GlobalValue::PrivateLinkage, Initializer, ".init.list", nullptr,
+      llvm::GlobalValue::NotThreadLocal, TargetAS);
+  GV->setAlignment(Alignment.getAsAlign());
+
+  llvm::Constant *CV = GV;
+  if (AddrSpace != LangAS::Default)
+    CV = performAddrSpaceCast(
+        GV, llvm::PointerType::get(
+                getLLVMContext(),
+                getContext().getTargetAddressSpace(LangAS::Default)));
+
+  return ConstantAddress(CV, Initializer->getType(), Alignment);
+}
+
 /// EmitObjCPropertyImplementations - Emit information for synthesized
 /// properties for an implementation.
 void CodeGenModule::EmitObjCPropertyImplementations(const
diff --git a/clang/lib/CodeGen/CodeGenModule.h 
b/clang/lib/CodeGen/CodeGenModule.h
index b7dab4ef583ff..b666937286572 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1283,6 +1283,12 @@ class CodeGenModule : public CodeGenTypeCache {
   ConstantAddress GetAddrOfGlobalTemporary(const MaterializeTemporaryExpr *E,
                                            const Expr *Inner);
 
+  /// Create a private constant global for a std::initializer_list backing 
array
+  /// that CodeGen has chosen to place in static storage.
+  ConstantAddress EmitStaticInitListBackingArray(QualType ArrayType,
+                                                 llvm::Constant *Initializer,
+                                                 CharUnits Alignment);
+
   /// Retrieve the record type that describes the state of an
   /// Objective-C fast enumeration loop (for..in).
   QualType getObjCFastEnumerationStateType();
diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p5.cpp 
b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p5.cpp
new file mode 100644
index 0000000000000..450ef84ab6898
--- /dev/null
+++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p5.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 %std_cxx11- -triple x86_64-none-linux-gnu -emit-llvm -o - 
%s | FileCheck %s
+// RUN: %clang_cc1 %std_cxx11- -DVERIFY -fsyntax-only -verify %s
+
+namespace std {
+using size_t = decltype(sizeof(int));
+
+template <class E> class initializer_list {
+  const E *begin_;
+  size_t size_;
+
+public:
+  constexpr initializer_list() : begin_(nullptr), size_(0) {}
+  constexpr initializer_list(const E *begin, size_t size)
+      : begin_(begin), size_(size) {}
+  constexpr const E *begin() const { return begin_; }
+  constexpr size_t size() const { return size_; }
+};
+} // namespace std
+
+// CHECK-DAG: @[[STATIC_DOUBLES:.+]] = private constant [3 x double] [double 
1.000000e+00, double 2.000000e+00, double 3.000000e+00], align 8
+
+// [dcl.init.list] example 12.
+void f(std::initializer_list<double> il);
+
+void g(float x) {
+  // CHECK-LABEL: define{{.*}} void @_Z1gf(
+  // CHECK: alloca [3 x double]
+  f({1, x, 3});
+}
+
+void h() {
+  // CHECK-LABEL: define{{.*}} void @_Z1hv()
+  // CHECK-NOT: alloca [3 x double]
+  // CHECK: store ptr @[[STATIC_DOUBLES]], ptr
+  // CHECK: call void @_Z1fSt16initializer_listIdE(
+  f({1, 2, 3});
+}
+
+struct A {
+  mutable int i;
+};
+
+void q(std::initializer_list<A>);
+
+void r() {
+  // CHECK-LABEL: define{{.*}} void @_Z1rv()
+  // CHECK: alloca [3 x %struct.A]
+  q({A{1}, A{2}, A{3}});
+}
+
+struct Dtor {
+  int i;
+  ~Dtor();
+};
+
+void f_with_dtor(std::initializer_list<Dtor>);
+
+void non_trivial_dtor() {
+  // CHECK-LABEL: define{{.*}} void @_Z16non_trivial_dtorv()
+  // CHECK: alloca [3 x %struct.Dtor]
+  // CHECK: call void @_ZN4DtorD1Ev(
+  f_with_dtor({{1}, {2}, {3}});
+}
+
+#ifdef VERIFY
+struct C5 {
+  std::initializer_list<int> il; // expected-note {{'std::initializer_list' 
member declared here}}
+  C5() : il{1, 2, 3} {}
+  // expected-error@-1 {{backing array for 'std::initializer_list' member 'il' 
is a temporary object whose lifetime would be shorter than the lifetime of the 
constructed object}}
+};
+#endif
diff --git a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp 
b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
index 62ea3c991f26c..d813acd3c71f8 100644
--- a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -481,8 +481,8 @@ namespace B19773010 {
   void f1() {
     // CHECK-LABEL: @_ZN9B197730102f1Ev
     testcase a{{"", ENUM_CONSTANT}};
-    // X86: store ptr @.ref.tmp{{.*}}, ptr %{{.*}}, align 8
-    // AMDGCN: store ptr addrspacecast{{.*}} @.ref.tmp{{.*}}{{.*}}, ptr 
%{{.*}}, align 8
+    // X86: store ptr @.init.list{{.*}}, ptr %{{.*}}, align 8
+    // AMDGCN: store ptr addrspacecast{{.*}} @.init.list{{.*}}{{.*}}, ptr 
%{{.*}}, align 8
   }
   void f2() {
     // CHECK-LABEL: @_ZN9B197730102f2Ev
diff --git a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp 
b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
index e9436f11b5106..98ae76d082608 100644
--- a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
+++ b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
@@ -21,6 +21,8 @@
 // CHECK: @__const._Z13testArrayInitv.p1 = private unnamed_addr constant [1 x 
{ i64, i64 }] [{ i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN5Base08virtual1Ev_vfpthunk_, i32 0, i64 35591) to i64), i64 0 }], align 8
 // CHECK: @__const._Z13testArrayInitv.c0 = private unnamed_addr constant 
%struct.Class0 { { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN5Base011nonvirtual0Ev, i32 0, i64 35591) to i64), i64 0 } }, align 8
 // CHECK: @__const._Z13testArrayInitv.c1 = private unnamed_addr constant 
%struct.Class0 { { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN5Base08virtual1Ev_vfpthunk_, i32 0, i64 35591) to i64), i64 0 } }, align 8
+// CHECK: @[[INIT_LIST0:[.]init[.]list]] = private constant [1 x { i64, i64 }] 
[{ i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN5Base011nonvirtual0Ev, i32 
0, i64 [[TYPEDISC1]]) to i64), i64 0 }], align 8
+// CHECK: @[[INIT_LIST1:[.]init[.]list[.]1]] = private constant [1 x { i64, 
i64 }] [{ i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN5Base08virtual1Ev_vfpthunk_, i32 0, i64 [[TYPEDISC1]]) to i64), i64 0 }], 
align 8
 
 // CHECK: @_ZN22testNoexceptConversion6mfptr1E = global { i64, i64 } { i64 
ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 
[[TYPEDISC3:.*]]) to i64), i64 0 },
 // CHECK: @_ZN22testNoexceptConversion6mfptr2E = global { i64, i64 } { i64 
ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S16virtual_noexceptEv_vfpthunk_, i32 0, i64 
[[TYPEDISC3]]) to i64), i64 0 },
@@ -427,8 +429,8 @@ MethodTy0 gmethod2 = 
reinterpret_cast<MethodTy0>(&Derived0::virtual1);
 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %p1, ptr align 8 
@__const._Z13testArrayInitv.p1, i64 16, i1 false)
 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %c0, ptr align 8 
@__const._Z13testArrayInitv.c0, i64 16, i1 false)
 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %c1, ptr align 8 
@__const._Z13testArrayInitv.c1, i64 16, i1 false)
-// CHECK: store { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN5Base011nonvirtual0Ev, i32 0, i64 [[TYPEDISC1]]) to i64), i64 0 }, ptr 
%{{.*}} align 8
-// CHECK: store { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN5Base08virtual1Ev_vfpthunk_, i32 0, i64 [[TYPEDISC1]]) to i64), i64 0 }, 
ptr %{{.*}}, align 8
+// CHECK: store ptr @[[INIT_LIST0]], ptr %{{.*}}, align 8
+// CHECK: store ptr @[[INIT_LIST1]], ptr %{{.*}}, align 8
 
 void initList(std::initializer_list<MethodTy1>);
 
diff --git a/clang/test/CodeGenCXX/static-storage-for-initializer-list.cpp 
b/clang/test/CodeGenCXX/static-storage-for-initializer-list.cpp
new file mode 100644
index 0000000000000..52a2364380dc6
--- /dev/null
+++ b/clang/test/CodeGenCXX/static-storage-for-initializer-list.cpp
@@ -0,0 +1,190 @@
+// RUN: %clang_cc1 %std_cxx11- -triple x86_64-unknown-linux-gnu -emit-llvm -o 
- %s | FileCheck --check-prefixes=CHECK,X86,SIZE %s
+// RUN: %clang_cc1 %std_cxx11- -triple x86_64-unknown-linux-gnu 
-fmerge-all-constants -emit-llvm -o - %s | FileCheck --check-prefix=MERGE %s
+// RUN: %clang_cc1 %std_cxx11- -triple x86_64-unknown-linux-gnu -DSTART_END 
-emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,X86,END %s
+// RUN: %clang_cc1 %std_cxx11- -triple amdgcn-amd-amdhsa -emit-llvm -o - %s | 
FileCheck --check-prefixes=CHECK,AMDGCN,SIZE %s
+
+namespace std {
+typedef decltype(sizeof(int)) size_t;
+
+template <class _E> class initializer_list {
+#ifdef START_END
+  const _E *__begin_;
+  const _E *__end_;
+  constexpr initializer_list(const _E *__b, const _E *__e)
+      : __begin_(__b), __end_(__e) {}
+#else
+  const _E *__begin_;
+  size_t __size_;
+  constexpr initializer_list(const _E *__b, size_t __s)
+      : __begin_(__b), __size_(__s) {}
+#endif
+
+public:
+  typedef _E value_type;
+  typedef const _E &reference;
+  typedef const _E &const_reference;
+  typedef size_t size_type;
+  typedef const _E *iterator;
+  typedef const _E *const_iterator;
+
+#ifdef START_END
+  constexpr initializer_list() : __begin_(nullptr), __end_(nullptr) {}
+  constexpr size_t size() const { return __end_ - __begin_; }
+  constexpr const _E *end() const { return __end_; }
+#else
+  constexpr initializer_list() : __begin_(nullptr), __size_(0) {}
+  constexpr size_t size() const { return __size_; }
+  constexpr const _E *end() const { return __begin_ + __size_; }
+#endif
+  constexpr const _E *begin() const { return __begin_; }
+};
+} // namespace std
+
+// X86-DAG: @[[THREE_INTS:.+]] = private constant [3 x i32] [i32 1, i32 2, i32 
3], align 4
+// X86-DAG: @[[LOCAL_INTS:.+]] = private constant [3 x i32] [i32 4, i32 5, i32 
6], align 4
+// X86-DAG: @[[LIFETIME_INTS:.+]] = private constant [3 x i32] [i32 7, i32 8, 
i32 9], align 4
+// X86-DAG: @[[CLASS_VALUES:.+]] = private constant [2 x 
%{{.*}}ConstexprClass] [%{{.*}}ConstexprClass { i32 11 }, %{{.*}}ConstexprClass 
{ i32 12 }], align 4
+// X86-DAG: @[[ISSUE_A:_ZGRN11issue104487L1aE_]] = internal constant [1 x i8] 
c"x", align 1
+// X86-DAG: @[[ISSUE_B:_ZGRN11issue104487L1bE_]] = internal constant [1 x i8] 
c"x", align 1
+// MERGE-DAG: @_ZGRN11issue104487L1aE_ = internal constant [1 x i8] c"x", 
align 1
+// MERGE-DAG: @_ZGRN11issue104487L1bE_ = internal constant [1 x i8] c"x", 
align 1
+// AMDGCN-DAG: @[[THREE_INTS:.+]] = private addrspace(4) constant [3 x i32] 
[i32 1, i32 2, i32 3], align 4
+// AMDGCN-DAG: @[[LOCAL_INTS:.+]] = private addrspace(4) constant [3 x i32] 
[i32 4, i32 5, i32 6], align 4
+// AMDGCN-DAG: @[[LIFETIME_INTS:.+]] = private addrspace(4) constant [3 x i32] 
[i32 7, i32 8, i32 9], align 4
+// AMDGCN-DAG: @[[CLASS_VALUES:.+]] = private addrspace(4) constant [2 x 
%{{.*}}ConstexprClass] [%{{.*}}ConstexprClass { i32 11 }, %{{.*}}ConstexprClass 
{ i32 12 }], align 4
+// AMDGCN-DAG: @[[ISSUE_A:_ZGRN11issue104487L1aE_]] = internal addrspace(1) 
constant [1 x i8] c"x", align 1
+// AMDGCN-DAG: @[[ISSUE_B:_ZGRN11issue104487L1bE_]] = internal addrspace(1) 
constant [1 x i8] c"x", align 1
+
+void take_ints(std::initializer_list<int>);
+
+void constant_call() {
+  // CHECK-LABEL: define{{.*}} void @_Z13constant_callv()
+  // CHECK-NOT: alloca [3 x i32]
+  // X86: store ptr @[[THREE_INTS]], ptr
+  // AMDGCN: store ptr addrspacecast (ptr addrspace(4) @[[THREE_INTS]] to 
ptr), ptr
+  // SIZE: store i64 3,
+  // END: store ptr getelementptr inbounds nuw (i8, ptr @[[THREE_INTS]], i64 
12),
+  // CHECK: call void @_Z9take_intsSt16initializer_listIiE(
+  take_ints({1, 2, 3});
+}
+
+void local_list() {
+  // CHECK-LABEL: define{{.*}} void @_Z10local_listv()
+  // CHECK-NOT: alloca [3 x i32]
+  // X86: store ptr @[[LOCAL_INTS]], ptr
+  // AMDGCN: store ptr addrspacecast (ptr addrspace(4) @[[LOCAL_INTS]] to 
ptr), ptr
+  std::initializer_list<int> il = {4, 5, 6};
+  take_ints(il);
+}
+
+void empty_list() {
+  // CHECK-LABEL: define{{.*}} void @_Z10empty_listv()
+  // CHECK-NOT: alloca [0 x i32]
+  // CHECK: call void @_Z9take_intsSt16initializer_listIiE(
+  take_ints({});
+}
+
+void non_constant(int x) {
+  // CHECK-LABEL: define{{.*}} void @_Z12non_constanti(
+  // CHECK: alloca [3 x i32]
+  // CHECK: store i32 %{{.*}},
+  take_ints({1, x, 3});
+}
+
+void take_volatile(std::initializer_list<volatile int>);
+
+void volatile_element() {
+  // CHECK-LABEL: define{{.*}} void @_Z16volatile_elementv()
+  // CHECK: alloca [2 x i32]
+  take_volatile({21, 22});
+}
+
+struct MutableMember {
+  mutable int value;
+  constexpr MutableMember(int v) : value(v) {}
+};
+void take_mutable(std::initializer_list<MutableMember>);
+
+void mutable_member() {
+  // CHECK-LABEL: define{{.*}} void @_Z14mutable_memberv()
+  // CHECK: alloca [2 x %{{.*}}MutableMember]
+  take_mutable({MutableMember(31), MutableMember(32)});
+}
+
+struct NestedMutable {
+  MutableMember member;
+  constexpr NestedMutable(int v) : member(v) {}
+};
+void take_nested_mutable(std::initializer_list<NestedMutable>);
+
+void recursive_mutable() {
+  // CHECK-LABEL: define{{.*}} void @_Z17recursive_mutablev()
+  // CHECK: alloca [2 x %{{.*}}NestedMutable]
+  take_nested_mutable({NestedMutable(41), NestedMutable(42)});
+}
+
+struct NonTrivialDtor {
+  int value;
+  ~NonTrivialDtor();
+};
+void take_dtor(std::initializer_list<NonTrivialDtor>);
+
+void non_trivial_dtor() {
+  // CHECK-LABEL: define{{.*}} void @_Z16non_trivial_dtorv()
+  // CHECK: alloca [2 x %{{.*}}NonTrivialDtor]
+  // CHECK: call void @_ZN14NonTrivialDtorD1Ev(
+  take_dtor({{51}, {52}});
+}
+
+void take_ints_ref(const std::initializer_list<int> &);
+
+void lifetime_extension() {
+  // CHECK-LABEL: define{{.*}} void @_Z18lifetime_extensionv()
+  // CHECK-NOT: alloca [3 x i32]
+  // X86: store ptr @[[LIFETIME_INTS]], ptr
+  // AMDGCN: store ptr addrspacecast (ptr addrspace(4) @[[LIFETIME_INTS]] to 
ptr), ptr
+  const auto &il = std::initializer_list<int>{7, 8, 9};
+  take_ints_ref(il);
+}
+
+struct ConstexprClass {
+  int value;
+  constexpr ConstexprClass(int v) : value(v) {}
+};
+void take_class(std::initializer_list<ConstexprClass>);
+
+void literal_class() {
+  // CHECK-LABEL: define{{.*}} void @_Z13literal_classv()
+  // CHECK-NOT: alloca [2 x %{{.*}}ConstexprClass]
+  // X86: store ptr @[[CLASS_VALUES]], ptr
+  // AMDGCN: store ptr addrspacecast (ptr addrspace(4) @[[CLASS_VALUES]] to 
ptr), ptr
+  take_class({ConstexprClass(11), ConstexprClass(12)});
+}
+
+namespace issue104487 {
+static constexpr std::initializer_list<char> a = {'x'};
+static constexpr std::initializer_list<char> b = {'x'};
+static constexpr bool direct_value = a.begin() == b.begin();
+
+bool direct() {
+  // CHECK-LABEL: define{{.*}} noundef zeroext i1 @_ZN11issue1044876directEv()
+  // CHECK: ret i1 false
+  // MERGE-LABEL: define{{.*}} noundef zeroext i1 @_ZN11issue1044876directEv()
+  // MERGE: ret i1 false
+  return direct_value;
+}
+
+bool runtime() {
+  // CHECK-LABEL: define{{.*}} noundef zeroext i1 @_ZN11issue1044877runtimeEv()
+  // CHECK: store volatile ptr
+  // CHECK: store volatile ptr
+  // CHECK: icmp eq ptr
+  // MERGE-LABEL: define{{.*}} noundef zeroext i1 @_ZN11issue1044877runtimeEv()
+  // MERGE: @_ZN11issue104487L1aE
+  // MERGE: @_ZN11issue104487L1bE
+  // MERGE: icmp eq ptr
+  const char *volatile ap = a.begin();
+  const char *volatile bp = b.begin();
+  return ap == bp;
+}
+} // namespace issue104487
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 8b7290a2a60cc..1137e2161b5f7 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -135,7 +135,7 @@ <h2 id="cxx26">C++2c implementation status</h2>
  <tr>
   <td>Static storage for braced initializers</td>
   <td><a href="https://wg21.link/P2752R3";>P2752R3</a> (<a 
href="#dr">DR</a>)</td>
-  <td class="none" align="center">No</td>
+  <td class="unreleased" align="center">Clang 23</td>
  </tr>
  <tr>
   <td>User-generated <tt>static_assert</tt> messages</td>

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to