Fix unique_ptr pretty printer for empty classes
authorJonathan Wakely <jwakely@redhat.com>
Tue, 14 May 2019 11:17:18 +0000 (12:17 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Tue, 14 May 2019 11:17:18 +0000 (12:17 +0100)
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.

From-SVN: r271159

libstdc++-v3/ChangeLog
libstdc++-v3/python/libstdcxx/v6/printers.py
libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc
libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc

index 440a1dfd80d786167cfa5d004c2dc2673db6be15..b6061f406cb84a2dba2f6e4d09d296b0d0dac1f4 100644 (file)
@@ -1,5 +1,12 @@
 2019-05-14  Jonathan Wakely  <jwakely@redhat.com>
 
+       * 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.
+
        LWG 2899 - Make is_move_constructible correct for unique_ptr
        * include/bits/unique_ptr.h (__uniq_ptr_impl): Add move constructor,
        move assignment operator.
index eae06f93c345813efc8a80f965546b50324094c3..162b00760e65e358d33836ababea8e855313d76a 100644 (file)
@@ -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)
index 7bfc3c6886723936c036eeb3d82662a9271e2d11..28b0c2154d7aa9233d6a5b25ebf5f6b1012c02fd 100644 (file)
 
 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>>
index 7d0a9a21768226465ffd552139f3a0e541ffbcfc..cc588125bdcc89d486432346ab8ee05816f50661 100644 (file)
@@ -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;