https://gcc.gnu.org/g:c345d6afd9a9b331cb679b82e89213deb8f8a69a

commit r17-909-gc345d6afd9a9b331cb679b82e89213deb8f8a69a
Author: Patrick Palka <[email protected]>
Date:   Thu May 28 10:39:32 2026 -0400

    libstdc++: Fix availability of flat_meow::operator=(initializer_list)
    
    This assignment operator was not being brought in from the private base
    class causing assignments from {...} to be inefficiently treated as
    construction + move assignment.
    
    libstdc++-v3/ChangeLog:
    
            * include/std/flat_map (flat_map): Bring in operator= from
            _Flat_map_base.
            (flat_multimap): Likewise.
            * include/std/flat_set (flat_set): Bring in operator= from
            _Flat_set_base.
            (flat_multiset): Likewise.
            * testsuite/23_containers/flat_map/1.cc (test11): Simplify by
            using = {...}.
            (test12): New test.
            * testsuite/23_containers/flat_multimap/1.cc (test10): Simplify
            by using = {...}.
            (test11): New test.
            * testsuite/23_containers/flat_multiset/1.cc (test10): Simplify
            by using = {...}.
            (test11): New test.
            * testsuite/23_containers/flat_set/1.cc (test10): Simplify by
            using = {...}.
            (test11): New test.
    
    Reviewed-by: Tomasz KamiƄski <[email protected]>
    Reviewed-by: Jonathan Wakely <[email protected]>

Diff:
---
 libstdc++-v3/include/std/flat_map                  | 10 +++++++++
 libstdc++-v3/include/std/flat_set                  | 10 +++++++++
 libstdc++-v3/testsuite/23_containers/flat_map/1.cc | 23 +++++++++++++++------
 .../testsuite/23_containers/flat_multimap/1.cc     | 23 +++++++++++++++------
 .../testsuite/23_containers/flat_multiset/1.cc     | 24 ++++++++++++++++------
 libstdc++-v3/testsuite/23_containers/flat_set/1.cc | 24 ++++++++++++++++------
 6 files changed, 90 insertions(+), 24 deletions(-)

diff --git a/libstdc++-v3/include/std/flat_map 
b/libstdc++-v3/include/std/flat_map
index f06c75a16f65..b82d41b4f5e1 100644
--- a/libstdc++-v3/include/std/flat_map
+++ b/libstdc++-v3/include/std/flat_map
@@ -1275,6 +1275,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // constructors
       using _Impl::_Impl;
 
+      // operator=(initializer_list<value_type>)
+      // Although this also brings in the base move/copy assignment operators,
+      // they will be hidden by our synthesized ones.
+      using _Impl::operator=;
+
       // iterators
       using _Impl::begin;
       using _Impl::end;
@@ -1628,6 +1633,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // constructors
       using _Impl::_Impl;
 
+      // operator=(initializer_list<value_type>)
+      // Although this also brings in the base move/copy assignment operators,
+      // they will be hidden by our synthesized ones.
+      using _Impl::operator=;
+
       // iterators
       using _Impl::begin;
       using _Impl::end;
diff --git a/libstdc++-v3/include/std/flat_set 
b/libstdc++-v3/include/std/flat_set
index e92559949ebb..2f204cc08bf9 100644
--- a/libstdc++-v3/include/std/flat_set
+++ b/libstdc++-v3/include/std/flat_set
@@ -967,6 +967,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // constructors
       using _Impl::_Impl;
 
+      // operator=(initializer_list<value_type>)
+      // Although this also brings in the base move/copy assignment operators,
+      // they will be hidden by our synthesized ones.
+      using _Impl::operator=;
+
       // iterators
       using _Impl::begin;
       using _Impl::end;
@@ -1115,6 +1120,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // constructors
       using _Impl::_Impl;
 
+      // operator=(initializer_list<value_type>)
+      // Although this also brings in the base move/copy assignment operators,
+      // they will be hidden by our synthesized ones.
+      using _Impl::operator=;
+
       // iterators
       using _Impl::begin;
       using _Impl::end;
diff --git a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc 
b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
index 7e22e0366ec2..0cd06b72e96c 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
@@ -351,8 +351,7 @@ test11()
     }
 
   // Verify invariant preservation upon throwing move assignment.
-  source.clear();
-  source.insert({{1, 100}, {2, 200}});
+  source = {{1, 100}, {2, 200}};
   flat_map target;
   target.insert({{3, 300}, {4, 400}});
   try
@@ -367,10 +366,8 @@ test11()
     }
 
   // Verify invariant preservation upon throwing swap.
-  source.clear();
-  source.insert({{1, 100}, {2, 200}});
-  target.clear();
-  target.insert({{3, 300}, {4, 400}});
+  source = {{1, 100}, {2, 200}};
+  target = {{3, 300}, {4, 400}};
   try
     {
       source.swap(target);
@@ -396,6 +393,18 @@ test12()
   VERIFY( std::ranges::equal(m.values(), (int[]){100, 200, 300}) );
 }
 
+void
+test13()
+{
+  // Verify usability of flat_map::operator=(initializer_list).
+  throwing_vector<int>::throw_on_move = true;
+  std::flat_map<int, int, std::less<int>, throwing_vector<int>> s;
+  std::initializer_list<std::pair<int, int>> il = {{2, 1}, {3, 2}, {1, 3}};
+  s = il;
+  VERIFY( std::ranges::equal(s.keys(), (int[]){1, 2, 3}) );
+  VERIFY( std::ranges::equal(s.values(), (int[]){3, 1, 2}) );
+}
+
 void
 test()
 {
@@ -415,6 +424,7 @@ test()
   test11<std::vector, throwing_vector>();
   test11<throwing_vector, std::vector>();
   test12();
+  test13();
 }
 
 constexpr
