summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2015-12-29 09:52:41 +0000
committerChandler Carruth <chandlerc@gmail.com>2015-12-29 09:52:41 +0000
commit8db8e8b86f486baffb22445b5cb3f24561059585 (patch)
tree6f970e756996ee018bbec09cb0f6e248f78461da
parent5bd31b37ca5226ac42eb52e79745e9f4d651ec57 (diff)
downloadbcm5719-llvm-8db8e8b86f486baffb22445b5cb3f24561059585.tar.gz
bcm5719-llvm-8db8e8b86f486baffb22445b5cb3f24561059585.zip
[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. llvm-svn: 256553
-rw-r--r--llvm/include/llvm/Support/AlignOf.h37
-rw-r--r--llvm/unittests/Support/AlignOfTest.cpp20
2 files changed, 52 insertions, 5 deletions
diff --git a/llvm/include/llvm/Support/AlignOf.h b/llvm/include/llvm/Support/AlignOf.h
index 07da02d063c..5268c8d1698 100644
--- a/llvm/include/llvm/Support/AlignOf.h
+++ b/llvm/include/llvm/Support/AlignOf.h
@@ -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 };
diff --git a/llvm/unittests/Support/AlignOfTest.cpp b/llvm/unittests/Support/AlignOfTest.cpp
index e0859fc747f..be208f7d28e 100644
--- a/llvm/unittests/Support/AlignOfTest.cpp
+++ b/llvm/unittests/Support/AlignOfTest.cpp
@@ -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, BasicAlignmentInvariants) {
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) {
OpenPOWER on IntegriCloud