File: | build/source/clang/lib/AST/TemplateBase.cpp |
Warning: | line 641, column 5 Storage provided to placement new is only 0 bytes, whereas the allocated type requires 32 bytes |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- TemplateBase.cpp - Common template AST class implementation --------===// | |||
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 implements common classes used throughout C++ template | |||
10 | // representations. | |||
11 | // | |||
12 | //===----------------------------------------------------------------------===// | |||
13 | ||||
14 | #include "clang/AST/TemplateBase.h" | |||
15 | #include "clang/AST/ASTContext.h" | |||
16 | #include "clang/AST/Decl.h" | |||
17 | #include "clang/AST/DeclBase.h" | |||
18 | #include "clang/AST/DeclTemplate.h" | |||
19 | #include "clang/AST/DependenceFlags.h" | |||
20 | #include "clang/AST/Expr.h" | |||
21 | #include "clang/AST/ExprCXX.h" | |||
22 | #include "clang/AST/PrettyPrinter.h" | |||
23 | #include "clang/AST/TemplateName.h" | |||
24 | #include "clang/AST/Type.h" | |||
25 | #include "clang/AST/TypeLoc.h" | |||
26 | #include "clang/Basic/Diagnostic.h" | |||
27 | #include "clang/Basic/LLVM.h" | |||
28 | #include "clang/Basic/LangOptions.h" | |||
29 | #include "clang/Basic/SourceLocation.h" | |||
30 | #include "llvm/ADT/APSInt.h" | |||
31 | #include "llvm/ADT/FoldingSet.h" | |||
32 | #include "llvm/ADT/SmallString.h" | |||
33 | #include "llvm/ADT/StringExtras.h" | |||
34 | #include "llvm/ADT/StringRef.h" | |||
35 | #include "llvm/Support/Casting.h" | |||
36 | #include "llvm/Support/Compiler.h" | |||
37 | #include "llvm/Support/ErrorHandling.h" | |||
38 | #include "llvm/Support/raw_ostream.h" | |||
39 | #include <cassert> | |||
40 | #include <cstddef> | |||
41 | #include <cstdint> | |||
42 | #include <cstring> | |||
43 | #include <optional> | |||
44 | ||||
45 | using namespace clang; | |||
46 | ||||
47 | /// Print a template integral argument value. | |||
48 | /// | |||
49 | /// \param TemplArg the TemplateArgument instance to print. | |||
50 | /// | |||
51 | /// \param Out the raw_ostream instance to use for printing. | |||
52 | /// | |||
53 | /// \param Policy the printing policy for EnumConstantDecl printing. | |||
54 | /// | |||
55 | /// \param IncludeType If set, ensure that the type of the expression printed | |||
56 | /// matches the type of the template argument. | |||
57 | static void printIntegral(const TemplateArgument &TemplArg, raw_ostream &Out, | |||
58 | const PrintingPolicy &Policy, bool IncludeType) { | |||
59 | const Type *T = TemplArg.getIntegralType().getTypePtr(); | |||
60 | const llvm::APSInt &Val = TemplArg.getAsIntegral(); | |||
61 | ||||
62 | if (Policy.UseEnumerators) { | |||
63 | if (const EnumType *ET = T->getAs<EnumType>()) { | |||
64 | for (const EnumConstantDecl *ECD : ET->getDecl()->enumerators()) { | |||
65 | // In Sema::CheckTemplateArugment, enum template arguments value are | |||
66 | // extended to the size of the integer underlying the enum type. This | |||
67 | // may create a size difference between the enum value and template | |||
68 | // argument value, requiring isSameValue here instead of operator==. | |||
69 | if (llvm::APSInt::isSameValue(ECD->getInitVal(), Val)) { | |||
70 | ECD->printQualifiedName(Out, Policy); | |||
71 | return; | |||
72 | } | |||
73 | } | |||
74 | } | |||
75 | } | |||
76 | ||||
77 | if (Policy.MSVCFormatting) | |||
78 | IncludeType = false; | |||
79 | ||||
80 | if (T->isBooleanType()) { | |||
81 | if (!Policy.MSVCFormatting) | |||
82 | Out << (Val.getBoolValue() ? "true" : "false"); | |||
83 | else | |||
84 | Out << Val; | |||
85 | } else if (T->isCharType()) { | |||
86 | if (IncludeType) { | |||
87 | if (T->isSpecificBuiltinType(BuiltinType::SChar)) | |||
88 | Out << "(signed char)"; | |||
89 | else if (T->isSpecificBuiltinType(BuiltinType::UChar)) | |||
90 | Out << "(unsigned char)"; | |||
91 | } | |||
92 | CharacterLiteral::print(Val.getZExtValue(), CharacterLiteral::Ascii, Out); | |||
93 | } else if (T->isAnyCharacterType() && !Policy.MSVCFormatting) { | |||
94 | CharacterLiteral::CharacterKind Kind; | |||
95 | if (T->isWideCharType()) | |||
96 | Kind = CharacterLiteral::Wide; | |||
97 | else if (T->isChar8Type()) | |||
98 | Kind = CharacterLiteral::UTF8; | |||
99 | else if (T->isChar16Type()) | |||
100 | Kind = CharacterLiteral::UTF16; | |||
101 | else if (T->isChar32Type()) | |||
102 | Kind = CharacterLiteral::UTF32; | |||
103 | else | |||
104 | Kind = CharacterLiteral::Ascii; | |||
105 | CharacterLiteral::print(Val.getExtValue(), Kind, Out); | |||
106 | } else if (IncludeType) { | |||
107 | if (const auto *BT = T->getAs<BuiltinType>()) { | |||
108 | switch (BT->getKind()) { | |||
109 | case BuiltinType::ULongLong: | |||
110 | Out << Val << "ULL"; | |||
111 | break; | |||
112 | case BuiltinType::LongLong: | |||
113 | Out << Val << "LL"; | |||
114 | break; | |||
115 | case BuiltinType::ULong: | |||
116 | Out << Val << "UL"; | |||
117 | break; | |||
118 | case BuiltinType::Long: | |||
119 | Out << Val << "L"; | |||
120 | break; | |||
121 | case BuiltinType::UInt: | |||
122 | Out << Val << "U"; | |||
123 | break; | |||
124 | case BuiltinType::Int: | |||
125 | Out << Val; | |||
126 | break; | |||
127 | default: | |||
128 | Out << "(" << T->getCanonicalTypeInternal().getAsString(Policy) << ")" | |||
129 | << Val; | |||
130 | break; | |||
131 | } | |||
132 | } else | |||
133 | Out << "(" << T->getCanonicalTypeInternal().getAsString(Policy) << ")" | |||
134 | << Val; | |||
135 | } else | |||
136 | Out << Val; | |||
137 | } | |||
138 | ||||
139 | static unsigned getArrayDepth(QualType type) { | |||
140 | unsigned count = 0; | |||
141 | while (const auto *arrayType = type->getAsArrayTypeUnsafe()) { | |||
142 | count++; | |||
143 | type = arrayType->getElementType(); | |||
144 | } | |||
145 | return count; | |||
146 | } | |||
147 | ||||
148 | static bool needsAmpersandOnTemplateArg(QualType paramType, QualType argType) { | |||
149 | // Generally, if the parameter type is a pointer, we must be taking the | |||
150 | // address of something and need a &. However, if the argument is an array, | |||
151 | // this could be implicit via array-to-pointer decay. | |||
152 | if (!paramType->isPointerType()) | |||
153 | return paramType->isMemberPointerType(); | |||
154 | if (argType->isArrayType()) | |||
155 | return getArrayDepth(argType) == getArrayDepth(paramType->getPointeeType()); | |||
156 | return true; | |||
157 | } | |||
158 | ||||
159 | //===----------------------------------------------------------------------===// | |||
160 | // TemplateArgument Implementation | |||
161 | //===----------------------------------------------------------------------===// | |||
162 | ||||
163 | TemplateArgument::TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, | |||
164 | QualType Type, bool IsDefaulted) { | |||
165 | Integer.Kind = Integral; | |||
166 | Integer.IsDefaulted = IsDefaulted; | |||
167 | // Copy the APSInt value into our decomposed form. | |||
168 | Integer.BitWidth = Value.getBitWidth(); | |||
169 | Integer.IsUnsigned = Value.isUnsigned(); | |||
170 | // If the value is large, we have to get additional memory from the ASTContext | |||
171 | unsigned NumWords = Value.getNumWords(); | |||
172 | if (NumWords > 1) { | |||
173 | void *Mem = Ctx.Allocate(NumWords * sizeof(uint64_t)); | |||
174 | std::memcpy(Mem, Value.getRawData(), NumWords * sizeof(uint64_t)); | |||
175 | Integer.pVal = static_cast<uint64_t *>(Mem); | |||
176 | } else { | |||
177 | Integer.VAL = Value.getZExtValue(); | |||
178 | } | |||
179 | ||||
180 | Integer.Type = Type.getAsOpaquePtr(); | |||
181 | } | |||
182 | ||||
183 | TemplateArgument | |||
184 | TemplateArgument::CreatePackCopy(ASTContext &Context, | |||
185 | ArrayRef<TemplateArgument> Args) { | |||
186 | if (Args.empty()) | |||
187 | return getEmptyPack(); | |||
188 | ||||
189 | return TemplateArgument(Args.copy(Context)); | |||
190 | } | |||
191 | ||||
192 | TemplateArgumentDependence TemplateArgument::getDependence() const { | |||
193 | auto Deps = TemplateArgumentDependence::None; | |||
194 | switch (getKind()) { | |||
195 | case Null: | |||
196 | llvm_unreachable("Should not have a NULL template argument")::llvm::llvm_unreachable_internal("Should not have a NULL template argument" , "clang/lib/AST/TemplateBase.cpp", 196); | |||
197 | ||||
198 | case Type: | |||
199 | Deps = toTemplateArgumentDependence(getAsType()->getDependence()); | |||
200 | if (isa<PackExpansionType>(getAsType())) | |||
201 | Deps |= TemplateArgumentDependence::Dependent; | |||
202 | return Deps; | |||
203 | ||||
204 | case Template: | |||
205 | return toTemplateArgumentDependence(getAsTemplate().getDependence()); | |||
206 | ||||
207 | case TemplateExpansion: | |||
208 | return TemplateArgumentDependence::Dependent | | |||
209 | TemplateArgumentDependence::Instantiation; | |||
210 | ||||
211 | case Declaration: { | |||
212 | auto *DC = dyn_cast<DeclContext>(getAsDecl()); | |||
213 | if (!DC) | |||
214 | DC = getAsDecl()->getDeclContext(); | |||
215 | if (DC->isDependentContext()) | |||
216 | Deps = TemplateArgumentDependence::Dependent | | |||
217 | TemplateArgumentDependence::Instantiation; | |||
218 | return Deps; | |||
219 | } | |||
220 | ||||
221 | case NullPtr: | |||
222 | case Integral: | |||
223 | return TemplateArgumentDependence::None; | |||
224 | ||||
225 | case Expression: | |||
226 | Deps = toTemplateArgumentDependence(getAsExpr()->getDependence()); | |||
227 | if (isa<PackExpansionExpr>(getAsExpr())) | |||
228 | Deps |= TemplateArgumentDependence::Dependent | | |||
229 | TemplateArgumentDependence::Instantiation; | |||
230 | return Deps; | |||
231 | ||||
232 | case Pack: | |||
233 | for (const auto &P : pack_elements()) | |||
234 | Deps |= P.getDependence(); | |||
235 | return Deps; | |||
236 | } | |||
237 | llvm_unreachable("unhandled ArgKind")::llvm::llvm_unreachable_internal("unhandled ArgKind", "clang/lib/AST/TemplateBase.cpp" , 237); | |||
238 | } | |||
239 | ||||
240 | bool TemplateArgument::isDependent() const { | |||
241 | return getDependence() & TemplateArgumentDependence::Dependent; | |||
242 | } | |||
243 | ||||
244 | bool TemplateArgument::isInstantiationDependent() const { | |||
245 | return getDependence() & TemplateArgumentDependence::Instantiation; | |||
246 | } | |||
247 | ||||
248 | bool TemplateArgument::isPackExpansion() const { | |||
249 | switch (getKind()) { | |||
250 | case Null: | |||
251 | case Declaration: | |||
252 | case Integral: | |||
253 | case Pack: | |||
254 | case Template: | |||
255 | case NullPtr: | |||
256 | return false; | |||
257 | ||||
258 | case TemplateExpansion: | |||
259 | return true; | |||
260 | ||||
261 | case Type: | |||
262 | return isa<PackExpansionType>(getAsType()); | |||
263 | ||||
264 | case Expression: | |||
265 | return isa<PackExpansionExpr>(getAsExpr()); | |||
266 | } | |||
267 | ||||
268 | llvm_unreachable("Invalid TemplateArgument Kind!")::llvm::llvm_unreachable_internal("Invalid TemplateArgument Kind!" , "clang/lib/AST/TemplateBase.cpp", 268); | |||
269 | } | |||
270 | ||||
271 | bool TemplateArgument::containsUnexpandedParameterPack() const { | |||
272 | return getDependence() & TemplateArgumentDependence::UnexpandedPack; | |||
273 | } | |||
274 | ||||
275 | std::optional<unsigned> TemplateArgument::getNumTemplateExpansions() const { | |||
276 | assert(getKind() == TemplateExpansion)(static_cast <bool> (getKind() == TemplateExpansion) ? void (0) : __assert_fail ("getKind() == TemplateExpansion", "clang/lib/AST/TemplateBase.cpp" , 276, __extension__ __PRETTY_FUNCTION__)); | |||
277 | if (TemplateArg.NumExpansions) | |||
278 | return TemplateArg.NumExpansions - 1; | |||
279 | ||||
280 | return std::nullopt; | |||
281 | } | |||
282 | ||||
283 | QualType TemplateArgument::getNonTypeTemplateArgumentType() const { | |||
284 | switch (getKind()) { | |||
285 | case TemplateArgument::Null: | |||
286 | case TemplateArgument::Type: | |||
287 | case TemplateArgument::Template: | |||
288 | case TemplateArgument::TemplateExpansion: | |||
289 | case TemplateArgument::Pack: | |||
290 | return QualType(); | |||
291 | ||||
292 | case TemplateArgument::Integral: | |||
293 | return getIntegralType(); | |||
294 | ||||
295 | case TemplateArgument::Expression: | |||
296 | return getAsExpr()->getType(); | |||
297 | ||||
298 | case TemplateArgument::Declaration: | |||
299 | return getParamTypeForDecl(); | |||
300 | ||||
301 | case TemplateArgument::NullPtr: | |||
302 | return getNullPtrType(); | |||
303 | } | |||
304 | ||||
305 | llvm_unreachable("Invalid TemplateArgument Kind!")::llvm::llvm_unreachable_internal("Invalid TemplateArgument Kind!" , "clang/lib/AST/TemplateBase.cpp", 305); | |||
306 | } | |||
307 | ||||
308 | void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, | |||
309 | const ASTContext &Context) const { | |||
310 | ID.AddInteger(getKind()); | |||
311 | switch (getKind()) { | |||
312 | case Null: | |||
313 | break; | |||
314 | ||||
315 | case Type: | |||
316 | getAsType().Profile(ID); | |||
317 | break; | |||
318 | ||||
319 | case NullPtr: | |||
320 | getNullPtrType().Profile(ID); | |||
321 | break; | |||
322 | ||||
323 | case Declaration: | |||
324 | getParamTypeForDecl().Profile(ID); | |||
325 | ID.AddPointer(getAsDecl()); | |||
326 | break; | |||
327 | ||||
328 | case TemplateExpansion: | |||
329 | ID.AddInteger(TemplateArg.NumExpansions); | |||
330 | LLVM_FALLTHROUGH[[fallthrough]]; | |||
331 | case Template: | |||
332 | getAsTemplateOrTemplatePattern().Profile(ID); | |||
333 | break; | |||
334 | ||||
335 | case Integral: | |||
336 | getAsIntegral().Profile(ID); | |||
337 | getIntegralType().Profile(ID); | |||
338 | break; | |||
339 | ||||
340 | case Expression: | |||
341 | getAsExpr()->Profile(ID, Context, true); | |||
342 | break; | |||
343 | ||||
344 | case Pack: | |||
345 | ID.AddInteger(Args.NumArgs); | |||
346 | for (unsigned I = 0; I != Args.NumArgs; ++I) | |||
347 | Args.Args[I].Profile(ID, Context); | |||
348 | } | |||
349 | } | |||
350 | ||||
351 | bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const { | |||
352 | if (getKind() != Other.getKind()) return false; | |||
353 | ||||
354 | switch (getKind()) { | |||
355 | case Null: | |||
356 | case Type: | |||
357 | case Expression: | |||
358 | case NullPtr: | |||
359 | return TypeOrValue.V == Other.TypeOrValue.V; | |||
360 | ||||
361 | case Template: | |||
362 | case TemplateExpansion: | |||
363 | return TemplateArg.Name == Other.TemplateArg.Name && | |||
364 | TemplateArg.NumExpansions == Other.TemplateArg.NumExpansions; | |||
365 | ||||
366 | case Declaration: | |||
367 | return getAsDecl() == Other.getAsDecl() && | |||
368 | getParamTypeForDecl() == Other.getParamTypeForDecl(); | |||
369 | ||||
370 | case Integral: | |||
371 | return getIntegralType() == Other.getIntegralType() && | |||
372 | getAsIntegral() == Other.getAsIntegral(); | |||
373 | ||||
374 | case Pack: | |||
375 | if (Args.NumArgs != Other.Args.NumArgs) return false; | |||
376 | for (unsigned I = 0, E = Args.NumArgs; I != E; ++I) | |||
377 | if (!Args.Args[I].structurallyEquals(Other.Args.Args[I])) | |||
378 | return false; | |||
379 | return true; | |||
380 | } | |||
381 | ||||
382 | llvm_unreachable("Invalid TemplateArgument Kind!")::llvm::llvm_unreachable_internal("Invalid TemplateArgument Kind!" , "clang/lib/AST/TemplateBase.cpp", 382); | |||
383 | } | |||
384 | ||||
385 | TemplateArgument TemplateArgument::getPackExpansionPattern() const { | |||
386 | assert(isPackExpansion())(static_cast <bool> (isPackExpansion()) ? void (0) : __assert_fail ("isPackExpansion()", "clang/lib/AST/TemplateBase.cpp", 386, __extension__ __PRETTY_FUNCTION__)); | |||
387 | ||||
388 | switch (getKind()) { | |||
389 | case Type: | |||
390 | return getAsType()->castAs<PackExpansionType>()->getPattern(); | |||
391 | ||||
392 | case Expression: | |||
393 | return cast<PackExpansionExpr>(getAsExpr())->getPattern(); | |||
394 | ||||
395 | case TemplateExpansion: | |||
396 | return TemplateArgument(getAsTemplateOrTemplatePattern()); | |||
397 | ||||
398 | case Declaration: | |||
399 | case Integral: | |||
400 | case Pack: | |||
401 | case Null: | |||
402 | case Template: | |||
403 | case NullPtr: | |||
404 | return TemplateArgument(); | |||
405 | } | |||
406 | ||||
407 | llvm_unreachable("Invalid TemplateArgument Kind!")::llvm::llvm_unreachable_internal("Invalid TemplateArgument Kind!" , "clang/lib/AST/TemplateBase.cpp", 407); | |||
408 | } | |||
409 | ||||
410 | void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out, | |||
411 | bool IncludeType) const { | |||
412 | ||||
413 | switch (getKind()) { | |||
414 | case Null: | |||
415 | Out << "(no value)"; | |||
416 | break; | |||
417 | ||||
418 | case Type: { | |||
419 | PrintingPolicy SubPolicy(Policy); | |||
420 | SubPolicy.SuppressStrongLifetime = true; | |||
421 | getAsType().print(Out, SubPolicy); | |||
422 | break; | |||
423 | } | |||
424 | ||||
425 | case Declaration: { | |||
426 | NamedDecl *ND = getAsDecl(); | |||
427 | if (getParamTypeForDecl()->isRecordType()) { | |||
428 | if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) { | |||
429 | TPO->getType().getUnqualifiedType().print(Out, Policy); | |||
430 | TPO->printAsInit(Out, Policy); | |||
431 | break; | |||
432 | } | |||
433 | } | |||
434 | if (auto *VD = dyn_cast<ValueDecl>(ND)) { | |||
435 | if (needsAmpersandOnTemplateArg(getParamTypeForDecl(), VD->getType())) | |||
436 | Out << "&"; | |||
437 | } | |||
438 | ND->printQualifiedName(Out); | |||
439 | break; | |||
440 | } | |||
441 | ||||
442 | case NullPtr: | |||
443 | // FIXME: Include the type if it's not obvious from the context. | |||
444 | Out << "nullptr"; | |||
445 | break; | |||
446 | ||||
447 | case Template: | |||
448 | getAsTemplate().print(Out, Policy, TemplateName::Qualified::Fully); | |||
449 | break; | |||
450 | ||||
451 | case TemplateExpansion: | |||
452 | getAsTemplateOrTemplatePattern().print(Out, Policy); | |||
453 | Out << "..."; | |||
454 | break; | |||
455 | ||||
456 | case Integral: | |||
457 | printIntegral(*this, Out, Policy, IncludeType); | |||
458 | break; | |||
459 | ||||
460 | case Expression: | |||
461 | getAsExpr()->printPretty(Out, nullptr, Policy); | |||
462 | break; | |||
463 | ||||
464 | case Pack: | |||
465 | Out << "<"; | |||
466 | bool First = true; | |||
467 | for (const auto &P : pack_elements()) { | |||
468 | if (First) | |||
469 | First = false; | |||
470 | else | |||
471 | Out << ", "; | |||
472 | ||||
473 | P.print(Policy, Out, IncludeType); | |||
474 | } | |||
475 | Out << ">"; | |||
476 | break; | |||
477 | } | |||
478 | } | |||
479 | ||||
480 | void TemplateArgument::dump(raw_ostream &Out) const { | |||
481 | LangOptions LO; // FIXME! see also TemplateName::dump(). | |||
482 | LO.CPlusPlus = true; | |||
483 | LO.Bool = true; | |||
484 | print(PrintingPolicy(LO), Out, /*IncludeType*/ true); | |||
485 | } | |||
486 | ||||
487 | LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) void TemplateArgument::dump() const { dump(llvm::errs()); } | |||
488 | ||||
489 | //===----------------------------------------------------------------------===// | |||
490 | // TemplateArgumentLoc Implementation | |||
491 | //===----------------------------------------------------------------------===// | |||
492 | ||||
493 | SourceRange TemplateArgumentLoc::getSourceRange() const { | |||
494 | switch (Argument.getKind()) { | |||
495 | case TemplateArgument::Expression: | |||
496 | return getSourceExpression()->getSourceRange(); | |||
497 | ||||
498 | case TemplateArgument::Declaration: | |||
499 | return getSourceDeclExpression()->getSourceRange(); | |||
500 | ||||
501 | case TemplateArgument::NullPtr: | |||
502 | return getSourceNullPtrExpression()->getSourceRange(); | |||
503 | ||||
504 | case TemplateArgument::Type: | |||
505 | if (TypeSourceInfo *TSI = getTypeSourceInfo()) | |||
506 | return TSI->getTypeLoc().getSourceRange(); | |||
507 | else | |||
508 | return SourceRange(); | |||
509 | ||||
510 | case TemplateArgument::Template: | |||
511 | if (getTemplateQualifierLoc()) | |||
512 | return SourceRange(getTemplateQualifierLoc().getBeginLoc(), | |||
513 | getTemplateNameLoc()); | |||
514 | return SourceRange(getTemplateNameLoc()); | |||
515 | ||||
516 | case TemplateArgument::TemplateExpansion: | |||
517 | if (getTemplateQualifierLoc()) | |||
518 | return SourceRange(getTemplateQualifierLoc().getBeginLoc(), | |||
519 | getTemplateEllipsisLoc()); | |||
520 | return SourceRange(getTemplateNameLoc(), getTemplateEllipsisLoc()); | |||
521 | ||||
522 | case TemplateArgument::Integral: | |||
523 | return getSourceIntegralExpression()->getSourceRange(); | |||
524 | ||||
525 | case TemplateArgument::Pack: | |||
526 | case TemplateArgument::Null: | |||
527 | return SourceRange(); | |||
528 | } | |||
529 | ||||
530 | llvm_unreachable("Invalid TemplateArgument Kind!")::llvm::llvm_unreachable_internal("Invalid TemplateArgument Kind!" , "clang/lib/AST/TemplateBase.cpp", 530); | |||
531 | } | |||
532 | ||||
533 | template <typename T> | |||
534 | static const T &DiagTemplateArg(const T &DB, const TemplateArgument &Arg) { | |||
535 | switch (Arg.getKind()) { | |||
536 | case TemplateArgument::Null: | |||
537 | // This is bad, but not as bad as crashing because of argument | |||
538 | // count mismatches. | |||
539 | return DB << "(null template argument)"; | |||
540 | ||||
541 | case TemplateArgument::Type: | |||
542 | return DB << Arg.getAsType(); | |||
543 | ||||
544 | case TemplateArgument::Declaration: | |||
545 | return DB << Arg.getAsDecl(); | |||
546 | ||||
547 | case TemplateArgument::NullPtr: | |||
548 | return DB << "nullptr"; | |||
549 | ||||
550 | case TemplateArgument::Integral: | |||
551 | return DB << toString(Arg.getAsIntegral(), 10); | |||
552 | ||||
553 | case TemplateArgument::Template: | |||
554 | return DB << Arg.getAsTemplate(); | |||
555 | ||||
556 | case TemplateArgument::TemplateExpansion: | |||
557 | return DB << Arg.getAsTemplateOrTemplatePattern() << "..."; | |||
558 | ||||
559 | case TemplateArgument::Expression: { | |||
560 | // This shouldn't actually ever happen, so it's okay that we're | |||
561 | // regurgitating an expression here. | |||
562 | // FIXME: We're guessing at LangOptions! | |||
563 | SmallString<32> Str; | |||
564 | llvm::raw_svector_ostream OS(Str); | |||
565 | LangOptions LangOpts; | |||
566 | LangOpts.CPlusPlus = true; | |||
567 | PrintingPolicy Policy(LangOpts); | |||
568 | Arg.getAsExpr()->printPretty(OS, nullptr, Policy); | |||
569 | return DB << OS.str(); | |||
570 | } | |||
571 | ||||
572 | case TemplateArgument::Pack: { | |||
573 | // FIXME: We're guessing at LangOptions! | |||
574 | SmallString<32> Str; | |||
575 | llvm::raw_svector_ostream OS(Str); | |||
576 | LangOptions LangOpts; | |||
577 | LangOpts.CPlusPlus = true; | |||
578 | PrintingPolicy Policy(LangOpts); | |||
579 | Arg.print(Policy, OS, /*IncludeType*/ true); | |||
580 | return DB << OS.str(); | |||
581 | } | |||
582 | } | |||
583 | ||||
584 | llvm_unreachable("Invalid TemplateArgument Kind!")::llvm::llvm_unreachable_internal("Invalid TemplateArgument Kind!" , "clang/lib/AST/TemplateBase.cpp", 584); | |||
585 | } | |||
586 | ||||
587 | const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB, | |||
588 | const TemplateArgument &Arg) { | |||
589 | return DiagTemplateArg(DB, Arg); | |||
590 | } | |||
591 | ||||
592 | clang::TemplateArgumentLocInfo::TemplateArgumentLocInfo( | |||
593 | ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, | |||
594 | SourceLocation TemplateNameLoc, SourceLocation EllipsisLoc) { | |||
595 | TemplateTemplateArgLocInfo *Template = new (Ctx) TemplateTemplateArgLocInfo; | |||
596 | Template->Qualifier = QualifierLoc.getNestedNameSpecifier(); | |||
597 | Template->QualifierLocData = QualifierLoc.getOpaqueData(); | |||
598 | Template->TemplateNameLoc = TemplateNameLoc; | |||
599 | Template->EllipsisLoc = EllipsisLoc; | |||
600 | Pointer = Template; | |||
601 | } | |||
602 | ||||
603 | const ASTTemplateArgumentListInfo * | |||
604 | ASTTemplateArgumentListInfo::Create(const ASTContext &C, | |||
605 | const TemplateArgumentListInfo &List) { | |||
606 | std::size_t size = totalSizeToAlloc<TemplateArgumentLoc>(List.size()); | |||
607 | void *Mem = C.Allocate(size, alignof(ASTTemplateArgumentListInfo)); | |||
608 | return new (Mem) ASTTemplateArgumentListInfo(List); | |||
609 | } | |||
610 | ||||
611 | const ASTTemplateArgumentListInfo * | |||
612 | ASTTemplateArgumentListInfo::Create(const ASTContext &C, | |||
613 | const ASTTemplateArgumentListInfo *List) { | |||
614 | if (!List) | |||
| ||||
615 | return nullptr; | |||
616 | std::size_t size = | |||
617 | totalSizeToAlloc<TemplateArgumentLoc>(List->getNumTemplateArgs()); | |||
618 | void *Mem = C.Allocate(size, alignof(ASTTemplateArgumentListInfo)); | |||
619 | return new (Mem) ASTTemplateArgumentListInfo(List); | |||
620 | } | |||
621 | ||||
622 | ASTTemplateArgumentListInfo::ASTTemplateArgumentListInfo( | |||
623 | const TemplateArgumentListInfo &Info) { | |||
624 | LAngleLoc = Info.getLAngleLoc(); | |||
625 | RAngleLoc = Info.getRAngleLoc(); | |||
626 | NumTemplateArgs = Info.size(); | |||
627 | ||||
628 | TemplateArgumentLoc *ArgBuffer = getTrailingObjects<TemplateArgumentLoc>(); | |||
629 | for (unsigned i = 0; i != NumTemplateArgs; ++i) | |||
630 | new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]); | |||
631 | } | |||
632 | ||||
633 | ASTTemplateArgumentListInfo::ASTTemplateArgumentListInfo( | |||
634 | const ASTTemplateArgumentListInfo *Info) { | |||
635 | LAngleLoc = Info->getLAngleLoc(); | |||
636 | RAngleLoc = Info->getRAngleLoc(); | |||
637 | NumTemplateArgs = Info->getNumTemplateArgs(); | |||
638 | ||||
639 | TemplateArgumentLoc *ArgBuffer = getTrailingObjects<TemplateArgumentLoc>(); | |||
640 | for (unsigned i = 0; i != NumTemplateArgs; ++i) | |||
641 | new (&ArgBuffer[i]) TemplateArgumentLoc((*Info)[i]); | |||
| ||||
642 | } | |||
643 | ||||
644 | void ASTTemplateKWAndArgsInfo::initializeFrom( | |||
645 | SourceLocation TemplateKWLoc, const TemplateArgumentListInfo &Info, | |||
646 | TemplateArgumentLoc *OutArgArray) { | |||
647 | this->TemplateKWLoc = TemplateKWLoc; | |||
648 | LAngleLoc = Info.getLAngleLoc(); | |||
649 | RAngleLoc = Info.getRAngleLoc(); | |||
650 | NumTemplateArgs = Info.size(); | |||
651 | ||||
652 | for (unsigned i = 0; i != NumTemplateArgs; ++i) | |||
653 | new (&OutArgArray[i]) TemplateArgumentLoc(Info[i]); | |||
654 | } | |||
655 | ||||
656 | void ASTTemplateKWAndArgsInfo::initializeFrom(SourceLocation TemplateKWLoc) { | |||
657 | assert(TemplateKWLoc.isValid())(static_cast <bool> (TemplateKWLoc.isValid()) ? void (0 ) : __assert_fail ("TemplateKWLoc.isValid()", "clang/lib/AST/TemplateBase.cpp" , 657, __extension__ __PRETTY_FUNCTION__)); | |||
658 | LAngleLoc = SourceLocation(); | |||
659 | RAngleLoc = SourceLocation(); | |||
660 | this->TemplateKWLoc = TemplateKWLoc; | |||
661 | NumTemplateArgs = 0; | |||
662 | } | |||
663 | ||||
664 | void ASTTemplateKWAndArgsInfo::initializeFrom( | |||
665 | SourceLocation TemplateKWLoc, const TemplateArgumentListInfo &Info, | |||
666 | TemplateArgumentLoc *OutArgArray, TemplateArgumentDependence &Deps) { | |||
667 | this->TemplateKWLoc = TemplateKWLoc; | |||
668 | LAngleLoc = Info.getLAngleLoc(); | |||
669 | RAngleLoc = Info.getRAngleLoc(); | |||
670 | NumTemplateArgs = Info.size(); | |||
671 | ||||
672 | for (unsigned i = 0; i != NumTemplateArgs; ++i) { | |||
673 | Deps |= Info[i].getArgument().getDependence(); | |||
674 | ||||
675 | new (&OutArgArray[i]) TemplateArgumentLoc(Info[i]); | |||
676 | } | |||
677 | } | |||
678 | ||||
679 | void ASTTemplateKWAndArgsInfo::copyInto(const TemplateArgumentLoc *ArgArray, | |||
680 | TemplateArgumentListInfo &Info) const { | |||
681 | Info.setLAngleLoc(LAngleLoc); | |||
682 | Info.setRAngleLoc(RAngleLoc); | |||
683 | for (unsigned I = 0; I != NumTemplateArgs; ++I) | |||
684 | Info.addArgument(ArgArray[I]); | |||
685 | } |
1 | //===--- TrailingObjects.h - Variable-length classes ------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | /// |
9 | /// \file |
10 | /// This header defines support for implementing classes that have |
11 | /// some trailing object (or arrays of objects) appended to them. The |
12 | /// main purpose is to make it obvious where this idiom is being used, |
13 | /// and to make the usage more idiomatic and more difficult to get |
14 | /// wrong. |
15 | /// |
16 | /// The TrailingObject template abstracts away the reinterpret_cast, |
17 | /// pointer arithmetic, and size calculations used for the allocation |
18 | /// and access of appended arrays of objects, and takes care that they |
19 | /// are all allocated at their required alignment. Additionally, it |
20 | /// ensures that the base type is final -- deriving from a class that |
21 | /// expects data appended immediately after it is typically not safe. |
22 | /// |
23 | /// Users are expected to derive from this template, and provide |
24 | /// numTrailingObjects implementations for each trailing type except |
25 | /// the last, e.g. like this sample: |
26 | /// |
27 | /// \code |
28 | /// class VarLengthObj : private TrailingObjects<VarLengthObj, int, double> { |
29 | /// friend TrailingObjects; |
30 | /// |
31 | /// unsigned NumInts, NumDoubles; |
32 | /// size_t numTrailingObjects(OverloadToken<int>) const { return NumInts; } |
33 | /// }; |
34 | /// \endcode |
35 | /// |
36 | /// You can access the appended arrays via 'getTrailingObjects', and |
37 | /// determine the size needed for allocation via |
38 | /// 'additionalSizeToAlloc' and 'totalSizeToAlloc'. |
39 | /// |
40 | /// All the methods implemented by this class are are intended for use |
41 | /// by the implementation of the class, not as part of its interface |
42 | /// (thus, private inheritance is suggested). |
43 | /// |
44 | //===----------------------------------------------------------------------===// |
45 | |
46 | #ifndef LLVM_SUPPORT_TRAILINGOBJECTS_H |
47 | #define LLVM_SUPPORT_TRAILINGOBJECTS_H |
48 | |
49 | #include "llvm/Support/AlignOf.h" |
50 | #include "llvm/Support/Alignment.h" |
51 | #include "llvm/Support/Compiler.h" |
52 | #include "llvm/Support/MathExtras.h" |
53 | #include "llvm/Support/type_traits.h" |
54 | #include <new> |
55 | #include <type_traits> |
56 | |
57 | namespace llvm { |
58 | |
59 | namespace trailing_objects_internal { |
60 | /// Helper template to calculate the max alignment requirement for a set of |
61 | /// objects. |
62 | template <typename First, typename... Rest> class AlignmentCalcHelper { |
63 | private: |
64 | enum { |
65 | FirstAlignment = alignof(First), |
66 | RestAlignment = AlignmentCalcHelper<Rest...>::Alignment, |
67 | }; |
68 | |
69 | public: |
70 | enum { |
71 | Alignment = FirstAlignment > RestAlignment ? FirstAlignment : RestAlignment |
72 | }; |
73 | }; |
74 | |
75 | template <typename First> class AlignmentCalcHelper<First> { |
76 | public: |
77 | enum { Alignment = alignof(First) }; |
78 | }; |
79 | |
80 | /// The base class for TrailingObjects* classes. |
81 | class TrailingObjectsBase { |
82 | protected: |
83 | /// OverloadToken's purpose is to allow specifying function overloads |
84 | /// for different types, without actually taking the types as |
85 | /// parameters. (Necessary because member function templates cannot |
86 | /// be specialized, so overloads must be used instead of |
87 | /// specialization.) |
88 | template <typename T> struct OverloadToken {}; |
89 | }; |
90 | |
91 | // Just a little helper for transforming a type pack into the same |
92 | // number of a different type. e.g.: |
93 | // ExtractSecondType<Foo..., int>::type |
94 | template <typename Ty1, typename Ty2> struct ExtractSecondType { |
95 | typedef Ty2 type; |
96 | }; |
97 | |
98 | // TrailingObjectsImpl is somewhat complicated, because it is a |
99 | // recursively inheriting template, in order to handle the template |
100 | // varargs. Each level of inheritance picks off a single trailing type |
101 | // then recurses on the rest. The "Align", "BaseTy", and |
102 | // "TopTrailingObj" arguments are passed through unchanged through the |
103 | // recursion. "PrevTy" is, at each level, the type handled by the |
104 | // level right above it. |
105 | |
106 | template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy, |
107 | typename... MoreTys> |
108 | class TrailingObjectsImpl { |
109 | // The main template definition is never used -- the two |
110 | // specializations cover all possibilities. |
111 | }; |
112 | |
113 | template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy, |
114 | typename NextTy, typename... MoreTys> |
115 | class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy, |
116 | MoreTys...> |
117 | : public TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, |
118 | MoreTys...> { |
119 | |
120 | typedef TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, MoreTys...> |
121 | ParentType; |
122 | |
123 | struct RequiresRealignment { |
124 | static const bool value = alignof(PrevTy) < alignof(NextTy); |
125 | }; |
126 | |
127 | static constexpr bool requiresRealignment() { |
128 | return RequiresRealignment::value; |
129 | } |
130 | |
131 | protected: |
132 | // Ensure the inherited getTrailingObjectsImpl is not hidden. |
133 | using ParentType::getTrailingObjectsImpl; |
134 | |
135 | // These two functions are helper functions for |
136 | // TrailingObjects::getTrailingObjects. They recurse to the left -- |
137 | // the result for each type in the list of trailing types depends on |
138 | // the result of calling the function on the type to the |
139 | // left. However, the function for the type to the left is |
140 | // implemented by a *subclass* of this class, so we invoke it via |
141 | // the TopTrailingObj, which is, via the |
142 | // curiously-recurring-template-pattern, the most-derived type in |
143 | // this recursion, and thus, contains all the overloads. |
144 | static const NextTy * |
145 | getTrailingObjectsImpl(const BaseTy *Obj, |
146 | TrailingObjectsBase::OverloadToken<NextTy>) { |
147 | auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( |
148 | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + |
149 | TopTrailingObj::callNumTrailingObjects( |
150 | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); |
151 | |
152 | if (requiresRealignment()) |
153 | return reinterpret_cast<const NextTy *>( |
154 | alignAddr(Ptr, Align::Of<NextTy>())); |
155 | else |
156 | return reinterpret_cast<const NextTy *>(Ptr); |
157 | } |
158 | |
159 | static NextTy * |
160 | getTrailingObjectsImpl(BaseTy *Obj, |
161 | TrailingObjectsBase::OverloadToken<NextTy>) { |
162 | auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( |
163 | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + |
164 | TopTrailingObj::callNumTrailingObjects( |
165 | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); |
166 | |
167 | if (requiresRealignment()) |
168 | return reinterpret_cast<NextTy *>(alignAddr(Ptr, Align::Of<NextTy>())); |
169 | else |
170 | return reinterpret_cast<NextTy *>(Ptr); |
171 | } |
172 | |
173 | // Helper function for TrailingObjects::additionalSizeToAlloc: this |
174 | // function recurses to superclasses, each of which requires one |
175 | // fewer size_t argument, and adds its own size. |
176 | static constexpr size_t additionalSizeToAllocImpl( |
177 | size_t SizeSoFar, size_t Count1, |
178 | typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) { |
179 | return ParentType::additionalSizeToAllocImpl( |
180 | (requiresRealignment() ? llvm::alignTo<alignof(NextTy)>(SizeSoFar) |
181 | : SizeSoFar) + |
182 | sizeof(NextTy) * Count1, |
183 | MoreCounts...); |
184 | } |
185 | }; |
186 | |
187 | // The base case of the TrailingObjectsImpl inheritance recursion, |
188 | // when there's no more trailing types. |
189 | template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy> |
190 | class alignas(Align) TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy> |
191 | : public TrailingObjectsBase { |
192 | protected: |
193 | // This is a dummy method, only here so the "using" doesn't fail -- |
194 | // it will never be called, because this function recurses backwards |
195 | // up the inheritance chain to subclasses. |
196 | static void getTrailingObjectsImpl(); |
197 | |
198 | static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) { |
199 | return SizeSoFar; |
200 | } |
201 | |
202 | template <bool CheckAlignment> static void verifyTrailingObjectsAlignment() {} |
203 | }; |
204 | |
205 | } // end namespace trailing_objects_internal |
206 | |
207 | // Finally, the main type defined in this file, the one intended for users... |
208 | |
209 | /// See the file comment for details on the usage of the |
210 | /// TrailingObjects type. |
211 | template <typename BaseTy, typename... TrailingTys> |
212 | class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl< |
213 | trailing_objects_internal::AlignmentCalcHelper< |
214 | TrailingTys...>::Alignment, |
215 | BaseTy, TrailingObjects<BaseTy, TrailingTys...>, |
216 | BaseTy, TrailingTys...> { |
217 | |
218 | template <int A, typename B, typename T, typename P, typename... M> |
219 | friend class trailing_objects_internal::TrailingObjectsImpl; |
220 | |
221 | template <typename... Tys> class Foo {}; |
222 | |
223 | typedef trailing_objects_internal::TrailingObjectsImpl< |
224 | trailing_objects_internal::AlignmentCalcHelper<TrailingTys...>::Alignment, |
225 | BaseTy, TrailingObjects<BaseTy, TrailingTys...>, BaseTy, TrailingTys...> |
226 | ParentType; |
227 | using TrailingObjectsBase = trailing_objects_internal::TrailingObjectsBase; |
228 | |
229 | using ParentType::getTrailingObjectsImpl; |
230 | |
231 | // This function contains only a static_assert BaseTy is final. The |
232 | // static_assert must be in a function, and not at class-level |
233 | // because BaseTy isn't complete at class instantiation time, but |
234 | // will be by the time this function is instantiated. |
235 | static void verifyTrailingObjectsAssertions() { |
236 | static_assert(std::is_final<BaseTy>(), "BaseTy must be final."); |
237 | } |
238 | |
239 | // These two methods are the base of the recursion for this method. |
240 | static const BaseTy * |
241 | getTrailingObjectsImpl(const BaseTy *Obj, |
242 | TrailingObjectsBase::OverloadToken<BaseTy>) { |
243 | return Obj; |
244 | } |
245 | |
246 | static BaseTy * |
247 | getTrailingObjectsImpl(BaseTy *Obj, |
248 | TrailingObjectsBase::OverloadToken<BaseTy>) { |
249 | return Obj; |
250 | } |
251 | |
252 | // callNumTrailingObjects simply calls numTrailingObjects on the |
253 | // provided Obj -- except when the type being queried is BaseTy |
254 | // itself. There is always only one of the base object, so that case |
255 | // is handled here. (An additional benefit of indirecting through |
256 | // this function is that consumers only say "friend |
257 | // TrailingObjects", and thus, only this class itself can call the |
258 | // numTrailingObjects function.) |
259 | static size_t |
260 | callNumTrailingObjects(const BaseTy *Obj, |
261 | TrailingObjectsBase::OverloadToken<BaseTy>) { |
262 | return 1; |
263 | } |
264 | |
265 | template <typename T> |
266 | static size_t callNumTrailingObjects(const BaseTy *Obj, |
267 | TrailingObjectsBase::OverloadToken<T>) { |
268 | return Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken<T>()); |
269 | } |
270 | |
271 | public: |
272 | // Make this (privately inherited) member public. |
273 | #ifndef _MSC_VER |
274 | using ParentType::OverloadToken; |
275 | #else |
276 | // An MSVC bug prevents the above from working, (last tested at CL version |
277 | // 19.28). "Class5" in TrailingObjectsTest.cpp tests the problematic case. |
278 | template <typename T> |
279 | using OverloadToken = typename ParentType::template OverloadToken<T>; |
280 | #endif |
281 | |
282 | /// Returns a pointer to the trailing object array of the given type |
283 | /// (which must be one of those specified in the class template). The |
284 | /// array may have zero or more elements in it. |
285 | template <typename T> const T *getTrailingObjects() const { |
286 | verifyTrailingObjectsAssertions(); |
287 | // Forwards to an impl function with overloads, since member |
288 | // function templates can't be specialized. |
289 | return this->getTrailingObjectsImpl( |
290 | static_cast<const BaseTy *>(this), |
291 | TrailingObjectsBase::OverloadToken<T>()); |
292 | } |
293 | |
294 | /// Returns a pointer to the trailing object array of the given type |
295 | /// (which must be one of those specified in the class template). The |
296 | /// array may have zero or more elements in it. |
297 | template <typename T> T *getTrailingObjects() { |
298 | verifyTrailingObjectsAssertions(); |
299 | // Forwards to an impl function with overloads, since member |
300 | // function templates can't be specialized. |
301 | return this->getTrailingObjectsImpl( |
302 | static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>()); |
303 | } |
304 | |
305 | /// Returns the size of the trailing data, if an object were |
306 | /// allocated with the given counts (The counts are in the same order |
307 | /// as the template arguments). This does not include the size of the |
308 | /// base object. The template arguments must be the same as those |
309 | /// used in the class; they are supplied here redundantly only so |
310 | /// that it's clear what the counts are counting in callers. |
311 | template <typename... Tys> |
312 | static constexpr std::enable_if_t< |
313 | std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t> |
314 | additionalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType< |
315 | TrailingTys, size_t>::type... Counts) { |
316 | return ParentType::additionalSizeToAllocImpl(0, Counts...); |
317 | } |
318 | |
319 | /// Returns the total size of an object if it were allocated with the |
320 | /// given trailing object counts. This is the same as |
321 | /// additionalSizeToAlloc, except it *does* include the size of the base |
322 | /// object. |
323 | template <typename... Tys> |
324 | static constexpr std::enable_if_t< |
325 | std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t> |
326 | totalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType< |
327 | TrailingTys, size_t>::type... Counts) { |
328 | return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...); |
329 | } |
330 | |
331 | TrailingObjects() = default; |
332 | TrailingObjects(const TrailingObjects &) = delete; |
333 | TrailingObjects(TrailingObjects &&) = delete; |
334 | TrailingObjects &operator=(const TrailingObjects &) = delete; |
335 | TrailingObjects &operator=(TrailingObjects &&) = delete; |
336 | |
337 | /// A type where its ::with_counts template member has a ::type member |
338 | /// suitable for use as uninitialized storage for an object with the given |
339 | /// trailing object counts. The template arguments are similar to those |
340 | /// of additionalSizeToAlloc. |
341 | /// |
342 | /// Use with FixedSizeStorageOwner, e.g.: |
343 | /// |
344 | /// \code{.cpp} |
345 | /// |
346 | /// MyObj::FixedSizeStorage<void *>::with_counts<1u>::type myStackObjStorage; |
347 | /// MyObj::FixedSizeStorageOwner |
348 | /// myStackObjOwner(new ((void *)&myStackObjStorage) MyObj); |
349 | /// MyObj *const myStackObjPtr = myStackObjOwner.get(); |
350 | /// |
351 | /// \endcode |
352 | template <typename... Tys> struct FixedSizeStorage { |
353 | template <size_t... Counts> struct with_counts { |
354 | enum { Size = totalSizeToAlloc<Tys...>(Counts...) }; |
355 | struct type { |
356 | alignas(BaseTy) char buffer[Size]; |
357 | }; |
358 | }; |
359 | }; |
360 | |
361 | /// A type that acts as the owner for an object placed into fixed storage. |
362 | class FixedSizeStorageOwner { |
363 | public: |
364 | FixedSizeStorageOwner(BaseTy *p) : p(p) {} |
365 | ~FixedSizeStorageOwner() { |
366 | assert(p && "FixedSizeStorageOwner owns null?")(static_cast <bool> (p && "FixedSizeStorageOwner owns null?" ) ? void (0) : __assert_fail ("p && \"FixedSizeStorageOwner owns null?\"" , "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 |