Fix unique_ptr pretty printer for empty classes

The printer was confused when unique_ptr<T,D>::pointer is an empty
class, or the deleter is not empty. Instead of assuming the tuple has a
single _M_head_impl member manually inspect the tuple base classes to
get the first element.

	* python/libstdcxx/v6/printers.py (UniquePointerPrinter.__init__): Do
	not assume field called _M_head_impl is the first tuple element.
	* testsuite/libstdc++-prettyprinters/compat.cc: Make tuple
	implementation more accurate.
	* testsuite/libstdc++-prettyprinters/cxx11.cc: Check unique_ptr with
	empty pointer type and non-empty deleter.

From-SVN: r271159
This commit is contained in:
Jonathan Wakely 2019-05-14 12:17:18 +01:00 committed by Jonathan Wakely
parent 1b18663e0f
commit e25f488d60
4 changed files with 57 additions and 5 deletions

View File

@ -1,5 +1,12 @@
2019-05-14 Jonathan Wakely <jwakely@redhat.com>
* python/libstdcxx/v6/printers.py (UniquePointerPrinter.__init__): Do
not assume field called _M_head_impl is the first tuple element.
* testsuite/libstdc++-prettyprinters/compat.cc: Make tuple
implementation more accurate.
* testsuite/libstdc++-prettyprinters/cxx11.cc: Check unique_ptr with
empty pointer type and non-empty deleter.
LWG 2899 - Make is_move_constructible correct for unique_ptr
* include/bits/unique_ptr.h (__uniq_ptr_impl): Add move constructor,
move assignment operator.

View File

@ -185,11 +185,18 @@ class UniquePointerPrinter:
# Check for new implementations first:
if is_specialization_of(impl_type, '__uniq_ptr_data') \
or is_specialization_of(impl_type, '__uniq_ptr_impl'):
self.pointer = val['_M_t']['_M_t']['_M_head_impl']
tuple_member = val['_M_t']['_M_t']
elif is_specialization_of(impl_type, 'tuple'):
self.pointer = val['_M_t']['_M_head_impl']
tuple_member = val['_M_t']
else:
raise ValueError("Unsupported implementation for unique_ptr: %s" % impl_type)
tuple_impl_type = tuple_member.type.fields()[0].type # _Tuple_impl
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']
elif head_field.is_base_class:
self.pointer = tuple_member.cast(head_field.type)
def children (self):
return SmartPtrIterator(self.pointer)

View File

@ -22,12 +22,30 @@
namespace std
{
template<typename T, typename U>
struct tuple
template<typename T>
struct _Head_base : T
{ };
template<typename T>
struct _Head_base<T*>
{
T _M_head_impl;
T* _M_head_impl;
};
template<unsigned long, typename ...> struct _Tuple_impl;
template<typename T, typename U>
struct _Tuple_impl<0, T, U> : _Tuple_impl<1, U>, _Head_base<T>
{ };
template<typename U>
struct _Tuple_impl<1, U> : _Head_base<U>
{ };
template<typename T, typename U>
struct tuple : _Tuple_impl<0, T, U>
{ };
template<typename T> struct default_delete { };
template<typename T, typename D = default_delete<T>>

View File

@ -59,6 +59,21 @@ struct datum
std::unique_ptr<datum> global;
struct Deleter
{
// Deleter is not an empty class:
int deleter_member = -1;
// But pointer is an empty class:
struct pointer
{
pointer(const void* = nullptr) { }
explicit operator bool() const noexcept { return false; }
friend bool operator==(pointer, pointer) noexcept { return true; }
friend bool operator!=(pointer, pointer) noexcept { return false; }
};
void operator()(pointer) const noexcept { }
};
int
main()
{
@ -136,6 +151,11 @@ main()
std::unique_ptr<data>& rarrptr = arrptr;
// { dg-final { regexp-test rarrptr {std::unique_ptr.datum \[\]. = {get\(\) = 0x.*}} } }
std::unique_ptr<int, Deleter> empty_ptr;
// { dg-final { note-test empty_ptr {std::unique_ptr<int> = {get() = {<No data fields>}}} } }
std::unique_ptr<int, Deleter>& rempty_ptr = empty_ptr;
// { dg-final { note-test rempty_ptr {std::unique_ptr<int> = {get() = {<No data fields>}}} } }
ExTuple tpl(6,7);
// { dg-final { note-test tpl {std::tuple containing = {[1] = 6, [2] = 7}} } }
ExTuple &rtpl = tpl;