On Thu, 5 Feb 2026 at 11:36, Tomasz Kaminski <[email protected]> wrote: > > > > 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.
It relies on the hacked-up types in the test to be an accurate emulation of the old implementation, and in this case I defined *just enough* of the old impl to keep the printer happy (the sp_atomic and Counts types above are not how the implementation really looks). But it allows us to verify that the backwards compatibility support in the printers does work, without having to compile TUs with an old GCC then link them to a new GCC and debug them using the new printers. I did *also* do that, manually, but we can't automate that for the testsuite.
