Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions include/proxy/v4/detail/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,7 @@ R invoke_dispatch(Args&&... args) {
template <class P>
struct destroying_guard {
explicit destroying_guard(P* p) noexcept : p_(p) {}
~destroying_guard() noexcept(std::is_nothrow_destructible_v<P>) {
std::destroy_at(p_);
}
~destroying_guard() noexcept(std::is_nothrow_destructible_v<P>) { p_->~P(); }

private:
P* p_;
Expand Down Expand Up @@ -617,10 +615,7 @@ struct copy_dispatch {
}
};
struct destroy_dispatch {
template <class T>
PRO4D_STATIC_CALL(void, T& self) noexcept(std::is_nothrow_destructible_v<T>) {
std::destroy_at(&self);
}
PRO4D_STATIC_CALL(void, auto&&) noexcept {}
};
template <class D, class ONE, class OE, constraint_level C>
struct lifetime_meta_traits : std::type_identity<void> {};
Expand Down Expand Up @@ -925,8 +920,8 @@ struct facade_traits : specialization_t<facade_conv_traits_impl,
void(void*) const, F::copyability>,
lifetime_meta_t<relocate_dispatch, void(void*) && noexcept,
void(void*) &&, F::relocatability>,
lifetime_meta_t<destroy_dispatch, void() noexcept, void(),
F::destructibility>,
lifetime_meta_t<destroy_dispatch, void() && noexcept,
void() &&, F::destructibility>,
typename facade_traits::conv_meta,
typename facade_traits::refl_meta>>;
using indirect_accessor = composite_t<
Expand Down Expand Up @@ -1331,8 +1326,8 @@ class proxy : public detail::facade_traits<F>::direct_accessor,
if constexpr (F::destructibility != constraint_level::trivial) {
if (meta_.has_value()) {
invoke<detail::destroy_dispatch,
void() noexcept(F::destructibility ==
constraint_level::nothrow)>(*this);
void() && noexcept(F::destructibility ==
constraint_level::nothrow)>(std::move(*this));
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions include/proxy/v4/detail/proxy_creation.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ template <class Alloc, class T>
void deallocate(const Alloc& alloc, T* ptr) {
auto al =
typename std::allocator_traits<Alloc>::template rebind_alloc<T>(alloc);
std::destroy_at(ptr);
ptr->~T();
al.deallocate(ptr, 1);
}
template <class Alloc>
Expand Down Expand Up @@ -223,7 +223,7 @@ class strong_compact_ptr {
strong_compact_ptr(strong_compact_ptr&& rhs) = delete;
~strong_compact_ptr() noexcept(std::is_nothrow_destructible_v<T>) {
if (ptr_->strong_count.fetch_sub(1, std::memory_order::acq_rel) == 1) {
std::destroy_at(operator->());
operator->()->~T();
if (ptr_->weak_count.fetch_sub(1u, std::memory_order::release) == 1) {
deallocate(ptr_->alloc, ptr_);
}
Expand Down
75 changes: 75 additions & 0 deletions tests/proxy_lifetime_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ struct TestTrivialFacade
::support_destruction<pro::constraint_level::trivial> //
::build {};

struct TestThrowingDestructionFacade
: pro::facade_builder //
::add_convention<utils::spec::FreeToString, std::string()> //
::support_copy<pro::constraint_level::nontrivial> //
::support_relocation<pro::constraint_level::nontrivial> //
::support_destruction<pro::constraint_level::nontrivial> //
::build {};

struct TestRttiFacade : pro::facade_builder //
::add_direct_reflection<utils::RttiReflector> //
::add_facade_with_substitution<TestFacade> //
Expand Down Expand Up @@ -274,6 +282,21 @@ TEST(ProxyLifetimeTests, TestMoveConstrction_FromNull) {
ASSERT_FALSE(p2.has_value());
}

TEST(ProxyLifetimeTests, TestDestruction_Exception) {
utils::LifetimeTracker tracker;
std::vector<utils::LifetimeOperation> expected_ops;
auto destroy = [&] {
pro::proxy<detail::TestThrowingDestructionFacade> p{
std::in_place_type<utils::LifetimeTracker::ThrowingDestructionSession>,
&tracker};
};
ASSERT_THROW(destroy(), utils::DestructionFailure);
expected_ops.emplace_back(1,
utils::LifetimeOperationType::kValueConstruction);
expected_ops.emplace_back(1, utils::LifetimeOperationType::kDestruction);
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
}

TEST(ProxyLifetimeTests, TestNullAssignment_FromNullptr_ToValue) {
utils::LifetimeTracker tracker;
std::vector<utils::LifetimeOperation> expected_ops;
Expand Down Expand Up @@ -358,6 +381,30 @@ TEST(ProxyLifetimeTests, TestPolyAssignment_ToValue_Exception) {
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
}

TEST(ProxyLifetimeTests, TestPolyAssignment_ToValue_DestructionException) {
utils::LifetimeTracker tracker;
std::vector<utils::LifetimeOperation> expected_ops;
{
pro::proxy<detail::TestThrowingDestructionFacade> p{
std::in_place_type<utils::LifetimeTracker::ThrowingDestructionSession>,
&tracker};
expected_ops.emplace_back(1,
utils::LifetimeOperationType::kValueConstruction);
utils::LifetimeTracker::Session session{&tracker};
expected_ops.emplace_back(2,
utils::LifetimeOperationType::kValueConstruction);
ASSERT_THROW(p = session, utils::DestructionFailure);
ASSERT_FALSE(p.has_value());
expected_ops.emplace_back(3,
utils::LifetimeOperationType::kCopyConstruction);
expected_ops.emplace_back(1, utils::LifetimeOperationType::kDestruction);
expected_ops.emplace_back(3, utils::LifetimeOperationType::kDestruction);
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
}
expected_ops.emplace_back(2, utils::LifetimeOperationType::kDestruction);
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
}

TEST(ProxyLifetimeTests, TestPolyAssignment_FromValue_ToNull) {
utils::LifetimeTracker tracker;
std::vector<utils::LifetimeOperation> expected_ops;
Expand Down Expand Up @@ -630,6 +677,34 @@ TEST(ProxyLifetimeTests, TestCopyAssignment_FromValue_ToValue_Exception) {
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
}

TEST(ProxyLifetimeTests,
TestCopyAssignment_FromValue_ToValue_DestructionException) {
utils::LifetimeTracker tracker;
std::vector<utils::LifetimeOperation> expected_ops;
{
pro::proxy<detail::TestThrowingDestructionFacade> p1{
std::in_place_type<utils::LifetimeTracker::ThrowingDestructionSession>,
&tracker};
expected_ops.emplace_back(1,
utils::LifetimeOperationType::kValueConstruction);
pro::proxy<detail::TestThrowingDestructionFacade> p2{
std::in_place_type<utils::LifetimeTracker::Session>, &tracker};
expected_ops.emplace_back(2,
utils::LifetimeOperationType::kValueConstruction);
ASSERT_THROW(p1 = p2, utils::DestructionFailure);
ASSERT_FALSE(p1.has_value());
ASSERT_TRUE(p2.has_value());
ASSERT_EQ(ToString(*p2), "Session 2");
expected_ops.emplace_back(3,
utils::LifetimeOperationType::kCopyConstruction);
expected_ops.emplace_back(1, utils::LifetimeOperationType::kDestruction);
expected_ops.emplace_back(3, utils::LifetimeOperationType::kDestruction);
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
}
expected_ops.emplace_back(2, utils::LifetimeOperationType::kDestruction);
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
}

TEST(ProxyLifetimeTests, TestCopyAssignment_FromValue_ToSelf) {
utils::LifetimeTracker tracker;
std::vector<utils::LifetimeOperation> expected_ops;
Expand Down
13 changes: 13 additions & 0 deletions tests/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef _MSFT_PROXY_TEST_UTILS_
#define _MSFT_PROXY_TEST_UTILS_

#include <exception>
#include <proxy/proxy.h>
#include <string>
#include <vector>
Expand Down Expand Up @@ -38,6 +39,8 @@ struct ConstructionFailure : std::exception {
LifetimeOperationType type_;
};

struct DestructionFailure : std::exception {};

class LifetimeTracker {
public:
LifetimeTracker() = default;
Expand Down Expand Up @@ -74,6 +77,16 @@ class LifetimeTracker {
LifetimeTracker* const host_;
};

class ThrowingDestructionSession : public Session {
public:
using Session::Session;
~ThrowingDestructionSession() noexcept(false) {
if (std::uncaught_exceptions() == 0) {
throw DestructionFailure{};
}
}
};

const std::vector<LifetimeOperation>& GetOperations() const { return ops_; }
void ThrowOnNextConstruction() { throw_on_next_construction_ = true; }

Expand Down
Loading