https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97609
--- Comment #4 from Andrew Macleod <amacleod at redhat dot com> --- This worked OK because the code does: /* Replace real uses in the statement. */ did_replace |= substitute_and_fold_engine->replace_uses_in (stmt); gimple_stmt_iterator prev_gsi = i; gsi_prev (&prev_gsi); /* If we made a replacement, fold the statement. */ if (did_replace) { fold_stmt (&i, follow_single_use_edges); stmt = gsi_stmt (i); gimple_set_modified (stmt, true); } basically replace uses, and then folded the statement to make it right. Enter the hybrid folder... and if you look closely at substitute_and_fold_engine::replace_uses_in (), you will see: FOR_EACH_SSA_USE_OPERAND (use, stmt, iter, SSA_OP_USE) { tree tuse = USE_FROM_PTR (use); tree val = value_of_expr (tuse, stmt); <...> The statement giving us grief is: _11->_M_next = __keep_12(D); where EVRP has decided that _11 can be replaced by &__to_destroy._M_head replace_uses_in () loops thru the SSA_NAMEs in the stmt. THe first one is _11, which it proceeds to replace with &__to_destroy._M_head, producing our problematic __to_destroy._M_head._M_next = __keep_12(D); but before returning and calling fold_stmt to fix it up, it looks at the next ssa_name, __keep_12 and calls tree val = value_of_expr (tuse, stmt); which causes a ranger lookup for __keep_12 on this stmt. Normally, that wouldn't be a big deal either because we don't need to look at this statement, but because its a pointer, it triggers a call to the rangers non-null pointer tracking code. __keep_12 has never been "checked" before, so the non-null pointer code goes and quickly visits each use to globally mark which blocks trigger a non-null deference for future use... and voila... it visits this malformed statement and dies. Now. what to do about it. I don't think replace_uses is doing anything wrong. This is purely the fault of non-null deref tracking, which I plan to revamp before the next stage 1... Let me think...