re PR libstdc++/12736 (Demangler bug)
authorCarlo Wood <carlo@alinoe.com>
Fri, 7 Nov 2003 17:55:27 +0000 (17:55 +0000)
committerCarlo Wood <carlo@gcc.gnu.org>
Fri, 7 Nov 2003 17:55:27 +0000 (17:55 +0000)
PR libstdc++/12736
* bits/demangle.h (qualifier_list<Allocator>::decode_KVrA): Added.
(qualifier_list<Allocator>::decode_qualifiers): Collect concatenated
K, V, r and A qualifiers before processing them as a group.
* testsuite/demangle/abi_text/01.cc: Reordered CV-qualifiers.
* testsuite/demangle/regression/cw-16.cc: New.

From-SVN: r73339

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/demangle.h
libstdc++-v3/testsuite/demangle/abi_text/01.cc
libstdc++-v3/testsuite/demangle/regression/cw-16.cc [new file with mode: 0644]

index aeb77f7e2246f8149221792fab40f1b5aa9bae38..d0c46d0042176bd5d8d1422f46477916a9e09eaf 100644 (file)
@@ -1,3 +1,12 @@
+2003-11-07  Carlo Wood  <carlo@alinoe.com>
+
+       PR libstdc++/12736
+       * bits/demangle.h (qualifier_list<Allocator>::decode_KVrA): Added.
+       (qualifier_list<Allocator>::decode_qualifiers): Collect concatenated
+       K, V, r and A qualifiers before processing them as a group.
+       * testsuite/demangle/abi_text/01.cc: Reordered CV-qualifiers.
+       * testsuite/demangle/regression/cw-16.cc: New.
+
 2003-11-07  Robert Millan  <robertmh@gnu.org>
 
         * configure.host: Add kfreebsd*-gnu and knetbsd*-gnu.
index 28581662db1767d3ac039fa6d399756e1ee359f8..872948c7d255d1d71fb0e837188bf25e8adde002 100644 (file)
@@ -227,6 +227,10 @@ namespace __gnu_cxx
        std::vector<qualifier<Allocator>, Allocator> M_qualifier_starts;
        session<Allocator>& M_demangler;
 
+       void decode_KVrA(string_type& prefix, string_type& postfix, int cvq,
+          typename std::vector<qualifier<Allocator>, Allocator>::
+             const_reverse_iterator const& iter_array) const;
+
       public:
        qualifier_list(session<Allocator>& demangler_obj)
        : M_printing_suppressed(false), M_demangler(demangler_obj)
@@ -339,11 +343,6 @@ namespace __gnu_cxx
        static int
        decode_encoding(string_type& output, char const* input, int len);
 
-       bool
-       decode_type_with_postfix(string_type& prefix,
-                                string_type& postfix,
-                   qualifier_list<Allocator>* qualifiers = NULL);
-
        bool
        decode_type(string_type& output,
                    qualifier_list<Allocator>* qualifiers = NULL)
@@ -384,6 +383,8 @@ namespace __gnu_cxx
                         substitution_nt sub_type,
                         int number_of_prefixes);
 
+       bool decode_type_with_postfix(string_type& prefix,
+           string_type& postfix, qualifier_list<Allocator>* qualifiers = NULL);
        bool decode_bare_function_type(string_type& output);
        bool decode_builtin_type(string_type& output);
        bool decode_call_offset(string_type& output);
@@ -1382,8 +1383,11 @@ namespace __gnu_cxx
     // <Q>M<C>         ==> C::*Q                       "M<C>..." (<C> recurs.)
     // A<I>            ==>  [I]                        "A<I>..." (<I> recurs.)
     // <Q>A<I>         ==>  (Q) [I]                    "A<I>..." (<I> recurs.)
-    //   Note that when <Q> ends on an A<I2> then the brackets are omitted:
-    //   A<I2>A<I>       ==> [I2][I]
+    //   Note that when <Q> ends on an A<I2> then the brackets are omitted
+    //   and no space is written between the two:
+    //   A<I2>A<I>     ==>  [I2][I]
+    //   If <Q> ends on [KVr]+, which can happen in combination with
+    //   substitutions only, then special handling is required, see below.
     //  
     // A <substitution> is handled with an input position switch during which
     // new substitutions are turned off.  Because recursive handling of types
