#include "StringView.h"
#include "Utility.h"
+#include <array>
#include <cctype>
#include <cstdio>
#include <tuple>
bool IntegerLiteralIsNegative = false;
bool IsEmptyParameterPack = false;
bool PointerToSymbol = false;
+ bool NullptrLiteral = false;
+ bool DataMemberPointer = false;
bool ReferenceToSymbol = false;
+ int ThunkOffsetCount = 0;
+ std::array<int64_t, 3> ThunkOffsets;
+
// If IsIntegerLiteral is true, this is a non-type template parameter
// whose value is contained in this field.
uint64_t IntegralValue = 0;
OS << '-';
OS << Head->IntegralValue;
} else if (Head->PointerToSymbol || Head->ReferenceToSymbol) {
- if (Head->PointerToSymbol)
- OS << "&";
- Type::outputPre(OS, *Head->ParamType);
- outputName(OS, Head->ParamName, Head->ParamType);
- Type::outputPost(OS, *Head->ParamType);
+ if (Head->NullptrLiteral)
+ OS << "nullptr";
+ else {
+ if (Head->ThunkOffsetCount > 0)
+ OS << "{";
+ else if (Head->PointerToSymbol)
+ OS << "&";
+ if (Head->ParamType)
+ Type::outputPre(OS, *Head->ParamType);
+ outputName(OS, Head->ParamName, Head->ParamType);
+ if (Head->ParamType)
+ Type::outputPost(OS, *Head->ParamType);
+ if (Head->ThunkOffsetCount > 0) {
+ for (int I = 0; I < Head->ThunkOffsetCount; ++I) {
+ OS << ", " << Head->ThunkOffsets[I];
+ }
+ OS << "}";
+ }
+ }
+ } else if (Head->DataMemberPointer) {
+ OS << "{" << Head->ThunkOffsets[0];
+ for (int I = 1; I < Head->ThunkOffsetCount; ++I)
+ OS << ", " << Head->ThunkOffsets[I];
+ OS << "}";
} else if (Head->ParamType) {
// simple type.
Type::outputPre(OS, *Head->ParamType);
outputParameterList(OS, *N.TParams);
}
+static const OperatorInfo *lastComponentAsOperator(const Name *TheName) {
+ if (!TheName)
+ return nullptr;
+ while (TheName->Next)
+ TheName = TheName->Next;
+ if (TheName->IsOperator)
+ return static_cast<const OperatorInfo *>(TheName);
+ return nullptr;
+}
+
static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) {
if (!TheName)
return;
outputSpaceIfNecessary(OS);
+ const OperatorInfo *Operator = lastComponentAsOperator(TheName);
+ const VirtualMemberPtrThunk *Thunk = nullptr;
+ if (Operator) {
+ if (Operator->Info->Operator == OperatorTy::Vcall) {
+ Thunk = static_cast<const VirtualMemberPtrThunk *>(Operator);
+ OS << "[thunk]: ";
+ outputCallingConvention(OS, Thunk->CC);
+ OS << " ";
+ }
+ }
+
const Name *Previous = nullptr;
// Print out namespaces or outer class BackReferences.
for (; TheName->Next; TheName = TheName->Next) {
return;
}
- const OperatorInfo &Operator = static_cast<const OperatorInfo &>(*TheName);
// Print out ctor or dtor.
- switch (Operator.Info->Operator) {
+ switch (Operator->Info->Operator) {
case OperatorTy::Dtor:
OS << "~";
LLVM_FALLTHROUGH;
}
break;
case OperatorTy::LiteralOperator:
- OS << Operator.Info->Name;
+ OS << Operator->Info->Name;
outputNameComponent(OS, *TheName);
break;
case OperatorTy::RttiBaseClassDescriptor: {
const RttiBaseClassDescriptor &BCD =
- static_cast<const RttiBaseClassDescriptor &>(Operator);
- OS << "`" << Operator.Info->Name << " at (";
+ static_cast<const RttiBaseClassDescriptor &>(*Operator);
+ OS << "`" << Operator->Info->Name << " at (";
OS << BCD.NVOffset << ", " << BCD.VBPtrOffset << ", " << BCD.VBTableOffset
<< ", " << BCD.Flags;
OS << ")'";
break;
}
+ case OperatorTy::Vcall: {
+ OS << "`vcall'{";
+ OS << Thunk->OffsetInVTable << ", {flat}}";
+ break;
+ }
+
case OperatorTy::LocalStaticGuard: {
const LocalStaticGuardVariable &LSG =
- static_cast<const LocalStaticGuardVariable &>(Operator);
- OS << Operator.Info->Name;
+ static_cast<const LocalStaticGuardVariable &>(*Operator);
+ OS << Operator->Info->Name;
if (LSG.ScopeIndex > 0)
OS << "{" << LSG.ScopeIndex << "}";
break;
}
default:
- OS << Operator.Info->Name;
- if (Operator.IsTemplateInstantiation)
- outputParameterList(OS, *Operator.TParams);
+ OS << Operator->Info->Name;
+ if (Operator->IsTemplateInstantiation)
+ outputParameterList(OS, *Operator->TParams);
break;
}
}
static void outputSpecialOperator(OutputStream &OS, const Name *OuterName) {
assert(OuterName);
// The last component should be an operator.
- const Name *LastComponent = OuterName;
- while (LastComponent->Next)
- LastComponent = LastComponent->Next;
+ const OperatorInfo *Operator = lastComponentAsOperator(OuterName);
- assert(LastComponent->IsOperator);
- const OperatorInfo &Oper = static_cast<const OperatorInfo &>(*LastComponent);
+ assert(Operator->IsOperator);
+ const OperatorInfo &Oper = static_cast<const OperatorInfo &>(*Operator);
switch (Oper.Info->Operator) {
case OperatorTy::StringLiteral: {
const StringLiteral &SL = static_cast<const StringLiteral &>(Oper);
std::tie(OTy, S->SymbolName) = demangleOperatorName(MangledName, true);
switch (OTy) {
case OperatorTy::StringLiteral:
- case OperatorTy::Vcall:
S->Category = SymbolCategory::SpecialOperator;
break;
+ case OperatorTy::Vcall:
+ S->Category = SymbolCategory::UnnamedFunction;
+ break;
+ case OperatorTy::LocalStaticGuard:
+ S->Category = SymbolCategory::UnnamedVariable;
+ break;
case OperatorTy::Vftable: // Foo@@6B@
case OperatorTy::LocalVftable: // Foo@@6B@
case OperatorTy::RttiCompleteObjLocator: // Foo@@6B@
if (!MangledName.empty())
Error = true;
break;
- case OperatorTy::LocalStaticGuard: {
- S->Category = SymbolCategory::UnnamedVariable;
- break;
- }
default:
if (!Error)
std::tie(S->Category, S->SymbolType) =
// Template parameter lists don't participate in back-referencing.
*Current = Arena.alloc<TemplateParams>();
+ TemplateParams &TP = **Current;
+
// Empty parameter pack.
if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") ||
MangledName.consumeFront("$$$V")) {
- (*Current)->IsEmptyParameterPack = true;
+ TP.IsEmptyParameterPack = true;
break;
}
if (MangledName.consumeFront("$$Y")) {
// Template alias
- (*Current)->IsTemplateTemplate = true;
- (*Current)->IsAliasTemplate = true;
- (*Current)->ParamName = demangleFullyQualifiedTypeName(MangledName);
+ TP.IsTemplateTemplate = true;
+ TP.IsAliasTemplate = true;
+ TP.ParamName = demangleFullyQualifiedTypeName(MangledName);
} else if (MangledName.consumeFront("$$B")) {
// Array
- (*Current)->ParamType =
- demangleType(MangledName, QualifierMangleMode::Drop);
+ TP.ParamType = demangleType(MangledName, QualifierMangleMode::Drop);
} else if (MangledName.consumeFront("$$C")) {
// Type has qualifiers.
- (*Current)->ParamType =
- demangleType(MangledName, QualifierMangleMode::Mangle);
- } else if (MangledName.startsWith("$1?")) {
- MangledName.consumeFront("$1");
- // Pointer to symbol
- Symbol *S = parse(MangledName);
- (*Current)->ParamName = S->SymbolName;
- (*Current)->ParamType = S->SymbolType;
- (*Current)->PointerToSymbol = true;
+ TP.ParamType = demangleType(MangledName, QualifierMangleMode::Mangle);
+ } else if (MangledName.startsWith("$1") || MangledName.startsWith("$H") ||
+ MangledName.startsWith("$I") || MangledName.startsWith("$J")) {
+ MangledName = MangledName.dropFront();
+ // 1 - single inheritance <name>
+ // H - multiple inheritance <name> <number>
+ // I - virtual inheritance <name> <number> <number> <number>
+ // J - unspecified inheritance <name> <number> <number> <number>
+ char InheritanceSpecifier = MangledName.popFront();
+ // Pointer to member
+ Symbol *S = MangledName.startsWith('?') ? parse(MangledName) : nullptr;
+ switch (InheritanceSpecifier) {
+ case 'J':
+ TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
+ LLVM_FALLTHROUGH;
+ case 'I':
+ TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
+ LLVM_FALLTHROUGH;
+ case 'H':
+ TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
+ LLVM_FALLTHROUGH;
+ case '1':
+ break;
+ default:
+ Error = true;
+ break;
+ }
+ TP.PointerToSymbol = true;
+ if (S) {
+ TP.ParamName = S->SymbolName;
+ TP.ParamType = S->SymbolType;
+ } else
+ TP.NullptrLiteral = true;
} else if (MangledName.startsWith("$E?")) {
MangledName.consumeFront("$E");
// Reference to symbol
Symbol *S = parse(MangledName);
- (*Current)->ParamName = S->SymbolName;
- (*Current)->ParamType = S->SymbolType;
- (*Current)->ReferenceToSymbol = true;
+ TP.ParamName = S->SymbolName;
+ TP.ParamType = S->SymbolType;
+ TP.ReferenceToSymbol = true;
+ } else if (MangledName.startsWith("$F") || MangledName.startsWith("$G")) {
+ // Data member pointer.
+ MangledName = MangledName.dropFront();
+ char InheritanceSpecifier = MangledName.popFront();
+
+ switch (InheritanceSpecifier) {
+ case 'G':
+ TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
+ LLVM_FALLTHROUGH;
+ case 'F':
+ TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
+ TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
+ LLVM_FALLTHROUGH;
+ case '0':
+ break;
+ default:
+ Error = true;
+ break;
+ }
+ TP.DataMemberPointer = true;
+
} else if (MangledName.consumeFront("$0")) {
// Integral non-type template parameter
bool IsNegative = false;
uint64_t Value = 0;
std::tie(Value, IsNegative) = demangleNumber(MangledName);
- (*Current)->IsIntegerLiteral = true;
- (*Current)->IntegerLiteralIsNegative = IsNegative;
- (*Current)->IntegralValue = Value;
+ TP.IsIntegerLiteral = true;
+ TP.IntegerLiteralIsNegative = IsNegative;
+ TP.IntegralValue = Value;
} else {
- (*Current)->ParamType =
- demangleType(MangledName, QualifierMangleMode::Drop);
+ TP.ParamType = demangleType(MangledName, QualifierMangleMode::Drop);
}
if (Error)
return nullptr;
- Current = &(*Current)->Next;
+ Current = &TP.Next;
}
if (Error)
--- /dev/null
+; RUN: llvm-undname < %s | FileCheck %s
+
+; CHECK-NOT: Invalid mangled name
+
+; There's a back-referencing problem here
+??$CallMethod@UC@NegativeNVOffset@@$I??_912@$BA@AEPPPPPPPM@A@@@YAXAAUC@NegativeNVOffset@@@Z
+; FIXME: void __cdecl CallMethod<struct NegativeNVOffset::C, {[thunk]: __thiscall NegativeNVOffset::C::`vcall'{0, {flat}}, 4294967292, 0}>(struct NegativeNVOffset::C &)
+
+??$CallMethod@UM@@$0A@@@YAXAAUM@@@Z
+; CHECK: void __cdecl CallMethod<struct M, 0>(struct M &)
+
+??$CallMethod@UM@@$H??_91@$BA@AEA@@@YAXAAUM@@@Z
+; FIXME: void __cdecl CallMethod<struct M, {[thunk]: __thiscall M::`vcall'{0, {flat}}', 0}>(struct M &)
+
+??$CallMethod@UM@@$H?f@1@QAEXXZA@@@YAXAAUM@@@Z
+; FIXME: void __cdecl CallMethod<struct M, {void __thiscall M::f(void), 0}>(struct M &)
+
+??$CallMethod@UO@@$H??_91@$BA@AE3@@YAXAAUO@@@Z
+; FIXME: void __cdecl CallMethod<struct O, {[thunk]: __thiscall O::`vcall'{0, {flat}}, 4}>(struct O &)
+
+??$CallMethod@US@@$0A@@@YAXAAUS@@@Z
+; CHECK: void __cdecl CallMethod<struct S, 0>(struct S &)
+
+??$CallMethod@US@@$1??_91@$BA@AE@@YAXAAUS@@@Z
+; CHECK: void __cdecl CallMethod<struct S, &[thunk]: __thiscall S::`vcall'{0, {flat}}>(struct S &)
+
+??$CallMethod@US@@$1?f@1@QAEXXZ@@YAXAAUS@@@Z
+; CHECK: void __cdecl CallMethod<struct S, &void __thiscall S::f(void)>(struct S &)
+
+??$CallMethod@UU@@$0A@@@YAXAAUU@@@Z
+; CHECK: void __cdecl CallMethod<struct U, 0>(struct U &)
+
+??$CallMethod@UU@@$J??_91@$BA@AEA@A@A@@@YAXAAUU@@@Z
+; CHECK: void __cdecl CallMethod<struct U, {[thunk]: __thiscall U::`vcall'{0, {flat}}, 0, 0, 0}>(struct U &)
+
+??$CallMethod@UU@@$J?f@1@QAEXXZA@A@A@@@YAXAAUU@@@Z
+; CHECK: void __cdecl CallMethod<struct U, {void __thiscall U::f(void), 0, 0, 0}>(struct U &)
+
+??$CallMethod@UV@@$0A@@@YAXAAUV@@@Z
+; CHECK: void __cdecl CallMethod<struct V, 0>(struct V &)
+
+??$CallMethod@UV@@$I??_91@$BA@AEA@A@@@YAXAAUV@@@Z
+; CHECK: void __cdecl CallMethod<struct V, {[thunk]: __thiscall V::`vcall'{0, {flat}}, 0, 0}>(struct V &)
+
+??$CallMethod@UV@@$I?f@1@QAEXXZA@A@@@YAXAAUV@@@Z
+; CHECK: void __cdecl CallMethod<struct V, {void __thiscall V::f(void), 0, 0}>(struct V &)
+
+??$ReadField@UA@@$0?0@@YAHAAUA@@@Z
+; CHECK: int __cdecl ReadField<struct A, -1>(struct A &)
+
+??$ReadField@UA@@$0A@@@YAHAAUA@@@Z
+; CHECK: int __cdecl ReadField<struct A, 0>(struct A &)
+
+??$ReadField@UI@@$03@@YAHAAUI@@@Z
+; CHECK: int __cdecl ReadField<struct I, 4>(struct I &)
+
+??$ReadField@UI@@$0A@@@YAHAAUI@@@Z
+; CHECK: int __cdecl ReadField<struct I, 0>(struct I &)
+
+??$ReadField@UM@@$0A@@@YAHAAUM@@@Z
+; CHECK: int __cdecl ReadField<struct M, 0>(struct M &)
+
+??$ReadField@UM@@$0BA@@@YAHAAUM@@@Z
+; CHECK: int __cdecl ReadField<struct M, 16>(struct M &)
+
+??$ReadField@UM@@$0M@@@YAHAAUM@@@Z
+; CHECK: int __cdecl ReadField<struct M, 12>(struct M &)
+
+??$ReadField@US@@$03@@YAHAAUS@@@Z
+; CHECK: int __cdecl ReadField<struct S, 4>(struct S &)
+
+??$ReadField@US@@$07@@YAHAAUS@@@Z
+; CHECK: int __cdecl ReadField<struct S, 8>(struct S &)
+
+??$ReadField@US@@$0A@@@YAHAAUS@@@Z
+; CHECK: int __cdecl ReadField<struct S, 0>(struct S &)
+
+??$ReadField@UU@@$0A@@@YAHAAUU@@@Z
+; CHECK: int __cdecl ReadField<struct U, 0>(struct U &)
+
+??$ReadField@UU@@$G3A@A@@@YAHAAUU@@@Z
+; CHECK: int __cdecl ReadField<struct U, {4, 0, 0}>(struct U &)
+
+??$ReadField@UU@@$G7A@A@@@YAHAAUU@@@Z
+; CHECK: int __cdecl ReadField<struct U, {8, 0, 0}>(struct U &)
+
+??$ReadField@UV@@$0A@@@YAHAAUV@@@Z
+; CHECK: int __cdecl ReadField<struct V, 0>(struct V &)
+
+??$ReadField@UV@@$F7A@@@YAHAAUV@@@Z
+; CHECK: int __cdecl ReadField<struct V, {8, 0}>(struct V &)
+
+??$ReadField@UV@@$FM@A@@@YAHAAUV@@@Z
+; CHECK: int __cdecl ReadField<struct V, {12, 0}>(struct V &)
+