diff options
| -rw-r--r-- | llvm/include/llvm/Support/AlignOf.h | 37 | ||||
| -rw-r--r-- | llvm/unittests/Support/AlignOfTest.cpp | 20 |
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) { |

