llvm.org GIT mirror llvm / df1cf99
[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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@256553 91177308-0d34-0410-b5e6-96231b3b80d8 Chandler Carruth 3 years ago
2 changed file(s) with 52 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
1616
1717 #include "llvm/Support/Compiler.h"
1818 #include
19 #include
1920
2021 namespace llvm {
21 template
22
23 namespace detail {
24
25 // For everything other than an abstract class we can calulate alignment by
26 // building a class with a single character and a member of the given type.
27 template ::value>
2228 struct AlignmentCalcImpl {
2329 char x;
2430 #if defined(_MSC_VER)
3339 private:
3440 AlignmentCalcImpl() {} // Never instantiate.
3541 };
42
43 // Abstract base class helper, this will have the minimal alignment and size
44 // for any abstract class. We don't even define its destructor because this
45 // type should never be used in a way that requires it.
46 struct AlignmentCalcImplBase {
47 virtual ~AlignmentCalcImplBase() = 0;
48 };
49
50 // When we have an abstract class type, specialize the alignment computation
51 // engine to create another abstract class that derives from both an empty
52 // abstract base class and the provided type. This has the same effect as the
53 // above except that it handles the fact that we can't actually create a member
54 // of type T.
55 template
56 struct AlignmentCalcImpl : AlignmentCalcImplBase, T {
57 virtual ~AlignmentCalcImpl() = 0;
58 };
59
60 } // End detail namespace.
3661
3762 /// AlignOf - A templated class that contains an enum value representing
3863 /// the alignment of the template argument. For example,
4974 // llvm::AlignOf::' [-Wenum-compare]
5075 // by using constexpr instead of enum.
5176 // (except on MSVC, since it doesn't support constexpr yet).
52 static constexpr unsigned Alignment =
53 static_cast(sizeof(AlignmentCalcImpl) - sizeof(T));
77 static constexpr unsigned Alignment = static_cast(
78 sizeof(detail::AlignmentCalcImpl) - sizeof(T));
5479 #else
55 enum { Alignment =
56 static_cast(sizeof(AlignmentCalcImpl) - sizeof(T)) };
80 enum {
81 Alignment = static_cast(sizeof(detail::AlignmentCalcImpl) -
82 sizeof(T))
83 };
5784 #endif
5885 enum { Alignment_GreaterEqual_2Bytes = Alignment >= 2 ? 1 : 0 };
5986 enum { Alignment_GreaterEqual_4Bytes = Alignment >= 4 ? 1 : 0 };
8787 V6::~V6() {}
8888 V7::~V7() {}
8989 V8::~V8() {}
90
91 struct Abstract1 {
92 virtual ~Abstract1() {}
93 virtual void method() = 0;
94
95 char c;
96 };
97
98 struct Abstract2 : Abstract1 {
99 virtual ~Abstract2() {}
100 double d;
101 };
102
103 struct Final final : Abstract2 {
104 void method() override {}
105 };
90106
91107 // Ensure alignment is a compile-time constant.
92108 char LLVM_ATTRIBUTE_UNUSED test_arr1
173189 EXPECT_LE(alignOf(), alignOf());
174190 EXPECT_LE(alignOf(), alignOf());
175191 EXPECT_LE(alignOf(), alignOf());
192
193 EXPECT_LE(alignOf(), alignOf());
194 EXPECT_LE(alignOf(), alignOf());
195 EXPECT_LE(alignOf(), alignOf());
176196 }
177197
178198 TEST(AlignOfTest, BasicAlignedArray) {