On Thu, Feb 5, 2026 at 12:09 PM Jonathan Wakely <[email protected]> wrote:
> This pretty printer was updated for GCC 16 to match a change to
> std::atomic<shared_ptr<T>>. But the gdb.Type.is_scalar property was
> added in GDB 12.1, so we get an error for older GDB versions.
>
> This adds a workaround for older GDB versions. The gdb.Type.tag property
> is None for scalar types, and should always be defined for the
> std::atomic class template. Another option would be to use the
> is_specialization_of function defined in printers.py, but just checking
> for the tag is simpler.
>
> libstdc++-v3/ChangeLog:
>
> * python/libstdcxx/v6/printers.py (SharedPointerPrinter): Only
> use gdb.Type.is_scalar if supported.
> * testsuite/libstdc++-prettyprinters/compat.cc: Test printer for
> old implementation of std::atomic<std::shared_ptr<T>>.
> ---
>
> v2: Added emulation of the old atomic<shared_ptr> impl to compat.cc to
> verify that the printer still handles it.
>
LGTM.
>
> Tested x86_64-linux, using both GDB 8 and GDB 16, and also tested a
> binary with the GCC 15 std::atomic<shared_ptr> can be printed by the GCC
> 16 printers.py.
>
> libstdc++-v3/python/libstdcxx/v6/printers.py | 10 ++++--
> .../libstdc++-prettyprinters/compat.cc | 34 +++++++++++++++++++
> 2 files changed, 42 insertions(+), 2 deletions(-)
>
> diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py
> b/libstdc++-v3/python/libstdcxx/v6/printers.py
> index 8bb7dd2ad600..be7e7a256065 100644
> --- a/libstdc++-v3/python/libstdcxx/v6/printers.py
> +++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
> @@ -292,9 +292,15 @@ class SharedPointerPrinter(printer_base):
> if self._typename == 'std::atomic':
> # A tagged pointer is stored as uintptr_t.
> val = self._val['_M_refcount']['_M_val']
> - if val.type.is_scalar: # GCC 16 stores uintptr_t
> + # GCC 16 stores it directly as uintptr_t
> + # GCC 12-15 stores std::atomic<uintptr_t>
> + if hasattr(val.type, 'is_scalar'): # Added in GDB 12.1
> + val_is_uintptr = val.type.is_scalar
> + else:
> + val_is_uintptr = val.type.tag is None
> + if val_is_uintptr:
> ptr_val = val
> - else: # GCC 12-15 stores std::atomic<uintptr_t>
> + else:
> ptr_val = val['_M_i']
> ptr_val = ptr_val - (ptr_val % 2) # clear lock bit
> ptr_type = find_type(self._val['_M_refcount'].type, 'pointer')
> diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc
> b/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc
> index 142ddb09e610..35ec5cf23981 100644
> --- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc
> +++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc
> @@ -88,6 +88,30 @@ namespace std
> this->_M_payload._M_engaged = true;
> }
> };
> +
> + using uintptr_t = __UINTPTR_TYPE__;
> + template<typename T> struct shared_ptr;
> + template<typename T> struct atomic;
> + template<> struct atomic<uintptr_t> { uintptr_t _M_i; };
> + template<typename T> struct sp_atomic;
> + struct sp_counts { int _M_use_count; int _M_weak_count; };
> +
> + // Old representation of std::atomic<std::shared_ptr<T>>, before GCC 16
> + template<typename T>
> + struct sp_atomic<shared_ptr<T>>
> + {
> + T* _M_ptr = nullptr;
> + struct Impl {
> + atomic<uintptr_t> _M_val;
> + using pointer = sp_counts*;
> + } _M_refcount;
> + };
> + template<typename T>
> + struct atomic<shared_ptr<T>>
> + {
> + sp_atomic<shared_ptr<T>> _M_impl;
> + };
> +
> } // namespace std
>
> int
> @@ -110,6 +134,16 @@ main()
> optional<void*> op{nullptr};
> // { dg-final { note-test op {std::optional = {[contained value] = 0x0}}
> } }
>
> + std::atomic<std::shared_ptr<int>> aspe{};
> +// { dg-final { note-test aspe {std::atomic<std::shared_ptr<int>> (empty)
> = {get() = 0x0}} } }
> +
> + std::sp_counts counts{ 1, 3 };
> + std::sp_atomic<std::shared_ptr<int>>::Impl::pointer p = &counts;
> + std::atomic<std::shared_ptr<int>> asp{};
> + asp._M_impl._M_ptr = reinterpret_cast<int*>(0x1234abcd);
> + asp._M_impl._M_refcount._M_val._M_i =
> reinterpret_cast<std::uintptr_t>(p);
> +// { dg-final { note-test asp {std::atomic<std::shared_ptr<int>> (use
> count 1, weak count 2) = {get() = 0x1234abcd}} } }
> +
>
I didn't know we have this way to test pretty printers. That's awesome.
> __builtin_puts("");
> return 0; // Mark SPOT
> }
> --
> 2.52.0
>
>