Skip to content

Commit 0153045

Browse files
committed
[clang][CGRecordLayout] Remove dependency on isZeroSize
This is a follow-up from the conversation starting at llvm#93809 (comment) The root problem that motivated the change are external AST sources that compute `ASTRecordLayout`s themselves instead of letting Clang compute them from the AST. One such examples is LLDB using DWARF to get the definitive offsets and sizes of C++ structures. Such layouts should be considered correct (modulo buggy DWARF), but various assertions and lowering logic around the `CGRecordLayoutBuilder` relies on the AST having `[[no_unique_address]]` attached to them. This is a layout-altering attribute which is not encoded in DWARF. This causes us LLDB to trip over the various LLVM<->Clang layout consistency checks. There has been precedent for avoiding such layout-altering attributes to affect lowering with externally-provided layouts (e.g., packed structs). This patch proposes to replace the `isZeroSize` checks in `CGRecordLayoutBuilder` (which roughly means "empty field with [[no_unique_address]]") with checks for `CodeGen::isEmptyField`/`CodeGen::isEmptyRecord`. (cherry picked from commit f593891)
1 parent 0357a88 commit 0153045

26 files changed

+124
-121
lines changed

clang/lib/CodeGen/ABIInfoImpl.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ Address CodeGen::emitMergePHI(CodeGenFunction &CGF, Address Addr1,
248248
return Address(PHI, Addr1.getElementType(), Align);
249249
}
250250

251-
bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD,
251+
bool CodeGen::isEmptyField(const ASTContext &Context, const FieldDecl *FD,
252252
bool AllowArrays, bool AsIfNoUniqueAddr) {
253253
if (FD->isUnnamedBitField())
254254
return true;
@@ -289,8 +289,20 @@ bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD,
289289
return isEmptyRecord(Context, FT, AllowArrays, AsIfNoUniqueAddr);
290290
}
291291

292-
bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
293-
bool AsIfNoUniqueAddr) {
292+
bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context,
293+
const FieldDecl *FD) {
294+
if (FD->isZeroLengthBitField(Context))
295+
return true;
296+
297+
if (FD->isUnnamedBitField())
298+
return false;
299+
300+
return isEmptyField(Context, FD, /*AllowArrays=*/false,
301+
/*AsIfNoUniqueAddr=*/true);
302+
}
303+
304+
bool CodeGen::isEmptyRecord(const ASTContext &Context, QualType T,
305+
bool AllowArrays, bool AsIfNoUniqueAddr) {
294306
const RecordType *RT = T->getAs<RecordType>();
295307
if (!RT)
296308
return false;
@@ -310,6 +322,11 @@ bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
310322
return true;
311323
}
312324

