Pretty printers for versioned namespace

Message ID 20170110123911.GK13348@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely Jan. 10, 2017, 12:39 p.m.
On 09/01/17 21:25 +0100, François Dumont wrote:
>On 04/01/2017 13:52, Jonathan Wakely wrote:

>>On 24/12/16 14:47 +0100, François Dumont wrote:

>>

>>I'd prefer not to have to use the regex matches in libstdc++.exp as

>>they complicate things.

>>

>>For the two examples above, the whatis results are bad even for the

>>non-versioned namespace. For specializations of basic_string we only

>>have type printers that recognize the standard typedefs like

>>std::u16string, but not other specializations. We really want it to

>>show std::basic_string<unsigned char> not the full name. That would

>>require a TemplateTypePrinter for basic_string. The attached patch

>>works, and should be easy to incorporate into your changes for the

>>versioned namespace.

>>

>+    add_one_template_type_printer(obj, 'basic_string<T>',

>+            'basic_string<((un)?signed char), std::char_traits<\\1 ?>, std::allocator<\\1 ?> >',

>+            'basic_string<{1}>')

>+

>

>I had consider a similar approach but more generic like:

>

>+    add_one_template_type_printer(obj, 'basic_string<T>',

>+            'basic_string<(.*)?, std::char_traits<\\1 ?>, std::allocator<\\1 ?> >',

>+            'basic_string<{1}>')

>+

>

>

>but it had bad effect on rendering of std::string type so I give up on this approach. Your version is indeed enough to cover not too exotic instantiations of std::basic_string.


Yes, I tried that first as well.

>I also updated 48362.cc test case as this test was already adapted for versioned namespace. But I had to keep one occurence of '__7' when displaying types inside a tuple. I think it is ok.


Yes, I think so too.

>Tested with versioned namespace. Is it ok to commit after I completed tests without versioned namespace ?


I've committed the attached patch, which passes the tests for the
default configuration and the versioned namespace configuration.

I added another helper function, strip_versioned_namespace, which is
more expressive than doing typename.replace(vers_nsp, '') everywhere.
I've also renamed vers_nsp to _versioned_namespace (using the naming
convention for global variables private to the module). I've added
checks so that if that variable is None then the extra printers and
special cases for the versioned namespace are skipped. That's not
currently used, but it would allow us to optimise things later if
needed.

I also needed to update the new SharedPtrMethodsMatcher to add
"(__\d+)?" to the regular expression.


>@@ -1392,47 +1406,54 @@ def register_type_printers(obj):

>     add_one_type_printer(obj, 'discard_block_engine', 'ranlux48')

>     add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b')

> 

>+    # Consider optional versioned namespace

>+    opt_nsp = '(' + vers_nsp + ')?'

>+

>     # Do not show defaulted template arguments in class templates

>     add_one_template_type_printer(obj, 'unique_ptr<T>',

>-            'unique_ptr<(.*), std::default_delete<\\1 ?> >',

>-            'unique_ptr<{1}>')

>+        '{0}unique_ptr<(.*), std::{0}default_delete<\\2 ?> >'.format(opt_nsp),

>+        'unique_ptr<{2}>')


This is ugly. Mixing python string formatting with regular expressions
makes it harder to read, and is inconsistent with how the versioned
namespace is handled elsewhere. In Printer.add_version and
add_one_type_printer we just register two names, one using std:: and
one using std::__7::. We can do the same for the template type
printers.

>@@ -1466,7 +1487,7 @@ def build_libstdcxx_dictionary ():

>     libstdcxx_printer = Printer("libstdc++-v6")

> 

>     # For _GLIBCXX_BEGIN_NAMESPACE_VERSION.

>-    vers = '(__7::)?'

>+    vers = '(' + vers_nsp + ')?'

>     # For _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.

>     container = '(__cxx1998::' + vers + ')?'

> 


These variables don't seem to be used, so can just be removed.

Comments

François Dumont Jan. 19, 2017, 9:01 p.m. | #1
On 10/01/2017 13:39, Jonathan Wakely wrote:
> I've committed the attached patch, which passes the tests for the

> default configuration and the versioned namespace configuration.

>

> I added another helper function, strip_versioned_namespace, which is

> more expressive than doing typename.replace(vers_nsp, '') everywhere.

> I've also renamed vers_nsp to _versioned_namespace (using the naming

> convention for global variables private to the module). I've added

> checks so that if that variable is None then the extra printers and

> special cases for the versioned namespace are skipped. That's not

> currently used, but it would allow us to optimise things later if

> needed.


Very nice feature indeed, see below.

>

> I also needed to update the new SharedPtrMethodsMatcher to add

> "(__\d+)?" to the regular expression.

>

>

>> @@ -1392,47 +1406,54 @@ def register_type_printers(obj):

