libstdc++: Add pretty printer for std::atomic

For the atomic specializations for shared_ptr and weak_ptr we can reuse
the existing SharedPointerPrinter, with a small tweak.

libstdc++-v3/ChangeLog:

	* python/libstdcxx/v6/printers.py (SharedPointerPrinter): Add
	support for atomic<shared_ptr<T>> and atomic<weak_ptr<T>>.
	(StdAtomicPrinter): New printer.
	(build_libstdcxx_dictionary): Register new printer.
	* testsuite/libstdc++-prettyprinters/cxx11.cc: Test std::atomic.
	* testsuite/libstdc++-prettyprinters/cxx20.cc: Test atomic smart
	pointers.
This commit is contained in:
Jonathan Wakely 2022-04-27 14:29:34 +01:00
parent e07ea03fce
commit a849584587
3 changed files with 69 additions and 3 deletions

View file

@ -218,7 +218,7 @@ class SmartPtrIterator(Iterator):
return ('get()', val)
class SharedPointerPrinter:
"Print a shared_ptr or weak_ptr"
"Print a shared_ptr, weak_ptr, atomic<shared_ptr>, or atomic<weak_ptr>"
def __init__ (self, typename, val):
self.typename = strip_versioned_namespace(typename)
@ -228,9 +228,21 @@ class SharedPointerPrinter:
def children (self):
return SmartPtrIterator(self.pointer)
# Return the _Sp_counted_base<>* that holds the refcounts.
def _get_refcounts (self):
if self.typename == 'std::atomic':
# A tagged pointer is stored as uintptr_t.
ptr_val = self.val['_M_refcount']['_M_val']['_M_i']
ptr_val = ptr_val - (ptr_val % 2) # clear lock bit
ptr_type = find_type(self.val['_M_refcount'].type, 'pointer')
return ptr_val.cast(ptr_type)
return self.val['_M_refcount']['_M_pi']
def to_string (self):
state = 'empty'
refcounts = self.val['_M_refcount']['_M_pi']
refcounts = self._get_refcounts()
targ = self.val.type.template_argument(0)
if refcounts != 0:
usecount = refcounts['_M_use_count']
weakcount = refcounts['_M_weak_count']
@ -238,7 +250,7 @@ class SharedPointerPrinter:
state = 'expired, weak count %d' % weakcount
else:
state = 'use count %d, weak count %d' % (usecount, weakcount - 1)
return '%s<%s> (%s)' % (self.typename, str(self.val.type.template_argument(0)), state)
return '%s<%s> (%s)' % (self.typename, str(targ), state)
def _tuple_impl_get(val):
"Return the tuple element stored in a _Tuple_impl<N, T> base class."
@ -1708,6 +1720,40 @@ class StdInitializerListPrinter:
def display_hint(self):
return 'array'
class StdAtomicPrinter:
"Print a std:atomic"
def __init__(self, typename, val):
self.typename = typename
self.val = val
self.shptr_printer = None
self.value_type = self.val.type.template_argument(0)
if self.value_type.tag is not None:
typ = strip_versioned_namespace(self.value_type.tag)
if typ.startswith('std::shared_ptr<') or typ.startswith('std::weak_ptr<'):
impl = val['_M_impl']
self.shptr_printer = SharedPointerPrinter(typename, impl)
self.children = self._shptr_children
def _shptr_children(self):
return SmartPtrIterator(self.shptr_printer.pointer)
def to_string(self):
if self.shptr_printer is not None:
return self.shptr_printer.to_string()
if self.value_type.code == gdb.TYPE_CODE_INT:
val = self.val['_M_i']
elif self.value_type.code == gdb.TYPE_CODE_FLT:
val = self.val['_M_fp']
elif self.value_type.code == gdb.TYPE_CODE_PTR:
val = self.val['_M_b']['_M_p']
elif self.value_type.code == gdb.TYPE_CODE_BOOL:
val = self.val['_M_base']['_M_i']
else:
val = self.val['_M_i']
return '%s<%s> = { %s }' % (self.typename, str(self.value_type), val)
# A "regular expression" printer which conforms to the
# "SubPrettyPrinter" protocol from gdb.printing.
class RxPrinter(object):
@ -2175,6 +2221,7 @@ def build_libstdcxx_dictionary ():
libstdcxx_printer.add_version('std::', 'initializer_list',
StdInitializerListPrinter)
libstdcxx_printer.add_version('std::', 'atomic', StdAtomicPrinter)
# std::regex components
libstdcxx_printer.add_version('std::__detail::', '_State',

View file

@ -26,6 +26,7 @@
#include <iostream>
#include <future>
#include <initializer_list>
#include <atomic>
#include "../util/testsuite_allocator.h" // NullablePointer
typedef std::tuple<int, int> ExTuple;
@ -197,6 +198,15 @@ main()
std::initializer_list<int> il = {3, 4};
// { dg-final { note-test il {std::initializer_list of length 2 = {3, 4}} } }
std::atomic<int> ai{100};
// { dg-final { note-test ai {std::atomic<int> = { 100 }} } }
long l{};
std::atomic<long*> ap{&l};
// { dg-final { regexp-test ap {std::atomic.long \*. = { 0x.* }} } }
struct Value { int i, j; };
std::atomic<Value> av{{8, 9}};
// { dg-final { note-test av {std::atomic<Value> = { {i = 8, j = 9} }} } }
placeholder(""); // Mark SPOT
use(efl);
use(fl);

View file

@ -21,6 +21,7 @@
#include <array>
#include <compare>
#include <iostream>
#include <memory>
#include <span>
struct X
@ -65,6 +66,14 @@ main()
static_assert(s2.extent == std::size_t(2));
// { dg-final { note-test s2 {std::span of length 2 = {3, 4}} } }
std::atomic<std::shared_ptr<int>> spe;
// { dg-final { note-test spe {std::atomic<std::shared_ptr<int>> (empty) = {get() = 0x0}} } }
std::atomic<std::shared_ptr<int>> sp1 = std::make_shared<int>(1);
std::atomic<std::shared_ptr<int>> sp2 = sp1.load();
std::atomic<std::weak_ptr<int>> wp{sp2.load()};
// { dg-final { regexp-test sp1 {std::atomic.std::shared_ptr.int.. \(use count 2, weak count 1\) = {get\(\) = 0x.*}} } }
// { dg-final { regexp-test wp {std::atomic.std::weak_ptr.int.. \(use count 2, weak count 1\) = {get\(\) = 0x.*}} } }
std::cout << "\n";
return 0; // Mark SPOT
}