PR19091: Track whether we're demangling a function template specialization to
determine whether we get a mangling for a return type, rather than trying to
figure it out based on whether the mangled name ended with a '>'.


git-svn-id: https://llvm.org/svn/llvm-project/libcxxabi/trunk@208611 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/src/cxa_demangle.cpp b/src/cxa_demangle.cpp
index 2ad832a..ff28c79 100644
--- a/src/cxa_demangle.cpp
+++ b/src/cxa_demangle.cpp
@@ -38,7 +38,8 @@
 template <class C>
     const char* parse_encoding(const char* first, const char* last, C& db);
 template <class C>
-    const char* parse_name(const char* first, const char* last, C& db);
+    const char* parse_name(const char* first, const char* last, C& db,
+                           bool* ends_with_template_args = 0);
 template <class C>
     const char* parse_expression(const char* first, const char* last, C& db);
 template <class C>
@@ -3897,7 +3898,8 @@
 
 template <class C>
 const char*
-parse_nested_name(const char* first, const char* last, C& db)
+parse_nested_name(const char* first, const char* last, C& db,
+                  bool* ends_with_template_args)
 {
     if (first != last && *first == 'N')
     {
@@ -3928,8 +3930,10 @@
             return first;
         }
         bool pop_subs = false;
+        bool component_ends_with_template_args = false;
         while (*t0 != 'E')
         {
+            component_ends_with_template_args = false;
             const char* t1;
             switch (*t0)
             {
@@ -3999,6 +4003,7 @@
                     db.names.back().first += name;
                     db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
                     t0 = t1;
+                    component_ends_with_template_args = true;
                 }
                 else
                     return first;
@@ -4030,6 +4035,8 @@
         db.cv = cv;
         if (pop_subs && !db.subs.empty())
             db.subs.pop_back();
+        if (ends_with_template_args)
+            *ends_with_template_args = component_ends_with_template_args;
     }
     return first;
 }
@@ -4077,7 +4084,8 @@
 
 template <class C>
 const char*
-parse_local_name(const char* first, const char* last, C& db)
+parse_local_name(const char* first, const char* last, C& db,
+                 bool* ends_with_template_args)
 {
     if (first != last && *first == 'Z')
     {
@@ -4099,7 +4107,8 @@
                     if (t1 != last && *t1 == '_')
                     {
                         t = t1 + 1;
-                        t1 = parse_name(t, last, db);
+                        t1 = parse_name(t, last, db,
+                                        ends_with_template_args);
                         if (t1 != t)
                         {
                             if (db.names.size() < 2)
@@ -4117,7 +4126,8 @@
                 break;
             default:
                 {
-                    const char* t1 = parse_name(t, last, db);
+                    const char* t1 = parse_name(t, last, db,
+                                                ends_with_template_args);
                     if (t1 != t)
                     {
                         // parse but ignore discriminator
@@ -4149,7 +4159,8 @@
 
 template <class C>
 const char*
-parse_name(const char* first, const char* last, C& db)
+parse_name(const char* first, const char* last, C& db,
+           bool* ends_with_template_args)
 {
     if (last - first >= 2)
     {
@@ -4161,14 +4172,16 @@
         {
         case 'N':
           {
-            const char* t1 = parse_nested_name(t0, last, db);
+            const char* t1 = parse_nested_name(t0, last, db,
+                                               ends_with_template_args);
             if (t1 != t0)
                 first = t1;
             break;
           }
         case 'Z':
           {
-            const char* t1 = parse_local_name(t0, last, db);
+            const char* t1 = parse_local_name(t0, last, db,
+                                              ends_with_template_args);
             if (t1 != t0)
                 first = t1;
             break;
@@ -4193,6 +4206,8 @@
                         db.names.pop_back();
                         db.names.back().first += tmp;
                         first = t1;
+                        if (ends_with_template_args)
+                            *ends_with_template_args = true;
                     }
                 }
                 else   // <unscoped-name>
@@ -4213,6 +4228,8 @@
                         db.names.pop_back();
                         db.names.back().first += tmp;
                         first = t1;
+                        if (ends_with_template_args)
+                            *ends_with_template_args = true;
                     }
                 }
             }
@@ -4476,7 +4493,9 @@
             break;
         default:
           {
-            const char* t = parse_name(first, last, db);
+            bool ends_with_template_args = false;
+            const char* t = parse_name(first, last, db,
+                                       &ends_with_template_args);
             unsigned cv = db.cv;
             unsigned ref = db.ref;
             if (t != first)
@@ -4492,8 +4511,7 @@
                     const typename C::String& nm = db.names.back().first;
                     if (nm.empty())
                         return first;
-                    if (!db.parsed_ctor_dtor_cv && nm.back() == '>' && nm[nm.size()-2] != '-'
-                                                                    && nm[nm.size()-2] != '>')
+                    if (!db.parsed_ctor_dtor_cv && ends_with_template_args)
                     {
                         t2 = parse_type(t, last, db);
                         if (t2 == t)
diff --git a/test/test_demangle.cpp b/test/test_demangle.cpp
index e00c913..15cb3a1 100644
--- a/test/test_demangle.cpp
+++ b/test/test_demangle.cpp
@@ -24,6 +24,8 @@
     {"_Z1A1B1C", "A(B, C)"},
     {"_Z4testI1A1BE1Cv", "C test<A, B>()"},
     {"_Z4testI1A1BET0_T_S3_", "B test<A, B>(A, A)"},
+    {"_ZN1SgtEi", "S::operator>(int)"},
+    {"_ZrsI1QEiT_i", "int operator>><Q>(Q, int)"},
     {"_ZN13dyldbootstrap5startEPK12macho_headeriPPKcl", "dyldbootstrap::start(macho_header const*, int, char const**, long)"},
     {"_ZN4dyld17getExecutablePathEv", "dyld::getExecutablePath()"},
     {"_ZN4dyld22mainExecutablePreboundEv", "dyld::mainExecutablePrebound()"},