From 9d3d032c7d9686fbd31c776f65155367d3e19dcd Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Thu, 6 Mar 2014 04:11:10 +0000 Subject: [PATCH] Do not derive __gnu_cxx::hash from std::hash. Instead, define explicit specializations for the basic types listed in the SGI documentation. This solves two problems: 1) Helps avoid silent ODR violations caused by the absence of a user-supplied __gnu_cxx::hash specialization in cases where a std::hash specialization exists (e.g. for std::string). 2) __gnu_cxx::hash semantics are slightly different to those of std::hash (for example, the former may dereference a pointer argument) so it is inappropriate for __gnu_cxx::hash to receive std::hash specializations by default. Differential Revision: http://llvm-reviews.chandlerc.com/D2747 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@203070 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/ext/__hash | 93 ++++++++++++++++++- test/extensions/hash/specializations.fail.cpp | 17 ++++ test/extensions/hash/specializations.pass.cpp | 29 ++++++ test/extensions/nothing_to_do.pass.cpp | 12 +++ 4 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 test/extensions/hash/specializations.fail.cpp create mode 100644 test/extensions/hash/specializations.pass.cpp create mode 100644 test/extensions/nothing_to_do.pass.cpp diff --git a/include/ext/__hash b/include/ext/__hash index c0523cce4..5675d5405 100644 --- a/include/ext/__hash +++ b/include/ext/__hash @@ -19,8 +19,7 @@ namespace __gnu_cxx { using namespace std; -template struct _LIBCPP_TYPE_VIS_ONLY hash : public std::hash<_Tp> - { }; +template struct _LIBCPP_TYPE_VIS_ONLY hash { }; template <> struct _LIBCPP_TYPE_VIS_ONLY hash : public unary_function @@ -41,6 +40,96 @@ template <> struct _LIBCPP_TYPE_VIS_ONLY hash return __do_string_hash(__c, __c + strlen(__c)); } }; + +template <> struct _LIBCPP_TYPE_VIS_ONLY hash + : public unary_function +{ + _LIBCPP_INLINE_VISIBILITY + size_t operator()(char __c) const _NOEXCEPT + { + return __c; + } +}; + +template <> struct _LIBCPP_TYPE_VIS_ONLY hash + : public unary_function +{ + _LIBCPP_INLINE_VISIBILITY + size_t operator()(signed char __c) const _NOEXCEPT + { + return __c; + } +}; + +template <> struct _LIBCPP_TYPE_VIS_ONLY hash + : public unary_function +{ + _LIBCPP_INLINE_VISIBILITY + size_t operator()(unsigned char __c) const _NOEXCEPT + { + return __c; + } +}; + +template <> struct _LIBCPP_TYPE_VIS_ONLY hash + : public unary_function +{ + _LIBCPP_INLINE_VISIBILITY + size_t operator()(short __c) const _NOEXCEPT + { + return __c; + } +}; + +template <> struct _LIBCPP_TYPE_VIS_ONLY hash + : public unary_function +{ + _LIBCPP_INLINE_VISIBILITY + size_t operator()(unsigned short __c) const _NOEXCEPT + { + return __c; + } +}; + +template <> struct _LIBCPP_TYPE_VIS_ONLY hash + : public unary_function +{ + _LIBCPP_INLINE_VISIBILITY + size_t operator()(int __c) const _NOEXCEPT + { + return __c; + } +}; + +template <> struct _LIBCPP_TYPE_VIS_ONLY hash + : public unary_function +{ + _LIBCPP_INLINE_VISIBILITY + size_t operator()(unsigned int __c) const _NOEXCEPT + { + return __c; + } +}; + +template <> struct _LIBCPP_TYPE_VIS_ONLY hash + : public unary_function +{ + _LIBCPP_INLINE_VISIBILITY + size_t operator()(long __c) const _NOEXCEPT + { + return __c; + } +}; + +template <> struct _LIBCPP_TYPE_VIS_ONLY hash + : public unary_function +{ + _LIBCPP_INLINE_VISIBILITY + size_t operator()(unsigned long __c) const _NOEXCEPT + { + return __c; + } +}; } #endif // _LIBCPP_EXT_HASH diff --git a/test/extensions/hash/specializations.fail.cpp b/test/extensions/hash/specializations.fail.cpp new file mode 100644 index 000000000..8eeffb580 --- /dev/null +++ b/test/extensions/hash/specializations.fail.cpp @@ -0,0 +1,17 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +int main() +{ + assert(__gnu_cxx::hash()(std::string()) == 0); // error +} diff --git a/test/extensions/hash/specializations.pass.cpp b/test/extensions/hash/specializations.pass.cpp new file mode 100644 index 000000000..884614ec8 --- /dev/null +++ b/test/extensions/hash/specializations.pass.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +int main() +{ + char str[] = "test"; + assert(__gnu_cxx::hash()("test") == + std::hash()("test")); + assert(__gnu_cxx::hash()(str) == std::hash()("test")); + assert(__gnu_cxx::hash()(42) == 42); + assert(__gnu_cxx::hash()(42) == 42); + assert(__gnu_cxx::hash()(42) == 42); + assert(__gnu_cxx::hash()(42) == 42); + assert(__gnu_cxx::hash()(42) == 42); + assert(__gnu_cxx::hash()(42) == 42); + assert(__gnu_cxx::hash()(42) == 42); + assert(__gnu_cxx::hash()(42) == 42); + assert(__gnu_cxx::hash()(42) == 42); +} diff --git a/test/extensions/nothing_to_do.pass.cpp b/test/extensions/nothing_to_do.pass.cpp new file mode 100644 index 000000000..b58f5c55b --- /dev/null +++ b/test/extensions/nothing_to_do.pass.cpp @@ -0,0 +1,12 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +int main() +{ +}