diff options
author | Duncan P. N. Exon Smith <dexonsmith@apple.com> | 2014-12-12 19:24:33 +0000 |
---|---|---|
committer | Duncan P. N. Exon Smith <dexonsmith@apple.com> | 2014-12-12 19:24:33 +0000 |
commit | 121eeff4f3cfa2e9b577dce342fd365462b95a4f (patch) | |
tree | 03f7bdb7dad14f464f2aa2f10f9cbaaaf0dc91ce | |
parent | fdb705318aa5cce4b238a2694db72d925afbeec9 (diff) | |
download | bcm5719-llvm-121eeff4f3cfa2e9b577dce342fd365462b95a4f.tar.gz bcm5719-llvm-121eeff4f3cfa2e9b577dce342fd365462b95a4f.zip |
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
-rw-r--r-- | llvm/lib/IR/Metadata.cpp | 3 | ||||
-rw-r--r-- | llvm/unittests/IR/MetadataTest.cpp | 47 |
2 files changed, 49 insertions, 1 deletions
diff --git a/llvm/lib/IR/Metadata.cpp b/llvm/lib/IR/Metadata.cpp index 506284fa87a..b45d0e393bd 100644 --- a/llvm/lib/IR/Metadata.cpp +++ b/llvm/lib/IR/Metadata.cpp @@ -173,7 +173,8 @@ void ReplaceableMetadataImpl::replaceAllUsesWith(Metadata *MD) { // Update unowned tracking references directly. Metadata *&Ref = *static_cast<Metadata **>(Pair.first); Ref = MD; - MetadataTracking::track(Ref); + if (MD) + MetadataTracking::track(Ref); UseMap.erase(Pair.first); continue; } diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp index d45aaae9316..3b99739eebe 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -207,6 +207,53 @@ TEST_F(MetadataAsValueTest, MDNodeConstant) { 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 = |