mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
libstdc++: Fix allocator propagation and tests for std::indirect and std::polymorphic
I noticed that several tests were doing:
static_assert([] { /* ... */; return true; });
i.e. just testing a lambda, not invoking it and testing the result. This
change fixes that, so that all the lambdas are invoked.
After fixing that, most of the tests failed because they were using
__gnu_test::tracker_allocator or std::scoped_allocator_adaptor in
constexpr functions. The tracker_allocator modifies global state, so can
never be constexpr, and none of std::scoped_allocator_adaptor's members
are marked constexpr.
This change makes __gnu_test::uneq_allocator and
__gnu_test::propagating_allocator usable in constant expressions, which
allows some of the tests which can't be constexpr to be duplicated to
new functions which use uneq_allocator or propagating_allocator instead
of tracker_allocator. This new functions can be tested with the
static_assert calling a lambda.
In some cases none of the tests could be adapted to be constexpr, so the
static_assert and lambda were just removed.
Two changes were also needed for the actual library code, because the
move assignment operators for std::indirect and std::polymorphic were
using copy-assignment on the allocator. Although the semantics of
move-assignment for allocators should be equivalent to copy-assignment,
an allocator isn't actually required to support copy-assignment unless
propagate_on_container_copy_assignment is true. So we have to use
move-assignment for propagate_on_container_move_assignment cases.
libstdc++-v3/ChangeLog:
* include/bits/indirect.h (indirect::operator=(indirect&&)):
Move assign allocator when POCMA is true.
(polymorphic::operator=(polymorphic&&)): Likewise.
* testsuite/std/memory/indirect/copy.cc: Remove constexpr from
functions that use tracker_allocator. Add test_constexpr().
* testsuite/std/memory/indirect/copy_alloc.cc: Remove constexpr
from all functions and remove static_assert.
* testsuite/std/memory/indirect/ctor.cc: Do not use
scoped_allocator_adaptor during constant evaluation.
* testsuite/std/memory/indirect/move.cc: Remove constexpr from
functions that use tracker_allocator. Add test_constexpr().
* testsuite/std/memory/indirect/move_alloc.cc: Remove constexpr
from all functions and remove static_assert.
* testsuite/std/memory/indirect/relops.cc: Invoke lambda in
static_assert.
* testsuite/std/memory/polymorphic/copy.cc: Remove constexpr
from functions that use tracker_allocator. Add test_constexpr().
* testsuite/std/memory/polymorphic/copy_alloc.cc: Remove
constexpr from all functions and remove static_assert.
* testsuite/std/memory/polymorphic/ctor.cc: Do not use
scoped_allocator_adaptor during constant evaluation.
* testsuite/std/memory/polymorphic/ctor_poly.cc: Likewise.
* testsuite/std/memory/polymorphic/move.cc: Remove constexpr
from functions that use tracker_allocator. Add test_constexpr().
* testsuite/std/memory/polymorphic/move_alloc.cc: Remove
constexpr from all functions and remove static_assert.
* testsuite/util/testsuite_allocator.h (tracker_allocator):
Remove redundant 'inline' from friend.
(uneq_allocator): Make all functions constexpr.
(uneq_allocator::base, uneq_allocator::swap_base): Remove.
(uneq_allocator::~uneq_allocator): Remove.
(uneq_allocator::allocate, uneq_allocator::deallocate): Do not
use map of allocations during constant evaluation.
(propagating_allocator): Make all functions constexpr.
(propagating_allocator::base): Remove.
(propagating_allocator::swap_base): Simplify.
(ExplicitConsAlloc, CustomPointerAlloc, NullablePointer): Add
constexpr to all functions.
Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com>
This commit is contained in:
committed by
Jonathan Wakely
parent
0c0847158c
commit
152f4daab4
@@ -263,7 +263,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
_M_reset(__ptr);
|
||||
|
||||
if constexpr (__pocma)
|
||||
_M_alloc = __other._M_alloc;
|
||||
_M_alloc = std::move(__other._M_alloc);
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -736,7 +736,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
_M_reset(__ptr);
|
||||
|
||||
if constexpr (__pocma)
|
||||
_M_alloc = __other._M_alloc;
|
||||
_M_alloc = std::move(__other._M_alloc);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ using Vector = std::vector<int>;
|
||||
using Indirect = std::indirect<Vector, tracker_allocator<Vector>>;
|
||||
const Indirect src(std::in_place, {1, 2, 3});
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_ctor()
|
||||
{
|
||||
Counter::reset();
|
||||
@@ -36,7 +36,7 @@ test_ctor()
|
||||
VERIFY( Counter::get_destruct_count() == 0 );
|
||||
}
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_assign()
|
||||
{
|
||||
Indirect i1;
|
||||
@@ -62,7 +62,7 @@ test_assign()
|
||||
VERIFY( Counter::get_destruct_count() == 0 );
|
||||
}
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_valueless()
|
||||
{
|
||||
Indirect e;
|
||||
@@ -103,19 +103,54 @@ test_valueless()
|
||||
}
|
||||
|
||||
constexpr void
|
||||
test_all()
|
||||
test_constexpr()
|
||||
{
|
||||
test_ctor();
|
||||
test_assign();
|
||||
test_valueless();
|
||||
using Alloc = __gnu_test::uneq_allocator<Vector>;
|
||||
using Indirect = std::indirect<Vector, Alloc>;
|
||||
const Indirect src(std::in_place, {1, 2, 3});
|
||||
|
||||
Indirect i1(src);
|
||||
VERIFY( *i1 == *src );
|
||||
VERIFY( &*i1 != &*src );
|
||||
VERIFY( i1.get_allocator() == Alloc{} );
|
||||
|
||||
Indirect i2(std::allocator_arg, Alloc{2}, src);
|
||||
VERIFY( *i2 == *src );
|
||||
VERIFY( &*i2 != &*src );
|
||||
VERIFY( i2.get_allocator() == Alloc{2} );
|
||||
|
||||
Indirect i3(std::allocator_arg, Alloc{3});
|
||||
i3 = src;
|
||||
VERIFY( *i3 == *src );
|
||||
VERIFY( &*i3 != &*src );
|
||||
VERIFY( i3.get_allocator() == Alloc{3} );
|
||||
|
||||
Indirect e;
|
||||
auto(std::move(e));
|
||||
VERIFY( e.valueless_after_move() );
|
||||
|
||||
Indirect e1(e);
|
||||
VERIFY( e1.valueless_after_move() );
|
||||
|
||||
Indirect e2(std::allocator_arg, {}, e);
|
||||
VERIFY( e2.valueless_after_move() );
|
||||
|
||||
i3 = e;
|
||||
VERIFY( i3.valueless_after_move() );
|
||||
|
||||
i3 = e;
|
||||
VERIFY( i3.valueless_after_move() );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_all();
|
||||
test_ctor();
|
||||
test_assign();
|
||||
test_valueless();
|
||||
test_constexpr();
|
||||
|
||||
static_assert([] {
|
||||
test_all();
|
||||
test_constexpr();
|
||||
return true;
|
||||
});
|
||||
}());
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ using __gnu_test::tracker_allocator;
|
||||
using Counter = __gnu_test::tracker_allocator_counter;
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_ctor()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -59,7 +59,7 @@ test_ctor()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_assign()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -144,7 +144,7 @@ test_assign()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_valueless()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -219,10 +219,4 @@ int main()
|
||||
{
|
||||
test_all<true>();
|
||||
test_all<false>();
|
||||
|
||||
static_assert([] {
|
||||
test_all<true>();
|
||||
test_all<false>();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -58,6 +58,9 @@ test_default_ctor()
|
||||
std::indirect<Obj, default_init_allocator<Obj>> i2(std::allocator_arg, a);
|
||||
VERIFY( i2.get_allocator() == a );
|
||||
|
||||
if (std::is_constant_evaluated())
|
||||
return;
|
||||
|
||||
// Object is constructed using allocator-aware constructor.
|
||||
std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc>
|
||||
i3(std::allocator_arg, ScopedAlloc(11, 22));
|
||||
@@ -93,6 +96,9 @@ test_forwarding_ctor()
|
||||
std::indirect<Obj> i6(7);
|
||||
VERIFY( i6->i == 7 );
|
||||
|
||||
if (std::is_constant_evaluated())
|
||||
return;
|
||||
|
||||
std::vector<int, UneqAlloc> v{1, 2, 3, 4, 5};
|
||||
// Object is constructed using allocator-aware constructor.
|
||||
std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc>
|
||||
@@ -165,6 +171,9 @@ test_inplace_ctor()
|
||||
VERIFY( i10->at(2) == 3 );
|
||||
VERIFY( i10->get_allocator().get_personality() == 42 );
|
||||
|
||||
if (std::is_constant_evaluated())
|
||||
return;
|
||||
|
||||
std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc>
|
||||
i14(std::allocator_arg, ScopedAlloc(11, 22),
|
||||
std::in_place);
|
||||
@@ -200,5 +209,5 @@ int main()
|
||||
test_forwarding_ctor();
|
||||
test_inplace_ctor();
|
||||
return true;
|
||||
});
|
||||
}());
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ using Vector = std::vector<int>;
|
||||
using Indirect = std::indirect<Vector, tracker_allocator<Vector>>;
|
||||
const Indirect val(std::in_place, {1, 2, 3});
|
||||
|
||||
constexpr void
|
||||
void
|
||||
verifyNoAllocations()
|
||||
{
|
||||
VERIFY( Counter::get_allocation_count() == 0 );
|
||||
@@ -24,7 +24,7 @@ verifyNoAllocations()
|
||||
VERIFY( Counter::get_destruct_count() == 0 );
|
||||
}
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_ctor()
|
||||
{
|
||||
std::optional<Indirect> src;
|
||||
@@ -45,7 +45,7 @@ test_ctor()
|
||||
verifyNoAllocations();
|
||||
}
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_assign()
|
||||
{
|
||||
std::optional<Indirect> src;
|
||||
@@ -72,7 +72,7 @@ test_assign()
|
||||
verifyNoAllocations();
|
||||
}
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_swap()
|
||||
{
|
||||
const Indirect val1(std::in_place, {1, 2, 3});
|
||||
@@ -87,7 +87,7 @@ test_swap()
|
||||
verifyNoAllocations();
|
||||
|
||||
auto(std::move(i1));
|
||||
|
||||
|
||||
Counter::reset();
|
||||
i1.swap(i2);
|
||||
VERIFY( *i1 == *val1 );
|
||||
@@ -95,7 +95,7 @@ test_swap()
|
||||
verifyNoAllocations();
|
||||
}
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_valueless()
|
||||
{
|
||||
auto e = [] {
|
||||
@@ -125,20 +125,77 @@ test_valueless()
|
||||
}
|
||||
|
||||
constexpr void
|
||||
test_all()
|
||||
test_constexpr()
|
||||
{
|
||||
using Alloc = __gnu_test::uneq_allocator<Vector>;
|
||||
using Indirect = std::indirect<Vector, Alloc>;
|
||||
const Indirect val(std::in_place, {1, 2, 3});
|
||||
|
||||
std::optional<Indirect> src;
|
||||
auto make = [&src, &val] -> Indirect&& {
|
||||
src.emplace(val);
|
||||
return std::move(*src);
|
||||
};
|
||||
|
||||
Indirect i1(make());
|
||||
VERIFY( src->valueless_after_move() );
|
||||
VERIFY( *i1 == *val );
|
||||
|
||||
Indirect i2(std::allocator_arg, {}, make());
|
||||
VERIFY( src->valueless_after_move() );
|
||||
VERIFY( *i2 == *val );
|
||||
|
||||
i2 = make();
|
||||
VERIFY( src->valueless_after_move() );
|
||||
VERIFY( *i2 == *val );
|
||||
|
||||
auto(std::move(i2));
|
||||
i2 = make();
|
||||
VERIFY( *i2 == *val );
|
||||
VERIFY( src->valueless_after_move() );
|
||||
|
||||
const Indirect val1(std::in_place, {1, 2, 3});
|
||||
const Indirect val2(std::in_place, {2, 4, 6});
|
||||
|
||||
Indirect s1(val1);
|
||||
Indirect s2(val2);
|
||||
s1.swap(s2);
|
||||
VERIFY( *s2 == *val1 );
|
||||
VERIFY( *s1 == *val2 );
|
||||
|
||||
auto(std::move(s1));
|
||||
|
||||
s1.swap(s2);
|
||||
VERIFY( *s1 == *val1 );
|
||||
VERIFY( s2.valueless_after_move() );
|
||||
|
||||
auto e = [] {
|
||||
Indirect res;
|
||||
auto(std::move(res));
|
||||
return res;
|
||||
};
|
||||
|
||||
Indirect e1(e());
|
||||
VERIFY( e1.valueless_after_move() );
|
||||
|
||||
Indirect e2(std::allocator_arg, {}, e());
|
||||
VERIFY( e2.valueless_after_move() );
|
||||
|
||||
Indirect e3(val);
|
||||
e3 = e();
|
||||
e3 = e();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_ctor();
|
||||
test_assign();
|
||||
test_swap();
|
||||
test_valueless();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_all();
|
||||
test_constexpr();
|
||||
|
||||
static_assert([] {
|
||||
test_all();
|
||||
test_constexpr();
|
||||
return true;
|
||||
});
|
||||
}());
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ using __gnu_test::propagating_allocator;
|
||||
using __gnu_test::tracker_allocator;
|
||||
using Counter = __gnu_test::tracker_allocator_counter;
|
||||
|
||||
constexpr void
|
||||
void
|
||||
verifyNoAllocations()
|
||||
{
|
||||
VERIFY( Counter::get_allocation_count() == 0 );
|
||||
@@ -23,7 +23,7 @@ verifyNoAllocations()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_ctor()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -68,7 +68,7 @@ test_ctor()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_assign()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -159,7 +159,7 @@ test_assign()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_swap()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -212,7 +212,7 @@ test_swap()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_valueless()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -274,7 +274,7 @@ test_valueless()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_all()
|
||||
{
|
||||
test_ctor<Propagate>();
|
||||
@@ -287,10 +287,4 @@ int main()
|
||||
{
|
||||
test_all<true>();
|
||||
test_all<false>();
|
||||
|
||||
static_assert([] {
|
||||
test_all<true>();
|
||||
test_all<false>();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -78,5 +78,5 @@ int main()
|
||||
test_relops();
|
||||
test_comp_with_t();
|
||||
return true;
|
||||
});
|
||||
}());
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ using Counter = __gnu_test::tracker_allocator_counter;
|
||||
using Polymorphic = std::polymorphic<Base, tracker_allocator<Base>>;
|
||||
const Polymorphic src(std::in_place_type<Derived>, 1, 2, 3);
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_ctor()
|
||||
{
|
||||
Counter::reset();
|
||||
@@ -69,7 +69,7 @@ test_ctor()
|
||||
VERIFY( Counter::get_destruct_count() == 0 );
|
||||
}
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_assign()
|
||||
{
|
||||
Counter::reset();
|
||||
@@ -98,7 +98,7 @@ test_assign()
|
||||
VERIFY( Counter::get_destruct_count() == 0 );
|
||||
}
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_valueless()
|
||||
{
|
||||
Polymorphic e(std::in_place_type<Derived>);
|
||||
@@ -139,19 +139,54 @@ test_valueless()
|
||||
}
|
||||
|
||||
constexpr void
|
||||
test_all()
|
||||
test_constexpr()
|
||||
{
|
||||
test_ctor();
|
||||
test_assign();
|
||||
test_valueless();
|
||||
using Polymorphic = std::polymorphic<Base, __gnu_test::uneq_allocator<Base>>;
|
||||
const Polymorphic src(std::in_place_type<Derived>, 1, 2, 3);
|
||||
|
||||
Polymorphic i1(src);
|
||||
VERIFY( *i1 == *src );
|
||||
VERIFY( &*i1 != &*src );
|
||||
|
||||
Polymorphic i2(std::allocator_arg, {}, src);
|
||||
VERIFY( *i2 == *src );
|
||||
VERIFY( &*i2 != &*src );
|
||||
|
||||
i1 = Polymorphic(std::in_place_type<Derived>);
|
||||
VERIFY( *i1 != *src );
|
||||
i1 = src;
|
||||
VERIFY( *i1 == *src );
|
||||
VERIFY( &*i1 != &*src );
|
||||
|
||||
auto(std::move(i1));
|
||||
i1 = src;
|
||||
VERIFY( *i1 == *src );
|
||||
VERIFY( &*i1 != &*src );
|
||||
|
||||
Polymorphic e(std::in_place_type<Derived>);
|
||||
auto(std::move(e));
|
||||
VERIFY( e.valueless_after_move() );
|
||||
|
||||
Polymorphic e1(e);
|
||||
VERIFY( e1.valueless_after_move() );
|
||||
|
||||
Polymorphic e2(std::allocator_arg, {}, e);
|
||||
VERIFY( e2.valueless_after_move() );
|
||||
|
||||
Polymorphic e3(src);
|
||||
e3 = e;
|
||||
VERIFY( e3.valueless_after_move() );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_all();
|
||||
test_ctor();
|
||||
test_assign();
|
||||
test_valueless();
|
||||
test_constexpr();
|
||||
|
||||
static_assert([] {
|
||||
test_all();
|
||||
test_constexpr();
|
||||
return true;
|
||||
});
|
||||
}());
|
||||
}
|
||||
|
||||
@@ -9,16 +9,16 @@
|
||||
#include <testsuite_allocator.h>
|
||||
|
||||
struct Base {
|
||||
friend constexpr
|
||||
friend
|
||||
bool operator==(const Base& lhs, const Base& rhs)
|
||||
{ return lhs.eq(rhs); }
|
||||
|
||||
virtual constexpr int
|
||||
virtual int
|
||||
get_alloc_personality() const
|
||||
{ return -1; }
|
||||
|
||||
private:
|
||||
constexpr virtual bool
|
||||
virtual bool
|
||||
eq(const Base& other) const = 0;
|
||||
};
|
||||
|
||||
@@ -29,13 +29,13 @@ struct VecDerived : Base, std::vector<T, Allocator>
|
||||
|
||||
using VecBase::VecBase;
|
||||
|
||||
constexpr int
|
||||
int
|
||||
get_alloc_personality() const override
|
||||
{ return this->get_allocator().get_personality(); }
|
||||
|
||||
private:
|
||||
|
||||
constexpr bool
|
||||
bool
|
||||
eq(const Base& other) const override
|
||||
{
|
||||
if (auto op = dynamic_cast<const VecDerived*>(&other))
|
||||
@@ -50,7 +50,7 @@ using __gnu_test::tracker_allocator;
|
||||
using Counter = __gnu_test::tracker_allocator_counter;
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_ctor()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -96,7 +96,7 @@ test_ctor()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_assign()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -185,7 +185,7 @@ test_assign()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_valueless()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -249,7 +249,7 @@ test_valueless()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_all()
|
||||
{
|
||||
test_ctor<Propagate>();
|
||||
@@ -261,10 +261,4 @@ int main()
|
||||
{
|
||||
test_all<true>();
|
||||
test_all<false>();
|
||||
|
||||
static_assert([] {
|
||||
test_all<true>();
|
||||
test_all<false>();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -45,6 +45,9 @@ test_default_ctor()
|
||||
std::polymorphic<Obj, default_init_allocator<Obj>> i2(std::allocator_arg, a);
|
||||
VERIFY( i2.get_allocator() == a );
|
||||
|
||||
if (std::is_constant_evaluated())
|
||||
return;
|
||||
|
||||
// Object is constructed using allocator-aware constructor.
|
||||
std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
|
||||
i3(std::allocator_arg, ScopedAlloc(11, 22));
|
||||
@@ -76,6 +79,9 @@ test_forwarding_ctor()
|
||||
std::polymorphic<Obj> i5({1, {'2', '3'}});
|
||||
verify(i5);
|
||||
|
||||
if (std::is_constant_evaluated())
|
||||
return;
|
||||
|
||||
std::vector<int, UneqAlloc> v{1, 2, 3, 4, 5};
|
||||
// Object is constructed using allocator-aware constructor.
|
||||
std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
|
||||
@@ -151,6 +157,9 @@ test_inplace_ctor()
|
||||
VERIFY( i10->at(2) == 3 );
|
||||
VERIFY( i10->get_allocator().get_personality() == 42 );
|
||||
|
||||
if (std::is_constant_evaluated())
|
||||
return;
|
||||
|
||||
std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
|
||||
i14(std::allocator_arg, ScopedAlloc(11, 22),
|
||||
std::in_place_type<std::vector<int, UneqAlloc>>);
|
||||
@@ -186,5 +195,5 @@ int main()
|
||||
test_forwarding_ctor();
|
||||
test_inplace_ctor();
|
||||
return true;
|
||||
});
|
||||
}());
|
||||
}
|
||||
|
||||
@@ -126,6 +126,9 @@ test_forwarding_ctor()
|
||||
VERIFY( *i4 == src );
|
||||
VERIFY( i4->get_personality() == -2 );
|
||||
|
||||
if (std::is_constant_evaluated())
|
||||
return;
|
||||
|
||||
const VecDerived<int, UneqAlloc> v{1, 2, 3, 4, 5};
|
||||
// Object is constructed using allocator-aware constructor.
|
||||
std::polymorphic<Base, ScopedAlloc>
|
||||
@@ -183,6 +186,9 @@ test_inplace_ctor()
|
||||
VERIFY( *i7 == il );
|
||||
VERIFY( i7->get_personality() == 42 );
|
||||
|
||||
if (std::is_constant_evaluated())
|
||||
return;
|
||||
|
||||
std::polymorphic<Base, ScopedAlloc>
|
||||
i8(std::allocator_arg, ScopedAlloc(11, 22),
|
||||
std::in_place_type<VecDerived<int, UneqAlloc>>);
|
||||
@@ -216,5 +222,5 @@ int main()
|
||||
test_forwarding_ctor();
|
||||
test_inplace_ctor();
|
||||
return true;
|
||||
});
|
||||
}());
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ using Counter = __gnu_test::tracker_allocator_counter;
|
||||
using Polymorphic = std::polymorphic<Base, tracker_allocator<Base>>;
|
||||
const Polymorphic val(std::in_place_type<Derived>, 1, 2, 3);
|
||||
|
||||
constexpr void
|
||||
void
|
||||
verifyNoAllocations()
|
||||
{
|
||||
VERIFY( Counter::get_allocation_count() == 0 );
|
||||
@@ -57,7 +57,7 @@ verifyNoAllocations()
|
||||
VERIFY( Counter::get_destruct_count() == 0 );
|
||||
}
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_ctor()
|
||||
{
|
||||
std::optional<Polymorphic> src;
|
||||
@@ -78,7 +78,7 @@ test_ctor()
|
||||
verifyNoAllocations();
|
||||
}
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_assign()
|
||||
{
|
||||
std::optional<Polymorphic> src;
|
||||
@@ -105,7 +105,7 @@ test_assign()
|
||||
verifyNoAllocations();
|
||||
}
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_swap()
|
||||
{
|
||||
const Polymorphic val1(std::in_place_type<Derived>, 1, 2, 3);
|
||||
@@ -128,7 +128,7 @@ test_swap()
|
||||
verifyNoAllocations();
|
||||
}
|
||||
|
||||
constexpr void
|
||||
void
|
||||
test_valueless()
|
||||
{
|
||||
auto e = [] {
|
||||
@@ -158,20 +158,75 @@ test_valueless()
|
||||
}
|
||||
|
||||
constexpr void
|
||||
test_all()
|
||||
test_constexpr()
|
||||
{
|
||||
using Polymorphic = std::polymorphic<Base, __gnu_test::uneq_allocator<Base>>;
|
||||
const Polymorphic val(std::in_place_type<Derived>, 1, 2, 3);
|
||||
|
||||
std::optional<Polymorphic> src;
|
||||
auto make = [&src, &val] -> Polymorphic&& {
|
||||
src.emplace(val);
|
||||
return std::move(*src);
|
||||
};
|
||||
|
||||
Polymorphic i1(make());
|
||||
VERIFY( src->valueless_after_move() );
|
||||
VERIFY( *i1 == *val );
|
||||
|
||||
Polymorphic i2(std::allocator_arg, {}, make());
|
||||
VERIFY( src->valueless_after_move() );
|
||||
VERIFY( *i2 == *val );
|
||||
|
||||
i1 = make();
|
||||
VERIFY( src->valueless_after_move() );
|
||||
VERIFY( *i1 == *val );
|
||||
|
||||
auto(std::move(i1));
|
||||
i1 = make();
|
||||
VERIFY( *i1 == *val );
|
||||
VERIFY( src->valueless_after_move() );
|
||||
|
||||
const Polymorphic val1(std::in_place_type<Derived>, 1, 2, 3);
|
||||
const Polymorphic val2(std::in_place_type<Derived>, 2, 4, 6);
|
||||
|
||||
Polymorphic s1(val1);
|
||||
Polymorphic s2(val2);
|
||||
s1.swap(s2);
|
||||
VERIFY( *s2 == *val1 );
|
||||
VERIFY( *s1 == *val2 );
|
||||
|
||||
auto(std::move(s1));
|
||||
s1.swap(s2);
|
||||
VERIFY( *s1 == *val1 );
|
||||
VERIFY( s2.valueless_after_move() );
|
||||
|
||||
auto e = [] {
|
||||
Polymorphic res(std::in_place_type<Derived>);
|
||||
auto(std::move(res));
|
||||
return res;
|
||||
};
|
||||
|
||||
Polymorphic e1(e());
|
||||
VERIFY( e1.valueless_after_move() );
|
||||
|
||||
Polymorphic e2(std::allocator_arg, {}, e());
|
||||
VERIFY( e2.valueless_after_move() );
|
||||
|
||||
Polymorphic e3(val);
|
||||
e3 = e();
|
||||
e3 = e();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_ctor();
|
||||
test_assign();
|
||||
test_swap();
|
||||
test_valueless();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_all();
|
||||
test_constexpr();
|
||||
|
||||
static_assert([] {
|
||||
test_all();
|
||||
test_constexpr();
|
||||
return true;
|
||||
});
|
||||
}());
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ using __gnu_test::propagating_allocator;
|
||||
using __gnu_test::tracker_allocator;
|
||||
using Counter = __gnu_test::tracker_allocator_counter;
|
||||
|
||||
constexpr void
|
||||
void
|
||||
verifyNoAllocations()
|
||||
{
|
||||
VERIFY( Counter::get_allocation_count() == 0 );
|
||||
@@ -60,7 +60,7 @@ verifyNoAllocations()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_ctor()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -105,7 +105,7 @@ test_ctor()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_assign()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -201,7 +201,7 @@ test_assign()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_swap()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -254,7 +254,7 @@ test_swap()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_valueless()
|
||||
{
|
||||
using PropAlloc = propagating_allocator<int, Propagate>;
|
||||
@@ -317,7 +317,7 @@ test_valueless()
|
||||
}
|
||||
|
||||
template<bool Propagate>
|
||||
constexpr void
|
||||
void
|
||||
test_all()
|
||||
{
|
||||
test_ctor<Propagate>();
|
||||
@@ -330,10 +330,4 @@ int main()
|
||||
{
|
||||
test_all<true>();
|
||||
test_all<false>();
|
||||
|
||||
static_assert([] {
|
||||
test_all<true>();
|
||||
test_all<false>();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace __gnu_test
|
||||
}
|
||||
|
||||
// Implement swap for underlying allocators that might need it.
|
||||
friend inline void
|
||||
friend void
|
||||
swap(tracker_allocator& a, tracker_allocator& b)
|
||||
{
|
||||
using std::swap;
|
||||
@@ -310,10 +310,6 @@ namespace __gnu_test
|
||||
{
|
||||
typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
|
||||
|
||||
Alloc& base() { return *this; }
|
||||
const Alloc& base() const { return *this; }
|
||||
void swap_base(Alloc& b) { using std::swap; swap(b, this->base()); }
|
||||
|
||||
public:
|
||||
typedef typename check_consistent_alloc_value_type<Tp, Alloc>::value_type
|
||||
value_type;
|
||||
@@ -332,9 +328,11 @@ namespace __gnu_test
|
||||
typename AllocTraits::template rebind<Tp1>::other> other;
|
||||
};
|
||||
|
||||
_GLIBCXX_CONSTEXPR
|
||||
uneq_allocator() _GLIBCXX_USE_NOEXCEPT
|
||||
: personality(0) { }
|
||||
|
||||
_GLIBCXX_CONSTEXPR
|
||||
uneq_allocator(int person) _GLIBCXX_USE_NOEXCEPT
|
||||
: personality(person) { }
|
||||
|
||||
@@ -344,21 +342,23 @@ namespace __gnu_test
|
||||
#endif
|
||||
|
||||
template<typename Tp1>
|
||||
_GLIBCXX_CONSTEXPR
|
||||
uneq_allocator(const uneq_allocator<Tp1,
|
||||
typename AllocTraits::template rebind<Tp1>::other>& b)
|
||||
_GLIBCXX_USE_NOEXCEPT
|
||||
: personality(b.get_personality()) { }
|
||||
|
||||
~uneq_allocator() _GLIBCXX_USE_NOEXCEPT
|
||||
{ }
|
||||
|
||||
int get_personality() const { return personality; }
|
||||
_GLIBCXX_CONSTEXPR int get_personality() const { return personality; }
|
||||
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
pointer
|
||||
allocate(size_type n, const void* = 0)
|
||||
{
|
||||
pointer p = AllocTraits::allocate(*this, n);
|
||||
|
||||
if (std::__is_constant_evaluated())
|
||||
return p;
|
||||
|
||||
try
|
||||
{
|
||||
get_map().insert(map_type::value_type(reinterpret_cast<void*>(p),
|
||||
@@ -373,19 +373,24 @@ namespace __gnu_test
|
||||
return p;
|
||||
}
|
||||
|
||||
_GLIBCXX14_CONSTEXPR
|
||||
void
|
||||
deallocate(pointer p, size_type n)
|
||||
{
|
||||
VERIFY( p );
|
||||
|
||||
map_type::iterator it = get_map().find(reinterpret_cast<void*>(p));
|
||||
VERIFY( it != get_map().end() );
|
||||
if (!std::__is_constant_evaluated())
|
||||
{
|
||||
map_type::iterator it = get_map().find(reinterpret_cast<void*>(p));
|
||||
VERIFY( it != get_map().end() );
|
||||
|
||||
// Enforce requirements in Table 32 about deallocation vs
|
||||
// allocator equality.
|
||||
VERIFY( it->second == personality );
|
||||
// Enforce requirements in Table 32 about deallocation vs
|
||||
// allocator equality.
|
||||
VERIFY( it->second == personality );
|
||||
|
||||
get_map().erase(it);
|
||||
}
|
||||
|
||||
get_map().erase(it);
|
||||
AllocTraits::deallocate(*this, p, n);
|
||||
}
|
||||
|
||||
@@ -406,22 +411,23 @@ namespace __gnu_test
|
||||
|
||||
private:
|
||||
// ... yet swappable!
|
||||
friend inline void
|
||||
friend _GLIBCXX_CONSTEXPR void
|
||||
swap(uneq_allocator& a, uneq_allocator& b)
|
||||
{
|
||||
std::swap(a.personality, b.personality);
|
||||
a.swap_base(b);
|
||||
using std::swap;
|
||||
swap(static_cast<Alloc&>(a), static_cast<Alloc&>(b));
|
||||
}
|
||||
|
||||
template<typename Tp1>
|
||||
friend inline bool
|
||||
friend _GLIBCXX_CONSTEXPR bool
|
||||
operator==(const uneq_allocator& a,
|
||||
const uneq_allocator<Tp1,
|
||||
typename AllocTraits::template rebind<Tp1>::other>& b)
|
||||
{ return a.personality == b.get_personality(); }
|
||||
|
||||
template<typename Tp1>
|
||||
friend inline bool
|
||||
friend _GLIBCXX_CONSTEXPR bool
|
||||
operator!=(const uneq_allocator& a,
|
||||
const uneq_allocator<Tp1,
|
||||
typename AllocTraits::template rebind<Tp1>::other>& b)
|
||||
@@ -438,9 +444,12 @@ namespace __gnu_test
|
||||
typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
|
||||
|
||||
typedef uneq_allocator<Tp, Alloc> base_alloc;
|
||||
base_alloc& base() { return *this; }
|
||||
const base_alloc& base() const { return *this; }
|
||||
void swap_base(base_alloc& b) { swap(b, this->base()); }
|
||||
_GLIBCXX14_CONSTEXPR void
|
||||
swap_base(base_alloc& b)
|
||||
{
|
||||
using std::swap;
|
||||
swap(b, static_cast<base_alloc&>(*this));
|
||||
}
|
||||
|
||||
typedef std::integral_constant<bool, Propagate> trait_type;
|
||||
|
||||
@@ -454,11 +463,13 @@ namespace __gnu_test
|
||||
typename AllocTraits::template rebind<Up>::other> other;
|
||||
};
|
||||
|
||||
constexpr
|
||||
propagating_allocator(int i) noexcept
|
||||
: base_alloc(i)
|
||||
{ }
|
||||
|
||||
template<typename Up>
|
||||
constexpr
|
||||
propagating_allocator(const propagating_allocator<Up, Propagate,
|
||||
typename AllocTraits::template rebind<Up>::other>& a)
|
||||
noexcept
|
||||
@@ -469,6 +480,7 @@ namespace __gnu_test
|
||||
|
||||
propagating_allocator(const propagating_allocator&) noexcept = default;
|
||||
|
||||
_GLIBCXX14_CONSTEXPR
|
||||
propagating_allocator&
|
||||
operator=(const propagating_allocator& a) noexcept
|
||||
{
|
||||
@@ -478,6 +490,7 @@ namespace __gnu_test
|
||||
}
|
||||
|
||||
template<bool P2>
|
||||
_GLIBCXX14_CONSTEXPR
|
||||
propagating_allocator&
|
||||
operator=(const propagating_allocator<Tp, P2, Alloc>& a) noexcept
|
||||
{
|
||||
@@ -487,11 +500,13 @@ namespace __gnu_test
|
||||
}
|
||||
|
||||
// postcondition: LWG2593 a.get_personality() un-changed.
|
||||
constexpr
|
||||
propagating_allocator(propagating_allocator&& a) noexcept
|
||||
: base_alloc(std::move(a.base()))
|
||||
: base_alloc(static_cast<base_alloc&&>(a))
|
||||
{ }
|
||||
|
||||
// postcondition: LWG2593 a.get_personality() un-changed
|
||||
_GLIBCXX14_CONSTEXPR
|
||||
propagating_allocator&
|
||||
operator=(propagating_allocator&& a) noexcept
|
||||
{
|
||||
@@ -503,7 +518,8 @@ namespace __gnu_test
|
||||
typedef trait_type propagate_on_container_move_assignment;
|
||||
typedef trait_type propagate_on_container_swap;
|
||||
|
||||
propagating_allocator select_on_container_copy_construction() const
|
||||
constexpr propagating_allocator
|
||||
select_on_container_copy_construction() const
|
||||
{ return Propagate ? *this : propagating_allocator(); }
|
||||
};
|
||||
|
||||
@@ -551,11 +567,11 @@ namespace __gnu_test
|
||||
: state(a.state)
|
||||
{ }
|
||||
|
||||
constexpr T*
|
||||
_GLIBCXX14_CONSTEXPR T*
|
||||
allocate(std::size_t n)
|
||||
{ return std::allocator<T>().allocate(n); }
|
||||
|
||||
constexpr void
|
||||
_GLIBCXX14_CONSTEXPR void
|
||||
deallocate(T* p, std::size_t n)
|
||||
{ std::allocator<T>().deallocate(p, n); }
|
||||
|
||||
@@ -581,7 +597,7 @@ namespace __gnu_test
|
||||
ExplicitConsAlloc() { }
|
||||
|
||||
template<typename Up>
|
||||
explicit
|
||||
explicit _GLIBCXX_CONSTEXPR
|
||||
ExplicitConsAlloc(const ExplicitConsAlloc<Up>&) { }
|
||||
|
||||
template<typename Up>
|
||||
@@ -600,6 +616,7 @@ namespace __gnu_test
|
||||
CustomPointerAlloc() = default;
|
||||
|
||||
template<typename Up>
|
||||
constexpr
|
||||
CustomPointerAlloc(const CustomPointerAlloc<Up>&) { }
|
||||
|
||||
template<typename Up>
|
||||
@@ -611,9 +628,11 @@ namespace __gnu_test
|
||||
typedef Ptr<void> void_pointer;
|
||||
typedef Ptr<const void> const_void_pointer;
|
||||
|
||||
_GLIBCXX14_CONSTEXPR
|
||||
pointer allocate(std::size_t n, const_void_pointer = {})
|
||||
{ return pointer(std::allocator<Tp>::allocate(n)); }
|
||||
|
||||
_GLIBCXX14_CONSTEXPR
|
||||
void deallocate(pointer p, std::size_t n)
|
||||
{ std::allocator<Tp>::deallocate(std::addressof(*p), n); }
|
||||
};
|
||||
@@ -631,16 +650,16 @@ namespace __gnu_test
|
||||
|
||||
explicit operator bool() const noexcept { return value != nullptr; }
|
||||
|
||||
friend inline bool
|
||||
friend constexpr bool
|
||||
operator==(NullablePointer lhs, NullablePointer rhs) noexcept
|
||||
{ return lhs.value == rhs.value; }
|
||||
|
||||
friend inline bool
|
||||
friend constexpr bool
|
||||
operator!=(NullablePointer lhs, NullablePointer rhs) noexcept
|
||||
{ return lhs.value != rhs.value; }
|
||||
|
||||
protected:
|
||||
explicit NullablePointer(Ptr p) noexcept : value(p) { }
|
||||
constexpr explicit NullablePointer(Ptr p) noexcept : value(p) { }
|
||||
Ptr value;
|
||||
};
|
||||
|
||||
@@ -649,16 +668,16 @@ namespace __gnu_test
|
||||
struct NullablePointer<void>
|
||||
{
|
||||
NullablePointer() = default;
|
||||
NullablePointer(std::nullptr_t) noexcept { }
|
||||
explicit NullablePointer(const volatile void*) noexcept { }
|
||||
constexpr NullablePointer(std::nullptr_t) noexcept { }
|
||||
constexpr explicit NullablePointer(const volatile void*) noexcept { }
|
||||
|
||||
explicit operator bool() const noexcept { return false; }
|
||||
constexpr explicit operator bool() const noexcept { return false; }
|
||||
|
||||
friend inline bool
|
||||
friend constexpr bool
|
||||
operator==(NullablePointer, NullablePointer) noexcept
|
||||
{ return true; }
|
||||
|
||||
friend inline bool
|
||||
friend constexpr bool
|
||||
operator!=(NullablePointer, NullablePointer) noexcept
|
||||
{ return false; }
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user