@@ -258,7 +258,9 @@ class PredEdgeList
258258// PredBlockList: adapter class for forward iteration of the predecessor edge linked list yielding
259259// predecessor blocks, using range-based `for`, normally used via BasicBlock::PredBlocks(), e.g.:
260260// for (BasicBlock* const predBlock : block->PredBlocks()) ...
261+ // allowEdits controls whether the iterator should be resilient to changes to the predecessor list.
261262//
263+ template <bool allowEdits>
262264class PredBlockList
263265{
264266 FlowEdge* m_begin;
@@ -270,13 +272,12 @@ class PredBlockList
270272 {
271273 FlowEdge* m_pred;
272274
273- #ifdef DEBUG
274- // Try to guard against the user of the iterator from making changes to the IR that would invalidate
275- // the iterator: cache the edge we think should be next, then check it when we actually do the `++`
275+ // When allowEdits=false, try to guard against the user of the iterator from modifying the predecessor list
276+ // being traversed: cache the edge we think should be next, then check it when we actually do the `++`
276277 // operation. This is a bit conservative, but attempts to protect against callers assuming too much about
277278 // this iterator implementation.
279+ // When allowEdits=true, m_next is always used to update m_pred, so changes to m_pred don't break the iterator.
278280 FlowEdge* m_next;
279- #endif
280281
281282 public:
282283 iterator (FlowEdge* pred);
@@ -1530,9 +1531,18 @@ struct BasicBlock : private LIR::Range
15301531 // PredBlocks: convenience method for enabling range-based `for` iteration over predecessor blocks, e.g.:
15311532 // for (BasicBlock* const predBlock : block->PredBlocks()) ...
15321533 //
1533- PredBlockList PredBlocks () const
1534+ PredBlockList<false > PredBlocks () const
1535+ {
1536+ return PredBlockList<false >(bbPreds);
1537+ }
1538+
1539+ // PredBlocksEditing: convenience method for enabling range-based `for` iteration over predecessor blocks, e.g.:
1540+ // for (BasicBlock* const predBlock : block->PredBlocksList()) ...
1541+ // This iterator tolerates modifications to bbPreds.
1542+ //
1543+ PredBlockList<true > PredBlocksEditing () const
15341544 {
1535- return PredBlockList (bbPreds);
1545+ return PredBlockList< true > (bbPreds);
15361546 }
15371547
15381548 // Pred list maintenance
@@ -2399,29 +2409,45 @@ inline PredEdgeList::iterator& PredEdgeList::iterator::operator++()
23992409 return *this ;
24002410}
24012411
2402- inline PredBlockList::iterator::iterator (FlowEdge* pred) : m_pred(pred)
2412+ template <bool allowEdits>
2413+ inline PredBlockList<allowEdits>::iterator::iterator(FlowEdge* pred) : m_pred(pred)
24032414{
2404- #ifdef DEBUG
2405- m_next = (m_pred == nullptr ) ? nullptr : m_pred->getNextPredEdge ();
2406- #endif
2415+ bool initNextPointer = allowEdits;
2416+ INDEBUG (initNextPointer = true );
2417+ if (initNextPointer)
2418+ {
2419+ m_next = (m_pred == nullptr ) ? nullptr : m_pred->getNextPredEdge ();
2420+ }
24072421}
24082422
2409- inline BasicBlock* PredBlockList::iterator::operator *() const
2423+ template <bool allowEdits>
2424+ inline BasicBlock* PredBlockList<allowEdits>::iterator::operator *() const
24102425{
24112426 return m_pred->getSourceBlock ();
24122427}
24132428
2414- inline PredBlockList::iterator& PredBlockList::iterator::operator ++()
2429+ template <bool allowEdits>
2430+ inline typename PredBlockList<allowEdits>::iterator& PredBlockList<allowEdits>::iterator::operator ++()
24152431{
2416- FlowEdge* next = m_pred->getNextPredEdge ();
2432+ if (allowEdits)
2433+ {
2434+ // For editing iterators, m_next is always used and maintained
2435+ m_pred = m_next;
2436+ m_next = (m_next == nullptr ) ? nullptr : m_next->getNextPredEdge ();
2437+ }
2438+ else
2439+ {
2440+ FlowEdge* next = m_pred->getNextPredEdge ();
24172441
24182442#ifdef DEBUG
2419- // Check that the next block is the one we expect to see.
2420- assert (next == m_next);
2421- m_next = (next == nullptr ) ? nullptr : next ->getNextPredEdge ();
2443+ // If allowEdits=false, check that the next block is the one we expect to see.
2444+ assert (next == m_next);
2445+ m_next = (m_next == nullptr ) ? nullptr : m_next ->getNextPredEdge ();
24222446#endif // DEBUG
24232447
2424- m_pred = next;
2448+ m_pred = next;
2449+ }
2450+
24252451 return *this ;
24262452}
24272453
0 commit comments