[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