diff --git a/src/include/midend/IR.h b/src/include/midend/IR.h index 5658d9d..ff30db7 100644 --- a/src/include/midend/IR.h +++ b/src/include/midend/IR.h @@ -232,7 +232,7 @@ class Value { void replaceAllUsesWith(Value *value); ///< 将原来使用该value的使用者全变为使用给定参数value并修改相应use关系 void removeUse(const std::shared_ptr &use) { assert(use != nullptr && "Use cannot be null"); - assert(use->getValue() != this && "Use does not belong to this Value"); + assert(use->getValue() == this && "Use being removed does NOT point to this Value!"); auto it = std::find(uses.begin(), uses.end(), use); assert(it != uses.end() && "Use not found in Value's uses"); uses.remove(use); diff --git a/src/midend/IR.cpp b/src/midend/IR.cpp index 10b133f..ae676f0 100644 --- a/src/midend/IR.cpp +++ b/src/midend/IR.cpp @@ -118,13 +118,45 @@ ArrayType *ArrayType::get(Type *elementType, unsigned numElements) { return result.first->get(); } +// void Value::replaceAllUsesWith(Value *value) { +// for (auto &use : uses) { +// auto user = use->getUser(); +// assert(user && "Use's user cannot be null"); +// user->setOperand(use->getIndex(), value); +// } +// uses.clear(); +// } void Value::replaceAllUsesWith(Value *value) { - for (auto &use : uses) { - use->getUser()->setOperand(use->getIndex(), value); - } - uses.clear(); -} + // 1. 创建 uses 列表的副本进行迭代。 + // 这样做是为了避免在迭代过程中,由于 setOperand 间接调用 removeUse 或 addUse + // 导致原列表被修改,从而引发迭代器失效问题。 + std::list> uses_copy = uses; + for (auto &use_ptr : uses_copy) { // 遍历副本 + // 2. 检查 shared_ptr 本身是否为空。这是最常见的崩溃原因之一。 + if (use_ptr == nullptr) { + std::cerr << "Warning: Encountered a null std::shared_ptr in Value::uses list. Skipping this entry." << std::endl; + // 在一个健康的 IR 中,这种情况不应该发生。如果经常出现,说明你的 Use 创建或管理有问题。 + continue; // 跳过空的智能指针 + } + + // 3. 检查 Use 对象内部的 User* 是否为空。 + User* user_val = use_ptr->getUser(); + if (user_val == nullptr) { + std::cerr << "Warning: Use object (" << use_ptr.get() << ") has a null User* in replaceAllUsesWith. Skipping this entry. This indicates IR corruption." << std::endl; + // 同样,在一个健康的 IR 中,Use 对象的 User* 不应该为空。 + continue; // 跳过用户指针为空的 Use 对象 + } + + // 如果走到这里,use_ptr 和 user_val 都是有效的,可以安全调用 setOperand + user_val->setOperand(use_ptr->getIndex(), value); + } + + // 4. 处理完所有 use 之后,清空原始的 uses 列表。 + // replaceAllUsesWith 的目的就是将所有使用关系从当前 Value 转移走, + // 所以最后清空列表是正确的。 + uses.clear(); +} // Implementations for static members