Fix unique_ptr pretty printer for empty classes

Message ID 20190514111904.GA32358@redhat.com
State New
Headers show
Series
  • Fix unique_ptr pretty printer for empty classes
Related show

Commit Message

Jonathan Wakely May 14, 2019, 11:19 a.m.
The printer was confused when unique_ptr<T,D>::pointer is an empty
class, or the deleter is not empty. Instead of assuming the tuple has a
single _M_head_impl member manually inspect the tuple base classes to
get the first element.

Doing this means the "compat" tuple in compat.cc needs to have the
same structure as the real std::tuple, so the printer works for it.

	* python/libstdcxx/v6/printers.py (UniquePointerPrinter.__init__): Do
	not assume field called _M_head_impl is the first tuple element.
	* testsuite/libstdc++-prettyprinters/compat.cc: Make tuple
	implementation more accurate.
	* testsuite/libstdc++-prettyprinters/cxx11.cc: Check unique_ptr with
	empty pointer type and non-empty deleter.

Tested powerpc64le-linux, committed to trunk.
commit e5d48f873a282056dd32bd1808e22b4c42ca7bb7
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue May 14 00:58:53 2019 +0100

    Fix unique_ptr pretty printer for empty classes
    
    The printer was confused when unique_ptr<T,D>::pointer is an empty
    class, or the deleter is not empty. Instead of assuming the tuple has a
    single _M_head_impl member manually inspect the tuple base classes to
    get the first element.
    
            * python/libstdcxx/v6/printers.py (UniquePointerPrinter.__init__): Do
            not assume field called _M_head_impl is the first tuple element.
            * testsuite/libstdc++-prettyprinters/compat.cc: Make tuple
            implementation more accurate.
            * testsuite/libstdc++-prettyprinters/cxx11.cc: Check unique_ptr with
            empty pointer type and non-empty deleter.

Patch

diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index eae06f93c34..162b00760e6 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -185,11 +185,18 @@  class UniquePointerPrinter:
         # Check for new implementations first:
         if is_specialization_of(impl_type, '__uniq_ptr_data') \
             or is_specialization_of(impl_type, '__uniq_ptr_impl'):
-            self.pointer = val['_M_t']['_M_t']['_M_head_impl']
+            tuple_member = val['_M_t']['_M_t']
         elif is_specialization_of(impl_type, 'tuple'):
-            self.pointer = val['_M_t']['_M_head_impl']
+            tuple_member = val['_M_t']
         else:
             raise ValueError("Unsupported implementation for unique_ptr: %s" % 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)
 
     def children (self):
         return SmartPtrIterator(self.pointer)
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc
index 7bfc3c68867..28b0c2154d7 100644
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc
@@ -22,12 +22,30 @@ 
 
 namespace std
 {
-  template<typename T, typename U>
-    struct tuple
+  template<typename T>
+    struct _Head_base : T
+    { };
+
+  template<typename T>
+    struct _Head_base<T*>
     {
-      T _M_head_impl;
+      T* _M_head_impl;
     };
 
+  template<unsigned long, typename ...> struct _Tuple_impl;
+
+  template<typename T, typename U>
+    struct _Tuple_impl<0, T, U> : _Tuple_impl<1, U>, _Head_base<T>
+    { };
+
+  template<typename U>
+    struct _Tuple_impl<1, U> : _Head_base<U>
+    { };
+
+  template<typename T, typename U>
+    struct tuple : _Tuple_impl<0, T, U>
+    { };
+
   template<typename T> struct default_delete { };
 
   template<typename T, typename D = default_delete<T>>
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc
index 7d0a9a21768..cc588125bdc 100644
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc
@@ -59,6 +59,21 @@  struct datum
 
 std::unique_ptr<datum> global;
 
+struct Deleter
+{
+  // Deleter is not an empty class:
+  int deleter_member = -1;
+  // But pointer is an empty class:
+  struct pointer
+  {
+    pointer(const void* = nullptr) { }
+    explicit operator bool() const noexcept { return false; }
+    friend bool operator==(pointer, pointer) noexcept { return true; }
+    friend bool operator!=(pointer, pointer) noexcept { return false; }
+  };
+  void operator()(pointer) const noexcept { }
+};
+
 int
 main()
 {
@@ -136,6 +151,11 @@  main()
   std::unique_ptr<data>& rarrptr = arrptr;
 // { dg-final { regexp-test rarrptr {std::unique_ptr.datum \[\]. = {get\(\) = 0x.*}} } }
 
+  std::unique_ptr<int, Deleter> empty_ptr;
+// { dg-final { note-test empty_ptr {std::unique_ptr<int> = {get() = {<No data fields>}}} } }
+  std::unique_ptr<int, Deleter>& rempty_ptr = empty_ptr;
+// { dg-final { note-test rempty_ptr {std::unique_ptr<int> = {get() = {<No data fields>}}} } }
+
   ExTuple tpl(6,7);
 // { dg-final { note-test tpl {std::tuple containing = {[1] = 6, [2] = 7}} } }
   ExTuple &rtpl = tpl;