On Fri, Feb 13, 2026 at 12:27 AM Jonathan Wakely <[email protected]> wrote:
> > > On Thu, 12 Feb 2026, 22:00 Tomasz Kamiński, <[email protected]> wrote: > >> Presence implicit conversion from int to it's allocator, makes the >> following >> makes constructing > > > There seem to be some extra words here, "makes the following makes > constructing" > > string from rvalue of same string type and int ambigous, >> as none of following candidates is better: >> basic_string(basic_string&&, allocator_type) >> // conversion from int to allocator for second argument >> basic_string(const basic_string&, int, allocator_type) >> // reference adjustment for first argument >> >> This makes __gnu_test:uneq_allocator(int) constructor explicit, to avoid >> above issues. >> > > Users can still have the same problems with their own allocators, but > they're not our fault, and there nothing we can do about that. > We can do something about it, i.e. add the rvalues overloads for "substring" constructor. basic_string(basic_string&&, int, allocator_type). I found the problem because I have added above to SSO string, and my test emitted ambiguity warning for COW string. But I still think that this ambiguity is what you deserve if you write an allocator that can be implicitly constructed from int. So unless we get a real user complaint, I do not feel like we should bend to fix it. > OK with the wording cleaned up above. > > > >> libstdc++-v3/ChangeLog: >> >> * testsuite/20_util/scoped_allocator/construct_pair_c++2a.cc >> (__gnu_test::uneq_allocator(int)): Declare as explicit. >> * testsuite/std/memory/indirect/ctor.cc: Construct uneq_allocator >> from int explicitly. >> * testsuite/std/memory/polymorphic/ctor.cc: Likewise. >> * testsuite/std/memory/polymorphic/ctor_poly.cc: Likewise. >> * testsuite/util/testsuite_allocator.h: Likewise. >> --- >> Tested on x86_64-linux. OK for trunk? >> >> .../scoped_allocator/construct_pair_c++2a.cc | 12 ++++---- >> .../testsuite/std/memory/indirect/ctor.cc | 29 +++++++++++-------- >> .../testsuite/std/memory/polymorphic/ctor.cc | 27 ++++++++++------- >> .../std/memory/polymorphic/ctor_poly.cc | 18 +++++++----- >> .../testsuite/util/testsuite_allocator.h | 2 +- >> 5 files changed, 51 insertions(+), 37 deletions(-) >> >> diff --git >> a/libstdc++-v3/testsuite/20_util/scoped_allocator/construct_pair_c++2a.cc >> b/libstdc++-v3/testsuite/20_util/scoped_allocator/construct_pair_c++2a.cc >> index ecc26cb5a63..4eb174a89f3 100644 >> --- >> a/libstdc++-v3/testsuite/20_util/scoped_allocator/construct_pair_c++2a.cc >> +++ >> b/libstdc++-v3/testsuite/20_util/scoped_allocator/construct_pair_c++2a.cc >> @@ -39,10 +39,10 @@ void >> test01() >> { >> using value_type = std::pair<std::pair<X, int>, std::pair<int, X>>; >> - using scoped_alloc >> - = >> std::scoped_allocator_adaptor<__gnu_test::uneq_allocator<value_type>>; >> + using uneq_alloc = __gnu_test::uneq_allocator<value_type>; >> + using scoped_alloc = std::scoped_allocator_adaptor<uneq_alloc>; >> >> - const scoped_alloc a(10); >> + const scoped_alloc a(uneq_alloc(10)); >> std::vector<value_type, scoped_alloc> v(a); >> VERIFY( v.get_allocator().get_personality() == a.get_personality() ); >> >> @@ -65,11 +65,11 @@ void >> test02() >> { >> using value_type = std::pair<std::pair<X, int>, std::pair<int, X>>; >> + using uneq_alloc = __gnu_test::uneq_allocator<value_type>; >> using scoped_alloc >> - = >> std::scoped_allocator_adaptor<__gnu_test::uneq_allocator<value_type>, >> - X::allocator_type>; >> + = std::scoped_allocator_adaptor<uneq_alloc, X::allocator_type>; >> >> - const scoped_alloc a(10, 20); >> + const scoped_alloc a(uneq_alloc(10), X::allocator_type(20)); >> std::vector<value_type, scoped_alloc> v(a); >> VERIFY( v.get_allocator().get_personality() == a.get_personality() ); >> >> diff --git a/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc >> b/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc >> index dfd9341582f..ec34e584b3f 100644 >> --- a/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc >> +++ b/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc >> @@ -16,9 +16,9 @@ >> >> using __gnu_test::uneq_allocator; >> using UneqAlloc = uneq_allocator<int>; >> -using ScopedAlloc = std::scoped_allocator_adaptor< >> - uneq_allocator<std::vector<int, UneqAlloc>>, >> - UneqAlloc>; >> +using UneqVecAlloc = uneq_allocator<std::vector<int, UneqAlloc>>; >> +using ScopedAlloc >> + = std::scoped_allocator_adaptor<UneqVecAlloc, UneqAlloc>; >> >> struct Obj >> { >> @@ -61,9 +61,10 @@ test_default_ctor() >> if (std::is_constant_evaluated()) >> return; >> >> + const ScopedAlloc scopedAlloc(UneqVecAlloc(11), UneqAlloc(22)); >> // Object is constructed using allocator-aware constructor. >> std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc> >> - i3(std::allocator_arg, ScopedAlloc(11, 22)); >> + i3(std::allocator_arg, scopedAlloc); >> VERIFY( i3->empty() ); >> VERIFY( i3->get_allocator().get_personality() == 22 ); >> VERIFY( i3.get_allocator().get_personality() == 11 ); >> @@ -99,17 +100,18 @@ test_forwarding_ctor() >> if (std::is_constant_evaluated()) >> return; >> >> + const ScopedAlloc scopedAlloc(UneqVecAlloc(11), UneqAlloc(22)); >> std::vector<int, UneqAlloc> v{1, 2, 3, 4, 5}; >> // Object is constructed using allocator-aware constructor. >> std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc> >> - i7(std::allocator_arg, ScopedAlloc(11, 22), v); >> + i7(std::allocator_arg, scopedAlloc, v); >> VERIFY( i7->size() == 5 ); >> VERIFY( v.size() == 5 ); >> VERIFY( i7->get_allocator().get_personality() == 22 ); >> VERIFY( i7.get_allocator().get_personality() == 11 ); >> >> std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc> >> - i8(std::allocator_arg, ScopedAlloc(11, 22), std::move(v)); >> + i8(std::allocator_arg, scopedAlloc, std::move(v)); >> VERIFY( i8->size() == 5 ); >> VERIFY( v.size() == 0 ); >> VERIFY( i8->get_allocator().get_personality() == 22 ); >> @@ -130,14 +132,16 @@ test_inplace_ctor() >> VERIFY( i2->c[1] == 0 ); >> >> std::indirect<Obj, uneq_allocator<Obj>> >> - i3(std::allocator_arg, 42, std::in_place); >> + i3(std::allocator_arg, uneq_allocator<Obj>(42), >> + std::in_place); >> VERIFY( i3->i == 0 ); >> VERIFY( i3->c[0] == 0 ); >> VERIFY( i3->c[1] == 0 ); >> VERIFY( i3.get_allocator().get_personality() == 42 ); >> >> - std::indirect<Obj, uneq_allocator<Obj>> >> - i4(std::allocator_arg, 42, std::in_place, 10); >> + std::indirect<Obj, uneq_allocator<Obj>> >> + i4(std::allocator_arg, uneq_allocator<Obj>(42), >> + std::in_place, 10); >> VERIFY( i4->i == 10 ); >> VERIFY( i4->c[0] == 0 ); >> VERIFY( i4->c[1] == 0 ); >> @@ -174,15 +178,16 @@ test_inplace_ctor() >> if (std::is_constant_evaluated()) >> return; >> >> + const ScopedAlloc scopedAlloc(UneqVecAlloc(11), UneqAlloc(22)); >> std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc> >> - i14(std::allocator_arg, ScopedAlloc(11, 22), >> + i14(std::allocator_arg, scopedAlloc, >> std::in_place); >> VERIFY( i14->size() == 0 ); >> VERIFY( i14->get_allocator().get_personality() == 22 ); >> VERIFY( i14.get_allocator().get_personality() == 11 ); >> >> std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc> >> - i15(std::allocator_arg, ScopedAlloc(11, 22), >> + i15(std::allocator_arg, scopedAlloc, >> std::in_place, 5, 13); >> VERIFY( i15->size() == 5 ); >> VERIFY( i15->at(0) == 13 ); >> @@ -190,7 +195,7 @@ test_inplace_ctor() >> VERIFY( i15.get_allocator().get_personality() == 11 ); >> >> std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc> >> - i16(std::allocator_arg, ScopedAlloc(11, 22), >> + i16(std::allocator_arg, scopedAlloc, >> std::in_place, {1, 2, 3, 4}); >> VERIFY( i16->size() == 4 ); >> VERIFY( i16->at(2) == 3 ); >> diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc >> b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc >> index 4d043db0ea4..a81d5615b4a 100644 >> --- a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc >> +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc >> @@ -16,9 +16,9 @@ >> >> using __gnu_test::uneq_allocator; >> using UneqAlloc = uneq_allocator<int>; >> -using ScopedAlloc = std::scoped_allocator_adaptor< >> - uneq_allocator<std::vector<int, UneqAlloc>>, >> - UneqAlloc>; >> +using UneqVecAlloc = uneq_allocator<std::vector<int, UneqAlloc>>; >> +using ScopedAlloc >> + = std::scoped_allocator_adaptor<UneqVecAlloc, UneqAlloc>; >> >> struct Obj >> { >> @@ -48,9 +48,10 @@ test_default_ctor() >> if (std::is_constant_evaluated()) >> return; >> >> + const ScopedAlloc scopedAlloc(UneqVecAlloc(11), UneqAlloc(22)); >> // Object is constructed using allocator-aware constructor. >> std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> >> - i3(std::allocator_arg, ScopedAlloc(11, 22)); >> + i3(std::allocator_arg, scopedAlloc); >> VERIFY( i3->empty() ); >> VERIFY( i3->get_allocator().get_personality() == 22 ); >> VERIFY( i3.get_allocator().get_personality() == 11 ); >> @@ -82,17 +83,18 @@ test_forwarding_ctor() >> if (std::is_constant_evaluated()) >> return; >> >> + const ScopedAlloc scopedAlloc(UneqVecAlloc(11), UneqAlloc(22)); >> std::vector<int, UneqAlloc> v{1, 2, 3, 4, 5}; >> // Object is constructed using allocator-aware constructor. >> std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> >> - i7(std::allocator_arg, ScopedAlloc(11, 22), v); >> + i7(std::allocator_arg, scopedAlloc, v); >> VERIFY( i7->size() == 5 ); >> VERIFY( v.size() == 5 ); >> VERIFY( i7->get_allocator().get_personality() == 22 ); >> VERIFY( i7.get_allocator().get_personality() == 11 ); >> >> std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> >> - i8(std::allocator_arg, ScopedAlloc(11, 22), std::move(v)); >> + i8(std::allocator_arg, scopedAlloc, std::move(v)); >> VERIFY( i8->size() == 5 ); >> VERIFY( v.size() == 0 ); >> VERIFY( i8->get_allocator().get_personality() == 22 ); >> @@ -113,14 +115,16 @@ test_inplace_ctor() >> VERIFY( i2->c[1] == 0 ); >> >> std::polymorphic<Obj, uneq_allocator<Obj>> >> - i3(std::allocator_arg, 42, std::in_place_type<Obj>); >> + i3(std::allocator_arg, uneq_allocator<Obj>(42), >> + std::in_place_type<Obj>); >> VERIFY( i3->i == 0 ); >> VERIFY( i3->c[0] == 0 ); >> VERIFY( i3->c[1] == 0 ); >> VERIFY( i3.get_allocator().get_personality() == 42 ); >> >> std::polymorphic<Obj, uneq_allocator<Obj>> >> - i4(std::allocator_arg, 42, std::in_place_type<Obj>, 10); >> + i4(std::allocator_arg, uneq_allocator<Obj>(42), >> + std::in_place_type<Obj>, 10); >> VERIFY( i4->i == 10 ); >> VERIFY( i4->c[0] == 0 ); >> VERIFY( i4->c[1] == 0 ); >> @@ -160,15 +164,16 @@ test_inplace_ctor() >> if (std::is_constant_evaluated()) >> return; >> >> + const ScopedAlloc scopedAlloc(UneqVecAlloc(11), UneqAlloc(22)); >> std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> >> - i14(std::allocator_arg, ScopedAlloc(11, 22), >> + i14(std::allocator_arg, scopedAlloc, >> std::in_place_type<std::vector<int, UneqAlloc>>); >> VERIFY( i14->size() == 0 ); >> VERIFY( i14->get_allocator().get_personality() == 22 ); >> VERIFY( i14.get_allocator().get_personality() == 11 ); >> >> std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> >> - i15(std::allocator_arg, ScopedAlloc(11, 22), >> + i15(std::allocator_arg, scopedAlloc, >> std::in_place_type<std::vector<int, UneqAlloc>>, 5, 13); >> VERIFY( i15->size() == 5 ); >> VERIFY( i15->at(0) == 13 ); >> @@ -176,7 +181,7 @@ test_inplace_ctor() >> VERIFY( i15.get_allocator().get_personality() == 11 ); >> >> std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> >> - i16(std::allocator_arg, ScopedAlloc(11, 22), >> + i16(std::allocator_arg, scopedAlloc, >> std::in_place_type<std::vector<int, UneqAlloc>>, {1, 2, 3, 4}); >> VERIFY( i16->size() == 4 ); >> VERIFY( i16->at(2) == 3 ); >> diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc >> b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc >> index cb18031a903..2c275d199d9 100644 >> --- a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc >> +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc >> @@ -129,16 +129,17 @@ test_forwarding_ctor() >> if (std::is_constant_evaluated()) >> return; >> >> + const ScopedAlloc scopedAlloc(uneq_allocator<Base>(11), UneqAlloc(22)); >> const VecDerived<int, UneqAlloc> v{1, 2, 3, 4, 5}; >> // Object is constructed using allocator-aware constructor. >> std::polymorphic<Base, ScopedAlloc> >> - i5(std::allocator_arg, ScopedAlloc(11, 22), v); >> + i5(std::allocator_arg, scopedAlloc, v); >> VERIFY( *i5 == v ); >> VERIFY( i5->get_personality() == 22 ); >> VERIFY( i5.get_allocator().get_personality() == 11 ); >> >> std::polymorphic<Base, ScopedAlloc> >> - i6(std::allocator_arg, ScopedAlloc(11, 22), auto(v)); >> + i6(std::allocator_arg, scopedAlloc, auto(v)); >> VERIFY( *i6 == v ); >> VERIFY( i6->get_personality() == 22 ); >> VERIFY( i6.get_allocator().get_personality() == 11 ); >> @@ -156,13 +157,15 @@ test_inplace_ctor() >> VERIFY( i2->get_personality() == -2 ); >> >> std::polymorphic<Base, uneq_allocator<Base>> >> - i3(std::allocator_arg, 42, std::in_place_type<ObjDerived>); >> + i3(std::allocator_arg, uneq_allocator<Base>(42), >> + std::in_place_type<ObjDerived>); >> VERIFY( *i3 == ObjDerived() ); >> VERIFY( i3->get_personality() == -2 ); >> VERIFY( i3.get_allocator().get_personality() == 42 ); >> >> std::polymorphic<Base, uneq_allocator<Base>> >> - i4(std::allocator_arg, 42, std::in_place_type<ObjDerived>, 10, 20, >> 30); >> + i4(std::allocator_arg, uneq_allocator<Base>(42), >> + std::in_place_type<ObjDerived>, 10, 20, 30); >> VERIFY( *i4 == ObjDerived(10, 20, 30) ); >> VERIFY( i4->get_personality() == -2 ); >> VERIFY( i4.get_allocator().get_personality() == 42 ); >> @@ -189,22 +192,23 @@ test_inplace_ctor() >> if (std::is_constant_evaluated()) >> return; >> >> + const ScopedAlloc scopedAlloc(uneq_allocator<Base>(11), UneqAlloc(22)); >> std::polymorphic<Base, ScopedAlloc> >> - i8(std::allocator_arg, ScopedAlloc(11, 22), >> + i8(std::allocator_arg, scopedAlloc, >> std::in_place_type<VecDerived<int, UneqAlloc>>); >> VERIFY( *i8 == ze ); >> VERIFY( i8->get_personality() == 22 ); >> VERIFY( i8.get_allocator().get_personality() == 11 ); >> >> std::polymorphic<Base, ScopedAlloc> >> - i9(std::allocator_arg, ScopedAlloc(11, 22), >> + i9(std::allocator_arg, scopedAlloc, >> std::in_place_type<VecDerived<int, UneqAlloc>>, 5, 13); >> VERIFY( *i9 == fe ); >> VERIFY( i9->get_personality() == 22 ); >> VERIFY( i9.get_allocator().get_personality() == 11 ); >> >> std::polymorphic<Base, ScopedAlloc> >> - i10(std::allocator_arg, ScopedAlloc(11, 22), >> + i10(std::allocator_arg, scopedAlloc, >> std::in_place_type<VecDerived<int, UneqAlloc>>, {1, 2, 3, 4}); >> VERIFY( *i10 == il ); >> VERIFY( i10->get_personality() == 22 ); >> diff --git a/libstdc++-v3/testsuite/util/testsuite_allocator.h >> b/libstdc++-v3/testsuite/util/testsuite_allocator.h >> index 295b458e3c6..892a385e307 100644 >> --- a/libstdc++-v3/testsuite/util/testsuite_allocator.h >> +++ b/libstdc++-v3/testsuite/util/testsuite_allocator.h >> @@ -332,7 +332,7 @@ namespace __gnu_test >> uneq_allocator() _GLIBCXX_USE_NOEXCEPT >> : personality(0) { } >> >> - _GLIBCXX_CONSTEXPR >> + _GLIBCXX_CONSTEXPR explicit >> uneq_allocator(int person) _GLIBCXX_USE_NOEXCEPT >> : personality(person) { } >> >> -- >> 2.53.0 >> >>
