From 04a95684879d8141cd3d4d0fc53a4e71dd7e1de1 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 7 Jan 2021 00:10:57 -0800 Subject: [PATCH] Implementing all [E]xception tests. --- include/pybind11/smart_holder_poc.h | 28 ++++- tests/core/smart_holder_poc_test.cpp | 158 ++++++++++++++++++++++++--- 2 files changed, 169 insertions(+), 17 deletions(-) diff --git a/include/pybind11/smart_holder_poc.h b/include/pybind11/smart_holder_poc.h index a3a85243c..31dacb82a 100644 --- a/include/pybind11/smart_holder_poc.h +++ b/include/pybind11/smart_holder_poc.h @@ -33,26 +33,36 @@ struct smart_holder { const std::type_info* rtti_uqp_del; std::shared_ptr vptr; bool vptr_deleter_guard_flag; - bool vptr_is_using_builtin_delete; + bool vptr_is_using_noop_deleter : 1; + bool vptr_is_using_builtin_delete : 1; + bool vptr_is_external_shared_ptr : 1; void clear() { rtti_held = nullptr; rtti_uqp_del = nullptr; vptr.reset(); vptr_deleter_guard_flag = false; + vptr_is_using_noop_deleter = false; vptr_is_using_builtin_delete = false; + vptr_is_external_shared_ptr = false; } smart_holder() : rtti_held{nullptr}, rtti_uqp_del{nullptr}, vptr_deleter_guard_flag{false}, - vptr_is_using_builtin_delete{false} {} + vptr_is_using_noop_deleter{false}, + vptr_is_using_builtin_delete{false}, + vptr_is_external_shared_ptr{false} {} bool has_pointee() const { return vptr.get() != nullptr; } template void ensure_compatible_rtti_held(const char* context) const { + if (!rtti_held) { + throw std::runtime_error(std::string("Unpopulated holder (") + context + + ")."); + } const std::type_info* rtti_requested = &typeid(T); if (!(*rtti_requested == *rtti_held)) { throw std::runtime_error(std::string("Incompatible type (") + context + @@ -62,6 +72,10 @@ struct smart_holder { template void ensure_compatible_rtti_uqp_del(const char* context) const { + if (!rtti_uqp_del) { + throw std::runtime_error(std::string("Missing unique_ptr deleter (") + + context + ")."); + } const std::type_info* rtti_requested = &typeid(D); if (!(*rtti_requested == *rtti_uqp_del)) { throw std::runtime_error( @@ -77,6 +91,14 @@ struct smart_holder { } void ensure_vptr_is_using_builtin_delete(const char* context) const { + if (vptr_is_external_shared_ptr) { + throw std::runtime_error( + std::string("Cannot disown external shared_ptr (") + context + ")."); + } + if (vptr_is_using_noop_deleter) { + throw std::runtime_error( + std::string("Cannot disown non-owning holder (") + context + ")."); + } if (!vptr_is_using_builtin_delete) { throw std::runtime_error(std::string("Cannot disown custom deleter (") + context + ")."); @@ -94,6 +116,7 @@ struct smart_holder { void from_raw_ptr_unowned(T* raw_ptr) { clear(); rtti_held = &typeid(T); + vptr_is_using_noop_deleter = true; vptr.reset(raw_ptr, guarded_builtin_delete(&vptr_deleter_guard_flag)); } @@ -176,6 +199,7 @@ struct smart_holder { void from_shared_ptr(std::shared_ptr shd_ptr) { clear(); rtti_held = &typeid(T); + vptr_is_external_shared_ptr = true; vptr = std::static_pointer_cast(shd_ptr); } diff --git a/tests/core/smart_holder_poc_test.cpp b/tests/core/smart_holder_poc_test.cpp index bff9eb6bf..87fda2180 100644 --- a/tests/core/smart_holder_poc_test.cpp +++ b/tests/core/smart_holder_poc_test.cpp @@ -12,6 +12,9 @@ struct functor_builtin_delete { void operator()(T* ptr) { delete ptr; } }; +template +struct functor_other_delete : functor_builtin_delete {}; + } // namespace helpers TEST_CASE("from_raw_ptr_unowned+as_raw_ptr_unowned", "[S]") { @@ -28,11 +31,34 @@ TEST_CASE("from_raw_ptr_unowned+const_value_ref", "[S]") { REQUIRE(hld.const_value_ref() == 19); } -TEST_CASE("from_raw_ptr_unowned+as_raw_ptr_release_ownership", "[E]") {} +TEST_CASE("from_raw_ptr_unowned+as_raw_ptr_release_ownership", "[E]") { + static int value = 19; + smart_holder hld; + hld.from_raw_ptr_unowned(&value); + REQUIRE_THROWS_WITH( + hld.as_raw_ptr_release_ownership(), + "Cannot disown non-owning holder (as_raw_ptr_release_ownership)."); +} -TEST_CASE("from_raw_ptr_unowned+as_unique_ptr", "[E]") {} +TEST_CASE("from_raw_ptr_unowned+as_unique_ptr", "[E]") { + static int value = 19; + smart_holder hld; + hld.from_raw_ptr_unowned(&value); + REQUIRE_THROWS_WITH(hld.as_unique_ptr(), + "Cannot disown non-owning holder (as_unique_ptr)."); +} -TEST_CASE("from_raw_ptr_unowned+as_unique_ptr_with_deleter", "[E]") {} +TEST_CASE("from_raw_ptr_unowned+as_unique_ptr_with_deleter", "[E]") { + static int value = 19; + smart_holder hld; + hld.from_raw_ptr_unowned(&value); + auto condense_for_macro = [](smart_holder& hld) { + hld.as_unique_ptr_with_deleter>(); + }; + REQUIRE_THROWS_WITH( + condense_for_macro(hld), + "Missing unique_ptr deleter (as_unique_ptr_with_deleter)."); +} TEST_CASE("from_raw_ptr_unowned+as_shared_ptr", "[S]") { static int value = 19; @@ -57,7 +83,14 @@ TEST_CASE("from_raw_ptr_take_ownership+as_raw_ptr_release_ownership1", "[S]") { REQUIRE(*new_owner == 19); } -TEST_CASE("from_raw_ptr_take_ownership+as_raw_ptr_release_ownership2", "[E]") {} +TEST_CASE("from_raw_ptr_take_ownership+as_raw_ptr_release_ownership2", "[E]") { + smart_holder hld; + hld.from_raw_ptr_take_ownership(new int(19)); + auto shd_ptr = hld.as_shared_ptr(); + REQUIRE_THROWS_WITH( + hld.as_raw_ptr_release_ownership(), + "Cannot disown use_count != 1 (as_raw_ptr_release_ownership)."); +} TEST_CASE("from_raw_ptr_take_ownership+as_unique_ptr1", "[S]") { smart_holder hld; @@ -67,9 +100,24 @@ TEST_CASE("from_raw_ptr_take_ownership+as_unique_ptr1", "[S]") { REQUIRE(*new_owner == 19); } -TEST_CASE("from_raw_ptr_take_ownership+as_unique_ptr2", "[E]") {} +TEST_CASE("from_raw_ptr_take_ownership+as_unique_ptr2", "[E]") { + smart_holder hld; + hld.from_raw_ptr_take_ownership(new int(19)); + auto shd_ptr = hld.as_shared_ptr(); + REQUIRE_THROWS_WITH(hld.as_unique_ptr(), + "Cannot disown use_count != 1 (as_unique_ptr)."); +} -TEST_CASE("from_raw_ptr_take_ownership+as_unique_ptr_with_deleter", "[E]") {} +TEST_CASE("from_raw_ptr_take_ownership+as_unique_ptr_with_deleter", "[E]") { + smart_holder hld; + hld.from_raw_ptr_take_ownership(new int(19)); + auto condense_for_macro = [](smart_holder& hld) { + hld.as_unique_ptr_with_deleter>(); + }; + REQUIRE_THROWS_WITH( + condense_for_macro(hld), + "Missing unique_ptr deleter (as_unique_ptr_with_deleter)."); +} TEST_CASE("from_raw_ptr_take_ownership+as_shared_ptr", "[S]") { smart_holder hld; @@ -98,7 +146,16 @@ TEST_CASE("from_unique_ptr+as_raw_ptr_release_ownership1", "[S]") { REQUIRE(*new_owner == 19); } -TEST_CASE("from_unique_ptr+as_raw_ptr_release_ownership2", "[E]") {} +TEST_CASE("from_unique_ptr+as_raw_ptr_release_ownership2", "[E]") { + std::unique_ptr orig_owner(new int(19)); + smart_holder hld; + hld.from_unique_ptr(std::move(orig_owner)); + REQUIRE(orig_owner.get() == nullptr); + auto shd_ptr = hld.as_shared_ptr(); + REQUIRE_THROWS_WITH( + hld.as_raw_ptr_release_ownership(), + "Cannot disown use_count != 1 (as_raw_ptr_release_ownership)."); +} TEST_CASE("from_unique_ptr+as_unique_ptr1", "[S]") { std::unique_ptr orig_owner(new int(19)); @@ -110,9 +167,28 @@ TEST_CASE("from_unique_ptr+as_unique_ptr1", "[S]") { REQUIRE(*new_owner == 19); } -TEST_CASE("from_unique_ptr+as_unique_ptr2", "[E]") {} +TEST_CASE("from_unique_ptr+as_unique_ptr2", "[E]") { + std::unique_ptr orig_owner(new int(19)); + smart_holder hld; + hld.from_unique_ptr(std::move(orig_owner)); + REQUIRE(orig_owner.get() == nullptr); + auto shd_ptr = hld.as_shared_ptr(); + REQUIRE_THROWS_WITH(hld.as_unique_ptr(), + "Cannot disown use_count != 1 (as_unique_ptr)."); +} -TEST_CASE("from_unique_ptr+as_unique_ptr_with_deleter", "[E]") {} +TEST_CASE("from_unique_ptr+as_unique_ptr_with_deleter", "[E]") { + std::unique_ptr orig_owner(new int(19)); + smart_holder hld; + hld.from_unique_ptr(std::move(orig_owner)); + REQUIRE(orig_owner.get() == nullptr); + auto condense_for_macro = [](smart_holder& hld) { + hld.as_unique_ptr_with_deleter>(); + }; + REQUIRE_THROWS_WITH( + condense_for_macro(hld), + "Missing unique_ptr deleter (as_unique_ptr_with_deleter)."); +} TEST_CASE("from_unique_ptr+as_shared_ptr", "[S]") { std::unique_ptr orig_owner(new int(19)); @@ -133,9 +209,26 @@ TEST_CASE("from_unique_ptr_with_deleter+const_value_ref", "[S]") { REQUIRE(hld.const_value_ref() == 19); } -TEST_CASE("from_unique_ptr_with_deleter+as_raw_ptr_release_ownership", "[E]") {} +TEST_CASE("from_unique_ptr_with_deleter+as_raw_ptr_release_ownership", "[E]") { + std::unique_ptr> orig_owner( + new int(19)); + smart_holder hld; + hld.from_unique_ptr_with_deleter(std::move(orig_owner)); + REQUIRE(orig_owner.get() == nullptr); + REQUIRE_THROWS_WITH( + hld.as_raw_ptr_release_ownership(), + "Cannot disown custom deleter (as_raw_ptr_release_ownership)."); +} -TEST_CASE("from_unique_ptr_with_deleter+as_unique_ptr", "[E]") {} +TEST_CASE("from_unique_ptr_with_deleter+as_unique_ptr", "[E]") { + std::unique_ptr> orig_owner( + new int(19)); + smart_holder hld; + hld.from_unique_ptr_with_deleter(std::move(orig_owner)); + REQUIRE(orig_owner.get() == nullptr); + REQUIRE_THROWS_WITH(hld.as_unique_ptr(), + "Cannot disown custom deleter (as_unique_ptr)."); +} TEST_CASE("from_unique_ptr_with_deleter+as_unique_ptr_with_deleter1", "[S]") { std::unique_ptr> orig_owner( @@ -150,7 +243,19 @@ TEST_CASE("from_unique_ptr_with_deleter+as_unique_ptr_with_deleter1", "[S]") { REQUIRE(*new_owner == 19); } -TEST_CASE("from_unique_ptr_with_deleter+as_unique_ptr_with_deleter2", "[E]") {} +TEST_CASE("from_unique_ptr_with_deleter+as_unique_ptr_with_deleter2", "[E]") { + std::unique_ptr> orig_owner( + new int(19)); + smart_holder hld; + hld.from_unique_ptr_with_deleter(std::move(orig_owner)); + REQUIRE(orig_owner.get() == nullptr); + auto condense_for_macro = [](smart_holder& hld) { + hld.as_unique_ptr_with_deleter>(); + }; + REQUIRE_THROWS_WITH( + condense_for_macro(hld), + "Incompatible unique_ptr deleter (as_unique_ptr_with_deleter)."); +} TEST_CASE("from_unique_ptr_with_deleter+as_shared_ptr", "[S]") { std::unique_ptr> orig_owner( @@ -170,11 +275,34 @@ TEST_CASE("from_shared_ptr+const_value_ref", "[S]") { REQUIRE(hld.const_value_ref() == 19); } -TEST_CASE("from_shared_ptr+as_raw_ptr_release_ownership", "[E]") {} +TEST_CASE("from_shared_ptr+as_raw_ptr_release_ownership", "[E]") { + std::shared_ptr orig_owner(new int(19)); + smart_holder hld; + hld.from_shared_ptr(orig_owner); + REQUIRE_THROWS_WITH( + hld.as_raw_ptr_release_ownership(), + "Cannot disown external shared_ptr (as_raw_ptr_release_ownership)."); +} -TEST_CASE("from_shared_ptr+as_unique_ptr", "[E]") {} +TEST_CASE("from_shared_ptr+as_unique_ptr", "[E]") { + std::shared_ptr orig_owner(new int(19)); + smart_holder hld; + hld.from_shared_ptr(orig_owner); + REQUIRE_THROWS_WITH(hld.as_unique_ptr(), + "Cannot disown external shared_ptr (as_unique_ptr)."); +} -TEST_CASE("from_shared_ptr+as_unique_ptr_with_deleter", "[E]") {} +TEST_CASE("from_shared_ptr+as_unique_ptr_with_deleter", "[E]") { + std::shared_ptr orig_owner(new int(19)); + smart_holder hld; + hld.from_shared_ptr(orig_owner); + auto condense_for_macro = [](smart_holder& hld) { + hld.as_unique_ptr_with_deleter>(); + }; + REQUIRE_THROWS_WITH( + condense_for_macro(hld), + "Missing unique_ptr deleter (as_unique_ptr_with_deleter)."); +} TEST_CASE("from_shared_ptr+as_shared_ptr", "[S]") { std::shared_ptr orig_owner(new int(19));