@@ -435,6 +445,7 @@ test_constexpr()
 #endif
   // test11() is non-constexpr
   test12();
+  // test13() is non-constexpr
   return true;
 }
 
diff --git a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc 
b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
index 48688b7583ed..a070c5ef0911 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
@@ -304,8 +304,7 @@ test10()
     }
 
   // Verify invariant preservation upon throwing move assignment.
-  source.clear();
-  source.insert({{1, 100}, {2, 200}});
+  source = {{1, 100}, {2, 200}};
   flat_multimap target;
   target.insert({{3, 300}, {4, 400}});
   try
@@ -320,10 +319,8 @@ test10()
     }
 
   // Verify invariant preservation upon throwing swap.
-  source.clear();
-  source.insert({{1, 100}, {2, 200}});
-  target.clear();
-  target.insert({{3, 300}, {4, 400}});
+  source = {{1, 100}, {2, 200}};
+  target = {{3, 300}, {4, 400}};
   try
     {
       source.swap(target);
@@ -349,6 +346,18 @@ test11()
   VERIFY( std::ranges::equal(m.values(), (int[]){100, 200, 300}) );
 }
 
+void
+test12()
+{
+  // Verify usability of flat_multimap::operator=(initializer_list).
+  throwing_vector<int>::throw_on_move = true;
+  std::flat_multimap<int, int, std::less<int>, throwing_vector<int>> s;
+  std::initializer_list<std::pair<int, int>> il = {{2, 1}, {3, 2}, {1, 3}};
+  s = il;
+  VERIFY( std::ranges::equal(s.keys(), (int[]){1, 2, 3}) );
+  VERIFY( std::ranges::equal(s.values(), (int[]){3, 1, 2}) );
+}
+
 void
 test()
 {
@@ -366,6 +375,7 @@ test()
   test10<std::vector, throwing_vector>();
   test10<throwing_vector, std::vector>();
   test11();
+  test12();
 }
 
 constexpr
@@ -382,6 +392,7 @@ test_constexpr()
   test09();
   // test10() is non-constexpr
   test11();
+  // test12() is non-constexpr
   return true;
 }
 
diff --git a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc 
b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
index 4544adb50770..eea53733f6d2 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
@@ -289,6 +289,8 @@ struct throwing_vector : std::vector<T>
       throw std::runtime_error("move assign");
     return *this;
   }
+
+  using std::vector<int>::operator=;
 };
 
 void
@@ -312,8 +314,7 @@ test10()
     }
 
   // Verify invariant preservation upon throwing move assignment.
-  source.clear();
-  source.insert({1, 2});
+  source = {1, 2};
   flat_multiset target = {3, 4};
   try
     {
@@ -327,10 +328,8 @@ test10()
     }
 
   // Verify invariant preservation upon throwing swap.
-  source.clear();
-  source.insert({1, 2});
-  target.clear();
-  target.insert({3, 4});
+  source = {1, 2};
+  target = {3, 4};
   try
     {
       source.swap(target);
@@ -355,6 +354,17 @@ test11()
   VERIFY( std::ranges::equal(m, (int[]){1, 2, 3}) );
 }
 
+void
+test12()
+{
+  // Verify usability of flat_multiset::operator=(initializer_list).
+  throwing_vector<int>::throw_on_move = true;
+  std::flat_multiset<int, std::less<int>, throwing_vector<int>> s;
+  std::initializer_list<int> il = {2, 3, 1};
+  s = il;
+  VERIFY( std::ranges::equal(s, (int[]){1, 2, 3}) );
+}
+
 void
 test()
 {
@@ -370,6 +380,7 @@ test()
   test09();
   test10();
   test11();
+  test12();
 }
 
 constexpr
@@ -386,6 +397,7 @@ test_constexpr()
   test09();
   // test10() is non-constexpr
   test11();
+  // test12() is non-constexpr
   return true;
 }
 
diff --git a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc 
b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
index ac12815bd0d4..116ccdcb48d4 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
@@ -301,6 +301,8 @@ struct throwing_vector : std::vector<T>
       throw std::runtime_error("move assign");
     return *this;
   }
+
+  using std::vector<int>::operator=;
 };
 
 void
@@ -324,8 +326,7 @@ test10()
     }
 
   // Verify invariant preservation upon throwing move assignment.
-  source.clear();
-  source.insert({1, 2});
+  source = {1, 2};
   flat_set target = {3, 4};
   try
     {
@@ -339,10 +340,8 @@ test10()
     }
 
   // Verify invariant preservation upon throwing swap.
-  source.clear();
-  source.insert({1, 2});
-  target.clear();
-  target.insert({3, 4});
+  source = {1, 2};
+  target = {3, 4};
   try
     {
       source.swap(target);
@@ -367,6 +366,17 @@ test11()
   VERIFY( std::ranges::equal(m, (int[]){1, 2, 3}) );
 }
 
+void
+test12()
+{
+  // Verify usability of flat_set::operator=(initializer_list).
+  throwing_vector<int>::throw_on_move = true;
+  std::flat_set<int, std::less<int>, throwing_vector<int>> s;
+  std::initializer_list<int> il = {2, 3, 1};
+  s = il;
+  VERIFY( std::ranges::equal(s, (int[]){1, 2, 3}) );
+}
+
 void
 test()
 {
@@ -382,6 +392,7 @@ test()
   test09();
   test10();
   test11();
+  test12();
 }
 
 constexpr
@@ -398,6 +409,7 @@ test_constexpr()
   test09();
   // test10() is non-constexpr
   test11();
+  // test12() is non-constexpr
   return true;
 }

Reply via email to