On Wed, 1 Oct 2025 at 14:00, Tomasz Kaminski <[email protected]> wrote:
>
> The tile should mention actual change to the indirect/polymorphic code.
>
> On Wed, Oct 1, 2025 at 2:36 PM Jonathan Wakely <[email protected]> wrote:
>>
>> 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.
>> ---
>>
>> Tested powerpc64le-linux.
>>
>> libstdc++-v3/include/bits/indirect.h | 4 +-
>> .../testsuite/std/memory/indirect/copy.cc | 55 +++++++++--
>> .../std/memory/indirect/copy_alloc.cc | 12 +--
>> .../testsuite/std/memory/indirect/ctor.cc | 11 ++-
>> .../testsuite/std/memory/indirect/move.cc | 85 ++++++++++++++---
>> .../std/memory/indirect/move_alloc.cc | 18 ++--
>> .../testsuite/std/memory/indirect/relops.cc | 2 +-
>> .../testsuite/std/memory/polymorphic/copy.cc | 55 +++++++++--
>> .../std/memory/polymorphic/copy_alloc.cc | 24 ++---
>> .../testsuite/std/memory/polymorphic/ctor.cc | 11 ++-
>> .../std/memory/polymorphic/ctor_poly.cc | 8 +-
>> .../testsuite/std/memory/polymorphic/move.cc | 82 +++++++++++++---
>> .../std/memory/polymorphic/move_alloc.cc | 18 ++--
>> .../testsuite/util/testsuite_allocator.h | 94 ++++++++++++-------
>> 14 files changed, 343 insertions(+), 136 deletions(-)
>>
>> diff --git a/libstdc++-v3/include/bits/indirect.h
>> b/libstdc++-v3/include/bits/indirect.h
>> index 89fa8c874fbd..2df46cc39a21 100644
>> --- a/libstdc++-v3/include/bits/indirect.h
>> +++ b/libstdc++-v3/include/bits/indirect.h
>> @@ -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;
>> }
>> diff --git a/libstdc++-v3/testsuite/std/memory/indirect/copy.cc
>> b/libstdc++-v3/testsuite/std/memory/indirect/copy.cc
>> index 0ac6e92a9213..5ecfbbd898f4 100644
>> --- a/libstdc++-v3/testsuite/std/memory/indirect/copy.cc
>> +++ b/libstdc++-v3/testsuite/std/memory/indirect/copy.cc
>> @@ -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;
>> - });
>> + }());
>> }
>> diff --git a/libstdc++-v3/testsuite/std/memory/indirect/copy_alloc.cc
>> b/libstdc++-v3/testsuite/std/memory/indirect/copy_alloc.cc
>> index d5865b9a580d..e48855a0eac5 100644
>> --- a/libstdc++-v3/testsuite/std/memory/indirect/copy_alloc.cc
>> +++ b/libstdc++-v3/testsuite/std/memory/indirect/copy_alloc.cc
>> @@ -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;
>> - });
>> }
>> diff --git a/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc
>> b/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc
>> index 124874d02fe6..dfd9341582f5 100644
>> --- a/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc
>> +++ b/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc
>> @@ -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>
>
> I am surprised that scoped_allocator_adaptor is not contexpr.
> I was certain it is.
Yeah, I was surprised too.
>>
>> @@ -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;
>> - });
>> + }());
>> }
>> diff --git a/libstdc++-v3/testsuite/std/memory/indirect/move.cc
>> b/libstdc++-v3/testsuite/std/memory/indirect/move.cc
>> index 6e87c60adb0d..9800f7fd1a79 100644
>> --- a/libstdc++-v3/testsuite/std/memory/indirect/move.cc
>> +++ b/libstdc++-v3/testsuite/std/memory/indirect/move.cc
>> @@ -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;
>> - });
>> + }());
>> }
>> diff --git a/libstdc++-v3/testsuite/std/memory/indirect/move_alloc.cc
>> b/libstdc++-v3/testsuite/std/memory/indirect/move_alloc.cc
>> index cd6f90dcdc56..cf35e83310f7 100644
>> --- a/libstdc++-v3/testsuite/std/memory/indirect/move_alloc.cc
>> +++ b/libstdc++-v3/testsuite/std/memory/indirect/move_alloc.cc
>> @@ -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;
>> - });
>> }
>> diff --git a/libstdc++-v3/testsuite/std/memory/indirect/relops.cc
>> b/libstdc++-v3/testsuite/std/memory/indirect/relops.cc
>> index d77fef2a4306..77d599c80861 100644
>> --- a/libstdc++-v3/testsuite/std/memory/indirect/relops.cc
>> +++ b/libstdc++-v3/testsuite/std/memory/indirect/relops.cc
>> @@ -78,5 +78,5 @@ int main()
>> test_relops();
>> test_comp_with_t();
>> return true;
>> - });
>> + }());
>> }
>> diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc
>> b/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc
>> index d66cc0657b39..34c78220e320 100644
>> --- a/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc
>> +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc
>> @@ -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;
>> - });
>> + }());
>> }
>> diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc
>> b/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc
>> index f41c32e1e1de..f149fc860e02 100644
>> --- a/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc
>> +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc
>> @@ -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;
>> - });
>> }
>> diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc
>> b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc
>> index bb4c947285e7..4d043db0ea4a 100644
>> --- a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc
>> +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc
>> @@ -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;
>> - });
>> + }());
>> }
>> diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc
>> b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc
>> index 03519a1db004..cb18031a9037 100644
>> --- a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc
>> +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc
>> @@ -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;
>> - });
>> + }());
>> }
>> diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc
>> b/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc
>> index c80215983b6c..d267994b36a4 100644
>> --- a/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc
>> +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc
>> @@ -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,76 @@ 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));
>> + Counter::reset();
>> + 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;
>> - });
>> + }());
>> }
>> diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc
>> b/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc
>> index 09afedb78848..490bffb8c392 100644
>> --- a/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc
>> +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc
>> @@ -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;
>> - });
>> }
>> diff --git a/libstdc++-v3/testsuite/util/testsuite_allocator.h
>> b/libstdc++-v3/testsuite/util/testsuite_allocator.h
>> index ee9575266a00..fabbef03f875 100644
>> --- a/libstdc++-v3/testsuite/util/testsuite_allocator.h
>> +++ b/libstdc++-v3/testsuite/util/testsuite_allocator.h
>> @@ -43,6 +43,11 @@ namespace unord = std;
>> namespace unord = std::tr1;
>> #endif
>>
>> +#ifndef __cpp_constexpr
>> +// Ignore the constexpr keywords below when compiled as C++98
>
> I would prefer if we use _GLIBCXX_CONSTEXPR here, instead of defining
> a keyword. We alrady use _GLIBCXX14_CONSTEXPR etc.
It's not a keyword in C++98 though :-)
I wanted to avoid the ugly macro where possible, but I can change it.
>>
>> +# define constexpr
>> +#endif
>> +
>> namespace __gnu_test
>> {
>> // A common API for calling max_size() on an allocator in any -std mode.
>> @@ -216,7 +221,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 +315,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 +333,11 @@ namespace __gnu_test
>> typename AllocTraits::template rebind<Tp1>::other> other;
>> };
>>
>> + constexpr
>> uneq_allocator() _GLIBCXX_USE_NOEXCEPT
>> : personality(0) { }
>>
>> + constexpr
>> uneq_allocator(int person) _GLIBCXX_USE_NOEXCEPT
>> : personality(person) { }
>>
>> @@ -344,21 +347,23 @@ namespace __gnu_test
>> #endif
>>
>> template<typename Tp1>
>> + 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; }
>> + 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 +378,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 +416,23 @@ namespace __gnu_test
>>
>> private:
>> // ... yet swappable!
>> - friend inline void
>> + friend 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 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 constexpr bool
>> operator!=(const uneq_allocator& a,
>> const uneq_allocator<Tp1,
>> typename AllocTraits::template rebind<Tp1>::other>& b)
>> @@ -438,9 +449,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 +468,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 +485,7 @@ namespace __gnu_test
>>
>> propagating_allocator(const propagating_allocator&) noexcept =
>> default;
>>
>> + _GLIBCXX14_CONSTEXPR
>> propagating_allocator&
>> operator=(const propagating_allocator& a) noexcept
>> {
>> @@ -478,6 +495,7 @@ namespace __gnu_test
>> }
>>
>> template<bool P2>
>> + _GLIBCXX14_CONSTEXPR
>> propagating_allocator&
>> operator=(const propagating_allocator<Tp, P2, Alloc>& a) noexcept
>> {
>> @@ -487,11 +505,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 +523,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 +572,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 +602,7 @@ namespace __gnu_test
>> ExplicitConsAlloc() { }
>>
>> template<typename Up>
>> - explicit
>> + explicit constexpr
>> ExplicitConsAlloc(const ExplicitConsAlloc<Up>&) { }
>>
>> template<typename Up>
>> @@ -600,6 +621,7 @@ namespace __gnu_test
>> CustomPointerAlloc() = default;
>>
>> template<typename Up>
>> + constexpr
>> CustomPointerAlloc(const CustomPointerAlloc<Up>&) { }
>>
>> template<typename Up>
>> @@ -611,9 +633,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 +655,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 +673,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; }
>> };
>> --
>> 2.51.0
>>