On Wed, Oct 1, 2025 at 3:05 PM Jonathan Wakely <[email protected]> wrote:
> 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. > I think I was more surprised by constexpr appearing in a file that is compiled in c++98, so I would prefer to make it clear that it is conditional (_GLIBCXX_CONSTEXPR does that). > > > >> > >> +# 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 > >> > >
