IR: Don't track nullptr on metadata RAUW
The RAUW support in `Metadata` supports going to `nullptr` specifically
to handle values being deleted, causing `ValueAsMetadata` to be deleted.
Fix the case where the reference is from a `TrackingMDRef` (as opposed
to an `MDOperand` or a `MetadataAsValue`).
This is surprisingly rare -- metadata tracked by `TrackingMDRef` going
to null -- but it came up in an openSUSE bootstrap during inlining. The
tracking ref was held by the `ValueMap` because it was referencing a
local, the basic block containing the local became dead after it had
been merged in, and when the local was deleted, the tracking ref
asserted in an `isa`.
llvm-svn: 224146
diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index d45aaae..3b99739 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -207,6 +207,53 @@
EXPECT_EQ(V, V2);
}
+typedef MetadataTest ValueAsMetadataTest;
+
+TEST_F(ValueAsMetadataTest, UpdatesOnRAUW) {
+ Type *Ty = Type::getInt1PtrTy(Context);
+ std::unique_ptr<GlobalVariable> GV0(
+ new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage));
+ auto *MD = ValueAsMetadata::get(GV0.get());
+ EXPECT_TRUE(MD->getValue() == GV0.get());
+ ASSERT_TRUE(GV0->use_empty());
+
+ std::unique_ptr<GlobalVariable> GV1(
+ new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage));
+ GV0->replaceAllUsesWith(GV1.get());
+ EXPECT_TRUE(MD->getValue() == GV1.get());
+}
+
+typedef MetadataTest TrackingMDRefTest;
+
+TEST_F(TrackingMDRefTest, UpdatesOnRAUW) {
+ Type *Ty = Type::getInt1PtrTy(Context);
+ std::unique_ptr<GlobalVariable> GV0(
+ new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage));
+ TypedTrackingMDRef<ValueAsMetadata> MD(ValueAsMetadata::get(GV0.get()));
+ EXPECT_TRUE(MD->getValue() == GV0.get());
+ ASSERT_TRUE(GV0->use_empty());
+
+ std::unique_ptr<GlobalVariable> GV1(
+ new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage));
+ GV0->replaceAllUsesWith(GV1.get());
+ EXPECT_TRUE(MD->getValue() == GV1.get());
+
+ // Reset it, so we don't inadvertently test deletion.
+ MD.reset();
+}
+
+TEST_F(TrackingMDRefTest, UpdatesOnDeletion) {
+ Type *Ty = Type::getInt1PtrTy(Context);
+ std::unique_ptr<GlobalVariable> GV(
+ new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage));
+ TypedTrackingMDRef<ValueAsMetadata> MD(ValueAsMetadata::get(GV.get()));
+ EXPECT_TRUE(MD->getValue() == GV.get());
+ ASSERT_TRUE(GV->use_empty());
+
+ GV.reset();
+ EXPECT_TRUE(!MD);
+}
+
TEST(NamedMDNodeTest, Search) {
LLVMContext Context;
ConstantAsMetadata *C =