Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -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 -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/clang/lib/AST -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/clang/lib/AST -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/clang/include -I tools/clang/include -I include -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/llvm/include -D _FORTIFY_SOURCE=2 -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 -fmacro-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm=build-llvm -fmacro-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm=build-llvm -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/= -O3 -Wno-unused-command-line-argument -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~++20220119111520+da61cb019eb2/build-llvm -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm=build-llvm -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -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-2022-01-19-134126-35450-1 -x c++ /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/clang/lib/AST/ASTConcept.cpp

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

/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/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?\""
, "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