From e2b37447b715b1eaa507de117fcb18beea6a4601 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Tue, 13 May 2014 01:23:21 +0000 Subject: [PATCH] Assert that we don't RAUW a Constant with a ConstantExpr that contains it. We already had an assert for foo->RAUW(foo), but not for something like foo->RAUW(GEP(foo)) and would go in an infinite loop trying to apply the replacement. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208663 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/IR/Value.cpp | 37 ++++++++++++++++++++++++++++++++++++- unittests/IR/ConstantsTest.cpp | 17 +++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/lib/IR/Value.cpp b/lib/IR/Value.cpp index 2ebdb702cf9..9a79e43359e 100644 --- a/lib/IR/Value.cpp +++ b/lib/IR/Value.cpp @@ -301,10 +301,45 @@ void Value::takeName(Value *V) { ST->reinsertValue(this); } +#ifndef NDEBUG +static bool contains(SmallPtrSet &Cache, ConstantExpr *Expr, + Constant *C) { + if (!Cache.insert(Expr)) + return false; + + for (auto &O : Expr->operands()) { + if (O == C) + return true; + auto *CE = dyn_cast(O); + if (!CE) + continue; + if (contains(Cache, CE, C)) + return true; + } + return false; +} + +static bool contains(Value *Expr, Value *V) { + if (Expr == V) + return true; + + auto *C = dyn_cast(V); + if (!C) + return false; + + auto *CE = dyn_cast(Expr); + if (!CE) + return false; + + SmallPtrSet Cache; + return contains(Cache, CE, C); +} +#endif void Value::replaceAllUsesWith(Value *New) { assert(New && "Value::replaceAllUsesWith() is invalid!"); - assert(New != this && "this->replaceAllUsesWith(this) is NOT valid!"); + assert(!contains(New, this) && + "this->replaceAllUsesWith(expr(this)) is NOT valid!"); assert(New->getType() == getType() && "replaceAllUses of value with new value of different type!"); diff --git a/unittests/IR/ConstantsTest.cpp b/unittests/IR/ConstantsTest.cpp index b3aa8102b64..59c9652e2ea 100644 --- a/unittests/IR/ConstantsTest.cpp +++ b/unittests/IR/ConstantsTest.cpp @@ -254,6 +254,23 @@ TEST(ConstantsTest, AsInstructionsTest) { P6STR ", i32 1"); } +#ifdef GTEST_HAS_DEATH_TEST +#ifndef NDEBUG +TEST(ConstantsTest, ReplaceWithConstantTest) { + std::unique_ptr M(new Module("MyModule", getGlobalContext())); + + Type *Int32Ty = Type::getInt32Ty(getGlobalContext()); + Constant *One = ConstantInt::get(Int32Ty, 1); + + Constant *Global = + M->getOrInsertGlobal("dummy", PointerType::getUnqual(Int32Ty)); + Constant *GEP = ConstantExpr::getGetElementPtr(Global, One); + EXPECT_DEATH(Global->replaceAllUsesWith(GEP), + "this->replaceAllUsesWith\\(expr\\(this\\)\\) is NOT valid!"); +} +#endif +#endif + #undef CHECK } // end anonymous namespace -- 2.11.0