Bug Summary

File:clang/lib/AST/ASTConcept.cpp
Warning:line 42, column 7
Storage provided to placement new is only 0 bytes, whereas the allocated type requires 16 bytes

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ASTConcept.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mthread-model posix -mframe-pointer=none -relaxed-aliasing -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-11/lib/clang/11.0.0 -D CLANG_VENDOR="Debian " -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/build-llvm/tools/clang/lib/AST -I /build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/AST -I /build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/include -I /build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/build-llvm/tools/clang/include -I /build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/build-llvm/include -I /build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-11/lib/clang/11.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/build-llvm/tools/clang/lib/AST -fdebug-prefix-map=/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347=. -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fno-common -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -o /tmp/scan-build-2020-03-09-184146-41876-1 -x c++ /build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/AST/ASTConcept.cpp

/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/AST/ASTConcept.cpp

1//===--- ASTConcept.cpp - Concepts Related AST Data Structures --*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief This file defines AST data structures related to concepts.
12///
13//===----------------------------------------------------------------------===//
14
15#include "clang/AST/ASTConcept.h"
16#include "clang/AST/ASTContext.h"
17#include "clang/AST/Decl.h"
18#include "clang/AST/TemplateBase.h"
19#include "llvm/ADT/ArrayRef.h"
20#include "llvm/ADT/FoldingSet.h"
21using namespace clang;
22
23ASTConstraintSatisfaction::ASTConstraintSatisfaction(const ASTContext &C,
24 const ConstraintSatisfaction &Satisfaction):
25 NumRecords{Satisfaction.Details.size()},
26 IsSatisfied{Satisfaction.IsSatisfied} {
27 for (unsigned I = 0; I < NumRecords; ++I) {
2
Assuming 'I' is < field 'NumRecords'
3
Loop condition is true. Entering loop body
28 auto &Detail = Satisfaction.Details[I];
29 if (Detail.second.is<Expr *>())
4
Calling 'PointerUnion::is'
7
Returning from 'PointerUnion::is'
8
Taking false branch
30 new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I)
31 UnsatisfiedConstraintRecord{Detail.first,
32 UnsatisfiedConstraintRecord::second_type(
33 Detail.second.get<Expr *>())};
34 else {
35 auto &SubstitutionDiagnostic =
36 *Detail.second.get<std::pair<SourceLocation, StringRef> *>();
37 unsigned MessageSize = SubstitutionDiagnostic.second.size();
38 char *Mem = new (C) char[MessageSize];
39 memcpy(Mem, SubstitutionDiagnostic.second.data(), MessageSize);
40 auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>(
41 SubstitutionDiagnostic.first, StringRef(Mem, MessageSize));
42 new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I)
9
Calling 'TrailingObjects::getTrailingObjects'
18
Returning from 'TrailingObjects::getTrailingObjects'
19
Storage provided to placement new is only 0 bytes, whereas the allocated type requires 16 bytes
43 UnsatisfiedConstraintRecord{Detail.first,
44 UnsatisfiedConstraintRecord::second_type(
45 NewSubstDiag)};
46 }
47 }
48}
49
50
51ASTConstraintSatisfaction *
52ASTConstraintSatisfaction::Create(const ASTContext &C,
53 const ConstraintSatisfaction &Satisfaction) {
54 std::size_t size =
55 totalSizeToAlloc<UnsatisfiedConstraintRecord>(
56 Satisfaction.Details.size());
57 void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction));
58 return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);
1
Calling constructor for 'ASTConstraintSatisfaction'
59}
60
61void ConstraintSatisfaction::Profile(
62 llvm::FoldingSetNodeID &ID, const ASTContext &C,
63 const NamedDecl *ConstraintOwner, ArrayRef<TemplateArgument> TemplateArgs) {
64 ID.AddPointer(ConstraintOwner);
65 ID.AddInteger(TemplateArgs.size());
66 for (auto &Arg : TemplateArgs)
67 Arg.Profile(ID, C);
68}

/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/include/llvm/ADT/PointerUnion.h

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
24namespace llvm {
25
26template <typename T> struct PointerUnionTypeSelectorReturn {
27 using Return = T;
28};
29
30/// Get a type based on whether two types are the same or not.
31///
32/// For:
33///
34/// \code
35/// using Ret = typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return;
36/// \endcode
37///
38/// Ret will be EQ type if T1 is same as T2 or NE type otherwise.
39template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
40struct PointerUnionTypeSelector {
41 using Return = typename PointerUnionTypeSelectorReturn<RET_NE>::Return;
42};
43
44template <typename T, typename RET_EQ, typename RET_NE>
45struct PointerUnionTypeSelector<T, T, RET_EQ, RET_NE> {
46 using Return = typename PointerUnionTypeSelectorReturn<RET_EQ>::Return;
47};
48
49template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
50struct PointerUnionTypeSelectorReturn<
51 PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>> {
52 using Return =
53 typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return;
54};
55
56namespace pointer_union_detail {
57 /// Determine the number of bits required to store integers with values < n.
58 /// This is ceil(log2(n)).
59 constexpr int bitsRequired(unsigned n) {
60 return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0;
61 }
62
63 template <typename... Ts> constexpr int lowBitsAvailable() {
64 return std::min<int>({PointerLikeTypeTraits<Ts>::NumLowBitsAvailable...});
65 }
66
67 /// Find the index of a type in a list of types. TypeIndex<T, Us...>::Index
68 /// is the index of T in Us, or sizeof...(Us) if T does not appear in the
69 /// list.
70 template <typename T, typename ...Us> struct TypeIndex;
71 template <typename T, typename ...Us> struct TypeIndex<T, T, Us...> {
72 static constexpr int Index = 0;
73 };
74 template <typename T, typename U, typename... Us>
75 struct TypeIndex<T, U, Us...> {
76 static constexpr int Index = 1 + TypeIndex<T, Us...>::Index;
77 };
78 template <typename T> struct TypeIndex<T> {
79 static constexpr int Index = 0;
80 };
81
82 /// Find the first type in a list of types.
83 template <typename T, typename...> struct GetFirstType {
84 using type = T;
85 };
86
87 /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
88 /// for the template arguments.
89 template <typename ...PTs> class PointerUnionUIntTraits {
90 public:
91 static inline void *getAsVoidPointer(void *P) { return P; }
92 static inline void *getFromVoidPointer(void *P) { return P; }
93 static constexpr int NumLowBitsAvailable = lowBitsAvailable<PTs...>();
94 };
95
96 /// Implement assignment in terms of construction.
97 template <typename Derived, typename T> struct AssignableFrom {
98 Derived &operator=(T t) {
99 return static_cast<Derived &>(*this) = Derived(t);
100 }
101 };
102
103 template <typename Derived, typename ValTy, int I, typename ...Types>
104 class PointerUnionMembers;
105
106 template <typename Derived, typename ValTy, int I>
107 class PointerUnionMembers<Derived, ValTy, I> {
108 protected:
109 ValTy Val;
110 PointerUnionMembers() = default;
111 PointerUnionMembers(ValTy Val) : Val(Val) {}
112
113 friend struct PointerLikeTypeTraits<Derived>;
114 };
115
116 template <typename Derived, typename ValTy, int I, typename Type,
117 typename ...Types>
118 class PointerUnionMembers<Derived, ValTy, I, Type, Types...>
119 : public PointerUnionMembers<Derived, ValTy, I + 1, Types...> {
120 using Base = PointerUnionMembers<Derived, ValTy, I + 1, Types...>;
121 public:
122 using Base::Base;
123 PointerUnionMembers() = default;
124 PointerUnionMembers(Type V)
125 : Base(ValTy(const_cast<void *>(
126 PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
127 I)) {}
128
129 using Base::operator=;
130 Derived &operator=(Type V) {
131 this->Val = ValTy(
132 const_cast<void *>(PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
133 I);
134 return static_cast<Derived &>(*this);
135 };
136 };
137}
138
139/// A discriminated union of two or more pointer types, with the discriminator
140/// in the low bit of the pointer.
141///
142/// This implementation is extremely efficient in space due to leveraging the
143/// low bits of the pointer, while exposing a natural and type-safe API.
144///
145/// Common use patterns would be something like this:
146/// PointerUnion<int*, float*> P;
147/// P = (int*)0;
148/// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0"
149/// X = P.get<int*>(); // ok.
150/// Y = P.get<float*>(); // runtime assertion failure.
151/// Z = P.get<double*>(); // compile time failure.
152/// P = (float*)0;
153/// Y = P.get<float*>(); // ok.
154/// X = P.get<int*>(); // runtime assertion failure.
155template <typename... PTs>
156class PointerUnion
157 : public pointer_union_detail::PointerUnionMembers<
158 PointerUnion<PTs...>,
159 PointerIntPair<
160 void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int,
161 pointer_union_detail::PointerUnionUIntTraits<PTs...>>,
162 0, PTs...> {
163 // The first type is special because we want to directly cast a pointer to a
164 // default-initialized union to a pointer to the first type. But we don't
165 // want PointerUnion to be a 'template <typename First, typename ...Rest>'
166 // because it's much more convenient to have a name for the whole pack. So
167 // split off the first type here.
168 using First = typename pointer_union_detail::GetFirstType<PTs...>::type;
169 using Base = typename PointerUnion::PointerUnionMembers;
170
171public:
172 PointerUnion() = default;
173
174 PointerUnion(std::nullptr_t) : PointerUnion() {}
175 using Base::Base;
176
177 /// Test if the pointer held in the union is null, regardless of
178 /// which type it is.
179 bool isNull() const { return !this->Val.getPointer(); }
180
181 explicit operator bool() const { return !isNull(); }
182
183 /// Test if the Union currently holds the type matching T.
184 template <typename T> bool is() const {
185 constexpr int Index = pointer_union_detail::TypeIndex<T, PTs...>::Index;
186 static_assert(Index < sizeof...(PTs),
187 "PointerUnion::is<T> given type not in the union");
188 return this->Val.getInt() == Index;
5
Assuming the condition is false
6
Returning zero, which participates in a condition later
189 }
190
191 /// Returns the value of the specified pointer type.
192 ///
193 /// If the specified pointer type is incorrect, assert.
194 template <typename T> T get() const {
195 assert(is<T>() && "Invalid accessor called")((is<T>() && "Invalid accessor called") ? static_cast
<void> (0) : __assert_fail ("is<T>() && \"Invalid accessor called\""
, "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/include/llvm/ADT/PointerUnion.h"
, 195, __PRETTY_FUNCTION__))
;
196 return PointerLikeTypeTraits<T>::getFromVoidPointer(this->Val.getPointer());
197 }
198
199 /// Returns the current pointer if it is of the specified pointer type,
200 /// otherwises returns null.
201 template <typename T> T dyn_cast() const {
202 if (is<T>())
203 return get<T>();
204 return T();
205 }
206
207 /// If the union is set to the first pointer type get an address pointing to
208 /// it.
209 First const *getAddrOfPtr1() const {
210 return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
211 }
212
213 /// If the union is set to the first pointer type get an address pointing to
214 /// it.
215 First *getAddrOfPtr1() {
216 assert(is<First>() && "Val is not the first pointer")((is<First>() && "Val is not the first pointer"
) ? static_cast<void> (0) : __assert_fail ("is<First>() && \"Val is not the first pointer\""
, "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/include/llvm/ADT/PointerUnion.h"
, 216, __PRETTY_FUNCTION__))
;
217 assert(((PointerLikeTypeTraits<First>::getAsVoidPointer(get<
First>()) == this->Val.getPointer() && "Can't get the address because PointerLikeTypeTraits changes the ptr"
) ? static_cast<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-11~++20200309111110+2c36c23f347/llvm/include/llvm/ADT/PointerUnion.h"
, 220, __PRETTY_FUNCTION__))
218 PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) ==((PointerLikeTypeTraits<First>::getAsVoidPointer(get<
First>()) == this->Val.getPointer() && "Can't get the address because PointerLikeTypeTraits changes the ptr"
) ? static_cast<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-11~++20200309111110+2c36c23f347/llvm/include/llvm/ADT/PointerUnion.h"
, 220, __PRETTY_FUNCTION__))
219 this->Val.getPointer() &&((PointerLikeTypeTraits<First>::getAsVoidPointer(get<
First>()) == this->Val.getPointer() && "Can't get the address because PointerLikeTypeTraits changes the ptr"
) ? static_cast<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-11~++20200309111110+2c36c23f347/llvm/include/llvm/ADT/PointerUnion.h"
, 220, __PRETTY_FUNCTION__))
220 "Can't get the address because PointerLikeTypeTraits changes the ptr")((PointerLikeTypeTraits<First>::getAsVoidPointer(get<
First>()) == this->Val.getPointer() && "Can't get the address because PointerLikeTypeTraits changes the ptr"
) ? static_cast<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-11~++20200309111110+2c36c23f347/llvm/include/llvm/ADT/PointerUnion.h"
, 220, __PRETTY_FUNCTION__))
;
221 return const_cast<First *>(
222 reinterpret_cast<const First *>(this->Val.getAddrOfPointer()));
223 }
224
225 /// Assignment from nullptr which just clears the union.
226 const PointerUnion &operator=(std::nullptr_t) {
227 this->Val.initWithPointer(nullptr);
228 return *this;
229 }
230
231 /// Assignment from elements of the union.
232 using Base::operator=;
233
234 void *getOpaqueValue() const { return this->Val.getOpaqueValue(); }
235 static inline PointerUnion getFromOpaqueValue(void *VP) {
236 PointerUnion V;
237 V.Val = decltype(V.Val)::getFromOpaqueValue(VP);
238 return V;
239 }
240};
241
242template <typename ...PTs>
243bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
244 return lhs.getOpaqueValue() == rhs.getOpaqueValue();
245}
246
247template <typename ...PTs>
248bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
249 return lhs.getOpaqueValue() != rhs.getOpaqueValue();
250}
251
252template <typename ...PTs>
253bool operator<(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
254 return lhs.getOpaqueValue() < rhs.getOpaqueValue();
255}
256
257// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
258// # low bits available = min(PT1bits,PT2bits)-1.
259template <typename ...PTs>
260struct PointerLikeTypeTraits<PointerUnion<PTs...>> {
261 static inline void *getAsVoidPointer(const PointerUnion<PTs...> &P) {
262 return P.getOpaqueValue();
263 }
264
265 static inline PointerUnion<PTs...> getFromVoidPointer(void *P) {
266 return PointerUnion<PTs...>::getFromOpaqueValue(P);
267 }
268
269 // The number of bits available are the min of the pointer types minus the
270 // bits needed for the discriminator.
271 static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits<decltype(
272 PointerUnion<PTs...>::Val)>::NumLowBitsAvailable;
273};
274
275// Teach DenseMap how to use PointerUnions as keys.
276template <typename ...PTs> struct DenseMapInfo<PointerUnion<PTs...>> {
277 using Union = PointerUnion<PTs...>;
278 using FirstInfo =
279 DenseMapInfo<typename pointer_union_detail::GetFirstType<PTs...>::type>;
280
281 static inline Union getEmptyKey() { return Union(FirstInfo::getEmptyKey()); }
282
283 static inline Union getTombstoneKey() {
284 return Union(FirstInfo::getTombstoneKey());
285 }
286
287 static unsigned getHashValue(const Union &UnionVal) {
288 intptr_t key = (intptr_t)UnionVal.getOpaqueValue();
289 return DenseMapInfo<intptr_t>::getHashValue(key);
290 }
291
292 static bool isEqual(const Union &LHS, const Union &RHS) {
293 return LHS == RHS;
294 }
295};
296
297} // end namespace llvm
298
299#endif // LLVM_ADT_POINTERUNION_H