@@ -1411,6 +1415,86 @@ namespace __gnu_cxx
     // For some weird reason, g++ (3.2.1) does not add substitutions for
     // qualified member function pointers.  I think that is another bug.
     //
+
+    // In the case of
+    // <Q>A<I>
+    // where <Q> ends on [K|V|r]+ then that part should be processed as
+    // if it was behind the A<I> instead of in front of it.  This is
+    // because a constant array of ints is normally always mangled as
+    // an array of constant ints.  KVr qualifiers can end up in front
+    // of an array when the array is part of a substitution or template
+    // parameter, but the demangling should still result in the same
+    // syntax; thus KA2_i (const array of ints) must result in the same
+    // demangling as A2_Ki (array of const ints).  As a result we must
+    // demangle ...[...[[KVr]+A<I0>][KVr]+A<I1>]...[KVr]+A<In>[KVr]+
+    // as A<I0>A<I1>...A<In>[KVr]+ where each K, V and r in the series
+    // collapses to a single character at the right of the string.
+    // For example:
+    // VA9_KrA6_KVi --> A9_A6_KVri --> int volatile const restrict [9][6]
+    // Note that substitutions are still added as usual (the translation
+    // to A9_A6_KVri does not really happen).
+    //
+    // This decoding is achieved by delaying the decoding of any sequence
+    // of [KVrA]'s and processing them together in the order: first the
+    // short-circuited KVr part and then the arrays.
+    static int const cvq_K = 1;                // Saw at least one K
+    static int const cvq_V = 2;                // Saw at least one V
+    static int const cvq_r = 4;                // Saw at least one r
+    static int const cvq_A = 8;                // Saw at least one A
+    static int const cvq_last = 16;    // No remaining qualifiers.
+    static int const cvq_A_cnt = 32;   // Bit 5 and higher represent the
+                                       //   number of A's in the series.
+    // In the function below, iter_array points to the first (right most)
+    // A in the series, if any.
+    template<typename Allocator>
+      void
+      qualifier_list<Allocator>::decode_KVrA(
+          string_type& prefix, string_type& postfix, int cvq,
+          typename std::vector<qualifier<Allocator>, Allocator>::
+             const_reverse_iterator const& iter_array) const
+       {
+         _GLIBCXX_DEMANGLER_DOUT_ENTERING3("decode_KVrA");
+         if ((cvq & cvq_K))
+           prefix += " const";
+         if ((cvq & cvq_V))
+           prefix += " volatile";
+         if ((cvq & cvq_r))
+           prefix += " restrict";
+         if ((cvq & cvq_A))
+         {
+           int n = cvq >> 5;
+           for (typename std::vector<qualifier<Allocator>, Allocator>::
+               const_reverse_iterator iter = iter_array;
+               iter != M_qualifier_starts.rend(); ++iter)
+           {
+             switch((*iter).first_qualifier())
+             {
+               case 'K':
+               case 'V':
+               case 'r':
+                 break;
+               case 'A':
+               {
+                 string_type index = (*iter).get_optional_type();
+                 if (--n == 0 && (cvq & cvq_last))
+                   postfix = " [" + index + "]" + postfix;
+                 else if (n > 0)
+                   postfix = "[" + index + "]" + postfix;
+                 else
+                 {
+                   prefix += " (";
+                   postfix = ") [" + index + "]" + postfix;
+                 }
+                 break;
+               }
+               default:
+                 _GLIBCXX_DEMANGLER_RETURN3;
+             }
+           }
+         }
+         _GLIBCXX_DEMANGLER_RETURN3;
+       }
+
     template<typename Allocator>
       void
       qualifier_list<Allocator>::decode_qualifiers(
@@ -1419,9 +1503,12 @@ namespace __gnu_cxx
          bool member_function_pointer_qualifiers = false) const
       {
        _GLIBCXX_DEMANGLER_DOUT_ENTERING3("decode_qualifiers");
+       int cvq = 0;
+       typename std::vector<qualifier<Allocator>, Allocator>::
+           const_reverse_iterator iter_array;
        for(typename std::vector<qualifier<Allocator>, Allocator>::
            const_reverse_iterator iter = M_qualifier_starts.rbegin();
-           iter != M_qualifier_starts.rend();)
+           iter != M_qualifier_starts.rend(); ++iter)
        {
          if (!member_function_pointer_qualifiers
              && !(*iter).part_of_substitution())
@@ -1437,40 +1524,54 @@ namespace __gnu_cxx
            switch(qualifier_char)
            {
              case 'P':
+               if (cvq)
+               {
+                 decode_KVrA(prefix, postfix, cvq, iter_array);
+                 cvq = 0;
+               }
                prefix += "*";
                break;
              case 'R':
+               if (cvq)
+               {
+                 decode_KVrA(prefix, postfix, cvq, iter_array);
+                 cvq = 0;
+               }
                prefix += "&";
                break;
              case 'K':
-               prefix += " const";
+               cvq |= cvq_K;
                continue;
              case 'V':
-               prefix += " volatile";
+               cvq |= cvq_V;
                continue;
              case 'r':
-               prefix += " restrict";
+               cvq |= cvq_r;
                continue;
              case 'A':
-             {
-               string_type index = (*iter).get_optional_type();
-               if (++iter == M_qualifier_starts.rend())
-                 postfix = " [" + index + "]" + postfix;
-               else if ((*iter).first_qualifier() == 'A')
-                 postfix = "[" + index + "]" + postfix;
-               else
+               if (!(cvq & cvq_A))
                {
-                 prefix += " (";
-                 postfix = ") [" + index + "]" + postfix;
+                 cvq |= cvq_A;
+                 iter_array = iter;
                }
+               cvq += cvq_A_cnt;
                break;
-             }
              case 'M':
+               if (cvq)
+               {
+                 decode_KVrA(prefix, postfix, cvq, iter_array);
+                 cvq = 0;
+               }
                prefix += " ";
                prefix += (*iter).get_optional_type();
                prefix += "::*";
                break;
              case 'U':
+               if (cvq)
+               {
+                 decode_KVrA(prefix, postfix, cvq, iter_array);
+                 cvq = 0;
+               }
                prefix += " ";
                prefix += (*iter).get_optional_type();
                break;
@@ -1479,9 +1580,9 @@ namespace __gnu_cxx
            }
            break;
          }
