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.
commit 6238b856776f1a86626f626009d28f4d29c119d8
Author: Jonathan Wakely <jwak...@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 <fdum...@gcc.gnu.org>
Jonathan Wakely <jwak...@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;