/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/include/llvm/Support/TrailingObjects.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
57namespace llvm {
58
59namespace trailing_objects_internal {
60/// Helper template to calculate the max alignment requirement for a set of
61/// objects.
62template <typename First, typename... Rest> class AlignmentCalcHelper {
63private:
64 enum {
65 FirstAlignment = alignof(First),
66 RestAlignment = AlignmentCalcHelper<Rest...>::Alignment,
67 };
68
69public:
70 enum {
71 Alignment = FirstAlignment > RestAlignment ? FirstAlignment : RestAlignment
72 };
73};
74
75template <typename First> class AlignmentCalcHelper<First> {
76public:
77 enum { Alignment = alignof(First) };
78};
79
80/// The base class for TrailingObjects* classes.
81class TrailingObjectsBase {
82protected:
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
91template <int Align>
92class TrailingObjectsAligner : public TrailingObjectsBase {};
93template <>
94class alignas(1) TrailingObjectsAligner<1> : public TrailingObjectsBase {};
95template <>
96class alignas(2) TrailingObjectsAligner<2> : public TrailingObjectsBase {};
97template <>
98class alignas(4) TrailingObjectsAligner<4> : public TrailingObjectsBase {};
99template <>
100class alignas(8) TrailingObjectsAligner<8> : public TrailingObjectsBase {};
101template <>
102class alignas(16) TrailingObjectsAligner<16> : public TrailingObjectsBase {
103};
104template <>
105class alignas(32) TrailingObjectsAligner<32> : public TrailingObjectsBase {
106};
107
108// Just a little helper for transforming a type pack into the same
109// number of a different type. e.g.:
110// ExtractSecondType<Foo..., int>::type
111template <typename Ty1, typename Ty2> struct ExtractSecondType {
112 typedef Ty2 type;
113};
114
115// TrailingObjectsImpl is somewhat complicated, because it is a
116// recursively inheriting template, in order to handle the template
117// varargs. Each level of inheritance picks off a single trailing type
118// then recurses on the rest. The "Align", "BaseTy", and
119// "TopTrailingObj" arguments are passed through unchanged through the
120// recursion. "PrevTy" is, at each level, the type handled by the
121// level right above it.
122
123template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
124 typename... MoreTys>
125class TrailingObjectsImpl {
126 // The main template definition is never used -- the two
127 // specializations cover all possibilities.
128};
129
130template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
131 typename NextTy, typename... MoreTys>
132class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy,
133 MoreTys...>
134 : public TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy,
135 MoreTys...> {
136
137 typedef TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, MoreTys...>
138 ParentType;
139
140 struct RequiresRealignment {
141 static const bool value = alignof(PrevTy) < alignof(NextTy);
142 };
143
144 static constexpr bool requiresRealignment() {
145 return RequiresRealignment::value;
146 }
147
148protected:
149 // Ensure the inherited getTrailingObjectsImpl is not hidden.
150 using ParentType::getTrailingObjectsImpl;
151
152 // These two functions are helper functions for
153 // TrailingObjects::getTrailingObjects. They recurse to the left --
154 // the result for each type in the list of trailing types depends on
155 // the result of calling the function on the type to the
156 // left. However, the function for the type to the left is
157 // implemented by a *subclass* of this class, so we invoke it via
158 // the TopTrailingObj, which is, via the
159 // curiously-recurring-template-pattern, the most-derived type in
160 // this recursion, and thus, contains all the overloads.
161 static const NextTy *
162 getTrailingObjectsImpl(const BaseTy *Obj,
163 TrailingObjectsBase::OverloadToken<NextTy>) {
164 auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
165 Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) +
166 TopTrailingObj::callNumTrailingObjects(
167 Obj, TrailingObjectsBase::OverloadToken<PrevTy>());
168
169 if (requiresRealignment())
170 return reinterpret_cast<const NextTy *>(
171 alignAddr(Ptr, Align::Of<NextTy>()));
172 else
173 return reinterpret_cast<const NextTy *>(Ptr);
174 }
175
176 static NextTy *
177 getTrailingObjectsImpl(BaseTy *Obj,
178 TrailingObjectsBase::OverloadToken<NextTy>) {
179 auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
13
'Ptr' initialized here
180 Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) +
12
Passing value via 1st parameter 'Obj'
181 TopTrailingObj::callNumTrailingObjects(
182 Obj, TrailingObjectsBase::OverloadToken<PrevTy>());
183
184 if (requiresRealignment())
14
Taking false branch
185 return reinterpret_cast<NextTy *>(alignAddr(Ptr, Align::Of<NextTy>()));
186 else
187 return reinterpret_cast<NextTy *>(Ptr);
15
Returning pointer (loaded from 'Ptr')
188 }
189
190 // Helper function for TrailingObjects::additionalSizeToAlloc: this
191 // function recurses to superclasses, each of which requires one
192 // fewer size_t argument, and adds its own size.
193 static constexpr size_t additionalSizeToAllocImpl(
194 size_t SizeSoFar, size_t Count1,
195 typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) {
196 return ParentType::additionalSizeToAllocImpl(
197 (requiresRealignment() ? llvm::alignTo<alignof(NextTy)>(SizeSoFar)
198 : SizeSoFar) +
199 sizeof(NextTy) * Count1,
200 MoreCounts...);
201 }
202};
203
204// The base case of the TrailingObjectsImpl inheritance recursion,
205// when there's no more trailing types.
206template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy>
207class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy>
208 : public TrailingObjectsAligner<Align> {
209protected:
210 // This is a dummy method, only here so the "using" doesn't fail --
211 // it will never be called, because this function recurses backwards
212 // up the inheritance chain to subclasses.
213 static void getTrailingObjectsImpl();
214
215 static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) {
216 return SizeSoFar;
217 }
218
219 template <bool CheckAlignment> static void verifyTrailingObjectsAlignment() {}
220};
221
222} // end namespace trailing_objects_internal
223
224// Finally, the main type defined in this file, the one intended for users...
225
226/// See the file comment for details on the usage of the
227/// TrailingObjects type.
228template <typename BaseTy, typename... TrailingTys>
229class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl<
230 trailing_objects_internal::AlignmentCalcHelper<
231 TrailingTys...>::Alignment,
232 BaseTy, TrailingObjects<BaseTy, TrailingTys...>,
233 BaseTy, TrailingTys...> {
234
235 template <int A, typename B, typename T, typename P, typename... M>
236 friend class trailing_objects_internal::TrailingObjectsImpl;
237
238 template <typename... Tys> class Foo {};
239
240 typedef trailing_objects_internal::TrailingObjectsImpl<
241 trailing_objects_internal::AlignmentCalcHelper<TrailingTys...>::Alignment,
242 BaseTy, TrailingObjects<BaseTy, TrailingTys...>, BaseTy, TrailingTys...>
243 ParentType;
244 using TrailingObjectsBase = trailing_objects_internal::TrailingObjectsBase;
245
246 using ParentType::getTrailingObjectsImpl;
247
248 // This function contains only a static_assert BaseTy is final. The
249 // static_assert must be in a function, and not at class-level
250 // because BaseTy isn't complete at class instantiation time, but
251 // will be by the time this function is instantiated.
252 static void verifyTrailingObjectsAssertions() {
253 static_assert(std::is_final<BaseTy>(), "BaseTy must be final.");
254 }
255
256 // These two methods are the base of the recursion for this method.
257 static const BaseTy *
258 getTrailingObjectsImpl(const BaseTy *Obj,
259 TrailingObjectsBase::OverloadToken<BaseTy>) {
260 return Obj;
261 }
262
263 static BaseTy *
264 getTrailingObjectsImpl(BaseTy *Obj,
265 TrailingObjectsBase::OverloadToken<BaseTy>) {
266 return Obj;
267 }
268
269 // callNumTrailingObjects simply calls numTrailingObjects on the
270 // provided Obj -- except when the type being queried is BaseTy
271 // itself. There is always only one of the base object, so that case
272 // is handled here. (An additional benefit of indirecting through
273 // this function is that consumers only say "friend
274 // TrailingObjects", and thus, only this class itself can call the
275 // numTrailingObjects function.)
276 static size_t
277 callNumTrailingObjects(const BaseTy *Obj,
278 TrailingObjectsBase::OverloadToken<BaseTy>) {
279 return 1;
280 }
281
282 template <typename T>
283 static size_t callNumTrailingObjects(const BaseTy *Obj,
284 TrailingObjectsBase::OverloadToken<T>) {
285 return Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken<T>());
286 }
287
288public:
289 // Make this (privately inherited) member public.
290#ifndef _MSC_VER
291 using ParentType::OverloadToken;
292#else
293 // MSVC bug prevents the above from working, at least up through CL
294 // 19.10.24629.
295 template <typename T>
296 using OverloadToken = typename ParentType::template OverloadToken<T>;
297#endif
298
299 /// Returns a pointer to the trailing object array of the given type
300 /// (which must be one of those specified in the class template). The
301 /// array may have zero or more elements in it.
302 template <typename T> const T *getTrailingObjects() const {
303 verifyTrailingObjectsAssertions();
304 // Forwards to an impl function with overloads, since member
305 // function templates can't be specialized.
306 return this->getTrailingObjectsImpl(
307 static_cast<const BaseTy *>(this),
308 TrailingObjectsBase::OverloadToken<T>());
309 }
310
311 /// Returns a pointer to the trailing object array of the given type
312 /// (which must be one of those specified in the class template). The
313 /// array may have zero or more elements in it.
314 template <typename T> T *getTrailingObjects() {
315 verifyTrailingObjectsAssertions();
316 // Forwards to an impl function with overloads, since member
317 // function templates can't be specialized.
318 return this->getTrailingObjectsImpl(
11
Calling 'TrailingObjectsImpl::getTrailingObjectsImpl'
16
Returning from 'TrailingObjectsImpl::getTrailingObjectsImpl'
17
Returning pointer
319 static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>());
10
Passing value via 1st parameter 'Obj'
320 }
321
322 /// Returns the size of the trailing data, if an object were
323 /// allocated with the given counts (The counts are in the same order
324 /// as the template arguments). This does not include the size of the
325 /// base object. The template arguments must be the same as those
326 /// used in the class; they are supplied here redundantly only so
327 /// that it's clear what the counts are counting in callers.
328 template <typename... Tys>
329 static constexpr std::enable_if_t<
330 std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>
331 additionalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType<
332 TrailingTys, size_t>::type... Counts) {
333 return ParentType::additionalSizeToAllocImpl(0, Counts...);
334 }
335
336 /// Returns the total size of an object if it were allocated with the
337 /// given trailing object counts. This is the same as
338 /// additionalSizeToAlloc, except it *does* include the size of the base
339 /// object.
340 template <typename... Tys>
341 static constexpr std::enable_if_t<
342 std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>
343 totalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType<
344 TrailingTys, size_t>::type... Counts) {
345 return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...);
346 }
347
348 /// A type where its ::with_counts template member has a ::type member
349 /// suitable for use as uninitialized storage for an object with the given
350 /// trailing object counts. The template arguments are similar to those
351 /// of additionalSizeToAlloc.
352 ///
353 /// Use with FixedSizeStorageOwner, e.g.:
354 ///
355 /// \code{.cpp}
356 ///
357 /// MyObj::FixedSizeStorage<void *>::with_counts<1u>::type myStackObjStorage;
358 /// MyObj::FixedSizeStorageOwner
359 /// myStackObjOwner(new ((void *)&myStackObjStorage) MyObj);
360 /// MyObj *const myStackObjPtr = myStackObjOwner.get();
361 ///
362 /// \endcode
363 template <typename... Tys> struct FixedSizeStorage {
364 template <size_t... Counts> struct with_counts {
365 enum { Size = totalSizeToAlloc<Tys...>(Counts...) };
366 struct type {
367 alignas(BaseTy) char buffer[Size];
368 };
369 };
370 };
371
372 /// A type that acts as the owner for an object placed into fixed storage.
373 class FixedSizeStorageOwner {
374 public:
375 FixedSizeStorageOwner(BaseTy *p) : p(p) {}
376 ~FixedSizeStorageOwner() {
377 assert(p && "FixedSizeStorageOwner owns null?")((p && "FixedSizeStorageOwner owns null?") ? static_cast
<void> (0) : __assert_fail ("p && \"FixedSizeStorageOwner owns null?\""
, "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/include/llvm/Support/TrailingObjects.h"
, 377, __PRETTY_FUNCTION__))
;
378 p->~BaseTy();
379 }
380
381 BaseTy *get() { return p; }
382 const BaseTy *get() const { return p; }
383
384 private:
385 FixedSizeStorageOwner(const FixedSizeStorageOwner &) = delete;
386 FixedSizeStorageOwner(FixedSizeStorageOwner &&) = delete;
387 FixedSizeStorageOwner &operator=(const FixedSizeStorageOwner &) = delete;
388 FixedSizeStorageOwner &operator=(FixedSizeStorageOwner &&) = delete;
389
390 BaseTy *const p;
391 };
392};
393
394} // end namespace llvm
395
396#endif