<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Sun, Jul 29, 2018 at 8:12 PM Zachary Turner via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: zturner<br>
Date: Sun Jul 29 20:12:34 2018<br>
New Revision: 338226<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=338226&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=338226&view=rev</a><br>
Log:<br>
[MS Demangler] Demangle symbols in function scopes.<br>
<br>
There are a couple of issues you run into when you start getting into<br>
more complex names, especially with regards to function local statics.<br>
When you've got something like:<br>
<br>
    int x() {<br>
      static int n = 0;<br>
      return n;<br>
    }<br>
<br>
Then this needs to demangle to something like<br>
<br>
    int `int __cdecl x()'::`1'::n<br>
<br>
The nested mangled symbols (e.g. `int __cdecl x()` in the above<br>
example) also share state with regards to back-referencing, so<br>
we need to be able to re-use the demangler in the middle of<br>
demangling a symbol while sharing back-ref state.<br>
<br>
To make matters more complicated, there are a lot of ambiguities<br>
when demangling a symbol's qualified name, because a function local<br>
scope pattern (usually something like `?1??name?`) looks suspiciously<br>
like many other possible things that can occur, such as `?1` meaning<br>
the second back-ref and disambiguating these cases is rather<br>
interesting.  The `?1?` in a local scope pattern is actually a special<br>
case of the more general pattern of `? + <encoded number> + ?`, where<br>
"encoded number" can itself have embedded `@` symbols, which is a<br>
common delimeter in mangled names.  So we have to take care during the<br>
disambiguation, which is the reason for the overly complicated<br>
`isLocalScopePattern` function in this patch.<br>
<br>
I've added some pretty obnoxious tests to exercise all of this, which<br>
exposed several other problems related to back-referencing, so those<br>
are fixed here as well. Finally, I've uncommented some tests that were<br>
previously marked as `FIXME`, since now these work.<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D49965" rel="noreferrer" target="_blank">https://reviews.llvm.org/D49965</a><br>
<br>
Added:<br>
    llvm/trunk/test/Demangle/ms-nested-scopes.test<br>
Modified:<br>
    llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp<br>
    llvm/trunk/lib/Demangle/StringView.h<br>
    llvm/trunk/test/Demangle/ms-mangle.test<br>
<br>
Modified: llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp?rev=338226&r1=338225&r2=338226&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp?rev=338226&r1=338225&r2=338226&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp (original)<br>
+++ llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp Sun Jul 29 20:12:34 2018<br>
@@ -33,11 +33,21 @@ class ArenaAllocator {<br>
   struct AllocatorNode {<br>
     uint8_t *Buf = nullptr;<br>
     size_t Used = 0;<br>
+    size_t Capacity = 0;<br>
     AllocatorNode *Next = nullptr;<br>
   };<br>
<br>
+  void addNode(size_t Capacity) {<br>
+    AllocatorNode *NewHead = new AllocatorNode;<br>
+    NewHead->Buf = new uint8_t[Capacity];<br>
+    NewHead->Next = Head;<br>
+    NewHead->Capacity = Capacity;<br>
+    Head = NewHead;<br>
+    NewHead->Used = 0;<br>
+  }<br>
+<br>
 public:<br>
-  ArenaAllocator() : Head(new AllocatorNode) { Head->Buf = new uint8_t[Unit]; }<br>
+  ArenaAllocator() { addNode(Unit); }<br>
<br>
   ~ArenaAllocator() {<br>
     while (Head) {<br>
@@ -49,10 +59,25 @@ public:<br>
     }<br>
   }<br>
<br>
+  char *allocUnalignedBuffer(size_t Length) {<br>
+    uint8_t *Buf = Head->Buf + Head->Used;<br>
+<br>
+    Head->Used += Length;<br>
+    if (Head->Used > Head->Capacity) {<br>
+      // It's possible we need a buffer which is larger than our default unit<br>
+      // size, so we need to be careful to add a node with capacity that is at<br>
+      // least as large as what we need.<br>
+      addNode(std::max(Unit, Length));<br>
+      Head->Used = Length;<br>
+      Buf = Head->Buf;<br>
+    }<br>
+<br>
+    return reinterpret_cast<char *>(Buf);<br>
+  }<br>
+<br>
   template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) {<br>
<br>
     size_t Size = sizeof(T);<br>
-    assert(Size < Unit);<br>
     assert(Head && Head->Buf);<br>
<br>
     size_t P = (size_t)Head->Buf + Head->Used;<br>
@@ -62,15 +87,12 @@ public:<br>
     size_t Adjustment = AlignedP - P;<br>
<br>
     Head->Used += Size + Adjustment;<br>
-    if (Head->Used < Unit)<br>
+    if (Head->Used < Head->Capacity)<br>
       return new (PP) T(std::forward<Args>(ConstructorArgs)...);<br>
<br>
-    AllocatorNode *NewHead = new AllocatorNode;<br>
-    NewHead->Buf = new uint8_t[ArenaAllocator::Unit];<br>
-    NewHead->Next = Head;<br>
-    Head = NewHead;<br>
-    NewHead->Used = Size;<br>
-    return new (NewHead->Buf) T(std::forward<Args>(ConstructorArgs)...);<br>
+    addNode(ArenaAllocator::Unit);<br>
+    Head->Used = Size;<br>
+    return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...);<br>
   }<br>
