https://github.com/adams381 updated 
https://github.com/llvm/llvm-project/pull/201654

>From dffed1eb7570356d7e053bbe7e6c2c2af2314170 Mon Sep 17 00:00:00 2001
From: Adam Smith <[email protected]>
Date: Thu, 4 Jun 2026 10:41:58 -0700
Subject: [PATCH 1/2] [CIR] Handle non-zero-initializable types in
 emitNullInitialization

Value-initializing an aggregate containing a pointer-to-data-member
(e.g. 'new Inner()' where Inner has an 'int Inner::*' field) crashed
with "type is not zero initializable" because emitNullInitialization
unconditionally called errorNYI for types where isZeroInitializable
returns false.

Member pointers use -1 as the null/invalid sentinel, so a plain zero
store is incorrect.  Replace the errorNYI with a call to
emitNullConstant, which already builds the correct per-field pattern
(-1 for member-pointer fields, zero elsewhere), and store the result.
Types with virtual bases are still guarded with errorNYI since
emitNullConstant does not yet handle them.
---
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp      | 15 ++++--
 .../CIR/CodeGen/member-pointer-null-init.cpp  | 47 +++++++++++++++++++
 2 files changed, 59 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/member-pointer-null-init.cpp

diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 4ecb47a864146..f16a5e6eb1574 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -1302,10 +1302,19 @@ void 
CIRGenFunction::emitNullInitialization(mlir::Location loc, Address destPtr,
 
   // If the type contains a pointer to data member we can't memset it to zero.
   // Instead, create a null constant and copy it to the destination.
-  // TODO: there are other patterns besides zero that we can usefully memset,
-  // like -1, which happens to be the pattern used by member-pointers.
+  // Member pointers use -1 as the null value, so a plain zero store would be
+  // incorrect; emitNullConstant produces the right per-field pattern.
   if (!cgm.getTypes().isZeroInitializable(ty)) {
-    cgm.errorNYI(loc, "type is not zero initializable");
+    // emitNullConstant does not yet handle types with virtual bases.
+    if (const auto *rd = ty->getAsCXXRecordDecl(); rd && rd->getNumVBases()) {
+      cgm.errorNYI(loc,
+                   "emitNullInitialization: non-zero-init type with virtual "
+                   "bases");
+      return;
+    }
+    mlir::Value nullVal = cgm.emitNullConstant(ty, loc);
+    builder.createStore(loc, nullVal, destPtr);
+    return;
   }
 
   // In LLVM Codegen: otherwise, just memset the whole thing to zero using
diff --git a/clang/test/CIR/CodeGen/member-pointer-null-init.cpp 
b/clang/test/CIR/CodeGen/member-pointer-null-init.cpp
new file mode 100644
index 0000000000000..74ee344c6f407
--- /dev/null
+++ b/clang/test/CIR/CodeGen/member-pointer-null-init.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir 
-emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir 
-emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM,LLVMCIR --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -emit-llvm %s 
-o %t.ll
+// RUN: FileCheck --check-prefix=LLVM,OGCG --input-file=%t.ll %s
+
+struct Inner {
+  int Inner::*p;
+};
+
+struct Outer {
+  Inner a;
+  int b;
+};
+
+// Value-init of a heap-allocated struct containing a pointer-to-data-member.
+// The member pointer is null (-1), so the stored constant must carry -1.
+
+// CIR-LABEL: cir.func {{.*}}@_Z8make_newv
+// CIR:         [[NULL:%.*]] = cir.const #cir.const_record<{#cir.int<-1> : 
!s64i}> : !rec_Inner
+// CIR:         cir.store align(8) [[NULL]], {{%.*}} : !rec_Inner, 
!cir.ptr<!rec_Inner>
+
+// LLVMCIR-LABEL: define {{.*}} ptr @_Z8make_newv
+// LLVMCIR:         call {{.*}} @_Znwm
+// LLVMCIR:         store %struct.Inner { i64 -1 }, ptr %{{.*}}, align 8
+
+// OGCG: @{{.*}} = private constant %struct.Inner { i64 -1 }
+// OGCG-LABEL: define {{.*}} ptr @_Z8make_newv
+// OGCG:         call {{.*}} @llvm.memcpy{{.*}}i64 8
+
+Inner *make_new() { return new Inner(); }
+
+// Partial aggregate init: Inner subobject 'a' is value-initialized because
+// it has no designated initializer.
+
+// CIR-LABEL: cir.func {{.*}}@_Z11runtime_aggi
+// CIR:         cir.const #cir.int<-1> : !s64i
+// CIR:         cir.store align(8) {{%.*}}, {{%.*}} : !s64i
+
+// LLVM-LABEL: define {{.*}} void @_Z11runtime_aggi
+// LLVM:          store i64 -1, ptr %{{.*}}, align 8
+
+void runtime_agg(int x) {
+  Outer o = {.b = x};
+  (void)o;
+}

>From 6bb221ecfc707b4ff6cc62f678d4282803b4e7d6 Mon Sep 17 00:00:00 2001
From: Adam Smith <[email protected]>
Date: Tue, 9 Jun 2026 09:41:31 -0700
Subject: [PATCH 2/2] [CIR] Fix null-init for non-zero-init aggregates

Value-initializing an aggregate containing a pointer-to-data-member
(e.g. 'new Inner()' where Inner has an 'int Inner::*' field) crashed
with "type is not zero initializable" because emitNullInitialization
unconditionally called errorNYI for types where isZeroInitializable
returns false.

Member pointers use -1 as the null/invalid sentinel, so a plain zero
store is incorrect.  Replace the errorNYI with a call to
emitNullConstant, which already builds the correct per-field pattern
(-1 for member-pointer fields, zero elsewhere), and store the result.
Types with virtual bases are still guarded with errorNYI since
emitNullConstant does not yet handle them.
---
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index f16a5e6eb1574..0a392b4202625 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -1302,10 +1302,15 @@ void 
CIRGenFunction::emitNullInitialization(mlir::Location loc, Address destPtr,
 
   // If the type contains a pointer to data member we can't memset it to zero.
   // Instead, create a null constant and copy it to the destination.
-  // Member pointers use -1 as the null value, so a plain zero store would be
-  // incorrect; emitNullConstant produces the right per-field pattern.
+  // TODO: there are other patterns besides zero that we can usefully memset,
+  // like -1, which happens to be the pattern used by member-pointers.
   if (!cgm.getTypes().isZeroInitializable(ty)) {
-    // emitNullConstant does not yet handle types with virtual bases.
+    // Classic codegen handles non-zero-init VLAs here via emitNonZeroVLAInit.
+    // In CIR, getTypeSizeInChars returns 0 for VLAs, so they are caught by
+    // the errorNYI above.
+    //
+    // Guard: emitNullConstant calls errorNYI for virtual bases and returns {},
+    // which would crash builder.getConstant; report the NYI here instead.
     if (const auto *rd = ty->getAsCXXRecordDecl(); rd && rd->getNumVBases()) {
       cgm.errorNYI(loc,
                    "emitNullInitialization: non-zero-init type with virtual "

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

Reply via email to