Add support for various C++14 demanglings.
authorZachary Turner <zturner@google.com>
Wed, 29 Aug 2018 04:12:44 +0000 (04:12 +0000)
committerZachary Turner <zturner@google.com>
Wed, 29 Aug 2018 04:12:44 +0000 (04:12 +0000)
Mostly this includes <auto> and <decltype-auto> return values.
Additionally, this fixes a fairly obscure back-referencing bug
that was encountered in one of the C++14 tests, which is that
if you have something like Foo<&bar, &bar> then the `bar`
forms a backreference.

llvm-svn: 340896

llvm/lib/Demangle/MicrosoftDemangle.cpp
llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
llvm/lib/Demangle/MicrosoftDemangleNodes.h
llvm/test/Demangle/ms-cxx14.test [new file with mode: 0644]

index 0eb0c6d..5081f94 100644 (file)
@@ -191,6 +191,8 @@ static bool isTagType(StringView S) {
   return false;
 }
 
+static bool isCustomType(StringView S) { return S[0] == '?'; }
+
 static bool isPointerType(StringView S) {
   if (S.startsWith("$$Q")) // foo &&
     return true;
@@ -288,6 +290,7 @@ private:
   // Parser functions. This is a recursive-descent parser.
   TypeNode *demangleType(StringView &MangledName, QualifierMangleMode QMM);
   PrimitiveTypeNode *demanglePrimitiveType(StringView &MangledName);
+  CustomTypeNode *demangleCustomType(StringView &MangledName);
   TagTypeNode *demangleClassType(StringView &MangledName);
   PointerTypeNode *demanglePointerType(StringView &MangledName);
   PointerTypeNode *demangleMemberPointerType(StringView &MangledName);
@@ -304,6 +307,7 @@ private:
   int64_t demangleSigned(StringView &MangledName);
 
   void memorizeString(StringView s);
+  void memorizeIdentifier(IdentifierNode *Identifier);
 
   /// Allocate a copy of \p Borrowed into memory that we own.
   StringView copyString(StringView Borrowed);
@@ -972,6 +976,19 @@ NamedIdentifierNode *Demangler::demangleBackRefName(StringView &MangledName) {
   return Backrefs.Names[I];
 }
 
+void Demangler::memorizeIdentifier(IdentifierNode *Identifier) {
+  // 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);
+  Identifier->output(OS, OF_Default);
+  OS << '\0';
+  char *Name = OS.getBuffer();
+
+  StringView Owned = copyString(Name);
+  memorizeString(Owned);
+  std::free(Name);
+}
+
 IdentifierNode *
 Demangler::demangleTemplateInstantiationName(StringView &MangledName,
                                              NameBackrefBehavior NBB) {
@@ -990,18 +1007,8 @@ Demangler::demangleTemplateInstantiationName(StringView &MangledName,
   if (Error)
     return nullptr;
 
-  if (NBB & NBB_Template) {
-    // 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);
-    Identifier->output(OS, OF_Default);
-    OS << '\0';
-    char *Name = OS.getBuffer();
-
-    StringView Owned = copyString(Name);
-    memorizeString(Owned);
-    std::free(Name);
-  }
+  if (NBB & NBB_Template)
+    memorizeIdentifier(Identifier);
 
   return Identifier;
 }
@@ -1749,6 +1756,8 @@ TypeNode *Demangler::demangleType(StringView &MangledName,
       MangledName.consumeFront("$$A6");
       Ty = demangleFunctionType(MangledName, false);
     }
+  } else if (isCustomType(MangledName)) {
+    Ty = demangleCustomType(MangledName);
   } else {
     Ty = demanglePrimitiveType(MangledName);
     assert(Ty && !Error);
@@ -1837,6 +1846,19 @@ Demangler::demangleFunctionEncoding(StringView &MangledName) {
   return Symbol;
 }
 
+CustomTypeNode *Demangler::demangleCustomType(StringView &MangledName) {
+  assert(MangledName.startsWith('?'));
+  MangledName.popFront();
+
+  CustomTypeNode *CTN = Arena.alloc<CustomTypeNode>();
+  CTN->Identifier = demangleUnqualifiedTypeName(MangledName, true);
+  if (!MangledName.consumeFront('@'))
+    Error = true;
+  if (Error)
+    return nullptr;
+  return CTN;
+}
+
 // Reads a primitive type.
 PrimitiveTypeNode *Demangler::demanglePrimitiveType(StringView &MangledName) {
   if (MangledName.consumeFront("$$T"))
@@ -2131,8 +2153,12 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) {
       // I - virtual inheritance      <name> <number> <number> <number>
       // J - unspecified inheritance  <name> <number> <number> <number>
       char InheritanceSpecifier = MangledName.popFront();
-      SymbolNode *S =
-          MangledName.startsWith('?') ? parse(MangledName) : nullptr;
+      SymbolNode *S = nullptr;
+      if (MangledName.startsWith('?')) {
+        S = parse(MangledName);
+        memorizeIdentifier(S->Name->getUnqualifiedIdentifier());
+      }
+
       switch (InheritanceSpecifier) {
       case 'J':
         TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
index 9610981..9d1aa1a 100644 (file)
@@ -565,9 +565,10 @@ void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
     Type->outputPost(OS, Flags);
 }
 
-void CustomNode::output(OutputStream &OS, OutputFlags Flags) const {
-  OS << Name;
+void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
+  Identifier->output(OS, Flags);
 }
+void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
 
 void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
   Components->output(OS, Flags, "::");
index 1797403..93845b5 100644 (file)
@@ -148,7 +148,10 @@ enum class CallingConv : uint8_t {
 
 enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef };
 
-enum OutputFlags { OF_Default = 0, OF_NoCallingConvention = 1 };
+enum OutputFlags {
+  OF_Default = 0,
+  OF_NoCallingConvention = 1,
+};
 
 // Types
 enum class PrimitiveKind {
@@ -392,8 +395,8 @@ struct FunctionSignatureNode : public TypeNode {
   explicit FunctionSignatureNode(NodeKind K) : TypeNode(K) {}
   FunctionSignatureNode() : TypeNode(NodeKind::FunctionSignature) {}
 
-  virtual void outputPre(OutputStream &OS, OutputFlags Flags) const;
-  virtual void outputPost(OutputStream &OS, OutputFlags Flags) const;
+  void outputPre(OutputStream &OS, OutputFlags Flags) const override;
+  void outputPost(OutputStream &OS, OutputFlags Flags) const override;
 
   // Valid if this FunctionTypeNode is the Pointee of a PointerType or
   // MemberPointerType.
@@ -566,13 +569,13 @@ struct IntrinsicNode : public TypeNode {
   void output(OutputStream &OS, OutputFlags Flags) const override {}
 };
 
-struct CustomNode : public Node {
-  CustomNode() : Node(NodeKind::Custom) {}
+struct CustomTypeNode : public TypeNode {
+  CustomTypeNode() : TypeNode(NodeKind::Custom) {}
 
-  void output(OutputStream &OS, OutputFlags Flags) const override;
+  void outputPre(OutputStream &OS, OutputFlags Flags) const override;
+  void outputPost(OutputStream &OS, OutputFlags Flags) const override;
 
-  // The string to print.
-  StringView Name;
+  IdentifierNode *Identifier;
 };
 
 struct NodeArrayNode : public Node {
diff --git a/llvm/test/Demangle/ms-cxx14.test b/llvm/test/Demangle/ms-cxx14.test
new file mode 100644 (file)
index 0000000..a630db8
--- /dev/null
@@ -0,0 +1,37 @@
+; These tests are based on clang/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp
+; RUN: llvm-undname < %s | FileCheck %s
+
+; CHECK-NOT: Invalid mangled name
+
+??$x@X@@3HA
+; CHECK: int x<void>
+
+?FunctionWithLocalType@@YA?A?<auto>@@XZ
+; CHECK: <auto> __cdecl FunctionWithLocalType(void)
+
+?ValueFromFunctionWithLocalType@@3ULocalType@?1??FunctionWithLocalType@@YA?A?<auto>@@XZ@A
+; CHECK: struct `<auto> __cdecl FunctionWithLocalType(void)'::`2'::LocalType ValueFromFunctionWithLocalType
+
+??R<lambda_0>@@QBE?A?<auto>@@XZ
+; CHECK: <auto> __thiscall <lambda_0>::operator()(void) const
+
+?ValueFromLambdaWithLocalType@@3ULocalType@?1???R<lambda_0>@@QBE?A?<auto>@@XZ@A
+; CHECK: struct `<auto> __thiscall <lambda_0>::operator()(void) const'::`2'::LocalType ValueFromLambdaWithLocalType
+
+?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?2???R<lambda_1>@?0???$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?3@XZ@A
+; CHECK: struct `<auto> __thiscall `<auto> __cdecl TemplateFuncionWithLocalLambda<int>(int)'::`1'::<lambda_1>::operator()(void) const'::`3'::LocalType ValueFromTemplateFuncionWithLocalLambda
+
+??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z
+; CHECK: <auto> __cdecl TemplateFuncionWithLocalLambda<int>(int)
+
+??R<lambda_1>@?0???$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?1@XZ
+; CHECK: <auto> __thiscall `<auto> __cdecl TemplateFuncionWithLocalLambda<int>(int)'::`1'::<lambda_1>::operator()(void) const
+
+??$WithPMD@$GA@A@?0@@3HA
+; CHECK: int WithPMD<{0, 0, -1}>
+
+?Zoo@@3U?$Foo@$1??$x@H@@3HA$1?1@3HA@@A
+; CHECK: struct Foo<&int x<int>, &int x<int>> Zoo
+
+??$unaligned_x@PFAH@@3PFAHA
+; CHECK: int __unaligned *unaligned_x<int __unaligned *>