<br>
 private:<br>
@@ -386,6 +408,47 @@ static void outputCallingConvention(Outp<br>
   }<br>
 }<br>
<br>
+static bool startsWithLocalScopePattern(StringView S) {<br>
+  if (!S.consumeFront('?'))<br>
+    return false;<br>
+  if (S.size() < 2)<br>
+    return false;<br>
+<br>
+  size_t End = S.find('?');<br>
+  if (End == StringView::npos)<br>
+    return false;<br>
+  StringView Candidate = S.substr(0, End);<br>
+  if (Candidate.empty())<br>
+    return false;<br>
+<br>
+  // \?[0-9]\?<br>
+  // ?@? is the discriminator 0.<br>
+  if (Candidate.size() == 1)<br>
+    return Candidate[0] == '@' || (Candidate[0] >= '0' && Candidate[0] <= '9');<br>
+<br>
+  // If it's not 0-9, then it's an encoded number terminated with an @<br>
+  if (Candidate.back() != '@')<br>
+    return false;<br>
+  Candidate = Candidate.dropBack();<br>
+<br>
+  // An encoded number starts with B-P and all subsequent digits are in A-P.<br>
+  // Note that the reason the first digit cannot be A is two fold.  First, it<br>
+  // would create an ambiguity with ?A which delimits the beginning of an<br>
+  // anonymous namespace.  Second, A represents 0, and you don't start a multi<br>
+  // digit number with a leading 0.  Presumably the anonymous namespace<br>
+  // ambiguity is also why single digit encoded numbers use 0-9 rather than A-J.<br>
+  if (Candidate[0] < 'B' || Candidate[0] > 'P')<br></blockquote><div><br></div><div>We just did a dropBack(). I think we need to check Candidate.empty() otherwise the range check against 'B' - 'P' will end up accessing Candidate out of bounds.<br></div><div>Perhaps something like:</div><div>  if (Candidate.empty() || Candidate[0] < 'B' || Candidate[0] > 'P')<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    return false;<br>
+  Candidate = Candidate.dropFront();<br>
+  while (!Candidate.empty()) {<br>
+    if (Candidate[0] < 'A' || Candidate[0] > 'P')<br>
+      return false;<br>
+    Candidate = Candidate.dropFront();<br>
+  }<br>
+<br>
+  return true;<br>
+}<br>
+<br>
 // Write a function or template parameter list.<br>
 static void outputParameterList(OutputStream &OS, const ParamList &Params) {<br>
   if (!Params.Current) {<br>
@@ -763,6 +826,10 @@ private:<br>
   int demangleNumber(StringView &MangledName);<br>
<br>
   void memorizeString(StringView s);<br>
+<br>
+  /// Allocate a copy of \p Borrowed into memory that we own.<br>
+  StringView copyString(StringView Borrowed);<br>
+<br>
   Name *demangleFullyQualifiedTypeName(StringView &MangledName);<br>
   Name *demangleFullyQualifiedSymbolName(StringView &MangledName);<br>
<br>
@@ -777,6 +844,7 @@ private:<br>
   Name *demangleOperatorName(StringView &MangledName);<br>
   Name *demangleSimpleName(StringView &MangledName, bool Memorize);<br>
   Name *demangleAnonymousNamespaceName(StringView &MangledName);<br>
+  Name *demangleLocallyScopedNamePiece(StringView &MangledName);<br>
<br>
   void demangleOperator(StringView &MangledName, Name *);<br>
   FuncClass demangleFunctionClass(StringView &MangledName);<br>
@@ -813,6 +881,13 @@ private:<br>
 };<br>
 } // namespace<br>
