| 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 | ID.AddPointer(TemplateArg.Name); | |||
| 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_v<Foo<TrailingTys...>, Foo<Tys...>>, 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_v<Foo<TrailingTys...>, Foo<Tys...>>, 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 |