Skip to content

Commit ee99475

Browse files
authored
[clang] Fix bitfield access unit for vbase corner case (#87238)
This fixes #87227, a vbase can be placed below nvsize when empty members and/or bases are in play. We must account for that.
1 parent 4cd7bb0 commit ee99475

File tree

2 files changed

+113
-48
lines changed

2 files changed

+113
-48
lines changed

clang/lib/CodeGen/CGRecordLayoutBuilder.cpp

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -185,18 +185,21 @@ struct CGRecordLowering {
185185
/// Lowers an ASTRecordLayout to a llvm type.
186186
void lower(bool NonVirtualBaseType);
187187
void lowerUnion(bool isNoUniqueAddress);
188-
void accumulateFields();
188+
void accumulateFields(bool isNonVirtualBaseType);
189189
RecordDecl::field_iterator
190-
accumulateBitFields(RecordDecl::field_iterator Field,
190+
accumulateBitFields(bool isNonVirtualBaseType,
191+
RecordDecl::field_iterator Field,
191192
RecordDecl::field_iterator FieldEnd);
192193
void computeVolatileBitfields();
193194
void accumulateBases();
194195
void accumulateVPtrs();
195196
void accumulateVBases();
196197
/// Recursively searches all of the bases to find out if a vbase is
197198
/// not the primary vbase of some base class.
198-
bool hasOwnStorage(const CXXRecordDecl *Decl, const CXXRecordDecl *Query);
199+
bool hasOwnStorage(const CXXRecordDecl *Decl,
200+
const CXXRecordDecl *Query) const;
199201
void calculateZeroInit();
202+
CharUnits calculateTailClippingOffset(bool isNonVirtualBaseType) const;
200203
/// Lowers bitfield storage types to I8 arrays for bitfields with tail
201204
/// padding that is or can potentially be used.
202205
void clipTailPadding();
@@ -287,7 +290,7 @@ void CGRecordLowering::lower(bool NVBaseType) {
287290
computeVolatileBitfields();
288291
return;
289292
}
290-
accumulateFields();
293+
accumulateFields(NVBaseType);
291294
// RD implies C++.
292295
if (RD) {
293296
accumulateVPtrs();
@@ -378,12 +381,12 @@ void CGRecordLowering::lowerUnion(bool isNoUniqueAddress) {
378381
Packed = true;
379382
}
380383

381-
void CGRecordLowering::accumulateFields() {
384+
void CGRecordLowering::accumulateFields(bool isNonVirtualBaseType) {
382385
for (RecordDecl::field_iterator Field = D->field_begin(),
383386
FieldEnd = D->field_end();
384387
Field != FieldEnd;) {
385388
if (Field->isBitField()) {
386-
Field = accumulateBitFields(Field, FieldEnd);
389+
Field = accumulateBitFields(isNonVirtualBaseType, Field, FieldEnd);
387390
assert((Field == FieldEnd || !Field->isBitField()) &&
388391
"Failed to accumulate all the bitfields");
389392
} else if (Field->isZeroSize(Context)) {
@@ -404,9 +407,12 @@ void CGRecordLowering::accumulateFields() {
404407
}
405408

406409
// Create members for bitfields. Field is a bitfield, and FieldEnd is the end
407-
// iterator of the record. Return the first non-bitfield encountered.
410+
// iterator of the record. Return the first non-bitfield encountered. We need
411+
// to know whether this is the base or complete layout, as virtual bases could
412+
// affect the upper bound of bitfield access unit allocation.
408413
RecordDecl::field_iterator
409-
CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
414+
CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
415+
RecordDecl::field_iterator Field,
410416
RecordDecl::field_iterator FieldEnd) {
411417
if (isDiscreteBitFieldABI()) {
412418
// Run stores the first element of the current run of bitfields. FieldEnd is
@@ -505,6 +511,10 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
505511
bitsToCharUnits(Context.getTargetInfo().getRegisterWidth());
506512
unsigned CharBits = Context.getCharWidth();
507513

514+
// Limit of useable tail padding at end of the record. Computed lazily and
515+
// cached here.
516+
CharUnits ScissorOffset = CharUnits::Zero();
517+
508518
// Data about the start of the span we're accumulating to create an access
509519
// unit from. Begin is the first bitfield of the span. If Begin is FieldEnd,
510520
// we've not got a current span. The span starts at the BeginOffset character
@@ -630,10 +640,14 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
630640
LimitOffset = bitsToCharUnits(getFieldBitOffset(*Probe));
631641
goto FoundLimit;
632642
}
633-
// We reached the end of the fields. We can't necessarily use tail
634-
// padding in C++ structs, so the NonVirtual size is what we must
635-
// use there.
636-
LimitOffset = RD ? Layout.getNonVirtualSize() : Layout.getDataSize();
643+
// We reached the end of the fields, determine the bounds of useable
644+
// tail padding. As this can be complex for C++, we cache the result.
645+
if (ScissorOffset.isZero()) {
646+
ScissorOffset = calculateTailClippingOffset(isNonVirtualBaseType);
647+
assert(!ScissorOffset.isZero() && "Tail clipping at zero");
648+
}
649+
650+
LimitOffset = ScissorOffset;
637651
FoundLimit:;
638652

639653
CharUnits TypeSize = getSize(Type);
@@ -838,13 +852,17 @@ void CGRecordLowering::accumulateVPtrs() {
838852
llvm::PointerType::getUnqual(Types.getLLVMContext())));
839853
}
840854

841-
void CGRecordLowering::accumulateVBases() {
855+
CharUnits
856+
CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
857+
if (!RD)
858+
return Layout.getDataSize();
859+
842860
CharUnits ScissorOffset = Layout.getNonVirtualSize();
843861
// In the itanium ABI, it's possible to place a vbase at a dsize that is
844862
// smaller than the nvsize. Here we check to see if such a base is placed
845863
// before the nvsize and set the scissor offset to that, instead of the
846864
// nvsize.
847-
if (isOverlappingVBaseABI())
865+
if (!isNonVirtualBaseType && isOverlappingVBaseABI())
848866
for (const auto &Base : RD->vbases()) {
849867
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
850868
if (BaseDecl->isEmpty())
@@ -856,8 +874,13 @@ void CGRecordLowering::accumulateVBases() {
856874
ScissorOffset = std::min(ScissorOffset,
857875
Layout.getVBaseClassOffset(BaseDecl));
858876
}
859-
Members.push_back(MemberInfo(ScissorOffset, MemberInfo::Scissor, nullptr,
860-
RD));
877+
878+
return ScissorOffset;
879+
}
880+
881+
void CGRecordLowering::accumulateVBases() {
882+
Members.push_back(MemberInfo(calculateTailClippingOffset(false),
883+
MemberInfo::Scissor, nullptr, RD));
861884
for (const auto &Base : RD->vbases()) {
862885
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
863886
if (BaseDecl->isEmpty())
@@ -882,7 +905,7 @@ void CGRecordLowering::accumulateVBases() {
882905
}
883906

884907
bool CGRecordLowering::hasOwnStorage(const CXXRecordDecl *Decl,
885-
const CXXRecordDecl *Query) {
908+
const CXXRecordDecl *Query) const {
886909
const ASTRecordLayout &DeclLayout = Context.getASTRecordLayout(Decl);
887910
if (DeclLayout.isPrimaryBaseVirtual() && DeclLayout.getPrimaryBase() == Query)
888911
return false;

clang/test/CodeGenCXX/bitfield-access-tail.cpp

Lines changed: 73 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,45 @@
22

33
// Configs that have cheap unaligned access
44
// Little Endian
5-
// RUN: %clang_cc1 -triple=aarch64-apple-darwin %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
6-
// RUN: %clang_cc1 -triple=aarch64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
5+
// RUN: %clang_cc1 -triple=aarch64-apple-darwin %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s
6+
// RUN: %clang_cc1 -triple=aarch64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s
77
// RUN: %clang_cc1 -triple=arm-apple-darwin %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT-DWN32 %s
8-
// RUN: %clang_cc1 -triple=arm-none-eabi %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
9-
// RUN: %clang_cc1 -triple=i686-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
10-
// RUN: %clang_cc1 -triple=loongarch64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
11-
// RUN: %clang_cc1 -triple=powerpcle-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
12-
// RUN: %clang_cc1 -triple=ve-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
13-
// RUN: %clang_cc1 -triple=wasm32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
14-
// RUN: %clang_cc1 -triple=wasm64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
15-
// RUN: %clang_cc1 -triple=x86_64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
8+
// RUN: %clang_cc1 -triple=arm-none-eabi %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
9+
// RUN: %clang_cc1 -triple=i686-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
10+
// RUN: %clang_cc1 -triple=loongarch64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s
11+
// RUN: %clang_cc1 -triple=powerpcle-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
12+
// RUN: %clang_cc1 -triple=ve-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s
13+
// RUN: %clang_cc1 -triple=wasm32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
14+
// RUN: %clang_cc1 -triple=wasm64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s
15+
// RUN: %clang_cc1 -triple=x86_64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s
1616

1717
// Big Endian
18-
// RUN: %clang_cc1 -triple=powerpc-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
19-
// RUN: %clang_cc1 -triple=powerpc64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
20-
// RUN: %clang_cc1 -triple=systemz %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
18+
// RUN: %clang_cc1 -triple=powerpc-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
19+
// RUN: %clang_cc1 -triple=powerpc64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s
20+
// RUN: %clang_cc1 -triple=systemz %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s
2121

2222
// Configs that have expensive unaligned access
2323
// Little Endian
24-
// RUN: %clang_cc1 -triple=amdgcn-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
25-
// RUN: %clang_cc1 -triple=arc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
26-
// RUN: %clang_cc1 -triple=bpf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
27-
// RUN: %clang_cc1 -triple=csky %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
28-
// RUN: %clang_cc1 -triple=hexagon-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
29-
// RUN: %clang_cc1 -triple=le64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
30-
// RUN: %clang_cc1 -triple=loongarch32-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
31-
// RUN: %clang_cc1 -triple=nvptx-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
32-
// RUN: %clang_cc1 -triple=riscv32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
33-
// RUN: %clang_cc1 -triple=riscv64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
34-
// RUN: %clang_cc1 -triple=spir-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
35-
// RUN: %clang_cc1 -triple=xcore-none-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
24+
// RUN: %clang_cc1 -triple=amdgcn-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s
25+
// RUN: %clang_cc1 -triple=arc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
26+
// RUN: %clang_cc1 -triple=bpf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s
27+
// RUN: %clang_cc1 -triple=csky %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
28+
// RUN: %clang_cc1 -triple=hexagon-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
29+
// RUN: %clang_cc1 -triple=le64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s
30+
// RUN: %clang_cc1 -triple=loongarch32-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
31+
// RUN: %clang_cc1 -triple=nvptx-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
32+
// RUN: %clang_cc1 -triple=riscv32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
33+
// RUN: %clang_cc1 -triple=riscv64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s
34+
// RUN: %clang_cc1 -triple=spir-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
35+
// RUN: %clang_cc1 -triple=xcore-none-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
3636

3737
// Big endian
38-
// RUN: %clang_cc1 -triple=lanai-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
39-
// RUN: %clang_cc1 -triple=m68k-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
40-
// RUN: %clang_cc1 -triple=mips-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
41-
// RUN: %clang_cc1 -triple=mips64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
42-
// RUN: %clang_cc1 -triple=sparc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
43-
// RUN: %clang_cc1 -triple=tce-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s
38+
// RUN: %clang_cc1 -triple=lanai-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
39+
// RUN: %clang_cc1 -triple=m68k-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
40+
// RUN: %clang_cc1 -triple=mips-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
41+
// RUN: %clang_cc1 -triple=mips64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s
42+
// RUN: %clang_cc1 -triple=sparc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
43+
// RUN: %clang_cc1 -triple=tce-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s
4444

4545
// Can use tail padding
4646
struct Pod {
@@ -113,3 +113,45 @@ struct __attribute__((packed)) PNonPod {
113113
// LAYOUT-DWN32-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:16 IsSigned:1 StorageSize:16 StorageOffset:0
114114
// LAYOUT-DWN32-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:8 IsSigned:1 StorageSize:8 StorageOffset:2
115115
// CHECK-NEXT: ]>
116+
117+
struct __attribute__((aligned(4))) Empty {} empty;
118+
119+
struct Char { char a; } cbase;
120+
struct D : virtual Char {
121+
[[no_unique_address]] Empty e0;
122+
[[no_unique_address]] Empty e1;
123+
unsigned a : 24; // keep as 24bits
124+
} d;
125+
// CHECK-LABEL: LLVMType:%struct.D =
126+
// LAYOUT64-SAME: type <{ ptr, [3 x i8], %struct.Char, [4 x i8] }>
127+
// LAYOUT32-SAME: type { ptr, [3 x i8], %struct.Char }
128+
// LAYOUT-DWN32-SAME: type { ptr, [3 x i8], %struct.Char }
129+
// CHECK-NEXT: NonVirtualBaseLLVMType:
130+
// LAYOUT64-SAME: %struct.D.base = type <{ ptr, i32 }>
131+
// LAYOUT32-SAME: %struct.D = type { ptr, [3 x i8], %struct.Char }
132+
// LAYOUT-DWN32-SAME: %struct.D = type { ptr, [3 x i8], %struct.Char }
133+
// CHECK: BitFields:[
134+
// LAYOUT-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:24 IsSigned:0 StorageSize:24 StorageOffset:{{(4|8)}}
135+
136+
// LAYOUT-DWN32-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:24 IsSigned:0 StorageSize:24 StorageOffset:{{(4|8)}}
137+
// CHECK-NEXT: ]>
138+
139+
struct Int { int a; } ibase;
140+
struct E : virtual Int {
141+
[[no_unique_address]] Empty e0;
142+
[[no_unique_address]] Empty e1;
143+
unsigned a : 24; // expand to 32
144+
} e;
145+
// CHECK-LABEL: LLVMType:%struct.E =
146+
// LAYOUT64-SAME: type <{ ptr, i32, %struct.Int }>
147+
// LAYOUT32-SAME: type { ptr, i32, %struct.Int }
148+
// LAYOUT-DWN32-SAME: type { ptr, i32, %struct.Int }
149+
// CHECK-NEXT: NonVirtualBaseLLVMType:%struct.E.base =
150+
// LAYOUT64-SAME: type <{ ptr, i32 }>
151+
// LAYOUT32-SAME: type { ptr, i32 }
152+
// LAYOUT-DWN32-SAME: type { ptr, i32 }
153+
// CHECK: BitFields:[
154+
// LAYOUT-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:24 IsSigned:0 StorageSize:32 StorageOffset:{{(4|8)}}
155+
156+
// LAYOUT-DWN32-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:24 IsSigned:0 StorageSize:32 StorageOffset:{{(4|8)}}
157+
// CHECK-NEXT: ]>

0 commit comments

Comments
 (0)