[clang] b46a38c - [CIR] Correct 'null' init for array types with non-zero init (#229543)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 6 17:09:22 PDT 2026
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>
More information about the cfe-commits
mailing list