Skip to content

Commit 93d68dd

Browse files
EricCousineau-TRIhenryiii
authored andcommitted
cast: Qualify symbol usage in PYBIND11_TYPE_CASTER (#3758)
* cast: Qualify symbol usage in PYBIND11_TYPE_CASTER Permits using macro outside of pybind11::detail * fixup! review
1 parent 5327c19 commit 93d68dd

File tree

3 files changed

+44
-5
lines changed

3 files changed

+44
-5
lines changed

include/pybind11/cast.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,15 @@ protected:
8585
\
8686
public: \
8787
static constexpr auto name = py_name; \
88-
template <typename T_, enable_if_t<std::is_same<type, remove_cv_t<T_>>::value, int> = 0> \
89-
static handle cast(T_ *src, return_value_policy policy, handle parent) { \
88+
template <typename T_, \
89+
::pybind11::detail::enable_if_t< \
90+
std::is_same<type, ::pybind11::detail::remove_cv_t<T_>>::value, \
91+
int> = 0> \
92+
static ::pybind11::handle cast( \
93+
T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) { \
9094
if (!src) \
91-
return none().release(); \
92-
if (policy == return_value_policy::take_ownership) { \
95+
return ::pybind11::none().release(); \
96+
if (policy == ::pybind11::return_value_policy::take_ownership) { \
9397
auto h = cast(std::move(*src), policy, parent); \
9498
delete src; \
9599
return h; \
@@ -100,7 +104,7 @@ public:
100104
operator type &() { return value; } /* NOLINT(bugprone-macro-parentheses) */ \
101105
operator type &&() && { return std::move(value); } /* NOLINT(bugprone-macro-parentheses) */ \
102106
template <typename T_> \
103-
using cast_op_type = pybind11::detail::movable_cast_op_type<T_>
107+
using cast_op_type = ::pybind11::detail::movable_cast_op_type<T_>
104108

105109
template <typename CharT>
106110
using is_std_char_type = any_of<std::is_same<CharT, char>, /* std::string */

tests/test_custom_type_casters.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class ArgInspector2 {
2020
std::string arg = "(default arg inspector 2)";
2121
};
2222
class ArgAlwaysConverts {};
23+
2324
namespace pybind11 {
2425
namespace detail {
2526
template <>
@@ -105,6 +106,34 @@ struct type_caster<DestructionTester> {
105106
} // namespace detail
106107
} // namespace pybind11
107108

109+
// Define type caster outside of `pybind11::detail` and then alias it.
110+
namespace other_lib {
111+
struct MyType {};
112+
// Corrupt `py` shorthand alias for surrounding context.
113+
namespace py {}
114+
// Corrupt unqualified relative `pybind11` namespace.
115+
namespace pybind11 {}
116+
// Correct alias.
117+
namespace py_ = ::pybind11;
118+
// Define caster. This is effectively no-op, we only ensure it compiles and we
119+
// don't have any symbol collision when using macro mixin.
120+
struct my_caster {
121+
PYBIND11_TYPE_CASTER(MyType, py_::detail::const_name("MyType"));
122+
bool load(py_::handle, bool) { return true; }
123+
124+
static py_::handle cast(const MyType &, py_::return_value_policy, py_::handle) {
125+
return py_::bool_(true).release();
126+
}
127+
};
128+
} // namespace other_lib
129+
// Effectively "alias" it into correct namespace (via inheritance).
130+
namespace pybind11 {
131+
namespace detail {
132+
template <>
133+
struct type_caster<other_lib::MyType> : public other_lib::my_caster {};
134+
} // namespace detail
135+
} // namespace pybind11
136+
108137
TEST_SUBMODULE(custom_type_casters, m) {
109138
// test_custom_type_casters
110139

@@ -175,4 +204,6 @@ TEST_SUBMODULE(custom_type_casters, m) {
175204
m.def("destruction_tester_cstats",
176205
&ConstructorStats::get<DestructionTester>,
177206
py::return_value_policy::reference);
207+
208+
m.def("other_lib_type", [](other_lib::MyType x) { return x; });
178209
}

tests/test_custom_type_casters.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,7 @@ def test_custom_caster_destruction():
115115

116116
# Make sure we still only have the original object (from ..._no_destroy()) alive:
117117
assert cstats.alive() == 1
118+
119+
120+
def test_custom_caster_other_lib():
121+
assert m.other_lib_type(True)

0 commit comments

Comments
 (0)