https://gcc.gnu.org/g:4794340cd257ece0d197f041812c34c5ac5d50a1
commit r16-182-g4794340cd257ece0d197f041812c34c5ac5d50a1 Author: Tomasz Kamiński <tkami...@redhat.com> Date: Thu Mar 20 09:02:03 2025 +0100 libstdc++: Strip reference and cv-qual in range deduction guides for maps. This implements part of LWG4223 that adjust the deduction guides for maps types (map, unordered_map, flat_map and non-unique equivalent) from "range" (std::from_range, iterator pair), such that referience and cv qualification are stripped from the element of the pair-like value_type. In combination with r15-8296-gd50171bc07006d, the LWG4223 is fully implemented now. libstdc++-v3/ChangeLog: * include/bits/ranges_base.h (__detail::__range_key_type): Replace remove_const_t with remove_cvref_t. (__detail::__range_mapped_type): Apply remove_cvref_t. * include/bits/stl_iterator.h: (__detail::__iter_key_t): Replace remove_const_t with __remove_cvref_t. (__detail::__iter_val_t): Apply __remove_cvref_t. * testsuite/23_containers/flat_map/1.cc: New tests. * testsuite/23_containers/flat_multimap/1.cc: New tests. * testsuite/23_containers/map/cons/deduction.cc: New tests. * testsuite/23_containers/map/cons/from_range.cc: New tests. * testsuite/23_containers/multimap/cons/deduction.cc: New tests. * testsuite/23_containers/multimap/cons/from_range.cc: New tests. * testsuite/23_containers/unordered_map/cons/deduction.cc: New tests. * testsuite/23_containers/unordered_map/cons/from_range.cc: New tests. * testsuite/23_containers/unordered_multimap/cons/deduction.cc: New tests. * testsuite/23_containers/unordered_multimap/cons/from_range.cc: New tests. Reviewed-by: Jonathan Wakely <jwak...@redhat.com> Signed-off-by: Tomasz Kamiński <tkami...@redhat.com> Diff: --- libstdc++-v3/include/bits/ranges_base.h | 4 +- libstdc++-v3/include/bits/stl_iterator.h | 11 ++-- libstdc++-v3/testsuite/23_containers/flat_map/1.cc | 21 +++---- .../testsuite/23_containers/flat_multimap/1.cc | 21 +++---- .../testsuite/23_containers/map/cons/deduction.cc | 46 +++++++++++++++ .../testsuite/23_containers/map/cons/from_range.cc | 8 +-- .../23_containers/multimap/cons/deduction.cc | 46 +++++++++++++++ .../23_containers/multimap/cons/from_range.cc | 8 +-- .../23_containers/unordered_map/cons/deduction.cc | 69 ++++++++++++++++++++++ .../23_containers/unordered_map/cons/from_range.cc | 10 ++-- .../unordered_multimap/cons/deduction.cc | 69 ++++++++++++++++++++++ .../unordered_multimap/cons/from_range.cc | 10 ++-- 12 files changed, 279 insertions(+), 44 deletions(-) diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index 488907da4466..dde164988569 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -1103,11 +1103,11 @@ namespace __detail // 4223. Deduction guides for maps are mishandling tuples and references template<ranges::input_range _Range> using __range_key_type - = remove_const_t<tuple_element_t<0, ranges::range_value_t<_Range>>>; + = remove_cvref_t<tuple_element_t<0, ranges::range_value_t<_Range>>>; template<ranges::input_range _Range> using __range_mapped_type - = tuple_element_t<1, ranges::range_value_t<_Range>>; + = remove_cvref_t<tuple_element_t<1, ranges::range_value_t<_Range>>>; // The allocator's value_type for map-like containers. template<ranges::input_range _Range> diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 9203a66b2ff0..bed72955d0c4 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -3086,8 +3086,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cpp_deduction_guides >= 201606 // These helper traits are used for deduction guides // of associative containers. + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4223. Deduction guides for maps are mishandling tuples and references template<typename _InputIterator> - using __iter_key_t = remove_const_t< + using __iter_key_t = __remove_cvref_t< #ifdef __glibcxx_tuple_like // >= C++23 tuple_element_t<0, typename iterator_traits<_InputIterator>::value_type>>; #else @@ -3095,11 +3098,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif template<typename _InputIterator> - using __iter_val_t + using __iter_val_t = __remove_cvref_t< #ifdef __glibcxx_tuple_like // >= C++23 - = tuple_element_t<1, typename iterator_traits<_InputIterator>::value_type>; + tuple_element_t<1, typename iterator_traits<_InputIterator>::value_type>>; #else - = typename iterator_traits<_InputIterator>::value_type::second_type; + typename iterator_traits<_InputIterator>::value_type::second_type>; #endif template<typename _T1, typename _T2> diff --git a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc index 4fd33f616f78..a4e0d867c936 100644 --- a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc +++ b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc @@ -56,16 +56,17 @@ test_deduction_guide() std::vector<long, __gnu_test::SimpleAllocator<long>>, std::vector<float, __gnu_test::SimpleAllocator<float>>>>); - // LWG4223: deduces flat_map<long, float const>, which in turn instantiates - // std::vector<cosnt float> that is ill-formed. - // __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); - // std::flat_map it5(r2.begin(), r2.begin()); - // std::flat_map fr5(std::from_range, r2); - - // LWG4223: deduces flat_map<const long&, float&> - //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); - // std::flat_map it6(r3.begin(), r3.begin()); - // std::flat_map fr6(std::from_range, r3); + __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); + std::flat_map it5(r2.begin(), r2.begin()); + static_assert(std::is_same_v<decltype(it5), std::flat_map<long, float>>); + std::flat_map fr5(std::from_range, r2); + static_assert(std::is_same_v<decltype(fr5), std::flat_map<long, float>>); + + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); + std::flat_map it6(r3.begin(), r3.begin()); + static_assert(std::is_same_v<decltype(it6), std::flat_map<long, float>>); + std::flat_map fr6(std::from_range, r3); + static_assert(std::is_same_v<decltype(fr6), std::flat_map<long, float>>); __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); std::flat_map it7(r4.begin(), r4.begin()); diff --git a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc index ea0d4b41e9fb..1e70535286a4 100644 --- a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc +++ b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc @@ -54,16 +54,17 @@ test_deduction_guide() std::vector<long, __gnu_test::SimpleAllocator<long>>, std::vector<float, __gnu_test::SimpleAllocator<float>>>>); - // LWG4223: deduces flat_multimap<long, float const>, which in turn instantiates - // std::vector<cosnt float> that is ill-formed. - // __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); - // std::flat_multimap it5(r2.begin(), r2.begin()); - // std::flat_multimap fr5(std::from_range, r2); - - // LWG4223: deduces flat_multimap<const long&, float&> - //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); - // std::flat_multimap it6(r3.begin(), r3.begin()); - // std::flat_multimap fr6(std::from_range, r3); + __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); + std::flat_multimap it5(r2.begin(), r2.begin()); + static_assert(std::is_same_v<decltype(it5), std::flat_multimap<long, float>>); + std::flat_multimap fr5(std::from_range, r2); + static_assert(std::is_same_v<decltype(fr5), std::flat_multimap<long, float>>); + + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); + std::flat_multimap it6(r3.begin(), r3.begin()); + static_assert(std::is_same_v<decltype(it6), std::flat_multimap<long, float>>); + std::flat_multimap fr6(std::from_range, r3); + static_assert(std::is_same_v<decltype(fr6), std::flat_multimap<long, float>>); __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); std::flat_multimap it7(r4.begin(), r4.begin()); diff --git a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc index f8e6e6e8b994..864598879b06 100644 --- a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc +++ b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc @@ -258,3 +258,49 @@ test_p1518r2() std::map s2(std::move(m), p); check_type<Map>(s2); } + +struct MyPred +{ + template<typename T, typename U> + bool operator()(T const&, U const&) const; +}; + +template<typename K, typename V> +constexpr bool test_lwg4223() +{ + using KD = std::remove_cv_t<std::remove_reference_t<K>>; + using VD = std::remove_cv_t<std::remove_reference_t<V>>; + using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>; + + std::initializer_list<std::pair<K, V>> il = {}; + Alloc a; + MyPred p; + + // The remove_cvref_t is not applied here. + // static_assert(std::is_same_v< + // decltype(std::map(il)), + // std::map<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::map(il.begin(), il.end())), + std::map<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::map(il.begin(), il.end(), p)), + std::map<KD, VD, MyPred>>); + + static_assert(std::is_same_v< + decltype(std::map(il.begin(), il.end(), a)), + std::map<KD, VD, std::less<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::map(il.begin(), il.end(), p, a)), + std::map<KD, VD, MyPred, Alloc>>); + + return true; +} + +static_assert(test_lwg4223<const int, const float>()); +static_assert(test_lwg4223<int&, float&>()); +static_assert(test_lwg4223<int&&, float&&>()); +static_assert(test_lwg4223<const int&, const float&>()); diff --git a/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc index 9935f44aa0f9..3a9fede04348 100644 --- a/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc @@ -43,11 +43,11 @@ test_deduction_guide() __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); std::map m5(std::from_range, r2); - static_assert(std::is_same_v<decltype(m5), std::map<long, const float>>); + static_assert(std::is_same_v<decltype(m5), std::map<long, float>>); - // LWG4223: deduces map<const long&, float&> - //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); - // std::map m6(std::from_range, r3); + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); + std::map m6(std::from_range, r3); + static_assert(std::is_same_v<decltype(m6), std::map<long, float>>); __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); std::map m7(std::from_range, r4); diff --git a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc index f0699e2eefc3..de5e6acb4f24 100644 --- a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc +++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc @@ -210,3 +210,49 @@ test_p1518r2() std::multimap s2(std::move(m), p); check_type<MMap>(s2); } + +struct MyPred +{ + template<typename T, typename U> + bool operator()(T const&, U const&) const; +}; + +template<typename K, typename V> +constexpr bool test_lwg4223() +{ + using KD = std::remove_cv_t<std::remove_reference_t<K>>; + using VD = std::remove_cv_t<std::remove_reference_t<V>>; + using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>; + + std::initializer_list<std::pair<K, V>> il = {}; + Alloc a; + MyPred p; + + // The remove_cvref_t is not applied here. + // static_assert(std::is_same_v< + // decltype(std::multimap(il)), + // std::multimap<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::multimap(il.begin(), il.end())), + std::multimap<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::multimap(il.begin(), il.end(), p)), + std::multimap<KD, VD, MyPred>>); + + static_assert(std::is_same_v< + decltype(std::multimap(il.begin(), il.end(), a)), + std::multimap<KD, VD, std::less<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::multimap(il.begin(), il.end(), p, a)), + std::multimap<KD, VD, MyPred, Alloc>>); + + return true; +} + +static_assert(test_lwg4223<const int, const float>()); +static_assert(test_lwg4223<int&, float&>()); +static_assert(test_lwg4223<int&&, float&&>()); +static_assert(test_lwg4223<const int&, const float&>()); diff --git a/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc index 4a8ea9fec7d7..5907bab9878c 100644 --- a/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc @@ -43,11 +43,11 @@ test_deduction_guide() __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); std::multimap m5(std::from_range, r2); - static_assert(std::is_same_v<decltype(m5), std::multimap<long, const float>>); + static_assert(std::is_same_v<decltype(m5), std::multimap<long, float>>); - // LWG4223: deduces multimap<const long&, float&> - //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); - // std::multimap m6(std::from_range, r3); + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); + std::multimap m6(std::from_range, r3); + static_assert(std::is_same_v<decltype(m6), std::multimap<long, float>>); __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); std::multimap m7(std::from_range, r4); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc index fa182f5866d3..26013da15c2f 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc @@ -190,3 +190,72 @@ test_p1518r2() std::unordered_map s2(std::move(m), p); check_type<UMap>(s2); } + +struct MyHash +{ + template<typename T> + std::size_t operator()(T const&) const; +}; + +struct MyPred +{ + template<typename T, typename U> + bool operator()(T const&, U const&) const; +}; + +template<typename K, typename V> +constexpr bool test_lwg4223() +{ + using KD = std::remove_cv_t<std::remove_reference_t<K>>; + using VD = std::remove_cv_t<std::remove_reference_t<V>>; + using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>; + + std::initializer_list<std::pair<K, V>> il = {}; + Alloc a; + MyHash h; + MyPred p; + + // The remove_cvref_t is not applied here. + // static_assert(std::is_same_v< + // decltype(std::unordered_map(il)), + // std::unordered_map<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end())), + std::unordered_map<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), 0)), + std::unordered_map<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), 0, h)), + std::unordered_map<KD, VD, MyHash>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), 0, h, p)), + std::unordered_map<KD, VD, MyHash, MyPred>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), a)), + std::unordered_map<KD, VD, std::hash<KD>, std::equal_to<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), 0, a)), + std::unordered_map<KD, VD, std::hash<KD>, std::equal_to<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), 0, h, a)), + std::unordered_map<KD, VD, MyHash, std::equal_to<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), 0, h, p, a)), + std::unordered_map<KD, VD, MyHash, MyPred, Alloc>>); + + return true; +} + +static_assert(test_lwg4223<const int, const float>()); +static_assert(test_lwg4223<int&, float&>()); +static_assert(test_lwg4223<int&&, float&&>()); +static_assert(test_lwg4223<const int&, const float&>()); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc index 36efc2de5a39..04479a5e54d8 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc @@ -78,13 +78,11 @@ test_deduction_guide() __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); std::unordered_map m9(std::from_range, r2); - static_assert(std::is_same_v< - decltype(m9), - std::unordered_map<long, const float>>); + static_assert(std::is_same_v<decltype(m9), std::unordered_map<long, float>>); - // LWG4223: deduces map<const long&, float&> - // __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); - // std::unordered_map m10(std::from_range, r3); + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); + std::unordered_map m10(std::from_range, r3); + static_assert(std::is_same_v<decltype(m10), std::unordered_map<long, float>>); __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); std::unordered_map m11(std::from_range, r4); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc index 4de23fe3e791..1db58a04abf8 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc @@ -205,3 +205,72 @@ test_p1518r2() std::unordered_multimap s2(std::move(m), p); check_type<UMMap>(s2); } + +struct MyHash +{ + template<typename T> + std::size_t operator()(T const&) const; +}; + +struct MyPred +{ + template<typename T, typename U> + bool operator()(T const&, U const&) const; +}; + +template<typename K, typename V> +constexpr bool test_lwg4223() +{ + using KD = std::remove_cv_t<std::remove_reference_t<K>>; + using VD = std::remove_cv_t<std::remove_reference_t<V>>; + using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>; + + std::initializer_list<std::pair<K, V>> il = {}; + Alloc a; + MyHash h; + MyPred p; + + // The remove_cvref_t is not applied here. + // static_assert(std::is_same_v< + // decltype(std::unordered_multimap(il)), + // std::unordered_multimap<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end())), + std::unordered_multimap<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), 0)), + std::unordered_multimap<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), 0, h)), + std::unordered_multimap<KD, VD, MyHash>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), 0, h, p)), + std::unordered_multimap<KD, VD, MyHash, MyPred>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), a)), + std::unordered_multimap<KD, VD, std::hash<KD>, std::equal_to<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), 0, a)), + std::unordered_multimap<KD, VD, std::hash<KD>, std::equal_to<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), 0, h, a)), + std::unordered_multimap<KD, VD, MyHash, std::equal_to<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), 0, h, p, a)), + std::unordered_multimap<KD, VD, MyHash, MyPred, Alloc>>); + + return true; +} + +static_assert(test_lwg4223<const int, const float>()); +static_assert(test_lwg4223<int&, float&>()); +static_assert(test_lwg4223<int&&, float&&>()); +static_assert(test_lwg4223<const int&, const float&>()); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc index b551df49f3e7..4567bd8aa914 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc @@ -86,11 +86,13 @@ test_deduction_guide() std::unordered_multimap m9(std::from_range, r2); static_assert(std::is_same_v< decltype(m9), - std::unordered_multimap<long, const float>>); + std::unordered_multimap<long, float>>); - // LWG4223: deduces map<const long&, float&> - // __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); - // std::unordered_multimap m10(std::from_range, r3); + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); + std::unordered_multimap m10(std::from_range, r3); + static_assert(std::is_same_v< + decltype(m10), + std::unordered_multimap<long, float>>); __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); std::unordered_multimap m11(std::from_range, r4);