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
>>
>>

Reply via email to