>>     add_one_type_printer(obj, 'discard_block_engine', 'ranlux48')

>>     add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b')

>>

>> +    # Consider optional versioned namespace

>> +    opt_nsp = '(' + vers_nsp + ')?'

>> +

>>     # Do not show defaulted template arguments in class templates

>>     add_one_template_type_printer(obj, 'unique_ptr<T>',

>> -            'unique_ptr<(.*), std::default_delete<\\1 ?> >',

>> -            'unique_ptr<{1}>')

>> +        '{0}unique_ptr<(.*), std::{0}default_delete<\\2 ?> 

>> >'.format(opt_nsp),

>> +        'unique_ptr<{2}>')

>

> This is ugly. Mixing python string formatting with regular expressions

> makes it harder to read, and is inconsistent with how the versioned

> namespace is handled elsewhere. In Printer.add_version and

> add_one_type_printer we just register two names, one using std:: and

> one using std::__7::. We can do the same for the template type

> printers.


     Yes, your approach is much nicer even if it results in more type 
printer registered.

     My plan was to submit the attached patch but this doesn't work as 
the python module seems to be loaded before libstdc++.so. If you know a 
way to test for versioned namespace before starting registering printers 
this patch might still be useful. Otherwise I will just forget it.

Françoisdiff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 36dd81d..5e42988 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -79,6 +79,15 @@ try:
 except ImportError:
     pass
 
+_versioned_namespace = None
+
+# Use std::string to find out if versioned namespace has been activated.
+try:
+    gdb.lookup_type('std::string')
+except RuntimeError:
+    _versioned_namespace = '__7::'
+    pass
+
 # Starting with the type ORIG, search for the member type NAME.  This
 # handles searching upward through superclasses.  This is needed to
 # work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615.
@@ -100,8 +109,6 @@ def find_type(orig, name):
             raise ValueError("Cannot find type %s::%s" % (str(orig), name))
         typ = field.type
 
-_versioned_namespace = '__7::'
-
 # Test if a type is a given template instantiation.
 def is_specialization_of(type, template_name):
     global _versioned_namespace
@@ -1222,11 +1229,12 @@ class Printer(object):
         self.subprinters.append(printer)
         self.lookup[name] = printer
 
-    # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION.
+    # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION if needed.
     def add_version(self, base, name, function):
-        self.add(base + name, function)
         if _versioned_namespace:
             self.add(base + _versioned_namespace + name, function)
+        else:
+            self.add(base + name, function)
 
     # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.
     def add_container(self, base, name, function):
@@ -1319,13 +1327,11 @@ class TemplateTypePrinter(object):
 
 def add_one_template_type_printer(obj, name, match, subst):
     match = '^std::' + match + '$'
-    printer = TemplateTypePrinter(name, match, 'std::' + subst)
-    gdb.types.register_type_printer(obj, printer)
     if _versioned_namespace:
-        # Add second type printer for same type in versioned namespace:
+        # Add type printer in versioned namespace:
         match = match.replace('std::', 'std::' + _versioned_namespace)
-        printer = TemplateTypePrinter(name, match, 'std::' + subst)
-        gdb.types.register_type_printer(obj, printer)
+    printer = TemplateTypePrinter(name, match, 'std::' + subst)
+    gdb.types.register_type_printer(obj, printer)
 
 class FilteringTypePrinter(object):
     def __init__(self, match, name):
@@ -1359,11 +1365,11 @@ class FilteringTypePrinter(object):
         return self._recognizer(self.match, self.name)
 
 def add_one_type_printer(obj, match, name):
-    printer = FilteringTypePrinter(match, 'std::' + name)
-    gdb.types.register_type_printer(obj, printer)
+    namespace = 'std::'
     if _versioned_namespace:
-        printer = FilteringTypePrinter(match, 'std::' + _versioned_namespace + name)
-        gdb.types.register_type_printer(obj, printer)
+        namespace += _versioned_namespace
+    printer = FilteringTypePrinter(match, namespace + name)
+    gdb.types.register_type_printer(obj, printer)
 
 def register_type_printers(obj):
     global _use_type_printing
