diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 0226a6ef..3934971a 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -492,23 +492,12 @@ public: protected: typedef void *(*Constructor)(const void *stream); -#if !defined(_MSC_VER) /* Only enabled when the types are {copy,move}-constructible *and* when the type does not have a private operator new implementaton. */ template ::value>> static auto make_copy_constructor(const T *value) -> decltype(new T(*value), Constructor(nullptr)) { return [](const void *arg) -> void * { return new T(*((const T *) arg)); }; } template static auto make_move_constructor(const T *value) -> decltype(new T(std::move(*((T *) value))), Constructor(nullptr)) { return [](const void *arg) -> void * { return (void *) new T(std::move(*const_cast(reinterpret_cast(arg)))); }; } -#else - /* Visual Studio 2015's SFINAE implementation doesn't yet handle the above robustly in all situations. - Use a workaround that only tests for constructibility for now. */ - template ::value>> - static Constructor make_copy_constructor(const T *value) { - return [](const void *arg) -> void * { return new T(*((const T *)arg)); }; } - template ::value>> - static Constructor make_move_constructor(const T *value) { - return [](const void *arg) -> void * { return (void *) new T(std::move(*((T *)arg))); }; } -#endif static Constructor make_copy_constructor(...) { return nullptr; } static Constructor make_move_constructor(...) { return nullptr; } diff --git a/tests/test_copy_move.cpp b/tests/test_copy_move.cpp index 898fc39d..90ca6da7 100644 --- a/tests/test_copy_move.cpp +++ b/tests/test_copy_move.cpp @@ -98,6 +98,12 @@ public: }; }} +struct PrivateOpNew { + int value = 1; + +private: + void *operator new(size_t bytes); +}; test_initializer copy_move_policies([](py::module &m) { py::class_(m, "lacking_copy_ctor") @@ -174,4 +180,11 @@ test_initializer copy_move_policies([](py::module &m) { m.attr("has_optional") = false; #endif + // #70 compilation issue if operator new is not public + py::class_(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value); + m.def("private_op_new_value", []() { return PrivateOpNew(); }); + m.def("private_op_new_reference", []() -> const PrivateOpNew & { + static PrivateOpNew x{}; + return x; + }, py::return_value_policy::reference); }); diff --git a/tests/test_copy_move.py b/tests/test_copy_move.py index d6479c58..386fce7b 100644 --- a/tests/test_copy_move.py +++ b/tests/test_copy_move.py @@ -98,3 +98,14 @@ def test_move_and_copy_load_optional(): assert c_c.copy_assignments == 2 assert c_c.copy_constructions == 5 assert c_m.alive() + c_mc.alive() + c_c.alive() == 0 + + +def test_private_op_new(): + """An object with a private `operator new` cannot be returned by value""" + import pybind11_tests as m + + with pytest.raises(RuntimeError) as excinfo: + m.private_op_new_value() + assert "the object is neither movable nor copyable" in str(excinfo.value) + + assert m.private_op_new_reference().value == 1 diff --git a/tests/test_issues.cpp b/tests/test_issues.cpp index cab9ddf6..6d88d9a9 100644 --- a/tests/test_issues.cpp +++ b/tests/test_issues.cpp @@ -77,16 +77,6 @@ template <> struct hash { size_t operator()(const TplConstrClass void init_issues(py::module &m) { py::module m2 = m.def_submodule("issues"); -#if !defined(_MSC_VER) - // Visual Studio 2015 currently cannot compile this test - // (see the comment in type_caster_base::make_copy_constructor) - // #70 compilation issue if operator new is not public - class NonConstructible { private: void *operator new(size_t bytes) throw(); }; - py::class_(m, "Foo"); - m2.def("getstmt", []() -> NonConstructible * { return nullptr; }, - py::return_value_policy::reference); -#endif - // #137: const char* isn't handled properly m2.def("print_cchar", [](const char *s) { return std::string(s); });