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