Author: Erich Keane
Date: 2026-10-07T00:09:11Z
New Revision: b46a38ca6d8abab3f1cce34639f9ee2a09bbeaf9

URL: 
https://github.com/llvm/llvm-project/commit/b46a38ca6d8abab3f1cce34639f9ee2a09bbeaf9
DIFF: 
https://github.com/llvm/llvm-project/commit/b46a38ca6d8abab3f1cce34639f9ee2a09bbeaf9.diff

LOG: [CIR] Correct 'null' init for array types with non-zero init (#229543)

The member pointers are supposed to be initialized to -1, so an array of
them or a record of them needs to be initialized properly to -1. This
patch makes sure we look through array types/etc to get the correct
initialization.

Also, quite a few places were using 'getZeroAttr' when they meant 'null
init', so this changes that as well.

Added: 
    

Modified: 
    clang/lib/CIR/CodeGen/CIRGenDecl.cpp
    clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
    clang/lib/CIR/CodeGen/CIRGenModule.cpp
    clang/lib/CIR/CodeGen/CIRGenTypes.cpp
    clang/test/CIR/CodeGen/member-pointer-null-init.cpp
    clang/test/CIR/CodeGen/unions-with-zero-init.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp 
b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index 05776c5579678..1c15c2fd6ec65 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -536,7 +536,7 @@ CIRGenModule::getOrCreateStaticVarDecl(const VarDecl &d,
       d.hasAttr<CUDASharedAttr>() || d.hasAttr<LoaderUninitializedAttr>())
     init = cir::UndefAttr::get(lty);
   else
-    init = builder.getZeroInitAttr(convertType(ty));
+    init = emitNullConstantAttr(ty);
 
   mlir::ptr::MemorySpaceAttrInterface addrSpace = cir::toCIRAddressSpaceAttr(
       getMLIRContext(), getGlobalVarAddressSpace(&d));

diff  --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index bdfe477831e1c..cfe575f4670dd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -676,7 +676,7 @@ class ConstExprEmitter
 
   mlir::Attribute VisitImplicitValueInitExpr(ImplicitValueInitExpr *e,
                                              QualType t) {
-    return cgm.getBuilder().getZeroInitAttr(cgm.convertType(t));
+    return cgm.emitNullConstantAttr(t);
   }
 
   mlir::Attribute VisitInitListExpr(InitListExpr *ile, QualType t) {
@@ -1669,9 +1669,22 @@ mlir::TypedAttr 
CIRGenModule::emitNullConstantAttr(QualType t) {
   if (getTypes().isZeroInitializable(t))
     return builder.getZeroInitAttr(getTypes().convertTypeForMem(t));
 
-  if (getASTContext().getAsConstantArrayType(t)) {
-    errorNYI("CIRGenModule::emitNullConstantAttr ConstantArrayType");
-    return {};
+  if (const ConstantArrayType *cat =
+          getASTContext().getAsConstantArrayType(t)) {
+    QualType elementTy = cat->getElementType();
+    mlir::TypedAttr elementAttr = emitNullConstantAttr(elementTy);
+    if (!elementAttr)
+      return {};
+
+    auto arrayTy = mlir::cast<cir::ArrayType>(getTypes().convertTypeForMem(t));
+
+    if (builder.isNullValue(elementAttr))
+      return cir::ZeroAttr::get(arrayTy);
+
+    llvm::SmallVector<mlir::Attribute> elements(cat->getZExtSize(),
+                                                elementAttr);
+    return cir::ConstArrayAttr::get(
+        arrayTy, mlir::ArrayAttr::get(builder.getContext(), elements));
   }
 
   if (const RecordType *rt = t->getAs<RecordType>())

diff  --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 92c8af433aace..5e1a98a15ad40 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -1604,7 +1604,7 @@ void CIRGenModule::emitGlobalVarDefinition(const 
clang::VarDecl *vd,
     // exists. A use may still exists, however, so we still may need
     // to do a RAUW.
     assert(!vd->getType()->isIncompleteType() && "Unexpected incomplete type");
-    init = builder.getZeroInitAttr(convertType(vd->getType()));
+    init = emitNullConstantAttr(vd->getType());
   } else {
     emitter.emplace(*this);
     mlir::Attribute initializer = emitter->tryEmitForInitializer(*initDecl);
@@ -1617,7 +1617,7 @@ void CIRGenModule::emitGlobalVarDefinition(const 
clang::VarDecl *vd,
         if (initDecl->hasFlexibleArrayInit(astContext))
           errorNYI(vd->getSourceRange(),
                    "emitGlobalVarDefinition: flexible array initializer");
-        init = builder.getZeroInitAttr(convertType(qt));
+        init = emitNullConstantAttr(qt);
         if (!isDefinitionAvailableExternally)
           needsGlobalCtor = true;
       } else {

diff  --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp 
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index dff1ce1260787..09283cf7362bb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -735,7 +735,7 @@ CIRGenTypes::getCIRGenRecordLayout(const RecordDecl *rd) {
 }
 
 bool CIRGenTypes::isZeroInitializable(clang::QualType t) {
-  if (t->getAs<PointerType>())
+  if (t->getAs<PointerType>() || t->isNullPtrType())
     return astContext.getTargetNullPointerValue(t) == 0;
 
   if (const auto *at = astContext.getAsArrayType(t)) {
@@ -745,6 +745,8 @@ bool CIRGenTypes::isZeroInitializable(clang::QualType t) {
     if (const auto *cat = dyn_cast<ConstantArrayType>(at))
       if (astContext.getConstantArrayElementCount(cat) == 0)
         return true;
+
+    t = astContext.getBaseElementType(t);
   }
 
   if (const auto *rd = t->getAsRecordDecl())

diff  --git a/clang/test/CIR/CodeGen/member-pointer-null-init.cpp 
b/clang/test/CIR/CodeGen/member-pointer-null-init.cpp
index 74ee344c6f407..ca15d122f5cbb 100644
--- a/clang/test/CIR/CodeGen/member-pointer-null-init.cpp
+++ b/clang/test/CIR/CodeGen/member-pointer-null-init.cpp
@@ -14,8 +14,55 @@ struct Outer {
   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.
+struct Outer2 {
+  int Outer::*m[2];
+  int b;
+};
+
+// Arrays of pointer-to-data-member should be all -1s.
+
+// CIR: cir.global "private" internal dso_local @_ZZ12static_slotsvE8fn_slots 
= #cir.const_array<[#cir.int<-1> : !s64i, #cir.int<-1> : !s64i]> : 
!cir.array<!s64i x 2>
+// CIR: cir.global external @ns_slots = #cir.const_array<[#cir.int<-1> : 
!s64i, #cir.int<-1> : !s64i]> : !cir.array<!s64i x 2>
+
+// LLVM-DAG: @_ZZ12static_slotsvE8fn_slots = internal global [2 x i64] [i64 
-1, i64 -1]
+// LLVM-DAG: @ns_slots = {{.*}}global [2 x i64] [i64 -1, i64 -1]
+
+int Inner::*ns_slots[2];
+
+void static_slots() {
+  static int Inner::*fn_slots[2];
+  (void)fn_slots;
+}
+
+// CIR: cir.global external @vol_slots = #cir.const_array<[#cir.int<-1> : 
!s64i, #cir.int<-1> : !s64i]> : !cir.array<!s64i x 2>
+
+// LLVM-DAG: @vol_slots = {{.*}}global [2 x i64] [i64 -1, i64 -1]
+
+volatile int Inner::*vol_slots[2];
+
+// Array of record-types with the member pointer, also should have -1s.
+
+// CIR: cir.global external @rec_slots = 
#cir.const_array<[#cir.const_record<{#cir.int<-1> : !s64i}> : !rec_Inner, 
#cir.const_record<{#cir.int<-1> : !s64i}> : !rec_Inner]> : 
!cir.array<!rec_Inner x 2>
+
+// LLVM-DAG: @rec_slots = {{.*}}global [2 x %struct.Inner] [%struct.Inner { 
i64 -1 }, %struct.Inner { i64 -1 }]
+
+Inner rec_slots[2];
+
+// A nested (multi-dimensional) array of pointers-to-data-member must have
+// -1 in every innermost element.
+
+// CIR: cir.global external @md_slots = 
#cir.const_array<[#cir.const_array<[#cir.int<-1> : !s64i, #cir.int<-1> : !s64i, 
#cir.int<-1> : !s64i]> : !cir.array<!s64i x 3>, #cir.const_array<[#cir.int<-1> 
: !s64i, #cir.int<-1> : !s64i, #cir.int<-1> : !s64i]> : !cir.array<!s64i x 3>]> 
: !cir.array<!cir.array<!s64i x 3> x 2>
+
+// LLVM-DAG: @md_slots = {{.*}}global [2 x [3 x i64]] [{{\[3 x i64\]}} [i64 
-1, i64 -1, i64 -1], {{\[3 x i64\]}} [i64 -1, i64 -1, i64 -1]]
+
+int Inner::*md_slots[2][3];
+
+// CIR: cir.global external @initList = 
#cir.const_record<{#cir.const_array<[#cir.int<-1> : !s64i, #cir.int<-1> : 
!s64i]> : !cir.array<!s64i x 2>, #cir.int<1> : !s32i}> : !rec_Outer2 align(8)
+// LLVM-DAG: @initList = global %struct.Outer2 { [2 x i64] [i64 -1, i64 -1], 
i32 1 }, align 8
+
+Outer2 initList = {.b = 1};
+
+// Same with 'new' allocated types.
 
 // CIR-LABEL: cir.func {{.*}}@_Z8make_newv
 // CIR:         [[NULL:%.*]] = cir.const #cir.const_record<{#cir.int<-1> : 
!s64i}> : !rec_Inner
@@ -31,8 +78,7 @@ struct Outer {
 
 Inner *make_new() { return new Inner(); }
 
-// Partial aggregate init: Inner subobject 'a' is value-initialized because
-// it has no designated initializer.
+// Aggregate init should also get this right.
 
 // CIR-LABEL: cir.func {{.*}}@_Z11runtime_aggi
 // CIR:         cir.const #cir.int<-1> : !s64i

diff  --git a/clang/test/CIR/CodeGen/unions-with-zero-init.cpp 
b/clang/test/CIR/CodeGen/unions-with-zero-init.cpp
index 9c9cdc0165a15..ebddb95c545eb 100644
--- a/clang/test/CIR/CodeGen/unions-with-zero-init.cpp
+++ b/clang/test/CIR/CodeGen/unions-with-zero-init.cpp
@@ -47,12 +47,7 @@ int S::* p = nullptr;
 // CIR-AFTER-LABEL: cir.global external @p = #cir.int<-1> : !s64i
 // LLVM-DAG: @p = global i64 -1, align 8
 
-// LLVMCIR gets this 
diff erent because by the time we see how to do a 'zero'
-// field, we've already lost the member-pointer type, because LowerToLLVM is
-// doing the 'zeroing'.  We could be more clever here, but this is only in 
cases
-// where it gets initialized anyway.
-// LLVMCIR-DAG: @outer_a1 = global %union.outer_aggregate zeroinitializer
-// OGCG-DAG:    @outer_a1 = global %union.outer_aggregate { i64 -1 }
+// LLVM-DAG:    @outer_a1 = global %union.outer_aggregate { i64 -1 }
 
 // LLVM-DAG: @outer_a2 = global { i32, [4 x i8] } { i32 32, [4 x i8] {{.*}} }
 // LLVM-DAG: @outer_a3 = global %union.outer_aggregate3 { i64 -1 }
@@ -79,7 +74,7 @@ union outer_aggregate{int S::*m; int i; } outer_a1 = { p };
 // CIR-BEFORE:     cir.store {{.*}}%[[LOAD_P]], %[[GET_MEM]] : 
!cir.data_member<!s32i in !rec_S>, !cir.ptr<!cir.data_member<!s32i in !rec_S>>
 // CIR-BEFORE:   }
 
-// CIR-AFTER-LABEL: cir.global external @outer_a1 = #cir.zero : 
!rec_outer_aggregate
+// CIR-AFTER-LABEL: cir.global external @outer_a1 = 
#cir.const_record<{#cir.int<-1> : !s64i}> : !rec_outer_aggregate
 // CIR-AFTER-LABEL: cir.func internal private @__cxx_global_var_init() {
 // CIR-AFTER:   %[[GET_GLOB:.*]] = cir.get_global @outer_a1 : 
!cir.ptr<!rec_outer_aggregate>
 // CIR-AFTER:   %[[GET_MEM:.*]] = cir.get_member %[[GET_GLOB]][0] {name = "m"} 
: !cir.ptr<!rec_outer_aggregate> -> !cir.ptr<!s64i>


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

Reply via email to