@@ -1427,60 +1433,60 @@ def register_type_printers(obj):
 
     # Do not show defaulted template arguments in class templates
     add_one_template_type_printer(obj, 'unique_ptr<T>',
-            'unique_ptr<(.*), std::default_delete<\\1 ?> >',
-            'unique_ptr<{1}>')
+        'unique_ptr<(.*), std::default_delete<\\1 ?> >',
+        'unique_ptr<{1}>')
 
     add_one_template_type_printer(obj, 'basic_string<T>',
-            'basic_string<((un)?signed char), std::char_traits<\\1 ?>, std::allocator<\\1 ?> >',
-            'basic_string<{1}>')
+        'basic_string<((un)?signed char), std::char_traits<\\1 ?>, std::allocator<\\1 ?> >',
+        'basic_string<{1}>')
 
     add_one_template_type_printer(obj, 'deque<T>',
-            'deque<(.*), std::allocator<\\1 ?> >',
-            'deque<{1}>')
+        'deque<(.*), std::allocator<\\1 ?> >',
+        'deque<{1}>')
     add_one_template_type_printer(obj, 'forward_list<T>',
-            'forward_list<(.*), std::allocator<\\1 ?> >',
-            'forward_list<{1}>')
+        'forward_list<(.*), std::allocator<\\1 ?> >',
+        'forward_list<{1}>')
     add_one_template_type_printer(obj, 'list<T>',
-            'list<(.*), std::allocator<\\1 ?> >',
-            'list<{1}>')
+        'list<(.*), std::allocator<\\1 ?> >',
+        'list<{1}>')
     add_one_template_type_printer(obj, 'vector<T>',
-            'vector<(.*), std::allocator<\\1 ?> >',
-            'vector<{1}>')
+        'vector<(.*), std::allocator<\\1 ?> >',
+        'vector<{1}>')
     add_one_template_type_printer(obj, 'map<Key, T>',
-            'map<(.*), (.*), std::less<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
-            'map<{1}, {2}>')
+        'map<(.*), (.*), std::less<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
+        'map<{1}, {2}>')
     add_one_template_type_printer(obj, 'multimap<Key, T>',
-            'multimap<(.*), (.*), std::less<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
-            'multimap<{1}, {2}>')
+        'multimap<(.*), (.*), std::less<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
+        'multimap<{1}, {2}>')
     add_one_template_type_printer(obj, 'set<T>',
-            'set<(.*), std::less<\\1 ?>, std::allocator<\\1 ?> >',
-            'set<{1}>')
+        'set<(.*), std::less<\\1 ?>, std::allocator<\\1 ?> >',
+        'set<{1}>')
     add_one_template_type_printer(obj, 'multiset<T>',
-            'multiset<(.*), std::less<\\1 ?>, std::allocator<\\1 ?> >',
-            'multiset<{1}>')
+        'multiset<(.*), std::less<\\1 ?>, std::allocator<\\1 ?> >',
+        'multiset<{1}>')
     add_one_template_type_printer(obj, 'unordered_map<Key, T>',
-            'unordered_map<(.*), (.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
-            'unordered_map<{1}, {2}>')
+        'unordered_map<(.*), (.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
+        'unordered_map<{1}, {2}>')
     add_one_template_type_printer(obj, 'unordered_multimap<Key, T>',
-            'unordered_multimap<(.*), (.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
-            'unordered_multimap<{1}, {2}>')
+        'unordered_multimap<(.*), (.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
+        'unordered_multimap<{1}, {2}>')
     add_one_template_type_printer(obj, 'unordered_set<T>',
-            'unordered_set<(.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<\\1 ?> >',
-            'unordered_set<{1}>')
+        'unordered_set<(.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<\\1 ?> >',
+        'unordered_set<{1}>')
     add_one_template_type_printer(obj, 'unordered_multiset<T>',
-            'unordered_multiset<(.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<\\1 ?> >',
-            'unordered_multiset<{1}>')
+        'unordered_multiset<(.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<\\1 ?> >',
+        'unordered_multiset<{1}>')
 
     # strip the "fundamentals_v1" inline namespace from these types
     add_one_template_type_printer(obj, 'any<T>',
-            'experimental::fundamentals_v\d::any<(.*)>',
-            'experimental::any<\\1>')
+        'experimental::fundamentals_v\d::any<(.*)>',
+        'experimental::any<\\1>')
     add_one_template_type_printer(obj, 'optional<T>',
-            'experimental::fundamentals_v\d::optional<(.*)>',
-            'experimental::optional<\\1>')
+        'experimental::fundamentals_v\d::optional<(.*)>',
+        'experimental::optional<\\1>')
     add_one_template_type_printer(obj, 'basic_string_view<C>',
-            'experimental::fundamentals_v\d::basic_string_view<(.*), std::char_traits<\\1> >',
-            'experimental::basic_string_view<\\1>')
+        'experimental::fundamentals_v\d::basic_string_view<(.*), std::char_traits<\\1> >',
+        'experimental::basic_string_view<\\1>')
 
 def register_libstdcxx_printers (obj):
     "Register libstdc++ pretty-printers with objfile Obj."



Jonathan Wakely Jan. 19, 2017, 9:21 p.m. | #2
On 19/01/17 22:01 +0100, François Dumont wrote:
>On 10/01/2017 13:39, Jonathan Wakely wrote:

>>I've committed the attached patch, which passes the tests for the

>>default configuration and the versioned namespace configuration.

>>

>>I added another helper function, strip_versioned_namespace, which is

