diff --git a/src/cpyrt/Converters.cxx b/src/cpyrt/Converters.cxx index c647696..4771e80 100644 --- a/src/cpyrt/Converters.cxx +++ b/src/cpyrt/Converters.cxx @@ -4271,11 +4271,13 @@ static struct InitConvFactories_t { gf["const std::wstring &"] = gf["std::wstring"]; gf["const " WSTRING1 " &"] = gf["std::wstring"]; gf["const " WSTRING2 " &"] = gf["std::wstring"]; - // VoidPtrRefConverter should only be used for const references to pointers - gf["const void*&"] = (cf_t) + [](cdims_t) { + // void*& is exempt from the T*& ban: the callee updates the proxy's + // held pointer through the opaque handle + gf["void*&"] = (cf_t) + [](cdims_t) { static VoidPtrRefConverter c{}; return &c; }; + gf["const void*&"] = gf["void*&"]; gf["void**"] = (cf_t) + [](cdims_t d) { return new VoidPtrPtrConverter{d}; }; gf["void ptr"] = gf["void**"]; diff --git a/test/test_conversions.py b/test/test_conversions.py index 8741534..65b1600 100644 --- a/test/test_conversions.py +++ b/test/test_conversions.py @@ -138,3 +138,19 @@ def test05_bool_conversions(self): assert ns.Test1() assert ns.Test2(True) assert not ns.Test2(False) + + def test07_mutable_voidp_reference(self): + """An object can be passed through a non-const void*& argument""" + + import cppjit + + cppjit.cppdef("""\ + namespace VoidPtrRef { + struct Obj { int v = 5; }; + bool is_same(void*& p, Obj* o) { return p == (void*)o; } + }""") + + ns = cppjit.gbl.VoidPtrRef + o = ns.Obj() + + assert ns.is_same(o, o)