File: | clang/lib/AST/ASTConcept.cpp |
Warning: | line 29, column 7 Storage provided to placement new is only 0 bytes, whereas the allocated type requires 16 bytes |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===--- ASTConcept.cpp - Concepts Related AST Data Structures --*- C++ -*-===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | /// | |||
9 | /// \file | |||
10 | /// \brief This file defines AST data structures related to concepts. | |||
11 | /// | |||
12 | //===----------------------------------------------------------------------===// | |||
13 | ||||
14 | #include "clang/AST/ASTConcept.h" | |||
15 | #include "clang/AST/ASTContext.h" | |||
16 | #include "clang/AST/Decl.h" | |||
17 | #include "clang/AST/TemplateBase.h" | |||
18 | #include "llvm/ADT/ArrayRef.h" | |||
19 | #include "llvm/ADT/FoldingSet.h" | |||
20 | using namespace clang; | |||
21 | ||||
22 | ASTConstraintSatisfaction::ASTConstraintSatisfaction(const ASTContext &C, | |||
23 | const ConstraintSatisfaction &Satisfaction): | |||
24 | NumRecords{Satisfaction.Details.size()}, | |||
25 | IsSatisfied{Satisfaction.IsSatisfied} { | |||
26 | for (unsigned I = 0; I < NumRecords; ++I) { | |||
27 | auto &Detail = Satisfaction.Details[I]; | |||
28 | if (Detail.second.is<Expr *>()) | |||
29 | new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I) | |||
| ||||
30 | UnsatisfiedConstraintRecord{Detail.first, | |||
31 | UnsatisfiedConstraintRecord::second_type( | |||
32 | Detail.second.get<Expr *>())}; | |||
33 | else { | |||
34 | auto &SubstitutionDiagnostic = | |||
35 | *Detail.second.get<std::pair<SourceLocation, StringRef> *>(); | |||
36 | unsigned MessageSize = SubstitutionDiagnostic.second.size(); | |||
37 | char *Mem = new (C) char[MessageSize]; | |||
38 | memcpy(Mem, SubstitutionDiagnostic.second.data(), MessageSize); | |||
39 | auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>( | |||
40 | SubstitutionDiagnostic.first, StringRef(Mem, MessageSize)); | |||
41 | new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I) | |||
42 | UnsatisfiedConstraintRecord{Detail.first, | |||
43 | UnsatisfiedConstraintRecord::second_type( | |||
44 | NewSubstDiag)}; | |||
45 | } | |||
46 | } | |||
47 | } | |||
48 | ||||
49 | ||||
50 | ASTConstraintSatisfaction * | |||
51 | ASTConstraintSatisfaction::Create(const ASTContext &C, | |||
52 | const ConstraintSatisfaction &Satisfaction) { | |||
53 | std::size_t size = | |||
54 | totalSizeToAlloc<UnsatisfiedConstraintRecord>( | |||
55 | Satisfaction.Details.size()); | |||
56 | void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction)); | |||
57 | return new (Mem) ASTConstraintSatisfaction(C, Satisfaction); | |||
| ||||
58 | } | |||
59 | ||||
60 | void ConstraintSatisfaction::Profile( | |||
61 | llvm::FoldingSetNodeID &ID, const ASTContext &C, | |||
62 | const NamedDecl *ConstraintOwner, ArrayRef<TemplateArgument> TemplateArgs) { | |||
63 | ID.AddPointer(ConstraintOwner); | |||
64 | ID.AddInteger(TemplateArgs.size()); | |||
65 | for (auto &Arg : TemplateArgs) | |||
66 | Arg.Profile(ID, C); | |||
67 | } |
1 | //===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file defines the PointerUnion class, which is a discriminated union of |
10 | // pointer types. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_ADT_POINTERUNION_H |
15 | #define LLVM_ADT_POINTERUNION_H |
16 | |
17 | #include "llvm/ADT/DenseMapInfo.h" |
18 | #include "llvm/ADT/PointerIntPair.h" |
19 | #include "llvm/Support/PointerLikeTypeTraits.h" |
20 | #include <cassert> |
21 | #include <cstddef> |
22 | #include <cstdint> |
23 | |
24 | namespace llvm { |
25 | |
26 | namespace pointer_union_detail { |
27 | /// Determine the number of bits required to store integers with values < n. |
28 | /// This is ceil(log2(n)). |
29 | constexpr int bitsRequired(unsigned n) { |
30 | return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0; |
31 | } |
32 | |
33 | template <typename... Ts> constexpr int lowBitsAvailable() { |
34 | return std::min<int>({PointerLikeTypeTraits<Ts>::NumLowBitsAvailable...}); |
35 | } |
36 | |
37 | /// Find the index of a type in a list of types. TypeIndex<T, Us...>::Index |
38 | /// is the index of T in Us, or sizeof...(Us) if T does not appear in the |
39 | /// list. |
40 | template <typename T, typename ...Us> struct TypeIndex; |
41 | template <typename T, typename ...Us> struct TypeIndex<T, T, Us...> { |
42 | static constexpr int Index = 0; |
43 | }; |
44 | template <typename T, typename U, typename... Us> |
45 | struct TypeIndex<T, U, Us...> { |
46 | static constexpr int Index = 1 + TypeIndex<T, Us...>::Index; |
47 | }; |
48 | template <typename T> struct TypeIndex<T> { |
49 | static constexpr int Index = 0; |
50 | }; |
51 | |
52 | /// Find the first type in a list of types. |
53 | template <typename T, typename...> struct GetFirstType { |
54 | using type = T; |
55 | }; |
56 | |
57 | /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion |
58 | /// for the template arguments. |
59 | template <typename ...PTs> class PointerUnionUIntTraits { |
60 | public: |
61 | static inline void *getAsVoidPointer(void *P) { return P; } |
62 | static inline void *getFromVoidPointer(void *P) { return P; } |
63 | static constexpr int NumLowBitsAvailable = lowBitsAvailable<PTs...>(); |
64 | }; |
65 | |
66 | template <typename Derived, typename ValTy, int I, typename ...Types> |
67 | class PointerUnionMembers; |
68 | |
69 | template <typename Derived, typename ValTy, int I> |
70 | class PointerUnionMembers<Derived, ValTy, I> { |
71 | protected: |
72 | ValTy Val; |
73 | PointerUnionMembers() = default; |
74 | PointerUnionMembers(ValTy Val) : Val(Val) {} |
75 | |
76 | friend struct PointerLikeTypeTraits<Derived>; |
77 | }; |
78 | |
79 | template <typename Derived, typename ValTy, int I, typename Type, |
80 | typename ...Types> |
81 | class PointerUnionMembers<Derived, ValTy, I, Type, Types...> |
82 | : public PointerUnionMembers<Derived, ValTy, I + 1, Types...> { |
83 | using Base = PointerUnionMembers<Derived, ValTy, I + 1, Types...>; |
84 | public: |
85 | using Base::Base; |
86 | PointerUnionMembers() = default; |
87 | PointerUnionMembers(Type V) |
88 | : Base(ValTy(const_cast<void *>( |
89 | PointerLikeTypeTraits<Type>::getAsVoidPointer(V)), |
90 | I)) {} |
91 | |
92 | using Base::operator=; |
93 | Derived &operator=(Type V) { |
94 | this->Val = ValTy( |
95 | const_cast<void *>(PointerLikeTypeTraits<Type>::getAsVoidPointer(V)), |
96 | I); |
97 | return static_cast<Derived &>(*this); |
98 | }; |
99 | }; |
100 | } |
101 | |
102 | /// A discriminated union of two or more pointer types, with the discriminator |
103 | /// in the low bit of the pointer. |
104 | /// |
105 | /// This implementation is extremely efficient in space due to leveraging the |
106 | /// low bits of the pointer, while exposing a natural and type-safe API. |
107 | /// |
108 | /// Common use patterns would be something like this: |
109 | /// PointerUnion<int*, float*> P; |
110 | /// P = (int*)0; |
111 | /// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0" |
112 | /// X = P.get<int*>(); // ok. |
113 | /// Y = P.get<float*>(); // runtime assertion failure. |
114 | /// Z = P.get<double*>(); // compile time failure. |
115 | /// P = (float*)0; |
116 | /// Y = P.get<float*>(); // ok. |
117 | /// X = P.get<int*>(); // runtime assertion failure. |
118 | template <typename... PTs> |
119 | class PointerUnion |
120 | : public pointer_union_detail::PointerUnionMembers< |
121 | PointerUnion<PTs...>, |
122 | PointerIntPair< |
123 | void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int, |
124 | pointer_union_detail::PointerUnionUIntTraits<PTs...>>, |
125 | 0, PTs...> { |
126 | // The first type is special because we want to directly cast a pointer to a |
127 | // default-initialized union to a pointer to the first type. But we don't |
128 | // want PointerUnion to be a 'template <typename First, typename ...Rest>' |
129 | // because it's much more convenient to have a name for the whole pack. So |
130 | // split off the first type here. |
131 | using First = typename pointer_union_detail::GetFirstType<PTs...>::type; |
132 | using Base = typename PointerUnion::PointerUnionMembers; |
133 | |
134 | public: |
135 | PointerUnion() = default; |
136 | |
137 | PointerUnion(std::nullptr_t) : PointerUnion() {} |
138 | using Base::Base; |
139 | |
140 | /// Test if the pointer held in the union is null, regardless of |
141 | /// which type it is. |
142 | bool isNull() const { return !this->Val.getPointer(); } |
143 | |
144 | explicit operator bool() const { return !isNull(); } |
145 | |
146 | /// Test if the Union currently holds the type matching T. |
147 | template <typename T> bool is() const { |
148 | constexpr int Index = pointer_union_detail::TypeIndex<T, PTs...>::Index; |
149 | static_assert(Index < sizeof...(PTs), |
150 | "PointerUnion::is<T> given type not in the union"); |
151 | return this->Val.getInt() == Index; |
152 | } |
153 | |
154 | /// Returns the value of the specified pointer type. |
155 | /// |
156 | /// If the specified pointer type is incorrect, assert. |
157 | template <typename T> T get() const { |
158 | assert(is<T>() && "Invalid accessor called")(static_cast <bool> (is<T>() && "Invalid accessor called" ) ? void (0) : __assert_fail ("is<T>() && \"Invalid accessor called\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/PointerUnion.h" , 158, __extension__ __PRETTY_FUNCTION__)); |
159 | return PointerLikeTypeTraits<T>::getFromVoidPointer(this->Val.getPointer()); |
160 | } |
161 | |
162 | /// Returns the current pointer if it is of the specified pointer type, |
163 | /// otherwise returns null. |
164 | template <typename T> T dyn_cast() const { |
165 | if (is<T>()) |
166 | return get<T>(); |
167 | return T(); |
168 | } |
169 | |
170 | /// If the union is set to the first pointer type get an address pointing to |
171 | /// it. |
172 | First const *getAddrOfPtr1() const { |
173 | return const_cast<PointerUnion *>(this)->getAddrOfPtr1(); |
174 | } |
175 | |
176 | /// If the union is set to the first pointer type get an address pointing to |
177 | /// it. |
178 | First *getAddrOfPtr1() { |
179 | assert(is<First>() && "Val is not the first pointer")(static_cast <bool> (is<First>() && "Val is not the first pointer" ) ? void (0) : __assert_fail ("is<First>() && \"Val is not the first pointer\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/PointerUnion.h" , 179, __extension__ __PRETTY_FUNCTION__)); |
180 | assert((static_cast <bool> (PointerLikeTypeTraits<First> ::getAsVoidPointer(get<First>()) == this->Val.getPointer () && "Can't get the address because PointerLikeTypeTraits changes the ptr" ) ? void (0) : __assert_fail ("PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) == this->Val.getPointer() && \"Can't get the address because PointerLikeTypeTraits changes the ptr\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/PointerUnion.h" , 183, __extension__ __PRETTY_FUNCTION__)) |
181 | PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) ==(static_cast <bool> (PointerLikeTypeTraits<First> ::getAsVoidPointer(get<First>()) == this->Val.getPointer () && "Can't get the address because PointerLikeTypeTraits changes the ptr" ) ? void (0) : __assert_fail ("PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) == this->Val.getPointer() && \"Can't get the address because PointerLikeTypeTraits changes the ptr\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/PointerUnion.h" , 183, __extension__ __PRETTY_FUNCTION__)) |
182 | this->Val.getPointer() &&(static_cast <bool> (PointerLikeTypeTraits<First> ::getAsVoidPointer(get<First>()) == this->Val.getPointer () && "Can't get the address because PointerLikeTypeTraits changes the ptr" ) ? void (0) : __assert_fail ("PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) == this->Val.getPointer() && \"Can't get the address because PointerLikeTypeTraits changes the ptr\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/PointerUnion.h" , 183, __extension__ __PRETTY_FUNCTION__)) |
183 | "Can't get the address because PointerLikeTypeTraits changes the ptr")(static_cast <bool> (PointerLikeTypeTraits<First> ::getAsVoidPointer(get<First>()) == this->Val.getPointer () && "Can't get the address because PointerLikeTypeTraits changes the ptr" ) ? void (0) : __assert_fail ("PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) == this->Val.getPointer() && \"Can't get the address because PointerLikeTypeTraits changes the ptr\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/PointerUnion.h" , 183, __extension__ __PRETTY_FUNCTION__)); |
184 | return const_cast<First *>( |
185 | reinterpret_cast<const First *>(this->Val.getAddrOfPointer())); |
186 | } |
187 | |
188 | /// Assignment from nullptr which just clears the union. |
189 | const PointerUnion &operator=(std::nullptr_t) { |
190 | this->Val.initWithPointer(nullptr); |
191 | return *this; |
192 | } |
193 | |
194 | /// Assignment from elements of the union. |
195 | using Base::operator=; |
196 | |
197 | void *getOpaqueValue() const { return this->Val.getOpaqueValue(); } |
198 | static inline PointerUnion getFromOpaqueValue(void *VP) { |
199 | PointerUnion V; |
200 | V.Val = decltype(V.Val)::getFromOpaqueValue(VP); |
201 | return V; |
202 | } |
203 | }; |
204 | |
205 | template <typename ...PTs> |
206 | bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) { |
207 | return lhs.getOpaqueValue() == rhs.getOpaqueValue(); |
208 | } |
209 | |
210 | template <typename ...PTs> |
211 | bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) { |
212 | return lhs.getOpaqueValue() != rhs.getOpaqueValue(); |
213 | } |
214 | |
215 | template <typename ...PTs> |
216 | bool operator<(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) { |
217 | return lhs.getOpaqueValue() < rhs.getOpaqueValue(); |
218 | } |
219 | |
220 | // Teach SmallPtrSet that PointerUnion is "basically a pointer", that has |
221 | // # low bits available = min(PT1bits,PT2bits)-1. |
222 | template <typename ...PTs> |
223 | struct PointerLikeTypeTraits<PointerUnion<PTs...>> { |
224 | static inline void *getAsVoidPointer(const PointerUnion<PTs...> &P) { |
225 | return P.getOpaqueValue(); |
226 | } |
227 | |
228 | static inline PointerUnion<PTs...> getFromVoidPointer(void *P) { |
229 | return PointerUnion<PTs...>::getFromOpaqueValue(P); |
230 | } |
231 | |
232 | // The number of bits available are the min of the pointer types minus the |
233 | // bits needed for the discriminator. |
234 | static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits<decltype( |
235 | PointerUnion<PTs...>::Val)>::NumLowBitsAvailable; |
236 | }; |
237 | |
238 | // Teach DenseMap how to use PointerUnions as keys. |
239 | template <typename ...PTs> struct DenseMapInfo<PointerUnion<PTs...>> { |
240 | using Union = PointerUnion<PTs...>; |
241 | using FirstInfo = |
242 | DenseMapInfo<typename pointer_union_detail::GetFirstType<PTs...>::type>; |
243 | |
244 | static inline Union getEmptyKey() { return Union(FirstInfo::getEmptyKey()); } |
245 | |
246 | static inline Union getTombstoneKey() { |
247 | return Union(FirstInfo::getTombstoneKey()); |
248 | } |
249 | |
250 | static unsigned getHashValue(const Union &UnionVal) { |
251 | intptr_t key = (intptr_t)UnionVal.getOpaqueValue(); |
252 | return DenseMapInfo<intptr_t>::getHashValue(key); |
253 | } |
254 | |
255 | static bool isEqual(const Union &LHS, const Union &RHS) { |
256 | return LHS == RHS; |
257 | } |
258 | }; |
259 | |
260 | } // end namespace llvm |
261 | |
262 | #endif // LLVM_ADT_POINTERUNION_H |
1 | //===--- TrailingObjects.h - Variable-length classes ------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | /// |
9 | /// \file |
10 | /// This header defines support for implementing classes that have |
11 | /// some trailing object (or arrays of objects) appended to them. The |
12 | /// main purpose is to make it obvious where this idiom is being used, |
13 | /// and to make the usage more idiomatic and more difficult to get |
14 | /// wrong. |
15 | /// |
16 | /// The TrailingObject template abstracts away the reinterpret_cast, |
17 | /// pointer arithmetic, and size calculations used for the allocation |
18 | /// and access of appended arrays of objects, and takes care that they |
19 | /// are all allocated at their required alignment. Additionally, it |
20 | /// ensures that the base type is final -- deriving from a class that |
21 | /// expects data appended immediately after it is typically not safe. |
22 | /// |
23 | /// Users are expected to derive from this template, and provide |
24 | /// numTrailingObjects implementations for each trailing type except |
25 | /// the last, e.g. like this sample: |
26 | /// |
27 | /// \code |
28 | /// class VarLengthObj : private TrailingObjects<VarLengthObj, int, double> { |
29 | /// friend TrailingObjects; |
30 | /// |
31 | /// unsigned NumInts, NumDoubles; |
32 | /// size_t numTrailingObjects(OverloadToken<int>) const { return NumInts; } |
33 | /// }; |
34 | /// \endcode |
35 | /// |
36 | /// You can access the appended arrays via 'getTrailingObjects', and |
37 | /// determine the size needed for allocation via |
38 | /// 'additionalSizeToAlloc' and 'totalSizeToAlloc'. |
39 | /// |
40 | /// All the methods implemented by this class are are intended for use |
41 | /// by the implementation of the class, not as part of its interface |
42 | /// (thus, private inheritance is suggested). |
43 | /// |
44 | //===----------------------------------------------------------------------===// |
45 | |
46 | #ifndef LLVM_SUPPORT_TRAILINGOBJECTS_H |
47 | #define LLVM_SUPPORT_TRAILINGOBJECTS_H |
48 | |
49 | #include "llvm/Support/AlignOf.h" |
50 | #include "llvm/Support/Alignment.h" |
51 | #include "llvm/Support/Compiler.h" |
52 | #include "llvm/Support/MathExtras.h" |
53 | #include "llvm/Support/type_traits.h" |
54 | #include <new> |
55 | #include <type_traits> |
56 | |
57 | namespace llvm { |
58 | |
59 | namespace trailing_objects_internal { |
60 | /// Helper template to calculate the max alignment requirement for a set of |
61 | /// objects. |
62 | template <typename First, typename... Rest> class AlignmentCalcHelper { |
63 | private: |
64 | enum { |
65 | FirstAlignment = alignof(First), |
66 | RestAlignment = AlignmentCalcHelper<Rest...>::Alignment, |
67 | }; |
68 | |
69 | public: |
70 | enum { |
71 | Alignment = FirstAlignment > RestAlignment ? FirstAlignment : RestAlignment |
72 | }; |
73 | }; |
74 | |
75 | template <typename First> class AlignmentCalcHelper<First> { |
76 | public: |
77 | enum { Alignment = alignof(First) }; |
78 | }; |
79 | |
80 | /// The base class for TrailingObjects* classes. |
81 | class TrailingObjectsBase { |
82 | protected: |
83 | /// OverloadToken's purpose is to allow specifying function overloads |
84 | /// for different types, without actually taking the types as |
85 | /// parameters. (Necessary because member function templates cannot |
86 | /// be specialized, so overloads must be used instead of |
87 | /// specialization.) |
88 | template <typename T> struct OverloadToken {}; |
89 | }; |
90 | |
91 | // Just a little helper for transforming a type pack into the same |
92 | // number of a different type. e.g.: |
93 | // ExtractSecondType<Foo..., int>::type |
94 | template <typename Ty1, typename Ty2> struct ExtractSecondType { |
95 | typedef Ty2 type; |
96 | }; |
97 | |
98 | // TrailingObjectsImpl is somewhat complicated, because it is a |
99 | // recursively inheriting template, in order to handle the template |
100 | // varargs. Each level of inheritance picks off a single trailing type |
101 | // then recurses on the rest. The "Align", "BaseTy", and |
102 | // "TopTrailingObj" arguments are passed through unchanged through the |
103 | // recursion. "PrevTy" is, at each level, the type handled by the |
104 | // level right above it. |
105 | |
106 | template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy, |
107 | typename... MoreTys> |
108 | class TrailingObjectsImpl { |
109 | // The main template definition is never used -- the two |
110 | // specializations cover all possibilities. |
111 | }; |
112 | |
113 | template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy, |
114 | typename NextTy, typename... MoreTys> |
115 | class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy, |
116 | MoreTys...> |
117 | : public TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, |
118 | MoreTys...> { |
119 | |
120 | typedef TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, MoreTys...> |
121 | ParentType; |
122 | |
123 | struct RequiresRealignment { |
124 | static const bool value = alignof(PrevTy) < alignof(NextTy); |
125 | }; |
126 | |
127 | static constexpr bool requiresRealignment() { |
128 | return RequiresRealignment::value; |
129 | } |
130 | |
131 | protected: |
132 | // Ensure the inherited getTrailingObjectsImpl is not hidden. |
133 | using ParentType::getTrailingObjectsImpl; |
134 | |
135 | // These two functions are helper functions for |
136 | // TrailingObjects::getTrailingObjects. They recurse to the left -- |
137 | // the result for each type in the list of trailing types depends on |
138 | // the result of calling the function on the type to the |
139 | // left. However, the function for the type to the left is |
140 | // implemented by a *subclass* of this class, so we invoke it via |
141 | // the TopTrailingObj, which is, via the |
142 | // curiously-recurring-template-pattern, the most-derived type in |
143 | // this recursion, and thus, contains all the overloads. |
144 | static const NextTy * |
145 | getTrailingObjectsImpl(const BaseTy *Obj, |
146 | TrailingObjectsBase::OverloadToken<NextTy>) { |
147 | auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( |
148 | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + |
149 | TopTrailingObj::callNumTrailingObjects( |
150 | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); |
151 | |
152 | if (requiresRealignment()) |
153 | return reinterpret_cast<const NextTy *>( |
154 | alignAddr(Ptr, Align::Of<NextTy>())); |
155 | else |
156 | return reinterpret_cast<const NextTy *>(Ptr); |
157 | } |
158 | |
159 | static NextTy * |
160 | getTrailingObjectsImpl(BaseTy *Obj, |
161 | TrailingObjectsBase::OverloadToken<NextTy>) { |
162 | auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( |
163 | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + |
164 | TopTrailingObj::callNumTrailingObjects( |
165 | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); |
166 | |
167 | if (requiresRealignment()) |
168 | return reinterpret_cast<NextTy *>(alignAddr(Ptr, Align::Of<NextTy>())); |
169 | else |
170 | return reinterpret_cast<NextTy *>(Ptr); |
171 | } |
172 | |
173 | // Helper function for TrailingObjects::additionalSizeToAlloc: this |
174 | // function recurses to superclasses, each of which requires one |
175 | // fewer size_t argument, and adds its own size. |
176 | static constexpr size_t additionalSizeToAllocImpl( |
177 | size_t SizeSoFar, size_t Count1, |
178 | typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) { |
179 | return ParentType::additionalSizeToAllocImpl( |
180 | (requiresRealignment() ? llvm::alignTo<alignof(NextTy)>(SizeSoFar) |
181 | : SizeSoFar) + |
182 | sizeof(NextTy) * Count1, |
183 | MoreCounts...); |
184 | } |
185 | }; |
186 | |
187 | // The base case of the TrailingObjectsImpl inheritance recursion, |
188 | // when there's no more trailing types. |
189 | template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy> |
190 | class alignas(Align) TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy> |
191 | : public TrailingObjectsBase { |
192 | protected: |
193 | // This is a dummy method, only here so the "using" doesn't fail -- |
194 | // it will never be called, because this function recurses backwards |
195 | // up the inheritance chain to subclasses. |
196 | static void getTrailingObjectsImpl(); |
197 | |
198 | static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) { |
199 | return SizeSoFar; |
200 | } |
201 | |
202 | template <bool CheckAlignment> static void verifyTrailingObjectsAlignment() {} |
203 | }; |
204 | |
205 | } // end namespace trailing_objects_internal |
206 | |
207 | // Finally, the main type defined in this file, the one intended for users... |
208 | |
209 | /// See the file comment for details on the usage of the |
210 | /// TrailingObjects type. |
211 | template <typename BaseTy, typename... TrailingTys> |
212 | class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl< |
213 | trailing_objects_internal::AlignmentCalcHelper< |
214 | TrailingTys...>::Alignment, |
215 | BaseTy, TrailingObjects<BaseTy, TrailingTys...>, |
216 | BaseTy, TrailingTys...> { |
217 | |
218 | template <int A, typename B, typename T, typename P, typename... M> |
219 | friend class trailing_objects_internal::TrailingObjectsImpl; |
220 | |
221 | template <typename... Tys> class Foo {}; |
222 | |
223 | typedef trailing_objects_internal::TrailingObjectsImpl< |
224 | trailing_objects_internal::AlignmentCalcHelper<TrailingTys...>::Alignment, |
225 | BaseTy, TrailingObjects<BaseTy, TrailingTys...>, BaseTy, TrailingTys...> |
226 | ParentType; |
227 | using TrailingObjectsBase = trailing_objects_internal::TrailingObjectsBase; |
228 | |
229 | using ParentType::getTrailingObjectsImpl; |
230 | |
231 | // This function contains only a static_assert BaseTy is final. The |
232 | // static_assert must be in a function, and not at class-level |
233 | // because BaseTy isn't complete at class instantiation time, but |
234 | // will be by the time this function is instantiated. |
235 | static void verifyTrailingObjectsAssertions() { |
236 | static_assert(std::is_final<BaseTy>(), "BaseTy must be final."); |
237 | } |
238 | |
239 | // These two methods are the base of the recursion for this method. |
240 | static const BaseTy * |
241 | getTrailingObjectsImpl(const BaseTy *Obj, |
242 | TrailingObjectsBase::OverloadToken<BaseTy>) { |
243 | return Obj; |
244 | } |
245 | |
246 | static BaseTy * |
247 | getTrailingObjectsImpl(BaseTy *Obj, |
248 | TrailingObjectsBase::OverloadToken<BaseTy>) { |
249 | return Obj; |
250 | } |
251 | |
252 | // callNumTrailingObjects simply calls numTrailingObjects on the |
253 | // provided Obj -- except when the type being queried is BaseTy |
254 | // itself. There is always only one of the base object, so that case |
255 | // is handled here. (An additional benefit of indirecting through |
256 | // this function is that consumers only say "friend |
257 | // TrailingObjects", and thus, only this class itself can call the |
258 | // numTrailingObjects function.) |
259 | static size_t |
260 | callNumTrailingObjects(const BaseTy *Obj, |
261 | TrailingObjectsBase::OverloadToken<BaseTy>) { |
262 | return 1; |
263 | } |
264 | |
265 | template <typename T> |
266 | static size_t callNumTrailingObjects(const BaseTy *Obj, |
267 | TrailingObjectsBase::OverloadToken<T>) { |
268 | return Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken<T>()); |
269 | } |
270 | |
271 | public: |
272 | // Make this (privately inherited) member public. |
273 | #ifndef _MSC_VER |
274 | using ParentType::OverloadToken; |
275 | #else |
276 | // An MSVC bug prevents the above from working, (last tested at CL version |
277 | // 19.28). "Class5" in TrailingObjectsTest.cpp tests the problematic case. |
278 | template <typename T> |
279 | using OverloadToken = typename ParentType::template OverloadToken<T>; |
280 | #endif |
281 | |
282 | /// Returns a pointer to the trailing object array of the given type |
283 | /// (which must be one of those specified in the class template). The |
284 | /// array may have zero or more elements in it. |
285 | template <typename T> const T *getTrailingObjects() const { |
286 | verifyTrailingObjectsAssertions(); |
287 | // Forwards to an impl function with overloads, since member |
288 | // function templates can't be specialized. |
289 | return this->getTrailingObjectsImpl( |
290 | static_cast<const BaseTy *>(this), |
291 | TrailingObjectsBase::OverloadToken<T>()); |
292 | } |
293 | |
294 | /// Returns a pointer to the trailing object array of the given type |
295 | /// (which must be one of those specified in the class template). The |
296 | /// array may have zero or more elements in it. |
297 | template <typename T> T *getTrailingObjects() { |
298 | verifyTrailingObjectsAssertions(); |
299 | // Forwards to an impl function with overloads, since member |
300 | // function templates can't be specialized. |
301 | return this->getTrailingObjectsImpl( |
302 | static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>()); |
303 | } |
304 | |
305 | /// Returns the size of the trailing data, if an object were |
306 | /// allocated with the given counts (The counts are in the same order |
307 | /// as the template arguments). This does not include the size of the |
308 | /// base object. The template arguments must be the same as those |
309 | /// used in the class; they are supplied here redundantly only so |
310 | /// that it's clear what the counts are counting in callers. |
311 | template <typename... Tys> |
312 | static constexpr std::enable_if_t< |
313 | std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t> |
314 | additionalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType< |
315 | TrailingTys, size_t>::type... Counts) { |
316 | return ParentType::additionalSizeToAllocImpl(0, Counts...); |
317 | } |
318 | |
319 | /// Returns the total size of an object if it were allocated with the |
320 | /// given trailing object counts. This is the same as |
321 | /// additionalSizeToAlloc, except it *does* include the size of the base |
322 | /// object. |
323 | template <typename... Tys> |
324 | static constexpr std::enable_if_t< |
325 | std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t> |
326 | totalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType< |
327 | TrailingTys, size_t>::type... Counts) { |
328 | return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...); |
329 | } |
330 | |
331 | TrailingObjects() = default; |
332 | TrailingObjects(const TrailingObjects &) = delete; |
333 | TrailingObjects(TrailingObjects &&) = delete; |
334 | TrailingObjects &operator=(const TrailingObjects &) = delete; |
335 | TrailingObjects &operator=(TrailingObjects &&) = delete; |
336 | |
337 | /// A type where its ::with_counts template member has a ::type member |
338 | /// suitable for use as uninitialized storage for an object with the given |
339 | /// trailing object counts. The template arguments are similar to those |
340 | /// of additionalSizeToAlloc. |
341 | /// |
342 | /// Use with FixedSizeStorageOwner, e.g.: |
343 | /// |
344 | /// \code{.cpp} |
345 | /// |
346 | /// MyObj::FixedSizeStorage<void *>::with_counts<1u>::type myStackObjStorage; |
347 | /// MyObj::FixedSizeStorageOwner |
348 | /// myStackObjOwner(new ((void *)&myStackObjStorage) MyObj); |
349 | /// MyObj *const myStackObjPtr = myStackObjOwner.get(); |
350 | /// |
351 | /// \endcode |
352 | template <typename... Tys> struct FixedSizeStorage { |
353 | template <size_t... Counts> struct with_counts { |
354 | enum { Size = totalSizeToAlloc<Tys...>(Counts...) }; |
355 | struct type { |
356 | alignas(BaseTy) char buffer[Size]; |
357 | }; |
358 | }; |
359 | }; |
360 | |
361 | /// A type that acts as the owner for an object placed into fixed storage. |
362 | class FixedSizeStorageOwner { |
363 | public: |
364 | FixedSizeStorageOwner(BaseTy *p) : p(p) {} |
365 | ~FixedSizeStorageOwner() { |
366 | assert(p && "FixedSizeStorageOwner owns null?")(static_cast <bool> (p && "FixedSizeStorageOwner owns null?" ) ? void (0) : __assert_fail ("p && \"FixedSizeStorageOwner owns null?\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/Support/TrailingObjects.h" , 366, __extension__ __PRETTY_FUNCTION__)); |
367 | p->~BaseTy(); |
368 | } |
369 | |
370 | BaseTy *get() { return p; } |
371 | const BaseTy *get() const { return p; } |
372 | |
373 | private: |
374 | FixedSizeStorageOwner(const FixedSizeStorageOwner &) = delete; |
375 | FixedSizeStorageOwner(FixedSizeStorageOwner &&) = delete; |
376 | FixedSizeStorageOwner &operator=(const FixedSizeStorageOwner &) = delete; |
377 | FixedSizeStorageOwner &operator=(FixedSizeStorageOwner &&) = delete; |
378 | |
379 | BaseTy *const p; |
380 | }; |
381 | }; |
382 | |
383 | } // end namespace llvm |
384 | |
385 | #endif |