https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103086

            Bug ID: 103086
           Summary: [11/12 Regression] std::unique_ptr printer gets
                    confused by [[no_unique_address]] in tuple
           Product: gcc
           Version: 11.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: redi at gcc dot gnu.org
  Target Milestone: ---

When using GDB 11 or 12 and GCC 11 or 12 the pretty printer for std::unique_ptr
shows the value of the deleter instead of the pointer:

$1 = std::unique_ptr<datum> = {get() = {<No data fields>}}

I filed this as https://sourceware.org/bugzilla/show_bug.cgi?id=28480 but with
Bruno's help we realised it's actually a libstdc++ printer bug.

The problem is that since std::tuple started using [[no_unique_address]] the
tuple<T*, default_delete<T>> object 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 probably more sensible, but now the
printer gets the default_delete<T> element.

The fix is for the printer to stop using an ambiguous field name and cast the
tuple to the right base class before accessing the _M_head_impl member:

--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -258,7 +258,7 @@ class UniquePointerPrinter:
         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']
+            self.pointer = tuple_member.cast(tuple_head_type)['_M_head_impl']
         elif head_field.is_base_class:
             self.pointer = tuple_member.cast(head_field.type)
         else:

Reply via email to