<br>
+StringView Demangler::copyString(StringView Borrowed) {<br>
+  char *Stable = Arena.allocUnalignedBuffer(Borrowed.size() + 1);<br>
+  std::strcpy(Stable, Borrowed.begin());<br>
+<br>
+  return {Stable, Borrowed.size()};<br>
+}<br>
+<br>
 // Parser entry point.<br>
 Symbol *Demangler::parse(StringView &MangledName) {<br>
   Symbol *S = Arena.alloc<Symbol>();<br>
@@ -956,6 +1031,18 @@ Name *Demangler::demangleClassTemplateNa<br>
<br>
   Name *Node = demangleSimpleName(MangledName, false);<br>
   Node->TemplateParams = demangleTemplateParameterList(MangledName);<br>
+<br>
+  // Render this class template name into a string buffer so that we can<br>
+  // memorize it for the purpose of back-referencing.<br>
+  OutputStream OS = OutputStream::create(nullptr, nullptr, 1024);<br>
+  outputName(OS, Node);<br>
+  OS << '\0';<br>
+  char *Name = OS.getBuffer();<br>
+<br>
+  StringView Owned = copyString(Name);<br>
+  memorizeString(Owned);<br>
+  std::free(Name);<br>
+<br>
   return Node;<br>
 }<br>
<br>
@@ -1103,6 +1190,34 @@ Name *Demangler::demangleAnonymousNamesp<br>
   return nullptr;<br>
 }<br>
<br>
+Name *Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) {<br>
+  assert(startsWithLocalScopePattern(MangledName));<br>
+<br>
+  Name *Node = Arena.alloc<Name>();<br>
+  MangledName.consumeFront('?');<br>
+  int ScopeIdentifier = demangleNumber(MangledName);<br>
+<br>
+  // One ? to terminate the number<br>
+  MangledName.consumeFront('?');<br>
+<br>
+  assert(!Error);<br>
+  Symbol *Scope = parse(MangledName);<br>
+  if (Error)<br>
+    return nullptr;<br>
+<br>
+  // Render the parent symbol's name into a buffer.<br>
+  OutputStream OS = OutputStream::create(nullptr, nullptr, 1024);<br>
+  OS << '`';<br>
+  output(Scope, OS);<br>
+  OS << '\'';<br>
+  OS << "::`" << ScopeIdentifier << "'";<br>
+  OS << '\0';<br>
+  char *Result = OS.getBuffer();<br>
+  Node->Str = copyString(Result);<br>
+  std::free(Result);<br>
+  return Node;<br>
+}<br>
+<br>
 // Parses a type name in the form of A@B@C@@ which represents C::B::A.<br>
 Name *Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) {<br>
   Name *TypeName = demangleUnqualifiedTypeName(MangledName);<br>
@@ -1140,6 +1255,10 @@ Name *Demangler::demangleUnqualifiedType<br>
 }<br>
