mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-21 18:22:53 +01:00
d697536ac9
This change is intended as initial setup. The plan is to add more semantic checks later. I plan to update the documentation as more semantic checks are added (instead of documenting the details up front). Most of the code closely mirrors that for the Swift calling convention. Three places are marked as [FIXME: swiftasynccc]; those will be addressed once the corresponding convention is introduced in LLVM. Reviewed By: rjmccall Differential Revision: https://reviews.llvm.org/D95561
661 lines
22 KiB
C++
661 lines
22 KiB
C++
//===- MicrosoftDemangle.cpp ----------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines a demangler for MSVC-style mangled symbols.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Demangle/MicrosoftDemangleNodes.h"
|
|
#include "llvm/Demangle/DemangleConfig.h"
|
|
#include "llvm/Demangle/Utility.h"
|
|
#include <cctype>
|
|
#include <string>
|
|
|
|
using namespace llvm;
|
|
using namespace ms_demangle;
|
|
|
|
#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \
|
|
case Enum::Value: \
|
|
OS << Desc; \
|
|
break;
|
|
|
|
// Writes a space if the last token does not end with a punctuation.
|
|
static void outputSpaceIfNecessary(OutputStream &OS) {
|
|
if (OS.empty())
|
|
return;
|
|
|
|
char C = OS.back();
|
|
if (std::isalnum(C) || C == '>')
|
|
OS << " ";
|
|
}
|
|
|
|
static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) {
|
|
switch (Q) {
|
|
case Q_Const:
|
|
OS << "const";
|
|
break;
|
|
case Q_Volatile:
|
|
OS << "volatile";
|
|
break;
|
|
case Q_Restrict:
|
|
OS << "__restrict";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,
|
|
Qualifiers Mask, bool NeedSpace) {
|
|
if (!(Q & Mask))
|
|
return NeedSpace;
|
|
|
|
if (NeedSpace)
|
|
OS << " ";
|
|
|
|
outputSingleQualifier(OS, Mask);
|
|
return true;
|
|
}
|
|
|
|
static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,
|
|
bool SpaceAfter) {
|
|
if (Q == Q_None)
|
|
return;
|
|
|
|
size_t Pos1 = OS.getCurrentPosition();
|
|
SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore);
|
|
SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore);
|
|
SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore);
|
|
size_t Pos2 = OS.getCurrentPosition();
|
|
if (SpaceAfter && Pos2 > Pos1)
|
|
OS << " ";
|
|
}
|
|
|
|
static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
|
|
outputSpaceIfNecessary(OS);
|
|
|
|
switch (CC) {
|
|
case CallingConv::Cdecl:
|
|
OS << "__cdecl";
|
|
break;
|
|
case CallingConv::Fastcall:
|
|
OS << "__fastcall";
|
|
break;
|
|
case CallingConv::Pascal:
|
|
OS << "__pascal";
|
|
break;
|
|
case CallingConv::Regcall:
|
|
OS << "__regcall";
|
|
break;
|
|
case CallingConv::Stdcall:
|
|
OS << "__stdcall";
|
|
break;
|
|
case CallingConv::Thiscall:
|
|
OS << "__thiscall";
|
|
break;
|
|
case CallingConv::Eabi:
|
|
OS << "__eabi";
|
|
break;
|
|
case CallingConv::Vectorcall:
|
|
OS << "__vectorcall";
|
|
break;
|
|
case CallingConv::Clrcall:
|
|
OS << "__clrcall";
|
|
break;
|
|
case CallingConv::Swift:
|
|
OS << "__attribute__((__swiftcall__)) ";
|
|
break;
|
|
case CallingConv::SwiftAsync:
|
|
OS << "__attribute__((__swiftasynccall__)) ";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::string Node::toString(OutputFlags Flags) const {
|
|
OutputStream OS;
|
|
initializeOutputStream(nullptr, nullptr, OS, 1024);
|
|
this->output(OS, Flags);
|
|
OS << '\0';
|
|
std::string Owned(OS.getBuffer());
|
|
std::free(OS.getBuffer());
|
|
return Owned;
|
|
}
|
|
|
|
void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
|
switch (PrimKind) {
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char8, "char8_t");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double");
|
|
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t");
|
|
}
|
|
outputQualifiers(OS, Quals, true, false);
|
|
}
|
|
|
|
void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {
|
|
output(OS, Flags, ", ");
|
|
}
|
|
|
|
void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,
|
|
StringView Separator) const {
|
|
if (Count == 0)
|
|
return;
|
|
if (Nodes[0])
|
|
Nodes[0]->output(OS, Flags);
|
|
for (size_t I = 1; I < Count; ++I) {
|
|
OS << Separator;
|
|
Nodes[I]->output(OS, Flags);
|
|
}
|
|
}
|
|
|
|
void EncodedStringLiteralNode::output(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
switch (Char) {
|
|
case CharKind::Wchar:
|
|
OS << "L\"";
|
|
break;
|
|
case CharKind::Char:
|
|
OS << "\"";
|
|
break;
|
|
case CharKind::Char16:
|
|
OS << "u\"";
|
|
break;
|
|
case CharKind::Char32:
|
|
OS << "U\"";
|
|
break;
|
|
}
|
|
OS << DecodedString << "\"";
|
|
if (IsTruncated)
|
|
OS << "...";
|
|
}
|
|
|
|
void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
|
|
if (IsNegative)
|
|
OS << '-';
|
|
OS << Value;
|
|
}
|
|
|
|
void TemplateParameterReferenceNode::output(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
if (ThunkOffsetCount > 0)
|
|
OS << "{";
|
|
else if (Affinity == PointerAffinity::Pointer)
|
|
OS << "&";
|
|
|
|
if (Symbol) {
|
|
Symbol->output(OS, Flags);
|
|
if (ThunkOffsetCount > 0)
|
|
OS << ", ";
|
|
}
|
|
|
|
if (ThunkOffsetCount > 0)
|
|
OS << ThunkOffsets[0];
|
|
for (int I = 1; I < ThunkOffsetCount; ++I) {
|
|
OS << ", " << ThunkOffsets[I];
|
|
}
|
|
if (ThunkOffsetCount > 0)
|
|
OS << "}";
|
|
}
|
|
|
|
void IdentifierNode::outputTemplateParameters(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
if (!TemplateParams)
|
|
return;
|
|
OS << "<";
|
|
TemplateParams->output(OS, Flags);
|
|
OS << ">";
|
|
}
|
|
|
|
void DynamicStructorIdentifierNode::output(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
if (IsDestructor)
|
|
OS << "`dynamic atexit destructor for ";
|
|
else
|
|
OS << "`dynamic initializer for ";
|
|
|
|
if (Variable) {
|
|
OS << "`";
|
|
Variable->output(OS, Flags);
|
|
OS << "''";
|
|
} else {
|
|
OS << "'";
|
|
Name->output(OS, Flags);
|
|
OS << "''";
|
|
}
|
|
}
|
|
|
|
void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
|
|
OS << Name;
|
|
outputTemplateParameters(OS, Flags);
|
|
}
|
|
|
|
void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
switch (Operator) {
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator==");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript,
|
|
"operator[]");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer,
|
|
"operator->*");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual,
|
|
"operator>=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual,
|
|
"operator&=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual,
|
|
"operator|=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual,
|
|
"operator^=");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor,
|
|
"`vector deleting dtor'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure,
|
|
"`default ctor closure'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor,
|
|
"`scalar deleting dtor'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter,
|
|
"`vector ctor iterator'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter,
|
|
"`vector dtor iterator'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter,
|
|
"`vector vbase ctor iterator'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap,
|
|
"`virtual displacement map'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter,
|
|
"`eh vector ctor iterator'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter,
|
|
"`eh vector dtor iterator'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter,
|
|
"`eh vector vbase ctor iterator'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure,
|
|
"`copy ctor closure'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure,
|
|
"`local vftable ctor closure'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete,
|
|
"operator delete[]");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter,
|
|
"`managed vector ctor iterator'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter,
|
|
"`managed vector dtor iterator'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter,
|
|
"`EH vector copy ctor iterator'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter,
|
|
"`EH vector vbase copy ctor iterator'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter,
|
|
"`vector copy ctor iterator'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter,
|
|
"`vector vbase copy constructor iterator'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter,
|
|
"`managed vector vbase copy constructor iterator'");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait,
|
|
"operator co_await");
|
|
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>");
|
|
case IntrinsicFunctionKind::MaxIntrinsic:
|
|
case IntrinsicFunctionKind::None:
|
|
break;
|
|
}
|
|
outputTemplateParameters(OS, Flags);
|
|
}
|
|
|
|
void LocalStaticGuardIdentifierNode::output(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
if (IsThread)
|
|
OS << "`local static thread guard'";
|
|
else
|
|
OS << "`local static guard'";
|
|
if (ScopeIndex > 0)
|
|
OS << "{" << ScopeIndex << "}";
|
|
}
|
|
|
|
void ConversionOperatorIdentifierNode::output(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
OS << "operator";
|
|
outputTemplateParameters(OS, Flags);
|
|
OS << " ";
|
|
TargetType->output(OS, Flags);
|
|
}
|
|
|
|
void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
|
|
if (IsDestructor)
|
|
OS << "~";
|
|
Class->output(OS, Flags);
|
|
outputTemplateParameters(OS, Flags);
|
|
}
|
|
|
|
void LiteralOperatorIdentifierNode::output(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
OS << "operator \"\"" << Name;
|
|
outputTemplateParameters(OS, Flags);
|
|
}
|
|
|
|
void FunctionSignatureNode::outputPre(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
if (!(Flags & OF_NoAccessSpecifier)) {
|
|
if (FunctionClass & FC_Public)
|
|
OS << "public: ";
|
|
if (FunctionClass & FC_Protected)
|
|
OS << "protected: ";
|
|
if (FunctionClass & FC_Private)
|
|
OS << "private: ";
|
|
}
|
|
|
|
if (!(Flags & OF_NoMemberType)) {
|
|
if (!(FunctionClass & FC_Global)) {
|
|
if (FunctionClass & FC_Static)
|
|
OS << "static ";
|
|
}
|
|
if (FunctionClass & FC_Virtual)
|
|
OS << "virtual ";
|
|
|
|
if (FunctionClass & FC_ExternC)
|
|
OS << "extern \"C\" ";
|
|
}
|
|
|
|
if (!(Flags & OF_NoReturnType) && ReturnType) {
|
|
ReturnType->outputPre(OS, Flags);
|
|
OS << " ";
|
|
}
|
|
|
|
if (!(Flags & OF_NoCallingConvention))
|
|
outputCallingConvention(OS, CallConvention);
|
|
}
|
|
|
|
void FunctionSignatureNode::outputPost(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
if (!(FunctionClass & FC_NoParameterList)) {
|
|
OS << "(";
|
|
if (Params)
|
|
Params->output(OS, Flags);
|
|
else
|
|
OS << "void";
|
|
|
|
if (IsVariadic) {
|
|
if (OS.back() != '(')
|
|
OS << ", ";
|
|
OS << "...";
|
|
}
|
|
OS << ")";
|
|
}
|
|
|
|
if (Quals & Q_Const)
|
|
OS << " const";
|
|
if (Quals & Q_Volatile)
|
|
OS << " volatile";
|
|
if (Quals & Q_Restrict)
|
|
OS << " __restrict";
|
|
if (Quals & Q_Unaligned)
|
|
OS << " __unaligned";
|
|
|
|
if (IsNoexcept)
|
|
OS << " noexcept";
|
|
|
|
if (RefQualifier == FunctionRefQualifier::Reference)
|
|
OS << " &";
|
|
else if (RefQualifier == FunctionRefQualifier::RValueReference)
|
|
OS << " &&";
|
|
|
|
if (!(Flags & OF_NoReturnType) && ReturnType)
|
|
ReturnType->outputPost(OS, Flags);
|
|
}
|
|
|
|
void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
|
OS << "[thunk]: ";
|
|
|
|
FunctionSignatureNode::outputPre(OS, Flags);
|
|
}
|
|
|
|
void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
|
|
if (FunctionClass & FC_StaticThisAdjust) {
|
|
OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
|
|
} else if (FunctionClass & FC_VirtualThisAdjust) {
|
|
if (FunctionClass & FC_VirtualThisAdjustEx) {
|
|
OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
|
|
<< ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
|
|
<< ", " << ThisAdjust.StaticOffset << "}'";
|
|
} else {
|
|
OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
|
|
<< ThisAdjust.StaticOffset << "}'";
|
|
}
|
|
}
|
|
|
|
FunctionSignatureNode::outputPost(OS, Flags);
|
|
}
|
|
|
|
void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
|
if (Pointee->kind() == NodeKind::FunctionSignature) {
|
|
// If this is a pointer to a function, don't output the calling convention.
|
|
// It needs to go inside the parentheses.
|
|
const FunctionSignatureNode *Sig =
|
|
static_cast<const FunctionSignatureNode *>(Pointee);
|
|
Sig->outputPre(OS, OF_NoCallingConvention);
|
|
} else
|
|
Pointee->outputPre(OS, Flags);
|
|
|
|
outputSpaceIfNecessary(OS);
|
|
|
|
if (Quals & Q_Unaligned)
|
|
OS << "__unaligned ";
|
|
|
|
if (Pointee->kind() == NodeKind::ArrayType) {
|
|
OS << "(";
|
|
} else if (Pointee->kind() == NodeKind::FunctionSignature) {
|
|
OS << "(";
|
|
const FunctionSignatureNode *Sig =
|
|
static_cast<const FunctionSignatureNode *>(Pointee);
|
|
outputCallingConvention(OS, Sig->CallConvention);
|
|
OS << " ";
|
|
}
|
|
|
|
if (ClassParent) {
|
|
ClassParent->output(OS, Flags);
|
|
OS << "::";
|
|
}
|
|
|
|
switch (Affinity) {
|
|
case PointerAffinity::Pointer:
|
|
OS << "*";
|
|
break;
|
|
case PointerAffinity::Reference:
|
|
OS << "&";
|
|
break;
|
|
case PointerAffinity::RValueReference:
|
|
OS << "&&";
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
outputQualifiers(OS, Quals, false, false);
|
|
}
|
|
|
|
void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
|
|
if (Pointee->kind() == NodeKind::ArrayType ||
|
|
Pointee->kind() == NodeKind::FunctionSignature)
|
|
OS << ")";
|
|
|
|
Pointee->outputPost(OS, Flags);
|
|
}
|
|
|
|
void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
|
if (!(Flags & OF_NoTagSpecifier)) {
|
|
switch (Tag) {
|
|
OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class");
|
|
OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct");
|
|
OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union");
|
|
OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum");
|
|
}
|
|
OS << " ";
|
|
}
|
|
QualifiedName->output(OS, Flags);
|
|
outputQualifiers(OS, Quals, true, false);
|
|
}
|
|
|
|
void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
|
|
|
|
void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
|
ElementType->outputPre(OS, Flags);
|
|
outputQualifiers(OS, Quals, true, false);
|
|
}
|
|
|
|
void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags,
|
|
Node *N) const {
|
|
assert(N->kind() == NodeKind::IntegerLiteral);
|
|
IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
|
|
if (ILN->Value != 0)
|
|
ILN->output(OS, Flags);
|
|
}
|
|
|
|
void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
if (Dimensions->Count == 0)
|
|
return;
|
|
|
|
outputOneDimension(OS, Flags, Dimensions->Nodes[0]);
|
|
for (size_t I = 1; I < Dimensions->Count; ++I) {
|
|
OS << "][";
|
|
outputOneDimension(OS, Flags, Dimensions->Nodes[I]);
|
|
}
|
|
}
|
|
|
|
void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
|
|
OS << "[";
|
|
outputDimensionsImpl(OS, Flags);
|
|
OS << "]";
|
|
|
|
ElementType->outputPost(OS, Flags);
|
|
}
|
|
|
|
void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
|
|
Name->output(OS, Flags);
|
|
}
|
|
|
|
void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
|
|
Signature->outputPre(OS, Flags);
|
|
outputSpaceIfNecessary(OS);
|
|
Name->output(OS, Flags);
|
|
Signature->outputPost(OS, Flags);
|
|
}
|
|
|
|
void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
|
|
const char *AccessSpec = nullptr;
|
|
bool IsStatic = true;
|
|
switch (SC) {
|
|
case StorageClass::PrivateStatic:
|
|
AccessSpec = "private";
|
|
break;
|
|
case StorageClass::PublicStatic:
|
|
AccessSpec = "public";
|
|
break;
|
|
case StorageClass::ProtectedStatic:
|
|
AccessSpec = "protected";
|
|
break;
|
|
default:
|
|
IsStatic = false;
|
|
break;
|
|
}
|
|
if (!(Flags & OF_NoAccessSpecifier) && AccessSpec)
|
|
OS << AccessSpec << ": ";
|
|
if (!(Flags & OF_NoMemberType) && IsStatic)
|
|
OS << "static ";
|
|
|
|
if (Type) {
|
|
Type->outputPre(OS, Flags);
|
|
outputSpaceIfNecessary(OS);
|
|
}
|
|
Name->output(OS, Flags);
|
|
if (Type)
|
|
Type->outputPost(OS, Flags);
|
|
}
|
|
|
|
void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
|
Identifier->output(OS, Flags);
|
|
}
|
|
void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
|
|
|
|
void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
|
|
Components->output(OS, Flags, "::");
|
|
}
|
|
|
|
void RttiBaseClassDescriptorNode::output(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
OS << "`RTTI Base Class Descriptor at (";
|
|
OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
|
|
<< this->Flags;
|
|
OS << ")'";
|
|
}
|
|
|
|
void LocalStaticGuardVariableNode::output(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
Name->output(OS, Flags);
|
|
}
|
|
|
|
void VcallThunkIdentifierNode::output(OutputStream &OS,
|
|
OutputFlags Flags) const {
|
|
OS << "`vcall'{" << OffsetInVTable << ", {flat}}";
|
|
}
|
|
|
|
void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
|
|
outputQualifiers(OS, Quals, false, true);
|
|
Name->output(OS, Flags);
|
|
if (TargetName) {
|
|
OS << "{for `";
|
|
TargetName->output(OS, Flags);
|
|
OS << "'}";
|
|
}
|
|
}
|