public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-4928] libstdc++: Fix pretty printing of std::unique_ptr [PR103086]
@ 2021-11-04 23:06 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2021-11-04 23:06 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:a634928f5c8a281442ac8f5fb1636aed048ed72c

commit r12-4928-ga634928f5c8a281442ac8f5fb1636aed048ed72c
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Nov 4 22:50:02 2021 +0000

    libstdc++: Fix pretty printing of std::unique_ptr [PR103086]
    
    Since std::tuple started using [[no_unique_address]] the tuple<T*, D>
    member of std::unique_ptr<T, D> has two _M_head_impl subobjects, in
    different base classes. That means this printer code is ambiguous:
    
        tuple_head_type = tuple_impl_type.fields()[1].type   # _Head_base
        head_field = tuple_head_type.fields()[0]
        if head_field.name == '_M_head_impl':
            self.pointer = tuple_member['_M_head_impl']
    
    In older versions of GDB it happened to work by chance, because GDB
    returned the last _M_head_impl member and std::tuple's base classes are
    stored in reverse order, so the last one was the T* element of the
    tuple. Since GDB 11 it returns the first _M_head_impl, which is the
    deleter element.
    
    The fix is for the printer to stop using an ambiguous field name and
    cast the tuple to the correct base class before accessing the
    _M_head_impl member.
    
    Instead of fixing this in both UniquePointerPrinter and StdPathPrinter a
    new unique_ptr_get function is defined to do it correctly. That is
    defined in terms of new tuple_get and _tuple_impl_get functions.
    
    It would be possible to reuse _tuple_impl_get to access each element in
    StdTuplePrinter._iterator.__next__, but that already does the correct
    casting, and wouldn't be much simpler anyway.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/103086
            * python/libstdcxx/v6/printers.py (_tuple_impl_get): New helper
            for accessing the tuple element stored in a _Tuple_impl node.
            (tuple_get): New function for accessing a tuple element.
            (unique_ptr_get): New function for accessing a unique_ptr.
            (UniquePointerPrinter, StdPathPrinter): Use unique_ptr_get.
            * python/libstdcxx/v6/xmethods.py (UniquePtrGetWorker): Cast
            tuple to its base class before accessing _M_head_impl.

Diff:
---
 libstdc++-v3/python/libstdcxx/v6/printers.py | 71 ++++++++++++++++++++--------
 libstdc++-v3/python/libstdcxx/v6/xmethods.py |  2 +-
 2 files changed, 52 insertions(+), 21 deletions(-)

diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index c7da4079a7d..c5072c52281 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -240,32 +240,63 @@ class SharedPointerPrinter:
                 state = 'use count %d, weak count %d' % (usecount, weakcount - 1)
         return '%s<%s> (%s)' % (self.typename, str(self.val.type.template_argument(0)), state)
 
+def _tuple_impl_get(val):
+    "Return the tuple element stored in a _Tuple_impl<N, T> base class."
+    bases = val.type.fields()
+    if not bases[-1].is_base_class:
+        raise ValueError("Unsupported implementation for std::tuple: %s" % str(val.type))
+    # Get the _Head_base<N, T> base class:
+    head_base = val.cast(bases[-1].type)
+    fields = head_base.type.fields()
+    if len(fields) == 0:
+        raise ValueError("Unsupported implementation for std::tuple: %s" % str(val.type))
+    if fields[0].name == '_M_head_impl':
+        # The tuple element is the _Head_base::_M_head_impl data member.
+        return head_base['_M_head_impl']
+    elif fields[0].is_base_class:
+        # The tuple element is an empty base class of _Head_base.
+        # Cast to that empty base class.
+        return head_base.cast(fields[0].type)
+    else:
+        raise ValueError("Unsupported implementation for std::tuple: %s" % str(val.type))
+
+def tuple_get(n, val):
+    "Return the result of std::get<n>(val) on a std::tuple"
+    tuple_size = len(get_template_arg_list(val.type))
+    if n > tuple_size:
+        raise ValueError("Out of range index for std::get<N> on std::tuple")
+    # Get the first _Tuple_impl<0, T...> base class:
+    node = val.cast(val.type.fields()[0].type)
+    while n > 0:
+        # Descend through the base classes until the Nth one.
+        node = node.cast(node.type.fields()[0].type)
+        n -= 1
+    return _tuple_impl_get(node)
+
+def unique_ptr_get(val):
+    "Return the result of val.get() on a std::unique_ptr"
+    # std::unique_ptr<T, D> contains a std::tuple<D::pointer, D>,
+    # either as a direct data member _M_t (the old implementation)
+    # or within a data member of type __uniq_ptr_data.
+    impl_type = val.type.fields()[0].type.strip_typedefs()
+    # Check for new implementations first:
+    if is_specialization_of(impl_type, '__uniq_ptr_data') \
+        or is_specialization_of(impl_type, '__uniq_ptr_impl'):
+        tuple_member = val['_M_t']['_M_t']
+    elif is_specialization_of(impl_type, 'tuple'):
+        tuple_member = val['_M_t']
+    else:
+        raise ValueError("Unsupported implementation for unique_ptr: %s" % str(impl_type))
+    return tuple_get(0, tuple_member)
+
 class UniquePointerPrinter:
     "Print a unique_ptr"
 
     def __init__ (self, typename, val):
         self.val = val