>>more expressive than doing typename.replace(vers_nsp, '') everywhere.

>>I've also renamed vers_nsp to _versioned_namespace (using the naming

>>convention for global variables private to the module). I've added

>>checks so that if that variable is None then the extra printers and

>>special cases for the versioned namespace are skipped. That's not

>>currently used, but it would allow us to optimise things later if

>>needed.

>

>Very nice feature indeed, see below.

>

>>

>>I also needed to update the new SharedPtrMethodsMatcher to add

>>"(__\d+)?" to the regular expression.

>>

>>

>>>@@ -1392,47 +1406,54 @@ def register_type_printers(obj):

>>>    add_one_type_printer(obj, 'discard_block_engine', 'ranlux48')

>>>    add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b')

>>>

>>>+    # Consider optional versioned namespace

>>>+    opt_nsp = '(' + vers_nsp + ')?'

>>>+

>>>    # Do not show defaulted template arguments in class templates

>>>    add_one_template_type_printer(obj, 'unique_ptr<T>',

>>>-            'unique_ptr<(.*), std::default_delete<\\1 ?> >',

>>>-            'unique_ptr<{1}>')

>>>+        '{0}unique_ptr<(.*), std::{0}default_delete<\\2 ?> 

>>>>'.format(opt_nsp),

>>>+        'unique_ptr<{2}>')

>>

>>This is ugly. Mixing python string formatting with regular expressions

>>makes it harder to read, and is inconsistent with how the versioned

>>namespace is handled elsewhere. In Printer.add_version and

>>add_one_type_printer we just register two names, one using std:: and

>>one using std::__7::. We can do the same for the template type

>>printers.

>

>    Yes, your approach is much nicer even if it results in more type 

>printer registered.

>

>    My plan was to submit the attached patch but this doesn't work as 

>the python module seems to be loaded before libstdc++.so. If you know 

>a way to test for versioned namespace before starting registering 

>printers this patch might still be useful. Otherwise I will just 

>forget it.


See the attached patch, which decides at configure-time whether to
enable the versioned namespace printers or not. This is what I had in
mind.diff --git a/libstdc++-v3/python/Makefile.am b/libstdc++-v3/python/Makefile.am
index 80790e2..5d19d3d 100644
--- a/libstdc++-v3/python/Makefile.am
+++ b/libstdc++-v3/python/Makefile.am
@@ -29,6 +29,12 @@ else
 pythondir = $(datadir)/gcc-$(gcc_version)/python
 endif
 
+if ENABLE_SYMVERS_GNU_NAMESPACE
+use_versioned_namespace = True
+else
+use_versioned_namespace = False
+endif
+
 all-local: gdb.py
 
 nobase_python_DATA = \
@@ -39,7 +45,9 @@ nobase_python_DATA = \
 
 gdb.py: hook.in Makefile
 	sed -e 's,@pythondir@,$(pythondir),' \
-	    -e 's,@toolexeclibdir@,$(toolexeclibdir),' < $(srcdir)/hook.in > $@
+	    -e 's,@toolexeclibdir@,$(toolexeclibdir),' \
+	    -e 's,@use_versioned_namespace@,$(use_versioned_namespace),' \
+	    < $(srcdir)/hook.in > $@
 
 install-data-local: gdb.py
 	@$(mkdir_p) $(DESTDIR)$(toolexeclibdir)
diff --git a/libstdc++-v3/python/hook.in b/libstdc++-v3/python/hook.in
index b82604a6c..1b3a577 100644
--- a/libstdc++-v3/python/hook.in
+++ b/libstdc++-v3/python/hook.in
@@ -58,4 +58,4 @@ if gdb.current_objfile () is not None:
 # Call a function as a plain import would not execute body of the included file
 # on repeated reloads of this object file.
 from libstdcxx.v6 import register_libstdcxx_printers
-register_libstdcxx_printers(gdb.current_objfile())
+register_libstdcxx_printers(gdb.current_objfile(), @use_versioned_namespace@)
diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 36dd81d..4a7d117 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -1482,7 +1482,7 @@ def register_type_printers(obj):
             'experimental::fundamentals_v\d::basic_string_view<(.*), std::char_traits<\\1> >',
             'experimental::basic_string_view<\\1>')
 
-def register_libstdcxx_printers (obj):
+def register_libstdcxx_printers (obj, use_versioned_namespace = False):
     "Register libstdc++ pretty-printers with objfile Obj."
 
     global _use_gdb_pp
@@ -1495,6 +1495,9 @@ def register_libstdcxx_printers (obj):
             obj = gdb
         obj.pretty_printers.append(libstdcxx_printer)
 
+    if not use_versioned_namespace:
+        _versioned_namespace = None
+
     register_type_printers(obj)
 
 def build_libstdcxx_dictionary ():

