Bug Summary

File:clang/lib/AST/ASTConcept.cpp
Warning:line 41, 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 -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 -mframe-pointer=none -relaxed-aliasing -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/build-llvm/tools/clang/lib/AST -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -D CLANG_ROUND_TRIP_CC1_ARGS=ON -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/build-llvm/tools/clang/lib/AST -I /build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/AST -I /build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/include -I /build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/build-llvm/tools/clang/include -I /build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/build-llvm/include -I /build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/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-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/build-llvm/tools/clang/lib/AST -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0=. -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2021-08-28-193554-24367-1 -x c++ /build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/AST/ASTConcept.cpp

/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/AST/ASTConcept.cpp

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"
20using namespace clang;
21
22ASTConstraintSatisfaction::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) {
2
Assuming 'I' is < field 'NumRecords'
3
Loop condition is true. Entering loop body
27 auto &Detail = Satisfaction.Details[I];
28 if (Detail.second.is<Expr *>())
4
Calling 'PointerUnion::is'
7
Returning from 'PointerUnion::is'
8
Taking false branch
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)
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
42 UnsatisfiedConstraintRecord{Detail.first,
43 UnsatisfiedConstraintRecord::second_type(
44 NewSubstDiag)};
45 }
46 }
47}
48
49
50ASTConstraintSatisfaction *
51ASTConstraintSatisfaction::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);
1
Calling constructor for 'ASTConstraintSatisfaction'
58}
59
60void 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}

/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/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
26namespace 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.
118template <typename... PTs>
119class 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
134public:
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;
5
Assuming the condition is false
6
Returning zero, which participates in a condition later
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
205template <typename ...PTs>
206bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
207 return lhs.getOpaqueValue() == rhs.getOpaqueValue();
208}
209
210template <typename ...PTs>
211bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
212 return lhs.getOpaqueValue() != rhs.getOpaqueValue();
213}
214
215template <typename ...PTs>
216bool 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.
222template <typename ...PTs>
223struct 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.
239template <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

/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/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
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
94template <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
106template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
107 typename... MoreTys>
108class TrailingObjectsImpl {
109 // The main template definition is never used -- the two
110 // specializations cover all possibilities.
111};
112
113template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
114 typename NextTy, typename... MoreTys>
115class 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
131protected:
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(
13
'Ptr' initialized here
163 Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) +
12
Passing value via 1st parameter 'Obj'
164 TopTrailingObj::callNumTrailingObjects(
165 Obj, TrailingObjectsBase::OverloadToken<PrevTy>());
166
167 if (requiresRealignment())
14
Taking false branch
168 return reinterpret_cast<NextTy *>(alignAddr(Ptr, Align::Of<NextTy>()));
169 else
170 return reinterpret_cast<NextTy *>(Ptr);
15
Returning pointer (loaded from '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.
189template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy>
190class alignas(Align) TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy>
191 : public TrailingObjectsBase {
192protected:
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.
211template <typename BaseTy, typename... TrailingTys>
212class 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
271public:
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(
11
Calling 'TrailingObjectsImpl::getTrailingObjectsImpl'
16
Returning from 'TrailingObjectsImpl::getTrailingObjectsImpl'
17
Returning pointer
302 static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>());
10
Passing value via 1st parameter 'Obj'
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