diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8f731ca5d8f..223e484a368 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2014-08-14 Jan Hubicka + + * ipa-utils.h (compare_virtual_tables): Declare. + * ipa-devirt.c (odr_subtypes_equivalent_p): New function + 2014-08-14 Marek Polacek DR 458 diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index 0f38655382d..2d356ad73b9 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -485,6 +485,120 @@ odr_subtypes_equivalent_p (tree t1, tree t2, hash_set *visited) return types_same_for_odr (t1, t2); } +/* Compare two virtual tables, PREVAILING and VTABLE and output ODR + violation warings. */ + +void +compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) +{ + int n1, n2; + if (DECL_VIRTUAL_P (prevailing->decl) != DECL_VIRTUAL_P (vtable->decl)) + { + odr_violation_reported = true; + if (DECL_VIRTUAL_P (prevailing->decl)) + { + varpool_node *tmp = prevailing; + prevailing = vtable; + vtable = tmp; + } + if (warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (vtable->decl))), + OPT_Wodr, + "virtual table of type %qD violates one definition rule", + DECL_CONTEXT (vtable->decl))) + inform (DECL_SOURCE_LOCATION (prevailing->decl), + "variable of same assembler name as the virtual table is " + "defined in another translation unit"); + return; + } + if (!prevailing->definition || !vtable->definition) + return; + for (n1 = 0, n2 = 0; true; n1++, n2++) + { + struct ipa_ref *ref1, *ref2; + bool end1, end2; + end1 = !prevailing->iterate_reference (n1, ref1); + end2 = !vtable->iterate_reference (n2, ref2); + if (end1 && end2) + return; + if (!end1 && !end2 + && DECL_ASSEMBLER_NAME (ref1->referred->decl) + != DECL_ASSEMBLER_NAME (ref2->referred->decl) + && !n2 + && !DECL_VIRTUAL_P (ref2->referred->decl) + && DECL_VIRTUAL_P (ref1->referred->decl)) + { + if (warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (vtable->decl))), 0, + "virtual table of type %qD contains RTTI information", + DECL_CONTEXT (vtable->decl))) + { + inform (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), + "but is prevailed by one without from other translation unit"); + inform (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), + "RTTI will not work on this type"); + } + n2++; + end2 = !vtable->iterate_reference (n2, ref2); + } + if (!end1 && !end2 + && DECL_ASSEMBLER_NAME (ref1->referred->decl) + != DECL_ASSEMBLER_NAME (ref2->referred->decl) + && !n1 + && !DECL_VIRTUAL_P (ref1->referred->decl) + && DECL_VIRTUAL_P (ref2->referred->decl)) + { + n1++; + end1 = !vtable->iterate_reference (n1, ref1); + } + if (end1 || end2) + { + if (end1) + { + varpool_node *tmp = prevailing; + prevailing = vtable; + vtable = tmp; + ref1 = ref2; + } + if (warning_at (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (vtable->decl))), 0, + "virtual table of type %qD violates " + "one definition rule", + DECL_CONTEXT (vtable->decl))) + { + inform (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), + "the conflicting type defined in another translation " + "unit"); + inform (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (ref1->referring->decl))), + "contains additional virtual method %qD", + ref1->referred->decl); + } + return; + } + if (DECL_ASSEMBLER_NAME (ref1->referred->decl) + != DECL_ASSEMBLER_NAME (ref2->referred->decl)) + { + if (warning_at (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (vtable->decl))), 0, + "virtual table of type %qD violates " + "one definition rule ", + DECL_CONTEXT (vtable->decl))) + { + inform (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), + "the conflicting type defined in another translation " + "unit"); + inform (DECL_SOURCE_LOCATION (ref1->referred->decl), + "virtual method %qD", ref1->referred->decl); + inform (DECL_SOURCE_LOCATION (ref2->referred->decl), + "ought to match virtual method %qD but does not", + ref2->referred->decl); + return; + } + } + } +} + /* Output ODR violation warning about T1 and T2 with REASON. Display location of ST1 and ST2 if REASON speaks about field or method of the type. diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h index 3801525ae7d..30adc6907d2 100644 --- a/gcc/ipa-utils.h +++ b/gcc/ipa-utils.h @@ -101,6 +101,7 @@ bool get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *, bool decl_maybe_in_construction_p (tree, tree, gimple, tree); tree vtable_pointer_value_to_binfo (const_tree); bool vtable_pointer_value_to_vtable (const_tree, tree *, unsigned HOST_WIDE_INT *); +void compare_virtual_tables (varpool_node *, varpool_node *); bool contains_polymorphic_type_p (const_tree); /* Return vector containing possible targets of polymorphic call E. diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index 3483711e0db..2e3a1563775 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,7 @@ +2014-08-14 Jan Hubicka + + * lto-symtab.c (lto_varpool_replace_node): Call compare_virtual_tables. + 2014-08-14 Richard Biener PR lto/62067 diff --git a/gcc/lto/lto-symtab.c b/gcc/lto/lto-symtab.c index 2332225afd4..aae865a0290 100644 --- a/gcc/lto/lto-symtab.c +++ b/gcc/lto/lto-symtab.c @@ -117,6 +117,10 @@ lto_varpool_replace_node (varpool_node *vnode, && vnode->decl != prevailing_node->decl) DECL_INITIAL (vnode->decl) = error_mark_node; + /* Check and report ODR violations on virtual tables. */ + if (DECL_VIRTUAL_P (vnode->decl) || DECL_VIRTUAL_P (prevailing_node->decl)) + compare_virtual_tables (prevailing_node, vnode); + if (vnode->tls_model != prevailing_node->tls_model) { error_at (DECL_SOURCE_LOCATION (vnode->decl),