[clang] [clang][CodeGen] Zero init unspecified fields in initializers in C (#78034) (PR #97121)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 28 15:54:59 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: None (yabinc)
<details>
<summary>Changes</summary>
When an initializer is provided to a variable, the Linux kernel relies on clang to zero-initialize unspecified fields. But clang doesn't guarantee this:
1. For a union type, if an empty initializer is given, clang only initializes bytes for the first field, left bytes for other (larger) fields are marked as undef. Accessing those undef bytes can lead to undefined behaviors, causing bugs like reported in https://patchwork.kernel.org/project/netdevbpf/patch/20240621211819.1690234-1-yabinc@<!-- -->google.com/#<!-- -->25906597.
2. For a union type, if an initializer explicitly sets a field, left bytes for other (larger) fields are marked as undef.
3. When an initializer is given, clang doesn't zero initialize padding.
So this patch makes the following change:
In C, when an initializer is provided for a variable, zero-initialize undef and padding fields in the initializer.
---
Patch is 35.66 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/97121.diff
18 Files Affected:
- (modified) clang/lib/CodeGen/CGDecl.cpp (+43-20)
- (modified) clang/lib/CodeGen/CodeGenModule.cpp (+6)
- (modified) clang/lib/CodeGen/CodeGenModule.h (+2)
- (modified) clang/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c (+1-1)
- (modified) clang/test/CodeGen/2008-08-07-AlignPadding1.c (+2-2)
- (modified) clang/test/CodeGen/64bit-swiftcall.c (+5-7)
- (modified) clang/test/CodeGen/arm-swiftcall.c (+2-2)
- (modified) clang/test/CodeGen/const-init.c (+2-2)
- (modified) clang/test/CodeGen/designated-initializers.c (+6-6)
- (modified) clang/test/CodeGen/flexible-array-init.c (+12-12)
- (modified) clang/test/CodeGen/global-init.c (+1-1)
- (modified) clang/test/CodeGen/init.c (-19)
- (added) clang/test/CodeGen/linux-kernel-struct-union-initializer.c (+212)
- (modified) clang/test/CodeGen/mingw-long-double.c (+3-6)
- (modified) clang/test/CodeGen/mms-bitfields.c (+2-2)
- (modified) clang/test/CodeGen/union-init2.c (+2-2)
- (modified) clang/test/CodeGen/windows-swiftcall.c (+5-7)
- (modified) clang/test/CodeGenObjC/designated-initializers.m (+1-1)
``````````diff
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 90aa4c0745a8a..960add12f323b 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -334,6 +334,13 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
return Addr;
}
+enum class IsPattern { No, Yes };
+
+static llvm::Constant *replaceUndef(CodeGenModule &CGM, IsPattern isPattern,
+ llvm::Constant *constant);
+static llvm::Constant *constWithPadding(CodeGenModule &CGM, IsPattern isPattern,
+ llvm::Constant *constant);
+
/// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the
/// global variable that has already been created for it. If the initializer
/// has a different type than GV does, this may free GV and return a different
@@ -360,6 +367,13 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
}
return GV;
}
+ if (getLangOpts().C99) {
+ // In C, static initialization guarantees that padding is initialized to
+ // zero bits. And the Linux kernel relies on clang to zero-initialize
+ // unspecified fields.
+ Init = constWithPadding(CGM, IsPattern::No,
+ replaceUndef(CGM, IsPattern::No, Init));
+ }
#ifndef NDEBUG
CharUnits VarSize = CGM.getContext().getTypeSizeInChars(D.getType()) +
@@ -1037,8 +1051,6 @@ static bool shouldSplitConstantStore(CodeGenModule &CGM,
return false;
}
-enum class IsPattern { No, Yes };
-
/// Generate a constant filled with either a pattern or zeroes.
static llvm::Constant *patternOrZeroFor(CodeGenModule &CGM, IsPattern isPattern,
llvm::Type *Ty) {
@@ -1048,9 +1060,6 @@ static llvm::Constant *patternOrZeroFor(CodeGenModule &CGM, IsPattern isPattern,
return llvm::Constant::getNullValue(Ty);
}
-static llvm::Constant *constWithPadding(CodeGenModule &CGM, IsPattern isPattern,
- llvm::Constant *constant);
-
/// Helper function for constWithPadding() to deal with padding in structures.
static llvm::Constant *constStructWithPadding(CodeGenModule &CGM,
IsPattern isPattern,
@@ -1108,6 +1117,9 @@ static llvm::Constant *constWithPadding(CodeGenModule &CGM, IsPattern isPattern,
if (ZeroInitializer) {
OpValue = llvm::Constant::getNullValue(ElemTy);
PaddedOp = constWithPadding(CGM, isPattern, OpValue);
+ // Avoid iterating large arrays with zero initializer when possible.
+ if (PaddedOp->getType() == ElemTy)
+ return constant;
}
for (unsigned Op = 0; Op != Size; ++Op) {
if (!ZeroInitializer) {
@@ -1953,21 +1965,26 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
D.mightBeUsableInConstantExpressions(getContext())) {
assert(!capturedByInit && "constant init contains a capturing block?");
constant = ConstantEmitter(*this).tryEmitAbstractForInitializer(D);
- if (constant && !constant->isZeroValue() &&
- (trivialAutoVarInit !=
- LangOptions::TrivialAutoVarInitKind::Uninitialized)) {
- IsPattern isPattern =
- (trivialAutoVarInit == LangOptions::TrivialAutoVarInitKind::Pattern)
- ? IsPattern::Yes
- : IsPattern::No;
- // C guarantees that brace-init with fewer initializers than members in
- // the aggregate will initialize the rest of the aggregate as-if it were
- // static initialization. In turn static initialization guarantees that
- // padding is initialized to zero bits. We could instead pattern-init if D
- // has any ImplicitValueInitExpr, but that seems to be unintuitive
- // behavior.
- constant = constWithPadding(CGM, IsPattern::No,
- replaceUndef(CGM, isPattern, constant));
+ if (constant && !constant->isZeroValue()) {
+ if (getLangOpts().C99) {
+ // C guarantees that brace-init with fewer initializers than members in
+ // the aggregate will initialize the rest of the aggregate as-if it were
+ // static initialization. In turn static initialization guarantees that
+ // padding is initialized to zero bits. And the Linux kernel relies on
+ // clang to zero-initialize unspecified fields.
+ constant = constWithPadding(CGM, IsPattern::No,
+ replaceUndef(CGM, IsPattern::No, constant));
+ } else if (trivialAutoVarInit !=
+ LangOptions::TrivialAutoVarInitKind::Uninitialized) {
+ IsPattern isPattern =
+ (trivialAutoVarInit == LangOptions::TrivialAutoVarInitKind::Pattern)
+ ? IsPattern::Yes
+ : IsPattern::No;
+ // We could instead pattern-init padding if D has any
+ // ImplicitValueInitExpr, but that seems to be unintuitive behavior.
+ constant = constWithPadding(CGM, IsPattern::No,
+ replaceUndef(CGM, isPattern, constant));
+ }
}
}
@@ -2849,3 +2866,9 @@ CodeGenModule::getOMPAllocateAlignment(const VarDecl *VD) {
}
return std::nullopt;
}
+
+llvm::Constant *
+CodeGenModule::zeroInitGlobalVarInitializer(llvm::Constant *Init) {
+ return constWithPadding(*this, IsPattern::No,
+ replaceUndef(*this, IsPattern::No, Init));
+}
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 652f519d82488..a29eafa2fad68 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -5433,6 +5433,12 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
Init = llvm::UndefValue::get(getTypes().ConvertType(T));
}
} else {
+ if (getLangOpts().C99) {
+ // In C, static initialization guarantees that padding is initialized
+ // to zero bits. And the Linux kernel relies on clang to
+ // zero-initialize unspecified fields.
+ Initializer = zeroInitGlobalVarInitializer(Initializer);
+ }
Init = Initializer;
// We don't need an initializer, so remove the entry for the delayed
// initializer position (just in case this entry was delayed) if we
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 22b2b314c316c..3222de2a32e6d 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1837,6 +1837,8 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::Metadata *CreateMetadataIdentifierImpl(QualType T, MetadataTypeMap &Map,
StringRef Suffix);
+
+ llvm::Constant *zeroInitGlobalVarInitializer(llvm::Constant *Init);
};
} // end namespace CodeGen
diff --git a/clang/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c b/clang/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c
index b72d689659e60..b639734ef5d4b 100644
--- a/clang/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c
+++ b/clang/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c
@@ -8,4 +8,4 @@ struct et7 {
52,
};
-// CHECK: @yv7 ={{.*}} global %struct.et7 { [0 x float] zeroinitializer, i8 52 }
+// CHECK: @yv7 ={{.*}} global { [0 x float], i8, [3 x i8] } { [0 x float] zeroinitializer, i8 52, [3 x i8] zeroinitializer }
diff --git a/clang/test/CodeGen/2008-08-07-AlignPadding1.c b/clang/test/CodeGen/2008-08-07-AlignPadding1.c
index 17e88ce02659f..d69cbc22cc1df 100644
--- a/clang/test/CodeGen/2008-08-07-AlignPadding1.c
+++ b/clang/test/CodeGen/2008-08-07-AlignPadding1.c
@@ -20,9 +20,9 @@ struct gc_generation {
#define GEN_HEAD(n) (&generations[n].head)
-// The idea is that there are 6 undefs in this structure initializer to cover
+// The idea is that there are 6 zeroinitializers in this structure initializer to cover
// the padding between elements.
-// CHECK: @generations ={{.*}} global [3 x %struct.gc_generation] [%struct.gc_generation { %union._gc_head { %struct.anon { ptr @generations, ptr @generations, i64 0 }, [8 x i8] undef }, i32 700, i32 0, [8 x i8] undef }, %struct.gc_generation { %union._gc_head { %struct.anon { ptr getelementptr (i8, ptr @generations, i64 48), ptr getelementptr (i8, ptr @generations, i64 48), i64 0 }, [8 x i8] undef }, i32 10, i32 0, [8 x i8] undef }, %struct.gc_generation { %union._gc_head { %struct.anon { ptr getelementptr (i8, ptr @generations, i64 96), ptr getelementptr (i8, ptr @generations, i64 96), i64 0 }, [8 x i8] undef }, i32 10, i32 0, [8 x i8] undef }]
+// CHECK: @generations ={{.*}} global [3 x %struct.gc_generation] [%struct.gc_generation { %union._gc_head { %struct.anon { ptr @generations, ptr @generations, i64 0 }, [8 x i8] zeroinitializer }, i32 700, i32 0, [8 x i8] zeroinitializer }, %struct.gc_generation { %union._gc_head { %struct.anon { ptr getelementptr (i8, ptr @generations, i64 48), ptr getelementptr (i8, ptr @generations, i64 48), i64 0 }, [8 x i8] zeroinitializer }, i32 10, i32 0, [8 x i8] zeroinitializer }, %struct.gc_generation { %union._gc_head { %struct.anon { ptr getelementptr (i8, ptr @generations, i64 96), ptr getelementptr (i8, ptr @generations, i64 96), i64 0 }, [8 x i8] zeroinitializer }, i32 10, i32 0, [8 x i8] zeroinitializer }]
/* linked lists of container objects */
struct gc_generation generations[3] = {
/* PyGC_Head, threshold, count */
diff --git a/clang/test/CodeGen/64bit-swiftcall.c b/clang/test/CodeGen/64bit-swiftcall.c
index b1c42e3b0a657..4b0143e37afbf 100644
--- a/clang/test/CodeGen/64bit-swiftcall.c
+++ b/clang/test/CodeGen/64bit-swiftcall.c
@@ -14,8 +14,6 @@
// CHECK-DAG: %struct.atomic_padded = type { { %struct.packed, [7 x i8] } }
// CHECK-DAG: %struct.packed = type <{ i64, i8 }>
-//
-// CHECK: [[STRUCT2_RESULT:@.*]] = private {{.*}} constant [[STRUCT2_TYPE:%.*]] { i32 0, i8 0, i8 undef, i8 0, i32 0, i32 0 }
/*****************************************************************************/
/****************************** PARAMETER ABIS *******************************/
@@ -162,8 +160,8 @@ typedef struct {
} struct_2;
TEST(struct_2);
// CHECK-LABEL: define{{.*}} swiftcc { i64, i64 } @return_struct_2() {{.*}}{
-// CHECK: [[RET:%.*]] = alloca [[STRUCT2_TYPE]], align 4
-// CHECK: call void @llvm.memcpy{{.*}}({{.*}}[[RET]], {{.*}}[[STRUCT2_RESULT]]
+// CHECK: [[RET:%.*]] = alloca [[STRUCT2:%.*]], align 4
+// CHECK: call void @llvm.memset
// CHECK: [[GEP0:%.*]] = getelementptr inbounds { i64, i64 }, ptr [[RET]], i32 0, i32 0
// CHECK: [[T0:%.*]] = load i64, ptr [[GEP0]], align 4
// CHECK: [[GEP1:%.*]] = getelementptr inbounds { i64, i64 }, ptr [[RET]], i32 0, i32 1
@@ -173,7 +171,7 @@ TEST(struct_2);
// CHECK: ret { i64, i64 } [[R1]]
// CHECK: }
// CHECK-LABEL: define{{.*}} swiftcc void @take_struct_2(i64 %0, i64 %1) {{.*}}{
-// CHECK: [[V:%.*]] = alloca [[STRUCT:%.*]], align 4
+// CHECK: [[V:%.*]] = alloca [[STRUCT2]], align 4
// CHECK: [[GEP0:%.*]] = getelementptr inbounds { i64, i64 }, ptr [[V]], i32 0, i32 0
// CHECK: store i64 %0, ptr [[GEP0]], align 4
// CHECK: [[GEP1:%.*]] = getelementptr inbounds { i64, i64 }, ptr [[V]], i32 0, i32 1
@@ -181,7 +179,7 @@ TEST(struct_2);
// CHECK: ret void
// CHECK: }
// CHECK-LABEL: define{{.*}} void @test_struct_2() {{.*}} {
-// CHECK: [[TMP:%.*]] = alloca [[STRUCT2_TYPE]], align 4
+// CHECK: [[TMP:%.*]] = alloca [[STRUCT2]], align 4
// CHECK: [[CALL:%.*]] = call swiftcc { i64, i64 } @return_struct_2()
// CHECK: [[GEP:%.*]] = getelementptr inbounds {{.*}} [[TMP]], i32 0, i32 0
// CHECK: [[T0:%.*]] = extractvalue { i64, i64 } [[CALL]], 0
@@ -254,7 +252,7 @@ typedef union {
TEST(union_het_fp)
// CHECK-LABEL: define{{.*}} swiftcc i64 @return_union_het_fp()
// CHECK: [[RET:%.*]] = alloca [[UNION:%.*]], align 8
-// CHECK: call void @llvm.memcpy{{.*}}(ptr align 8 [[RET]]
+// CHECK: call void @llvm.memset{{.*}}(ptr align 8 [[RET]]
// CHECK: [[GEP:%.*]] = getelementptr inbounds { i64 }, ptr [[RET]], i32 0, i32 0
// CHECK: [[R0:%.*]] = load i64, ptr [[GEP]], align 8
// CHECK: ret i64 [[R0]]
diff --git a/clang/test/CodeGen/arm-swiftcall.c b/clang/test/CodeGen/arm-swiftcall.c
index 9fa607a968ccf..78ceed5926014 100644
--- a/clang/test/CodeGen/arm-swiftcall.c
+++ b/clang/test/CodeGen/arm-swiftcall.c
@@ -172,7 +172,7 @@ typedef struct {
TEST(struct_2);
// CHECK-LABEL: define{{.*}} @return_struct_2()
// CHECK: [[RET:%.*]] = alloca [[REC:%.*]], align 4
-// CHECK: @llvm.memcpy
+// CHECK: @llvm.memset
// CHECK: [[T0:%.*]] = getelementptr inbounds [[AGG:{ i32, i32, float, float }]], ptr [[RET]], i32 0, i32 0
// CHECK: [[FIRST:%.*]] = load i32, ptr [[T0]], align 4
// CHECK: [[T0:%.*]] = getelementptr inbounds [[AGG]], ptr [[RET]], i32 0, i32 1
@@ -274,7 +274,7 @@ typedef union {
TEST(union_het_fp)
// CHECK-LABEL: define{{.*}} @return_union_het_fp()
// CHECK: [[RET:%.*]] = alloca [[REC:%.*]], align {{(4|8)}}
-// CHECK: @llvm.memcpy
+// CHECK: @llvm.memset
// CHECK: [[T0:%.*]] = getelementptr inbounds [[AGG:{ i32, i32 }]], ptr [[RET]], i32 0, i32 0
// CHECK: [[FIRST:%.*]] = load i32, ptr [[T0]], align {{(4|8)}}
// CHECK: [[T0:%.*]] = getelementptr inbounds [[AGG]], ptr [[RET]], i32 0, i32 1
diff --git a/clang/test/CodeGen/const-init.c b/clang/test/CodeGen/const-init.c
index ad3e9551199ac..fc973cb983a80 100644
--- a/clang/test/CodeGen/const-init.c
+++ b/clang/test/CodeGen/const-init.c
@@ -170,7 +170,7 @@ void g30(void) {
int : 1;
int x;
} a = {};
- // CHECK: @g30.a = internal global %struct.anon.1 <{ i8 undef, i32 0 }>, align 1
+ // CHECK: @g30.a = internal global %struct.anon.1 zeroinitializer, align 1
#pragma pack()
}
@@ -182,7 +182,7 @@ void g31(void) {
short z;
} a = {23122, -12312731, -312};
#pragma pack()
- // CHECK: @g31.a = internal global %struct.anon.2 { i16 23122, i32 -12312731, i16 -312 }, align 4
+ // CHECK: @g31.a = internal global { i16, [2 x i8], i32, i16, [2 x i8] } { i16 23122, [2 x i8] zeroinitializer, i32 -12312731, i16 -312, [2 x i8] zeroinitializer }, align 4
}
// Clang should evaluate this in constant context, so floating point mode should
diff --git a/clang/test/CodeGen/designated-initializers.c b/clang/test/CodeGen/designated-initializers.c
index 620b1b90d2575..56600f39e8bb2 100644
--- a/clang/test/CodeGen/designated-initializers.c
+++ b/clang/test/CodeGen/designated-initializers.c
@@ -8,7 +8,7 @@ struct foo {
// CHECK: @u ={{.*}} global %union.anon zeroinitializer
union { int i; float f; } u = { };
-// CHECK: @u2 ={{.*}} global { i32, [4 x i8] } { i32 0, [4 x i8] undef }
+// CHECK: @u2 ={{.*}} global { i32, [4 x i8] } zeroinitializer
union { int i; double f; } u2 = { };
// CHECK: @u3 ={{.*}} global %union.anon.1 zeroinitializer
@@ -62,22 +62,22 @@ struct overwrite_string_struct2 {
char L[6];
int M;
} overwrite_string2[] = { { { "foo" }, 1 }, [0].L[2] = 'x'};
-// CHECK: [6 x i8] c"fox\00\00\00", i32 1
+// CHECK: [6 x i8] c"fox\00\00\00", [2 x i8] zeroinitializer, i32 1
struct overwrite_string_struct3 {
char L[3];
int M;
} overwrite_string3[] = { { { "foo" }, 1 }, [0].L[2] = 'x'};
-// CHECK: [3 x i8] c"fox", i32 1
+// CHECK: [3 x i8] c"fox", [1 x i8] zeroinitializer, i32 1
struct overwrite_string_struct4 {
char L[3];
int M;
} overwrite_string4[] = { { { "foobar" }, 1 }, [0].L[2] = 'x'};
-// CHECK: [3 x i8] c"fox", i32 1
+// CHECK: [3 x i8] c"fox", [1 x i8] zeroinitializer, i32 1
struct overwrite_string_struct5 {
char L[6];
int M;
} overwrite_string5[] = { { { "foo" }, 1 }, [0].L[4] = 'y'};
-// CHECK: [6 x i8] c"foo\00y\00", i32 1
+// CHECK: [6 x i8] c"foo\00y\00", [2 x i8] zeroinitializer, i32 1
// CHECK: @u1 = {{.*}} { i32 65535 }
@@ -138,7 +138,7 @@ union_16644_t union_16644_instance_4[2] =
[1].b[1] = 4
};
-// CHECK: @lab ={{.*}} global { [4 x i8], i32 } { [4 x i8] undef, i32 123 }
+// CHECK: @lab ={{.*}} global { [4 x i8], i32 } { [4 x i8] zeroinitializer, i32 123 }
struct leading_anon_bitfield { int : 32; int n; } lab = { .n = 123 };
struct Base {
diff --git a/clang/test/CodeGen/flexible-array-init.c b/clang/test/CodeGen/flexible-array-init.c
index 15a30c15ac966..08b5aaf63eaea 100644
--- a/clang/test/CodeGen/flexible-array-init.c
+++ b/clang/test/CodeGen/flexible-array-init.c
@@ -14,11 +14,11 @@ struct { int y[]; } b1 = { { 14, 16 } };
// sizeof(c) == 8, so this global should be at least 8 bytes.
struct { int x; char c; char y[]; } c = { 1, 2, { 13, 15 } };
-// CHECK: @c ={{.*}} global { i32, i8, [2 x i8] } { i32 1, i8 2, [2 x i8] c"\0D\0F" }
+// CHECK: @c ={{.*}} global { i32, i8, [2 x i8], [1 x i8] } { i32 1, i8 2, [2 x i8] c"\0D\0F", [1 x i8] zeroinitializer }
// sizeof(d) == 8, so this global should be at least 8 bytes.
struct __attribute((packed, aligned(4))) { char a; int x; char z[]; } d = { 1, 2, { 13, 15 } };
-// CHECK: @d ={{.*}} <{ i8, i32, [2 x i8], i8 }> <{ i8 1, i32 2, [2 x i8] c"\0D\0F", i8 undef }>,
+// CHECK: @d ={{.*}} <{ i8, i32, [2 x i8], i8 }> <{ i8 1, i32 2, [2 x i8] c"\0D\0F", i8 0 }>,
// This global needs 9 bytes to hold all the flexible array members.
struct __attribute((packed, aligned(4))) { char a; int x; char z[]; } e = { 1, 2, { 13, 15, 17, 19 } };
@@ -55,21 +55,21 @@ struct { int a; union { int b; short x[]; }; int c; int d; } hf = {1, 2, {}, 3};
// First member is the potential flexible array, initialization requires braces.
struct { int a; union { short x; int b; }; int c; int d; } i = {1, 2, {}, 3};
-// CHECK: @i = global { i32, { i16, [2 x i8] }, i32, i32 } { i32 1, { i16, [2 x i8] } { i16 2, [2 x i8] undef }, i32 0, i32 3 }
+// CHECK: @i = global { i32, { i16, [2 x i8] }, i32, i32 } { i32 1, { i16, [2 x i8] } { i16 2, [2 x i8] zeroinitializer }, i32 0, i32 3 }
struct { int a; union { short x[0]; int b; }; int c; int d; } i0 = {1, {}, 2, 3};
-// CHECK: @i0 = global { i32, { [0 x i16], [4 x i8] }, i32, i32 } { i32 1, { [0 x i16], [4 x i8] } { [0 x i16] zeroinitializer, [4 x i8] undef }, i32 2, i32 3 }
+// CHECK: @i0 = global { i32, { [0 x i16], [4 x i8] }, i32, i32 } { i32 1, { [0 x i16], [4 x i8] } zeroinitializer, i32 2, i32 3 }
struct { int a; union { short x[1]; int b; }; int c; int d; } i1 = {1, {2}, {}, 3};
-// CHECK: @i1 = global { i32, { [1 x i16], [2 x i8] }, i32, i32 } { i32 1, { [1 x i16], [2 x i8] } { [1 x i16] [i16 2], [2 x i8] undef }, i32 0, i32 3 }
+// CHECK: @i1 = global { i32, { [1 x i16], [2 x i8] }, i32, i32 } { i32 1, { [1 x i16], [2 x i8] } { [1 x i16] [i16 2], [2 x i8] zeroinitializer }, i32 0, i32 3 }
struct { int a; union { short x[]; int b; }; int c; int d; } i_f = {4, {}, {}, 6};
-// CHECK: @i_f = global { i32, { [0 x i16], [4 x i8] }, i32, i32 } { i32 4, { [0 x i16], [4 x i8] } { [0 x i16] zeroinitializer, [4 x i8] undef }, i32 0, i32 6 }
+// CHECK: @i_f = global { i32, { [0 x i16], [4 x i8] }, i32, i32 } { i32 4, { [0 x i16], [4 x i8] } zeroinitializer, i32 0, i32 6 }
// Named initializers; order doesn't matter.
struct { int a; union { int b; short x; }; int c; int d; } hn = {.a = 1, .x = 2, .c = 3};
-// CHECK: @hn = global { i32, { i16, [2 x i8] }, i32, i32 } { i32 1, { i16, [2 x i8] } { i16 2, [2 x i8] undef }, i32 3, i32 0 }
+// CHECK: @hn = global { i32, { i16, [2 x i8] }, i32, i32 } { i32 1, { i16, [2 x i8] } { i16 2, [2 x i8] zeroinitializer }, i32 3, i32 0 }
struct { int a; union { int b; short x[0]; }; int c; int d; } hn0 = {.a = 1, .x = {2}, .c = 3};
-// CHECK: @hn0 = global { i32, { [0 x i16], [4 x i8] }, i32, i32 } { i32 1, { [0 x i16], [4 x i8] } { [0 x i16] zeroinitializer, [4 x i8] undef }, i32 3, i32 0 }
+// CHECK: @hn0 = global { i32, { [0 x i16], [4 x i8] }, i32, i32 } { i32 1, { [0 x i16], [4 x i8] } zeroinitializer, i32 3, i32 0 }
struct { int a; union { int b; short x[1]; }; int c; int d; } hn1 = {.a = 1, .x = {2}, .c = 3};
-// CHECK: @hn1 = global { i32, { [1 x i16], [2 x i8] }, i32, i32 } { i32 1, { [1 x i16], [2 x i8] } { [1 x i16] [i16 2], [2 x i8] undef }, i32 3, i32 0 }
+// CHECK: @hn1 = global { i32, { [1 x i16], [2 x i8] }, i32, i32 } { i32 1, { [1 x i16], [2 x i8] } { [1 x i16] [i16 2], [2 x i8] zeroinitializer }, i32 3, i32 0 }
struct { char a[]; } empty_struct = {};
// CHECK: @empty_struct ={{.*}} global %struct.anon{{.*}} zeroinitializer, align 1
@@ -96,10 +96,10 @@ union { char a[]; } only_in_union0 = {0};
// CHECK: @only_in_union0 = global { [1 x i8] } zeroi...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/97121
More information about the cfe-commits
mailing list