Jonathan Wakely Feb. 16, 2017, 12:11 p.m. | #3
On 15/02/17 22:44 +0100, François Dumont wrote:
>Hi

>

>    Here is the end result. I eventually chose to detect usage of 

>versioned namespace while generating the .gdb file. I haven't use any 

>caching mecanism considering the limited number of test cases.

>

>    Tested under Linux x86_64 with and without versioned namespace.

>

>    * python/Makefile.am (use_versioned_namespace): New.

>    (gdb.py): Subst use_versioned_namespace.

>    * python/Makefile.in: Regenerate.

>    * python/hook.in: Adapt.

>    * python/libstdcxx/v6/printers.py (Printer.add_version): Add name

>    versioned namespace if _versioned_namespace is defined.

>    (Printer.add_one_template_type_printer): Likewise

>    (add_one_type_printer): Likewise.

>    (register_libstdcxx_printers): Add parameter to indicate if versioned

>    namespace is active.

>    * testsuite/lib/gdb-test.exp (get_use_versioned_namespace): New.

>    (gdb-test): Use latter.

>    * testsuite/libstdc++-prettyprinters/48362.cc: Prefer note-test to

>    regexp-test.

>

>Ok to commit to trunk ?


No, I thought the point of the use_versioned_namespace parameter was
to optimise thigns later, if needed. Do we need to do it?

We certainly don't need to do it during stage 4, as it's not actually
fixing any bug.

Let's reconsider during stage 1.

Patch hide | download patch | download mbox

commit 6238b856776f1a86626f626009d28f4d29c119d8
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Jan 10 12:31:31 2017 +0000

    Make Python printers and xmethods work with versioned namespace
    
    2017-01-10  Fran??ois Dumont  <fdumont@gcc.gnu.org>
    	    Jonathan Wakely  <jwakely@redhat.com>
    
    	* python/libstdcxx/v6/printers.py (_versioned_namespace): Define.
    	(is_specialization, strip_versioned_namespace): New helpers functions
    	to work with symbols in the versioned namespace.
    	(Printer.add_version): Add second name using versioned namespace.
    	(add_one_template_type_printer, add_one_type_printer): Add second
    	type printers using versioned namespace.
    	(register_type_printers): Add template type printer for basic_string.
    	(build_libstdcxx_dictionary): Remove dead code.
    	* python/libstdcxx/v6/xmethods.py: Make all matchers look for
    	versioned namespace.
    	* testsuite/libstdc++-prettyprinters/48362.cc: Adjust expected
    	results.
    	* testsuite/libstdc++-prettyprinters/whatis.cc: Likewise.

diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 7690a6b..36dd81d 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -100,11 +100,26 @@  def find_type(orig, name):
             raise ValueError("Cannot find type %s::%s" % (str(orig), name))
         typ = field.type
 
+_versioned_namespace = '__7::'
+
+# Test if a type is a given template instantiation.
+def is_specialization_of(type, template_name):
+    global _versioned_namespace
+    if _versioned_namespace:
+        return re.match('^std::(%s)?%s<.*>$' % (_versioned_namespace, template_name), type) is not None
+    return re.match('^std::%s<.*>$' % template_name, type) is not None
+
+def strip_versioned_namespace(typename):
+    global _versioned_namespace
+    if _versioned_namespace:
+        return typename.replace(_versioned_namespace, '')
+    return typename
+
 class SharedPointerPrinter:
     "Print a shared_ptr or weak_ptr"
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = strip_versioned_namespace(typename)
         self.val = val
 
     def to_string (self):
@@ -127,9 +142,9 @@  class UniquePointerPrinter:
 
     def to_string (self):
         impl_type = self.val.type.fields()[0].type.tag
-        if impl_type.startswith('std::__uniq_ptr_impl<'): # New implementation
+        if is_specialization_of(impl_type, '__uniq_ptr_impl'): # New implementation
             v = self.val['_M_t']['_M_t']['_M_head_impl']
-        elif impl_type.startswith('std::tuple<'):
+        elif is_specialization_of(impl_type, 'tuple'):
             v = self.val['_M_t']['_M_head_impl']
         else:
             raise ValueError("Unsupported implementation for unique_ptr: %s" % self.val.type.fields()[0].type.tag)
@@ -179,7 +194,7 @@  class StdListPrinter:
             return ('[%d]' % count, val)
 
     def __init__(self, typename, val):
-        self.typename = typename
+        self.typename = strip_versioned_namespace(typename)
         self.val = val
 
     def children(self):
@@ -299,7 +314,7 @@  class StdVectorPrinter:
                 return ('[%d]' % count, elt)
 
     def __init__(self, typename, val):
-        self.typename = typename
+        self.typename = strip_versioned_namespace(typename)
         self.val = val
         self.is_bool = val.type.template_argument(0).code  == gdb.TYPE_CODE_BOOL
 
