Skip to content

Commit e5cb8bd

Browse files
authored
Revert "[clang][CGRecordLayout] Remove dependency on isZeroSize (llvm#96422)" (#156)
This reverts commit 4497ec2. Change-Id: I172a59c5aa51dcd9dda38bf380d49b97c8f67cc4 Co-authored-by: Konstantin Zhuravlyov <[email protected]>
1 parent 1ff501d commit e5cb8bd

28 files changed

+161
-258
lines changed

clang/lib/CodeGen/ABIInfoImpl.cpp

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -301,41 +301,6 @@ bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
301301
return true;
302302
}
303303

304-
bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context,
305-
const FieldDecl *FD) {
306-
if (FD->isZeroLengthBitField())
307-
return true;
308-
309-
if (FD->isUnnamedBitField())
310-
return false;
311-
312-
return isEmptyRecordForLayout(Context, FD->getType());
313-
}
314-
315-
bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) {
316-
const RecordType *RT = T->getAs<RecordType>();
317-
if (!RT)
318-
return false;
319-
320-
const RecordDecl *RD = RT->getDecl();
321-
322-
// If this is a C++ record, check the bases first.
323-
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
324-
if (CXXRD->isDynamicClass())
325-
return false;
326-
327-
for (const auto &I : CXXRD->bases())
328-
if (!isEmptyRecordForLayout(Context, I.getType()))
329-
return false;
330-
}
331-
332-
for (const auto *I : RD->fields())
333-
if (!isEmptyFieldForLayout(Context, I))
334-
return false;
335-
336-
return true;
337-
}
338-
339304
const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) {
340305
const RecordType *RT = T->getAs<RecordType>();
341306
if (!RT)

clang/lib/CodeGen/ABIInfoImpl.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,6 @@ bool isEmptyField(ASTContext &Context, const FieldDecl *FD, bool AllowArrays,
120120
bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
121121
bool AsIfNoUniqueAddr = false);
122122

123-
/// isEmptyFieldForLayout - Return true iff the field is "empty", that is,
124-
/// either a zero-width bit-field or an \ref isEmptyRecordForLayout.
125-
bool isEmptyFieldForLayout(const ASTContext &Context, const FieldDecl *FD);
126-
127-
/// isEmptyRecordForLayout - Return true iff a structure contains only empty
128-
/// base classes (per \ref isEmptyRecordForLayout) and fields (per
129-
/// \ref isEmptyFieldForLayout). Note, C++ record fields are considered empty
130-
/// if the [[no_unique_address]] attribute would have made them empty.
131-
bool isEmptyRecordForLayout(const ASTContext &Context, QualType T);
132-
133123
/// isSingleElementStruct - Determine if a structure is a "single
134124
/// element struct", i.e. it has exactly one non-empty field or
135125
/// exactly one field which is itself a single element

clang/lib/CodeGen/CGClass.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "ABIInfoImpl.h"
1413
#include "CGBlocks.h"
1514
#include "CGCXXABI.h"
1615
#include "CGDebugInfo.h"
@@ -933,7 +932,7 @@ namespace {
933932
}
934933

935934
void addMemcpyableField(FieldDecl *F) {
936-
if (isEmptyFieldForLayout(CGF.getContext(), F))
935+
if (F->isZeroSize(CGF.getContext()))
937936
return;
938937
if (!FirstField)
939938
addInitialField(F);
@@ -1815,7 +1814,7 @@ namespace {
18151814
const CXXDestructorDecl *DD)
18161815
: Context(Context), EHStack(EHStack), DD(DD), StartIndex(std::nullopt) {}
18171816
void PushCleanupForField(const FieldDecl *Field) {
1818-
if (isEmptyFieldForLayout(Context, Field))
1817+
if (Field->isZeroSize(Context))
18191818
return;
18201819
unsigned FieldIndex = Field->getFieldIndex();
18211820
if (FieldHasTrivialDestructorBody(Context, Field)) {

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "ABIInfoImpl.h"
1413
#include "CGCUDARuntime.h"
1514
#include "CGCXXABI.h"
1615
#include "CGCall.h"
@@ -4850,7 +4849,7 @@ static Address emitAddrOfZeroSizeField(CodeGenFunction &CGF, Address Base,
48504849
/// The resulting address doesn't necessarily have the right type.
48514850
static Address emitAddrOfFieldStorage(CodeGenFunction &CGF, Address base,
48524851
const FieldDecl *field) {
4853-
if (isEmptyFieldForLayout(CGF.getContext(), field))
4852+
if (field->isZeroSize(CGF.getContext()))
48544853
return emitAddrOfZeroSizeField(CGF, base, field);
48554854

48564855
const RecordDecl *rec = field->getParent();

clang/lib/CodeGen/CGExprConstant.cpp

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "ABIInfoImpl.h"
1413
#include "CGCXXABI.h"
1514
#include "CGObjCRuntime.h"
1615
#include "CGRecordLayout.h"
@@ -758,7 +757,7 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) {
758757

759758
// Zero-sized fields are not emitted, but their initializers may still
760759
// prevent emission of this struct as a constant.
761-
if (isEmptyFieldForLayout(CGM.getContext(), Field)) {
760+
if (Field->isZeroSize(CGM.getContext())) {
762761
if (Init && Init->HasSideEffects(CGM.getContext()))
763762
return false;
764763
continue;
@@ -894,8 +893,7 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
894893
continue;
895894

896895
// Don't emit anonymous bitfields or zero-sized fields.
897-
if (Field->isUnnamedBitField() ||
898-
isEmptyFieldForLayout(CGM.getContext(), *Field))
896+
if (Field->isUnnamedBitField() || Field->isZeroSize(CGM.getContext()))
899897
continue;
900898

901899
// Emit the value of the initializer.
@@ -2612,10 +2610,8 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
26122610
cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
26132611

26142612
// Ignore empty bases.
2615-
if (isEmptyRecordForLayout(CGM.getContext(), I.getType()) ||
2616-
CGM.getContext()
2617-
.getASTRecordLayout(base)
2618-
.getNonVirtualSize()
2613+
if (base->isEmpty() ||
2614+
CGM.getContext().getASTRecordLayout(base).getNonVirtualSize()
26192615
.isZero())
26202616
continue;
26212617

@@ -2629,8 +2625,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
26292625
for (const auto *Field : record->fields()) {
26302626
// Fill in non-bitfields. (Bitfields always use a zero pattern, which we
26312627
// will fill in later.)
2632-
if (!Field->isBitField() &&
2633-
!isEmptyFieldForLayout(CGM.getContext(), Field)) {
2628+
if (!Field->isBitField() && !Field->isZeroSize(CGM.getContext())) {
26342629
unsigned fieldIndex = layout.getLLVMFieldNo(Field);
26352630
elements[fieldIndex] = CGM.EmitNullConstant(Field->getType());
26362631
}
@@ -2652,7 +2647,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
26522647
cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
26532648

26542649
// Ignore empty bases.
2655-
if (isEmptyRecordForLayout(CGM.getContext(), I.getType()))
2650+
if (base->isEmpty())
26562651
continue;
26572652

26582653
unsigned fieldIndex = layout.getVirtualBaseIndex(base);

clang/lib/CodeGen/CGOpenMPRuntime.cpp

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "CGOpenMPRuntime.h"
14-
#include "ABIInfoImpl.h"
1514
#include "CGCXXABI.h"
1615
#include "CGCleanup.h"
1716
#include "CGRecordLayout.h"
@@ -7775,28 +7774,23 @@ class MappableExprsHandler {
77757774
for (const auto &I : RD->bases()) {
77767775
if (I.isVirtual())
77777776
continue;
7778-
7779-
QualType BaseTy = I.getType();
7780-
const auto *Base = BaseTy->getAsCXXRecordDecl();
7777+
const auto *Base = I.getType()->getAsCXXRecordDecl();
77817778
// Ignore empty bases.
7782-
if (isEmptyRecordForLayout(CGF.getContext(), BaseTy) ||
7783-
CGF.getContext()
7784-
.getASTRecordLayout(Base)
7785-
.getNonVirtualSize()
7786-
.isZero())
7779+
if (Base->isEmpty() || CGF.getContext()
7780+
.getASTRecordLayout(Base)
7781+
.getNonVirtualSize()
7782+
.isZero())
77877783
continue;
77887784

77897785
unsigned FieldIndex = RL.getNonVirtualBaseLLVMFieldNo(Base);
77907786
RecordLayout[FieldIndex] = Base;
77917787
}
77927788
// Fill in virtual bases.
77937789
for (const auto &I : RD->vbases()) {
7794-
QualType BaseTy = I.getType();
7790+
const auto *Base = I.getType()->getAsCXXRecordDecl();
77957791
// Ignore empty bases.
7796-
if (isEmptyRecordForLayout(CGF.getContext(), BaseTy))
7792+
if (Base->isEmpty())
77977793
continue;
7798-
7799-
const auto *Base = BaseTy->getAsCXXRecordDecl();
78007794
unsigned FieldIndex = RL.getVirtualBaseIndex(Base);
78017795
if (RecordLayout[FieldIndex])
78027796
continue;
@@ -7807,8 +7801,7 @@ class MappableExprsHandler {
78077801
for (const auto *Field : RD->fields()) {
78087802
// Fill in non-bitfields. (Bitfields always use a zero pattern, which we
78097803
// will fill in later.)
7810-
if (!Field->isBitField() &&
7811-
!isEmptyFieldForLayout(CGF.getContext(), Field)) {
7804+
if (!Field->isBitField() && !Field->isZeroSize(CGF.getContext())) {
78127805
unsigned FieldIndex = RL.getLLVMFieldNo(Field);
78137806
RecordLayout[FieldIndex] = Field;
78147807
}

clang/lib/CodeGen/CGRecordLayoutBuilder.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "ABIInfoImpl.h"
14-
#include "CGCXXABI.h"
1513
#include "CGRecordLayout.h"
14+
#include "CGCXXABI.h"
1615
#include "CodeGenTypes.h"
1716
#include "clang/AST/ASTContext.h"
1817
#include "clang/AST/Attr.h"
@@ -385,7 +384,7 @@ void CGRecordLowering::accumulateFields(bool isNonVirtualBaseType) {
385384
Field = accumulateBitFields(isNonVirtualBaseType, Field, FieldEnd);
386385
assert((Field == FieldEnd || !Field->isBitField()) &&
387386
"Failed to accumulate all the bitfields");
388-
} else if (isEmptyFieldForLayout(Context, *Field)) {
387+
} else if (Field->isZeroSize(Context)) {
389388
// Empty fields have no storage.
390389
++Field;
391390
} else {
@@ -634,7 +633,7 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
634633
// non-reusable tail padding.
635634
CharUnits LimitOffset;
636635
for (auto Probe = Field; Probe != FieldEnd; ++Probe)
637-
if (!isEmptyFieldForLayout(Context, *Probe)) {
636+
if (!Probe->isZeroSize(Context)) {
638637
// A member with storage sets the limit.
639638
assert((getFieldBitOffset(*Probe) % CharBits) == 0 &&
640639
"Next storage is not byte-aligned");
@@ -732,7 +731,7 @@ void CGRecordLowering::accumulateBases() {
732731
// Bases can be zero-sized even if not technically empty if they
733732
// contain only a trailing array member.
734733
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
735-
if (!isEmptyRecordForLayout(Context, Base.getType()) &&
734+
if (!BaseDecl->isEmpty() &&
736735
!Context.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero())
737736
Members.push_back(MemberInfo(Layout.getBaseClassOffset(BaseDecl),
738737
MemberInfo::Base, getStorageType(BaseDecl), BaseDecl));
@@ -880,7 +879,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
880879
if (!isNonVirtualBaseType && isOverlappingVBaseABI())
881880
for (const auto &Base : RD->vbases()) {
882881
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
883-
if (isEmptyRecordForLayout(Context, Base.getType()))
882+
if (BaseDecl->isEmpty())
884883
continue;
885884
// If the vbase is a primary virtual base of some base, then it doesn't
886885
// get its own storage location but instead lives inside of that base.
@@ -896,7 +895,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
896895
void CGRecordLowering::accumulateVBases() {
897896
for (const auto &Base : RD->vbases()) {
898897
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
899-
if (isEmptyRecordForLayout(Context, Base.getType()))
898+
if (BaseDecl->isEmpty())
900899
continue;
901900
CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl);
902901
// If the vbase is a primary virtual base of some base, then it doesn't
@@ -1162,7 +1161,7 @@ CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, llvm::StructType *Ty) {
11621161
const FieldDecl *FD = *it;
11631162

11641163
// Ignore zero-sized fields.
1165-
if (isEmptyFieldForLayout(getContext(), FD))
1164+
if (FD->isZeroSize(getContext()))
11661165
continue;
11671166

11681167
// For non-bit-fields, just check that the LLVM struct offset matches the

clang/lib/CodeGen/CodeGenTBAA.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "CodeGenTBAA.h"
18-
#include "ABIInfoImpl.h"
1918
#include "CGCXXABI.h"
2019
#include "CGRecordLayout.h"
2120
#include "CodeGenTypes.h"
@@ -398,7 +397,7 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset,
398397
unsigned idx = 0;
399398
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
400399
i != e; ++i, ++idx) {
401-
if (isEmptyFieldForLayout(Context, *i))
400+
if ((*i)->isZeroSize(Context))
402401
continue;
403402

404403
uint64_t Offset =
Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,8 @@
1-
// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefixes=CHECK,EMPTY
2-
// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-windows-msvc -o - | FileCheck %s --check-prefixes=CHECK,EMPTY-MSVC
1+
// RUN: %clang_cc1 -emit-llvm < %s | grep "zeroinitializer, i16 16877"
32
// PR4390
43
struct sysfs_dirent {
5-
union { struct sysfs_elem_dir { int x; } s_dir; };
4+
union { struct sysfs_elem_dir {} s_dir; };
65
unsigned short s_mode;
76
};
87
struct sysfs_dirent sysfs_root = { {}, 16877 };
98

10-
// CHECK: @sysfs_root = {{.*}}global { %union.anon, i16, [2 x i8] } { %union.anon zeroinitializer, i16 16877, [2 x i8] zeroinitializer }
11-
12-
struct Foo {
13-
union { struct empty {} x; };
14-
unsigned short s_mode;
15-
};
16-
struct Foo foo = { {}, 16877 };
17-
18-
// EMPTY: @foo = {{.*}}global %struct.Foo { i16 16877 }
19-
// EMPTY-MSVC: @foo = {{.*}}global %struct.Foo { [4 x i8] zeroinitializer, i16 16877 }

clang/test/CodeGen/X86/x86_64-vaarg.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ typedef struct {
5656
// CHECK: vaarg.end:
5757
// CHECK-NEXT: [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP1]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ]
5858
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[VAARG_ADDR]], i64 8, i1 false)
59-
// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_S1]], ptr [[RETVAL]], i32 0, i32 0
60-
// CHECK-NEXT: [[TMP3:%.*]] = load double, ptr [[COERCE_DIVE]], align 8
59+
// CHECK-NEXT: [[TMP3:%.*]] = load double, ptr [[RETVAL]], align 8
6160
// CHECK-NEXT: ret double [[TMP3]]
6261
//
6362
s1 f(int z, ...) {

clang/test/CodeGen/paren-list-agg-init.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,14 @@ struct E {
4848
~E() {};
4949
};
5050

51+
// CHECK-DAG: [[STRUCT_F:%.*]] = type { i8 }
5152
struct F {
5253
F (int i = 1);
5354
F (const F &f) = delete;
5455
F (F &&f) = default;
5556
};
5657

57-
// CHECK-DAG: [[STRUCT_G:%.*]] = type <{ i32, [4 x i8] }>
58+
// CHECK-DAG: [[STRUCT_G:%.*]] = type <{ i32, [[STRUCT_F]], [3 x i8] }>
5859
struct G {
5960
int a;
6061
F f;
@@ -77,12 +78,12 @@ namespace gh61145 {
7778
~Vec();
7879
};
7980

80-
// CHECK-DAG: [[STRUCT_S1:%.*]] = type { i8 }
81+
// CHECK-DAG: [[STRUCT_S1:%.*]] = type { [[STRUCT_VEC]] }
8182
struct S1 {
8283
Vec v;
8384
};
8485

85-
// CHECK-DAG: [[STRUCT_S2:%.*]] = type { i8, i8 }
86+
// CHECK-DAG: [[STRUCT_S2:%.*]] = type { [[STRUCT_VEC]], i8 }
8687
struct S2 {
8788
Vec v;
8889
char c;
@@ -376,7 +377,7 @@ void foo18() {
376377
// CHECK-NEXT: [[G:%.*g.*]] = alloca [[STRUCT_G]], align 4
377378
// CHECK-NEXT: [[A:%.*a.*]] = getelementptr inbounds nuw [[STRUCT_G]], ptr [[G]], i32 0, i32 0
378379
// CHECK-NEXT: store i32 2, ptr [[A]], align 4
379-
// CHECK-NEXT: [[F:%.*]] = getelementptr inbounds i8, ptr [[G]], i64 4
380+
// CHECK-NEXT: [[F:%.*f.*]] = getelementptr inbounds nuw [[STRUCT_G]], ptr [[G]], i32 0, i32 1
380381
// CHECk-NEXT: call void @{{.*F.*}}(ptr noundef nonnull align 1 dereferenceable(1)) [[F]], ie32 noundef 1)
381382
// CHECK: ret void
382383
void foo19() {
@@ -391,8 +392,9 @@ namespace gh61145 {
391392
// CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S1]], align 1
392393
// a.k.a. Vec::Vec()
393394
// CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
395+
// CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds nuw [[STRUCT_S1]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
394396
// a.k.a. Vec::Vec(Vec&&)
395-
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
397+
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[V1]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
396398
// a.k.a. S1::~S1()
397399
// CHECK-NEXT: call void @_ZN7gh611452S1D1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]])
398400
// a.k.a.Vec::~Vec()
@@ -411,8 +413,9 @@ namespace gh61145 {
411413
// CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S2]], align 1
412414
// a.k.a. Vec::Vec()
413415
// CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
416+
// CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds nuw [[STRUCT_S2]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
414417
// a.k.a. Vec::Vec(Vec&&)
415-
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
418+
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[V1]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
416419
// CHECK-NEXT: [[C:%.*c.*]] = getelementptr inbounds nuw [[STRUCT_S2]], ptr [[AGG_TMP_ENSURED]], i32 0, i32
417420
// CHECK-NEXT: store i8 0, ptr [[C]], align 1
418421
// a.k.a. S2::~S2()

clang/test/CodeGen/union-init2.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ union z {
1313
};
1414
union z y = {};
1515

16-
// CHECK: @foo = {{.*}}global %union.Foo undef, align 1
16+
// CHECK: @foo = {{.*}}global %union.Foo zeroinitializer, align 1
1717
// CHECK-CXX: @foo = {{.*}}global %union.Foo undef, align 1
1818
union Foo {
1919
struct Empty {} val;

0 commit comments

Comments
 (0)