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