===================================================================
@@ -679,5 +679,13 @@ lto_symtab_prevailing_decl (tree decl)
if (!ret)
return decl;
+ /* Check and report ODR violations on virtual tables. */
+ if (decl != ret->decl && DECL_VIRTUAL_P (decl))
+ {
+ compare_virtual_tables (ret->decl, decl);
+ /* We are done with checking and DECL will die after merigng. */
+ DECL_VIRTUAL_P (decl) = 0;
+ }
+
return ret->decl;
}
===================================================================
@@ -1675,6 +1673,101 @@ update_type_inheritance_graph (void)
}
+/* Compare two virtual tables, PREVAILING and VTABLE and output ODR
+ violation warings. */
+
+void
+compare_virtual_tables (tree prevailing, tree vtable)
+{
+ tree init1 = DECL_INITIAL (prevailing), init2 = DECL_INITIAL (vtable);
+ if (init1 == init2)
+ return;
+ if (init2 == error_mark_node)
+ return;
+ /* Be sure to keep virtual table contents even for external
+ vtables when they are available. */
+ if (init1 == error_mark_node || !init1)
+ {
+ DECL_INITIAL (prevailing) = DECL_INITIAL (vtable);
+ return;
+ }
+ if (!init2 && DECL_EXTERNAL (vtable))
+ return;
+ if (DECL_VIRTUAL_P (prevailing) && init1 && init2
+ && CONSTRUCTOR_NELTS (init1) == CONSTRUCTOR_NELTS (init2))
+ {
+ unsigned i;
+ tree field1, field2;
+ tree val1, val2;
+ bool matched = true;
+
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init1),
+ i, field1, val1)
+ {
+ gcc_assert (!field1);
+ field2 = CONSTRUCTOR_ELT (init2, i)->index;
+ val2 = CONSTRUCTOR_ELT (init2, i)->value;
+ gcc_assert (!field2);
+ if (val2 == val1)
+ continue;
+ STRIP_NOPS (val1);
+ STRIP_NOPS (val2);
+ /* Unwind
+ val <addr_expr type <pointer_type>
+ readonly constant
+ arg 0 <mem_ref type <pointer_type __vtbl_ptr_type>
+ readonly
+ arg 0 <addr_expr type <pointer_type>
+ arg 0 <var_decl _ZTCSd0_Si>> arg 1 <integer_cst 24>>> */
+
+ while ((TREE_CODE (val1) == MEM_REF
+ && TREE_CODE (val2) == MEM_REF
+ && (TREE_OPERAND (val1, 1)
+ == TREE_OPERAND (val2, 1)))
+ || (TREE_CODE (val1) == ADDR_EXPR
+ && TREE_CODE (val2) == ADDR_EXPR))
+ {
+ val1 = TREE_OPERAND (val1, 0);
+ val2 = TREE_OPERAND (val2, 0);
+ }
+ if (val1 == val2)
+ continue;
+ if (TREE_CODE (val2) == ADDR_EXPR)
+ {
+ tree tmp = val1;
+ val1 = val2;
+ val2 = tmp;
+ }
+ /* Allow combining RTTI and non-RTTI is OK. */
+ if (TREE_CODE (val1) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (val1, 0)) == VAR_DECL
+ && !DECL_VIRTUAL_P (TREE_OPERAND (val1, 0))
+ && TREE_CODE (val2) == NOP_EXPR
+ && integer_zerop (TREE_OPERAND (val2, 0)))
+ continue;
+ if (TREE_CODE (val1) == NOP_EXPR
+ && TREE_CODE (val2) == NOP_EXPR
+ && integer_zerop (TREE_OPERAND (val1, 0))
+ && integer_zerop (TREE_OPERAND (val2, 0)))
+ continue;
+ if (DECL_P (val1) && DECL_P (val2)
+ && DECL_ASSEMBLER_NAME (val1) == DECL_ASSEMBLER_NAME (val2))
+ continue;
+ matched = false;
+ break;
+ }
+ if (matched)
+ return;
+ }
+ odr_violation_reported = true;
+ if (warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (vtable))), 0,
+ "type %qD violates one definition rule ",
+ DECL_CONTEXT (vtable)))
+ inform (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (prevailing))),
+ "a type with the same name but different virtual table is "
+ "defined in another translation unit");
+}
+
/* Return true if N looks like likely target of a polymorphic call.
Rule out cxa_pure_virtual, noreturns, function declared cold and
other obvious cases. */
===================================================================
@@ -92,6 +92,7 @@ bool get_polymorphic_call_info_from_inva
tree, tree, HOST_WIDE_INT);
tree vtable_pointer_value_to_binfo (tree t);
bool vtable_pointer_value_to_vtable (tree, tree *, unsigned HOST_WIDE_INT *);
+void compare_virtual_tables (tree, tree);
/* Return vector containing possible targets of polymorphic call E.
If FINALP is non-NULL, store true if the list is complette.