@@ -403,7 +418,7 @@  class StdTuplePrinter:
                 return ('[%d]' % self.count, impl['_M_head_impl'])
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = strip_versioned_namespace(typename)
         self.val = val;
 
     def children (self):
@@ -418,7 +433,7 @@  class StdStackOrQueuePrinter:
     "Print a std::stack or std::queue"
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = strip_versioned_namespace(typename)
         self.visualizer = gdb.default_visualizer(val['c'])
 
     def children (self):
@@ -496,7 +511,10 @@  class StdRbtreeIteratorPrinter:
     def __init__ (self, typename, val):
         self.val = val
         valtype = self.val.type.template_argument(0).strip_typedefs()
-        nodetype = gdb.lookup_type('std::_Rb_tree_node<' + str(valtype) + '>')
+        nodetype = '_Rb_tree_node<' + str(valtype) + '>'
+        if _versioned_namespace and typename.startswith('std::' + _versioned_namespace):
+            nodetype = _versioned_namespace + nodetype
+        nodetype = gdb.lookup_type('std::' + nodetype)
         self.link_type = nodetype.strip_typedefs().pointer()
 
     def to_string (self):
@@ -552,7 +570,7 @@  class StdMapPrinter:
             return result
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = strip_versioned_namespace(typename)
         self.val = val
 
     def to_string (self):
@@ -592,7 +610,7 @@  class StdSetPrinter:
             return result
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = strip_versioned_namespace(typename)
         self.val = val
 
     def to_string (self):
@@ -609,7 +627,7 @@  class StdBitsetPrinter:
     "Print a std::bitset"
 
     def __init__(self, typename, val):
-        self.typename = typename
+        self.typename = strip_versioned_namespace(typename)
         self.val = val
 
     def to_string (self):
@@ -679,7 +697,7 @@  class StdDequePrinter:
             return result
 
     def __init__(self, typename, val):
-        self.typename = typename
+        self.typename = strip_versioned_namespace(typename)
         self.val = val
         self.elttype = val.type.template_argument(0)
         size = self.elttype.sizeof
@@ -805,7 +823,7 @@  class Tr1UnorderedSetPrinter:
     "Print a tr1::unordered_set"
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = strip_versioned_namespace(typename)
         self.val = val
 
     def hashtable (self):
@@ -831,7 +849,7 @@  class Tr1UnorderedMapPrinter:
     "Print a tr1::unordered_map"
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = strip_versioned_namespace(typename)
         self.val = val
 
     def hashtable (self):
@@ -897,7 +915,7 @@  class StdForwardListPrinter:
 
     def __init__(self, typename, val):
         self.val = val
-        self.typename = typename
+        self.typename = strip_versioned_namespace(typename)
 
     def children(self):
         nodetype = find_type(self.val.type, '_Node')
@@ -952,12 +970,12 @@  class SingleObjContainerPrinter(object):
             return self.visualizer.display_hint ()
         return self.hint
 
-
 class StdExpAnyPrinter(SingleObjContainerPrinter):
     "Print a std::any or std::experimental::any"
 
     def __init__ (self, typename, val):
         self.typename = re.sub('^std::experimental::fundamentals_v\d::', 'std::experimental::', typename, 1)
+        self.typename = strip_versioned_namespace(self.typename)
         self.val = val
         self.contained_type = None
         contained_value = None
@@ -972,8 +990,11 @@  class StdExpAnyPrinter(SingleObjContainerPrinter):
             if not m:
                 raise ValueError("Unknown manager function in %s" % self.typename)
 
+            mgrname = m.group(1)
             # FIXME need to expand 'std::string' so that gdb.lookup_type works
-            mgrname = re.sub("std::string(?!\w)", str(gdb.lookup_type('std::string').strip_typedefs()), m.group(1))
+            if 'std::string' in mgrname:
+                mgrname = re.sub("std::string(?!\w)", str(gdb.lookup_type('std::string').strip_typedefs()), m.group(1))
+
             mgrtype = gdb.lookup_type(mgrname)
             self.contained_type = mgrtype.template_argument(0)
             valptr = None
@@ -994,7 +1015,7 @@  class StdExpAnyPrinter(SingleObjContainerPrinter):
         if hasattr (self.visualizer, 'children'):
             return desc + self.visualizer.to_string ()
         valtype = self._recognize (self.contained_type)
-        return desc + valtype
+        return desc + strip_versioned_namespace(str(valtype))
 
 class StdExpOptionalPrinter(SingleObjContainerPrinter):
     "Print a std::optional or std::experimental::optional"
@@ -1002,6 +1023,7 @@  class StdExpOptionalPrinter(SingleObjContainerPrinter):
     def __init__ (self, typename, val):
         valtype = self._recognize (val.type.template_argument(0))
         self.typename = re.sub('^std::(experimental::|)(fundamentals_v\d::|)(.*)', r'std::\1\3<%s>' % valtype, typename, 1)
