Error in replacing mlir::Operation while traversing the IR

Hello,

I want to transform the IR in one pass.
So I visit the IR in a recursive manner.

Under the following code snippet:

  for (Operation &op : block.getOperations()) {
        changeOperation(&op);
    }

I traverse the operations under a block. The changeOperation method replaces the current operation by another one.

   IRRewriter rewriter(&getContext());
   rewriter.setInsertionPoint(op);
   auto anotherOp = rewriter.create... // create another op
   rewriter.replaceOp(op, {anotherOp }); // replace the operation by another op

However, I am getting the following error while running the program.

 #0 0x000055f8504f7e0f PrintStackTraceSignalHandler(void*) (./bin/cijie-opt+0x1d4e0f)
 #1 0x000055f8504f5a1f SignalHandler(int) (./bin/cijie-opt+0x1d2a1f)
 #2 0x00007fe5f4de48a0 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x128a0)
 #3 0x000055f8503a4c28 llvm::PointerIntPair<llvm::ilist_node_base<true>*, 1u, unsigned int, llvm::PointerLikeTypeTraits<llvm::ilist_node_base<true>*>, llvm::PointerIntPairInfo<llvm::ilist_node_base<true>*, 1u, llvm::PointerLikeTypeTraits<llvm::ilist_node_base<true>*> > >::getInt() const (./bin/cijie-opt+0x81c28)
 #4 0x000055f8503a3e22 llvm::ilist_node_base<true>::isSentinel() const (./bin/cijie-opt+0x80e22)
 #5 0x000055f8503a3e42 llvm::ilist_node_base<true>::isKnownSentinel() const (./bin/cijie-opt+0x80e42)
 #6 0x000055f8503a4e87 llvm::ilist_iterator<llvm::ilist_detail::node_options<mlir::Operation, true, false, void>, false, false>::operator*() const (./bin/cijie-opt+0x81e87)

Could anyone help me out where goes wrong?

Blocks are linked lists of operations. By replacing the current operation, you erase it from the list so your loop cannot query it to get the next operation, which leads to a segfault. LLVM has a handy wrapper llvm::make_early_inc_range that makes a range such that the next element is obtained before entering the loop so you can erase the current element in the loop.

Surrounding llvm::make_early_inc_range() around block, so something like this should help

for (Operation &op : llvm::make_early_inc_range(block))