1 //=== - llvm/unittest/Support/TrailingObjectsTest.cpp ---------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Support/TrailingObjects.h"
10 #include "gtest/gtest.h"
15 // This class, beyond being used by the test case, a nice
16 // demonstration of the intended usage of TrailingObjects, with a
17 // single trailing array.
18 class Class1 final
: protected TrailingObjects
<Class1
, short> {
19 friend TrailingObjects
;
24 size_t numTrailingObjects(OverloadToken
<short>) const { return NumShorts
; }
26 Class1(int *ShortArray
, unsigned NumShorts
) : NumShorts(NumShorts
) {
27 std::uninitialized_copy(ShortArray
, ShortArray
+ NumShorts
,
28 getTrailingObjects
<short>());
32 static Class1
*create(int *ShortArray
, unsigned NumShorts
) {
33 void *Mem
= ::operator new(totalSizeToAlloc
<short>(NumShorts
));
34 return new (Mem
) Class1(ShortArray
, NumShorts
);
36 void operator delete(void *p
) { ::operator delete(p
); }
38 short get(unsigned Num
) const { return getTrailingObjects
<short>()[Num
]; }
40 unsigned numShorts() const { return NumShorts
; }
42 // Pull some protected members in as public, for testability.
43 template <typename
... Ty
>
44 using FixedSizeStorage
= TrailingObjects::FixedSizeStorage
<Ty
...>;
46 using TrailingObjects::totalSizeToAlloc
;
47 using TrailingObjects::additionalSizeToAlloc
;
48 using TrailingObjects::getTrailingObjects
;
51 // Here, there are two singular optional object types appended. Note
52 // that the alignment of Class2 is automatically increased to account
53 // for the alignment requirements of the trailing objects.
54 class Class2 final
: protected TrailingObjects
<Class2
, double, short> {
55 friend TrailingObjects
;
57 bool HasShort
, HasDouble
;
60 size_t numTrailingObjects(OverloadToken
<short>) const {
61 return HasShort
? 1 : 0;
63 size_t numTrailingObjects(OverloadToken
<double>) const {
64 return HasDouble
? 1 : 0;
67 Class2(bool HasShort
, bool HasDouble
)
68 : HasShort(HasShort
), HasDouble(HasDouble
) {}
71 static Class2
*create(short S
= 0, double D
= 0.0) {
72 bool HasShort
= S
!= 0;
73 bool HasDouble
= D
!= 0.0;
76 ::operator new(totalSizeToAlloc
<double, short>(HasDouble
, HasShort
));
77 Class2
*C
= new (Mem
) Class2(HasShort
, HasDouble
);
79 *C
->getTrailingObjects
<short>() = S
;
81 *C
->getTrailingObjects
<double>() = D
;
84 void operator delete(void *p
) { ::operator delete(p
); }
86 short getShort() const {
89 return *getTrailingObjects
<short>();
92 double getDouble() const {
95 return *getTrailingObjects
<double>();
98 // Pull some protected members in as public, for testability.
99 template <typename
... Ty
>
100 using FixedSizeStorage
= TrailingObjects::FixedSizeStorage
<Ty
...>;
102 using TrailingObjects::totalSizeToAlloc
;
103 using TrailingObjects::additionalSizeToAlloc
;
104 using TrailingObjects::getTrailingObjects
;
107 TEST(TrailingObjects
, OneArg
) {
108 int arr
[] = {1, 2, 3};
109 Class1
*C
= Class1::create(arr
, 3);
110 EXPECT_EQ(sizeof(Class1
), sizeof(unsigned));
111 EXPECT_EQ(Class1::additionalSizeToAlloc
<short>(1), sizeof(short));
112 EXPECT_EQ(Class1::additionalSizeToAlloc
<short>(3), sizeof(short) * 3);
114 EXPECT_EQ(alignof(Class1
),
115 alignof(Class1::FixedSizeStorage
<short>::with_counts
<1>::type
));
116 EXPECT_EQ(sizeof(Class1::FixedSizeStorage
<short>::with_counts
<1>::type
),
117 llvm::alignTo(Class1::totalSizeToAlloc
<short>(1), alignof(Class1
)));
118 EXPECT_EQ(Class1::totalSizeToAlloc
<short>(1), sizeof(Class1
) + sizeof(short));
120 EXPECT_EQ(alignof(Class1
),
121 alignof(Class1::FixedSizeStorage
<short>::with_counts
<3>::type
));
122 EXPECT_EQ(sizeof(Class1::FixedSizeStorage
<short>::with_counts
<3>::type
),
123 llvm::alignTo(Class1::totalSizeToAlloc
<short>(3), alignof(Class1
)));
124 EXPECT_EQ(Class1::totalSizeToAlloc
<short>(3),
125 sizeof(Class1
) + sizeof(short) * 3);
127 EXPECT_EQ(C
->getTrailingObjects
<short>(), reinterpret_cast<short *>(C
+ 1));
128 EXPECT_EQ(C
->get(0), 1);
129 EXPECT_EQ(C
->get(2), 3);
133 TEST(TrailingObjects
, TwoArg
) {
134 Class2
*C1
= Class2::create(4);
135 Class2
*C2
= Class2::create(0, 4.2);
137 EXPECT_EQ(sizeof(Class2
), llvm::alignTo(sizeof(bool) * 2, alignof(double)));
138 EXPECT_EQ(alignof(Class2
), alignof(double));
140 EXPECT_EQ((Class2::additionalSizeToAlloc
<double, short>(1, 0)),
142 EXPECT_EQ((Class2::additionalSizeToAlloc
<double, short>(0, 1)),
144 EXPECT_EQ((Class2::additionalSizeToAlloc
<double, short>(3, 1)),
145 sizeof(double) * 3 + sizeof(short));
150 Class2::FixedSizeStorage
<double, short>::with_counts
<1, 1>::type
)));
152 sizeof(Class2::FixedSizeStorage
<double, short>::with_counts
<1, 1>::type
),
153 llvm::alignTo(Class2::totalSizeToAlloc
<double, short>(1, 1),
155 EXPECT_EQ((Class2::totalSizeToAlloc
<double, short>(1, 1)),
156 sizeof(Class2
) + sizeof(double) + sizeof(short));
158 EXPECT_EQ(C1
->getDouble(), 0);
159 EXPECT_EQ(C1
->getShort(), 4);
160 EXPECT_EQ(C1
->getTrailingObjects
<double>(),
161 reinterpret_cast<double *>(C1
+ 1));
162 EXPECT_EQ(C1
->getTrailingObjects
<short>(), reinterpret_cast<short *>(C1
+ 1));
164 EXPECT_EQ(C2
->getDouble(), 4.2);
165 EXPECT_EQ(C2
->getShort(), 0);
166 EXPECT_EQ(C2
->getTrailingObjects
<double>(),
167 reinterpret_cast<double *>(C2
+ 1));
168 EXPECT_EQ(C2
->getTrailingObjects
<short>(),
169 reinterpret_cast<short *>(reinterpret_cast<double *>(C2
+ 1) + 1));
174 // This test class is not trying to be a usage demo, just asserting
175 // that three args does actually work too (it's the same code as
176 // handles the second arg, so it's basically covered by the above, but
178 class Class3 final
: public TrailingObjects
<Class3
, double, short, bool> {
179 friend TrailingObjects
;
181 size_t numTrailingObjects(OverloadToken
<double>) const { return 1; }
182 size_t numTrailingObjects(OverloadToken
<short>) const { return 1; }
185 TEST(TrailingObjects
, ThreeArg
) {
186 EXPECT_EQ((Class3::additionalSizeToAlloc
<double, short, bool>(1, 1, 3)),
187 sizeof(double) + sizeof(short) + 3 * sizeof(bool));
188 EXPECT_EQ(sizeof(Class3
), llvm::alignTo(1, alignof(double)));
192 (alignof(Class3::FixedSizeStorage
<double, short,
193 bool>::with_counts
<1, 1, 3>::type
)));
195 sizeof(Class3::FixedSizeStorage
<double, short,
196 bool>::with_counts
<1, 1, 3>::type
),
197 llvm::alignTo(Class3::totalSizeToAlloc
<double, short, bool>(1, 1, 3),
200 std::unique_ptr
<char[]> P(new char[1000]);
201 Class3
*C
= reinterpret_cast<Class3
*>(P
.get());
202 EXPECT_EQ(C
->getTrailingObjects
<double>(), reinterpret_cast<double *>(C
+ 1));
203 EXPECT_EQ(C
->getTrailingObjects
<short>(),
204 reinterpret_cast<short *>(reinterpret_cast<double *>(C
+ 1) + 1));
206 C
->getTrailingObjects
<bool>(),
207 reinterpret_cast<bool *>(
208 reinterpret_cast<short *>(reinterpret_cast<double *>(C
+ 1) + 1) +
212 class Class4 final
: public TrailingObjects
<Class4
, char, long> {
213 friend TrailingObjects
;
214 size_t numTrailingObjects(OverloadToken
<char>) const { return 1; }
217 TEST(TrailingObjects
, Realignment
) {
218 EXPECT_EQ((Class4::additionalSizeToAlloc
<char, long>(1, 1)),
219 llvm::alignTo(sizeof(long) + 1, alignof(long)));
220 EXPECT_EQ(sizeof(Class4
), llvm::alignTo(1, alignof(long)));
224 (alignof(Class4::FixedSizeStorage
<char, long>::with_counts
<1, 1>::type
)));
226 sizeof(Class4::FixedSizeStorage
<char, long>::with_counts
<1, 1>::type
),
227 llvm::alignTo(Class4::totalSizeToAlloc
<char, long>(1, 1),
230 std::unique_ptr
<char[]> P(new char[1000]);
231 Class4
*C
= reinterpret_cast<Class4
*>(P
.get());
232 EXPECT_EQ(C
->getTrailingObjects
<char>(), reinterpret_cast<char *>(C
+ 1));
233 EXPECT_EQ(C
->getTrailingObjects
<long>(),
234 reinterpret_cast<long *>(llvm::alignAddr(
235 reinterpret_cast<char *>(C
+ 1) + 1, alignof(long))));
239 // Test the use of TrailingObjects with a template class. This
240 // previously failed to compile due to a bug in MSVC's member access
241 // control/lookup handling for OverloadToken.
242 template <typename Derived
>
243 class Class5Tmpl
: private llvm::TrailingObjects
<Derived
, float, int> {
244 using TrailingObjects
= typename
llvm::TrailingObjects
<Derived
, float>;
245 friend TrailingObjects
;
247 size_t numTrailingObjects(
248 typename
TrailingObjects::template OverloadToken
<float>) const {
252 size_t numTrailingObjects(
253 typename
TrailingObjects::template OverloadToken
<int>) const {
258 class Class5
: public Class5Tmpl
<Class5
> {};