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...