aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/cgraph.c5
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/torture/pr40102.C41
-rw-r--r--gcc/tree-inline.c9
5 files changed, 62 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c31e618..f6bf148 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2009-06-08 Jan Hubicka <jh@suse.cz>
+
+ PR middle-end/40102
+ * cgraph.c (cgraph_create_edge_including_clones): Also asume that the
+ original node might've been modified.
+ * tree-inline.c (copy_bb): Do not assume that all clones are the same.
+
2009-06-08 Jakub Jelinek <jakub@redhat.com>
* tree-object-size.c (addr_object_size): Add OSI argument.
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index fe1126b..53475d1 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -701,8 +701,9 @@ cgraph_create_edge_including_clones (struct cgraph_node *orig, struct cgraph_nod
{
struct cgraph_node *node;
- cgraph_create_edge (orig, callee, stmt, count, freq, loop_depth)->inline_failed =
- reason;
+ if (!cgraph_edge (orig, stmt))
+ cgraph_create_edge (orig, callee, stmt,
+ count, freq, loop_depth)->inline_failed = reason;
if (orig->clones)
for (node = orig->clones; node != orig;)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c6e7618..56dc2bc 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2009-06-08 Jan Hubicka <jh@suse.cz>
+
+ PR middle-end/40102
+ * g++.dg/torture/pr40102.C: New testcase.
+
2009-06-08 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/builtin-object-size-2.c (test1): Adjust expected results.
diff --git a/gcc/testsuite/g++.dg/torture/pr40102.C b/gcc/testsuite/g++.dg/torture/pr40102.C
new file mode 100644
index 0000000..49f56b5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr40102.C
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+bool foo0(int) { return true; }
+
+bool foo1();
+
+struct A
+{
+ A();
+ ~A();
+
+ template<typename T> void bar1(T f)
+ {
+ if (f(0))
+ foo1();
+ }
+
+ template<typename T> void bar2(T);
+};
+
+template<typename T> void A::bar2(T f)
+{
+ A a, b[1], *p;
+
+ while (foo1())
+ {
+ if (p)
+ ++p;
+ if (p && foo1())
+ bar1(f);
+ if (p)
+ ++p;
+ }
+
+ if (foo1())
+ bar1(f);
+}
+
+void baz()
+{
+ A().bar2(foo0);
+}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index f79424d..18c2c03 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -1508,11 +1508,14 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
gcc_unreachable ();
}
+ edge = cgraph_edge (id->src_node, orig_stmt);
/* Constant propagation on argument done during inlining
may create new direct call. Produce an edge for it. */
- if (!edge && is_gimple_call (stmt)
- && (fn = gimple_call_fndecl (stmt)) != NULL
- && !cgraph_edge (id->dst_node, stmt))
+ if ((!edge
+ || (edge->indirect_call
+ && id->transform_call_graph_edges == CB_CGE_MOVE_CLONES))
+ && is_gimple_call (stmt)
+ && (fn = gimple_call_fndecl (stmt)) != NULL)
{
struct cgraph_node *dest = cgraph_node (fn);