diff --git a/libstdc++-v3/include/bits/stl_map.h b/libstdc++-v3/include/bits/stl_map.h index cc87f11fb11e..658d58651386 100644 --- a/libstdc++-v3/include/bits/stl_map.h +++ b/libstdc++-v3/include/bits/stl_map.h @@ -154,6 +154,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef __gnu_cxx::__alloc_traits<_Pair_alloc_type> _Alloc_traits; +#if __cplusplus >= 201703L + template> + static constexpr bool __usable_key + = __or_v, + __and_, is_scalar<_Key>>>; +#endif + public: // many of these are specified differently in ISO, but the following are // "functionally equivalent" @@ -574,7 +581,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template std::pair emplace(_Args&&... __args) - { return _M_t._M_emplace_unique(std::forward<_Args>(__args)...); } + { +#if __cplusplus >= 201703L + if constexpr (sizeof...(_Args) == 2) + if constexpr (is_same_v>) + { + auto&& [__a, __v] = pair<_Args&...>(__args...); + if constexpr (__usable_key) + { + const key_type& __k = __a; + iterator __i = lower_bound(__k); + if (__i == end() || key_comp()(__k, (*__i).first)) + { + __i = emplace_hint(__i, std::forward<_Args>(__args)...); + return {__i, true}; + } + return {__i, false}; + } + } +#endif + return _M_t._M_emplace_unique(std::forward<_Args>(__args)...); + } /** * @brief Attempts to build and insert a std::pair into the %map. @@ -814,7 +841,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER __enable_if_t::value, pair> insert(_Pair&& __x) - { return _M_t._M_emplace_unique(std::forward<_Pair>(__x)); } + { +#if __cplusplus >= 201703L + using _P2 = remove_reference_t<_Pair>; + if constexpr (__is_pair<_P2>) + if constexpr (is_same_v>) + if constexpr (__usable_key) + { + const key_type& __k = __x.first; + iterator __i = lower_bound(__k); + if (__i == end() || key_comp()(__k, (*__i).first)) + { + __i = emplace_hint(__i, std::forward<_Pair>(__x)); + return {__i, true}; + } + return {__i, false}; + } +#endif + return _M_t._M_emplace_unique(std::forward<_Pair>(__x)); + } #endif /// @} diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 6081e0c7fe97..5f7b60932e46 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -777,6 +777,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template inline constexpr size_t tuple_size_v> = 2; + + template + inline constexpr bool __is_pair = false; + + template + inline constexpr bool __is_pair> = true; + + template + inline constexpr bool __is_pair> = true; #endif /// @cond undocumented diff --git a/libstdc++-v3/include/bits/uses_allocator_args.h b/libstdc++-v3/include/bits/uses_allocator_args.h index 8b548ff6981d..e1fd7e7d6118 100644 --- a/libstdc++-v3/include/bits/uses_allocator_args.h +++ b/libstdc++-v3/include/bits/uses_allocator_args.h @@ -56,12 +56,6 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION - template - inline constexpr bool __is_pair = false; - template - inline constexpr bool __is_pair> = true; - template - inline constexpr bool __is_pair> = true; template concept _Std_pair = __is_pair<_Tp>; diff --git a/libstdc++-v3/testsuite/23_containers/map/modifiers/emplace/92300.cc b/libstdc++-v3/testsuite/23_containers/map/modifiers/emplace/92300.cc new file mode 100644 index 000000000000..937b4d9a103b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/map/modifiers/emplace/92300.cc @@ -0,0 +1,36 @@ +// { dg-do run { target c++17 } } + +#include +#include + +bool oom = false; + +void* operator new(std::size_t n) +{ + if (oom) + throw std::bad_alloc(); + return std::malloc(n); +} + +void operator delete(void* p) +{ + std::free(p); +} + +void operator delete(void* p, std::size_t) +{ + std::free(p); +} + +int main() +{ + std::map m; + int i = 0; + (void) m[i]; + oom = true; + m.emplace(i, 1); + m.emplace(i, 2L); + const int c = 3; + m.emplace(i, c); + m.emplace((long)i, 4); +} diff --git a/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/92300.cc b/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/92300.cc new file mode 100644 index 000000000000..80abdaf1f30b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/92300.cc @@ -0,0 +1,38 @@ +// { dg-do run { target c++17 } } + +#include +#include + +bool oom = false; + +void* operator new(std::size_t n) +{ + if (oom) + throw std::bad_alloc(); + return std::malloc(n); +} + +void operator delete(void* p) +{ + std::free(p); +} + +void operator delete(void* p, std::size_t) +{ + std::free(p); +} + +int main() +{ + using std::pair; + std::map m; + int i = 0; + (void) m[i]; + oom = true; + m.insert({i, 1}); // insert(value_type&&) + m.insert(pair(i, 2)); // insert(Pair&&) + m.insert(pair(i, 3)); // insert(Pair&&) + m.insert(pair(i, 4L)); // insert(Pair&&) + m.insert(pair(i, 5L)); // insert(Pair&&) + m.insert(pair(i, 6L)); // insert(Pair&&) +}