* testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc: Use operator-> to access raw pointer member. * testsuite/23_containers/vector/59829.cc: Likewise. * testsuite/23_containers/vector/bool/80893.cc: Likewise. * testsuite/libstdc++-prettyprinters/cxx11.cc: Use NullablePointer. * testsuite/util/testsuite_allocator.h (NullablePointer): New utility for tests. (PointerBase, PointerBase_void): Derive from NullablePointer and use its constructors and equality operators. Change converting constructors to use operator-> to access private member of the other pointer type. (PointerBase_void::operator->()): Add, for access to private member. (operator-(PointerBase, PointerBase)): Change to hidden friend. (operator==(PointerBase, PointerBase)): Remove. (operator!=(PointerBase, PointerBase)): Remove.
There are probably more places in the testsuite that could use NullablePointer as a minimally-conforming type that meets the Cpp17NullablePointer requirements, instead of defining a new type each time one is needed. Tested powerpc64le-linux, committed to trunk.
commit d238e99b1eea20ba5bb52df6d4544fb4062fb075 Author: Jonathan Wakely <jwak...@redhat.com> Date: Tue May 14 11:02:41 2019 +0100 Add __gnu_test::NullablePointer utility to testsuite * testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc: Use operator-> to access raw pointer member. * testsuite/23_containers/vector/59829.cc: Likewise. * testsuite/23_containers/vector/bool/80893.cc: Likewise. * testsuite/libstdc++-prettyprinters/cxx11.cc: Use NullablePointer. * testsuite/util/testsuite_allocator.h (NullablePointer): New utility for tests. (PointerBase, PointerBase_void): Derive from NullablePointer and use its constructors and equality operators. Change converting constructors to use operator-> to access private member of the other pointer type. (PointerBase_void::operator->()): Add, for access to private member. (operator-(PointerBase, PointerBase)): Change to hidden friend. (operator==(PointerBase, PointerBase)): Remove. (operator!=(PointerBase, PointerBase)): Remove. diff --git a/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc b/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc index a5e2a269a15..f9193e83e94 100644 --- a/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc +++ b/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc @@ -45,7 +45,7 @@ struct Alloc { return pointer(std::allocator<T>().allocate(n)); } void deallocate(pointer p, std::size_t n) - { std::allocator<T>().deallocate(p.value, n); } + { std::allocator<T>().deallocate(p.operator->(), n); } }; template<typename T> diff --git a/libstdc++-v3/testsuite/23_containers/vector/59829.cc b/libstdc++-v3/testsuite/23_containers/vector/59829.cc index 0e053fa6627..892b9055eb4 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/59829.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/59829.cc @@ -51,7 +51,7 @@ struct Alloc { return pointer(std::allocator<T>().allocate(n)); } void deallocate(pointer p, std::size_t n) - { std::allocator<T>().deallocate(p.value, n); } + { std::allocator<T>().deallocate(p.operator->(), n); } }; template<typename T> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/80893.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/80893.cc index f44cdc4a75e..08b15c8d2da 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/bool/80893.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/80893.cc @@ -59,7 +59,7 @@ struct Alloc void deallocate(pointer p, std::size_t n) { if (n) - std::allocator<T>().deallocate(p.value, n); + std::allocator<T>().deallocate(p.operator->(), n); } }; diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc index cc588125bdc..c87c8035c45 100644 --- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc +++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc @@ -24,6 +24,7 @@ #include <string> #include <memory> #include <iostream> +#include "../util/testsuite_allocator.h" // NullablePointer typedef std::tuple<int, int> ExTuple; @@ -59,21 +60,6 @@ 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() { @@ -151,6 +137,15 @@ main() std::unique_ptr<data>& rarrptr = arrptr; // { dg-final { regexp-test rarrptr {std::unique_ptr.datum \[\]. = {get\(\) = 0x.*}} } } + struct Deleter + { + int deleter_member = -1; + using pointer = __gnu_test::NullablePointer<void>; + void operator()(pointer) const noexcept { } + }; + static_assert( !std::is_empty<Deleter>(), "Deleter is not empty" ); + static_assert( std::is_empty<Deleter::pointer>(), "but pointer is empty" ); + 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; diff --git a/libstdc++-v3/testsuite/util/testsuite_allocator.h b/libstdc++-v3/testsuite/util/testsuite_allocator.h index 0392421ca04..428c0823395 100644 --- a/libstdc++-v3/testsuite/util/testsuite_allocator.h +++ b/libstdc++-v3/testsuite/util/testsuite_allocator.h @@ -589,9 +589,54 @@ namespace __gnu_test { std::allocator<Tp>::deallocate(std::addressof(*p), n); } }; + // A class type meeting *only* the Cpp17NullablePointer requirements. + // Can be used as a base class for fancy pointers (like PointerBase, below) + // or to wrap a built-in pointer type to remove operations not required + // by the Cpp17NullablePointer requirements (dereference, increment etc.) + template<typename Ptr> + struct NullablePointer + { + // N.B. default constructor does not initialize value + NullablePointer() = default; + NullablePointer(std::nullptr_t) noexcept : value() { } + + explicit operator bool() const noexcept { return value == nullptr; } + + friend inline bool + operator==(NullablePointer lhs, NullablePointer rhs) noexcept + { return lhs.value == rhs.value; } + + friend inline bool + operator!=(NullablePointer lhs, NullablePointer rhs) noexcept + { return lhs.value != rhs.value; } + + protected: + explicit NullablePointer(Ptr p) noexcept : value(p) { } + Ptr value; + }; + + // NullablePointer<void> is an empty type that models Cpp17NullablePointer. + template<> + struct NullablePointer<void> + { + NullablePointer() = default; + NullablePointer(std::nullptr_t) noexcept { } + explicit NullablePointer(const volatile void*) noexcept { } + + explicit operator bool() const noexcept { return false; } + + friend inline bool + operator==(NullablePointer, NullablePointer) noexcept + { return true; } + + friend inline bool + operator!=(NullablePointer, NullablePointer) noexcept + { return false; } + }; + // Utility for use as CRTP base class of custom pointer types template<typename Derived, typename T> - struct PointerBase + struct PointerBase : NullablePointer<T*> { typedef T element_type; @@ -602,29 +647,38 @@ namespace __gnu_test typedef Derived pointer; typedef T& reference; - T* value; + using NullablePointer<T*>::NullablePointer; - explicit PointerBase(T* p = nullptr) : value(p) { } - - PointerBase(std::nullptr_t) : value(nullptr) { } + // Public (but explicit) constructor from raw pointer: + explicit PointerBase(T* p) noexcept : NullablePointer<T*>(p) { } template<typename D, typename U, typename = decltype(static_cast<T*>(std::declval<U*>()))> - PointerBase(const PointerBase<D, U>& p) : value(p.value) { } + PointerBase(const PointerBase<D, U>& p) + : NullablePointer<T*>(p.operator->()) { } - T& operator*() const { return *value; } - T* operator->() const { return value; } - T& operator[](difference_type n) const { return value[n]; } + T& operator*() const { return *this->value; } + T* operator->() const { return this->value; } + T& operator[](difference_type n) const { return this->value[n]; } - Derived& operator++() { ++value; return derived(); } - Derived operator++(int) { Derived tmp(derived()); ++value; return tmp; } - Derived& operator--() { --value; return derived(); } - Derived operator--(int) { Derived tmp(derived()); --value; return tmp; } + Derived& operator++() { ++this->value; return derived(); } + Derived& operator--() { --this->value; return derived(); } - Derived& operator+=(difference_type n) { value += n; return derived(); } - Derived& operator-=(difference_type n) { value -= n; return derived(); } + Derived operator++(int) { return Derived(this->value++); } - explicit operator bool() const { return value != nullptr; } + Derived operator--(int) { return Derived(this->value--); } + + Derived& operator+=(difference_type n) + { + this->value += n; + return derived(); + } + + Derived& operator-=(difference_type n) + { + this->value -= n; + return derived(); + } Derived operator+(difference_type n) const @@ -641,6 +695,9 @@ namespace __gnu_test } private: + friend std::ptrdiff_t operator-(PointerBase l, PointerBase r) + { return l.value - r.value; } + Derived& derived() { return static_cast<Derived&>(*this); } @@ -648,21 +705,9 @@ namespace __gnu_test derived() const { return static_cast<const Derived&>(*this); } }; - template<typename D, typename T> - std::ptrdiff_t operator-(PointerBase<D, T> l, PointerBase<D, T> r) - { return l.value - r.value; } - - template<typename D, typename T> - bool operator==(PointerBase<D, T> l, PointerBase<D, T> r) - { return l.value == r.value; } - - template<typename D, typename T> - bool operator!=(PointerBase<D, T> l, PointerBase<D, T> r) - { return l.value != r.value; } - - // implementation for void specializations - template<typename T> - struct PointerBase_void + // implementation for pointer-to-void specializations + template<typename T> + struct PointerBase_void : NullablePointer<T*> { typedef T element_type; @@ -671,25 +716,24 @@ namespace __gnu_test typedef std::ptrdiff_t difference_type; typedef std::random_access_iterator_tag iterator_category; - T* value; + using NullablePointer<T*>::NullablePointer; - explicit PointerBase_void(T* p = nullptr) : value(p) { } + T* operator->() const { return this->value; } template<typename D, typename U, typename = decltype(static_cast<T*>(std::declval<U*>()))> - PointerBase_void(const PointerBase<D, U>& p) : value(p.value) { } - - explicit operator bool() const { return value != nullptr; } + PointerBase_void(const PointerBase<D, U>& p) + : NullablePointer<T*>(p.operator->()) { } }; - template<typename Derived> + template<typename Derived> struct PointerBase<Derived, void> : PointerBase_void<void> { using PointerBase_void::PointerBase_void; typedef Derived pointer; }; - template<typename Derived> + template<typename Derived> struct PointerBase<Derived, const void> : PointerBase_void<const void> { using PointerBase_void::PointerBase_void;