diff --git a/llvm/include/llvm/IR/Metadata.h b/llvm/include/llvm/IR/Metadata.h --- a/llvm/include/llvm/IR/Metadata.h +++ b/llvm/include/llvm/IR/Metadata.h @@ -775,10 +775,21 @@ public: MDOperand() = default; - MDOperand(MDOperand &&) = delete; MDOperand(const MDOperand &) = delete; - MDOperand &operator=(MDOperand &&) = delete; + MDOperand(MDOperand &&Op) { + MD = Op.MD; + if (MD) + (void)MetadataTracking::retrack(Op.MD, MD); + Op.MD = nullptr; + } MDOperand &operator=(const MDOperand &) = delete; + MDOperand &operator=(MDOperand &&Op) { + MD = Op.MD; + if (MD) + (void)MetadataTracking::retrack(Op.MD, MD); + Op.MD = nullptr; + return *this; + } ~MDOperand() { untrack(); } Metadata *get() const { return MD; } diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -3602,4 +3602,33 @@ EXPECT_EQ(DebugVariableMap.find(DebugVariableFragB)->second, 12u); } +typedef MetadataTest MDTupleAllocationTest; +TEST_F(MDTupleAllocationTest, Tracking) { + // Make sure that the move constructor and move assignment op + // for MDOperand correctly adjust tracking information. + auto *Value1 = getConstantAsMetadata(); + MDTuple *A = MDTuple::getDistinct(Context, {Value1, Value1}); + EXPECT_EQ(A->getOperand(0), Value1); + EXPECT_EQ(A->getOperand(1), Value1); + + MDNode::op_range Ops = A->operands(); + + MDOperand NewOps1; + // Move assignment operator. + NewOps1 = std::move(*const_cast(Ops.begin())); + // Move constructor. + MDOperand NewOps2(std::move(*const_cast(Ops.begin() + 1))); + + EXPECT_EQ(NewOps1.get(), static_cast(Value1)); + EXPECT_EQ(NewOps2.get(), static_cast(Value1)); + + auto *Value2 = getConstantAsMetadata(); + Value *V1 = Value1->getValue(); + Value *V2 = Value2->getValue(); + ValueAsMetadata::handleRAUW(V1, V2); + + EXPECT_EQ(NewOps1.get(), static_cast(Value2)); + EXPECT_EQ(NewOps2.get(), static_cast(Value2)); +} + } // end namespace