1 //=== - llvm/unittest/Support/TrailingObjectsTest.cpp ---------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Support/TrailingObjects.h" 11 #include "gtest/gtest.h" 12 13 using namespace llvm; 14 15 namespace { 16 // This class, beyond being used by the test case, a nice 17 // demonstration of the intended usage of TrailingObjects, with a 18 // single trailing array. 19 class Class1 final : protected TrailingObjects<Class1, short> { 20 friend TrailingObjects; 21 22 unsigned NumShorts; 23 24 protected: 25 size_t numTrailingObjects(OverloadToken<short>) const { return NumShorts; } 26 27 Class1(int *ShortArray, unsigned NumShorts) : NumShorts(NumShorts) { 28 std::uninitialized_copy(ShortArray, ShortArray + NumShorts, 29 getTrailingObjects<short>()); 30 } 31 32 public: 33 static Class1 *create(int *ShortArray, unsigned NumShorts) { 34 void *Mem = ::operator new(totalSizeToAlloc<short>(NumShorts)); 35 return new (Mem) Class1(ShortArray, NumShorts); 36 } 37 void operator delete(void *p) { ::operator delete(p); } 38 39 short get(unsigned Num) const { return getTrailingObjects<short>()[Num]; } 40 41 unsigned numShorts() const { return NumShorts; } 42 43 // Pull some protected members in as public, for testability. 44 template <typename... Ty> 45 using FixedSizeStorage = TrailingObjects::FixedSizeStorage<Ty...>; 46 47 using TrailingObjects::totalSizeToAlloc; 48 using TrailingObjects::additionalSizeToAlloc; 49 using TrailingObjects::getTrailingObjects; 50 }; 51 52 // Here, there are two singular optional object types appended. Note 53 // that the alignment of Class2 is automatically increased to account 54 // for the alignment requirements of the trailing objects. 55 class Class2 final : protected TrailingObjects<Class2, double, short> { 56 friend TrailingObjects; 57 58 bool HasShort, HasDouble; 59 60 protected: 61 size_t numTrailingObjects(OverloadToken<short>) const { 62 return HasShort ? 1 : 0; 63 } 64 size_t numTrailingObjects(OverloadToken<double>) const { 65 return HasDouble ? 1 : 0; 66 } 67 68 Class2(bool HasShort, bool HasDouble) 69 : HasShort(HasShort), HasDouble(HasDouble) {} 70 71 public: 72 static Class2 *create(short S = 0, double D = 0.0) { 73 bool HasShort = S != 0; 74 bool HasDouble = D != 0.0; 75 76 void *Mem = 77 ::operator new(totalSizeToAlloc<double, short>(HasDouble, HasShort)); 78 Class2 *C = new (Mem) Class2(HasShort, HasDouble); 79 if (HasShort) 80 *C->getTrailingObjects<short>() = S; 81 if (HasDouble) 82 *C->getTrailingObjects<double>() = D; 83 return C; 84 } 85 void operator delete(void *p) { ::operator delete(p); } 86 87 short getShort() const { 88 if (!HasShort) 89 return 0; 90 return *getTrailingObjects<short>(); 91 } 92 93 double getDouble() const { 94 if (!HasDouble) 95 return 0.0; 96 return *getTrailingObjects<double>(); 97 } 98 99 // Pull some protected members in as public, for testability. 100 template <typename... Ty> 101 using FixedSizeStorage = TrailingObjects::FixedSizeStorage<Ty...>; 102 103 using TrailingObjects::totalSizeToAlloc; 104 using TrailingObjects::additionalSizeToAlloc; 105 using TrailingObjects::getTrailingObjects; 106 }; 107 108 TEST(TrailingObjects, OneArg) { 109 int arr[] = {1, 2, 3}; 110 Class1 *C = Class1::create(arr, 3); 111 EXPECT_EQ(sizeof(Class1), sizeof(unsigned)); 112 EXPECT_EQ(Class1::additionalSizeToAlloc<short>(1), sizeof(short)); 113 EXPECT_EQ(Class1::additionalSizeToAlloc<short>(3), sizeof(short) * 3); 114 115 EXPECT_EQ(alignof(Class1), 116 alignof(Class1::FixedSizeStorage<short>::with_counts<1>::type)); 117 EXPECT_EQ(sizeof(Class1::FixedSizeStorage<short>::with_counts<1>::type), 118 llvm::alignTo(Class1::totalSizeToAlloc<short>(1), alignof(Class1))); 119 EXPECT_EQ(Class1::totalSizeToAlloc<short>(1), sizeof(Class1) + sizeof(short)); 120 121 EXPECT_EQ(alignof(Class1), 122 alignof(Class1::FixedSizeStorage<short>::with_counts<3>::type)); 123 EXPECT_EQ(sizeof(Class1::FixedSizeStorage<short>::with_counts<3>::type), 124 llvm::alignTo(Class1::totalSizeToAlloc<short>(3), alignof(Class1))); 125 EXPECT_EQ(Class1::totalSizeToAlloc<short>(3), 126 sizeof(Class1) + sizeof(short) * 3); 127 128 EXPECT_EQ(C->getTrailingObjects<short>(), reinterpret_cast<short *>(C + 1)); 129 EXPECT_EQ(C->get(0), 1); 130 EXPECT_EQ(C->get(2), 3); 131 delete C; 132 } 133 134 TEST(TrailingObjects, TwoArg) { 135 Class2 *C1 = Class2::create(4); 136 Class2 *C2 = Class2::create(0, 4.2); 137 138 EXPECT_EQ(sizeof(Class2), llvm::alignTo(sizeof(bool) * 2, alignof(double))); 139 EXPECT_EQ(alignof(Class2), alignof(double)); 140 141 EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(1, 0)), 142 sizeof(double)); 143 EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(0, 1)), 144 sizeof(short)); 145 EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(3, 1)), 146 sizeof(double) * 3 + sizeof(short)); 147 148 EXPECT_EQ( 149 alignof(Class2), 150 (alignof( 151 Class2::FixedSizeStorage<double, short>::with_counts<1, 1>::type))); 152 EXPECT_EQ( 153 sizeof(Class2::FixedSizeStorage<double, short>::with_counts<1, 1>::type), 154 llvm::alignTo(Class2::totalSizeToAlloc<double, short>(1, 1), 155 alignof(Class2))); 156 EXPECT_EQ((Class2::totalSizeToAlloc<double, short>(1, 1)), 157 sizeof(Class2) + sizeof(double) + sizeof(short)); 158 159 EXPECT_EQ(C1->getDouble(), 0); 160 EXPECT_EQ(C1->getShort(), 4); 161 EXPECT_EQ(C1->getTrailingObjects<double>(), 162 reinterpret_cast<double *>(C1 + 1)); 163 EXPECT_EQ(C1->getTrailingObjects<short>(), reinterpret_cast<short *>(C1 + 1)); 164 165 EXPECT_EQ(C2->getDouble(), 4.2); 166 EXPECT_EQ(C2->getShort(), 0); 167 EXPECT_EQ(C2->getTrailingObjects<double>(), 168 reinterpret_cast<double *>(C2 + 1)); 169 EXPECT_EQ(C2->getTrailingObjects<short>(), 170 reinterpret_cast<short *>(reinterpret_cast<double *>(C2 + 1) + 1)); 171 delete C1; 172 delete C2; 173 } 174 175 // This test class is not trying to be a usage demo, just asserting 176 // that three args does actually work too (it's the same code as 177 // handles the second arg, so it's basically covered by the above, but 178 // just in case..) 179 class Class3 final : public TrailingObjects<Class3, double, short, bool> { 180 friend TrailingObjects; 181 182 size_t numTrailingObjects(OverloadToken<double>) const { return 1; } 183 size_t numTrailingObjects(OverloadToken<short>) const { return 1; } 184 }; 185 186 TEST(TrailingObjects, ThreeArg) { 187 EXPECT_EQ((Class3::additionalSizeToAlloc<double, short, bool>(1, 1, 3)), 188 sizeof(double) + sizeof(short) + 3 * sizeof(bool)); 189 EXPECT_EQ(sizeof(Class3), llvm::alignTo(1, alignof(double))); 190 191 EXPECT_EQ( 192 alignof(Class3), 193 (alignof(Class3::FixedSizeStorage<double, short, 194 bool>::with_counts<1, 1, 3>::type))); 195 EXPECT_EQ( 196 sizeof(Class3::FixedSizeStorage<double, short, 197 bool>::with_counts<1, 1, 3>::type), 198 llvm::alignTo(Class3::totalSizeToAlloc<double, short, bool>(1, 1, 3), 199 alignof(Class3))); 200 201 std::unique_ptr<char[]> P(new char[1000]); 202 Class3 *C = reinterpret_cast<Class3 *>(P.get()); 203 EXPECT_EQ(C->getTrailingObjects<double>(), reinterpret_cast<double *>(C + 1)); 204 EXPECT_EQ(C->getTrailingObjects<short>(), 205 reinterpret_cast<short *>(reinterpret_cast<double *>(C + 1) + 1)); 206 EXPECT_EQ( 207 C->getTrailingObjects<bool>(), 208 reinterpret_cast<bool *>( 209 reinterpret_cast<short *>(reinterpret_cast<double *>(C + 1) + 1) + 210 1)); 211 } 212 213 class Class4 final : public TrailingObjects<Class4, char, long> { 214 friend TrailingObjects; 215 size_t numTrailingObjects(OverloadToken<char>) const { return 1; } 216 }; 217 218 TEST(TrailingObjects, Realignment) { 219 EXPECT_EQ((Class4::additionalSizeToAlloc<char, long>(1, 1)), 220 llvm::alignTo(sizeof(long) + 1, alignof(long))); 221 EXPECT_EQ(sizeof(Class4), llvm::alignTo(1, alignof(long))); 222 223 EXPECT_EQ( 224 alignof(Class4), 225 (alignof(Class4::FixedSizeStorage<char, long>::with_counts<1, 1>::type))); 226 EXPECT_EQ( 227 sizeof(Class4::FixedSizeStorage<char, long>::with_counts<1, 1>::type), 228 llvm::alignTo(Class4::totalSizeToAlloc<char, long>(1, 1), 229 alignof(Class4))); 230 231 std::unique_ptr<char[]> P(new char[1000]); 232 Class4 *C = reinterpret_cast<Class4 *>(P.get()); 233 EXPECT_EQ(C->getTrailingObjects<char>(), reinterpret_cast<char *>(C + 1)); 234 EXPECT_EQ(C->getTrailingObjects<long>(), 235 reinterpret_cast<long *>(llvm::alignAddr( 236 reinterpret_cast<char *>(C + 1) + 1, alignof(long)))); 237 } 238 } 239 240 // Test the use of TrailingObjects with a template class. This 241 // previously failed to compile due to a bug in MSVC's member access 242 // control/lookup handling for OverloadToken. 243 template <typename Derived> 244 class Class5Tmpl : private llvm::TrailingObjects<Derived, float, int> { 245 using TrailingObjects = typename llvm::TrailingObjects<Derived, float>; 246 friend TrailingObjects; 247 248 size_t numTrailingObjects( 249 typename TrailingObjects::template OverloadToken<float>) const { 250 return 1; 251 } 252 253 size_t numTrailingObjects( 254 typename TrailingObjects::template OverloadToken<int>) const { 255 return 2; 256 } 257 }; 258 259 class Class5 : public Class5Tmpl<Class5> {}; 260