diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 2820b46167b..6e404b228e5 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,32 @@ 2019-05-17 Jonathan Wakely + PR libstdc++/85965 + * include/bits/hashtable.h (_Hashtable::~_Hashtable()): Remove static + assertions from the destructor. + * include/bits/hashtable_policy.h (_Hash_code_base::_M_hash_code): + Move static_assert for hash function to here. + (_Hash_table_base::_M_equals): Move static_assert for equality + predicate to here. + * include/bits/stl_tree.h (_Rb_tree::_S_value(_Const_Link_type)): + Remove. + (_Rb_tree::_S_key(_Const_Link_type)): Move assertions here. Access + the value directly instead of calling _S_value. + (_Rb_tree::_S_value(_Const_Base_ptr)): Remove. + (_Rb_tree::_S_key(_Const_Base_ptr)): Do downcast and forward to + _S_key(_Const_Link_type). + * testsuite/23_containers/set/85965.cc: Check construction, + destruction, assignment and size() do not trigger the assertions. + * testsuite/23_containers/unordered_set/85965.cc: Likewise. + * testsuite/23_containers/map/48101_neg.cc: Call find and adjust + expected errors. + * testsuite/23_containers/multimap/48101_neg.cc: Likewise. + * testsuite/23_containers/multiset/48101_neg.cc: Likewise. + * testsuite/23_containers/set/48101_neg.cc: Likewise. + * testsuite/23_containers/unordered_map/48101_neg.cc: Likewise. + * testsuite/23_containers/unordered_multimap/48101_neg.cc: Likewise. + * testsuite/23_containers/unordered_multiset/48101_neg.cc: Likewise. + * testsuite/23_containers/unordered_set/48101_neg.cc: Likewise. + * include/bits/invoke.h [__cplusplus < 201703L] (__invoke_r): Use _GLIBCXX14_CONSTEXPR because void functions cannot be constexpr in C++11. diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h index 2e8aeb7e4d4..ab24b5bb537 100644 --- a/libstdc++-v3/include/bits/hashtable.h +++ b/libstdc++-v3/include/bits/hashtable.h @@ -1351,12 +1351,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { clear(); _M_deallocate_buckets(); - - static_assert(__is_invocable{}, - "hash function must be invocable with an argument of key type"); - static_assert(__is_invocable{}, - "key equality predicate must be invocable with two arguments of " - "key type"); } template{}, + "hash function must be invocable with an argument of key type"); + return _M_h1()(__k); + } std::size_t _M_bucket_index(const _Key&, __hash_code __c, std::size_t __n) const @@ -1363,7 +1367,11 @@ namespace __detail __hash_code _M_hash_code(const _Key& __k) const - { return _M_h1()(__k); } + { + static_assert(__is_invocable{}, + "hash function must be invocable with an argument of key type"); + return _M_h1()(__k); + } std::size_t _M_bucket_index(const _Key&, __hash_code __c, @@ -1783,6 +1791,9 @@ namespace __detail bool _M_equals(const _Key& __k, __hash_code __c, __node_type* __n) const { + static_assert(__is_invocable{}, + "key equality predicate must be invocable with two arguments of " + "key type"); return _Equal_hash_code<__node_type>::_S_equals(__c, *__n) && _M_eq()(__k, this->_M_extract()(__n->_M_v())); } diff --git a/libstdc++-v3/include/bits/stl_tree.h b/libstdc++-v3/include/bits/stl_tree.h index 00e4a0cccbf..940155d8a32 100644 --- a/libstdc++-v3/include/bits/stl_tree.h +++ b/libstdc++-v3/include/bits/stl_tree.h @@ -759,13 +759,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_end() const _GLIBCXX_NOEXCEPT { return &this->_M_impl._M_header; } - static const_reference - _S_value(_Const_Link_type __x) - { return *__x->_M_valptr(); } - static const _Key& _S_key(_Const_Link_type __x) - { return _KeyOfValue()(_S_value(__x)); } + { +#if __cplusplus >= 201103L + // If we're asking for the key we're presumably using the comparison + // object, and so this is a good place to sanity check it. + static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{}, + "comparison object must be invocable " + "with two arguments of key type"); +# if __cplusplus >= 201703L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2542. Missing const requirements for associative containers + if constexpr (__is_invocable<_Compare&, const _Key&, const _Key&>{}) + static_assert( + is_invocable_v, + "comparison object must be invocable as const"); +# endif // C++17 +#endif // C++11 + + return _KeyOfValue()(*__x->_M_valptr()); + } static _Link_type _S_left(_Base_ptr __x) _GLIBCXX_NOEXCEPT @@ -783,13 +797,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _S_right(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT { return static_cast<_Const_Link_type>(__x->_M_right); } - static const_reference - _S_value(_Const_Base_ptr __x) - { return *static_cast<_Const_Link_type>(__x)->_M_valptr(); } - static const _Key& _S_key(_Const_Base_ptr __x) - { return _KeyOfValue()(_S_value(__x)); } + { return _S_key(static_cast<_Const_Link_type>(__x)); } static _Base_ptr _S_minimum(_Base_ptr __x) _GLIBCXX_NOEXCEPT @@ -974,21 +984,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif ~_Rb_tree() _GLIBCXX_NOEXCEPT - { - _M_erase(_M_begin()); - -#if __cplusplus >= 201103L - static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{}, - "comparison object must be invocable " - "with two arguments of key type"); -# if __cplusplus >= 201703L - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 2542. Missing const requirements for associative containers - static_assert(is_invocable_v, - "comparison object must be invocable as const"); -# endif // C++17 -#endif // C++11 - } + { _M_erase(_M_begin()); } _Rb_tree& operator=(const _Rb_tree& __x); diff --git a/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc index 355222058ff..8a7429c85a8 100644 --- a/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc @@ -24,9 +24,13 @@ void test01() { std::map> c; + c.find(1); // { dg-error "here" } std::map> c2; + c2.find(2); // { dg-error "here" } } // { dg-error "_Compare = std::less" "" { target *-*-* } 0 } // { dg-error "_Compare = std::allocator" "" { target *-*-* } 0 } // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 } +// { dg-prune-output "no match for call" } +// { dg-prune-output "invalid conversion" } diff --git a/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc index 5f53ccee168..7bd56cc9c73 100644 --- a/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc @@ -24,9 +24,13 @@ void test01() { std::multimap> c; + c.find(1); // { dg-error "here" } std::multimap> c2; + c2.find(2); // { dg-error "here" } } // { dg-error "_Compare = std::less" "" { target *-*-* } 0 } // { dg-error "_Compare = std::allocator" "" { target *-*-* } 0 } // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 } +// { dg-prune-output "no match for call" } +// { dg-prune-output "invalid conversion" } diff --git a/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc index 71b90e80951..f13aa098976 100644 --- a/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc @@ -24,9 +24,12 @@ test01() { std::multiset c; // { dg-error "here" } std::multiset> c2; + c2.find(2); // { dg-error "here" } } // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 } // { dg-prune-output "std::allocator<.* has no member named " } // { dg-prune-output "must have the same value_type as its allocator" } +// { dg-prune-output "no match for call" } +// { dg-prune-output "invalid conversion" } diff --git a/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc index e58c0627eb8..4ede0421d90 100644 --- a/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc @@ -24,9 +24,12 @@ test01() { std::set c; // { dg-error "here" } std::set> c2; + c2.find(2); // { dg-error "here" } } // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 } // { dg-prune-output "std::allocator<.* has no member named " } // { dg-prune-output "must have the same value_type as its allocator" } +// { dg-prune-output "no match for call" } +// { dg-prune-output "invalid conversion" } diff --git a/libstdc++-v3/testsuite/23_containers/set/85965.cc b/libstdc++-v3/testsuite/23_containers/set/85965.cc index 54d501f6c4f..7d8f2167519 100644 --- a/libstdc++-v3/testsuite/23_containers/set/85965.cc +++ b/libstdc++-v3/testsuite/23_containers/set/85965.cc @@ -27,3 +27,12 @@ struct Foo // PR libstdc++/85965 std::set> s; }; + +std::size_t +test01(std::set> s) +{ + // these operations should not require the comparison object + auto copy = s; + copy = s; + return s.size(); +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/48101_neg.cc index 6c3092554f3..8d823dfa476 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/48101_neg.cc @@ -24,8 +24,10 @@ test01() { using namespace std; unordered_map, hash> c2; + c2.find(2); // { dg-error "here" } } // { dg-error "hash function must be invocable" "" { target *-*-* } 0 } // { dg-error "key equality predicate must be invocable" "" { target *-*-* } 0 } // { dg-prune-output "use of deleted function" } +// { dg-prune-output "no match for call" } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/48101_neg.cc index f5de313a8f1..a81615b3607 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/48101_neg.cc @@ -24,8 +24,10 @@ test01() { using namespace std; unordered_multimap, hash> c2; + c2.find(2); // { dg-error "here" } } // { dg-error "hash function must be invocable" "" { target *-*-* } 0 } // { dg-error "key equality predicate must be invocable" "" { target *-*-* } 0 } // { dg-prune-output "use of deleted function" } +// { dg-prune-output "no match for call" } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/48101_neg.cc index d4e479aaf97..03ddb898d6c 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/48101_neg.cc @@ -25,6 +25,7 @@ test01() using namespace std; unordered_multiset> c; // { dg-error "here" } unordered_multiset, hash> c2; + c2.find(2); // { dg-error "here" } } // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } @@ -32,3 +33,4 @@ test01() // { dg-error "key equality predicate must be invocable" "" { target *-*-* } 0 } // { dg-prune-output "use of deleted function" } // { dg-prune-output "must have the same value_type as its allocator" } +// { dg-prune-output "no match for call" } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/48101_neg.cc index c7e27c53690..e79d3769248 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_set/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/48101_neg.cc @@ -25,6 +25,7 @@ test01() using namespace std; unordered_set> c; // { dg-error "here" } unordered_set, hash> c2; + c2.find(2); // { dg-error "here" } } // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } @@ -32,3 +33,4 @@ test01() // { dg-error "key equality predicate must be invocable" "" { target *-*-* } 0 } // { dg-prune-output "use of deleted function" } // { dg-prune-output "must have the same value_type as its allocator" } +// { dg-prune-output "no match for call" } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/85965.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/85965.cc index 8b90b369901..8c48fa2a978 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_set/85965.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/85965.cc @@ -27,3 +27,12 @@ struct Foo // PR libstdc++/85965 std::unordered_set, std::hash> u; }; + +std::size_t +test01(std::unordered_set, std::hash> s) +{ + // these operations should not require the comparison object + auto copy = s; + copy = s; + return s.size(); +}