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