Skip to content

Commit 5aa6093

Browse files
committed
Patching in snapshot of PR pybind#4319
1 parent 3163ae2 commit 5aa6093

7 files changed

Lines changed: 107 additions & 2 deletions

File tree

docs/classes.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ interactive Python session demonstrating this example is shown below:
5858
Static member functions can be bound in the same way using
5959
:func:`class_::def_static`.
6060

61+
.. note::
62+
63+
Binding C++ types in unnamed namespaces (also known as anonymous namespaces)
64+
works reliably only with GCC and MSVC, but not with CLANG, or if libc++ is used.
65+
See `#4319 <https://github.com/pybind/pybind11/pull/4319>`_ for background.
66+
If portability is a concern, it is therefore not recommended to bind C++
67+
types in unnamed namespaces. It will be safest to manually pick unique
68+
namespace names.
69+
6170
Keyword and default arguments
6271
=============================
6372
It is possible to specify keyword and default arguments using the syntax

include/pybind11/detail/internals.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
/// further ABI-incompatible changes may be made before the ABI is officially
3535
/// changed to the new version.
3636
#ifndef PYBIND11_INTERNALS_VERSION
37-
# define PYBIND11_INTERNALS_VERSION 4
37+
# define PYBIND11_INTERNALS_VERSION 5
3838
#endif
3939

4040
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
@@ -114,7 +114,7 @@ inline void tls_replace_value(PYBIND11_TLS_KEY_REF key, void *value) {
114114
// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name,
115115
// which works. If not under a known-good stl, provide our own name-based hash and equality
116116
// functions that use the type name.
117-
#if defined(__GLIBCXX__)
117+
#if !defined(_LIBCPP_VERSION)
118118
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; }
119119
using type_hash = std::hash<std::type_index>;
120120
using type_equal_to = std::equal_to<std::type_index>;

tests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ set(PYBIND11_TEST_FILES
156156
test_tagbased_polymorphic
157157
test_thread
158158
test_union
159+
test_unnamed_namespace_a
160+
test_unnamed_namespace_b
159161
test_virtual_functions)
160162

161163
# Invoking cmake with something like:

tests/test_unnamed_namespace_a.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "pybind11_tests.h"
2+
3+
namespace {
4+
struct any_struct {};
5+
} // namespace
6+
7+
TEST_SUBMODULE(unnamed_namespace_a, m) {
8+
if (py::detail::get_type_info(typeid(any_struct)) == nullptr) {
9+
py::class_<any_struct>(m, "unnamed_namespace_a_any_struct");
10+
} else {
11+
m.attr("unnamed_namespace_a_any_struct") = py::none();
12+
}
13+
m.attr("defined___clang__") =
14+
#if defined(__clang__)
15+
true;
16+
#else
17+
false;
18+
#endif
19+
m.attr("defined__LIBCPP_VERSION") =
20+
#if defined(_LIBCPP_VERSION)
21+
true;
22+
#else
23+
false;
24+
#endif
25+
}

tests/test_unnamed_namespace_a.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import pytest
2+
3+
from pybind11_tests import unnamed_namespace_a as m
4+
from pybind11_tests import unnamed_namespace_b as mb
5+
6+
7+
@pytest.mark.xfail(
8+
"m.defined___clang__ or m.defined__LIBCPP_VERSION",
9+
reason="Known issues: https://github.com/pybind/pybind11/pull/4319",
10+
strict=False,
11+
)
12+
def test_have_class_any_struct():
13+
assert m.unnamed_namespace_a_any_struct is not None
14+
15+
16+
def test_have_at_least_one_class_any_struct():
17+
assert (
18+
m.unnamed_namespace_a_any_struct is not None
19+
or mb.unnamed_namespace_b_any_struct is not None
20+
)
21+
22+
23+
@pytest.mark.xfail(
24+
"m.defined___clang__ or m.defined__LIBCPP_VERSION",
25+
reason="Known issues: https://github.com/pybind/pybind11/pull/4319",
26+
strict=True,
27+
)
28+
def test_have_both_class_any_struct():
29+
assert (
30+
m.unnamed_namespace_a_any_struct is not None
31+
and mb.unnamed_namespace_b_any_struct is not None
32+
)

tests/test_unnamed_namespace_b.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "pybind11_tests.h"
2+
3+
namespace {
4+
struct any_struct {};
5+
} // namespace
6+
7+
TEST_SUBMODULE(unnamed_namespace_b, m) {
8+
if (py::detail::get_type_info(typeid(any_struct)) == nullptr) {
9+
py::class_<any_struct>(m, "unnamed_namespace_b_any_struct");
10+
} else {
11+
m.attr("unnamed_namespace_b_any_struct") = py::none();
12+
}
13+
m.attr("defined___clang__") =
14+
#if defined(__clang__)
15+
true;
16+
#else
17+
false;
18+
#endif
19+
m.attr("defined__LIBCPP_VERSION") =
20+
#if defined(_LIBCPP_VERSION)
21+
true;
22+
#else
23+
false;
24+
#endif
25+
}

tests/test_unnamed_namespace_b.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import pytest
2+
3+
from pybind11_tests import unnamed_namespace_b as m
4+
5+
6+
@pytest.mark.xfail(
7+
"m.defined___clang__ or m.defined__LIBCPP_VERSION",
8+
reason="Known issues: https://github.com/pybind/pybind11/pull/4319",
9+
strict=False,
10+
)
11+
def test_have_class_any_struct():
12+
assert m.unnamed_namespace_b_any_struct is not None

0 commit comments

Comments
 (0)