325+
bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) {
326+
return isEmptyRecord(Context, T, /*AllowArrays=*/false,
327+
/*AsIfNoUniqueAddr=*/true);
328+
}
329+
313330
const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) {
314331
const RecordType *RT = T->getAs<RecordType>();
315332
if (!RT)

clang/lib/CodeGen/ABIInfoImpl.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,17 +126,26 @@ Address emitMergePHI(CodeGenFunction &CGF, Address Addr1,
126126
/// is an unnamed bit-field or an (array of) empty record(s). If
127127
/// AsIfNoUniqueAddr is true, then C++ record fields are considered empty if
128128
/// the [[no_unique_address]] attribute would have made them empty.
129-
bool isEmptyField(ASTContext &Context, const FieldDecl *FD, bool AllowArrays,
130-
bool AsIfNoUniqueAddr = false);
129+
bool isEmptyField(const ASTContext &Context, const FieldDecl *FD,
130+
bool AllowArrays, bool AsIfNoUniqueAddr = false);
131+
132+
/// isEmptyFieldForLayout - Return true iff the field is "empty", that is,
133+
/// either a zero-width bit-field or an empty record.
134+
bool isEmptyFieldForLayout(const ASTContext &Context, const FieldDecl *FD);
131135

132136
/// isEmptyRecord - Return true iff a structure contains only empty
133137
/// fields. Note that a structure with a flexible array member is not
134138
/// considered empty. If AsIfNoUniqueAddr is true, then C++ record fields are
135139
/// considered empty if the [[no_unique_address]] attribute would have made
136140
/// them empty.
137-
bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
141+
bool isEmptyRecord(const ASTContext &Context, QualType T, bool AllowArrays,
138142
bool AsIfNoUniqueAddr = false);
139143

144+
/// isEmptyRecordForLayout - Return true iff a structure contains only empty
145+
/// fields. Note, C++ record fields are considered empty if the
146+
/// [[no_unique_address]] attribute would have made them empty.
147+
bool isEmptyRecordForLayout(const ASTContext &Context, QualType T);
148+
140149
/// isSingleElementStruct - Determine if a structure is a "single
141150
/// element struct", i.e. it has exactly one non-empty field or
142151
/// exactly one field which is itself a single element

clang/lib/CodeGen/CGExpr.cpp

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

13+
#include "ABIInfoImpl.h"
1314
#include "CGCUDARuntime.h"
1415
#include "CGCXXABI.h"
1516
#include "CGCall.h"
@@ -4762,7 +4763,7 @@ static Address emitAddrOfZeroSizeField(CodeGenFunction &CGF, Address Base,
47624763
/// The resulting address doesn't necessarily have the right type.
47634764
static Address emitAddrOfFieldStorage(CodeGenFunction &CGF, Address base,
47644765
const FieldDecl *field) {
4765-
if (field->isZeroSize(CGF.getContext()))
4766+
if (isEmptyFieldForLayout(CGF.getContext(), field))
47664767
return emitAddrOfZeroSizeField(CGF, base, field);
47674768

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

clang/lib/CodeGen/CGExprConstant.cpp

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

13+
#include "ABIInfoImpl.h"
1314
#include "CGCXXABI.h"
1415
#include "CGObjCRuntime.h"
1516
#include "CGRecordLayout.h"
@@ -2481,8 +2482,10 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
24812482
cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
24822483

24832484
// Ignore empty bases.
2484-
if (base->isEmpty() ||
2485-
CGM.getContext().getASTRecordLayout(base).getNonVirtualSize()
2485+
if (isEmptyRecordForLayout(CGM.getContext(), I.getType()) ||
2486+
CGM.getContext()
2487+
.getASTRecordLayout(base)
2488+
.getNonVirtualSize()
24862489
.isZero())
24872490
continue;
24882491

@@ -2518,7 +2521,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
25182521
cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
25192522

25202523
// Ignore empty bases.
2521-
if (base->isEmpty())
2524+
if (isEmptyRecordForLayout(CGM.getContext(), I.getType()))
25222525
continue;
25232526

25242527
unsigned fieldIndex = layout.getVirtualBaseIndex(base);

clang/lib/CodeGen/CGRecordLayoutBuilder.cpp

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

13-
#include "CGRecordLayout.h"
13+
#include "ABIInfoImpl.h"
1414
#include "CGCXXABI.h"
15+
#include "CGRecordLayout.h"
1516
#include "CodeGenTypes.h"
1617
#include "clang/AST/ASTContext.h"
1718
#include "clang/AST/Attr.h"
@@ -384,7 +385,7 @@ void CGRecordLowering::accumulateFields(bool isNonVirtualBaseType) {
384385
Field = accumulateBitFields(isNonVirtualBaseType, Field, FieldEnd);
385386
assert((Field == FieldEnd || !Field->isBitField()) &&
386387
"Failed to accumulate all the bitfields");
387-
} else if (Field->isZeroSize(Context)) {
388+
} else if (isEmptyFieldForLayout(Context, *Field)) {
388389
// Empty fields have no storage.
389390
++Field;
390391
} else {
@@ -634,7 +635,7 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
634635
// non-reusable tail padding.
635636
CharUnits LimitOffset;
636637
for (auto Probe = Field; Probe != FieldEnd; ++Probe)
637-
if (!Probe->isZeroSize(Context)) {
638+
if (!isEmptyFieldForLayout(Context, *Probe)) {
638639
// A member with storage sets the limit.
639640
assert((getFieldBitOffset(*Probe) % CharBits) == 0 &&
640641
"Next storage is not byte-aligned");
@@ -732,7 +733,7 @@ void CGRecordLowering::accumulateBases() {
732733
// Bases can be zero-sized even if not technically empty if they
733734
// contain only a trailing array member.
734735
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
735-
if (!BaseDecl->isEmpty() &&
736+
if (!isEmptyRecordForLayout(Context, Base.getType()) &&
736737
!Context.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero())
737738
Members.push_back(MemberInfo(Layout.getBaseClassOffset(BaseDecl),
738739
MemberInfo::Base, getStorageType(BaseDecl), BaseDecl));
@@ -880,7 +881,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
880881
if (!isNonVirtualBaseType && isOverlappingVBaseABI())
881882
for (const auto &Base : RD->vbases()) {
882883
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
883-
if (BaseDecl->isEmpty())
884+
if (isEmptyRecordForLayout(Context, Base.getType()))
884885
continue;
885886
// If the vbase is a primary virtual base of some base, then it doesn't
886887
// get its own storage location but instead lives inside of that base.
@@ -896,7 +897,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
896897
void CGRecordLowering::accumulateVBases() {
897898
for (const auto &Base : RD->vbases()) {
898899
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
899-
if (BaseDecl->isEmpty())
900+
if (isEmptyRecordForLayout(Context, Base.getType()))
900901
continue;
901902
CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl);
902903
// If the vbase is a primary virtual base of some base, then it doesn't
@@ -1162,7 +1163,7 @@ CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, llvm::StructType *Ty) {
11621163
const FieldDecl *FD = *it;
11631164

11641165
// Ignore zero-sized fields.
1165-
if (FD->isZeroSize(getContext()))
1166+
if (isEmptyFieldForLayout(getContext(), FD))
11661167
continue;
11671168

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

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ 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: [[TMP3:%.*]] = load double, ptr [[RETVAL]], align 8
59+
// CHECK-NEXT: [[COERCE:%.*]] = getelementptr inbounds [[STRUCT_S1]], ptr [[RETVAL]], i32 0, i32 0
60+
// CHECK-NEXT: [[TMP3:%.*]] = load double, ptr [[COERCE]], align 8
6061
// CHECK-NEXT: ret double [[TMP3]]
6162
//
6263
s1 f(int z, ...) {

clang/test/CodeGen/debug-info-packed-struct.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
// CHECK: %struct.layout3 = type <{ i8, [3 x i8], %struct.size8_pack4, i8, [3 x i8] }>
44
// CHECK: %struct.layout0 = type { i8, %struct.size8, i8 }
5-
// CHECK: %struct.layout1 = type <{ i8, %struct.size8_anon, i8, [2 x i8] }>
5+
// CHECK: %struct.layout1 = type { i8, [8 x i8], i8, [2 x i8] }
66
// CHECK: %struct.layout2 = type <{ i8, %struct.size8_pack1, i8 }>
77

88
// ---------------------------------------------------------------------

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

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

51-
// CHECK-DAG: [[STRUCT_F:%.*]] = type { i8 }
5251
struct F {
5352
F (int i = 1);
5453
F (const F &f) = delete;
5554
F (F &&f) = default;
5655
};
5756

58-
// CHECK-DAG: [[STRUCT_G:%.*]] = type <{ i32, [[STRUCT_F]], [3 x i8] }>
57+
// CHECK-DAG: [[STRUCT_G:%.*]] = type <{ i32, [4 x i8] }>
5958
struct G {
6059
int a;
6160
F f;
@@ -78,12 +77,12 @@ namespace gh61145 {
7877
~Vec();
7978
};
8079

81-
// CHECK-DAG: [[STRUCT_S1:%.*]] = type { [[STRUCT_VEC]] }
80+
// CHECK-DAG: [[STRUCT_S1:%.*]] = type { i8 }
8281
struct S1 {
8382
Vec v;
8483
};
8584

86-
// CHECK-DAG: [[STRUCT_S2:%.*]] = type { [[STRUCT_VEC]], i8 }
85+
// CHECK-DAG: [[STRUCT_S2:%.*]] = type { i8, i8 }
8786
struct S2 {
8887
Vec v;
8988
char c;
@@ -377,7 +376,7 @@ void foo18() {
377376
// CHECK-NEXT: [[G:%.*g.*]] = alloca [[STRUCT_G]], align 4
378377
// CHECK-NEXT: [[A:%.*a.*]] = getelementptr inbounds [[STRUCT_G]], ptr [[G]], i32 0, i32 0
379378
// CHECK-NEXT: store i32 2, ptr [[A]], align 4
380-
// CHECK-NEXT: [[F:%.*f.*]] = getelementptr inbounds [[STRUCT_G]], ptr [[G]], i32 0, i32 1
379+
// CHECK-NEXT: [[F:%.*]] = getelementptr inbounds i8, ptr [[G]], i64 4
381380
// CHECk-NEXT: call void @{{.*F.*}}(ptr noundef nonnull align 1 dereferenceable(1)) [[F]], ie32 noundef 1)
382381
// CHECK: ret void
383382
void foo19() {
@@ -392,9 +391,8 @@ namespace gh61145 {
392391
// CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S1]], align 1
393392
// a.k.a. Vec::Vec()
394393
// CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
395-
// CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds [[STRUCT_S1]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
396394
// a.k.a. Vec::Vec(Vec&&)
397-
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[V1]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
395+
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
398396
// a.k.a. S1::~S1()
399397
// CHECK-NEXT: call void @_ZN7gh611452S1D1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]])
400398
// a.k.a.Vec::~Vec()
@@ -413,9 +411,8 @@ namespace gh61145 {
413411
// CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S2]], align 1
414412
// a.k.a. Vec::Vec()
415413
// CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
416-
// CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds [[STRUCT_S2]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
417414
// a.k.a. Vec::Vec(Vec&&)
418-
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[V1]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
415+
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
419416
// CHECK-NEXT: [[C:%.*c.*]] = getelementptr inbounds [[STRUCT_S2]], ptr [[AGG_TMP_ENSURED]], i32 0, i32
420417
// CHECK-NEXT: store i8 0, ptr [[C]], align 1
421418
// a.k.a. S2::~S2()

clang/test/CodeGen/voidptr-vaarg.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ typedef struct {
245245
// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
246246
// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4
247247
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[RETVAL]], ptr align 4 [[ARGP_CUR]], i32 4, i1 false)
248-
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 4
248+
// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds [[STRUCT_EMPTY_INT_T]], ptr [[RETVAL]], i32 0, i32 0
249+
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[COERCE_DIVE]], align 4
249250
// CHECK-NEXT: ret i32 [[TMP0]]
250251
//
251252
empty_int_t empty_int(__builtin_va_list list) {

clang/test/CodeGenCXX/2011-12-19-init-list-ctor.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ struct S {
1919
};
2020

2121
// CHECK: store i32 0, ptr @arr
22-
// CHECK: call void @_ZN1AC1EPKc(ptr {{[^,]*}} getelementptr inbounds (%struct.S, ptr @arr, i32 0, i32 1), ptr noundef @.str)
22+
// CHECK: call void @_ZN1AC1EPKc(ptr {{[^,]*}} getelementptr inbounds (i8, ptr @arr, i64 4), ptr noundef @.str)
2323
// CHECK: store i32 1, ptr getelementptr inbounds (%struct.S, ptr @arr, i64 1)
24-
// CHECK: call void @_ZN1AC1EPKc(ptr {{[^,]*}} getelementptr inbounds (%struct.S, ptr getelementptr inbounds (%struct.S, ptr @arr, i64 1), i32 0, i32 1), ptr noundef @.str.1)
24+
// CHECK: call void @_ZN1AC1EPKc(ptr {{[^,]*}} getelementptr inbounds (i8, ptr getelementptr inbounds (%struct.S, ptr @arr, i64 1), i64 4), ptr noundef @.str.1)
2525
// CHECK: store i32 2, ptr getelementptr inbounds (%struct.S, ptr @arr, i64 2)
26-
// CHECK: call void @_ZN1AC1EPKc(ptr {{[^,]*}} getelementptr inbounds (%struct.S, ptr getelementptr inbounds (%struct.S, ptr @arr, i64 2), i32 0, i32 1), ptr noundef @.str.2)
26+
// CHECK: call void @_ZN1AC1EPKc(ptr {{[^,]*}} getelementptr inbounds (i8, ptr getelementptr inbounds (%struct.S, ptr @arr, i64 2), i64 4), ptr noundef @.str.2)

clang/test/CodeGenCXX/auto-var-init.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,CHECK-O0
2-
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,PATTERN,PATTERN-O0
2+
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,PATTERN,PATTERN-O0,PATTERN-64-O0
33
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -O1 -emit-llvm -o - | FileCheck %s -check-prefixes=PATTERN,PATTERN-O1
44
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=zero %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,ZERO,ZERO-O0
55
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=zero %s -O1 -emit-llvm -o - | FileCheck %s -check-prefixes=ZERO,ZERO-O1
6-
// RUN: %clang_cc1 -std=c++14 -triple i386-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,PATTERN,PATTERN-O0
6+
// RUN: %clang_cc1 -std=c++14 -triple i386-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,PATTERN,PATTERN-O0,PATTERN-32-O0
77

88
#pragma clang diagnostic ignored "-Winaccessible-base"
99

@@ -166,14 +166,17 @@ struct semivolatileinit { int i = 0x11111111; volatile int vi = 0x11111111; };
166166
// PATTERN-O0: @__const.test_base_braces.braces = private unnamed_addr constant %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) }, align
167167
// PATTERN-O1-NOT: @__const.test_base_braces.braces
168168
struct base { virtual ~base(); };
169-
// PATTERN-O0: @__const.test_derived_uninit.uninit = private unnamed_addr constant %struct.derived { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) } }, align
169+
// PATTERN-32-O0: @__const.test_derived_uninit.uninit = private unnamed_addr constant %struct.derived { [4 x i8] c"\FF\FF\FF\FF" }, align 4
170+
// PATTERN-64-O0: @__const.test_derived_uninit.uninit = private unnamed_addr constant %struct.derived { [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8
170171
// PATTERN-O1-NOT: @__const.test_derived_uninit.uninit
171-
// PATTERN-O0: @__const.test_derived_braces.braces = private unnamed_addr constant %struct.derived { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) } }, align
172+
// PATTERN-32-O0: @__const.test_derived_braces.braces = private unnamed_addr constant %struct.derived { [4 x i8] c"\FF\FF\FF\FF" }, align 4
173+
// PATTERN-64-O0: @__const.test_derived_braces.braces = private unnamed_addr constant %struct.derived { [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8
172174
// PATTERN-O1-NOT: @__const.test_derived_braces.braces
173175
struct derived : public base {};
174-
// PATTERN-O0: @__const.test_virtualderived_uninit.uninit = private unnamed_addr constant %struct.virtualderived { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) }, %struct.derived { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) } } }, align
176+
// PATERN-O0: @__const.test_virtualderived_uninit.uninit = private unnamed_addr constant %struct.virtualderived { %struct.base { ptr inttoptr (i64 -6148914691236517206 to ptr) }, [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8
175177
// PATTERN-O1-NOT: @__const.test_virtualderived_uninit.uninit
176-
// PATTERN-O0: @__const.test_virtualderived_braces.braces = private unnamed_addr constant %struct.virtualderived { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) }, %struct.derived { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) } } }, align
178+
// PATTERN-32-O0: @__const.test_virtualderived_uninit.uninit = private unnamed_addr constant %struct.virtualderived { %struct.base { ptr inttoptr (i32 -1 to ptr) }, [4 x i8] c"\FF\FF\FF\FF" }, align 4
179+
// PATTERN-64-O0: @__const.test_virtualderived_uninit.uninit = private unnamed_addr constant %struct.virtualderived { %struct.base { ptr inttoptr (i64 -6148914691236517206 to ptr) }, [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8
177180
// PATTERN-O1-NOT: @__const.test_virtualderived_braces.braces
178181
struct virtualderived : public virtual base, public virtual derived {};
179182
// PATTERN-O0: @__const.test_matching_uninit.uninit = private unnamed_addr constant %union.matching { i32 [[I32]] }, align 4

0 commit comments

Comments
 (0)