https://gcc.gnu.org/g:2e4e58bb43c5769827cd7c6dde46dd1060740e55
commit r16-7321-g2e4e58bb43c5769827cd7c6dde46dd1060740e55 Author: Jonathan Wakely <[email protected]> Date: Wed Feb 4 22:57:34 2026 +0000 libstdc++: Fix std::shared_ptr pretty printer for GDB 11 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>>. Reviewed-by: Tomasz KamiĆski <[email protected]> Diff: --- libstdc++-v3/python/libstdcxx/v6/printers.py | 10 +++++-- .../testsuite/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}} } } + __builtin_puts(""); return 0; // Mark SPOT }