+        self.typename = strip_versioned_namespace(self.typename)
         self.val = val
         contained_value = val['_M_payload'] if self.val['_M_engaged'] else None
         visualizer = gdb.default_visualizer (val['_M_payload'])
@@ -1021,6 +1043,7 @@  class StdVariantPrinter(SingleObjContainerPrinter):
     def __init__(self, typename, val):
         alternatives = self._template_args(val)
         self.typename = "%s<%s>" % (typename, ', '.join([self._recognize(alt) for alt in alternatives]))
+        self.typename = strip_versioned_namespace(self.typename)
         self.index = val['_M_index']
         if self.index >= len(alternatives):
             self.contained_type = None
@@ -1058,7 +1081,7 @@  class StdNodeHandlePrinter(SingleObjContainerPrinter):
     def __init__(self, typename, val):
         self.value_type = val.type.template_argument(1)
         nodetype = val.type.template_argument(2).template_argument(0)
-        self.is_rb_tree_node = nodetype.name.startswith('std::_Rb_tree_node')
+        self.is_rb_tree_node = is_specialization_of(nodetype.name, '_Rb_tree_node')
         self.is_map_node = val.type.template_argument(0) != self.value_type
         nodeptr = val['_M_ptr']
         if nodeptr:
@@ -1202,7 +1225,8 @@  class Printer(object):
     # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION.
     def add_version(self, base, name, function):
         self.add(base + name, function)
-        self.add(base + '__7::' + name, function)
+        if _versioned_namespace:
+            self.add(base + _versioned_namespace + name, function)
 
     # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.
     def add_container(self, base, name, function):
@@ -1294,8 +1318,14 @@  class TemplateTypePrinter(object):
         return self._recognizer(self.pattern, self.subst)
 
 def add_one_template_type_printer(obj, name, match, subst):
-    printer = TemplateTypePrinter(name, '^std::' + match + '$', 'std::' + subst)
+    match = '^std::' + match + '$'
+    printer = TemplateTypePrinter(name, match, 'std::' + subst)
     gdb.types.register_type_printer(obj, printer)
+    if _versioned_namespace:
+        # Add second type printer for same type in versioned namespace:
+        match = match.replace('std::', 'std::' + _versioned_namespace)
+        printer = TemplateTypePrinter(name, match, 'std::' + subst)
+        gdb.types.register_type_printer(obj, printer)
 
 class FilteringTypePrinter(object):
     def __init__(self, match, name):
@@ -1322,7 +1352,7 @@  class FilteringTypePrinter(object):
                 except:
                     pass
             if self.type_obj == type_obj:
-                return self.name
+                return strip_versioned_namespace(self.name)
             return None
 
     def instantiate(self):
@@ -1331,6 +1361,9 @@  class FilteringTypePrinter(object):
 def add_one_type_printer(obj, match, name):
     printer = FilteringTypePrinter(match, 'std::' + name)
     gdb.types.register_type_printer(obj, printer)
+    if _versioned_namespace:
+        printer = FilteringTypePrinter(match, 'std::' + _versioned_namespace + name)
+        gdb.types.register_type_printer(obj, printer)
 
 def register_type_printers(obj):
     global _use_type_printing
@@ -1372,9 +1405,9 @@  def register_type_printers(obj):
     # Note that we can't have a printer for std::wstreampos, because
     # it shares the same underlying type as std::streampos.
     add_one_type_printer(obj, 'fpos', 'streampos')
+
     add_one_type_printer(obj, 'basic_string', 'u16string')
     add_one_type_printer(obj, 'basic_string', 'u32string')
-
     add_one_type_printer(obj, 'basic_string_view', 'u16string_view')
     add_one_type_printer(obj, 'basic_string_view', 'u32string_view')
 
@@ -1397,6 +1430,10 @@  def register_type_printers(obj):
             'unique_ptr<(.*), std::default_delete<\\1 ?> >',
             'unique_ptr<{1}>')
 
+    add_one_template_type_printer(obj, 'basic_string<T>',
+            'basic_string<((un)?signed char), std::char_traits<\\1 ?>, std::allocator<\\1 ?> >',
+            'basic_string<{1}>')
+
     add_one_template_type_printer(obj, 'deque<T>',
             'deque<(.*), std::allocator<\\1 ?> >',
             'deque<{1}>')
@@ -1465,11 +1502,6 @@  def build_libstdcxx_dictionary ():
 
     libstdcxx_printer = Printer("libstdc++-v6")
 
-    # For _GLIBCXX_BEGIN_NAMESPACE_VERSION.
-    vers = '(__7::)?'
-    # For _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.
-    container = '(__cxx1998::' + vers + ')?'
-
     # libstdc++ objects requiring pretty-printing.
     # In order from:
     # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
