[llvm] r256054 - Rewrite the TrailingObjects template to provide two new features:
James Y Knight via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 21 11:38:51 PST 2015
Apologies for the oversight -- looks fine to me.
On Mon, Dec 21, 2015 at 2:13 PM, Kostya Serebryany <kcc at google.com> wrote:
> 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/136cc67b/attachment.html>
More information about the llvm-commits
mailing list