===================================================================
@@ -0,0 +1,59 @@
+// { dg-lto-do run }
+// { dg-require-linker-plugin "" }
+// { dg-lto-options {{-O2 -fuse-linker-plugin -fno-early-inlining}}
+
+extern "C" void abort (void);
+extern "C" void linker_error ();
+
+class A
+{
+public:
+ int data;
+ virtual int foo (int i)
+ {
+ return i + 1;
+ }
+};
+
+class B : public A
+{
+public:
+ virtual int foo (int i)
+ {
+ return i + 2;
+ }
+};
+
+class C : public A
+{
+public:
+ virtual int foo (int i)
+ {
+ linker_error ();
+ return i + 3;
+ }
+};
+
+
+static int middleman (class A *obj, int i)
+{
+ return obj->foo (i);
+}
+
+int __attribute__ ((noinline,noclone)) get_input(void)
+{
+ return 1;
+}
+
+int main (int argc, char *argv[])
+{
+ class B b;
+ if (middleman (&b, get_input ()) != 3)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*B::foo" "cp" } } */
+/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
===================================================================
@@ -1285,11 +1287,9 @@ produce_symtab (struct output_block *ob)
struct streamer_tree_cache_d *cache = ob->writer_cache;
char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL);
struct pointer_set_t *seen;
- struct cgraph_node *node;
- struct varpool_node *vnode;
struct lto_output_stream stream;
lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
- int i;
+ lto_symtab_encoder_iterator lsei;
lto_begin_section (section_name, false);
free (section_name);
@@ -1297,78 +1297,26 @@ produce_symtab (struct output_block *ob)
seen = pointer_set_create ();
memset (&stream, 0, sizeof (stream));
- /* Write all functions.
- First write all defined functions and then write all used functions.
- This is done so only to handle duplicated symbols in cgraph. */
- for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
+ /* Write the symbol table.
+ First write everything defined and then all declarations.
+ This is neccesary to handle cases where we have duplicated symbols. */
+ for (lsei = lsei_start (encoder);
+ !lsei_end_p (lsei); lsei_next (&lsei))
{
- if (!symtab_function_p (lto_symtab_encoder_deref (encoder, i)))
- continue;
- node = cgraph (lto_symtab_encoder_deref (encoder, i));
- if (DECL_EXTERNAL (node->symbol.decl))
- continue;
- if (DECL_COMDAT (node->symbol.decl)
- && cgraph_comdat_can_be_unshared_p (node))
- continue;
- if ((node->alias && !node->thunk.alias) || node->global.inlined_to)
+ symtab_node node = lsei_node (lsei);
+
+ if (!symtab_real_symbol_p (node) || DECL_EXTERNAL (node->symbol.decl))
continue;
write_symbol (cache, &stream, node->symbol.decl, seen, false);
}
- for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
+ for (lsei = lsei_start (encoder);
+ !lsei_end_p (lsei); lsei_next (&lsei))
{
- if (!symtab_function_p (lto_symtab_encoder_deref (encoder, i)))
- continue;
- node = cgraph (lto_symtab_encoder_deref (encoder, i));
- if (!DECL_EXTERNAL (node->symbol.decl))
- continue;
- /* We keep around unused extern inlines in order to be able to inline
- them indirectly or via vtables. Do not output them to symbol
- table: they end up being undefined and just consume space. */
- if (!node->symbol.address_taken && !node->callers)
- continue;
- if (DECL_COMDAT (node->symbol.decl)
- && cgraph_comdat_can_be_unshared_p (node))
- continue;
- if ((node->alias && !node->thunk.alias) || node->global.inlined_to)
- continue;
- write_symbol (cache, &stream, node->symbol.decl, seen, false);
- }
+ symtab_node node = lsei_node (lsei);
- /* Write all variables. */
- for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
- {
- if (!symtab_variable_p (lto_symtab_encoder_deref (encoder, i)))
- continue;
- vnode = varpool (lto_symtab_encoder_deref (encoder, i));
- if (DECL_EXTERNAL (vnode->symbol.decl))
- continue;
- /* COMDAT virtual tables can be unshared. Do not declare them
- in the LTO symbol table to prevent linker from forcing them
- into the output. */
- if (DECL_COMDAT (vnode->symbol.decl)
- && !vnode->symbol.force_output
- && vnode->finalized
- && DECL_VIRTUAL_P (vnode->symbol.decl))
- continue;
- if (vnode->alias && !vnode->alias_of)
- continue;
- write_symbol (cache, &stream, vnode->symbol.decl, seen, false);
- }
- for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
- {
- if (!symtab_variable_p (lto_symtab_encoder_deref (encoder, i)))
- continue;
- vnode = varpool (lto_symtab_encoder_deref (encoder, i));
- if (!DECL_EXTERNAL (vnode->symbol.decl))
+ if (!symtab_real_symbol_p (node) || !DECL_EXTERNAL (node->symbol.decl))
continue;
- if (DECL_COMDAT (vnode->symbol.decl)
- && !vnode->symbol.force_output
- && vnode->finalized
- && DECL_VIRTUAL_P (vnode->symbol.decl))
- continue;
- if (vnode->alias && !vnode->alias_of)
- continue;
- write_symbol (cache, &stream, vnode->symbol.decl, seen, false);
+ write_symbol (cache, &stream, node->symbol.decl, seen, false);
}
lto_write_stream (&stream);