===================================================================
@@ -440,6 +440,8 @@ struct GTY(()) cgraph_indirect_call_info
/* Set when the call is a call of a pointer loaded from contents of an
aggregate at offset. */
unsigned agg_contents : 1;
+ /* Set when this is a call through a member pointer. */
+ unsigned member_ptr : 1;
/* When the previous bit is set, this one determines whether the destination
is loaded from a parameter passed by reference. */
unsigned by_ref : 1;
===================================================================
@@ -288,8 +288,9 @@ ipa_print_node_jump_functions (FILE *f,
ii = cs->indirect_info;
if (ii->agg_contents)
- fprintf (f, " indirect aggregate callsite, calling param %i, "
+ fprintf (f, " indirect %s callsite, calling param %i, "
"offset " HOST_WIDE_INT_PRINT_DEC ", %s",
+ ii->member_ptr ? "member ptr" : "aggregate",
ii->param_index, ii->offset,
ii->by_ref ? "by reference" : "by_value");
else
@@ -1608,6 +1609,7 @@ ipa_note_param_call (struct cgraph_node
cs->indirect_info->offset = 0;
cs->indirect_info->polymorphic = 0;
cs->indirect_info->agg_contents = 0;
+ cs->indirect_info->member_ptr = 0;
return cs;
}
@@ -1801,6 +1803,7 @@ ipa_analyze_indirect_call_uses (struct c
struct cgraph_edge *cs = ipa_note_param_call (node, index, call);
cs->indirect_info->offset = offset;
cs->indirect_info->agg_contents = 1;
+ cs->indirect_info->member_ptr = 1;
}
return;
@@ -2212,6 +2215,10 @@ ipa_make_edge_direct_to_target (struct c
target = canonicalize_constructor_val (target, NULL);
if (!target || TREE_CODE (target) != FUNCTION_DECL)
{
+ if (ie->indirect_info->member_ptr)
+ /* Member pointer call that goes through a VMT lookup. */
+ return NULL;
+
if (dump_file)
fprintf (dump_file, "ipa-prop: Discovered direct call to non-function"
" in %s/%i, making it unreachable.\n",
@@ -3765,6 +3772,7 @@ ipa_write_indirect_edge_info (struct out
bp = bitpack_create (ob->main_stream);
bp_pack_value (&bp, ii->polymorphic, 1);
bp_pack_value (&bp, ii->agg_contents, 1);
+ bp_pack_value (&bp, ii->member_ptr, 1);
bp_pack_value (&bp, ii->by_ref, 1);
streamer_write_bitpack (&bp);
@@ -3791,6 +3799,7 @@ ipa_read_indirect_edge_info (struct lto_
bp = streamer_read_bitpack (ib);
ii->polymorphic = bp_unpack_value (&bp, 1);
ii->agg_contents = bp_unpack_value (&bp, 1);
+ ii->member_ptr = bp_unpack_value (&bp, 1);
ii->by_ref = bp_unpack_value (&bp, 1);
if (ii->polymorphic)
{
===================================================================
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-early-inlining" } */
+
+class H
+{
+public:
+ virtual unsigned bar() const { return 16; }
+};
+
+class A : public H
+{
+ unsigned foo(unsigned (H::*func)(void) const) const;
+public:
+ H *h;
+ virtual unsigned bar() const;
+};
+
+unsigned A::foo(unsigned (H::*func)(void) const) const
+{
+ return (h->*func)();
+}
+
+unsigned A::bar() const
+{
+ return foo(&H::bar);
+}
+
+int main (int argc, char **argv)
+{
+ H h;
+ A a;
+ a.h = &h;
+
+ if (a.bar() != 16)
+ __builtin_abort ();
+ return 0;
+}