2019-10-23 Jonathan Wakely <jwakely@redhat.com>
+ PR c++/91369 Implement P0784R7 changes to allocation and construction
+ * include/bits/alloc_traits.h: Include <bits/stl_construct.h>.
+ (allocator_traits::_S_allocate, allocator_traits::_S_construct)
+ (allocator_traits::_S_destroy, allocator_traits::_S_max_size)
+ (allocator_traits::_S_select, allocator_traits::allocate)
+ (allocator_traits::deallocate, allocator_traits::construct)
+ (allocator_traits::destroy, allocator_traits::max_size)
+ (allocator_traits::select_on_container_copy_construction)
+ (allocator_traits<allocator<T>>): Add constexpr specifier for C++20.
+ (allocator_traits<allocator<T>>::construct): Use construct_at.
+ (allocator_traits<allocator<T>>::destroy): Use destroy_at.
+ (__alloc_on_copy, __alloc_on_move, __alloc_on_swap): Add constexpr
+ specifier.
+ (_Destroy(ForwardIterator, ForwardIterator, Alloc&))
+ (_Destroy(ForwardIterator, ForwardIterator, allocator<T>&)): Move here
+ from <bits/stl_construct.h>.
+ * include/bits/allocator.h (allocator::~allocator): Remove for C++20.
+ (allocator::allocate, allocate::deallocate): Define for C++20 and up.
+ (operator==, operator!=): Add constexpr specifier for C++20.
+ * include/bits/stl_construct.h: Don't include <ext/alloc_traits.h>.
+ (destroy_at): For C++20 add constexpr specifier and support for
+ destroying arrays.
+ (construct_at): Define new function for C++20.
+ (_Construct): Return result of placement new-expression. For C++11 and
+ up add constexpr. For C++20 dispatch to std::construct_at during
+ constant evaluation.
+ (_Destroy(pointer)): Add constexpr specifier. For C++20 dispatch to
+ std::destroy_at during constant evaluation.
+ (_Destroy_aux::__destroy, _Destroy_n_aux::__destroy_n): Add constexpr
+ specifier for C++20.
+ (_Destroy(ForwardIterator, ForwardIterator))
+ (_Destroy(ForwardIterator, Size)): Likewise. Do not elide trivial
+ destructors during constant evaluation.
+ (destroy, destroy_n): Add constexpr specifier for C++20.
+ (_Destroy(ForwardIterator, ForwardIterator, Alloc&))
+ (_Destroy(ForwardIterator, ForwardIterator, allocator<T>&)): Move to
+ <bits/alloc_traits.h>, to remove dependency on allocators.
+ * include/bits/stl_uninitialized.h: Include <ext/alloc_traits.h>.
+ Include <bits/stl_pair.h> instead of <utility>.
+ * include/ext/alloc_traits.h: Always include <bits/alloc_traits.h>.
+ (__alloc_traits::construct, __alloc_traits::destroy)
+ (__alloc_traits::_S_select_on_copy, __alloc_traits::_S_on_swap): Add
+ constexpr specifier.
+ * include/ext/malloc_allocator.h (operator==, operator!=): Add
+ constexpr specifier for C++20.
+ * include/ext/new_allocator.h (operator==, operator!=): Likewise.
+ * testsuite/20_util/headers/memory/synopsis.cc: Add constexpr.
+ * testsuite/20_util/scoped_allocator/69293_neg.cc: Ignore additional
+ errors due to constexpr function called after failed static_assert.
+ * testsuite/20_util/specialized_algorithms/construct_at/1.cc: New test.
+ * testsuite/23_containers/vector/cons/destructible_debug_neg.cc:
+ Ignore additional errors due to constexpr function called after failed
+ static_assert.
+ * testsuite/23_containers/vector/cons/destructible_neg.cc: Likewise.
+
* testsuite/20_util/bind/91371.cc: Fix test to compile as C++11.
* include/debug/helper_functions.h (__valid_range): Change
#ifndef _ALLOC_TRAITS_H
#define _ALLOC_TRAITS_H 1
-#if __cplusplus >= 201103L
-
+#include <bits/stl_construct.h>
#include <bits/memoryfwd.h>
-#include <bits/ptr_traits.h>
-#include <ext/numeric_traits.h>
-
-#define __cpp_lib_allocator_traits_is_always_equal 201411
+#if __cplusplus >= 201103L
+# include <bits/allocator.h>
+# include <bits/ptr_traits.h>
+# include <ext/numeric_traits.h>
+#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
+#if __cplusplus >= 201103L
+#define __cpp_lib_allocator_traits_is_always_equal 201411
+
struct __allocator_traits_base
{
template<typename _Tp, typename _Up, typename = void>
private:
template<typename _Alloc2>
- static auto
+ static constexpr auto
_S_allocate(_Alloc2& __a, size_type __n, const_void_pointer __hint, int)
-> decltype(__a.allocate(__n, __hint))
{ return __a.allocate(__n, __hint); }
template<typename _Alloc2>
- static pointer
+ static constexpr pointer
_S_allocate(_Alloc2& __a, size_type __n, const_void_pointer, ...)
{ return __a.allocate(__n); }
= typename __construct_helper<_Tp, _Args...>::type;
template<typename _Tp, typename... _Args>
- static _Require<__has_construct<_Tp, _Args...>>
+ static constexpr _Require<__has_construct<_Tp, _Args...>>
_S_construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
noexcept(noexcept(__a.construct(__p, std::forward<_Args>(__args)...)))
{ __a.construct(__p, std::forward<_Args>(__args)...); }
template<typename _Tp, typename... _Args>
- static
+ static constexpr
_Require<__and_<__not_<__has_construct<_Tp, _Args...>>,
is_constructible<_Tp, _Args...>>>
_S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
noexcept(noexcept(::new((void*)__p)
_Tp(std::forward<_Args>(__args)...)))
- { ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); }
+ { std::_Construct(__p, std::forward<_Args>(__args)...); }
template<typename _Alloc2, typename _Tp>
- static auto
+ static constexpr auto
_S_destroy(_Alloc2& __a, _Tp* __p, int)
noexcept(noexcept(__a.destroy(__p)))
-> decltype(__a.destroy(__p))
{ __a.destroy(__p); }
template<typename _Alloc2, typename _Tp>
- static void
+ static constexpr void
_S_destroy(_Alloc2&, _Tp* __p, ...)
noexcept(noexcept(__p->~_Tp()))
- { __p->~_Tp(); }
+ { std::_Destroy(__p); }
template<typename _Alloc2>
- static auto
+ static constexpr auto
_S_max_size(_Alloc2& __a, int)
-> decltype(__a.max_size())
{ return __a.max_size(); }
template<typename _Alloc2>
- static size_type
+ static constexpr size_type
_S_max_size(_Alloc2&, ...)
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
}
template<typename _Alloc2>
- static auto
+ static constexpr auto
_S_select(_Alloc2& __a, int)
-> decltype(__a.select_on_container_copy_construction())
{ return __a.select_on_container_copy_construction(); }
template<typename _Alloc2>
- static _Alloc2
+ static constexpr _Alloc2
_S_select(_Alloc2& __a, ...)
{ return __a; }
*
* Calls @c a.allocate(n)
*/
- _GLIBCXX_NODISCARD static pointer
+ _GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
allocate(_Alloc& __a, size_type __n)
{ return __a.allocate(__n); }
* Returns <tt> a.allocate(n, hint) </tt> if that expression is
* well-formed, otherwise returns @c a.allocate(n)
*/
- _GLIBCXX_NODISCARD static pointer
+ _GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
allocate(_Alloc& __a, size_type __n, const_void_pointer __hint)
{ return _S_allocate(__a, __n, __hint, 0); }
*
* Calls <tt> a.deallocate(p, n) </tt>
*/
- static void
+ static _GLIBCXX20_CONSTEXPR void
deallocate(_Alloc& __a, pointer __p, size_type __n)
{ __a.deallocate(__p, __n); }
* arguments @a __args...
*/
template<typename _Tp, typename... _Args>
- static auto construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
+ static _GLIBCXX20_CONSTEXPR auto
+ construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
noexcept(noexcept(_S_construct(__a, __p,
std::forward<_Args>(__args)...)))
-> decltype(_S_construct(__a, __p, std::forward<_Args>(__args)...))
* otherwise calls @c __p->~_Tp()
*/
template<typename _Tp>
- static void destroy(_Alloc& __a, _Tp* __p)
+ static _GLIBCXX20_CONSTEXPR void
+ destroy(_Alloc& __a, _Tp* __p)
noexcept(noexcept(_S_destroy(__a, __p, 0)))
{ _S_destroy(__a, __p, 0); }
* Returns @c __a.max_size() if that expression is well-formed,
* otherwise returns @c numeric_limits<size_type>::max()
*/
- static size_type max_size(const _Alloc& __a) noexcept
+ static _GLIBCXX20_CONSTEXPR size_type
+ max_size(const _Alloc& __a) noexcept
{ return _S_max_size(__a, 0); }
/**
* Returns @c __rhs.select_on_container_copy_construction() if that
* expression is well-formed, otherwise returns @a __rhs
*/
- static _Alloc
+ static _GLIBCXX20_CONSTEXPR _Alloc
select_on_container_copy_construction(const _Alloc& __rhs)
{ return _S_select(__rhs, 0); }
};
*
* Calls @c a.allocate(n)
*/
- _GLIBCXX_NODISCARD static pointer
+ _GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
allocate(allocator_type& __a, size_type __n)
{ return __a.allocate(__n); }
*
* Returns <tt> a.allocate(n, hint) </tt>
*/
- _GLIBCXX_NODISCARD static pointer
+ _GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
allocate(allocator_type& __a, size_type __n, const_void_pointer __hint)
{
#if __cplusplus <= 201703L
*
* Calls <tt> a.deallocate(p, n) </tt>
*/
- static void
+ static _GLIBCXX20_CONSTEXPR void
deallocate(allocator_type& __a, pointer __p, size_type __n)
{ __a.deallocate(__p, __n); }
/**
- * @brief Construct an object of type @a _Up
+ * @brief Construct an object of type `_Up`
* @param __a An allocator.
- * @param __p Pointer to memory of suitable size and alignment for Tp
+ * @param __p Pointer to memory of suitable size and alignment for
+ * an object of type `_Up`.
* @param __args Constructor arguments.
*
- * Calls <tt> __a.construct(__p, std::forward<Args>(__args)...) </tt>
+ * Calls `__a.construct(__p, std::forward<_Args>(__args)...)`
+ * in C++11, C++14 and C++17. Changed in C++20 to call
+ * `std::construct_at(__p, std::forward<_Args>(__args)...)` instead.
*/
template<typename _Up, typename... _Args>
- static void
+ static _GLIBCXX20_CONSTEXPR void
construct(allocator_type& __a, _Up* __p, _Args&&... __args)
noexcept(noexcept(::new((void*)__p) _Up(std::forward<_Args>(__args)...)))
{
#if __cplusplus <= 201703L
__a.construct(__p, std::forward<_Args>(__args)...);
#else
- ::new((void*)__p) _Up(std::forward<_Args>(__args)...);
+ std::construct_at(__p, std::forward<_Args>(__args)...);
#endif
}
* Calls @c __a.destroy(__p).
*/
template<typename _Up>
- static void
+ static _GLIBCXX20_CONSTEXPR void
destroy(allocator_type& __a, _Up* __p)
noexcept(is_nothrow_destructible<_Up>::value)
{
#if __cplusplus <= 201703L
__a.destroy(__p);
#else
- __p->~_Up();
+ std::destroy_at(__p);
#endif
}
* @param __a An allocator.
* @return @c __a.max_size()
*/
- static size_type
+ static _GLIBCXX20_CONSTEXPR size_type
max_size(const allocator_type& __a) noexcept
{
#if __cplusplus <= 201703L
* @param __rhs An allocator.
* @return @c __rhs
*/
- static allocator_type
+ static _GLIBCXX20_CONSTEXPR allocator_type
select_on_container_copy_construction(const allocator_type& __rhs)
{ return __rhs; }
};
#endif
template<typename _Alloc>
- inline void __alloc_on_copy(_Alloc& __one, const _Alloc& __two)
+ constexpr void
+ __alloc_on_copy(_Alloc& __one, const _Alloc& __two)
{
typedef allocator_traits<_Alloc> __traits;
typedef typename __traits::propagate_on_container_copy_assignment __pocca;
}
template<typename _Alloc>
- inline _Alloc __alloc_on_copy(const _Alloc& __a)
+ constexpr _Alloc
+ __alloc_on_copy(const _Alloc& __a)
{
typedef allocator_traits<_Alloc> __traits;
return __traits::select_on_container_copy_construction(__a);
#endif
template<typename _Alloc>
- inline void __alloc_on_move(_Alloc& __one, _Alloc& __two)
+ constexpr void
+ __alloc_on_move(_Alloc& __one, _Alloc& __two)
{
typedef allocator_traits<_Alloc> __traits;
typedef typename __traits::propagate_on_container_move_assignment __pocma;
#endif
template<typename _Alloc>
- inline void __alloc_on_swap(_Alloc& __one, _Alloc& __two)
+ constexpr void
+ __alloc_on_swap(_Alloc& __one, _Alloc& __two)
{
typedef allocator_traits<_Alloc> __traits;
typedef typename __traits::propagate_on_container_swap __pocs;
template<typename _Alloc>
using _RequireNotAllocator
= typename enable_if<!__is_allocator<_Alloc>::value, _Alloc>::type;
+#endif // C++11
+
+ /**
+ * Destroy a range of objects using the supplied allocator. For
+ * non-default allocators we do not optimize away invocation of
+ * destroy() even if _Tp has a trivial destructor.
+ */
+
+ template<typename _ForwardIterator, typename _Allocator>
+ void
+ _Destroy(_ForwardIterator __first, _ForwardIterator __last,
+ _Allocator& __alloc)
+ {
+ for (; __first != __last; ++__first)
+#if __cplusplus < 201103L
+ __alloc.destroy(std::__addressof(*__first));
+#else
+ allocator_traits<_Allocator>::destroy(__alloc,
+ std::__addressof(*__first));
+#endif
+ }
+
+ template<typename _ForwardIterator, typename _Tp>
+ inline void
+ _Destroy(_ForwardIterator __first, _ForwardIterator __last,
+ allocator<_Tp>&)
+ {
+ _Destroy(__first, __last);
+ }
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
-#endif // C++11
#endif // _ALLOC_TRAITS_H
_GLIBCXX20_CONSTEXPR
allocator(const allocator<_Tp1>&) _GLIBCXX_NOTHROW { }
+#if __cplusplus <= 201703L
~allocator() _GLIBCXX_NOTHROW { }
+#endif
+
+#if __cplusplus > 201703L
+ [[nodiscard,__gnu__::__always_inline__]]
+ constexpr _Tp*
+ allocate(size_t __n)
+ {
+#ifdef __cpp_lib_is_constant_evaluated
+ if (std::is_constant_evaluated())
+ return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
+#endif
+ return __allocator_base<_Tp>::allocate(__n, 0);
+ }
+
+ [[__gnu__::__always_inline__]]
+ constexpr void
+ deallocate(_Tp* __p, size_t __n)
+ {
+#ifdef __cpp_lib_is_constant_evaluated
+ if (std::is_constant_evaluated())
+ {
+ ::operator delete(__p);
+ return;
+ }
+#endif
+ __allocator_base<_Tp>::deallocate(__p, __n);
+ }
+#endif // C++20
- friend bool
+ friend _GLIBCXX20_CONSTEXPR bool
operator==(const allocator&, const allocator&) _GLIBCXX_NOTHROW
{ return true; }
- friend bool
+ friend _GLIBCXX20_CONSTEXPR bool
operator!=(const allocator&, const allocator&) _GLIBCXX_NOTHROW
{ return false; }
};
template<typename _T1, typename _T2>
- inline bool
+ inline _GLIBCXX20_CONSTEXPR bool
operator==(const allocator<_T1>&, const allocator<_T2>&)
_GLIBCXX_NOTHROW
{ return true; }
template<typename _T1, typename _T2>
- inline bool
+ inline _GLIBCXX20_CONSTEXPR bool
operator!=(const allocator<_T1>&, const allocator<_T2>&)
_GLIBCXX_NOTHROW
{ return false; }
#include <new>
#include <bits/move.h>
-#include <ext/alloc_traits.h>
+#include <bits/stl_iterator_base_types.h> // for iterator_traits
+#include <bits/stl_iterator_base_funcs.h> // for advance
+
+/* This file provides the C++17 functions std::destroy_at, std::destroy, and
+ * std::destroy_n, and the C++20 function std::construct_at.
+ * It also provides std::_Construct, std::_Destroy,and std::_Destroy_n functions
+ * which are defined in all standard modes and so can be used in C++98-14 code.
+ * The _Construct and _Destroy functions will dispatch to construct_at and
+ * destroy_at during constant evaluation, because calls to those functions are
+ * intercepted by the compiler to allow use in constant expressions.
+ */
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
+#if __cplusplus >= 201703L
+ template <typename _Tp>
+ _GLIBCXX20_CONSTEXPR inline void
+ destroy_at(_Tp* __location)
+ {
+ if constexpr (__cplusplus > 201703L && is_array_v<_Tp>)
+ {
+ for (auto& __x : *__location)
+ std::destroy_at(std::__addressof(__x));
+ }
+ else
+ __location->~_Tp();
+ }
+
+#if __cplusplus > 201703L
+ template<typename _Tp, typename... _Args>
+ constexpr auto
+ construct_at(_Tp* __location, _Args&&... __args)
+ noexcept(noexcept(::new((void*)0) _Tp(std::declval<_Args>()...)))
+ -> decltype(::new((void*)0) _Tp(std::declval<_Args>()...))
+ { return ::new((void*)__location) _Tp(std::forward<_Args>(__args)...); }
+#endif // C++20
+#endif// C++17
+
/**
* Constructs an object in existing memory by invoking an allocated
* object's constructor with an initializer.
*/
#if __cplusplus >= 201103L
- template<typename _T1, typename... _Args>
- inline void
- _Construct(_T1* __p, _Args&&... __args)
- { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
+ template<typename _Tp, typename... _Args>
+ constexpr _Tp*
+ _Construct(_Tp* __p, _Args&&... __args)
+ {
+#if __cplusplus > 201703L
+ return std::construct_at(__p, std::forward<_Args>(__args)...);
+#else
+ return ::new(static_cast<void*>(__p)) _Tp(std::forward<_Args>(__args)...);
+#endif
+ }
#else
template<typename _T1, typename _T2>
- inline void
+ inline _T1*
_Construct(_T1* __p, const _T2& __value)
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 402. wrong new expression in [some_]allocator::construct
- ::new(static_cast<void*>(__p)) _T1(__value);
+ return ::new(static_cast<void*>(__p)) _T1(__value);
}
#endif
_Construct_novalue(_T1* __p)
{ ::new(static_cast<void*>(__p)) _T1; }
+ template<typename _ForwardIterator>
+ _GLIBCXX20_CONSTEXPR void
+ _Destroy(_ForwardIterator __first, _ForwardIterator __last);
+
/**
* Destroy the object pointed to by a pointer type.
*/
template<typename _Tp>
- inline void
+ _GLIBCXX_CONSTEXPR inline void
_Destroy(_Tp* __pointer)
- { __pointer->~_Tp(); }
+ {
+#if __cplusplus > 201703L
+ std::destroy_at(__pointer);
+#else
+ __pointer->~_Tp();
+#endif
+ }
template<bool>
struct _Destroy_aux
{
template<typename _ForwardIterator>
- static void
- __destroy(_ForwardIterator __first, _ForwardIterator __last)
+ static _GLIBCXX20_CONSTEXPR void
+ __destroy(_ForwardIterator __first, _ForwardIterator __last)
{
for (; __first != __last; ++__first)
std::_Destroy(std::__addressof(*__first));
* away, otherwise the objects' destructors must be invoked.
*/
template<typename _ForwardIterator>
- inline void
+ _GLIBCXX20_CONSTEXPR inline void
_Destroy(_ForwardIterator __first, _ForwardIterator __last)
{
typedef typename iterator_traits<_ForwardIterator>::value_type
// A deleted destructor is trivial, this ensures we reject such types:
static_assert(is_destructible<_Value_type>::value,
"value type is destructible");
+#endif
+#if __cplusplus > 201703L && defined __cpp_lib_is_constant_evaluated
+ if (std::is_constant_evaluated())
+ return _Destroy_aux<false>::__destroy(__first, __last);
#endif
std::_Destroy_aux<__has_trivial_destructor(_Value_type)>::
__destroy(__first, __last);
struct _Destroy_n_aux
{
template<typename _ForwardIterator, typename _Size>
- static _ForwardIterator
- __destroy_n(_ForwardIterator __first, _Size __count)
+ static _GLIBCXX20_CONSTEXPR _ForwardIterator
+ __destroy_n(_ForwardIterator __first, _Size __count)
{
for (; __count > 0; (void)++__first, --__count)
std::_Destroy(std::__addressof(*__first));
* away, otherwise the objects' destructors must be invoked.
*/
template<typename _ForwardIterator, typename _Size>
- inline _ForwardIterator
+ _GLIBCXX20_CONSTEXPR inline _ForwardIterator
_Destroy_n(_ForwardIterator __first, _Size __count)
{
typedef typename iterator_traits<_ForwardIterator>::value_type
// A deleted destructor is trivial, this ensures we reject such types:
static_assert(is_destructible<_Value_type>::value,
"value type is destructible");
+#endif
+#if __cplusplus > 201703L && defined __cpp_lib_is_constant_evaluated
+ if (std::is_constant_evaluated())
+ return _Destroy_n_aux<false>::__destroy_n(__first, __count);
#endif
return std::_Destroy_n_aux<__has_trivial_destructor(_Value_type)>::
__destroy_n(__first, __count);
}
- /**
- * Destroy a range of objects using the supplied allocator. For
- * nondefault allocators we do not optimize away invocation of
- * destroy() even if _Tp has a trivial destructor.
- */
-
- template<typename _ForwardIterator, typename _Allocator>
- void
- _Destroy(_ForwardIterator __first, _ForwardIterator __last,
- _Allocator& __alloc)
- {
- typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
- for (; __first != __last; ++__first)
- __traits::destroy(__alloc, std::__addressof(*__first));
- }
-
- template<typename _ForwardIterator, typename _Tp>
- inline void
- _Destroy(_ForwardIterator __first, _ForwardIterator __last,
- allocator<_Tp>&)
- {
- _Destroy(__first, __last);
- }
-
-#if __cplusplus > 201402L
- template <typename _Tp>
- inline void
- destroy_at(_Tp* __location)
- {
- std::_Destroy(__location);
- }
-
+#if __cplusplus >= 201703L
template <typename _ForwardIterator>
- inline void
+ _GLIBCXX20_CONSTEXPR inline void
destroy(_ForwardIterator __first, _ForwardIterator __last)
{
std::_Destroy(__first, __last);
}
template <typename _ForwardIterator, typename _Size>
- inline _ForwardIterator
+ _GLIBCXX20_CONSTEXPR inline _ForwardIterator
destroy_n(_ForwardIterator __first, _Size __count)
{
return std::_Destroy_n(__first, __count);
}
-#endif
+#endif // C++17
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif /* _STL_CONSTRUCT_H */
-
#define _STL_UNINITIALIZED_H 1
#if __cplusplus > 201402L
-#include <utility>
+#include <bits/stl_pair.h>
#endif
#if __cplusplus >= 201103L
#include <type_traits>
#endif
+#include <ext/alloc_traits.h>
+
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
#pragma GCC system_header
-#if __cplusplus >= 201103L
-# include <bits/move.h>
# include <bits/alloc_traits.h>
-#else
+#if __cplusplus < 201103L
# include <bits/allocator.h> // for __alloc_swap
#endif
public:
// overload construct for non-standard pointer types
template<typename _Ptr, typename... _Args>
- static typename std::enable_if<__is_custom_pointer<_Ptr>::value>::type
+ static constexpr std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
construct(_Alloc& __a, _Ptr __p, _Args&&... __args)
noexcept(noexcept(_Base_type::construct(__a, std::__to_address(__p),
std::forward<_Args>(__args)...)))
// overload destroy for non-standard pointer types
template<typename _Ptr>
- static typename std::enable_if<__is_custom_pointer<_Ptr>::value>::type
+ static constexpr std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
destroy(_Alloc& __a, _Ptr __p)
noexcept(noexcept(_Base_type::destroy(__a, std::__to_address(__p))))
{ _Base_type::destroy(__a, std::__to_address(__p)); }
- static _Alloc _S_select_on_copy(const _Alloc& __a)
+ static constexpr _Alloc _S_select_on_copy(const _Alloc& __a)
{ return _Base_type::select_on_container_copy_construction(__a); }
- static void _S_on_swap(_Alloc& __a, _Alloc& __b)
+ static constexpr void _S_on_swap(_Alloc& __a, _Alloc& __b)
{ std::__alloc_on_swap(__a, __b); }
static constexpr bool _S_propagate_on_copy_assign()
template<typename _Tp>
struct rebind
{ typedef typename _Base_type::template rebind_alloc<_Tp> other; };
-#else
+#else // ! C++11
typedef typename _Alloc::pointer pointer;
typedef typename _Alloc::const_pointer const_pointer;
template<typename _Tp>
struct rebind
{ typedef typename _Alloc::template rebind<_Tp>::other other; };
-#endif
+#endif // C++11
};
_GLIBCXX_END_NAMESPACE_VERSION
#endif // ! C++20
template<typename _Up>
- friend bool
+ friend _GLIBCXX20_CONSTEXPR bool
operator==(const malloc_allocator&, const malloc_allocator<_Up>&)
_GLIBCXX_NOTHROW
{ return true; }
template<typename _Up>
- friend bool
+ friend _GLIBCXX20_CONSTEXPR bool
operator!=(const malloc_allocator&, const malloc_allocator<_Up>&)
_GLIBCXX_NOTHROW
{ return false; }
#endif // ! C++20
template<typename _Up>
- friend bool
+ friend _GLIBCXX20_CONSTEXPR bool
operator==(const new_allocator&, const new_allocator<_Up>&)
_GLIBCXX_NOTHROW
{ return true; }
template<typename _Up>
- friend bool
+ friend _GLIBCXX20_CONSTEXPR bool
operator!=(const new_allocator&, const new_allocator<_Up>&)
_GLIBCXX_NOTHROW
{ return false; }
template <class T> class allocator;
template <> class allocator<void>;
template <class T, class U>
+#if __cplusplus > 201703L
+ constexpr
+#endif
bool operator==(const allocator<T>&, const allocator<U>&) throw();
template <class T, class U>
+#if __cplusplus > 201703L
+ constexpr
+#endif
bool operator!=(const allocator<T>&, const allocator<U>&) throw();
// lib.storage.iterator, raw storage iterator:
sa.construct(p); // this is required to be ill-formed
// { dg-error "failed: .* uses_allocator is true" "" { target *-*-* } 0 }
}
+
+// Needed because of PR c++/92193
+// { dg-prune-output "no matching function for call to" }
--- /dev/null
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+template<typename T, typename... Args>
+ concept can_construct_at = requires(T* p, Args&&... args)
+ {
+ p = std::construct_at(p, std::forward<Args>(args)...);
+ };
+
+static_assert( can_construct_at<int> );
+static_assert( can_construct_at<int, int> );
+static_assert( !can_construct_at<int, int, int> );
+
+// Not required by C++20:
+static_assert( noexcept(std::construct_at(std::declval<int*>(), 1)) );
+
+void
+test01()
+{
+ int i = -1;
+ auto p = std::construct_at(&i);
+ VERIFY( p == &i );
+ VERIFY( i == 0 );
+ p = std::construct_at(&i, 42);
+ VERIFY( p == &i );
+ VERIFY( i == 42 );
+}
+
+struct X {
+ X(char&, void*) { }
+};
+
+static_assert( can_construct_at<X, char&, void*> );
+static_assert( !can_construct_at<X> );
+static_assert( !can_construct_at<X, char> );
+static_assert( !can_construct_at<X, char&, const void*> );
+
+static_assert( !noexcept(std::construct_at(std::declval<X*>(), std::declval<char&>(), std::declval<void*>())) );
+
+int
+main()
+{
+ test01();
+}
// In Debug Mode the "required from here" errors come from <debug/vector>
// { dg-error "required from here" "" { target *-*-* } 163 }
+
+// Needed because of PR c++/92193
+// { dg-prune-output "deleted function" }
+// { dg-prune-output "private within this context" }
}
// { dg-error "value type is destructible" "" { target *-*-* } 0 }
+
+// Needed because of PR c++/92193
+// { dg-prune-output "deleted function" }
+// { dg-prune-output "private within this context" }