[llvm] r256553 - [ADT] Teach alignment helpers to work correctly for abstract classes.

Chandler Carruth via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 29 01:52:41 PST 2015


Author: chandlerc
Date: Tue Dec 29 03:52:41 2015
New Revision: 256553

URL: http://llvm.org/viewvc/llvm-project?rev=256553&view=rev
Log:
[ADT] Teach alignment helpers to work correctly for abstract classes.
This is necessary to use them as part of pointer traits and is generally
useful. I've added unit test coverage to isolate and ensure this works
correctly.

I'll watch the build bots to try to see if any compilers can't tolerate
this bit of magic (and much credit goes to Richard Smith for coming up
with this magical production!) but give a shout if you see issues.

Modified:
    llvm/trunk/include/llvm/Support/AlignOf.h
    llvm/trunk/unittests/Support/AlignOfTest.cpp

Modified: llvm/trunk/include/llvm/Support/AlignOf.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/AlignOf.h?rev=256553&r1=256552&r2=256553&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/AlignOf.h (original)
+++ llvm/trunk/include/llvm/Support/AlignOf.h Tue Dec 29 03:52:41 2015
@@ -17,9 +17,15 @@
 
 #include "llvm/Support/Compiler.h"
 #include <cstddef>
+#include <type_traits>
 
 namespace llvm {
-template <typename T>
+
+namespace detail {
+
+// For everything other than an abstract class we can calulate alignment by
+// building a class with a single character and a member of the given type.
+template <typename T, bool = std::is_abstract<T>::value>
 struct AlignmentCalcImpl {
   char x;
 #if defined(_MSC_VER)
@@ -35,6 +41,25 @@ private:
   AlignmentCalcImpl() {} // Never instantiate.
 };
 
+// Abstract base class helper, this will have the minimal alignment and size
+// for any abstract class. We don't even define its destructor because this
+// type should never be used in a way that requires it.
+struct AlignmentCalcImplBase {
+  virtual ~AlignmentCalcImplBase() = 0;
+};
+
+// When we have an abstract class type, specialize the alignment computation
+// engine to create another abstract class that derives from both an empty
+// abstract base class and the provided type. This has the same effect as the
+// above except that it handles the fact that we can't actually create a member
+// of type T.
+template <typename T>
+struct AlignmentCalcImpl<T, true> : AlignmentCalcImplBase, T {
+  virtual ~AlignmentCalcImpl() = 0;
+};
+
+} // End detail namespace.
+
 /// AlignOf - A templated class that contains an enum value representing
 ///  the alignment of the template argument.  For example,
 ///  AlignOf<int>::Alignment represents the alignment of type "int".  The
@@ -50,11 +75,13 @@ struct AlignOf {
   //   llvm::AlignOf<Y>::<anonymous>' [-Wenum-compare]
   // by using constexpr instead of enum.
   // (except on MSVC, since it doesn't support constexpr yet).
-  static constexpr unsigned Alignment =
-      static_cast<unsigned int>(sizeof(AlignmentCalcImpl<T>) - sizeof(T));
+  static constexpr unsigned Alignment = static_cast<unsigned int>(
+      sizeof(detail::AlignmentCalcImpl<T>) - sizeof(T));
 #else
-  enum { Alignment =
-         static_cast<unsigned int>(sizeof(AlignmentCalcImpl<T>) - sizeof(T)) };
+  enum {
+    Alignment = static_cast<unsigned int>(sizeof(detail::AlignmentCalcImpl<T>) -
+                                          sizeof(T))
+  };
 #endif
   enum { Alignment_GreaterEqual_2Bytes = Alignment >= 2 ? 1 : 0 };
   enum { Alignment_GreaterEqual_4Bytes = Alignment >= 4 ? 1 : 0 };

Modified: llvm/trunk/unittests/Support/AlignOfTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/AlignOfTest.cpp?rev=256553&r1=256552&r2=256553&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/AlignOfTest.cpp (original)
+++ llvm/trunk/unittests/Support/AlignOfTest.cpp Tue Dec 29 03:52:41 2015
@@ -89,6 +89,22 @@ V6::~V6() {}
 V7::~V7() {}
 V8::~V8() {}
 
+struct Abstract1 {
+  virtual ~Abstract1() {}
+  virtual void method() = 0;
+
+  char c;
+};
+
+struct Abstract2 : Abstract1 {
+  virtual ~Abstract2() {}
+  double d;
+};
+
+struct Final final : Abstract2 {
+  void method() override {}
+};
+
 // Ensure alignment is a compile-time constant.
 char LLVM_ATTRIBUTE_UNUSED test_arr1
   [AlignOf<char>::Alignment > 0]
@@ -174,6 +190,10 @@ TEST(AlignOfTest, BasicAlignmentInvarian
   EXPECT_LE(alignOf<V1>(),     alignOf<V6>());
   EXPECT_LE(alignOf<V1>(),     alignOf<V7>());
   EXPECT_LE(alignOf<V1>(),     alignOf<V8>());
+
+  EXPECT_LE(alignOf<char>(), alignOf<Abstract1>());
+  EXPECT_LE(alignOf<double>(), alignOf<Abstract2>());
+  EXPECT_LE(alignOf<Abstract2>(), alignOf<Final>());
 }
 
 TEST(AlignOfTest, BasicAlignedArray) {




More information about the llvm-commits mailing list