diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 6fd16419f0c49..1f91b4828d4d3 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -872,6 +872,7 @@ set(files __type_traits/is_trivially_relocatable.h __type_traits/is_unbounded_array.h __type_traits/is_union.h + __type_traits/is_unqualified.h __type_traits/is_unsigned.h __type_traits/is_valid_expansion.h __type_traits/is_void.h diff --git a/libcxx/include/__functional/hash.h b/libcxx/include/__functional/hash.h index 489a6f00b8a3d..83bbf1b5e26c3 100644 --- a/libcxx/include/__functional/hash.h +++ b/libcxx/include/__functional/hash.h @@ -21,6 +21,7 @@ #include <__type_traits/is_enum.h> #include <__type_traits/is_floating_point.h> #include <__type_traits/is_integral.h> +#include <__type_traits/is_unqualified.h> #include <__type_traits/underlying_type.h> #include <__utility/pair.h> #include <__utility/swap.h> @@ -355,7 +356,8 @@ struct __hash_impl { }; template -struct __hash_impl<_Tp, __enable_if_t::value> > : __unary_function<_Tp, size_t> { +struct __hash_impl<_Tp, __enable_if_t::value && __is_unqualified_v<_Tp> > > + : __unary_function<_Tp, size_t> { _LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp __v) const _NOEXCEPT { using type = __underlying_type_t<_Tp>; return hash()(static_cast(__v)); @@ -363,17 +365,21 @@ struct __hash_impl<_Tp, __enable_if_t::value> > : __unary_function< }; template -struct __hash_impl<_Tp, __enable_if_t::value && (sizeof(_Tp) <= sizeof(size_t))> > +struct __hash_impl< + _Tp, + __enable_if_t::value && __is_unqualified_v<_Tp> && (sizeof(_Tp) <= sizeof(size_t))> > : __unary_function<_Tp, size_t> { _LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp __v) const _NOEXCEPT { return static_cast(__v); } }; template -struct __hash_impl<_Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(size_t))> > +struct __hash_impl<_Tp, + __enable_if_t::value && __is_unqualified_v<_Tp> && (sizeof(_Tp) > sizeof(size_t))> > : __scalar_hash<_Tp> {}; template -struct __hash_impl<_Tp, __enable_if_t::value> > : __scalar_hash<_Tp> { +struct __hash_impl<_Tp, __enable_if_t::value && __is_unqualified_v<_Tp> > > + : __scalar_hash<_Tp> { _LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp __v) const _NOEXCEPT { // -0.0 and 0.0 should return same hash if (__v == 0.0f) diff --git a/libcxx/include/__type_traits/is_unqualified.h b/libcxx/include/__type_traits/is_unqualified.h new file mode 100644 index 0000000000000..7970b3611601f --- /dev/null +++ b/libcxx/include/__type_traits/is_unqualified.h @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___TYPE_TRAITS_IS_UNQUALIFIED_H +#define _LIBCPP___TYPE_TRAITS_IS_UNQUALIFIED_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline const bool __is_unqualified_v = __is_same(_Tp, __remove_cvref(_Tp)); + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_IS_UNQUALIFIED_H diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index ee18d04c78d0e..c50c4dd73d4bb 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -335,6 +335,7 @@ module std_core [system] { header "__type_traits/is_union.h" export std_core.type_traits.integral_constant } + module is_unqualified { header "__type_traits/is_unqualified.h" } module is_unsigned { header "__type_traits/is_unsigned.h" export std_core.type_traits.integral_constant diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/enum.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/enum.pass.cpp index fd1fbe5f113ba..05a19329f909a 100644 --- a/libcxx/test/std/utilities/function.objects/unord.hash/enum.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/unord.hash/enum.pass.cpp @@ -21,6 +21,10 @@ #include "test_macros.h" +#if TEST_STD_VER >= 11 +# include "poisoned_hash_helper.h" +#endif + enum class Colors { red, orange, yellow, green, blue, indigo, violet }; enum class Cardinals { zero, one, two, three, five=5 }; enum class LongColors : short { red, orange, yellow, green, blue, indigo, violet }; @@ -33,6 +37,12 @@ template void test() { +#if TEST_STD_VER >= 11 + test_hash_disabled(); + test_hash_disabled(); + test_hash_disabled(); +#endif + typedef std::hash H; #if TEST_STD_VER <= 17 static_assert((std::is_same::value), ""); diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/floating.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/floating.pass.cpp index b8f85e193dc8f..f6c31d068b231 100644 --- a/libcxx/test/std/utilities/function.objects/unord.hash/floating.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/unord.hash/floating.pass.cpp @@ -27,10 +27,20 @@ #include "test_macros.h" +#if TEST_STD_VER >= 11 +# include "poisoned_hash_helper.h" +#endif + template void test() { +#if TEST_STD_VER >= 11 + test_hash_disabled(); + test_hash_disabled(); + test_hash_disabled(); +#endif + typedef std::hash H; #if TEST_STD_VER <= 17 static_assert((std::is_same::value), ""); diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp index 14af7093c1e36..c798b3aa77ea5 100644 --- a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp @@ -26,10 +26,20 @@ #include "test_macros.h" +#if TEST_STD_VER >= 11 +# include "poisoned_hash_helper.h" +#endif + template void test() { +#if TEST_STD_VER >= 11 + test_hash_disabled(); + test_hash_disabled(); + test_hash_disabled(); +#endif + typedef std::hash H; #if TEST_STD_VER <= 17 static_assert((std::is_same::value), "");