<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>