diff options
-rw-r--r-- | libcxx/include/__hash_table | 4 | ||||
-rw-r--r-- | libcxx/include/__tree | 2 | ||||
-rw-r--r-- | libcxx/include/map | 12 | ||||
-rw-r--r-- | libcxx/include/set | 12 | ||||
-rw-r--r-- | libcxx/include/unordered_map | 14 | ||||
-rw-r--r-- | libcxx/include/unordered_set | 14 | ||||
-rw-r--r-- | libcxx/test/libcxx/containers/associative/non_const_comparator.fail.cpp | 4 | ||||
-rw-r--r-- | libcxx/test/libcxx/containers/associative/non_const_comparator.pass.cpp | 58 | ||||
-rw-r--r-- | libcxx/test/libcxx/containers/unord/non_const_comparator.fail.cpp | 8 | ||||
-rw-r--r-- | libcxx/test/libcxx/containers/unord/non_const_comparator.pass.cpp | 58 |
10 files changed, 165 insertions, 21 deletions
diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table index c5a9db1dc41..4b04dd62dbb 100644 --- a/libcxx/include/__hash_table +++ b/libcxx/include/__hash_table @@ -875,9 +875,9 @@ struct __enforce_unordered_container_requirements { template <class _Key, class _Hash, class _Equal> #ifndef _LIBCPP_CXX03_LANG _LIBCPP_DIAGNOSE_WARNING(!__invokable<_Equal const&, _Key const&, _Key const&>::value, - "the specified comparator type does not provide a const call operator") + "the specified comparator type does not provide a viable const call operator") _LIBCPP_DIAGNOSE_WARNING(!__invokable<_Hash const&, _Key const&>::value, - "the specified hash functor does not provide a const call operator") + "the specified hash functor does not provide a viable const call operator") #endif typename __enforce_unordered_container_requirements<_Key, _Hash, _Equal>::type __diagnose_unordered_container_requirements(int); diff --git a/libcxx/include/__tree b/libcxx/include/__tree index 9f0931ee940..0aa9bff6151 100644 --- a/libcxx/include/__tree +++ b/libcxx/include/__tree @@ -971,7 +971,7 @@ private: template<class _Tp, class _Compare> #ifndef _LIBCPP_CXX03_LANG _LIBCPP_DIAGNOSE_WARNING(!std::__invokable<_Compare const&, _Tp const&, _Tp const&>::value, - "the specified comparator type does not provide a const call operator") + "the specified comparator type does not provide a viable const call operator") #endif int __diagnose_non_const_comparator(); diff --git a/libcxx/include/map b/libcxx/include/map index e21dd5a8454..a8bf448dd57 100644 --- a/libcxx/include/map +++ b/libcxx/include/map @@ -907,7 +907,6 @@ public: typedef value_type& reference; typedef const value_type& const_reference; - static_assert(sizeof(__diagnose_non_const_comparator<_Key, _Compare>()), ""); static_assert((is_same<typename allocator_type::value_type, value_type>::value), "Allocator::value_type must be same type as value_type"); @@ -1086,6 +1085,11 @@ public: } _LIBCPP_INLINE_VISIBILITY + ~map() { + static_assert(sizeof(__diagnose_non_const_comparator<_Key, _Compare>()), ""); + } + + _LIBCPP_INLINE_VISIBILITY iterator begin() _NOEXCEPT {return __tree_.begin();} _LIBCPP_INLINE_VISIBILITY const_iterator begin() const _NOEXCEPT {return __tree_.begin();} @@ -1638,7 +1642,6 @@ public: typedef value_type& reference; typedef const value_type& const_reference; - static_assert(sizeof(__diagnose_non_const_comparator<_Key, _Compare>()), ""); static_assert((is_same<typename allocator_type::value_type, value_type>::value), "Allocator::value_type must be same type as value_type"); @@ -1818,6 +1821,11 @@ public: } _LIBCPP_INLINE_VISIBILITY + ~multimap() { + static_assert(sizeof(__diagnose_non_const_comparator<_Key, _Compare>()), ""); + } + + _LIBCPP_INLINE_VISIBILITY iterator begin() _NOEXCEPT {return __tree_.begin();} _LIBCPP_INLINE_VISIBILITY const_iterator begin() const _NOEXCEPT {return __tree_.begin();} diff --git a/libcxx/include/set b/libcxx/include/set index 17837228f26..4574f69fa8a 100644 --- a/libcxx/include/set +++ b/libcxx/include/set @@ -450,7 +450,6 @@ public: typedef value_type& reference; typedef const value_type& const_reference; - static_assert(sizeof(__diagnose_non_const_comparator<_Key, _Compare>()), ""); static_assert((is_same<typename allocator_type::value_type, value_type>::value), "Allocator::value_type must be same type as value_type"); @@ -597,6 +596,11 @@ public: #endif // _LIBCPP_CXX03_LANG _LIBCPP_INLINE_VISIBILITY + ~set() { + static_assert(sizeof(__diagnose_non_const_comparator<_Key, _Compare>()), ""); + } + + _LIBCPP_INLINE_VISIBILITY iterator begin() _NOEXCEPT {return __tree_.begin();} _LIBCPP_INLINE_VISIBILITY const_iterator begin() const _NOEXCEPT {return __tree_.begin();} @@ -938,7 +942,6 @@ public: typedef value_type& reference; typedef const value_type& const_reference; - static_assert(sizeof(__diagnose_non_const_comparator<_Key, _Compare>()), ""); static_assert((is_same<typename allocator_type::value_type, value_type>::value), "Allocator::value_type must be same type as value_type"); @@ -1084,6 +1087,11 @@ public: #endif // _LIBCPP_CXX03_LANG _LIBCPP_INLINE_VISIBILITY + ~multiset() { + static_assert(sizeof(__diagnose_non_const_comparator<_Key, _Compare>()), ""); + } + + _LIBCPP_INLINE_VISIBILITY iterator begin() _NOEXCEPT {return __tree_.begin();} _LIBCPP_INLINE_VISIBILITY const_iterator begin() const _NOEXCEPT {return __tree_.begin();} diff --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map index 7ae9805d81d..42057c5d3fd 100644 --- a/libcxx/include/unordered_map +++ b/libcxx/include/unordered_map @@ -852,7 +852,6 @@ public: typedef const value_type& const_reference; static_assert((is_same<value_type, typename allocator_type::value_type>::value), "Invalid allocator::value_type"); - static_assert(sizeof(__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(0)), ""); private: typedef __hash_value_type<key_type, mapped_type> __value_type; @@ -963,7 +962,11 @@ public: const allocator_type& __a) : unordered_map(__il, __n, __hf, key_equal(), __a) {} #endif - // ~unordered_map() = default; + _LIBCPP_INLINE_VISIBILITY + ~unordered_map() { + static_assert(sizeof(__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(0)), ""); + } + _LIBCPP_INLINE_VISIBILITY unordered_map& operator=(const unordered_map& __u) { @@ -1678,7 +1681,6 @@ public: typedef const value_type& const_reference; static_assert((is_same<value_type, typename allocator_type::value_type>::value), "Invalid allocator::value_type"); - static_assert(sizeof(__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(0)), ""); private: typedef __hash_value_type<key_type, mapped_type> __value_type; @@ -1787,7 +1789,11 @@ public: const allocator_type& __a) : unordered_multimap(__il, __n, __hf, key_equal(), __a) {} #endif - // ~unordered_multimap() = default; + _LIBCPP_INLINE_VISIBILITY + ~unordered_multimap() { + static_assert(sizeof(__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(0)), ""); + } + _LIBCPP_INLINE_VISIBILITY unordered_multimap& operator=(const unordered_multimap& __u) { diff --git a/libcxx/include/unordered_set b/libcxx/include/unordered_set index 4cfaa86b883..b32e4cae2cd 100644 --- a/libcxx/include/unordered_set +++ b/libcxx/include/unordered_set @@ -390,7 +390,6 @@ public: typedef const value_type& const_reference; static_assert((is_same<value_type, typename allocator_type::value_type>::value), "Invalid allocator::value_type"); - static_assert(sizeof(__diagnose_unordered_container_requirements<_Value, _Hash, _Pred>(0)), ""); private: typedef __hash_table<value_type, hasher, key_equal, allocator_type> __table; @@ -486,7 +485,11 @@ public: : unordered_set(__il, __n, __hf, key_equal(), __a) {} #endif #endif // _LIBCPP_CXX03_LANG - // ~unordered_set() = default; + _LIBCPP_INLINE_VISIBILITY + ~unordered_set() { + static_assert(sizeof(__diagnose_unordered_container_requirements<_Value, _Hash, _Pred>(0)), ""); + } + _LIBCPP_INLINE_VISIBILITY unordered_set& operator=(const unordered_set& __u) { @@ -990,7 +993,6 @@ public: typedef const value_type& const_reference; static_assert((is_same<value_type, typename allocator_type::value_type>::value), "Invalid allocator::value_type"); - static_assert(sizeof(__diagnose_unordered_container_requirements<_Value, _Hash, _Pred>(0)), ""); private: typedef __hash_table<value_type, hasher, key_equal, allocator_type> __table; @@ -1084,7 +1086,11 @@ public: : unordered_multiset(__il, __n, __hf, key_equal(), __a) {} #endif #endif // _LIBCPP_CXX03_LANG - // ~unordered_multiset() = default; + _LIBCPP_INLINE_VISIBILITY + ~unordered_multiset() { + static_assert(sizeof(__diagnose_unordered_container_requirements<_Value, _Hash, _Pred>(0)), ""); + } + _LIBCPP_INLINE_VISIBILITY unordered_multiset& operator=(const unordered_multiset& __u) { diff --git a/libcxx/test/libcxx/containers/associative/non_const_comparator.fail.cpp b/libcxx/test/libcxx/containers/associative/non_const_comparator.fail.cpp index 432e7c08d14..9a9a1c6d6d1 100644 --- a/libcxx/test/libcxx/containers/associative/non_const_comparator.fail.cpp +++ b/libcxx/test/libcxx/containers/associative/non_const_comparator.fail.cpp @@ -26,8 +26,8 @@ int main(int, char**) { static_assert(!std::__invokable<BadCompare const&, int const&, int const&>::value, ""); static_assert(std::__invokable<BadCompare&, int const&, int const&>::value, ""); - // expected-warning@set:* 2 {{the specified comparator type does not provide a const call operator}} - // expected-warning@map:* 2 {{the specified comparator type does not provide a const call operator}} + // expected-warning@set:* 2 {{the specified comparator type does not provide a viable const call operator}} + // expected-warning@map:* 2 {{the specified comparator type does not provide a viable const call operator}} { using C = std::set<int, BadCompare>; C s; diff --git a/libcxx/test/libcxx/containers/associative/non_const_comparator.pass.cpp b/libcxx/test/libcxx/containers/associative/non_const_comparator.pass.cpp new file mode 100644 index 00000000000..83a1cee1127 --- /dev/null +++ b/libcxx/test/libcxx/containers/associative/non_const_comparator.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 +// REQUIRES: verify-support + +// Test that libc++ does not generate a warning diagnostic about the comparator +// too early for containers of incomplete types. +// +// See PR41360. + +#include <set> +#include <map> +#include <functional> + + +template <template <typename ...> class Container> +void test_set() { + struct KeyBase { }; + struct KeyDerived; // derives from KeyBase, but incomplete at this point + + // Name the type but don't instantiate it. + using C = Container<KeyDerived*, std::less<KeyBase*>>; + + // Instantiate it but don't ODR use any members. + typename C::value_type dummy; (void)dummy; + + // Complete the types. + struct KeyDerived : KeyBase { }; + + C c; // ODR use it, which should be OK +} + +template <template <typename ...> class Container> +void test_map() { + struct Value { }; + struct KeyBase { }; + struct KeyDerived; + using C = Container<KeyDerived*, Value, std::less<KeyBase*>>; + typename C::value_type dummy; (void)dummy; + struct KeyDerived : KeyBase { }; + C c; +} + +int main(int, char**) { + // expected-no-diagnostics + test_set<std::set>(); + test_set<std::multiset>(); + test_map<std::map>(); + test_map<std::multimap>(); + + return 0; +} diff --git a/libcxx/test/libcxx/containers/unord/non_const_comparator.fail.cpp b/libcxx/test/libcxx/containers/unord/non_const_comparator.fail.cpp index 8fa500e45e4..c1027adbc8e 100644 --- a/libcxx/test/libcxx/containers/unord/non_const_comparator.fail.cpp +++ b/libcxx/test/libcxx/containers/unord/non_const_comparator.fail.cpp @@ -33,10 +33,10 @@ int main(int, char**) { static_assert(!std::__invokable<BadEqual const&, int const&, int const&>::value, ""); static_assert(std::__invokable<BadEqual&, int const&, int const&>::value, ""); - // expected-warning@unordered_set:* 2 {{the specified comparator type does not provide a const call operator}} - // expected-warning@unordered_map:* 2 {{the specified comparator type does not provide a const call operator}} - // expected-warning@unordered_set:* 2 {{the specified hash functor does not provide a const call operator}} - // expected-warning@unordered_map:* 2 {{the specified hash functor does not provide a const call operator}} + // expected-warning@unordered_set:* 2 {{the specified comparator type does not provide a viable const call operator}} + // expected-warning@unordered_map:* 2 {{the specified comparator type does not provide a viable const call operator}} + // expected-warning@unordered_set:* 2 {{the specified hash functor does not provide a viable const call operator}} + // expected-warning@unordered_map:* 2 {{the specified hash functor does not provide a viable const call operator}} { using C = std::unordered_set<int, BadHash, BadEqual>; diff --git a/libcxx/test/libcxx/containers/unord/non_const_comparator.pass.cpp b/libcxx/test/libcxx/containers/unord/non_const_comparator.pass.cpp new file mode 100644 index 00000000000..e2eeda53964 --- /dev/null +++ b/libcxx/test/libcxx/containers/unord/non_const_comparator.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 +// REQUIRES: verify-support + +// Test that libc++ does not generate a warning diagnostic about the comparator +// or the hasher too early for containers of incomplete types. +// +// See PR41360. + +#include <unordered_set> +#include <unordered_map> +#include <functional> + + +template <template <typename ...> class Container> +void test_set() { + struct KeyBase { }; + struct KeyDerived; // derives from KeyBase, but incomplete at this point + + // Name the type but don't instantiate it. + using C = Container<KeyDerived*, std::hash<KeyBase*>, std::equal_to<KeyBase*>>; + + // Instantiate it but don't ODR use any members. + typename C::value_type dummy; (void)dummy; + + // Complete the types. + struct KeyDerived : KeyBase { }; + + C c; // ODR use it, which should be OK +} + +template <template <typename ...> class Container> +void test_map() { + struct Value { }; + struct KeyBase { }; + struct KeyDerived; + using C = Container<KeyDerived*, Value, std::hash<KeyBase*>, std::equal_to<KeyBase*>>; + typename C::value_type dummy; (void)dummy; + struct KeyDerived : KeyBase { }; + C c; +} + +int main(int, char**) { + // expected-no-disagnostics + test_set<std::unordered_set>(); + test_set<std::unordered_multiset>(); + test_map<std::unordered_map>(); + test_map<std::unordered_multimap>(); + + return 0; +} |