Author: ericwf Date: Tue Feb 28 20:02:28 2017 New Revision: 296565 URL: http://llvm.org/viewvc/llvm-project?rev=296565&view=rev Log: Improve diagnostics when an invalid hash is used in an unordered container.
This patch adds a static assertion that the specified hash meets the requirements of an enabled hash, and it ensures that the static assertion is evaluated before __compressed_pair is instantiated. That way the static assertion diagnostic is emitted first. Added: libcxx/trunk/test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp Modified: libcxx/trunk/include/__hash_table Modified: libcxx/trunk/include/__hash_table URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__hash_table?rev=296565&r1=296564&r2=296565&view=diff ============================================================================== --- libcxx/trunk/include/__hash_table (original) +++ libcxx/trunk/include/__hash_table Tue Feb 28 20:02:28 2017 @@ -871,11 +871,20 @@ public: template <class _Key, class _Hash, class _Equal, class _Alloc> struct __diagnose_hash_table_helper { static constexpr bool __trigger_diagnostics() - _LIBCPP_DIAGNOSE_WARNING(!__invokable<_Hash const&, _Key const&>::value, - "the specified hash functor does not provide a const call operator") - _LIBCPP_DIAGNOSE_WARNING(!__invokable<_Equal const&, _Key const&, _Key const&>::value, - "the specified comparator type does not provide a const call operator") - { return true; } + _LIBCPP_DIAGNOSE_WARNING(__has_enabled_hash<_Key, _Hash>::value + && !__invokable<_Hash const&, _Key const&>::value, + "the specified hash functor does not provide a const call operator") + _LIBCPP_DIAGNOSE_WARNING(is_copy_constructible<_Equal>::value + && !__invokable<_Equal const&, _Key const&, _Key const&>::value, + "the specified comparator type does not provide a const call operator") + { + static_assert(__has_enabled_hash<_Key, _Hash>::value, + "the specified hash functor does not meet the requirements for an " + "enabled hash"); + static_assert(is_copy_constructible<_Equal>::value, + "the specified comparator is required to be copy constructible"); + return true; + } }; template <class _Key, class _Value, class _Hash, class _Equal, class _Alloc> @@ -951,6 +960,10 @@ private: typedef allocator_traits<__pointer_allocator> __pointer_alloc_traits; typedef typename __bucket_list_deleter::pointer __node_pointer_pointer; +#ifndef _LIBCPP_CXX03_LANG + static_assert(__diagnose_hash_table_helper<_Tp, _Hash, _Equal, _Alloc>::__trigger_diagnostics(), ""); +#endif + // --- Member data begin --- __bucket_list __bucket_list_; __compressed_pair<__first_node, __node_allocator> __p1_; @@ -1482,13 +1495,13 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc> template <class _Tp, class _Hash, class _Equal, class _Alloc> __hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table() { +#if defined(_LIBCPP_CXX03_LANG) static_assert((is_copy_constructible<key_equal>::value), "Predicate must be copy-constructible."); static_assert((is_copy_constructible<hasher>::value), "Hasher must be copy-constructible."); -#ifndef _LIBCPP_CXX03_LANG - static_assert(__diagnose_hash_table_helper<_Tp, _Hash, _Equal, _Alloc>::__trigger_diagnostics(), ""); #endif + __deallocate_node(__p1_.first().__next_); #if _LIBCPP_DEBUG_LEVEL >= 2 __get_db()->__erase_c(this); Added: libcxx/trunk/test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp?rev=296565&view=auto ============================================================================== --- libcxx/trunk/test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp (added) +++ libcxx/trunk/test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp Tue Feb 28 20:02:28 2017 @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 +// REQUIRES: diagnose-if-support + +// <unordered_set> + +// Test that we generate a reasonable diagnostic when the specified hash is +// not enabled. + +#include <unordered_set> +#include <utility> + +using VT = std::pair<int, int>; +using Set = std::unordered_set<VT>; + +int main() { + + Set s; // expected-error@__hash_table:* {{the specified hash functor does not meet the requirements for an enabled hash}} + + // FIXME: It would be great to suppress the below diagnostic all together. + // but for now it's sufficient that it appears last. However there is + // currently no way to test the order diagnostics are issued. + // expected-error@memory:* {{call to implicitly-deleted default constructor of 'std::__1::hash<std::__1::pair<int, int> >'}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits