@@ -1577,6 +1577,11 @@ fold_stmt_1 (gimple_stmt_iterator *gsi,
bool changed = false;
gimple stmt = gsi_stmt (*gsi);
unsigned i;
+ gimple_stmt_iterator gsinext = *gsi;
+ gimple next_stmt;
+
+ gsi_next (&gsinext);
+ next_stmt = gsi_end_p (gsinext) ? NULL : gsi_stmt (gsinext);
/* Fold the main computation performed by the statement. */
switch (gimple_code (stmt))
@@ -1665,10 +1670,19 @@ fold_stmt_1 (gimple_stmt_iterator *gsi,
default:;
}
+ /* If stmt folds into nothing and it was the last stmt in a bb,
+ don't call gsi_stmt. */
+ if (gsi_end_p (*gsi))
+ {
+ gcc_assert (next_stmt == NULL);
+ return changed;
+ }
+
stmt = gsi_stmt (*gsi);
- /* Fold *& on the lhs. */
- if (gimple_has_lhs (stmt))
+ /* Fold *& on the lhs. Don't do this if stmt folded into nothing,
+ as we'd changing the next stmt. */
+ if (gimple_has_lhs (stmt) && stmt != next_stmt)
{
tree lhs = gimple_get_lhs (stmt);
if (lhs && REFERENCE_CLASS_P (lhs))
@@ -4055,6 +4055,14 @@ fold_marked_statements (int first, struc
if (fold_stmt (&gsi))
{
gimple new_stmt;
+ /* If a builtin at the end of a bb folded into nothing,
+ the following loop won't work. */
+ if (gsi_end_p (gsi))
+ {
+ cgraph_update_edges_for_call_stmt (old_stmt,
+ old_decl, NULL);
+ break;
+ }
if (gsi_end_p (i2))
i2 = gsi_start_bb (BASIC_BLOCK (first));
else
@@ -1233,13 +1233,17 @@ cgraph_make_edge_direct (struct cgraph_e
/* Update or remove the corresponding cgraph edge if a GIMPLE_CALL
OLD_STMT changed into NEW_STMT. OLD_CALL is gimple_call_fndecl
- of OLD_STMT if it was previously call statement. */
+ of OLD_STMT if it was previously call statement.
+ If NEW_STMT is NULL, the call has been dropped without any
+ replacement. */
static void
cgraph_update_edges_for_call_stmt_node (struct cgraph_node *node,
- gimple old_stmt, tree old_call, gimple new_stmt)
+ gimple old_stmt, tree old_call,
+ gimple new_stmt)
{
- tree new_call = (is_gimple_call (new_stmt)) ? gimple_call_fndecl (new_stmt) : 0;
+ tree new_call = (new_stmt && is_gimple_call (new_stmt))
+ ? gimple_call_fndecl (new_stmt) : 0;
/* We are seeing indirect calls, then there is nothing to update. */
if (!new_call && !old_call)
@@ -1277,7 +1281,7 @@ cgraph_update_edges_for_call_stmt_node (
frequency = e->frequency;
cgraph_remove_edge (e);
}
- else
+ else if (new_call)
{
/* We are seeing new direct call; compute profile info based on BB. */
basic_block bb = gimple_bb (new_stmt);
@@ -0,0 +1,19 @@
+// PR c++/49264
+// { dg-do compile }
+// { dg-options "-O2" }
+
+struct B { };
+struct A { char a[sizeof (B) + 1]; } a;
+
+static inline void
+foo (const B &b)
+{
+ __builtin_memcpy (&a, &b, sizeof (b));
+}
+
+void
+bar ()
+{
+ B c;
+ foo (c);
+}