[llvm] r256054 - Rewrite the TrailingObjects template to provide two new features:
Kostya Serebryany via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 21 11:13:27 PST 2015
r256179 should fix the leak and make the bot green, please verify that this
is what you want.
On Mon, Dec 21, 2015 at 10:42 AM, Kostya Serebryany <kcc at google.com> wrote:
> There seem to be a leak in TrailingObjectsTest.cpp, which makes the
> sanitizer bot unhappy:
>
> http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/8768/steps/check-llvm%20asan/logs/stdio
>
> ==30500==ERROR: LeakSanitizer: detected memory leaks
>
> Direct leak of 1000 byte(s) in 1 object(s) allocated from:
> #0 0x502e60 in operator new(unsigned long) /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:62
> #1 0x9b9e7d in (anonymous namespace)::TrailingObjects_ThreeArg_Test::TestBody() /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/unittests/Support/TrailingObjectsTest.cpp:167:42
> #2 0xbc307a in HandleExceptionsInMethodIfSupported<testing::Test, void> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/utils/unittest/googletest/src/gtest.cc:2145:12
> #3 0xbc307a in testing::Test::Run() /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/utils/unittest/googletest/src/gtest.cc:2161
> #4 0xbc6836 in testing::TestInfo::Run() /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/utils/unittest/googletest/src/gtest.cc:2309:5
> #5 0xbc777a in testing::TestCase::Run() /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/utils/unittest/googletest/src/gtest.cc:2416:5
> #6 0xbddb0c in testing::internal::UnitTestImpl::RunAllTests() /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/utils/unittest/googletest/src/gtest.cc:4207:11
> #7 0xbdcc18 in HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/utils/unittest/googletest/src/gtest.cc:2145:12
> #8 0xbdcc18 in testing::UnitTest::Run() /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/utils/unittest/googletest/src/gtest.cc:3841
> #9 0xc045a8 in main /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/utils/unittest/UnitTestMain/TestMain.cpp:47:10
> #10 0x7fbbcac6aec4 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
>
>
>
> On Fri, Dec 18, 2015 at 2:54 PM, James Y Knight via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
>> Author: jyknight
>> Date: Fri Dec 18 16:54:37 2015
>> New Revision: 256054
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=256054&view=rev
>> Log:
>> Rewrite the TrailingObjects template to provide two new features:
>>
>> - Automatic alignment of the base type for the alignment requirements
>> of the trailing types.
>>
>> - Support for an arbitrary numbers of trailing types, instead of only
>> 1 or 2, by using a variadic template implementation.
>>
>> Upcoming commits to clang will take advantage of both of these features.
>>
>> Differential Revision: http://reviews.llvm.org/D12439
>>
>> Modified:
>> llvm/trunk/include/llvm/Support/TrailingObjects.h
>> llvm/trunk/unittests/Support/TrailingObjectsTest.cpp
>>
>> Modified: llvm/trunk/include/llvm/Support/TrailingObjects.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/TrailingObjects.h?rev=256054&r1=256053&r2=256054&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/Support/TrailingObjects.h (original)
>> +++ llvm/trunk/include/llvm/Support/TrailingObjects.h Fri Dec 18 16:54:37
>> 2015
>> @@ -59,6 +59,27 @@
>>
>> namespace llvm {
>>
>> +namespace trailing_objects_internal {
>> +/// Helper template to calculate the max alignment requirement for a set
>> of
>> +/// objects.
>> +template <typename First, typename... Rest> class AlignmentCalcHelper {
>> +private:
>> + enum {
>> + FirstAlignment = AlignOf<First>::Alignment,
>> + RestAlignment = AlignmentCalcHelper<Rest...>::Alignment,
>> + };
>> +
>> +public:
>> + enum {
>> + Alignment = FirstAlignment > RestAlignment ? FirstAlignment :
>> RestAlignment
>> + };
>> +};
>> +
>> +template <typename First> class AlignmentCalcHelper<First> {
>> +public:
>> + enum { Alignment = AlignOf<First>::Alignment };
>> +};
>> +
>> /// The base class for TrailingObjects* classes.
>> class TrailingObjectsBase {
>> protected:
>> @@ -70,64 +91,200 @@ protected:
>> template <typename T> struct OverloadToken {};
>> };
>>
>> -// Internally used to indicate that the user didn't supply this value,
>> -// so the explicit-specialization for fewer args will be used.
>> -class NoTrailingTypeArg {};
>> -
>> -// TODO: Consider using a single variadic implementation instead of
>> -// multiple copies of the TrailingObjects template? [but, variadic
>> -// template recursive implementations are annoying...]
>> -
>> -/// This is the two-type version of the TrailingObjects template; see
>> -/// file docstring for details.
>> -template <typename BaseTy, typename TrailingTy1,
>> - typename TrailingTy2 = NoTrailingTypeArg>
>> -class TrailingObjects : public TrailingObjectsBase {
>> -private:
>> +/// This helper template works-around MSVC 2013's lack of useful
>> +/// alignas() support. The argument to LLVM_ALIGNAS(), in MSVC, is
>> +/// required to be a literal integer. But, you *can* use template
>> +/// specialization to select between a bunch of different LLVM_ALIGNAS
>> +/// expressions...
>> +template <int Align>
>> +class TrailingObjectsAligner : public TrailingObjectsBase {};
>> +template <>
>> +class LLVM_ALIGNAS(1) TrailingObjectsAligner<1> : public
>> TrailingObjectsBase {};
>> +template <>
>> +class LLVM_ALIGNAS(2) TrailingObjectsAligner<2> : public
>> TrailingObjectsBase {};
>> +template <>
>> +class LLVM_ALIGNAS(4) TrailingObjectsAligner<4> : public
>> TrailingObjectsBase {};
>> +template <>
>> +class LLVM_ALIGNAS(8) TrailingObjectsAligner<8> : public
>> TrailingObjectsBase {};
>> +template <>
>> +class LLVM_ALIGNAS(16) TrailingObjectsAligner<16> : public
>> TrailingObjectsBase {
>> +};
>> +template <>
>> +class LLVM_ALIGNAS(32) TrailingObjectsAligner<32> : public
>> TrailingObjectsBase {
>> +};
>> +
>> +// Just a little helper for transforming a type pack into the same
>> +// number of a different type. e.g.:
>> +// ExtractSecondType<Foo..., int>::type
>> +template <typename Ty1, typename Ty2> struct ExtractSecondType {
>> + typedef Ty2 type;
>> +};
>> +
>> +// TrailingObjectsImpl is somewhat complicated, because it is a
>> +// recursively inheriting template, in order to handle the template
>> +// varargs. Each level of inheritance picks off a single trailing type
>> +// then recurses on the rest. The "Align", "BaseTy", and
>> +// "TopTrailingObj" arguments are passed through unchanged through the
>> +// recursion. "PrevTy" is, at each level, the type handled by the
>> +// level right above it.
>> +
>> +template <int Align, typename BaseTy, typename TopTrailingObj, typename
>> PrevTy,
>> + typename... MoreTys>
>> +struct TrailingObjectsImpl {
>> + // The main template definition is never used -- the two
>> + // specializations cover all possibilities.
>> +};
>> +
>> +template <int Align, typename BaseTy, typename TopTrailingObj, typename
>> PrevTy,
>> + typename NextTy, typename... MoreTys>
>> +struct TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy,
>> + MoreTys...>
>> + : public TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy,
>> + MoreTys...> {
>> +
>> + typedef TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy,
>> MoreTys...>
>> + ParentType;
>> +
>> + // Ensure the methods we inherit are not hidden.
>> + using ParentType::getTrailingObjectsImpl;
>> + using ParentType::additionalSizeToAllocImpl;
>> +
>> + static void verifyTrailingObjectsAssertions() {
>> + static_assert(llvm::AlignOf<PrevTy>::Alignment >=
>> + llvm::AlignOf<NextTy>::Alignment,
>> + "A trailing object requires more alignment than the
>> previous "
>> + "trailing object provides");
>> +
>> + ParentType::verifyTrailingObjectsAssertions();
>> + }
>> +
>> + // These two functions are helper functions for
>> + // TrailingObjects::getTrailingObjects. They recurse to the left --
>> + // the result for each type in the list of trailing types depends on
>> + // the result of calling the function on the type to the
>> + // left. However, the function for the type to the left is
>> + // implemented by a *subclass* of this class, so we invoke it via
>> + // the TopTrailingObj, which is, via the
>> + // curiously-recurring-template-pattern, the most-derived type in
>> + // this recursion, and thus, contains all the overloads.
>> + static const NextTy *
>> + getTrailingObjectsImpl(const BaseTy *Obj,
>> + TrailingObjectsBase::OverloadToken<NextTy>) {
>> + return reinterpret_cast<const NextTy *>(
>> + TopTrailingObj::getTrailingObjectsImpl(
>> + Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) +
>> + TopTrailingObj::callNumTrailingObjects(
>> + Obj, TrailingObjectsBase::OverloadToken<PrevTy>()));
>> + }
>> +
>> + static NextTy *
>> + getTrailingObjectsImpl(BaseTy *Obj,
>> + TrailingObjectsBase::OverloadToken<NextTy>) {
>> + return reinterpret_cast<NextTy *>(
>> + TopTrailingObj::getTrailingObjectsImpl(
>> + Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) +
>> + TopTrailingObj::callNumTrailingObjects(
>> + Obj, TrailingObjectsBase::OverloadToken<PrevTy>()));
>> + }
>> +
>> + // Helper function for TrailingObjects::additionalSizeToAlloc: this
>> + // function recurses to superclasses, each of which requires one
>> + // fewer size_t argument, and adds its own size.
>> + static LLVM_CONSTEXPR size_t additionalSizeToAllocImpl(
>> + size_t Count1,
>> + typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) {
>> + return sizeof(NextTy) * Count1 +
>> additionalSizeToAllocImpl(MoreCounts...);
>> + }
>> +};
>> +
>> +// The base case of the TrailingObjectsImpl inheritance recursion,
>> +// when there's no more trailing types.
>> +template <int Align, typename BaseTy, typename TopTrailingObj, typename
>> PrevTy>
>> +struct TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy>
>> + : public TrailingObjectsAligner<Align> {
>> + // This is a dummy method, only here so the "using" doesn't fail --
>> + // it will never be called, because this function recurses backwards
>> + // up the inheritance chain to subclasses.
>> + static void getTrailingObjectsImpl();
>> +
>> + static LLVM_CONSTEXPR size_t additionalSizeToAllocImpl() { return 0; }
>> +
>> + static void verifyTrailingObjectsAssertions() {}
>> +};
>> +
>> +} // end namespace trailing_objects_internal
>> +
>> +// Finally, the main type defined in this file, the one intended for
>> users...
>> +
>> +/// See the file comment for details on the usage of the
>> +/// TrailingObjects type.
>> +template <typename BaseTy, typename... TrailingTys>
>> +class TrailingObjects : private
>> trailing_objects_internal::TrailingObjectsImpl<
>> +
>> trailing_objects_internal::AlignmentCalcHelper<
>> + TrailingTys...>::Alignment,
>> + BaseTy, TrailingObjects<BaseTy,
>> TrailingTys...>,
>> + BaseTy, TrailingTys...> {
>> +
>> + template <int A, typename B, typename T, typename P, typename... M>
>> + friend struct trailing_objects_internal::TrailingObjectsImpl;
>> +
>> + template <typename... Tys> class Foo {};
>> +
>> + typedef trailing_objects_internal::TrailingObjectsImpl<
>> +
>> trailing_objects_internal::AlignmentCalcHelper<TrailingTys...>::Alignment,
>> + BaseTy, TrailingObjects<BaseTy, TrailingTys...>, BaseTy,
>> TrailingTys...>
>> + ParentType;
>> + using TrailingObjectsBase =
>> trailing_objects_internal::TrailingObjectsBase;
>> +
>> + using ParentType::getTrailingObjectsImpl;
>> +
>> // Contains static_assert statements for the alignment of the
>> // types. Must not be at class-level, because BaseTy isn't complete
>> // at class instantiation time, but will be by the time this
>> - // function is instantiated.
>> + // function is instantiated. Recurses through the superclasses.
>> static void verifyTrailingObjectsAssertions() {
>> - static_assert(llvm::AlignOf<BaseTy>::Alignment >=
>> - llvm::AlignOf<TrailingTy1>::Alignment,
>> - "TrailingTy1 requires more alignment than BaseTy
>> provides");
>> - static_assert(
>> - llvm::AlignOf<TrailingTy1>::Alignment >=
>> - llvm::AlignOf<TrailingTy2>::Alignment,
>> - "TrailingTy2 requires more alignment than TrailingTy1 provides");
>> -
>> #ifdef LLVM_IS_FINAL
>> static_assert(LLVM_IS_FINAL(BaseTy), "BaseTy must be final.");
>> #endif
>> + ParentType::verifyTrailingObjectsAssertions();
>> }
>>
>> - // The next four functions are internal helpers for getTrailingObjects.
>> - static const TrailingTy1 *getTrailingObjectsImpl(const BaseTy *Obj,
>> -
>> OverloadToken<TrailingTy1>) {
>> - return reinterpret_cast<const TrailingTy1 *>(Obj + 1);
>> + // These two methods are the base of the recursion for this method.
>> + static const BaseTy *
>> + getTrailingObjectsImpl(const BaseTy *Obj,
>> + TrailingObjectsBase::OverloadToken<BaseTy>) {
>> + return Obj;
>> }
>>
>> - static TrailingTy1 *getTrailingObjectsImpl(BaseTy *Obj,
>> - OverloadToken<TrailingTy1>)
>> {
>> - return reinterpret_cast<TrailingTy1 *>(Obj + 1);
>> + static BaseTy *
>> + getTrailingObjectsImpl(BaseTy *Obj,
>> + TrailingObjectsBase::OverloadToken<BaseTy>) {
>> + return Obj;
>> }
>>
>> - static const TrailingTy2 *getTrailingObjectsImpl(const BaseTy *Obj,
>> -
>> OverloadToken<TrailingTy2>) {
>> - return reinterpret_cast<const TrailingTy2 *>(
>> - getTrailingObjectsImpl(Obj, OverloadToken<TrailingTy1>()) +
>> - Obj->numTrailingObjects(OverloadToken<TrailingTy1>()));
>> + // callNumTrailingObjects simply calls numTrailingObjects on the
>> + // provided Obj -- except when the type being queried is BaseTy
>> + // itself. There is always only one of the base object, so that case
>> + // is handled here. (An additional benefit of indirecting through
>> + // this function is that consumers only say "friend
>> + // TrailingObjects", and thus, only this class itself can call the
>> + // numTrailingObjects function.)
>> + static size_t
>> + callNumTrailingObjects(const BaseTy *Obj,
>> + TrailingObjectsBase::OverloadToken<BaseTy>) {
>> + return 1;
>> }
>>
>> - static TrailingTy2 *getTrailingObjectsImpl(BaseTy *Obj,
>> - OverloadToken<TrailingTy2>)
>> {
>> - return reinterpret_cast<TrailingTy2 *>(
>> - getTrailingObjectsImpl(Obj, OverloadToken<TrailingTy1>()) +
>> - Obj->numTrailingObjects(OverloadToken<TrailingTy1>()));
>> + template <typename T>
>> + static size_t callNumTrailingObjects(const BaseTy *Obj,
>> +
>> TrailingObjectsBase::OverloadToken<T>) {
>> + return
>> Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken<T>());
>> }
>>
>> -protected:
>> +public:
>> + // make this (privately inherited) class public.
>> + using TrailingObjectsBase::OverloadToken;
>> +
>> /// Returns a pointer to the trailing object array of the given type
>> /// (which must be one of those specified in the class template). The
>> /// array may have zero or more elements in it.
>> @@ -135,8 +292,9 @@ protected:
>> verifyTrailingObjectsAssertions();
>> // Forwards to an impl function with overloads, since member
>> // function templates can't be specialized.
>> - return getTrailingObjectsImpl(static_cast<const BaseTy *>(this),
>> - OverloadToken<T>());
>> + return this->getTrailingObjectsImpl(
>> + static_cast<const BaseTy *>(this),
>> + TrailingObjectsBase::OverloadToken<T>());
>> }
>>
>> /// Returns a pointer to the trailing object array of the given type
>> @@ -146,8 +304,8 @@ protected:
>> verifyTrailingObjectsAssertions();
>> // Forwards to an impl function with overloads, since member
>> // function templates can't be specialized.
>> - return getTrailingObjectsImpl(static_cast<BaseTy *>(this),
>> - OverloadToken<T>());
>> + return this->getTrailingObjectsImpl(
>> + static_cast<BaseTy *>(this),
>> TrailingObjectsBase::OverloadToken<T>());
>> }
>>
>> /// Returns the size of the trailing data, if an object were
>> @@ -156,73 +314,25 @@ protected:
>> /// base object. The template arguments must be the same as those
>> /// used in the class; they are supplied here redundantly only so
>> /// that it's clear what the counts are counting in callers.
>> - template <typename Ty1, typename Ty2,
>> - typename std::enable_if<std::is_same<Ty1,
>> TrailingTy1>::value &&
>> - std::is_same<Ty2,
>> TrailingTy2>::value,
>> - int>::type = 0>
>> - static LLVM_CONSTEXPR size_t additionalSizeToAlloc(size_t Count1,
>> size_t Count2) {
>> - return sizeof(TrailingTy1) * Count1 + sizeof(TrailingTy2) * Count2;
>> + template <typename... Tys>
>> + static LLVM_CONSTEXPR typename std::enable_if<
>> + std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value,
>> size_t>::type
>> + additionalSizeToAlloc(
>> + typename trailing_objects_internal::ExtractSecondType<
>> + TrailingTys, size_t>::type... Counts) {
>> + return ParentType::additionalSizeToAllocImpl(Counts...);
>> }
>>
>> /// Returns the total size of an object if it were allocated with the
>> /// given trailing object counts. This is the same as
>> /// additionalSizeToAlloc, except it *does* include the size of the
>> base
>> /// object.
>> - template <typename Ty1, typename Ty2>
>> - static LLVM_CONSTEXPR size_t totalSizeToAlloc(size_t Count1, size_t
>> Count2) {
>> - return sizeof(BaseTy) + additionalSizeToAlloc<Ty1, Ty2>(Count1,
>> Count2);
>> - }
>> -};
>> -
>> -/// This is the one-type version of the TrailingObjects template. See
>> -/// the two-type version for more documentation.
>> -template <typename BaseTy, typename TrailingTy1>
>> -class TrailingObjects<BaseTy, TrailingTy1, NoTrailingTypeArg>
>> - : public TrailingObjectsBase {
>> -private:
>> - static void verifyTrailingObjectsAssertions() {
>> - static_assert(llvm::AlignOf<BaseTy>::Alignment >=
>> - llvm::AlignOf<TrailingTy1>::Alignment,
>> - "TrailingTy1 requires more alignment than BaseTy
>> provides");
>> -
>> -#ifdef LLVM_IS_FINAL
>> - static_assert(LLVM_IS_FINAL(BaseTy), "BaseTy must be final.");
>> -#endif
>> - }
>> -
>> - static const TrailingTy1 *getTrailingObjectsImpl(const BaseTy *Obj,
>> -
>> OverloadToken<TrailingTy1>) {
>> - return reinterpret_cast<const TrailingTy1 *>(Obj + 1);
>> - }
>> -
>> - static TrailingTy1 *getTrailingObjectsImpl(BaseTy *Obj,
>> - OverloadToken<TrailingTy1>)
>> {
>> - return reinterpret_cast<TrailingTy1 *>(Obj + 1);
>> - }
>> -
>> -protected:
>> - template <typename T> const T *getTrailingObjects() const {
>> - verifyTrailingObjectsAssertions();
>> - return getTrailingObjectsImpl(static_cast<const BaseTy *>(this),
>> - OverloadToken<T>());
>> - }
>> -
>> - template <typename T> T *getTrailingObjects() {
>> - verifyTrailingObjectsAssertions();
>> - return getTrailingObjectsImpl(static_cast<BaseTy *>(this),
>> - OverloadToken<T>());
>> - }
>> -
>> - template <typename Ty1,
>> - typename std::enable_if<std::is_same<Ty1,
>> TrailingTy1>::value,
>> - int>::type = 0>
>> - static LLVM_CONSTEXPR size_t additionalSizeToAlloc(size_t Count1) {
>> - return sizeof(TrailingTy1) * Count1;
>> - }
>> -
>> - template <typename Ty1>
>> - static LLVM_CONSTEXPR size_t totalSizeToAlloc(size_t Count1) {
>> - return sizeof(BaseTy) + additionalSizeToAlloc<Ty1>(Count1);
>> + template <typename... Tys>
>> + static LLVM_CONSTEXPR typename std::enable_if<
>> + std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value,
>> size_t>::type
>> + totalSizeToAlloc(typename
>> trailing_objects_internal::ExtractSecondType<
>> + TrailingTys, size_t>::type... Counts) {
>> + return sizeof(BaseTy) +
>> ParentType::additionalSizeToAllocImpl(Counts...);
>> }
>> };
>>
>>
>> Modified: llvm/trunk/unittests/Support/TrailingObjectsTest.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/TrailingObjectsTest.cpp?rev=256054&r1=256053&r2=256054&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/unittests/Support/TrailingObjectsTest.cpp (original)
>> +++ llvm/trunk/unittests/Support/TrailingObjectsTest.cpp Fri Dec 18
>> 16:54:37 2015
>> @@ -45,9 +45,10 @@ public:
>> using TrailingObjects::getTrailingObjects;
>> };
>>
>> -// Here, there are two singular optional object types appended.
>> -// Note that it fails to compile without the alignment spec.
>> -class LLVM_ALIGNAS(8) Class2 final : protected TrailingObjects<Class2,
>> double, short> {
>> +// Here, there are two singular optional object types appended. Note
>> +// that the alignment of Class2 is automatically increased to account
>> +// for the alignment requirements of the trailing objects.
>> +class Class2 final : protected TrailingObjects<Class2, double, short> {
>> friend TrailingObjects;
>>
>> bool HasShort, HasDouble;
>> @@ -117,7 +118,9 @@ TEST(TrailingObjects, TwoArg) {
>> Class2 *C1 = Class2::create(4);
>> Class2 *C2 = Class2::create(0, 4.2);
>>
>> - EXPECT_EQ(sizeof(Class2), 8u); // due to alignment
>> + EXPECT_EQ(sizeof(Class2), llvm::RoundUpToAlignment(sizeof(bool) * 2,
>> +
>> llvm::alignOf<double>()));
>> + EXPECT_EQ(llvm::alignOf<Class2>(), llvm::alignOf<double>());
>>
>> EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(1, 0)),
>> sizeof(double));
>> @@ -144,4 +147,31 @@ TEST(TrailingObjects, TwoArg) {
>> delete C1;
>> delete C2;
>> }
>> +
>> +// This test class is not trying to be a usage demo, just asserting
>> +// that three args does actually work too (it's the same code as
>> +// handles the second arg, so it's basically covered by the above, but
>> +// just in case..)
>> +class Class3 final : public TrailingObjects<Class3, double, short, bool>
>> {
>> + friend TrailingObjects;
>> +
>> + size_t numTrailingObjects(OverloadToken<double>) const { return 1; }
>> + size_t numTrailingObjects(OverloadToken<short>) const { return 1; }
>> +};
>> +
>> +TEST(TrailingObjects, ThreeArg) {
>> + EXPECT_EQ((Class3::additionalSizeToAlloc<double, short, bool>(1, 1,
>> 3)),
>> + sizeof(double) + sizeof(short) + 3 * sizeof(bool));
>> + EXPECT_EQ(sizeof(Class3),
>> + llvm::RoundUpToAlignment(1, llvm::alignOf<double>()));
>> + Class3 *C = reinterpret_cast<Class3 *>(::operator new(1000));
>> + EXPECT_EQ(C->getTrailingObjects<double>(), reinterpret_cast<double
>> *>(C + 1));
>> + EXPECT_EQ(C->getTrailingObjects<short>(),
>> + reinterpret_cast<short *>(reinterpret_cast<double *>(C + 1)
>> + 1));
>> + EXPECT_EQ(
>> + C->getTrailingObjects<bool>(),
>> + reinterpret_cast<bool *>(
>> + reinterpret_cast<short *>(reinterpret_cast<double *>(C + 1) +
>> 1) +
>> + 1));
>> +}
>> }
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20151221/0630c644/attachment.html>
More information about the llvm-commits
mailing list