Skip to content

Commit

Permalink
[MS Demangler] Properly demangle templated operators.
Browse files Browse the repository at this point in the history
After we detected the presence of a template via ?$ we would proceed by
only demangling a simple unqualified name. This means we would fail on
templated operators (and perhaps other yet-to-be-determined things)

This was discovered while doing some refactoring to store richer
semantic information about the demangled types to pave the way for
overhauling the way we handle backreferences. (Specifically, we need to
defer recording or resolving back-references until a symbol has been
completely demangled, because we need to use information that only
occurs later in the mangled string to decide whether a back-reference
should be recorded.)

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

llvm-svn: 338608
  • Loading branch information
Zachary Turner committed Aug 1, 2018
1 parent 54d4ffe commit 44ebbc2
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 31 deletions.
74 changes: 43 additions & 31 deletions llvm/lib/Demangle/MicrosoftDemangle.cpp
Expand Up @@ -204,6 +204,8 @@ enum FuncClass : uint8_t {
Far = 1 << 6,
};

enum class SymbolCategory { Function, Variable };

namespace {

struct Type;
Expand Down Expand Up @@ -265,12 +267,10 @@ struct Name {
// Name read from an MangledName string.
StringView Str;

// Overloaded operators are represented as special BackReferences in mangled
// symbols. If this is an operator name, "op" has an operator name (e.g.
// ">>"). Otherwise, empty.
StringView Operator;
bool IsTemplateInstantiation = false;
bool IsOperator = false;

// Template parameters. Null if not a template.
// Template parameters. Only valid if Flags contains NF_TemplateInstantiation.
TemplateParams *TParams = nullptr;

// Nested BackReferences (e.g. "A::B::C") are represented as a linked list.
Expand Down Expand Up @@ -541,34 +541,34 @@ static void outputName(OutputStream &OS, const Name *TheName) {
for (; TheName->Next; TheName = TheName->Next) {
Previous = TheName;
OS << TheName->Str;
if (TheName->TParams)
if (TheName->IsTemplateInstantiation)
outputParameterList(OS, *TheName->TParams);
OS << "::";
}

// Print out a regular name.
if (TheName->Operator.empty()) {
if (!TheName->IsOperator) {
OS << TheName->Str;
if (TheName->TParams)
if (TheName->IsTemplateInstantiation)
outputParameterList(OS, *TheName->TParams);
return;
}

// Print out ctor or dtor.
if (TheName->Operator == "dtor")
if (TheName->Str == "dtor")
OS << "~";

if (TheName->Operator == "ctor" || TheName->Operator == "dtor") {
if (TheName->Str == "ctor" || TheName->Str == "dtor") {
OS << Previous->Str;
if (Previous->TParams)
outputParameterList(OS, *Previous->TParams);
return;
}

// Print out an overloaded operator.
if (!TheName->Str.empty())
OS << TheName->Str << "::";
OS << "operator" << TheName->Operator;
OS << "operator" << TheName->Str;
if (TheName->IsTemplateInstantiation)
outputParameterList(OS, *TheName->TParams);
}

namespace {
Expand Down Expand Up @@ -853,6 +853,8 @@ void ArrayType::outputPost(OutputStream &OS) {
}

struct Symbol {
SymbolCategory Category;

Name *SymbolName = nullptr;
Type *SymbolType = nullptr;
};
Expand Down Expand Up @@ -906,14 +908,14 @@ class Demangler {
Name *demangleFullyQualifiedTypeName(StringView &MangledName);
Name *demangleFullyQualifiedSymbolName(StringView &MangledName);

Name *demangleUnqualifiedTypeName(StringView &MangledName);
Name *demangleUnqualifiedSymbolName(StringView &MangledName);
Name *demangleUnqualifiedTypeName(StringView &MangledName, bool Memorize);
Name *demangleUnqualifiedSymbolName(StringView &MangledName, bool Memorize);

Name *demangleNameScopeChain(StringView &MangledName, Name *UnqualifiedName);
Name *demangleNameScopePiece(StringView &MangledName);

Name *demangleBackRefName(StringView &MangledName);
Name *demangleClassTemplateName(StringView &MangledName);
Name *demangleTemplateInstantiationName(StringView &MangledName);
Name *demangleOperatorName(StringView &MangledName);
Name *demangleSimpleName(StringView &MangledName, bool Memorize);
Name *demangleAnonymousNamespaceName(StringView &MangledName);
Expand Down Expand Up @@ -981,9 +983,14 @@ Symbol *Demangler::parse(StringView &MangledName) {
if (Error)
return nullptr;
// Read a variable.
S->SymbolType = startsWithDigit(MangledName)
? demangleVariableEncoding(MangledName)
: demangleFunctionEncoding(MangledName);
if (startsWithDigit(MangledName)) {
S->Category = SymbolCategory::Variable;
S->SymbolType = demangleVariableEncoding(MangledName);
} else {
S->Category = SymbolCategory::Function;
S->SymbolType = demangleFunctionEncoding(MangledName);
}

if (Error)
return nullptr;

Expand Down Expand Up @@ -1101,18 +1108,20 @@ Name *Demangler::demangleBackRefName(StringView &MangledName) {
return Node;
}

Name *Demangler::demangleClassTemplateName(StringView &MangledName) {
Name *Demangler::demangleTemplateInstantiationName(StringView &MangledName) {
assert(MangledName.startsWith("?$"));
MangledName.consumeFront("?$");

Name *Node = demangleSimpleName(MangledName, false);
Name *Node = demangleUnqualifiedSymbolName(MangledName, false);
if (Error)
return nullptr;

Node->TParams = demangleTemplateParameterList(MangledName);
if (Error)
return nullptr;

Node->IsTemplateInstantiation = true;

// Render this class template name into a string buffer so that we can
// memorize it for the purpose of back-referencing.
OutputStream OS = OutputStream::create(nullptr, nullptr, 1024);
Expand Down Expand Up @@ -1250,7 +1259,8 @@ Name *Demangler::demangleOperatorName(StringView &MangledName) {
};

Name *Node = Arena.alloc<Name>();
Node->Operator = NameString();
Node->Str = NameString();
Node->IsOperator = true;
return Node;
}

Expand Down Expand Up @@ -1325,7 +1335,7 @@ Name *Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) {

// Parses a type name in the form of A@B@C@@ which represents C::B::A.
Name *Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) {
Name *TypeName = demangleUnqualifiedTypeName(MangledName);
Name *TypeName = demangleUnqualifiedTypeName(MangledName, true);
if (Error)
return nullptr;
assert(TypeName);
Expand All @@ -1341,7 +1351,7 @@ Name *Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) {
// Symbol names have slightly different rules regarding what can appear
// so we separate out the implementations for flexibility.
Name *Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) {
Name *SymbolName = demangleUnqualifiedSymbolName(MangledName);
Name *SymbolName = demangleUnqualifiedSymbolName(MangledName, true);
if (Error)
return nullptr;
assert(SymbolName);
Expand All @@ -1353,7 +1363,8 @@ Name *Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) {
return QualName;
}

Name *Demangler::demangleUnqualifiedTypeName(StringView &MangledName) {
Name *Demangler::demangleUnqualifiedTypeName(StringView &MangledName,
bool Memorize) {
// An inner-most name can be a back-reference, because a fully-qualified name
// (e.g. Scope + Inner) can contain other fully qualified names inside of
// them (for example template parameters), and these nested parameters can
Expand All @@ -1362,27 +1373,28 @@ Name *Demangler::demangleUnqualifiedTypeName(StringView &MangledName) {
return demangleBackRefName(MangledName);

if (MangledName.startsWith("?$"))
return demangleClassTemplateName(MangledName);
return demangleTemplateInstantiationName(MangledName);

return demangleSimpleName(MangledName, true);
return demangleSimpleName(MangledName, Memorize);
}

Name *Demangler::demangleUnqualifiedSymbolName(StringView &MangledName) {
Name *Demangler::demangleUnqualifiedSymbolName(StringView &MangledName,
bool Memorize) {
if (startsWithDigit(MangledName))
return demangleBackRefName(MangledName);
if (MangledName.startsWith("?$"))
return demangleClassTemplateName(MangledName);
return demangleTemplateInstantiationName(MangledName);
if (MangledName.startsWith('?'))
return demangleOperatorName(MangledName);
return demangleSimpleName(MangledName, true);
return demangleSimpleName(MangledName, Memorize);
}

Name *Demangler::demangleNameScopePiece(StringView &MangledName) {
if (startsWithDigit(MangledName))
return demangleBackRefName(MangledName);

if (MangledName.startsWith("?$"))
return demangleClassTemplateName(MangledName);
return demangleTemplateInstantiationName(MangledName);

if (MangledName.startsWith("?A"))
return demangleAnonymousNamespaceName(MangledName);
Expand Down
4 changes: 4 additions & 0 deletions llvm/test/Demangle/ms-back-references.test
Expand Up @@ -51,3 +51,7 @@

?foo@0@YAXXZ
; CHECK: void __cdecl foo::foo(void)

; We have some issues with back-references and class / function templates.
??$?HH@S@@QEAAAEAU0@H@Z
; FIXME: struct S &__cdecl S::operator+<int>(int)
3 changes: 3 additions & 0 deletions llvm/test/Demangle/ms-mangle.test
Expand Up @@ -64,6 +64,9 @@
??Hfoo@@QEAAHH@Z
; CHECK: int __cdecl foo::operator+(int)

??$?HH@S@@QEAAAEANH@Z
; CHECK: double & __cdecl S::operator+<int>(int)

?static_method@foo@@SAPAV1@XZ
; CHECK: static class foo * __cdecl foo::static_method(void)

Expand Down

0 comments on commit 44ebbc2

Please sign in to comment.