1 //===- MicrosoftDemangle.cpp ----------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines a demangler for MSVC-style mangled symbols. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/Demangle/MicrosoftDemangleNodes.h" 14 #include "llvm/Demangle/DemangleConfig.h" 15 #include "llvm/Demangle/Utility.h" 16 #include <cctype> 17 #include <string> 18 19 using namespace llvm; 20 using namespace ms_demangle; 21 22 #define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \ 23 case Enum::Value: \ 24 OS << Desc; \ 25 break; 26 27 // Writes a space if the last token does not end with a punctuation. 28 static void outputSpaceIfNecessary(OutputStream &OS) { 29 if (OS.empty()) 30 return; 31 32 char C = OS.back(); 33 if (std::isalnum(C) || C == '>') 34 OS << " "; 35 } 36 37 static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) { 38 switch (Q) { 39 case Q_Const: 40 OS << "const"; 41 break; 42 case Q_Volatile: 43 OS << "volatile"; 44 break; 45 case Q_Restrict: 46 OS << "__restrict"; 47 break; 48 default: 49 break; 50 } 51 } 52 53 static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q, 54 Qualifiers Mask, bool NeedSpace) { 55 if (!(Q & Mask)) 56 return NeedSpace; 57 58 if (NeedSpace) 59 OS << " "; 60 61 outputSingleQualifier(OS, Mask); 62 return true; 63 } 64 65 static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore, 66 bool SpaceAfter) { 67 if (Q == Q_None) 68 return; 69 70 size_t Pos1 = OS.getCurrentPosition(); 71 SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore); 72 SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore); 73 SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore); 74 size_t Pos2 = OS.getCurrentPosition(); 75 if (SpaceAfter && Pos2 > Pos1) 76 OS << " "; 77 } 78 79 static void outputCallingConvention(OutputStream &OS, CallingConv CC) { 80 outputSpaceIfNecessary(OS); 81 82 switch (CC) { 83 case CallingConv::Cdecl: 84 OS << "__cdecl"; 85 break; 86 case CallingConv::Fastcall: 87 OS << "__fastcall"; 88 break; 89 case CallingConv::Pascal: 90 OS << "__pascal"; 91 break; 92 case CallingConv::Regcall: 93 OS << "__regcall"; 94 break; 95 case CallingConv::Stdcall: 96 OS << "__stdcall"; 97 break; 98 case CallingConv::Thiscall: 99 OS << "__thiscall"; 100 break; 101 case CallingConv::Eabi: 102 OS << "__eabi"; 103 break; 104 case CallingConv::Vectorcall: 105 OS << "__vectorcall"; 106 break; 107 case CallingConv::Clrcall: 108 OS << "__clrcall"; 109 break; 110 default: 111 break; 112 } 113 } 114 115 std::string Node::toString(OutputFlags Flags) const { 116 OutputStream OS; 117 initializeOutputStream(nullptr, nullptr, OS, 1024); 118 this->output(OS, Flags); 119 OS << '\0'; 120 return {OS.getBuffer()}; 121 } 122 123 void TypeNode::outputQuals(bool SpaceBefore, bool SpaceAfter) const {} 124 125 void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 126 switch (PrimKind) { 127 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void"); 128 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool"); 129 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char"); 130 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char"); 131 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char"); 132 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char8, "char8_t"); 133 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t"); 134 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t"); 135 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short"); 136 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short"); 137 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int"); 138 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int"); 139 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long"); 140 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long"); 141 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64"); 142 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64"); 143 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t"); 144 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float"); 145 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double"); 146 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double"); 147 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t"); 148 } 149 outputQualifiers(OS, Quals, true, false); 150 } 151 152 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const { 153 output(OS, Flags, ", "); 154 } 155 156 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags, 157 StringView Separator) const { 158 if (Count == 0) 159 return; 160 if (Nodes[0]) 161 Nodes[0]->output(OS, Flags); 162 for (size_t I = 1; I < Count; ++I) { 163 OS << Separator; 164 Nodes[I]->output(OS, Flags); 165 } 166 } 167 168 void EncodedStringLiteralNode::output(OutputStream &OS, 169 OutputFlags Flags) const { 170 switch (Char) { 171 case CharKind::Wchar: 172 OS << "L\""; 173 break; 174 case CharKind::Char: 175 OS << "\""; 176 break; 177 case CharKind::Char16: 178 OS << "u\""; 179 break; 180 case CharKind::Char32: 181 OS << "U\""; 182 break; 183 } 184 OS << DecodedString << "\""; 185 if (IsTruncated) 186 OS << "..."; 187 } 188 189 void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const { 190 if (IsNegative) 191 OS << '-'; 192 OS << Value; 193 } 194 195 void TemplateParameterReferenceNode::output(OutputStream &OS, 196 OutputFlags Flags) const { 197 if (ThunkOffsetCount > 0) 198 OS << "{"; 199 else if (Affinity == PointerAffinity::Pointer) 200 OS << "&"; 201 202 if (Symbol) { 203 Symbol->output(OS, Flags); 204 if (ThunkOffsetCount > 0) 205 OS << ", "; 206 } 207 208 if (ThunkOffsetCount > 0) 209 OS << ThunkOffsets[0]; 210 for (int I = 1; I < ThunkOffsetCount; ++I) { 211 OS << ", " << ThunkOffsets[I]; 212 } 213 if (ThunkOffsetCount > 0) 214 OS << "}"; 215 } 216 217 void IdentifierNode::outputTemplateParameters(OutputStream &OS, 218 OutputFlags Flags) const { 219 if (!TemplateParams) 220 return; 221 OS << "<"; 222 TemplateParams->output(OS, Flags); 223 OS << ">"; 224 } 225 226 void DynamicStructorIdentifierNode::output(OutputStream &OS, 227 OutputFlags Flags) const { 228 if (IsDestructor) 229 OS << "`dynamic atexit destructor for "; 230 else 231 OS << "`dynamic initializer for "; 232 233 if (Variable) { 234 OS << "`"; 235 Variable->output(OS, Flags); 236 OS << "''"; 237 } else { 238 OS << "'"; 239 Name->output(OS, Flags); 240 OS << "''"; 241 } 242 } 243 244 void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { 245 OS << Name; 246 outputTemplateParameters(OS, Flags); 247 } 248 249 void IntrinsicFunctionIdentifierNode::output(OutputStream &OS, 250 OutputFlags Flags) const { 251 switch (Operator) { 252 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new"); 253 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete"); 254 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator="); 255 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>"); 256 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<"); 257 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!"); 258 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator=="); 259 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!="); 260 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript, 261 "operator[]"); 262 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->"); 263 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++"); 264 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--"); 265 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-"); 266 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+"); 267 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*"); 268 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&"); 269 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer, 270 "operator->*"); 271 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/"); 272 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%"); 273 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<"); 274 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<="); 275 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>"); 276 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual, 277 "operator>="); 278 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,"); 279 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()"); 280 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~"); 281 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^"); 282 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|"); 283 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&"); 284 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||"); 285 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*="); 286 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+="); 287 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-="); 288 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/="); 289 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%="); 290 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>="); 291 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<="); 292 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual, 293 "operator&="); 294 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual, 295 "operator|="); 296 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual, 297 "operator^="); 298 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'"); 299 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor, 300 "`vector deleting dtor'"); 301 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure, 302 "`default ctor closure'"); 303 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor, 304 "`scalar deleting dtor'"); 305 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter, 306 "`vector ctor iterator'"); 307 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter, 308 "`vector dtor iterator'"); 309 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter, 310 "`vector vbase ctor iterator'"); 311 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap, 312 "`virtual displacement map'"); 313 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter, 314 "`eh vector ctor iterator'"); 315 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter, 316 "`eh vector dtor iterator'"); 317 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter, 318 "`eh vector vbase ctor iterator'"); 319 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure, 320 "`copy ctor closure'"); 321 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure, 322 "`local vftable ctor closure'"); 323 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]"); 324 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete, 325 "operator delete[]"); 326 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter, 327 "`managed vector ctor iterator'"); 328 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter, 329 "`managed vector dtor iterator'"); 330 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter, 331 "`EH vector copy ctor iterator'"); 332 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter, 333 "`EH vector vbase copy ctor iterator'"); 334 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter, 335 "`vector copy ctor iterator'"); 336 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter, 337 "`vector vbase copy constructor iterator'"); 338 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter, 339 "`managed vector vbase copy constructor iterator'"); 340 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait, 341 "operator co_await"); 342 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>"); 343 case IntrinsicFunctionKind::MaxIntrinsic: 344 case IntrinsicFunctionKind::None: 345 break; 346 } 347 outputTemplateParameters(OS, Flags); 348 } 349 350 void LocalStaticGuardIdentifierNode::output(OutputStream &OS, 351 OutputFlags Flags) const { 352 if (IsThread) 353 OS << "`local static thread guard'"; 354 else 355 OS << "`local static guard'"; 356 if (ScopeIndex > 0) 357 OS << "{" << ScopeIndex << "}"; 358 } 359 360 void ConversionOperatorIdentifierNode::output(OutputStream &OS, 361 OutputFlags Flags) const { 362 OS << "operator"; 363 outputTemplateParameters(OS, Flags); 364 OS << " "; 365 TargetType->output(OS, Flags); 366 } 367 368 void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { 369 if (IsDestructor) 370 OS << "~"; 371 Class->output(OS, Flags); 372 outputTemplateParameters(OS, Flags); 373 } 374 375 void LiteralOperatorIdentifierNode::output(OutputStream &OS, 376 OutputFlags Flags) const { 377 OS << "operator \"\"" << Name; 378 outputTemplateParameters(OS, Flags); 379 } 380 381 void FunctionSignatureNode::outputPre(OutputStream &OS, 382 OutputFlags Flags) const { 383 if (FunctionClass & FC_Public) 384 OS << "public: "; 385 if (FunctionClass & FC_Protected) 386 OS << "protected: "; 387 if (FunctionClass & FC_Private) 388 OS << "private: "; 389 390 if (!(FunctionClass & FC_Global)) { 391 if (FunctionClass & FC_Static) 392 OS << "static "; 393 } 394 if (FunctionClass & FC_Virtual) 395 OS << "virtual "; 396 397 if (FunctionClass & FC_ExternC) 398 OS << "extern \"C\" "; 399 400 if (ReturnType) { 401 ReturnType->outputPre(OS, Flags); 402 OS << " "; 403 } 404 405 if (!(Flags & OF_NoCallingConvention)) 406 outputCallingConvention(OS, CallConvention); 407 } 408 409 void FunctionSignatureNode::outputPost(OutputStream &OS, 410 OutputFlags Flags) const { 411 if (!(FunctionClass & FC_NoParameterList)) { 412 OS << "("; 413 if (Params) 414 Params->output(OS, Flags); 415 else 416 OS << "void"; 417 418 if (IsVariadic) { 419 if (OS.back() != '(') 420 OS << ", "; 421 OS << "..."; 422 } 423 OS << ")"; 424 } 425 426 if (Quals & Q_Const) 427 OS << " const"; 428 if (Quals & Q_Volatile) 429 OS << " volatile"; 430 if (Quals & Q_Restrict) 431 OS << " __restrict"; 432 if (Quals & Q_Unaligned) 433 OS << " __unaligned"; 434 435 if (IsNoexcept) 436 OS << " noexcept"; 437 438 if (RefQualifier == FunctionRefQualifier::Reference) 439 OS << " &"; 440 else if (RefQualifier == FunctionRefQualifier::RValueReference) 441 OS << " &&"; 442 443 if (ReturnType) 444 ReturnType->outputPost(OS, Flags); 445 } 446 447 void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 448 OS << "[thunk]: "; 449 450 FunctionSignatureNode::outputPre(OS, Flags); 451 } 452 453 void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const { 454 if (FunctionClass & FC_StaticThisAdjust) { 455 OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'"; 456 } else if (FunctionClass & FC_VirtualThisAdjust) { 457 if (FunctionClass & FC_VirtualThisAdjustEx) { 458 OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", " 459 << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset 460 << ", " << ThisAdjust.StaticOffset << "}'"; 461 } else { 462 OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", " 463 << ThisAdjust.StaticOffset << "}'"; 464 } 465 } 466 467 FunctionSignatureNode::outputPost(OS, Flags); 468 } 469 470 void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 471 if (Pointee->kind() == NodeKind::FunctionSignature) { 472 // If this is a pointer to a function, don't output the calling convention. 473 // It needs to go inside the parentheses. 474 const FunctionSignatureNode *Sig = 475 static_cast<const FunctionSignatureNode *>(Pointee); 476 Sig->outputPre(OS, OF_NoCallingConvention); 477 } else 478 Pointee->outputPre(OS, Flags); 479 480 outputSpaceIfNecessary(OS); 481 482 if (Quals & Q_Unaligned) 483 OS << "__unaligned "; 484 485 if (Pointee->kind() == NodeKind::ArrayType) { 486 OS << "("; 487 } else if (Pointee->kind() == NodeKind::FunctionSignature) { 488 OS << "("; 489 const FunctionSignatureNode *Sig = 490 static_cast<const FunctionSignatureNode *>(Pointee); 491 outputCallingConvention(OS, Sig->CallConvention); 492 OS << " "; 493 } 494 495 if (ClassParent) { 496 ClassParent->output(OS, Flags); 497 OS << "::"; 498 } 499 500 switch (Affinity) { 501 case PointerAffinity::Pointer: 502 OS << "*"; 503 break; 504 case PointerAffinity::Reference: 505 OS << "&"; 506 break; 507 case PointerAffinity::RValueReference: 508 OS << "&&"; 509 break; 510 default: 511 assert(false); 512 } 513 outputQualifiers(OS, Quals, false, false); 514 } 515 516 void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { 517 if (Pointee->kind() == NodeKind::ArrayType || 518 Pointee->kind() == NodeKind::FunctionSignature) 519 OS << ")"; 520 521 Pointee->outputPost(OS, Flags); 522 } 523 524 void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 525 if (!(Flags & OF_NoTagSpecifier)) { 526 switch (Tag) { 527 OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class"); 528 OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct"); 529 OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union"); 530 OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum"); 531 } 532 OS << " "; 533 } 534 QualifiedName->output(OS, Flags); 535 outputQualifiers(OS, Quals, true, false); 536 } 537 538 void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} 539 540 void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 541 ElementType->outputPre(OS, Flags); 542 outputQualifiers(OS, Quals, true, false); 543 } 544 545 void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags, 546 Node *N) const { 547 assert(N->kind() == NodeKind::IntegerLiteral); 548 IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N); 549 if (ILN->Value != 0) 550 ILN->output(OS, Flags); 551 } 552 553 void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS, 554 OutputFlags Flags) const { 555 if (Dimensions->Count == 0) 556 return; 557 558 outputOneDimension(OS, Flags, Dimensions->Nodes[0]); 559 for (size_t I = 1; I < Dimensions->Count; ++I) { 560 OS << "]["; 561 outputOneDimension(OS, Flags, Dimensions->Nodes[I]); 562 } 563 } 564 565 void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { 566 OS << "["; 567 outputDimensionsImpl(OS, Flags); 568 OS << "]"; 569 570 ElementType->outputPost(OS, Flags); 571 } 572 573 void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const { 574 Name->output(OS, Flags); 575 } 576 577 void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { 578 Signature->outputPre(OS, Flags); 579 outputSpaceIfNecessary(OS); 580 Name->output(OS, Flags); 581 Signature->outputPost(OS, Flags); 582 } 583 584 void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { 585 switch (SC) { 586 case StorageClass::PrivateStatic: 587 OS << "private: static "; 588 break; 589 case StorageClass::PublicStatic: 590 OS << "public: static "; 591 break; 592 case StorageClass::ProtectedStatic: 593 OS << "protected: static "; 594 break; 595 default: 596 break; 597 } 598 599 if (Type) { 600 Type->outputPre(OS, Flags); 601 outputSpaceIfNecessary(OS); 602 } 603 Name->output(OS, Flags); 604 if (Type) 605 Type->outputPost(OS, Flags); 606 } 607 608 void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 609 Identifier->output(OS, Flags); 610 } 611 void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} 612 613 void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const { 614 Components->output(OS, Flags, "::"); 615 } 616 617 void RttiBaseClassDescriptorNode::output(OutputStream &OS, 618 OutputFlags Flags) const { 619 OS << "`RTTI Base Class Descriptor at ("; 620 OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", " 621 << this->Flags; 622 OS << ")'"; 623 } 624 625 void LocalStaticGuardVariableNode::output(OutputStream &OS, 626 OutputFlags Flags) const { 627 Name->output(OS, Flags); 628 } 629 630 void VcallThunkIdentifierNode::output(OutputStream &OS, 631 OutputFlags Flags) const { 632 OS << "`vcall'{" << OffsetInVTable << ", {flat}}"; 633 } 634 635 void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { 636 outputQualifiers(OS, Quals, false, true); 637 Name->output(OS, Flags); 638 if (TargetName) { 639 OS << "{for `"; 640 TargetName->output(OS, Flags); 641 OS << "'}"; 642 } 643 return; 644 } 645