diff --git a/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h b/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h --- a/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h +++ b/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h @@ -171,21 +171,18 @@ IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); } IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; } - template - IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.get()) { + template ::value, bool> = true> + IntrusiveRefCntPtr(IntrusiveRefCntPtr S) : Obj(S.get()) { S.Obj = nullptr; } - template + template ::value, bool> = true> IntrusiveRefCntPtr(std::unique_ptr S) : Obj(S.release()) { retain(); } - template - IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.get()) { - retain(); - } - ~IntrusiveRefCntPtr() { release(); } IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) { diff --git a/llvm/unittests/ADT/IntrusiveRefCntPtrTest.cpp b/llvm/unittests/ADT/IntrusiveRefCntPtrTest.cpp --- a/llvm/unittests/ADT/IntrusiveRefCntPtrTest.cpp +++ b/llvm/unittests/ADT/IntrusiveRefCntPtrTest.cpp @@ -96,4 +96,50 @@ EXPECT_TRUE(Retained); } +// Test that the generic constructors use SFINAE to disable invalid +// conversions. +struct X : RefCountedBase {}; +struct Y : X {}; +struct Z : RefCountedBase {}; +static_assert(!std::is_convertible &&, + IntrusiveRefCntPtr>::value, + "X&& -> Y should be rejected with SFINAE"); +static_assert(!std::is_convertible &, + IntrusiveRefCntPtr>::value, + "const X& -> Y should be rejected with SFINAE"); +static_assert( + !std::is_convertible, IntrusiveRefCntPtr>::value, + "X -> Y should be rejected with SFINAE"); +static_assert(!std::is_convertible &&, + IntrusiveRefCntPtr>::value, + "X&& -> Z should be rejected with SFINAE"); +static_assert(!std::is_convertible &, + IntrusiveRefCntPtr>::value, + "cosnt X& -> Z should be rejected with SFINAE"); +static_assert( + !std::is_convertible, IntrusiveRefCntPtr>::value, + "X -> Z should be rejected with SFINAE"); + +TEST(IntrusiveRefCntPtr, InteropsWithConvertible) { + // Check converting constructors and operator=. + auto Y1 = makeIntrusiveRefCnt(); + auto Y2 = makeIntrusiveRefCnt(); + auto Y3 = makeIntrusiveRefCnt(); + auto Y4 = makeIntrusiveRefCnt(); + const void *P1 = Y1.get(); + const void *P2 = Y2.get(); + const void *P3 = Y3.get(); + const void *P4 = Y4.get(); + IntrusiveRefCntPtr X1 = std::move(Y1); + IntrusiveRefCntPtr X2 = Y2; + IntrusiveRefCntPtr X3; + IntrusiveRefCntPtr 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