diff --git a/libstdc++-v3/python/libstdcxx/v6/xmethods.py b/libstdc++-v3/python/libstdcxx/v6/xmethods.py
index def72b0..02feab6 100644
--- a/libstdc++-v3/python/libstdcxx/v6/xmethods.py
+++ b/libstdc++-v3/python/libstdcxx/v6/xmethods.py
@@ -148,7 +148,7 @@  class ArrayMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::array<.*>$', class_type.tag):
+        if not re.match('^std::(__\d+::)?array<.*>$', class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
@@ -265,7 +265,7 @@  class DequeMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::deque<.*>$', class_type.tag):
+        if not re.match('^std::(__\d+::)?deque<.*>$', class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
@@ -309,7 +309,7 @@  class ForwardListMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::forward_list<.*>$', class_type.tag):
+        if not re.match('^std::(__\d+::)?forward_list<.*>$', class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
@@ -390,7 +390,7 @@  class ListMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::(__cxx11::)?list<.*>$', class_type.tag):
+        if not re.match('^std::(__\d+::)?(__cxx11::)?list<.*>$', class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
@@ -505,7 +505,7 @@  class VectorMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::vector<.*>$', class_type.tag):
+        if not re.match('^std::(__\d+::)?vector<.*>$', class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
@@ -554,7 +554,7 @@  class AssociativeContainerMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::%s<.*>$' % self._name, class_type.tag):
+        if not re.match('^std::(__\d+::)?%s<.*>$' % self._name, class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
@@ -586,9 +586,9 @@  class UniquePtrGetWorker(gdb.xmethod.XMethodWorker):
 
     def __call__(self, obj):
         impl_type = obj.dereference().type.fields()[0].type.tag
-        if impl_type.startswith('std::__uniq_ptr_impl<'): # New implementation
+        if re.match('^std::(__\d+::)?__uniq_ptr_impl<.*>$', impl_type): # New implementation
             return obj['_M_t']['_M_t']['_M_head_impl']
-        elif impl_type.startswith('std::tuple<'):
+        elif re.match('^std::(__\d+::)?tuple<.*>$', impl_type):
             return obj['_M_t']['_M_head_impl']
         return None
 
@@ -640,7 +640,7 @@  class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::unique_ptr<.*>$', class_type.tag):
+        if not re.match('^std::(__\d+::)?unique_ptr<.*>$', class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
@@ -758,7 +758,7 @@  class SharedPtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::shared_ptr<.*>$', class_type.tag):
+        if not re.match('^std::(__\d+::)?shared_ptr<.*>$', class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/48362.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/48362.cc
index 16ef07b..998b6d5 100644
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/48362.cc
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/48362.cc
@@ -26,10 +26,10 @@  int
 main()
 {
   std::tuple<> t1;
-// { dg-final { regexp-test t1 {empty std::(__7::)?tuple} } }
+// { dg-final { regexp-test t1 {empty std::tuple} } }
 
   std::tuple<std::string, int, std::tuple<>> t2{ "Johnny", 5, {} };
-// { dg-final { regexp-test t2 {std::(__7::)?tuple containing = {\[1\] = "Johnny", \[2\] = 5, \[3\] = {<std::(__7::)?tuple<>> = empty std::(__7::)?tuple, <No data fields>}}} } }
+// { dg-final { regexp-test t2 {std::tuple containing = {\[1\] = "Johnny", \[2\] = 5, \[3\] = {<std::(__7::)?tuple<>> = empty std::tuple, <No data fields>}}} } }
 
   std::cout << "\n";
   return 0; // Mark SPOT
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/whatis.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/whatis.cc
index 31ded8b..7a55bb7 100644
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/whatis.cc
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/whatis.cc
@@ -166,11 +166,11 @@  holder<std::knuth_b> knuth_b_holder;
 
 ustring *ustring_ptr;
 holder<ustring> ustring_holder;
-// { dg-final { whatis-test ustring_holder "holder<std::basic_string<unsigned char, std::char_traits<unsigned char>, std::allocator<unsigned char> > >" } }
+// { dg-final { whatis-test ustring_holder "holder<std::basic_string<unsigned char> >" } }
 
 std::basic_string<signed char> *sstring_ptr;
 holder< std::basic_string<signed char> > sstring_holder;
-// { dg-final { whatis-test sstring_holder "holder<std::basic_string<signed char, std::char_traits<signed char>, std::allocator<signed char> > >" } }
+// { dg-final { whatis-test sstring_holder "holder<std::basic_string<signed char> >" } }
 
 std::vector<std::deque<std::unique_ptr<char>>> *seq1_ptr;
 holder< std::vector<std::deque<std::unique_ptr<char>>> > seq1_holder;