Skip to content

Commit 9113554

Browse files
authored
Merge branch 'feature/v5' into user/mingxwa/super-stage5
2 parents d9393de + b5ea4a9 commit 9113554

7 files changed

Lines changed: 119 additions & 14 deletions

File tree

.github/workflows/pipeline-ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
run-bvt-appleclang-arm64e:
3737
uses: ./.github/workflows/bvt-appleclang-arm64e.yml
3838
name: Run BVT with AppleClang (arm64e with PAC)
39+
if: github.event_name != 'push' || github.repository == 'ngcpp/proxy'
3940

4041
run-bvt-nvhpc:
4142
uses: ./.github/workflows/bvt-nvhpc.yml

include/proxy/v4/detail/core.h

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -391,9 +391,7 @@ R invoke_dispatch(Args&&... args) {
391391
template <class P>
392392
struct destroying_guard {
393393
explicit destroying_guard(P* p) noexcept : p_(p) {}
394-
~destroying_guard() noexcept(std::is_nothrow_destructible_v<P>) {
395-
std::destroy_at(p_);
396-
}
394+
~destroying_guard() noexcept(std::is_nothrow_destructible_v<P>) { p_->~P(); }
397395

398396
private:
399397
P* p_;
@@ -580,10 +578,7 @@ struct copy_dispatch {
580578
}
581579
};
582580
struct destroy_dispatch {
583-
template <class T>
584-
PRO4D_STATIC_CALL(void, T& self) noexcept(std::is_nothrow_destructible_v<T>) {
585-
std::destroy_at(&self);
586-
}
581+
PRO4D_STATIC_CALL(void, auto&&) noexcept {}
587582
};
588583
template <class D, class ONE, class OE, constraint_level C>
589584
struct lifetime_meta_traits : std::type_identity<void> {};
@@ -1010,8 +1005,8 @@ struct facade_traits
10101005
void(void*) const, F::copyability>,
10111006
lifetime_meta_t<relocate_dispatch, void(void*) && noexcept,
10121007
void(void*) &&, F::relocatability>,
1013-
lifetime_meta_t<destroy_dispatch, void() noexcept, void(),
1014-
F::destructibility>,
1008+
lifetime_meta_t<destroy_dispatch, void() && noexcept,
1009+
void() &&, F::destructibility>,
10151010
typename facade_traits::self_conv_meta,
10161011
typename facade_traits::refl_meta>>;
10171012

@@ -1470,8 +1465,8 @@ class proxy : public detail::facade_traits<F>::direct_accessor,
14701465
if constexpr (F::destructibility != constraint_level::trivial) {
14711466
if (meta_.has_value()) {
14721467
invoke<detail::destroy_dispatch,
1473-
void() noexcept(F::destructibility ==
1474-
constraint_level::nothrow)>(*this);
1468+
void() && noexcept(F::destructibility ==
1469+
constraint_level::nothrow)>(std::move(*this));
14751470
}
14761471
}
14771472
}

include/proxy/v4/detail/proxy_creation.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ template <class Alloc, class T>
7878
void deallocate(const Alloc& alloc, T* ptr) {
7979
auto al =
8080
typename std::allocator_traits<Alloc>::template rebind_alloc<T>(alloc);
81-
std::destroy_at(ptr);
81+
ptr->~T();
8282
al.deallocate(ptr, 1);
8383
}
8484
template <class Alloc>
@@ -223,7 +223,7 @@ class strong_compact_ptr {
223223
strong_compact_ptr(strong_compact_ptr&& rhs) = delete;
224224
~strong_compact_ptr() noexcept(std::is_nothrow_destructible_v<T>) {
225225
if (ptr_->strong_count.fetch_sub(1, std::memory_order::acq_rel) == 1) {
226-
std::destroy_at(operator->());
226+
operator->()->~T();
227227
if (ptr_->weak_count.fetch_sub(1u, std::memory_order::release) == 1) {
228228
deallocate(ptr_->alloc, ptr_);
229229
}

include/proxy/v4/detail/skills.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ struct proxy_cast_dispatch {
205205
if (typeid(T) == *ctx.type_ptr) [[likely]] {
206206
if (ctx.is_ref) {
207207
if constexpr (std::is_lvalue_reference_v<T>) {
208-
if (ctx.is_const || !std::is_const_v<T>) [[likely]] {
208+
if (ctx.is_const || !std::is_const_v<std::remove_reference_t<T>>)
209+
[[likely]] {
209210
*static_cast<void**>(ctx.result_ptr) = (void*)std::addressof(self);
210211
}
211212
}

tests/proxy_lifetime_tests.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ struct TestTrivialFacade
2626
::support_destruction<pro::constraint_level::trivial> //
2727
::build {};
2828

29+
struct TestThrowingDestructionFacade
30+
: pro::facade_builder //
31+
::add_convention<utils::spec::FreeToString, std::string()> //
32+
::support_copy<pro::constraint_level::nontrivial> //
33+
::support_relocation<pro::constraint_level::nontrivial> //
34+
::support_destruction<pro::constraint_level::nontrivial> //
35+
::build {};
36+
2937
struct TestRttiFacade : pro::facade_builder //
3038
::add_direct_reflection<utils::RttiReflector> //
3139
::add_facade_with_substitution<TestFacade> //
@@ -278,6 +286,21 @@ TEST(ProxyLifetimeTests, TestMoveConstrction_FromNull) {
278286
ASSERT_FALSE(p2.has_value());
279287
}
280288

289+
TEST(ProxyLifetimeTests, TestDestruction_Exception) {
290+
utils::LifetimeTracker tracker;
291+
std::vector<utils::LifetimeOperation> expected_ops;
292+
auto destroy = [&] {
293+
pro::proxy<detail::TestThrowingDestructionFacade> p{
294+
std::in_place_type<utils::LifetimeTracker::ThrowingDestructionSession>,
295+
&tracker};
296+
};
297+
ASSERT_THROW(destroy(), utils::DestructionFailure);
298+
expected_ops.emplace_back(1,
299+
utils::LifetimeOperationType::kValueConstruction);
300+
expected_ops.emplace_back(1, utils::LifetimeOperationType::kDestruction);
301+
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
302+
}
303+
281304
TEST(ProxyLifetimeTests, TestNullAssignment_FromNullptr_ToValue) {
282305
utils::LifetimeTracker tracker;
283306
std::vector<utils::LifetimeOperation> expected_ops;
@@ -362,6 +385,30 @@ TEST(ProxyLifetimeTests, TestPolyAssignment_ToValue_Exception) {
362385
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
363386
}
364387

388+
TEST(ProxyLifetimeTests, TestPolyAssignment_ToValue_DestructionException) {
389+
utils::LifetimeTracker tracker;
390+
std::vector<utils::LifetimeOperation> expected_ops;
391+
{
392+
pro::proxy<detail::TestThrowingDestructionFacade> p{
393+
std::in_place_type<utils::LifetimeTracker::ThrowingDestructionSession>,
394+
&tracker};
395+
expected_ops.emplace_back(1,
396+
utils::LifetimeOperationType::kValueConstruction);
397+
utils::LifetimeTracker::Session session{&tracker};
398+
expected_ops.emplace_back(2,
399+
utils::LifetimeOperationType::kValueConstruction);
400+
ASSERT_THROW(p = session, utils::DestructionFailure);
401+
ASSERT_FALSE(p.has_value());
402+
expected_ops.emplace_back(3,
403+
utils::LifetimeOperationType::kCopyConstruction);
404+
expected_ops.emplace_back(1, utils::LifetimeOperationType::kDestruction);
405+
expected_ops.emplace_back(3, utils::LifetimeOperationType::kDestruction);
406+
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
407+
}
408+
expected_ops.emplace_back(2, utils::LifetimeOperationType::kDestruction);
409+
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
410+
}
411+
365412
TEST(ProxyLifetimeTests, TestPolyAssignment_FromValue_ToNull) {
366413
utils::LifetimeTracker tracker;
367414
std::vector<utils::LifetimeOperation> expected_ops;
@@ -634,6 +681,34 @@ TEST(ProxyLifetimeTests, TestCopyAssignment_FromValue_ToValue_Exception) {
634681
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
635682
}
636683

684+
TEST(ProxyLifetimeTests,
685+
TestCopyAssignment_FromValue_ToValue_DestructionException) {
686+
utils::LifetimeTracker tracker;
687+
std::vector<utils::LifetimeOperation> expected_ops;
688+
{
689+
pro::proxy<detail::TestThrowingDestructionFacade> p1{
690+
std::in_place_type<utils::LifetimeTracker::ThrowingDestructionSession>,
691+
&tracker};
692+
expected_ops.emplace_back(1,
693+
utils::LifetimeOperationType::kValueConstruction);
694+
pro::proxy<detail::TestThrowingDestructionFacade> p2{
695+
std::in_place_type<utils::LifetimeTracker::Session>, &tracker};
696+
expected_ops.emplace_back(2,
697+
utils::LifetimeOperationType::kValueConstruction);
698+
ASSERT_THROW(p1 = p2, utils::DestructionFailure);
699+
ASSERT_FALSE(p1.has_value());
700+
ASSERT_TRUE(p2.has_value());
701+
ASSERT_EQ(ToString(*p2), "Session 2");
702+
expected_ops.emplace_back(3,
703+
utils::LifetimeOperationType::kCopyConstruction);
704+
expected_ops.emplace_back(1, utils::LifetimeOperationType::kDestruction);
705+
expected_ops.emplace_back(3, utils::LifetimeOperationType::kDestruction);
706+
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
707+
}
708+
expected_ops.emplace_back(2, utils::LifetimeOperationType::kDestruction);
709+
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
710+
}
711+
637712
TEST(ProxyLifetimeTests, TestCopyAssignment_FromValue_ToSelf) {
638713
utils::LifetimeTracker tracker;
639714
std::vector<utils::LifetimeOperation> expected_ops;

tests/proxy_rtti_tests.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,26 @@ TEST(ProxyRttiTests, TestIndirectCast_ConstPtr_Fail) {
131131
ASSERT_EQ(v, 123);
132132
}
133133

134+
TEST(ProxyRttiTests, TestIndirectCast_Ref_ConstTarget) {
135+
const auto p = pro::make_proxy<detail::TestFacade, int>(123);
136+
bool exception_thrown = false;
137+
try {
138+
proxy_cast<int&>(*p);
139+
} catch (const pro::bad_proxy_cast&) {
140+
exception_thrown = true;
141+
}
142+
ASSERT_TRUE(exception_thrown);
143+
ASSERT_EQ(proxy_cast<const int&>(*p), 123);
144+
}
145+
146+
TEST(ProxyRttiTests, TestIndirectCast_Ptr_ConstTarget) {
147+
const auto p = pro::make_proxy<detail::TestFacade, int>(123);
148+
ASSERT_EQ(proxy_cast<int>(&*p), nullptr);
149+
auto ptr = proxy_cast<const int>(&*p);
150+
static_assert(std::is_same_v<decltype(ptr), const int*>);
151+
ASSERT_EQ(*ptr, 123);
152+
}
153+
134154
TEST(ProxyRttiTests, TestIndirectTypeid) {
135155
int a = 123;
136156
pro::proxy<detail::TestFacade> p = &a;

tests/utils.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef _MSFT_PROXY_TEST_UTILS_
66
#define _MSFT_PROXY_TEST_UTILS_
77

8+
#include <exception>
89
#include <proxy/proxy.h>
910
#include <string>
1011
#include <vector>
@@ -38,6 +39,8 @@ struct ConstructionFailure : std::exception {
3839
LifetimeOperationType type_;
3940
};
4041

42+
struct DestructionFailure : std::exception {};
43+
4144
class LifetimeTracker {
4245
public:
4346
LifetimeTracker() = default;
@@ -74,6 +77,16 @@ class LifetimeTracker {
7477
LifetimeTracker* const host_;
7578
};
7679

80+
class ThrowingDestructionSession : public Session {
81+
public:
82+
using Session::Session;
83+
~ThrowingDestructionSession() noexcept(false) {
84+
if (std::uncaught_exceptions() == 0) {
85+
throw DestructionFailure{};
86+
}
87+
}
88+
};
89+
7790
const std::vector<LifetimeOperation>& GetOperations() const { return ops_; }
7891
void ThrowOnNextConstruction() { throw_on_next_construction_ = true; }
7992

0 commit comments

Comments
 (0)