<br>
 Name *Demangler::demangleUnqualifiedSymbolName(StringView &MangledName) {<br>
+  if (startsWithDigit(MangledName))<br>
+    return demangleBackRefName(MangledName);<br>
+  if (MangledName.startsWith("?$"))<br>
+    return demangleClassTemplateName(MangledName);<br>
   if (MangledName.startsWith('?'))<br>
     return demangleOperatorName(MangledName);<br>
   return demangleSimpleName(MangledName, true);<br>
@@ -1155,6 +1274,9 @@ Name *Demangler::demangleNameScopePiece(<br>
   if (MangledName.startsWith("?A"))<br>
     return demangleAnonymousNamespaceName(MangledName);<br>
<br>
+  if (startsWithLocalScopePattern(MangledName))<br>
+    return demangleLocallyScopedNamePiece(MangledName);<br>
+<br>
   return demangleSimpleName(MangledName, true);<br>
 }<br>
<br>
@@ -1727,9 +1849,6 @@ void Demangler::output(const Symbol *S,<br>
   Type::outputPre(OS, *S->SymbolType);<br>
   outputName(OS, S->SymbolName);<br>
   Type::outputPost(OS, *S->SymbolType);<br>
-<br>
-  // Null terminate the buffer.<br>
-  OS << '\0';<br>
 }<br>
<br>
 char *llvm::microsoftDemangle(const char *MangledName, char *Buf, size_t *N,<br>
@@ -1745,5 +1864,6 @@ char *llvm::microsoftDemangle(const char<br>
<br>
   OutputStream OS = OutputStream::create(Buf, N, 1024);<br>
   D.output(S, OS);<br>
+  OS << '\0';<br>
   return OS.getBuffer();<br>
 }<br>
<br>
Modified: llvm/trunk/lib/Demangle/StringView.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/StringView.h?rev=338226&r1=338225&r2=338226&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/StringView.h?rev=338226&r1=338225&r2=338226&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Demangle/StringView.h (original)<br>
+++ llvm/trunk/lib/Demangle/StringView.h Sun Jul 29 20:12:34 2018<br>
@@ -22,6 +22,8 @@ class StringView {<br>
   const char *Last;<br>
<br>
 public:<br>
+  static const size_t npos = ~size_t(0);<br>
+<br>
   template <size_t N><br>
   StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}<br>
   StringView(const char *First_, const char *Last_)<br>
@@ -35,6 +37,17 @@ public:<br>
     return StringView(begin() + From, size() - From);<br>
   }<br>
<br>
+  size_t find(char C, size_t From = 0) const {<br>
+    size_t FindBegin = std::min(From, size());<br>
+    // Avoid calling memchr with nullptr.<br>
+    if (FindBegin < size()) {<br>
+      // Just forward to memchr, which is faster than a hand-rolled loop.<br>
+      if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))<br>
+        return static_cast<const char *>(P) - First;<br>
+    }<br>
+    return npos;<br>
+  }<br>
+<br>
   StringView substr(size_t From, size_t To) const {<br>
     if (To >= size())<br>
       To = size() - 1;<br>
@@ -49,11 +62,22 @@ public:<br>
     return StringView(First + N, Last);<br>
   }<br>
<br>
+  StringView dropBack(size_t N = 1) const {<br>
+    if (N >= size())<br>
+      N = size();<br>
+    return StringView(First, Last - N);<br>
+  }<br>
+<br>
   char front() const {<br>
     assert(!empty());<br>
     return *begin();<br>
   }<br>
<br>
+  char back() const {<br>
+    assert(!empty());<br>
+    return *(end() - 1);<br>
+  }<br>
+<br>
   char popFront() {<br>
     assert(!empty());<br>
     return *First++;<br>
<br>
Modified: llvm/trunk/test/Demangle/ms-mangle.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-mangle.test?rev=338226&r1=338225&r2=338226&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-mangle.test?rev=338226&r1=338225&r2=338226&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/Demangle/ms-mangle.test (original)<br>
+++ llvm/trunk/test/Demangle/ms-mangle.test Sun Jul 29 20:12:34 2018<br>
@@ -265,18 +265,18 @@<br>
 ?s6@PR13182@@3PBQBDB<br>
 ; CHECK: char const *const *PR13182::s6<br>
<br>
-; FIXME: We don't properly support static locals in functions yet.<br>
+; FIXME: We don't properly support extern "C" functions yet.<br>
 ; ?local@?1??extern_c_func@@9@4HA<br>
 ; FIXME: int `extern_c_func'::`2'::local<br>
<br>
 ; ?local@?1??extern_c_func@@9@4HA<br>
 ; FIXME: int `extern_c_func'::`2'::local<br>
<br>
-; ?v@?1??f@@YAHXZ@4U<unnamed-type-v>@?1??1@YAHXZ@A<br>
-; FIXME: struct `int __cdecl f(void)'::`2'::<unnamed-type-v> `int __cdecl f(void)'::`2'::v<br>
+?v@?1??f@@YAHXZ@4U<unnamed-type-v>@?1??1@YAHXZ@A<br>
+; CHECK: struct `int __cdecl f(void)'::`2'::<unnamed-type-v> `int __cdecl f(void)'::`2'::v<br>
<br>
-; ?v@?1???$f@H@@YAHXZ@4U<unnamed-type-v>@?1???$f@H@@YAHXZ@A<br>
-; FIXME: struct `int __cdecl f<int>(void)'::`2'::<unnamed-type-v> `int __cdecl f<int>(void)'::`2'::v<br>
+?v@?1???$f@H@@YAHXZ@4U<unnamed-type-v>@?1???$f@H@@YAHXZ@A<br>
+; CHECK: struct `int __cdecl f<int>(void)'::`2'::<unnamed-type-v> `int __cdecl f<int>(void)'::`2'::v<br>
<br>
 ??2OverloadedNewDelete@@SAPAXI@Z<br>
 ; CHECK: static void * __cdecl OverloadedNewDelete::operator new(unsigned int)<br>
@@ -335,8 +335,8 @@<br>
 ; ?overloaded_fn@@$$J0YAXXZ<br>
 ; FIXME-EXTERNC: extern \"C\" void __cdecl overloaded_fn(void)<br>
<br>
-; ?f@UnnamedType@@YAXQAPAU<unnamed-type-T1>@S@1@@Z<br>
-; FIXME: void __cdecl UnnamedType::f(struct UnnamedType::S::<unnamed-type-T1> ** const)<br>
+?f@UnnamedType@@YAXQAPAU<unnamed-type-T1>@S@1@@Z<br>
+; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::<unnamed-type-T1> **const)<br>
<br>
 ?f@UnnamedType@@YAXUT2@S@1@@Z<br>
 ; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T2)<br>
