[MS Demangler] Fix several issues related to templates.

These were uncovered when porting the mangling tests in
ms-templates.cpp from clang/CodeGenCXX over to demangling
tests.  The main issues fixed here are surrounding integer
literal signed and unsignedness, empty array dimensions,
and pointer and reference non-type template parameters.

Differential Revision: https://reviews.llvm.org/D50512

llvm-svn: 339434
This commit is contained in:
Zachary Turner 2018-08-10 14:31:04 +00:00
parent f337f5b7a5
commit dbefc6cd4e
2 changed files with 285 additions and 34 deletions

View File

@ -234,6 +234,15 @@ struct FunctionParams {
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.
@ -340,14 +349,18 @@ struct UdtType : public Type {
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;
};
@ -510,7 +523,7 @@ static void outputName(OutputStream &OS, const Name *TheName,
static void outputParameterList(OutputStream &OS, const TemplateParams &Params,
NameResolver &Resolver) {
if (!Params.ParamType && !Params.ParamName) {
if (Params.IsEmptyParameterPack) {
OS << "<>";
return;
}
@ -521,9 +534,13 @@ static void outputParameterList(OutputStream &OS, const TemplateParams &Params,
// 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);
@ -867,12 +884,16 @@ void ArrayType::outputPre(OutputStream &OS, NameResolver &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 {
@ -938,7 +959,7 @@ private:
TemplateParams *demangleTemplateParameterList(StringView &MangledName);
FunctionParams demangleFunctionParameterList(StringView &MangledName);
int demangleNumber(StringView &MangledName);
std::pair<uint64_t, bool> demangleNumber(StringView &MangledName);
void memorizeString(StringView s);
@ -1091,21 +1112,21 @@ Type *Demangler::demangleVariableEncoding(StringView &MangledName) {
// ::= <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');
@ -1115,7 +1136,7 @@ int Demangler::demangleNumber(StringView &MangledName) {
}
Error = true;
return 0;
return {0ULL, false};
}
// First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9.
@ -1346,7 +1367,8 @@ Name *Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) {
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('?');
@ -1361,7 +1383,7 @@ Name *Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) {
OS << '`';
output(Scope, OS);
OS << '\'';
OS << "::`" << ScopeIdentifier << "'";
OS << "::`" << Number.first << "'";
OS << '\0';
char *Result = OS.getBuffer();
Node->Str = copyString(Result);
@ -1933,19 +1955,28 @@ ArrayType *Demangler::demangleArrayType(StringView &MangledName) {
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")) {
@ -1958,7 +1989,6 @@ ArrayType *Demangler::demangleArrayType(StringView &MangledName) {
}
ATy->ElementType = demangleType(MangledName, QualifierMangleMode::Drop);
Dim->ElementType = ATy->ElementType;
return ATy;
}
@ -2034,16 +2064,42 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) {
// 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);

View File

@ -0,0 +1,195 @@
; 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)