[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
Sun May 25 09:24:57 PDT 2025


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/141067

>From 23c8f511c3e061f6d5eb967668af9ddb63ef1a8a 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         | 33 +++++++++++++++++++
 .../unord.hash/default_visibility.fwd.sh.cpp  | 33 +++++++++++++++++++
 6 files changed, 85 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..c58ba3e16caac
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/function.objects/unord.hash/default_visibility.defined.sh.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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}
+
+// XFAIL: FROZEN-CXX03-HEADERS-FIXME
+
+#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..8631019965b0f
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/function.objects/unord.hash/default_visibility.fwd.sh.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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}
+
+// XFAIL: FROZEN-CXX03-HEADERS-FIXME
+
+#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