-        impl_type = val.type.fields()[0].type.strip_typedefs()
-        # Check for new implementations first:
-        if is_specialization_of(impl_type, '__uniq_ptr_data') \
-            or is_specialization_of(impl_type, '__uniq_ptr_impl'):
-            tuple_member = val['_M_t']['_M_t']
-        elif is_specialization_of(impl_type, 'tuple'):
-            tuple_member = val['_M_t']
-        else:
-            raise ValueError("Unsupported implementation for unique_ptr: %s" % str(impl_type))
-        tuple_impl_type = tuple_member.type.fields()[0].type # _Tuple_impl
-        tuple_head_type = tuple_impl_type.fields()[1].type   # _Head_base
-        head_field = tuple_head_type.fields()[0]
-        if head_field.name == '_M_head_impl':
-            self.pointer = tuple_member['_M_head_impl']
-        elif head_field.is_base_class:
-            self.pointer = tuple_member.cast(head_field.type)
-        else:
-            raise ValueError("Unsupported implementation for tuple in unique_ptr: %s" % str(impl_type))
 
     def children (self):
-        return SmartPtrIterator(self.pointer)
+        return SmartPtrIterator(unique_ptr_get(self.val))
 
     def to_string (self):
         return ('std::unique_ptr<%s>' % (str(self.val.type.template_argument(0))))
@@ -1370,7 +1401,7 @@ class StdPathPrinter:
     def __init__ (self, typename, val):
         self.val = val
         self.typename = typename
-        impl = self.val['_M_cmpts']['_M_impl']['_M_t']['_M_t']['_M_head_impl']
+        impl = unique_ptr_get(self.val['_M_cmpts']['_M_impl'])
         self.type = impl.cast(gdb.lookup_type('uintptr_t')) & 3
         if self.type == 0:
             self.impl = impl
diff --git a/libstdc++-v3/python/libstdcxx/v6/xmethods.py b/libstdc++-v3/python/libstdcxx/v6/xmethods.py
index 77870e9a264..991d945321a 100644
--- a/libstdc++-v3/python/libstdcxx/v6/xmethods.py
+++ b/libstdc++-v3/python/libstdcxx/v6/xmethods.py
@@ -597,7 +597,7 @@ class UniquePtrGetWorker(gdb.xmethod.XMethodWorker):
         tuple_head_type = tuple_impl_type.fields()[1].type   # _Head_base
         head_field = tuple_head_type.fields()[0]
         if head_field.name == '_M_head_impl':
-            return tuple_member['_M_head_impl']
+            return tuple_member.cast(tuple_head_type)['_M_head_impl']
         elif head_field.is_base_class:
             return tuple_member.cast(head_field.type)
         else:


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-11-04 23:06 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-04 23:06 [gcc r12-4928] libstdc++: Fix pretty printing of std::unique_ptr [PR103086] Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).