forked from OSchip/llvm-project
[MS Demangler] Add rudimentary C++11 Support
This patch adds support for demangling r-value references, new operators such as the ""_foo operator, lambdas, alias types, nullptr_t, and various other C++11'isms. There is 1 failing test remaining in this file, which appears to be related to back-referencing. This type of problem has the potential to get ugly so I'd rather fix it in a separate patch. Differential Revision: https://reviews.llvm.org/D50013 llvm-svn: 338324
This commit is contained in:
parent
8f6d65c685
commit
931e879cef
|
@ -139,7 +139,7 @@ enum class StorageClass : uint8_t {
|
||||||
|
|
||||||
enum class QualifierMangleMode { Drop, Mangle, Result };
|
enum class QualifierMangleMode { Drop, Mangle, Result };
|
||||||
|
|
||||||
enum class PointerAffinity { Pointer, Reference };
|
enum class PointerAffinity { Pointer, Reference, RValueReference };
|
||||||
|
|
||||||
// Calling conventions
|
// Calling conventions
|
||||||
enum class CallingConv : uint8_t {
|
enum class CallingConv : uint8_t {
|
||||||
|
@ -163,7 +163,6 @@ enum class PrimTy : uint8_t {
|
||||||
None,
|
None,
|
||||||
Function,
|
Function,
|
||||||
Ptr,
|
Ptr,
|
||||||
Ref,
|
|
||||||
MemberPtr,
|
MemberPtr,
|
||||||
Array,
|
Array,
|
||||||
|
|
||||||
|
@ -177,6 +176,8 @@ enum class PrimTy : uint8_t {
|
||||||
Char,
|
Char,
|
||||||
Schar,
|
Schar,
|
||||||
Uchar,
|
Uchar,
|
||||||
|
Char16,
|
||||||
|
Char32,
|
||||||
Short,
|
Short,
|
||||||
Ushort,
|
Ushort,
|
||||||
Int,
|
Int,
|
||||||
|
@ -189,6 +190,7 @@ enum class PrimTy : uint8_t {
|
||||||
Float,
|
Float,
|
||||||
Double,
|
Double,
|
||||||
Ldouble,
|
Ldouble,
|
||||||
|
Nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function classes
|
// Function classes
|
||||||
|
@ -205,14 +207,20 @@ enum FuncClass : uint8_t {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct Type;
|
struct Type;
|
||||||
|
struct Name;
|
||||||
|
|
||||||
// Represents a list of parameters (template params or function arguments.
|
// Represents a list of parameters (template params or function arguments.
|
||||||
// It's represented as a linked list.
|
// It's represented as a linked list.
|
||||||
struct ParamList {
|
struct ParamList {
|
||||||
bool IsVariadic = false;
|
bool IsVariadic = false;
|
||||||
|
|
||||||
|
// If this is a type, Current will be valid and AliasName will be null.
|
||||||
Type *Current = nullptr;
|
Type *Current = nullptr;
|
||||||
|
|
||||||
|
// If this is an alias (e.g. using X = Y), Current will be null and AliasName
|
||||||
|
// will be valid.
|
||||||
|
Name *AliasName = nullptr;
|
||||||
|
|
||||||
ParamList *Next = nullptr;
|
ParamList *Next = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -254,7 +262,7 @@ struct Name {
|
||||||
StringView Operator;
|
StringView Operator;
|
||||||
|
|
||||||
// Template parameters. Null if not a template.
|
// Template parameters. Null if not a template.
|
||||||
ParamList TemplateParams;
|
ParamList *TemplateParams = nullptr;
|
||||||
|
|
||||||
// Nested BackReferences (e.g. "A::B::C") are represented as a linked list.
|
// Nested BackReferences (e.g. "A::B::C") are represented as a linked list.
|
||||||
Name *Next = nullptr;
|
Name *Next = nullptr;
|
||||||
|
@ -265,6 +273,8 @@ struct PointerType : public Type {
|
||||||
void outputPre(OutputStream &OS) override;
|
void outputPre(OutputStream &OS) override;
|
||||||
void outputPost(OutputStream &OS) override;
|
void outputPost(OutputStream &OS) override;
|
||||||
|
|
||||||
|
PointerAffinity Affinity;
|
||||||
|
|
||||||
// Represents a type X in "a pointer to X", "a reference to X",
|
// Represents a type X in "a pointer to X", "a reference to X",
|
||||||
// "an array of X", or "a function returning X".
|
// "an array of X", or "a function returning X".
|
||||||
Type *Pointee = nullptr;
|
Type *Pointee = nullptr;
|
||||||
|
@ -324,9 +334,13 @@ struct ArrayType : public Type {
|
||||||
|
|
||||||
static bool isMemberPointer(StringView MangledName) {
|
static bool isMemberPointer(StringView MangledName) {
|
||||||
switch (MangledName.popFront()) {
|
switch (MangledName.popFront()) {
|
||||||
|
case '$':
|
||||||
|
// This is probably an rvalue reference (e.g. $$Q), and you cannot have an
|
||||||
|
// rvalue reference to a member.
|
||||||
|
return false;
|
||||||
case 'A':
|
case 'A':
|
||||||
// 'A' indicates a reference, and you cannot have a reference to a member
|
// 'A' indicates a reference, and you cannot have a reference to a member
|
||||||
// function or member variable.
|
// function or member.
|
||||||
return false;
|
return false;
|
||||||
case 'P':
|
case 'P':
|
||||||
case 'Q':
|
case 'Q':
|
||||||
|
@ -449,17 +463,25 @@ static bool startsWithLocalScopePattern(StringView S) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void outputName(OutputStream &OS, const Name *TheName);
|
||||||
|
|
||||||
// Write a function or template parameter list.
|
// Write a function or template parameter list.
|
||||||
static void outputParameterList(OutputStream &OS, const ParamList &Params) {
|
static void outputParameterList(OutputStream &OS, const ParamList &Params,
|
||||||
if (!Params.Current) {
|
bool EmptyAsVoid) {
|
||||||
OS << "void";
|
if (!Params.Current && !Params.AliasName) {
|
||||||
|
if (EmptyAsVoid)
|
||||||
|
OS << "void";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ParamList *Head = &Params;
|
const ParamList *Head = &Params;
|
||||||
while (Head) {
|
while (Head) {
|
||||||
Type::outputPre(OS, *Head->Current);
|
if (Head->Current) {
|
||||||
Type::outputPost(OS, *Head->Current);
|
Type::outputPre(OS, *Head->Current);
|
||||||
|
Type::outputPost(OS, *Head->Current);
|
||||||
|
} else if (Head->AliasName) {
|
||||||
|
outputName(OS, Head->AliasName);
|
||||||
|
}
|
||||||
|
|
||||||
Head = Head->Next;
|
Head = Head->Next;
|
||||||
|
|
||||||
|
@ -469,11 +491,11 @@ static void outputParameterList(OutputStream &OS, const ParamList &Params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outputTemplateParams(OutputStream &OS, const Name &TheName) {
|
static void outputTemplateParams(OutputStream &OS, const Name &TheName) {
|
||||||
if (!TheName.TemplateParams.Current)
|
if (!TheName.TemplateParams)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
OS << "<";
|
OS << "<";
|
||||||
outputParameterList(OS, TheName.TemplateParams);
|
outputParameterList(OS, *TheName.TemplateParams, false);
|
||||||
OS << ">";
|
OS << ">";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,6 +599,12 @@ void Type::outputPre(OutputStream &OS) {
|
||||||
case PrimTy::Uchar:
|
case PrimTy::Uchar:
|
||||||
OS << "unsigned char";
|
OS << "unsigned char";
|
||||||
break;
|
break;
|
||||||
|
case PrimTy::Char16:
|
||||||
|
OS << "char16_t";
|
||||||
|
break;
|
||||||
|
case PrimTy::Char32:
|
||||||
|
OS << "char32_t";
|
||||||
|
break;
|
||||||
case PrimTy::Short:
|
case PrimTy::Short:
|
||||||
OS << "short";
|
OS << "short";
|
||||||
break;
|
break;
|
||||||
|
@ -613,6 +641,9 @@ void Type::outputPre(OutputStream &OS) {
|
||||||
case PrimTy::Ldouble:
|
case PrimTy::Ldouble:
|
||||||
OS << "long double";
|
OS << "long double";
|
||||||
break;
|
break;
|
||||||
|
case PrimTy::Nullptr:
|
||||||
|
OS << "std::nullptr_t";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false && "Invalid primitive type!");
|
assert(false && "Invalid primitive type!");
|
||||||
}
|
}
|
||||||
|
@ -647,8 +678,10 @@ static void outputPointerIndicator(OutputStream &OS, PointerAffinity Affinity,
|
||||||
|
|
||||||
if (Affinity == PointerAffinity::Pointer)
|
if (Affinity == PointerAffinity::Pointer)
|
||||||
OS << "*";
|
OS << "*";
|
||||||
else
|
else if (Affinity == PointerAffinity::Reference)
|
||||||
OS << "&";
|
OS << "&";
|
||||||
|
else
|
||||||
|
OS << "&&";
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointerType::outputPre(OutputStream &OS) {
|
void PointerType::outputPre(OutputStream &OS) {
|
||||||
|
@ -659,9 +692,6 @@ void PointerType::outputPre(OutputStream &OS) {
|
||||||
if (Quals & Q_Unaligned)
|
if (Quals & Q_Unaligned)
|
||||||
OS << "__unaligned ";
|
OS << "__unaligned ";
|
||||||
|
|
||||||
PointerAffinity Affinity = (Prim == PrimTy::Ptr) ? PointerAffinity::Pointer
|
|
||||||
: PointerAffinity::Reference;
|
|
||||||
|
|
||||||
outputPointerIndicator(OS, Affinity, nullptr, Pointee);
|
outputPointerIndicator(OS, Affinity, nullptr, Pointee);
|
||||||
|
|
||||||
// FIXME: We should output this, but it requires updating lots of tests.
|
// FIXME: We should output this, but it requires updating lots of tests.
|
||||||
|
@ -725,12 +755,21 @@ void FunctionType::outputPre(OutputStream &OS) {
|
||||||
|
|
||||||
void FunctionType::outputPost(OutputStream &OS) {
|
void FunctionType::outputPost(OutputStream &OS) {
|
||||||
OS << "(";
|
OS << "(";
|
||||||
outputParameterList(OS, Params);
|
outputParameterList(OS, Params, true);
|
||||||
OS << ")";
|
OS << ")";
|
||||||
if (Quals & Q_Const)
|
if (Quals & Q_Const)
|
||||||
OS << " const";
|
OS << " const";
|
||||||
if (Quals & Q_Volatile)
|
if (Quals & Q_Volatile)
|
||||||
OS << " volatile";
|
OS << " volatile";
|
||||||
|
if (Quals & Q_Restrict)
|
||||||
|
OS << " __restrict";
|
||||||
|
if (Quals & Q_Unaligned)
|
||||||
|
OS << " __unaligned";
|
||||||
|
|
||||||
|
if (RefKind == ReferenceKind::LValueRef)
|
||||||
|
OS << " &";
|
||||||
|
else if (RefKind == ReferenceKind::RValueRef)
|
||||||
|
OS << " &&";
|
||||||
|
|
||||||
if (ReturnType)
|
if (ReturnType)
|
||||||
Type::outputPost(OS, *ReturnType);
|
Type::outputPost(OS, *ReturnType);
|
||||||
|
@ -820,7 +859,7 @@ private:
|
||||||
|
|
||||||
ArrayType *demangleArrayType(StringView &MangledName);
|
ArrayType *demangleArrayType(StringView &MangledName);
|
||||||
|
|
||||||
ParamList demangleTemplateParameterList(StringView &MangledName);
|
ParamList *demangleTemplateParameterList(StringView &MangledName);
|
||||||
ParamList demangleFunctionParameterList(StringView &MangledName);
|
ParamList demangleFunctionParameterList(StringView &MangledName);
|
||||||
|
|
||||||
int demangleNumber(StringView &MangledName);
|
int demangleNumber(StringView &MangledName);
|
||||||
|
@ -846,7 +885,8 @@ private:
|
||||||
Name *demangleAnonymousNamespaceName(StringView &MangledName);
|
Name *demangleAnonymousNamespaceName(StringView &MangledName);
|
||||||
Name *demangleLocallyScopedNamePiece(StringView &MangledName);
|
Name *demangleLocallyScopedNamePiece(StringView &MangledName);
|
||||||
|
|
||||||
void demangleOperator(StringView &MangledName, Name *);
|
StringView demangleSimpleString(StringView &MangledName, bool Memorize);
|
||||||
|
|
||||||
FuncClass demangleFunctionClass(StringView &MangledName);
|
FuncClass demangleFunctionClass(StringView &MangledName);
|
||||||
CallingConv demangleCallingConvention(StringView &MangledName);
|
CallingConv demangleCallingConvention(StringView &MangledName);
|
||||||
StorageClass demangleVariableStorageClass(StringView &MangledName);
|
StorageClass demangleVariableStorageClass(StringView &MangledName);
|
||||||
|
@ -931,7 +971,6 @@ Type *Demangler::demangleVariableEncoding(StringView &MangledName) {
|
||||||
// ::= <type> <pointee-cvr-qualifiers> # pointers, references
|
// ::= <type> <pointee-cvr-qualifiers> # pointers, references
|
||||||
switch (Ty->Prim) {
|
switch (Ty->Prim) {
|
||||||
case PrimTy::Ptr:
|
case PrimTy::Ptr:
|
||||||
case PrimTy::Ref:
|
|
||||||
case PrimTy::MemberPtr: {
|
case PrimTy::MemberPtr: {
|
||||||
Qualifiers ExtraChildQuals = Q_None;
|
Qualifiers ExtraChildQuals = Q_None;
|
||||||
Ty->Quals =
|
Ty->Quals =
|
||||||
|
@ -1148,6 +1187,19 @@ Name *Demangler::demangleOperatorName(StringView &MangledName) {
|
||||||
case '_':
|
case '_':
|
||||||
if (MangledName.consumeFront("L"))
|
if (MangledName.consumeFront("L"))
|
||||||
return " co_await";
|
return " co_await";
|
||||||
|
if (MangledName.consumeFront("K")) {
|
||||||
|
size_t EndPos = MangledName.find('@');
|
||||||
|
if (EndPos == StringView::npos)
|
||||||
|
break;
|
||||||
|
StringView OpName = demangleSimpleString(MangledName, false);
|
||||||
|
size_t FullSize = OpName.size() + 3; // <space>""OpName
|
||||||
|
char *Buffer = Arena.allocUnalignedBuffer(FullSize);
|
||||||
|
Buffer[0] = ' ';
|
||||||
|
Buffer[1] = '"';
|
||||||
|
Buffer[2] = '"';
|
||||||
|
std::memcpy(Buffer + 3, OpName.begin(), OpName.size());
|
||||||
|
return {Buffer, FullSize};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1161,20 +1213,31 @@ Name *Demangler::demangleOperatorName(StringView &MangledName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Name *Demangler::demangleSimpleName(StringView &MangledName, bool Memorize) {
|
Name *Demangler::demangleSimpleName(StringView &MangledName, bool Memorize) {
|
||||||
|
StringView S = demangleSimpleString(MangledName, Memorize);
|
||||||
|
if (Error)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
Name *Node = Arena.alloc<Name>();
|
Name *Node = Arena.alloc<Name>();
|
||||||
|
Node->Str = S;
|
||||||
|
return Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView Demangler::demangleSimpleString(StringView &MangledName,
|
||||||
|
bool Memorize) {
|
||||||
|
StringView S;
|
||||||
for (size_t i = 0; i < MangledName.size(); ++i) {
|
for (size_t i = 0; i < MangledName.size(); ++i) {
|
||||||
if (MangledName[i] != '@')
|
if (MangledName[i] != '@')
|
||||||
continue;
|
continue;
|
||||||
Node->Str = MangledName.substr(0, i);
|
S = MangledName.substr(0, i);
|
||||||
MangledName = MangledName.dropFront(i + 1);
|
MangledName = MangledName.dropFront(i + 1);
|
||||||
|
|
||||||
if (Memorize)
|
if (Memorize)
|
||||||
memorizeString(Node->Str);
|
memorizeString(S);
|
||||||
return Node;
|
return S;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error = true;
|
Error = true;
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Name *Demangler::demangleAnonymousNamespaceName(StringView &MangledName) {
|
Name *Demangler::demangleAnonymousNamespaceName(StringView &MangledName) {
|
||||||
|
@ -1429,6 +1492,38 @@ Demangler::demangleQualifiers(StringView &MangledName) {
|
||||||
return std::make_pair(Q_None, false);
|
return std::make_pair(Q_None, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isTagType(StringView S) {
|
||||||
|
switch (S.front()) {
|
||||||
|
case 'T': // union
|
||||||
|
case 'U': // struct
|
||||||
|
case 'V': // class
|
||||||
|
case 'W': // enum
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isPointerType(StringView S) {
|
||||||
|
if (S.startsWith("$$Q")) // foo &&
|
||||||
|
return true;
|
||||||
|
|
||||||
|
switch (S.front()) {
|
||||||
|
case 'A': // foo &
|
||||||
|
case 'P': // foo *
|
||||||
|
case 'Q': // foo *const
|
||||||
|
case 'R': // foo *volatile
|
||||||
|
case 'S': // foo *const volatile
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isArrayType(StringView S) { return S[0] == 'Y'; }
|
||||||
|
|
||||||
|
static bool isFunctionType(StringView S) {
|
||||||
|
return S.startsWith("$$A8@@") || S.startsWith("$$A6");
|
||||||
|
}
|
||||||
|
|
||||||
// <variable-type> ::= <type> <cvr-qualifiers>
|
// <variable-type> ::= <type> <cvr-qualifiers>
|
||||||
// ::= <type> <pointee-cvr-qualifiers> # pointers, references
|
// ::= <type> <pointee-cvr-qualifiers> # pointers, references
|
||||||
Type *Demangler::demangleType(StringView &MangledName,
|
Type *Demangler::demangleType(StringView &MangledName,
|
||||||
|
@ -1447,32 +1542,33 @@ Type *Demangler::demangleType(StringView &MangledName,
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *Ty = nullptr;
|
Type *Ty = nullptr;
|
||||||
switch (MangledName.front()) {
|
if (isTagType(MangledName))
|
||||||
case 'T': // union
|
|
||||||
case 'U': // struct
|
|
||||||
case 'V': // class
|
|
||||||
case 'W': // enum
|
|
||||||
Ty = demangleClassType(MangledName);
|
Ty = demangleClassType(MangledName);
|
||||||
break;
|
else if (isPointerType(MangledName)) {
|
||||||
case 'A': // foo &
|
|
||||||
case 'P': // foo *
|
|
||||||
case 'Q': // foo *const
|
|
||||||
case 'R': // foo *volatile
|
|
||||||
case 'S': // foo *const volatile
|
|
||||||
if (!IsMemberKnown)
|
if (!IsMemberKnown)
|
||||||
IsMember = isMemberPointer(MangledName);
|
IsMember = isMemberPointer(MangledName);
|
||||||
|
|
||||||
if (IsMember)
|
if (IsMember)
|
||||||
Ty = demangleMemberPointerType(MangledName);
|
Ty = demangleMemberPointerType(MangledName);
|
||||||
else
|
else
|
||||||
Ty = demanglePointerType(MangledName);
|
Ty = demanglePointerType(MangledName);
|
||||||
break;
|
} else if (isArrayType(MangledName))
|
||||||
case 'Y':
|
|
||||||
Ty = demangleArrayType(MangledName);
|
Ty = demangleArrayType(MangledName);
|
||||||
break;
|
else if (isFunctionType(MangledName)) {
|
||||||
default:
|
if (MangledName.consumeFront("$$A8@@"))
|
||||||
|
Ty = demangleFunctionType(MangledName, true, false);
|
||||||
|
else {
|
||||||
|
assert(MangledName.startsWith("$$A6"));
|
||||||
|
MangledName.consumeFront("$$A6");
|
||||||
|
Ty = demangleFunctionType(MangledName, false, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
Ty = demangleBasicType(MangledName);
|
Ty = demangleBasicType(MangledName);
|
||||||
break;
|
assert(Ty && !Error);
|
||||||
|
if (!Ty || Error)
|
||||||
|
return Ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ty->Quals = Qualifiers(Ty->Quals | Quals);
|
Ty->Quals = Qualifiers(Ty->Quals | Quals);
|
||||||
return Ty;
|
return Ty;
|
||||||
}
|
}
|
||||||
|
@ -1535,6 +1631,11 @@ Type *Demangler::demangleFunctionEncoding(StringView &MangledName) {
|
||||||
Type *Demangler::demangleBasicType(StringView &MangledName) {
|
Type *Demangler::demangleBasicType(StringView &MangledName) {
|
||||||
Type *Ty = Arena.alloc<Type>();
|
Type *Ty = Arena.alloc<Type>();
|
||||||
|
|
||||||
|
if (MangledName.consumeFront("$$T")) {
|
||||||
|
Ty->Prim = PrimTy::Nullptr;
|
||||||
|
return Ty;
|
||||||
|
}
|
||||||
|
|
||||||
switch (MangledName.popFront()) {
|
switch (MangledName.popFront()) {
|
||||||
case 'X':
|
case 'X':
|
||||||
Ty->Prim = PrimTy::Void;
|
Ty->Prim = PrimTy::Void;
|
||||||
|
@ -1593,11 +1694,21 @@ Type *Demangler::demangleBasicType(StringView &MangledName) {
|
||||||
case 'W':
|
case 'W':
|
||||||
Ty->Prim = PrimTy::Wchar;
|
Ty->Prim = PrimTy::Wchar;
|
||||||
break;
|
break;
|
||||||
|
case 'S':
|
||||||
|
Ty->Prim = PrimTy::Char16;
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
Ty->Prim = PrimTy::Char32;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
Error = true;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
Error = true;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
return Ty;
|
return Ty;
|
||||||
}
|
}
|
||||||
|
@ -1632,6 +1743,9 @@ UdtType *Demangler::demangleClassType(StringView &MangledName) {
|
||||||
|
|
||||||
static std::pair<Qualifiers, PointerAffinity>
|
static std::pair<Qualifiers, PointerAffinity>
|
||||||
demanglePointerCVQualifiers(StringView &MangledName) {
|
demanglePointerCVQualifiers(StringView &MangledName) {
|
||||||
|
if (MangledName.consumeFront("$$Q"))
|
||||||
|
return std::make_pair(Q_None, PointerAffinity::RValueReference);
|
||||||
|
|
||||||
switch (MangledName.popFront()) {
|
switch (MangledName.popFront()) {
|
||||||
case 'A':
|
case 'A':
|
||||||
return std::make_pair(Q_None, PointerAffinity::Reference);
|
return std::make_pair(Q_None, PointerAffinity::Reference);
|
||||||
|
@ -1655,11 +1769,10 @@ demanglePointerCVQualifiers(StringView &MangledName) {
|
||||||
PointerType *Demangler::demanglePointerType(StringView &MangledName) {
|
PointerType *Demangler::demanglePointerType(StringView &MangledName) {
|
||||||
PointerType *Pointer = Arena.alloc<PointerType>();
|
PointerType *Pointer = Arena.alloc<PointerType>();
|
||||||
|
|
||||||
PointerAffinity Affinity;
|
std::tie(Pointer->Quals, Pointer->Affinity) =
|
||||||
std::tie(Pointer->Quals, Affinity) = demanglePointerCVQualifiers(MangledName);
|
demanglePointerCVQualifiers(MangledName);
|
||||||
|
|
||||||
Pointer->Prim =
|
Pointer->Prim = PrimTy::Ptr;
|
||||||
(Affinity == PointerAffinity::Pointer) ? PrimTy::Ptr : PrimTy::Ref;
|
|
||||||
if (MangledName.consumeFront("6")) {
|
if (MangledName.consumeFront("6")) {
|
||||||
Pointer->Pointee = demangleFunctionType(MangledName, false, true);
|
Pointer->Pointee = demangleFunctionType(MangledName, false, true);
|
||||||
return Pointer;
|
return Pointer;
|
||||||
|
@ -1805,14 +1918,26 @@ ParamList Demangler::demangleFunctionParameterList(StringView &MangledName) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ParamList Demangler::demangleTemplateParameterList(StringView &MangledName) {
|
ParamList *Demangler::demangleTemplateParameterList(StringView &MangledName) {
|
||||||
ParamList *Head;
|
ParamList *Head;
|
||||||
ParamList **Current = &Head;
|
ParamList **Current = &Head;
|
||||||
while (!Error && !MangledName.startsWith('@')) {
|
while (!Error && !MangledName.startsWith('@')) {
|
||||||
|
|
||||||
// Template parameter lists don't participate in back-referencing.
|
// Template parameter lists don't participate in back-referencing.
|
||||||
*Current = Arena.alloc<ParamList>();
|
*Current = Arena.alloc<ParamList>();
|
||||||
(*Current)->Current = demangleType(MangledName, QualifierMangleMode::Drop);
|
|
||||||
|
// Empty parameter pack.
|
||||||
|
if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") ||
|
||||||
|
MangledName.consumeFront("$$$V")) {
|
||||||
|
if (!MangledName.startsWith('@'))
|
||||||
|
Error = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MangledName.consumeFront("$$Y"))
|
||||||
|
(*Current)->AliasName = demangleFullyQualifiedTypeName(MangledName);
|
||||||
|
else
|
||||||
|
(*Current)->Current =
|
||||||
|
demangleType(MangledName, QualifierMangleMode::Drop);
|
||||||
|
|
||||||
Current = &(*Current)->Next;
|
Current = &(*Current)->Next;
|
||||||
}
|
}
|
||||||
|
@ -1823,7 +1948,7 @@ ParamList Demangler::demangleTemplateParameterList(StringView &MangledName) {
|
||||||
// Template parameter lists cannot be variadic, so it can only be terminated
|
// Template parameter lists cannot be variadic, so it can only be terminated
|
||||||
// by @.
|
// by @.
|
||||||
if (MangledName.consumeFront('@'))
|
if (MangledName.consumeFront('@'))
|
||||||
return *Head;
|
return Head;
|
||||||
Error = true;
|
Error = true;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
; RUN: llvm-undname < %s | FileCheck %s
|
||||||
|
|
||||||
|
; CHECK-NOT: Invalid mangled name
|
||||||
|
|
||||||
|
?a@FTypeWithQuals@@3U?$S@$$A8@@BAHXZ@1@A
|
||||||
|
; CHECK: struct FTypeWithQuals::S<int __cdecl(void) const> FTypeWithQuals::a
|
||||||
|
|
||||||
|
?b@FTypeWithQuals@@3U?$S@$$A8@@CAHXZ@1@A
|
||||||
|
; CHECK: struct FTypeWithQuals::S<int __cdecl(void) volatile> FTypeWithQuals::b
|
||||||
|
|
||||||
|
?c@FTypeWithQuals@@3U?$S@$$A8@@IAAHXZ@1@A
|
||||||
|
; CHECK: struct FTypeWithQuals::S<int __cdecl(void) __restrict> FTypeWithQuals::c
|
||||||
|
|
||||||
|
?d@FTypeWithQuals@@3U?$S@$$A8@@GBAHXZ@1@A
|
||||||
|
; CHECK: struct FTypeWithQuals::S<int __cdecl(void) const &> FTypeWithQuals::d
|
||||||
|
|
||||||
|
?e@FTypeWithQuals@@3U?$S@$$A8@@GCAHXZ@1@A
|
||||||
|
; CHECK: struct FTypeWithQuals::S<int __cdecl(void) volatile &> FTypeWithQuals::e
|
||||||
|
|
||||||
|
?f@FTypeWithQuals@@3U?$S@$$A8@@IGAAHXZ@1@A
|
||||||
|
; CHECK: struct FTypeWithQuals::S<int __cdecl(void) __restrict &> FTypeWithQuals::f
|
||||||
|
|
||||||
|
?g@FTypeWithQuals@@3U?$S@$$A8@@HBAHXZ@1@A
|
||||||
|
; CHECK: struct FTypeWithQuals::S<int __cdecl(void) const &&> FTypeWithQuals::g
|
||||||
|
|
||||||
|
?h@FTypeWithQuals@@3U?$S@$$A8@@HCAHXZ@1@A
|
||||||
|
; CHECK: struct FTypeWithQuals::S<int __cdecl(void) volatile &&> FTypeWithQuals::h
|
||||||
|
|
||||||
|
?i@FTypeWithQuals@@3U?$S@$$A8@@IHAAHXZ@1@A
|
||||||
|
; CHECK: struct FTypeWithQuals::S<int __cdecl(void) __restrict &&> FTypeWithQuals::i
|
||||||
|
|
||||||
|
?j@FTypeWithQuals@@3U?$S@$$A6AHXZ@1@A
|
||||||
|
; CHECK: struct FTypeWithQuals::S<int __cdecl(void)> FTypeWithQuals::j
|
||||||
|
|
||||||
|
?k@FTypeWithQuals@@3U?$S@$$A8@@GAAHXZ@1@A
|
||||||
|
; CHECK: struct FTypeWithQuals::S<int __cdecl(void) &> FTypeWithQuals::k
|
||||||
|
|
||||||
|
?l@FTypeWithQuals@@3U?$S@$$A8@@HAAHXZ@1@A
|
||||||
|
; CHECK: struct FTypeWithQuals::S<int __cdecl(void) &&> FTypeWithQuals::l
|
||||||
|
|
||||||
|
?Char16Var@@3_SA
|
||||||
|
; CHECK: char16_t Char16Var
|
||||||
|
|
||||||
|
?Char32Var@@3_UA
|
||||||
|
; CHECK: char32_t Char32Var
|
||||||
|
|
||||||
|
?LRef@@YAXAAH@Z
|
||||||
|
; CHECK: void __cdecl LRef(int &)
|
||||||
|
|
||||||
|
?RRef@@YAH$$QAH@Z
|
||||||
|
; CHECK: int __cdecl RRef(int &&)
|
||||||
|
|
||||||
|
?Null@@YAX$$T@Z
|
||||||
|
; CHECK: void __cdecl Null(std::nullptr_t)
|
||||||
|
|
||||||
|
?fun@PR18022@@YA?AU<unnamed-type-a>@1@U21@0@Z
|
||||||
|
; CHECK: struct PR18022::<unnamed-type-a> __cdecl PR18022::fun(struct PR18022::<unnamed-type-a>, struct PR18022::<unnamed-type-a>)
|
||||||
|
|
||||||
|
; First, we have the static local variable of type "<lambda_1>" inside of "define_lambda".
|
||||||
|
; decltype(lambda), where lambda = [] { static int local=42; return 42; };
|
||||||
|
?lambda@?1??define_lambda@@YAHXZ@4V<lambda_1>@?0??1@YAHXZ@A
|
||||||
|
; CHECK: class `int __cdecl define_lambda(void)'::`1'::<lambda_1> `int __cdecl define_lambda(void)'::`2'::lambda
|
||||||
|
|
||||||
|
; Next, we have the "operator()" for "<lambda_1>" which is inside of "define_lambda".
|
||||||
|
??R<lambda_1>@?0??define_lambda@@YAHXZ@QBE@XZ
|
||||||
|
; CHECK: __thiscall `int __cdecl define_lambda(void)'::`1'::<lambda_1>::operator()(void) const
|
||||||
|
|
||||||
|
; Finally, we have the local which is inside of "<lambda_1>" which is inside of "define_lambda".
|
||||||
|
?local@?2???R<lambda_1>@?0??define_lambda@@YAHXZ@QBE@XZ@4HA
|
||||||
|
; CHECK: __thiscall `int __cdecl define_lambda(void)'::`1'::<lambda_1>::operator()(void) const
|
||||||
|
|
||||||
|
??$use_lambda_arg@V<lambda_1>@?0??call_with_lambda_arg1@@YAXXZ@@@YAXV<lambda_1>@?0??call_with_lambda_arg1@@YAXXZ@@Z
|
||||||
|
; CHECK: void __cdecl use_lambda_arg<class `void __cdecl call_with_lambda_arg1(void)'::`1'::<lambda_1>>(class `void __cdecl call_with_lambda_arg1(void)'::`1'::<lambda_1>)
|
||||||
|
|
||||||
|
?foo@A@PR19361@@QIGAEXXZ
|
||||||
|
; CHECK: void __thiscall PR19361::A::foo(void) __restrict &
|
||||||
|
|
||||||
|
?foo@A@PR19361@@QIHAEXXZ
|
||||||
|
; CHECK: void __thiscall PR19361::A::foo(void) __restrict &&
|
||||||
|
|
||||||
|
??__K_deg@@YAHO@Z
|
||||||
|
; CHECK: int __cdecl operator ""_deg(long double)
|
||||||
|
|
||||||
|
??$templ_fun_with_pack@$S@@YAXXZ
|
||||||
|
; CHECK: void __cdecl templ_fun_with_pack<>(void)
|
||||||
|
|
||||||
|
??$templ_fun_with_ty_pack@$$$V@@YAXXZ
|
||||||
|
; CHECK: void __cdecl templ_fun_with_ty_pack<>(void)
|
||||||
|
??$templ_fun_with_ty_pack@$$V@@YAXXZ
|
||||||
|
; CHECK: void __cdecl templ_fun_with_ty_pack<>(void)
|
||||||
|
|
||||||
|
??$f@$$YAliasA@PR20047@@@PR20047@@YAXXZ
|
||||||
|
; CHECK: void __cdecl PR20047::f<PR20047::AliasA>(void)
|
||||||
|
|
||||||
|
?f@UnnamedType@@YAXAAU<unnamed-type-TD>@A@1@@Z
|
||||||
|
; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::A::<unnamed-type-TD> &)
|
||||||
|
|
||||||
|
?f@UnnamedType@@YAXPAW4<unnamed-type-e>@?$B@H@1@@Z
|
||||||
|
; CHECK: void __cdecl UnnamedType::f(enum UnnamedType::B<int>::<unnamed-type-e> *)
|
||||||
|
|
||||||
|
??$f@W4<unnamed-type-E>@?1??g@PR24651@@YAXXZ@@PR24651@@YAXW4<unnamed-type-E>@?1??g@0@YAXXZ@@Z
|
||||||
|
; We have a back-referencing problem here, we print `void __cdecl <unnamed-type-E>::g(void)`
|
||||||
|
; for the second occurrence of g.
|
||||||
|
; FIXME: void __cdecl PR24651::f<enum `void __cdecl PR24651::g(void)'::`2'::<unnamed-type-E>>(enum `void __cdecl PR24651::g(void)'::`2'::<unnamed-type-E>)
|
||||||
|
|
||||||
|
??$f@T<unnamed-type-$S1>@PR18204@@@PR18204@@YAHPAT<unnamed-type-$S1>@0@@Z
|
||||||
|
; FIXME: int __cdecl PR18204::f<union PR18204::<unnamed-type-$S1>>(union PR18204::<unnamed-type-$S1> *)
|
||||||
|
|
||||||
|
??R<lambda_0>@?0??PR26105@@YAHXZ@QBE@H@Z
|
||||||
|
; CHECK: __thiscall `int __cdecl PR26105(void)'::`1'::<lambda_0>::operator()(int) const
|
||||||
|
|
||||||
|
??R<lambda_1>@?0???R<lambda_0>@?0??PR26105@@YAHXZ@QBE@H@Z@QBE@H@Z
|
||||||
|
; CHECK: __thiscall `__thiscall `int __cdecl PR26105(void)'::`1'::<lambda_0>::operator()(int) const'::`1'::<lambda_1>::operator()(int) const
|
||||||
|
|
||||||
|
?unaligned_foo1@@YAPFAHXZ
|
||||||
|
; CHECK: int __unaligned * __cdecl unaligned_foo1(void)
|
||||||
|
|
||||||
|
?unaligned_foo2@@YAPFAPFAHXZ
|
||||||
|
; CHECK: int __unaligned *__unaligned * __cdecl unaligned_foo2(void)
|
||||||
|
|
||||||
|
?unaligned_foo3@@YAHXZ
|
||||||
|
; CHECK: int __cdecl unaligned_foo3(void)
|
||||||
|
|
||||||
|
?unaligned_foo4@@YAXPFAH@Z
|
||||||
|
; CHECK: void __cdecl unaligned_foo4(int __unaligned *)
|
||||||
|
|
||||||
|
?unaligned_foo5@@YAXPIFAH@Z
|
||||||
|
; CHECK: void __cdecl unaligned_foo5(int __unaligned *__restrict)
|
||||||
|
|
||||||
|
??$unaligned_foo6@PAH@@YAPAHPAH@Z
|
||||||
|
; CHECK: int * __cdecl unaligned_foo6<int *>(int *)
|
||||||
|
|
||||||
|
??$unaligned_foo6@PFAH@@YAPFAHPFAH@Z
|
||||||
|
; CHECK: int __unaligned * __cdecl unaligned_foo6<int __unaligned *>(int __unaligned *)
|
||||||
|
|
||||||
|
?unaligned_foo8@unaligned_foo8_S@@QFCEXXZ
|
||||||
|
; CHECK: void __thiscall unaligned_foo8_S::unaligned_foo8(void) volatile __unaligned
|
||||||
|
|
||||||
|
??R<lambda_1>@x@A@PR31197@@QBE@XZ
|
||||||
|
; CHECK: __thiscall PR31197::A::x::<lambda_1>::operator()(void) const
|
||||||
|
|
||||||
|
?white@?1???R<lambda_1>@x@A@PR31197@@QBE@XZ@4HA
|
||||||
|
; CHECK: int `__thiscall PR31197::A::x::<lambda_1>::operator()(void) const'::`2'::white
|
||||||
|
|
||||||
|
?f@@YAXW4<unnamed-enum-enumerator>@@@Z
|
||||||
|
; CHECK: void __cdecl f(enum <unnamed-enum-enumerator>)
|
Loading…
Reference in New Issue