mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-02 01:16:05 +00:00

RecordLayoutBuilder assumes the size of a potentially-overlapping class/struct field with non-zero size as the size of the base subobject type corresponding to the field type. Make CGRecordLayoutBuilder to acknowledge that in order to avoid incorrect padding insertion. Differential Revision: https://reviews.llvm.org/D139741
210 lines
7.4 KiB
C++
210 lines
7.4 KiB
C++
// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -emit-llvm -fdump-record-layouts -std=c++17 %s -o %t | FileCheck %s
|
|
|
|
// CHECK-LABEL: 0 | class Empty (empty)
|
|
// CHECK-NEXT: | [sizeof=1, dsize=1, align=1,
|
|
// CHECK-NEXT: | nvsize=1, nvalign=1]
|
|
// CHECK-LABEL: 0 | class Second
|
|
// CHECK-NEXT: 0 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 0:0-0 | short A
|
|
// CHECK-NEXT: | [sizeof=2, dsize=1, align=2,
|
|
// CHECK-NEXT: | nvsize=1, nvalign=2]
|
|
// CHECK-LABEL: 0 | class Foo
|
|
// CHECK-NEXT: 0 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 2 | class Second NZNoUnique
|
|
// CHECK-NEXT: 2 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 2:0-0 | short A
|
|
// CHECK-NEXT: 3 | char B
|
|
// CHECK-NEXT: | [sizeof=4, dsize=4, align=2,
|
|
// CHECK-NEXT: | nvsize=4, nvalign=2]
|
|
|
|
class Empty {};
|
|
|
|
// CHECK-LABEL: LLVMType:%class.Second = type { i8, i8 }
|
|
// CHECK-NEXT: NonVirtualBaseLLVMType:%class.Second.base = type { i8 }
|
|
class Second : Empty {
|
|
short A : 1;
|
|
};
|
|
|
|
// CHECK-LABEL: LLVMType:%class.Foo = type { [2 x i8], %class.Second.base, i8 }
|
|
// CHECK-NEXT: NonVirtualBaseLLVMType:%class.Foo = type { [2 x i8], %class.Second.base, i8 }
|
|
class Foo : Empty {
|
|
[[no_unique_address]] Second NZNoUnique;
|
|
char B;
|
|
};
|
|
Foo I;
|
|
|
|
// CHECK-LABEL: 0 | class SecondEmpty (empty)
|
|
// CHECK-NEXT: 0 | class Empty (base) (empty)
|
|
// CHECK-NEXT: | [sizeof=1, dsize=0, align=1,
|
|
// CHECK-NEXT: | nvsize=1, nvalign=1]
|
|
class SecondEmpty: Empty {
|
|
};
|
|
|
|
// CHECK-LABEL: 0 | class Bar
|
|
// CHECK-NEXT: 0 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 1 | class SecondEmpty ZNoUnique (empty)
|
|
// CHECK-NEXT: 1 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 0 | char C
|
|
// CHECK-NEXT: | [sizeof=2, dsize=1, align=1,
|
|
// CHECK-NEXT: | nvsize=2, nvalign=1]
|
|
|
|
// CHECK-LABEL: LLVMType:%class.Bar = type { i8, i8 }
|
|
// CHECK-NEXT: NonVirtualBaseLLVMType:%class.Bar = type { i8, i8 }
|
|
class Bar : Empty {
|
|
[[no_unique_address]] SecondEmpty ZNoUnique;
|
|
char C;
|
|
};
|
|
Bar J;
|
|
|
|
// CHECK-LABEL: 0 | class IntFieldClass
|
|
// CHECK-NEXT: 0 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 2 | class Second Field
|
|
// CHECK-NEXT: 2 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 2:0-0 | short A
|
|
// CHECK-NEXT: 4 | int C
|
|
// CHECK-NEXT: | [sizeof=8, dsize=8, align=4,
|
|
// CHECK-NEXT: | nvsize=8, nvalign=4]
|
|
|
|
// CHECK-LABEL: LLVMType:%class.IntFieldClass = type { [2 x i8], %class.Second.base, i32 }
|
|
// CHECK-NEXT: NonVirtualBaseLLVMType:%class.IntFieldClass = type { [2 x i8], %class.Second.base, i32 }
|
|
class IntFieldClass : Empty {
|
|
[[no_unique_address]] Second Field;
|
|
int C;
|
|
};
|
|
IntFieldClass K;
|
|
|
|
// CHECK-LABEL: 0 | class UnionClass
|
|
// CHECK-NEXT: 0 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 0 | union UnionClass
|
|
// CHECK-NEXT: 0 | int I
|
|
// CHECK-NEXT: 0 | char C
|
|
// CHECK-NEXT: 4 | int C
|
|
// CHECK-NEXT: | [sizeof=8, dsize=8, align=4,
|
|
// CHECK-NEXT: | nvsize=8, nvalign=4]
|
|
|
|
// CHECK-LABEL: LLVMType:%class.UnionClass = type { %union.anon, i32 }
|
|
// CHECK-NEXT: NonVirtualBaseLLVMType:%class.UnionClass = type { %union.anon, i32 }
|
|
// CHECK-NEXT: IsZeroInitializable:1
|
|
// CHECK-NEXT: BitFields:[
|
|
// CHECK-NEXT: ]>
|
|
class UnionClass : Empty {
|
|
[[no_unique_address]] union {
|
|
int I;
|
|
char C;
|
|
} U;
|
|
int C;
|
|
};
|
|
UnionClass L;
|
|
|
|
// CHECK-LABEL: 0 | class EnumClass
|
|
// CHECK-NEXT: 0 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 0 | enum E A
|
|
// CHECK-NEXT: 4 | int C
|
|
// CHECK-NEXT: | [sizeof=8, dsize=8, align=4,
|
|
// CHECK-NEXT: | nvsize=8, nvalign=4]
|
|
|
|
// CHECK-LABEL: LLVMType:%class.EnumClass = type { i32, i32 }
|
|
// CHECK-NEXT: NonVirtualBaseLLVMType:%class.EnumClass = type { i32, i32 }
|
|
// CHECK-NEXT: IsZeroInitializable:1
|
|
// CHECK-NEXT: BitFields:[
|
|
// CHECK-NEXT: ]>
|
|
class EnumClass : Empty {
|
|
[[no_unique_address]] enum class E { X, Y, Z } A;
|
|
int C;
|
|
};
|
|
EnumClass M;
|
|
|
|
// CHECK-LABEL: 0 | class NoBaseField
|
|
// CHECK-NEXT: 0 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 1 | class Empty A (empty)
|
|
// CHECK-NEXT: 0 | int B
|
|
// CHECK-NEXT: | [sizeof=4, dsize=4, align=4,
|
|
// CHECK-NEXT: | nvsize=4, nvalign=4]
|
|
|
|
// CHECK-LABEL: LLVMType:%class.NoBaseField = type { i32 }
|
|
// CHECK-NEXT: NonVirtualBaseLLVMType:%class.NoBaseField = type { i32 }
|
|
// CHECK-NEXT: IsZeroInitializable:1
|
|
// CHECK-NEXT: BitFields:[
|
|
// CHECK-NEXT: ]>
|
|
class NoBaseField : Empty {
|
|
[[no_unique_address]] Empty A;
|
|
int B;
|
|
};
|
|
NoBaseField N;
|
|
|
|
// CHECK-LABEL: 0 | class FinalEmpty (empty)
|
|
// CHECK-NEXT: | [sizeof=1, dsize=1, align=1,
|
|
// CHECK-NEXT: | nvsize=1, nvalign=1]
|
|
|
|
// CHECK-LABEL: 0 | class FinalClass
|
|
// CHECK-NEXT: 0 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 0 | class FinalEmpty A (empty)
|
|
// CHECK-NEXT: 0 | int B
|
|
// CHECK-NEXT: | [sizeof=4, dsize=4, align=4,
|
|
// CHECK-NEXT: | nvsize=4, nvalign=4]
|
|
class FinalEmpty final {};
|
|
class FinalClass final : Empty {
|
|
[[no_unique_address]] FinalEmpty A;
|
|
int B;
|
|
} O;
|
|
|
|
|
|
// CHECK-LABEL: 0 | union Union2Class::PaddedUnion
|
|
// CHECK-NEXT: 0 | class Empty A (empty)
|
|
// CHECK-NEXT: 0 | char B
|
|
// CHECK-NEXT: | [sizeof=2, dsize=1, align=2,
|
|
// CHECK-NEXT: | nvsize=1, nvalign=2]
|
|
|
|
// CHECK-LABEL: 0 | class Union2Class
|
|
// CHECK-NEXT: 0 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 2 | union Union2Class::PaddedUnion U
|
|
// CHECK-NEXT: 2 | class Empty A (empty)
|
|
// CHECK-NEXT: 2 | char B
|
|
// CHECK-NEXT: 3 | char C
|
|
// CHECK-NEXT: | [sizeof=4, dsize=4, align=2,
|
|
// CHECK-NEXT: | nvsize=4, nvalign=2]
|
|
class Union2Class : Empty {
|
|
[[no_unique_address]] union PaddedUnion {
|
|
private:
|
|
Empty A;
|
|
alignas(2) char B;
|
|
} U;
|
|
char C;
|
|
} P;
|
|
|
|
// CHECK-LABEL: 0 | struct NotEmptyWithBitfield
|
|
// CHECK-NEXT: 0 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 0 | char[2] A
|
|
// CHECK-NEXT: 2:0-0 | int B
|
|
// CHECK-NEXT: | [sizeof=4, dsize=3, align=4,
|
|
// CHECK-NEXT: | nvsize=3, nvalign=4]
|
|
|
|
// CHECK-LABEL: 0 | union C::
|
|
// CHECK-NEXT: 0 | short C
|
|
// CHECK-NEXT: 0 | struct NotEmptyWithBitfield A
|
|
// CHECK-NEXT: 0 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 0 | char[2] A
|
|
// CHECK-NEXT: 2:0-0 | int B
|
|
// CHECK-NEXT: | [sizeof=4, dsize=3, align=4,
|
|
// CHECK-NEXT: | nvsize=3, nvalign=4]
|
|
|
|
// CHECK-LABEL: 0 | struct C
|
|
// CHECK-NEXT: 0 | union C::
|
|
// CHECK-NEXT: 0 | short C
|
|
// CHECK-NEXT: 0 | struct NotEmptyWithBitfield A
|
|
// CHECK-NEXT: 0 | class Empty (base) (empty)
|
|
// CHECK-NEXT: 0 | char[2] A
|
|
// CHECK-NEXT: 2:0-0 | int B
|
|
// CHECK-NEXT: | [sizeof=4, dsize=3, align=4,
|
|
// CHECK-NEXT: | nvsize=3, nvalign=4]
|
|
struct NotEmptyWithBitfield : Empty {
|
|
char A[2];
|
|
int B : 1;
|
|
};
|
|
struct C {
|
|
[[no_unique_address]] union {
|
|
short C;
|
|
[[no_unique_address]] NotEmptyWithBitfield A;
|
|
} U;
|
|
} Q;
|