-         if (qualifier_char != 'A')
-           ++iter;
        }
+       if (cvq)
+         decode_KVrA(prefix, postfix, cvq|cvq_last, iter_array);
        M_printing_suppressed = false;
        _GLIBCXX_DEMANGLER_RETURN3;
       }
index 33cfd01ac0b0c7390d95b9f0e0c014660b1b95ed..5563d5093f746b000a67e37c1606d6af97c093a9 100644 (file)
@@ -36,7 +36,7 @@ int main()
   // standard text
   // verify_demangle("U4_farrVKPi", "int* volatile const restrict _far");
   // new __cxa_demangle
-  verify_demangle("U4_farrVKPi", "int* restrict volatile const _far");
+  verify_demangle("U4_farrVKPi", "int* const volatile restrict _far");
 
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/demangle/regression/cw-16.cc b/libstdc++-v3/testsuite/demangle/regression/cw-16.cc
new file mode 100644 (file)
index 0000000..866143a
--- /dev/null
@@ -0,0 +1,34 @@
+// 2003-10-14  Carlo Wood  <carlo@alinoe.com>
+
+// Copyright (C) 2003 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING.  If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// IA 64 C++ ABI - 5.1 External Names (a.k.a. Mangling)
+
+#include <testsuite_hooks.h>
+
+// libcwd tests
+int main()
+{
+  using namespace __gnu_test;
+
+verify_demangle("_Z3fooIA6_KiEvA9_KT_rVPrS4_",
+               "void foo<int const [6]>(int const [9][6], int const restrict (* volatile restrict) [9][6])");
+
+  return 0;
+}