Add ODR violation warnings about virtual table mismatches

Jan Hubicka hubicka@ucw.cz
Tue Aug 12 15:29:00 GMT 2014


Hi,
this patch adds warning on mismatching virtual tables. It is update/rewrite of
my earlier version https://gcc.gnu.org/ml/gcc-patches/2014-02/msg00741.html
The main difference is that we no longer stream all variable initializers, so
the new code uses ipa-reference instead of walk of the DECL_INITIAL.

An example of warning is here:

$ cat t.C
struct A {
  virtual void t();
  virtual void e();
};
struct A a;
$ cat t2.C
struct A {
  virtual void t();
  virtual void q();
};
struct A b;
$ ./xgcc -B ./ -O2 t.C t2.C  -flto
t.C:1:8: warning: virtual table of type �struct A� violates one definition rule  
 struct A {
        ^
t.C:1:8: note: the conflicting type defined in another translation unit
t.C:3:16: note: virtual method �e� in the first virtual table
   virtual void e();
                ^
t2.C:3:16: note: ought to match virtual method �q� in the second but does not
   virtual void q();
                ^

It also shows a glitch - the location of conflicting type is wrong.  This is
because tree merging does not consider location information so we no longer
thave the info.  I think instead we ought to print the compilation unit where
it came from, because often the differences are caused by different
preprocessor macros. At least judging from now fixed firefox problems I
reported in February.

https://gcc.gnu.org/ml/gcc-patches/2014-07/msg01876.html adds code that may
be used to report the mismatched translation units that may be more useful.

Bootstrapped/regtested x86_64-linux, will commit it tomorrow if there are no
complains.

Honza

Index: ipa-utils.h
===================================================================
--- ipa-utils.h	(revision 213860)
+++ ipa-utils.h	(working copy)
@@ -101,7 +101,8 @@ bool get_polymorphic_call_info_from_inva
 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.
    If FINALP is non-NULL, store true if the list is complette. 
Index: lto/lto-symtab.c
===================================================================
--- lto/lto-symtab.c	(revision 213860)
+++ lto/lto-symtab.c	(working copy)
@@ -117,6 +117,10 @@ lto_varpool_replace_node (varpool_node *
       && 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),
Index: ipa-devirt.c
===================================================================
--- ipa-devirt.c	(revision 213860)
+++ ipa-devirt.c	(working copy)
@@ -485,6 +485,120 @@ odr_subtypes_equivalent_p (tree t1, tree
   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.



More information about the Gcc-patches mailing list