Assert that we don't RAUW a Constant with a ConstantExpr that contains it.
authorRafael Espindola <rafael.espindola@gmail.com>
Tue, 13 May 2014 01:23:21 +0000 (01:23 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Tue, 13 May 2014 01:23:21 +0000 (01:23 +0000)
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
unittests/IR/ConstantsTest.cpp

index 2ebdb702cf96a60792a08668b9e290dfa8e3ac51..9a79e43359ef6bb0819d4d8089383249cddf4172 100644 (file)
@@ -301,10 +301,45 @@ void Value::takeName(Value *V) {
     ST->reinsertValue(this);
 }
 
+#ifndef NDEBUG
+static bool contains(SmallPtrSet<ConstantExpr *, 4> &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<ConstantExpr>(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<Constant>(V);
+  if (!C)
+    return false;
+
+  auto *CE = dyn_cast<ConstantExpr>(Expr);
+  if (!CE)
+    return false;
+
+  SmallPtrSet<ConstantExpr *, 4> Cache;
+  return contains(Cache, CE, C);
+}
+#endif
 
 void Value::replaceAllUsesWith(Value *New) {
   assert(New && "Value::replaceAllUsesWith(<null>) 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!");
 
index b3aa8102b64d36b3de85cbd2e308b5afd6d69620..59c9652e2ea8c995064beda5a326959e0ad3bde2 100644 (file)
@@ -254,6 +254,23 @@ TEST(ConstantsTest, AsInstructionsTest) {
         P6STR ", i32 1");
 }
 
+#ifdef GTEST_HAS_DEATH_TEST
+#ifndef NDEBUG
+TEST(ConstantsTest, ReplaceWithConstantTest) {
+  std::unique_ptr<Module> 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