<br>
Added: llvm/trunk/test/Demangle/ms-nested-scopes.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-nested-scopes.test?rev=338226&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-nested-scopes.test?rev=338226&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/Demangle/ms-nested-scopes.test (added)<br>
+++ llvm/trunk/test/Demangle/ms-nested-scopes.test Sun Jul 29 20:12:34 2018<br>
@@ -0,0 +1,146 @@<br>
+; RUN: llvm-undname < %s | FileCheck %s<br>
+<br>
+; CHECK-NOT: Invalid mangled name<br>
+<br>
+; Test demangling of function local scope discriminator IDs.<br>
+?M@?@??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`0'::M<br>
+<br>
+?M@?0??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`1'::M<br>
+<br>
+?M@?1??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`2'::M<br>
+<br>
+?M@?2??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`3'::M<br>
+<br>
+?M@?3??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`4'::M<br>
+<br>
+?M@?4??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`5'::M<br>
+<br>
+?M@?5??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`6'::M<br>
+<br>
+?M@?6??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`7'::M<br>
+<br>
+?M@?7??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`8'::M<br>
+<br>
+?M@?8??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`9'::M<br>
+<br>
+?M@?9??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`10'::M<br>
+<br>
+?M@?L@??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`11'::M<br>
+<br>
+?M@?M@??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`12'::M<br>
+<br>
+?M@?N@??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`13'::M<br>
+<br>
+?M@?O@??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`14'::M<br>
+<br>
+?M@?P@??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`15'::M<br>
+<br>
+?M@?BA@??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`16'::M<br>
+<br>
+?M@?BB@??L@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L(void)'::`17'::M<br>
+<br>
+?j@?1??L@@YAHXZ@4UJ@@A<br>
+; CHECK: struct J `int __cdecl L(void)'::`2'::j<br>
+<br>
+; Test demangling of name back-references<br>
+?NN@0XX@@3HA<br>
+; CHECK: int XX::NN::NN<br>
+<br>
+?MM@0NN@XX@@3HA<br>
+; CHECK: int XX::NN::MM::MM<br>
+<br>
+?NN@MM@0XX@@3HA<br>
+; CHECK: int XX::NN::MM::NN<br>
+<br>
+?OO@0NN@01XX@@3HA<br>
+; CHECK: int XX::NN::OO::NN::OO::OO<br>
+<br>
+?NN@OO@010XX@@3HA<br>
+; CHECK: int XX::NN::OO::NN::OO::NN<br>
+<br>
+; Test demangling of name back-references combined with function local scopes.<br>
+?M@?1??0@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl M(void)'::`2'::M<br>
+<br>
+?L@?2??M@0?2??0@YAHXZ@QEAAHXZ@4HA<br>
+; CHECK: int `int __cdecl `int __cdecl L(void)'::`3'::L::M(void)'::`3'::L<br>
+<br>
+?M@?2??0L@?2??1@YAHXZ@QEAAHXZ@4HA<br>
+; CHECK: int `int __cdecl `int __cdecl L(void)'::`3'::L::M(void)'::`3'::M<br>
+<br>
+; Function local scopes of template functions<br>
+?M@?1???$L@H@@YAHXZ@4HA<br>
+; CHECK: int `int __cdecl L<int>(void)'::`2'::M<br>
+<br>
+; And member functions of template classes<br>
+?SN@?$NS@H@NS@@QEAAHXZ<br>
+; CHECK: int __cdecl NS::NS<int>::SN(void)<br>
+<br>
+?NS@?1??SN@?$NS@H@0@QEAAHXZ@4HA<br>
+; CHECK: int `int __cdecl NS::NS<int>::SN(void)'::`2'::NS<br>
+<br>
+?SN@?1??0?$NS@H@NS@@QEAAHXZ@4HA<br>
+; CHECK: int `int __cdecl NS::NS<int>::SN(void)'::`2'::SN<br>
+<br>
+?NS@?1??SN@?$NS@H@10@QEAAHXZ@4HA<br>
+; CHECK: int `int __cdecl NS::SN::NS<int>::SN(void)'::`2'::NS<br>
+<br>
+?SN@?1??0?$NS@H@0NS@@QEAAHXZ@4HA<br>
+; CHECK: int `int __cdecl NS::SN::NS<int>::SN(void)'::`2'::SN<br>
+<br>
+; Make sure instantiated templates participate in back-referencing.<br>
+; In the next 3 examples there should be 3 back-references:<br>
+; 0 = X (right most name)<br>
+; 1 = C<int> (second from right)<br>
+; 2 = C (third from right)<br>
+; Make sure all 3 work as expected by having the 4th component take each value<br>
+; from 0-2 and confirming it is the right component.<br>
+?X@?$C@H@C@0@2HB<br>
+; CHECK: static int const X::C::C<int>::X<br>
+<br>
+?X@?$C@H@C@1@2HB<br>
+; CHECK: static int const C<int>::C::C<int>::X<br>
+<br>
+?X@?$C@H@C@2@2HB<br>
+; CHECK: static int const C::C::C<int>::X<br>
+<br>
+; Putting everything together.<br>
+<br>
+; namespace A { namespace B { namespace C { namespace B { namespace C {<br>
+;   template<typename T><br>
+;   struct C {<br>
+;     int B() {<br>
+;       static C<int> C;<br>
+;       static int B = 7;<br>
+;       static int A = 7;<br>
+;       return C.B() + B + A;<br>
+;     }<br>
+;   };<br>
+; } } } } }<br>
+<br>
+?C@?1??B@?$C@H@0101A@@QEAAHXZ@4U201013@A<br>
+; CHECK: struct A::B::C::B::C::C<int> `int __cdecl A::B::C::B::C::C<int>::B(void)'::`2'::C<br>
+<br>
+?B@?1??0?$C@H@C@020A@@QEAAHXZ@4HA<br>
+; CHECK: int `int __cdecl A::B::C::B::C::C<int>::B(void)'::`2'::B<br>
+<br>
+?A@?1??B@?$C@H@C@1310@QEAAHXZ@4HA<br>
+; CHECK: int `int __cdecl A::B::C::B::C::C<int>::B(void)'::`2'::A<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div></div>