[gcc(refs/vendors/redhat/heads/gcc-8-branch)] libstdc++: Fix unique_ptr pretty printer for empty classes

Jakub Jelinek jakub@gcc.gnu.org
Fri Apr 23 10:37:24 GMT 2021


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

commit a3ae177e245fcaba5390a87481414abc3c3de28d
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue May 14 12:17:18 2019 +0100

    libstdc++: 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: Copy from gcc-9
            branch.
            * testsuite/libstdc++-prettyprinters/cxx11.cc: Check unique_ptr with
            empty pointer type and non-empty deleter.
    
    (cherry picked from commit e25f488d603a6bd7570c1ffdfd9572e4b8a645de)

Diff:
---
 libstdc++-v3/python/libstdcxx/v6/printers.py       |  11 +-
 .../testsuite/libstdc++-prettyprinters/compat.cc   | 116 +++++++++++++++++++++
 .../testsuite/libstdc++-prettyprinters/cxx11.cc    |  20 ++++
 3 files changed, 145 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 37b8173435d..36352b8d0a8 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -181,11 +181,18 @@ class UniquePointerPrinter:
         self.val = val
         impl_type = val.type.fields()[0].type.tag
         if is_specialization_of(impl_type, '__uniq_ptr_impl'): # New implementation
-            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
new file mode 100644
index 00000000000..1555ba8e798
--- /dev/null
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc
@@ -0,0 +1,116 @@
+// { dg-options "-g -O0" }
+// { dg-do run { target c++11 } }
+// { dg-skip-if "" { *-*-* } { "-D_GLIBCXX_PROFILE" } }
+
+// Copyright (C) 2014-2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// Test that current printers still support old definitions of types.
+
+namespace std
+{
+  template<typename T>
+    struct _Head_base : T
+    { };
+
+  template<typename T>
+    struct _Head_base<T*>
+    {
+      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>>
+    struct unique_ptr
+    {
+      unique_ptr(T* p) { _M_t._M_head_impl = p; }
+
+      tuple<T*, D> _M_t;
+    };
+
+  // Old representation of std::optional, before GCC 9
+  template<typename T>
+    struct _Optional_payload
+    {
+      _Optional_payload() : _M_empty(), _M_engaged(false) { }
+      struct _Empty_byte { };
+      union {
+	_Empty_byte _M_empty;
+	T _M_payload;
+      };
+      bool _M_engaged;
+    };
+
+  template<typename T>
+    struct _Optional_base
+    {
+      _Optional_payload<T> _M_payload;
+    };
+
+  template<typename T>
+    struct optional : _Optional_base<T>
+    {
+      optional() { }
+
+      optional(T t)
+      {
+	this->_M_payload._M_payload = t;
+	this->_M_payload._M_engaged = true;
+      }
+    };
+} // namespace std
+
+int
+main()
+{
+  struct datum { };
+  std::unique_ptr<datum> uptr (new datum);
+// { dg-final { regexp-test uptr {std::unique_ptr.datum. = {get\(\) = 0x.*}} } }
+  std::unique_ptr<datum> &ruptr = uptr;
+// { dg-final { regexp-test ruptr {std::unique_ptr.datum. = {get\(\) = 0x.*}} } }
+
+  using std::optional;
+
+  optional<int> o;
+// { dg-final { note-test o {std::optional<int> [no contained value]} } }
+  optional<bool> ob{false};
+// { dg-final { note-test ob {std::optional<bool> = {[contained value] = false}} } }
+  optional<int> oi{5};
+// { dg-final { note-test oi {std::optional<int> = {[contained value] = 5}} } }
+  optional<void*> op{nullptr};
+// { dg-final { note-test op {std::optional<void *> = {[contained value] = 0x0}} } }
+
+  __builtin_puts("");
+  return 0;			// Mark SPOT
+}
+
+// { dg-final { gdb-test SPOT } }
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc
index 0ecc3771351..9a90d8d91db 100644
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc
@@ -60,6 +60,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()
 {
@@ -137,6 +152,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;


More information about the Libstdc++-cvs mailing list