diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 6fd61098c4d..8183ce8a58e 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -209,6 +209,11 @@ struct internals { PYBIND11_TLS_FREE(tstate); } #endif + + std::unordered_map> + std_type_index_registry_unnamed_namespace; + std::unordered_map> + std_type_index_registry_named_namespace; }; /// Additional type information which does not fit into the PyTypeObject. diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 491f215cef9..20bc6de2a4e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -133,6 +133,8 @@ set(PYBIND11_TEST_FILES test_eigen_tensor_avoid_stl_array.cpp test_enum test_eval + test_exc_named_namespace_a.py + test_exc_named_namespace_b.py test_exceptions test_factory_constructors test_gil_scoped @@ -156,6 +158,8 @@ set(PYBIND11_TEST_FILES test_tagbased_polymorphic test_thread test_union + test_unnamed_namespace_a + test_unnamed_namespace_b test_virtual_functions) # Invoking cmake with something like: @@ -219,6 +223,8 @@ tests_extra_targets("test_exceptions.py;test_local_bindings.py;test_stl.py;test_ # And add additional targets for other tests. tests_extra_targets("test_exceptions.py" "cross_module_interleaved_error_already_set") tests_extra_targets("test_gil_scoped.py" "cross_module_gil_utils") +tests_extra_targets("test_exc_named_namespace_a.py" "named_namespace_a") +tests_extra_targets("test_exc_named_namespace_b.py" "named_namespace_b") set(PYBIND11_EIGEN_REPO "https://gitlab.com/libeigen/eigen.git" diff --git a/tests/named_namespace_a.cpp b/tests/named_namespace_a.cpp new file mode 100644 index 00000000000..f997119d30e --- /dev/null +++ b/tests/named_namespace_a.cpp @@ -0,0 +1,25 @@ +#include + +#include "pybind11_tests.h" + +namespace test_named_namespace { +struct any_struct {}; +} // namespace test_named_namespace + +PYBIND11_MODULE(named_namespace_a, m) { + m.attr("name") = "NA"; + + py::detail::get_internals() + .std_type_index_registry_named_namespace[std::type_index( + typeid(test_named_namespace::any_struct))] + .push_back("NA"); + + m.def("std_type_index_registry_dump", []() { + py::list items; + for (const auto &it : + py::detail::get_internals().std_type_index_registry_named_namespace) { + items.append(py::make_tuple(it.first.name(), it.second)); + } + return items; + }); +} diff --git a/tests/named_namespace_b.cpp b/tests/named_namespace_b.cpp new file mode 100644 index 00000000000..ca38e178001 --- /dev/null +++ b/tests/named_namespace_b.cpp @@ -0,0 +1,14 @@ +#include "pybind11_tests.h" + +namespace test_named_namespace { +struct any_struct {}; +} // namespace test_named_namespace + +PYBIND11_MODULE(named_namespace_b, m) { + m.attr("name") = "NB"; + + py::detail::get_internals() + .std_type_index_registry_named_namespace[std::type_index( + typeid(test_named_namespace::any_struct))] + .push_back("NB"); +} diff --git a/tests/test_exc_named_namespace_a.py b/tests/test_exc_named_namespace_a.py new file mode 100644 index 00000000000..e19f31f1690 --- /dev/null +++ b/tests/test_exc_named_namespace_a.py @@ -0,0 +1,15 @@ +import named_namespace_a as m +import pytest + + +def test_inspect(): + assert m.name == "NA" + reg = m.std_type_index_registry_dump() + if len(reg) == 1: + assert tuple(sorted(reg[0][1])) == ("NA", "NB") + pytest.skip("std::type_index-EQ-GOOD") + if len(reg) == 2: + assert reg[0][0] == reg[1][0] + assert tuple(sorted(reg[0][1] + reg[1][1])) == ("NA", "NB") + pytest.skip("std::type_index-NE-BAD") + assert reg is None # Sure to fail. diff --git a/tests/test_exc_named_namespace_b.py b/tests/test_exc_named_namespace_b.py new file mode 100644 index 00000000000..f00fd97af29 --- /dev/null +++ b/tests/test_exc_named_namespace_b.py @@ -0,0 +1,5 @@ +import named_namespace_b as m + + +def test_inspect(): + assert m.name == "NB" diff --git a/tests/test_unnamed_namespace_a.cpp b/tests/test_unnamed_namespace_a.cpp new file mode 100644 index 00000000000..00d55d5da05 --- /dev/null +++ b/tests/test_unnamed_namespace_a.cpp @@ -0,0 +1,24 @@ +#include + +#include "pybind11_tests.h" + +namespace { +struct any_struct {}; +} // namespace + +TEST_SUBMODULE(unnamed_namespace_a, m) { + m.attr("name") = "UA"; + + py::detail::get_internals() + .std_type_index_registry_unnamed_namespace[std::type_index(typeid(any_struct))] + .push_back("UA"); + + m.def("std_type_index_registry_dump", []() { + py::list items; + for (const auto &it : + py::detail::get_internals().std_type_index_registry_unnamed_namespace) { + items.append(py::make_tuple(it.first.name(), it.second)); + } + return items; + }); +} diff --git a/tests/test_unnamed_namespace_a.py b/tests/test_unnamed_namespace_a.py new file mode 100644 index 00000000000..ea882cc8d8a --- /dev/null +++ b/tests/test_unnamed_namespace_a.py @@ -0,0 +1,15 @@ +import pytest + +from pybind11_tests import unnamed_namespace_a as m + + +def test_inspect(): + assert m.name == "UA" + reg = m.std_type_index_registry_dump() + if len(reg) == 1: + assert tuple(sorted(reg[0][1])) == ("UA", "UB") + pytest.skip("std::type_index-EQ-BAD") + if len(reg) == 2: + assert tuple(sorted([reg[0][1][0], reg[1][1][0]])) == ("UA", "UB") + pytest.skip("std::type_index-NE-GOOD") + assert reg is None # Sure to fail. diff --git a/tests/test_unnamed_namespace_b.cpp b/tests/test_unnamed_namespace_b.cpp new file mode 100644 index 00000000000..c38691af2f2 --- /dev/null +++ b/tests/test_unnamed_namespace_b.cpp @@ -0,0 +1,13 @@ +#include "pybind11_tests.h" + +namespace { +struct any_struct {}; +} // namespace + +TEST_SUBMODULE(unnamed_namespace_b, m) { + m.attr("name") = "UB"; + + py::detail::get_internals() + .std_type_index_registry_unnamed_namespace[std::type_index(typeid(any_struct))] + .push_back("UB"); +} diff --git a/tests/test_unnamed_namespace_b.py b/tests/test_unnamed_namespace_b.py new file mode 100644 index 00000000000..4c033597bda --- /dev/null +++ b/tests/test_unnamed_namespace_b.py @@ -0,0 +1,5 @@ +from pybind11_tests import unnamed_namespace_b as m + + +def test_inspect(): + assert m.name == "UB"