libstdc++: Add missing noexcept to std::scoped_allocator_adaptor
The standard requires these constructors and accessors to be noexcept. libstdc++-v3/ChangeLog: * include/std/scoped_allocator (scoped_allocator_adaptor): Add noexcept to all constructors except the default constructor. (scoped_allocator_adaptor::inner_allocator): Add noexcept. (scoped_allocator_adaptor::outer_allocator): Likewise. * testsuite/20_util/scoped_allocator/noexcept.cc: New test. (cherry picked from commit b960c253e988c68ed3f3829125bc267bdf169356)
This commit is contained in:
@@ -65,7 +65,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
struct __outermost_type
|
||||
{
|
||||
using type = _Alloc;
|
||||
static type& _S_outermost(_Alloc& __a) { return __a; }
|
||||
static type& _S_outermost(_Alloc& __a) noexcept { return __a; }
|
||||
};
|
||||
|
||||
template<typename _Alloc>
|
||||
@@ -79,7 +79,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
>;
|
||||
|
||||
static typename __base::type&
|
||||
_S_outermost(_Alloc& __a)
|
||||
_S_outermost(_Alloc& __a) noexcept
|
||||
{ return __base::_S_outermost(__a.outer_allocator()); }
|
||||
};
|
||||
|
||||
@@ -104,11 +104,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
__inner_type_impl& operator=(__inner_type_impl&&) = default;
|
||||
|
||||
template<typename _Alloc>
|
||||
__inner_type_impl(const __inner_type_impl<_Alloc>& __other)
|
||||
__inner_type_impl(const __inner_type_impl<_Alloc>& __other) noexcept
|
||||
{ }
|
||||
|
||||
template<typename _Alloc>
|
||||
__inner_type_impl(__inner_type_impl<_Alloc>&& __other)
|
||||
__inner_type_impl(__inner_type_impl<_Alloc>&& __other) noexcept
|
||||
{ }
|
||||
|
||||
__type&
|
||||
@@ -137,16 +137,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
__inner_type_impl& operator=(__inner_type_impl&&) = default;
|
||||
|
||||
template<typename... _Allocs>
|
||||
__inner_type_impl(const __inner_type_impl<_Allocs...>& __other)
|
||||
__inner_type_impl(const __inner_type_impl<_Allocs...>& __other) noexcept
|
||||
: _M_inner(__other._M_inner) { }
|
||||
|
||||
template<typename... _Allocs>
|
||||
__inner_type_impl(__inner_type_impl<_Allocs...>&& __other)
|
||||
__inner_type_impl(__inner_type_impl<_Allocs...>&& __other) noexcept
|
||||
: _M_inner(std::move(__other._M_inner)) { }
|
||||
|
||||
template<typename... _Args>
|
||||
explicit
|
||||
__inner_type_impl(_Args&&... __args)
|
||||
__inner_type_impl(_Args&&... __args) noexcept
|
||||
: _M_inner(std::forward<_Args>(__args)...) { }
|
||||
|
||||
__type&
|
||||
@@ -307,31 +307,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
template<typename _Outer2, typename = _Constructible<_Outer2>>
|
||||
scoped_allocator_adaptor(_Outer2&& __outer,
|
||||
const _InnerAllocs&... __inner)
|
||||
const _InnerAllocs&... __inner) noexcept
|
||||
: _OuterAlloc(std::forward<_Outer2>(__outer)),
|
||||
_M_inner(__inner...)
|
||||
{ }
|
||||
|
||||
scoped_allocator_adaptor(const scoped_allocator_adaptor& __other)
|
||||
scoped_allocator_adaptor(const scoped_allocator_adaptor& __other) noexcept
|
||||
: _OuterAlloc(__other.outer_allocator()),
|
||||
_M_inner(__other._M_inner)
|
||||
{ }
|
||||
|
||||
scoped_allocator_adaptor(scoped_allocator_adaptor&& __other)
|
||||
scoped_allocator_adaptor(scoped_allocator_adaptor&& __other) noexcept
|
||||
: _OuterAlloc(std::move(__other.outer_allocator())),
|
||||
_M_inner(std::move(__other._M_inner))
|
||||
{ }
|
||||
|
||||
template<typename _Outer2, typename = _Constructible<const _Outer2&>>
|
||||
scoped_allocator_adaptor(
|
||||
const scoped_allocator_adaptor<_Outer2, _InnerAllocs...>& __other)
|
||||
const scoped_allocator_adaptor<_Outer2, _InnerAllocs...>& __other
|
||||
) noexcept
|
||||
: _OuterAlloc(__other.outer_allocator()),
|
||||
_M_inner(__other._M_inner)
|
||||
{ }
|
||||
|
||||
template<typename _Outer2, typename = _Constructible<_Outer2>>
|
||||
scoped_allocator_adaptor(
|
||||
scoped_allocator_adaptor<_Outer2, _InnerAllocs...>&& __other)
|
||||
scoped_allocator_adaptor<_Outer2, _InnerAllocs...>&& __other) noexcept
|
||||
: _OuterAlloc(std::move(__other.outer_allocator())),
|
||||
_M_inner(std::move(__other._M_inner))
|
||||
{ }
|
||||
@@ -342,25 +343,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
scoped_allocator_adaptor&
|
||||
operator=(scoped_allocator_adaptor&&) = default;
|
||||
|
||||
inner_allocator_type& inner_allocator() noexcept
|
||||
inner_allocator_type&
|
||||
inner_allocator() noexcept
|
||||
{ return _M_inner._M_get(this); }
|
||||
|
||||
const inner_allocator_type& inner_allocator() const noexcept
|
||||
const inner_allocator_type&
|
||||
inner_allocator() const noexcept
|
||||
{ return _M_inner._M_get(this); }
|
||||
|
||||
outer_allocator_type& outer_allocator() noexcept
|
||||
outer_allocator_type&
|
||||
outer_allocator() noexcept
|
||||
{ return static_cast<_OuterAlloc&>(*this); }
|
||||
|
||||
const outer_allocator_type& outer_allocator() const noexcept
|
||||
const outer_allocator_type&
|
||||
outer_allocator() const noexcept
|
||||
{ return static_cast<const _OuterAlloc&>(*this); }
|
||||
|
||||
_GLIBCXX_NODISCARD pointer allocate(size_type __n)
|
||||
_GLIBCXX_NODISCARD pointer
|
||||
allocate(size_type __n)
|
||||
{ return __traits::allocate(outer_allocator(), __n); }
|
||||
|
||||
_GLIBCXX_NODISCARD pointer allocate(size_type __n, const_void_pointer __hint)
|
||||
_GLIBCXX_NODISCARD pointer
|
||||
allocate(size_type __n, const_void_pointer __hint)
|
||||
{ return __traits::allocate(outer_allocator(), __n, __hint); }
|
||||
|
||||
void deallocate(pointer __p, size_type __n)
|
||||
void deallocate(pointer __p, size_type __n) noexcept
|
||||
{ return __traits::deallocate(outer_allocator(), __p, __n); }
|
||||
|
||||
size_type max_size() const
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
#include <scoped_allocator>
|
||||
|
||||
template<typename T>
|
||||
struct Alloc
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
Alloc() noexcept(false) { }
|
||||
Alloc(const Alloc&) noexcept(false) { }
|
||||
template<typename U> Alloc(const Alloc<U>&) noexcept { }
|
||||
|
||||
T* allocate(std::size_t);
|
||||
void deallocate(T*, std::size_t);
|
||||
|
||||
bool operator==(const Alloc&) const noexcept(false) { return true; }
|
||||
bool operator!=(const Alloc&) const noexcept(false) { return false; }
|
||||
};
|
||||
|
||||
using A1 = std::allocator<int>;
|
||||
using A2 = std::allocator<long>;
|
||||
using Ax = Alloc<int>;
|
||||
using SA1 = std::scoped_allocator_adaptor<A1, Ax>;
|
||||
using SA2 = std::scoped_allocator_adaptor<A2, Ax>;
|
||||
static_assert( std::is_default_constructible<SA1>::value
|
||||
&& ! std::is_nothrow_default_constructible<SA1>::value,
|
||||
"default constructor is potentially-throwing" );
|
||||
static_assert( std::is_nothrow_constructible<SA1, A1, Ax>::value,
|
||||
"multi-arg constructor is non-throwing" );
|
||||
static_assert( std::is_nothrow_copy_constructible<SA1>::value,
|
||||
"copy constructor is non-throwing" );
|
||||
static_assert( std::is_nothrow_move_constructible<SA1>::value,
|
||||
"move constructor is non-throwing" );
|
||||
static_assert( std::is_nothrow_constructible<SA1, const SA2&>::value,
|
||||
"converting copy constructor is non-throwing" );
|
||||
static_assert( std::is_nothrow_constructible<SA1, SA2>::value,
|
||||
"converting move constructor is non-throwing" );
|
||||
|
||||
static_assert( noexcept(std::declval<SA1&>().inner_allocator()),
|
||||
"inner_allocator() is non-throwing" );
|
||||
static_assert( noexcept(std::declval<const SA1&>().inner_allocator()),
|
||||
"inner_allocator() const is non-throwing" );
|
||||
static_assert( noexcept(std::declval<SA1&>().outer_allocator()),
|
||||
"outer_allocator() is non-throwing" );
|
||||
static_assert( noexcept(std::declval<const SA1&>().outer_allocator()),
|
||||
"outer_allocator() const is non-throwing" );
|
||||
Reference in New Issue
Block a user