diff --git a/include/llvm/IR/ValueHandle.h b/include/llvm/IR/ValueHandle.h index 9435e9404a4..1370802d6cb 100644 --- a/include/llvm/IR/ValueHandle.h +++ b/include/llvm/IR/ValueHandle.h @@ -34,7 +34,7 @@ protected: /// /// This is to avoid having a vtable for the light-weight handle pointers. The /// fully general Callback version does have a vtable. - enum HandleBaseKind { Assert, Callback, WeakTracking }; + enum HandleBaseKind { Assert, Callback, Weak, WeakTracking }; ValueHandleBase(const ValueHandleBase &RHS) : ValueHandleBase(RHS.PrevPair.getInt(), RHS) {} @@ -46,7 +46,7 @@ protected: } private: - PointerIntPair PrevPair; + PointerIntPair PrevPair; ValueHandleBase *Next; Value *Val; @@ -134,6 +134,42 @@ private: void AddToUseList(); }; +/// \brief A nullable Value handle that is nullable. +/// +/// This is a value handle that points to a value, and nulls itself +/// out if that value is deleted. +class WeakVH : public ValueHandleBase { +public: + WeakVH() : ValueHandleBase(Weak) {} + WeakVH(Value *P) : ValueHandleBase(Weak, P) {} + WeakVH(const WeakVH &RHS) + : ValueHandleBase(Weak, RHS) {} + + WeakVH &operator=(const WeakVH &RHS) = default; + + Value *operator=(Value *RHS) { + return ValueHandleBase::operator=(RHS); + } + Value *operator=(const ValueHandleBase &RHS) { + return ValueHandleBase::operator=(RHS); + } + + operator Value*() const { + return getValPtr(); + } +}; + +// Specialize simplify_type to allow WeakVH to participate in +// dyn_cast, isa, etc. +template <> struct simplify_type { + typedef Value *SimpleType; + static SimpleType getSimplifiedValue(WeakVH &WVH) { return WVH; } +}; +template <> struct simplify_type { + typedef Value *SimpleType; + static SimpleType getSimplifiedValue(const WeakVH &WVH) { return WVH; } +}; + /// \brief Value handle that is nullable, but tries to track the Value. /// /// This is a value handle that tries hard to point to a Value, even across diff --git a/lib/IR/Value.cpp b/lib/IR/Value.cpp index bde5b3a8ce0..02b40c93b5d 100644 --- a/lib/IR/Value.cpp +++ b/lib/IR/Value.cpp @@ -820,8 +820,10 @@ void ValueHandleBase::ValueIsDeleted(Value *V) { switch (Entry->getKind()) { case Assert: break; + case Weak: case WeakTracking: - // WeakTracking just goes to null, which will unlink it from the list. + // WeakTracking and Weak just go to null, which unlinks them + // from the list. Entry->operator=(nullptr); break; case Callback: @@ -869,7 +871,8 @@ void ValueHandleBase::ValueIsRAUWd(Value *Old, Value *New) { switch (Entry->getKind()) { case Assert: - // Asserting handle does not follow RAUW implicitly. + case Weak: + // Asserting and Weak handles do not follow RAUW implicitly. break; case WeakTracking: // Weak goes to the new value, which will unlink it from Old's list. diff --git a/unittests/IR/ValueHandleTest.cpp b/unittests/IR/ValueHandleTest.cpp index 96331288d07..9a4ce156dc3 100644 --- a/unittests/IR/ValueHandleTest.cpp +++ b/unittests/IR/ValueHandleTest.cpp @@ -34,6 +34,24 @@ public: ConcreteCallbackVH(Value *V) : CallbackVH(V) {} }; +TEST_F(ValueHandle, WeakVH_BasicOperation) { + WeakVH WVH(BitcastV.get()); + EXPECT_EQ(BitcastV.get(), WVH); + WVH = ConstantV; + EXPECT_EQ(ConstantV, WVH); + + // Make sure I can call a method on the underlying Value. It + // doesn't matter which method. + EXPECT_EQ(Type::getInt32Ty(Context), WVH->getType()); + EXPECT_EQ(Type::getInt32Ty(Context), (*WVH).getType()); + + WVH = BitcastV.get(); + BitcastV->replaceAllUsesWith(ConstantV); + EXPECT_EQ(WVH, BitcastV.get()); + BitcastV.reset(); + EXPECT_EQ(WVH, nullptr); +} + TEST_F(ValueHandle, WeakTrackingVH_BasicOperation) { WeakTrackingVH WVH(BitcastV.get()); EXPECT_EQ(BitcastV.get(), WVH);