struct TemplateParams {
bool IsTemplateTemplate = false;
bool IsAliasTemplate = false;
+ bool IsIntegerLiteral = false;
+ bool IntegerLiteralIsNegative = false;
+ bool IsEmptyParameterPack = false;
+ bool PointerToSymbol = false;
+ bool ReferenceToSymbol = false;
+
+ // If IsIntegerLiteral is true, this is a non-type template parameter
+ // whose value is contained in this field.
+ uint64_t IntegralValue = 0;
// Type can be null if this is a template template parameter. In that case
// only Name will be valid.
Name *UdtName = nullptr;
};
+struct ArrayDimension {
+ uint64_t Dim = 0;
+ ArrayDimension *Next = nullptr;
+};
+
struct ArrayType : public Type {
Type *clone(ArenaAllocator &Arena) const override;
void outputPre(OutputStream &OS, NameResolver &Resolver) override;
void outputPost(OutputStream &OS, NameResolver &Resolver) override;
// Either NextDimension or ElementType will be valid.
- ArrayType *NextDimension = nullptr;
- uint32_t ArrayDimension = 0;
+ ArrayDimension *Dims = nullptr;
Type *ElementType = nullptr;
};
static void outputParameterList(OutputStream &OS, const TemplateParams &Params,
NameResolver &Resolver) {
- if (!Params.ParamType && !Params.ParamName) {
+ if (Params.IsEmptyParameterPack) {
OS << "<>";
return;
}
// Type can be null if this is a template template parameter,
// and Name can be null if this is a simple type.
- if (Head->ParamType && Head->ParamName) {
- // Function pointer.
- OS << "&";
+ if (Head->IsIntegerLiteral) {
+ if (Head->IntegerLiteralIsNegative)
+ OS << '-';
+ OS << Head->IntegralValue;
+ } else if (Head->PointerToSymbol || Head->ReferenceToSymbol) {
+ if (Head->PointerToSymbol)
+ OS << "&";
Type::outputPre(OS, *Head->ParamType, Resolver);
outputName(OS, Head->ParamName, Resolver);
Type::outputPost(OS, *Head->ParamType, Resolver);
}
void ArrayType::outputPost(OutputStream &OS, NameResolver &Resolver) {
- if (ArrayDimension > 0)
- OS << "[" << ArrayDimension << "]";
- if (NextDimension)
- Type::outputPost(OS, *NextDimension, Resolver);
- else if (ElementType)
- Type::outputPost(OS, *ElementType, Resolver);
+ ArrayDimension *D = Dims;
+ while (D) {
+ OS << "[";
+ if (D->Dim > 0)
+ OS << D->Dim;
+ OS << "]";
+ D = D->Next;
+ }
+
+ Type::outputPost(OS, *ElementType, Resolver);
}
struct Symbol {
TemplateParams *demangleTemplateParameterList(StringView &MangledName);
FunctionParams demangleFunctionParameterList(StringView &MangledName);
- int demangleNumber(StringView &MangledName);
+ std::pair<uint64_t, bool> demangleNumber(StringView &MangledName);
void memorizeString(StringView s);
// ::= <hex digit>+ @ # when Numbrer == 0 or >= 10
//
// <hex-digit> ::= [A-P] # A = 0, B = 1, ...
-int Demangler::demangleNumber(StringView &MangledName) {
- bool neg = MangledName.consumeFront("?");
+std::pair<uint64_t, bool> Demangler::demangleNumber(StringView &MangledName) {
+ bool IsNegative = MangledName.consumeFront('?');
if (startsWithDigit(MangledName)) {
- int32_t Ret = MangledName[0] - '0' + 1;
+ uint64_t Ret = MangledName[0] - '0' + 1;
MangledName = MangledName.dropFront(1);
- return neg ? -Ret : Ret;
+ return {Ret, IsNegative};
}
- int Ret = 0;
+ uint64_t Ret = 0;
for (size_t i = 0; i < MangledName.size(); ++i) {
char C = MangledName[i];
if (C == '@') {
MangledName = MangledName.dropFront(i + 1);
- return neg ? -Ret : Ret;
+ return {Ret, IsNegative};
}
if ('A' <= C && C <= 'P') {
Ret = (Ret << 4) + (C - 'A');
}
Error = true;
- return 0;
+ return {0ULL, false};
}
// First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9.
Name *Node = Arena.alloc<Name>();
MangledName.consumeFront('?');
- int ScopeIdentifier = demangleNumber(MangledName);
+ auto Number = demangleNumber(MangledName);
+ assert(!Number.second);
// One ? to terminate the number
MangledName.consumeFront('?');
OS << '`';
output(Scope, OS);
OS << '\'';
- OS << "::`" << ScopeIdentifier << "'";
+ OS << "::`" << Number.first << "'";
OS << '\0';
char *Result = OS.getBuffer();
Node->Str = copyString(Result);
assert(MangledName.front() == 'Y');
MangledName.popFront();
- int Dimension = demangleNumber(MangledName);
- if (Dimension <= 0) {
+ uint64_t Rank = 0;
+ bool IsNegative = false;
+ std::tie(Rank, IsNegative) = demangleNumber(MangledName);
+ if (IsNegative || Rank == 0) {
Error = true;
return nullptr;
}
ArrayType *ATy = Arena.alloc<ArrayType>();
- ArrayType *Dim = ATy;
- for (int I = 0; I < Dimension; ++I) {
- Dim->Prim = PrimTy::Array;
- Dim->ArrayDimension = demangleNumber(MangledName);
- Dim->NextDimension = Arena.alloc<ArrayType>();
- Dim = Dim->NextDimension;
+ ATy->Prim = PrimTy::Array;
+ ATy->Dims = Arena.alloc<ArrayDimension>();
+ ArrayDimension *Dim = ATy->Dims;
+ for (uint64_t I = 0; I < Rank; ++I) {
+ std::tie(Dim->Dim, IsNegative) = demangleNumber(MangledName);
+ if (IsNegative) {
+ Error = true;
+ return nullptr;
+ }
+ if (I + 1 < Rank) {
+ Dim->Next = Arena.alloc<ArrayDimension>();
+ Dim = Dim->Next;
+ }
}
if (MangledName.consumeFront("$$C")) {
}
ATy->ElementType = demangleType(MangledName, QualifierMangleMode::Drop);
- Dim->ElementType = ATy->ElementType;
return ATy;
}
// Empty parameter pack.
if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") ||
MangledName.consumeFront("$$$V")) {
+ (*Current)->IsEmptyParameterPack = true;
break;
}
if (MangledName.consumeFront("$$Y")) {
+ // Template alias
(*Current)->IsTemplateTemplate = true;
(*Current)->IsAliasTemplate = true;
(*Current)->ParamName = demangleFullyQualifiedTypeName(MangledName);
- } else if (MangledName.consumeFront("$1?")) {
- (*Current)->ParamName = demangleFullyQualifiedSymbolName(MangledName);
- (*Current)->ParamType = demangleFunctionEncoding(MangledName);
+ } else if (MangledName.consumeFront("$$B")) {
+ // Array
+ (*Current)->ParamType =
+ demangleType(MangledName, QualifierMangleMode::Drop);
+ } 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;
+ } 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;
+ } 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;
} else {
(*Current)->ParamType =
demangleType(MangledName, QualifierMangleMode::Drop);
--- /dev/null
+; These tests are based on clang/test/CodeGenCXX/mangle-ms-cxx11.cpp
+
+; RUN: llvm-undname < %s | FileCheck %s
+
+; CHECK-NOT: Invalid mangled name
+
+
+??0?$Class@VTypename@@@@QAE@XZ
+; CHECK: __thiscall Class<class Typename>::Class<class Typename>(void)
+??0?$Class@VTypename@@@@QEAA@XZ
+; CHECK: __cdecl Class<class Typename>::Class<class Typename>(void)
+
+??0?$Class@$$CBVTypename@@@@QAE@XZ
+; FIXME: __thiscall Class<class Typename const>::Class<class Typename const>(void)
+??0?$Class@$$CBVTypename@@@@QEAA@XZ
+; FIXME: __thiscall Class<class Typename const>::Class<class Typename const>(void)
+
+??0?$Class@$$CCVTypename@@@@QAE@XZ
+; FIXME: __thiscall Class<class Typename volatile>::Class<class Typename volatile>(void)
+??0?$Class@$$CCVTypename@@@@QEAA@XZ
+; FIXME: __thiscall Class<class Typename volatile>::Class<class Typename volatile>(void)
+
+??0?$Class@$$CDVTypename@@@@QAE@XZ
+; FIXME: __thiscall Class<class Typename const volatile>::Class<class Typename const volatile>(void)
+??0?$Class@$$CDVTypename@@@@QEAA@XZ
+; FIXME: __thiscall Class<class Typename const volatile>::Class<class Typename const volatile>(void)
+
+??0?$Class@V?$Nested@VTypename@@@@@@QAE@XZ
+; CHECK: __thiscall Class<class Nested<class Typename>>::Class<class Nested<class Typename>>(void)
+??0?$Class@V?$Nested@VTypename@@@@@@QEAA@XZ
+; CHECK: __cdecl Class<class Nested<class Typename>>::Class<class Nested<class Typename>>(void)
+
+??0?$Class@QAH@@QAE@XZ
+; CHECK: __thiscall Class<int *const>::Class<int *const>(void)
+??0?$Class@QEAH@@QEAA@XZ
+; CHECK: __cdecl Class<int *const>::Class<int *const>(void)
+
+??0?$Class@$$A6AHXZ@@QAE@XZ
+; CHECK: __thiscall Class<int __cdecl(void)>::Class<int __cdecl(void)>(void)
+??0?$Class@$$A6AHXZ@@QEAA@XZ
+; CHECK: __cdecl Class<int __cdecl(void)>::Class<int __cdecl(void)>(void)
+
+??0?$Class@$$BY0A@H@@QAE@XZ
+; CHECK: __thiscall Class<int[]>::Class<int[]>(void)
+??0?$Class@$$BY0A@H@@QEAA@XZ
+; CHECK: __cdecl Class<int[]>::Class<int[]>(void)
+
+??0?$Class@$$BY04H@@QAE@XZ
+; CHECK: __thiscall Class<int[5]>::Class<int[5]>(void)
+??0?$Class@$$BY04H@@QEAA@XZ
+; CHECK: __cdecl Class<int[5]>::Class<int[5]>(void)
+
+??0?$Class@$$BY04$$CBH@@QAE@XZ
+; CHECK: __thiscall Class<int const[5]>::Class<int const[5]>(void)
+??0?$Class@$$BY04$$CBH@@QEAA@XZ
+; CHECK: __cdecl Class<int const[5]>::Class<int const[5]>(void)
+
+??0?$Class@$$BY04QAH@@QAE@XZ
+; CHECK: __thiscall Class<int *const[5]>::Class<int *const[5]>(void)
+??0?$Class@$$BY04QEAH@@QEAA@XZ
+; CHECK: __cdecl Class<int *const[5]>::Class<int *const[5]>(void)
+
+??0?$BoolTemplate@$0A@@@QAE@XZ
+; CHECK: __thiscall BoolTemplate<0>::BoolTemplate<0>(void)
+??0?$BoolTemplate@$0A@@@QEAA@XZ
+; CHECK: __cdecl BoolTemplate<0>::BoolTemplate<0>(void)
+
+??0?$BoolTemplate@$00@@QAE@XZ
+; CHECK: __thiscall BoolTemplate<1>::BoolTemplate<1>(void)
+??0?$BoolTemplate@$00@@QEAA@XZ
+; CHECK: __cdecl BoolTemplate<1>::BoolTemplate<1>(void)
+
+??$Foo@H@?$BoolTemplate@$00@@QAEXH@Z
+; CHECK: void __thiscall BoolTemplate<1>::Foo<int>(int)
+??$Foo@H@?$BoolTemplate@$00@@QEAAXH@Z
+; CHECK: void __cdecl BoolTemplate<1>::Foo<int>(int)
+
+??0?$IntTemplate@$0A@@@QAE@XZ
+; CHECK: __thiscall IntTemplate<0>::IntTemplate<0>(void)
+??0?$IntTemplate@$0A@@@QEAA@XZ
+; CHECK: __cdecl IntTemplate<0>::IntTemplate<0>(void)
+
+??0?$IntTemplate@$04@@QAE@XZ
+; CHECK: __thiscall IntTemplate<5>::IntTemplate<5>(void)
+??0?$IntTemplate@$04@@QEAA@XZ
+; CHECK: __cdecl IntTemplate<5>::IntTemplate<5>(void)
+
+??0?$IntTemplate@$0L@@@QAE@XZ
+; CHECK: __thiscall IntTemplate<11>::IntTemplate<11>(void)
+??0?$IntTemplate@$0L@@@QEAA@XZ
+; CHECK: __cdecl IntTemplate<11>::IntTemplate<11>(void)
+
+??0?$IntTemplate@$0BAA@@@QAE@XZ
+; CHECK: __thiscall IntTemplate<256>::IntTemplate<256>(void)
+??0?$IntTemplate@$0BAA@@@QEAA@XZ
+; CHECK: __cdecl IntTemplate<256>::IntTemplate<256>(void)
+
+??0?$IntTemplate@$0CAB@@@QAE@XZ
+; CHECK: __thiscall IntTemplate<513>::IntTemplate<513>(void)
+??0?$IntTemplate@$0CAB@@@QEAA@XZ
+; CHECK: __cdecl IntTemplate<513>::IntTemplate<513>(void)
+
+??0?$IntTemplate@$0EAC@@@QAE@XZ
+; CHECK: __thiscall IntTemplate<1026>::IntTemplate<1026>(void)
+??0?$IntTemplate@$0EAC@@@QEAA@XZ
+; CHECK: __cdecl IntTemplate<1026>::IntTemplate<1026>(void)
+
+??0?$IntTemplate@$0PPPP@@@QAE@XZ
+; CHECK: __thiscall IntTemplate<65535>::IntTemplate<65535>(void)
+??0?$IntTemplate@$0PPPP@@@QEAA@XZ
+; CHECK: __cdecl IntTemplate<65535>::IntTemplate<65535>(void)
+
+??0?$IntTemplate@$0?0@@QAE@XZ
+; CHECK: __thiscall IntTemplate<-1>::IntTemplate<-1>(void)
+??0?$IntTemplate@$0?0@@QEAA@XZ
+; CHECK: __cdecl IntTemplate<-1>::IntTemplate<-1>(void)
+
+??0?$IntTemplate@$0?8@@QAE@XZ
+; CHECK: __thiscall IntTemplate<-9>::IntTemplate<-9>(void)
+??0?$IntTemplate@$0?8@@QEAA@XZ
+; CHECK: __cdecl IntTemplate<-9>::IntTemplate<-9>(void)
+
+??0?$IntTemplate@$0?9@@QAE@XZ
+; CHECK: __thiscall IntTemplate<-10>::IntTemplate<-10>(void)
+??0?$IntTemplate@$0?9@@QEAA@XZ
+; CHECK: __cdecl IntTemplate<-10>::IntTemplate<-10>(void)
+
+??0?$IntTemplate@$0?L@@@QAE@XZ
+; CHECK: __thiscall IntTemplate<-11>::IntTemplate<-11>(void)
+??0?$IntTemplate@$0?L@@@QEAA@XZ
+; CHECK: __cdecl IntTemplate<-11>::IntTemplate<-11>(void)
+
+??0?$UnsignedIntTemplate@$0PPPPPPPP@@@QAE@XZ
+; CHECK: __thiscall UnsignedIntTemplate<4294967295>::UnsignedIntTemplate<4294967295>(void)
+??0?$UnsignedIntTemplate@$0PPPPPPPP@@@QEAA@XZ
+; CHECK: __cdecl UnsignedIntTemplate<4294967295>::UnsignedIntTemplate<4294967295>(void)
+
+??0?$LongLongTemplate@$0?IAAAAAAAAAAAAAAA@@@QAE@XZ
+; CHECK: __thiscall LongLongTemplate<-9223372036854775808>::LongLongTemplate<-9223372036854775808>(void)
+??0?$LongLongTemplate@$0?IAAAAAAAAAAAAAAA@@@QEAA@XZ
+; CHECK: __cdecl LongLongTemplate<-9223372036854775808>::LongLongTemplate<-9223372036854775808>(void)
+
+??0?$LongLongTemplate@$0HPPPPPPPPPPPPPPP@@@QAE@XZ
+; CHECK: __thiscall LongLongTemplate<9223372036854775807>::LongLongTemplate<9223372036854775807>(void)
+??0?$LongLongTemplate@$0HPPPPPPPPPPPPPPP@@@QEAA@XZ
+; CHECK: __cdecl LongLongTemplate<9223372036854775807>::LongLongTemplate<9223372036854775807>(void)
+
+; -1 is indistinguishable from uint64_max in this encoding.
+??0?$UnsignedLongLongTemplate@$0?0@@QAE@XZ
+; CHECK: __thiscall UnsignedLongLongTemplate<-1>::UnsignedLongLongTemplate<-1>(void)
+??0?$UnsignedLongLongTemplate@$0?0@@QEAA@XZ
+; CHECK: __cdecl UnsignedLongLongTemplate<-1>::UnsignedLongLongTemplate<-1>(void)
+
+??$foo@H@space@@YAABHABH@Z
+; CHECK: int const & __cdecl space::foo<int>(int const &)
+??$foo@H@space@@YAAEBHAEBH@Z
+; CHECK: int const & __cdecl space::foo<int>(int const &)
+
+??$FunctionPointerTemplate@$1?spam@@YAXXZ@@YAXXZ
+; CHECK: void __cdecl FunctionPointerTemplate<&void __cdecl spam(void)>(void)
+
+??$variadic_fn_template@HHHH@@YAXABH000@Z
+; CHECK: void __cdecl variadic_fn_template<int, int, int, int>(int const &, int const &, int const &, int const &)
+??$variadic_fn_template@HHD$$BY01D@@YAXABH0ABDAAY01$$CBD@Z
+; CHECK: void __cdecl variadic_fn_template<int, int, char, char[2]>(int const &, int const &, char const &, char const (&)[2]
+
+??0?$VariadicClass@HD_N@@QAE@XZ
+; CHECK: __thiscall VariadicClass<int, char, bool>::VariadicClass<int, char, bool>(void)
+
+??0?$VariadicClass@_NDH@@QAE@XZ
+; CHECK: __thiscall VariadicClass<bool, char, int>::VariadicClass<bool, char, int>(void)
+
+
+?template_template_fun@@YAXU?$Type@U?$Thing@USecond@@$00@@USecond@@@@@Z
+; CHECK: void __cdecl template_template_fun(struct Type<struct Thing<struct Second, 1>, struct Second>)
+
+??$template_template_specialization@$$A6AXU?$Type@U?$Thing@USecond@@$00@@USecond@@@@@Z@@YAXXZ
+; CHECK: void __cdecl template_template_specialization<void __cdecl(struct Type<struct Thing<struct Second, 1>, struct Second>)>(void)
+
+?f@@YAXU?$S1@$0A@@@@Z
+; CHECK: void __cdecl f(struct S1<0>)
+
+?recref@@YAXU?$type1@$E?inst@@3Urecord@@B@@@Z
+; CHECK: void __cdecl recref(struct type1<struct record const inst>)
+
+?fun@@YAXU?$UUIDType1@Uuuid@@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z
+; CHECK: void __cdecl fun(struct UUIDType1<struct uuid, &struct __s_GUID const _GUID_12345678_1234_1234_1234_1234567890ab>)
+?fun@@YAXU?$UUIDType2@Uuuid@@$E?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z
+; CHECK: void __cdecl fun(struct UUIDType2<struct uuid, struct __s_GUID const _GUID_12345678_1234_1234_1234_1234567890ab>)
+
+?FunctionDefinedWithInjectedName@@YAXU?$TypeWithFriendDefinition@H@@@Z
+; CHECK: void __cdecl FunctionDefinedWithInjectedName(struct TypeWithFriendDefinition<int>)
+
+?bar@?$UUIDType4@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@QAEXXZ
+; CHECK: void __thiscall UUIDType4<&struct __s_GUID const _GUID_12345678_1234_1234_1234_1234567890ab>::bar(void)
\ No newline at end of file