[libcxx-commits] [libcxx] [libc++] Work around namespace visibility annotations bleeding into user code (PR #141067)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Thu May 22 06:55:59 PDT 2025
https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/141067
`[[gnu::visibility("hidden")]]` applied to the namespace scope can bleed into user-defined specializations of `std::hash` in some cases. This works around the issue until all of our supported compilers are fixed.
>From 04ee4b9de6ebbb45759f58923dbe2a42b4718b1d Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 22 May 2025 15:51:47 +0200
Subject: [PATCH] [libc++] Work around namespace visibility annotations
bleeding into user code
---
libcxx/include/__functional/hash.h | 12 +++++--
libcxx/include/__fwd/functional.h | 12 +++++--
libcxx/include/bitset | 5 ---
libcxx/include/typeindex | 4 +--
.../default_visibility.defined.sh.cpp | 31 +++++++++++++++++++
.../unord.hash/default_visibility.fwd.sh.cpp | 31 +++++++++++++++++++
6 files changed, 81 insertions(+), 14 deletions(-)
create mode 100644 libcxx/test/libcxx/utilities/function.objects/unord.hash/default_visibility.defined.sh.cpp
create mode 100644 libcxx/test/libcxx/utilities/function.objects/unord.hash/default_visibility.fwd.sh.cpp
diff --git a/libcxx/include/__functional/hash.h b/libcxx/include/__functional/hash.h
index 1056734d20db5..6446172139dcb 100644
--- a/libcxx/include/__functional/hash.h
+++ b/libcxx/include/__functional/hash.h
@@ -517,9 +517,6 @@ struct __enum_hash<_Tp, false> {
__enum_hash& operator=(__enum_hash const&) = delete;
};
-template <class _Tp>
-struct hash : public __enum_hash<_Tp> {};
-
#if _LIBCPP_STD_VER >= 17
template <>
@@ -555,4 +552,13 @@ using __enable_hash_helper _LIBCPP_NODEBUG = _Type;
_LIBCPP_END_NAMESPACE_STD
+// Work around the visibility on a namespace bleed into user specializations.
+// TODO: Remove this workaround once all supported compilers are fixed
+namespace std {
+inline namespace _LIBCPP_ABI_NAMESPACE {
+template <class _Tp>
+struct hash : public __enum_hash<_Tp> {};
+} // namespace _LIBCPP_ABI_NAMESPACE
+} // namespace std
+
#endif // _LIBCPP___FUNCTIONAL_HASH_H
diff --git a/libcxx/include/__fwd/functional.h b/libcxx/include/__fwd/functional.h
index a8c602417b981..94dad8de80e56 100644
--- a/libcxx/include/__fwd/functional.h
+++ b/libcxx/include/__fwd/functional.h
@@ -15,6 +15,15 @@
# pragma GCC system_header
#endif
+// Work around the visibility on a namespace bleed into user specializations.
+// TODO: Remove this workaround once all supported compilers are fixed
+namespace std {
+inline namespace _LIBCPP_ABI_NAMESPACE {
+template <class>
+struct hash;
+} // namespace _LIBCPP_ABI_NAMESPACE
+} // namespace std
+
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 14
@@ -24,9 +33,6 @@ template <class _Tp>
#endif
struct less;
-template <class>
-struct hash;
-
template <class>
class reference_wrapper;
diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index eee5a51a39e24..f7eeb87b72f14 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -641,11 +641,6 @@ inline _LIBCPP_CONSTEXPR __bitset<0, 0>::__bitset() _NOEXCEPT {}
inline _LIBCPP_CONSTEXPR __bitset<0, 0>::__bitset(unsigned long long) _NOEXCEPT {}
-template <size_t _Size>
-class bitset;
-template <size_t _Size>
-struct hash<bitset<_Size> >;
-
template <size_t _Size>
class bitset : private __bitset<_Size == 0 ? 0 : (_Size - 1) / (sizeof(size_t) * CHAR_BIT) + 1, _Size> {
public:
diff --git a/libcxx/include/typeindex b/libcxx/include/typeindex
index e32cb074318b6..6a39af8cbcbd8 100644
--- a/libcxx/include/typeindex
+++ b/libcxx/include/typeindex
@@ -50,6 +50,7 @@ struct hash<type_index>
#else
# include <__config>
# include <__functional/unary_function.h>
+# include <__fwd/functional.h>
# include <typeinfo>
# include <version>
@@ -90,9 +91,6 @@ public:
_LIBCPP_HIDE_FROM_ABI const char* name() const _NOEXCEPT { return __t_->name(); }
};
-template <class _Tp>
-struct hash;
-
template <>
struct hash<type_index> : public __unary_function<type_index, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(type_index __index) const _NOEXCEPT { return __index.hash_code(); }
diff --git a/libcxx/test/libcxx/utilities/function.objects/unord.hash/default_visibility.defined.sh.cpp b/libcxx/test/libcxx/utilities/function.objects/unord.hash/default_visibility.defined.sh.cpp
new file mode 100644
index 0000000000000..b4d88a55a032c
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/function.objects/unord.hash/default_visibility.defined.sh.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Ensure that user specializations of std::hash have default visibility
+
+// RUN: %{cxx} %s %{flags} %{compile_flags} %{link_flags} -DSHARED -fPIC -shared -o %t.shared_lib
+// RUN: %{build} %t.shared_lib
+// RUN: %{run}
+
+#include <__functional/hash.h>
+
+struct S {};
+
+template <>
+struct std::hash<S> {
+ void operator()();
+};
+
+#ifdef SHARED
+void std::hash<S>::operator()() {}
+#else
+int main(int, char**) {
+ std::hash<S>()();
+ return 0;
+}
+#endif
diff --git a/libcxx/test/libcxx/utilities/function.objects/unord.hash/default_visibility.fwd.sh.cpp b/libcxx/test/libcxx/utilities/function.objects/unord.hash/default_visibility.fwd.sh.cpp
new file mode 100644
index 0000000000000..814778b94c296
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/function.objects/unord.hash/default_visibility.fwd.sh.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Ensure that user specializations of std::hash have default visibility
+
+// RUN: %{cxx} %s %{flags} %{compile_flags} %{link_flags} -DSHARED -fPIC -shared -o %t.shared_lib
+// RUN: %{build} %t.shared_lib
+// RUN: %{run}
+
+#include <__fwd/functional.h>
+
+struct S {};
+
+template <>
+struct std::hash<S> {
+ void operator()();
+};
+
+#ifdef SHARED
+void std::hash<S>::operator()() {}
+#else
+int main(int, char**) {
+ std::hash<S>()();
+ return 0;
+}
+#endif
More information about the libcxx-commits
mailing list