aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2021-11-04 22:50:02 +0000
committerJonathan Wakely <jwakely@redhat.com>2021-11-04 22:50:02 +0000
commita634928f5c8a281442ac8f5fb1636aed048ed72c (patch)
tree2a423d626c36d9ab6ee6f9eaf9e9dfa771ea54ea /libstdc++-v3
parentf4130a3eb545ab1aaf3ecb44f3d06b43e3751e04 (diff)
downloadgcc-a634928f5c8a281442ac8f5fb1636aed048ed72c.zip
gcc-a634928f5c8a281442ac8f5fb1636aed048ed72c.tar.gz
gcc-a634928f5c8a281442ac8f5fb1636aed048ed72c.tar.bz2
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.
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/python/libstdcxx/v6/printers.py71
-rw-r--r--libstdc++-v3/python/libstdcxx/v6/xmethods.py2
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 c7da407..c5072c5 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 77870e9..991d945 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: