mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-18 18:42:46 +02:00
ADT: Add SFINAE to the generic IntrusiveRefCntPtr constructors
Add an `enable_if` to the generic `IntrusiveRefCntPtr` constructors so that std::is_convertible gives an honest answer when the underlying pointers cannot be converted. Added `static_assert`s to the test suite to verify. Also combine generic constructors from `IntrusiveRefCntPtr<X>&&` and `const IntrusiveRefCntPtr<X>&`. At first glance this appears to be an infinite loop, but the real copy/move constructors are spelled out separately above. Added a unit test to verify. Differential Revision: https://reviews.llvm.org/D95498
This commit is contained in:
parent
c1671731c6
commit
a126d2972b
@ -171,21 +171,18 @@ public:
|
||||
IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); }
|
||||
IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; }
|
||||
|
||||
template <class X>
|
||||
IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> &&S) : Obj(S.get()) {
|
||||
template <class X,
|
||||
std::enable_if_t<std::is_convertible<X *, T *>::value, bool> = true>
|
||||
IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> S) : Obj(S.get()) {
|
||||
S.Obj = nullptr;
|
||||
}
|
||||
|
||||
template <class X>
|
||||
template <class X,
|
||||
std::enable_if_t<std::is_convertible<X *, T *>::value, bool> = true>
|
||||
IntrusiveRefCntPtr(std::unique_ptr<X> S) : Obj(S.release()) {
|
||||
retain();
|
||||
}
|
||||
|
||||
template <class X>
|
||||
IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> &S) : Obj(S.get()) {
|
||||
retain();
|
||||
}
|
||||
|
||||
~IntrusiveRefCntPtr() { release(); }
|
||||
|
||||
IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) {
|
||||
|
@ -96,4 +96,50 @@ TEST(IntrusiveRefCntPtr, UsesTraitsToRetainAndRelease) {
|
||||
EXPECT_TRUE(Retained);
|
||||
}
|
||||
|
||||
// Test that the generic constructors use SFINAE to disable invalid
|
||||
// conversions.
|
||||
struct X : RefCountedBase<X> {};
|
||||
struct Y : X {};
|
||||
struct Z : RefCountedBase<Z> {};
|
||||
static_assert(!std::is_convertible<IntrusiveRefCntPtr<X> &&,
|
||||
IntrusiveRefCntPtr<Y>>::value,
|
||||
"X&& -> Y should be rejected with SFINAE");
|
||||
static_assert(!std::is_convertible<const IntrusiveRefCntPtr<X> &,
|
||||
IntrusiveRefCntPtr<Y>>::value,
|
||||
"const X& -> Y should be rejected with SFINAE");
|
||||
static_assert(
|
||||
!std::is_convertible<std::unique_ptr<X>, IntrusiveRefCntPtr<Y>>::value,
|
||||
"X -> Y should be rejected with SFINAE");
|
||||
static_assert(!std::is_convertible<IntrusiveRefCntPtr<X> &&,
|
||||
IntrusiveRefCntPtr<Z>>::value,
|
||||
"X&& -> Z should be rejected with SFINAE");
|
||||
static_assert(!std::is_convertible<const IntrusiveRefCntPtr<X> &,
|
||||
IntrusiveRefCntPtr<Z>>::value,
|
||||
"cosnt X& -> Z should be rejected with SFINAE");
|
||||
static_assert(
|
||||
!std::is_convertible<std::unique_ptr<X>, IntrusiveRefCntPtr<Z>>::value,
|
||||
"X -> Z should be rejected with SFINAE");
|
||||
|
||||
TEST(IntrusiveRefCntPtr, InteropsWithConvertible) {
|
||||
// Check converting constructors and operator=.
|
||||
auto Y1 = makeIntrusiveRefCnt<Y>();
|
||||
auto Y2 = makeIntrusiveRefCnt<Y>();
|
||||
auto Y3 = makeIntrusiveRefCnt<Y>();
|
||||
auto Y4 = makeIntrusiveRefCnt<Y>();
|
||||
const void *P1 = Y1.get();
|
||||
const void *P2 = Y2.get();
|
||||
const void *P3 = Y3.get();
|
||||
const void *P4 = Y4.get();
|
||||
IntrusiveRefCntPtr<X> X1 = std::move(Y1);
|
||||
IntrusiveRefCntPtr<X> X2 = Y2;
|
||||
IntrusiveRefCntPtr<X> X3;
|
||||
IntrusiveRefCntPtr<X> X4;
|
||||
X3 = std::move(Y3);
|
||||
X4 = Y4;
|
||||
EXPECT_EQ(P1, X1.get());
|
||||
EXPECT_EQ(P2, X2.get());
|
||||
EXPECT_EQ(P3, X3.get());
|
||||
EXPECT_EQ(P4, X4.get());
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
Loading…
Reference in New Issue
Block a user