This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

More informative ODR warnings


Hi,
this patch adds structural comparsion into ODR warnings, so we do not rely
on types_compatible_p to checks if the individual variants of same
name looks same.  This allows us to give more precise reason for the
mismatch and also be more strict than canonical type merging.

Function odr_types_equivalent_p is based on canonical type hash equivalency
from lto.c.  Originally I wanted to share the implementation, but details
seems sufficiently different to justify a fresh copy of the whole monster.

To avoid false warnings on types containg va_list pointer, I added
the disucssed hack to type_in_anonymous_namespace_p to return false
on types that do not have public stub but no context (since all anonymous
types produced by FE have as a context something)

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

Currently we warn only about polymorphic types.  With my experimental patch for
full ODR type merging we get the following warnings (minus the information
about conflicting units). Those seems to be real bugs in firefox.

/aux/hubicka/firefox/netwerk/sctp/datachannel/DataChannel.h:64:0: warning: field âmSpaâ (of type âstruct BufferedMsgâ) violates one definition rule   [-Wodr]
   struct sctp_sendv_spa *mSpa;
 ^
../../../../dist/include/mozilla/net/DataChannel.h:64:0: note: a field of same name but different type is defined in another translation unit
/aux/hubicka/firefox/netwerk/streamconv/converters/nsMultiMixedConv.cpp:466:0: warning: field âmBufferâ (of type âstruct AutoFreeâ) violates one definition rule   [-Wodr]
   char *mBuffer;
 ^
/aux/hubicka/firefox/dom/base/nsJSEnvironment.cpp:307:0: note: a field with different name is defined in another translation unit
   void *mPtr;
 ^
lto1: note: Conflicting compilation units: /aux/hubicka/firefox/dom/base/nsJSEnvironment.cpp and /aux/hubicka/build-firefox491-inst4/netwerk/streamconv/converters/Unified_cpp_netwerk_streamconv_converters0.cpp
../../dist/include/zipstruct.h:47:25: warning: field âMOZ_Z_crc32â (of type âstruct ZipCentral_â) violates one definition rule   [-Wodr]
../../dist/include/zipstruct.h:47:0: note: a field with different name is defined in another translation unit
lto1: note: Conflicting compilation units: /aux/hubicka/build-firefox491-inst4/dom/file/Unified_cpp_dom_file0.cpp and /aux/hubicka/firefox/xpcom/build/FileLocation.cpp
/aux/hubicka/firefox/modules/libjar/zipstruct.h:24:0: warning: field âMOZ_Z_crc32â (of type âstruct ZipLocal_â) violates one definition rule   [-Wodr]
   unsigned char crc32 [4];
 ^
../../dist/include/zipstruct.h:24:0: note: a field with different name is defined in another translation unit
lto1: note: Conflicting compilation units: /aux/hubicka/build-firefox491-inst4/dom/file/Unified_cpp_dom_file0.cpp and /aux/hubicka/firefox/modules/libjar/nsZipArchive.cpp
../../dist/include/mp4_demuxer/audio_decoder_config.h:112:0: warning: field âsample_format_â (of type âstruct AudioDecoderConfigâ) violates one definition rule   [-Wodr]
../../../dist/include/mp4_demuxer/audio_decoder_config.h:112:0: note: a field of same name but different type is defined in another translation unit
   SampleFormat sample_format_;
 ^
../../dist/include/mp4_demuxer/audio_decoder_config.h:41:0: note: type âSampleFormatâ should match type âAVSampleFormatâ
../../../dist/include/mp4_demuxer/audio_decoder_config.h:41:0: note: the incompatible type is defined here
 enum SampleFormat {
 ^
/aux/hubicka/firefox/modules/libpref/src/nsPrefBranch.cpp:51:16: warning: field âparentâ (of type âstruct EnumerateDataâ) violates one definition rule   [-Wodr]
   const char  *parent;
                ^
/aux/hubicka/firefox/layout/base/nsPresArena.cpp:123:0: note: a field with different name is defined in another translation unit
   nsArenaMemoryStats* stats;
 ^
lto1: note: Conflicting compilation units: /aux/hubicka/firefox/layout/base/nsPresArena.cpp and /aux/hubicka/build-firefox491-inst4/modules/libpref/src/Unified_cpp_modules_libpref_src0.cpp
./glslang_lex.cpp:815:0: warning: field âyyextra_râ (of type âstruct yyguts_tâ) violates one definition rule   [-Wodr]
./Tokenizer.cpp:575:0: note: a field of same name but different type is defined in another translation unit
lto1: note: Conflicting compilation units: /aux/hubicka/build-firefox491-inst4/gfx/angle/Unified_cpp_gfx_angle3.cpp and /aux/hubicka/firefox/gfx/angle/src/compiler/glslang_lex.cpp
/aux/hubicka/firefox/rdf/base/src/nsInMemoryDataSource.cpp:148:0: warning: field âmHdrâ (of type âstruct Entryâ) violates one definition rule   [-Wodr]
     PLDHashEntryHdr mHdr;
 ^
/aux/hubicka/firefox/gfx/skia/trunk/src/core/SkFlattenable.cpp:67:0: note: a field with different name is defined in another translation unit
     const char*             fName;
 ^
lto1: note: Conflicting compilation units: /aux/hubicka/firefox/gfx/skia/trunk/src/core/SkFlattenable.cpp and /aux/hubicka/build-firefox491-inst4/rdf/base/src/Unified_cpp_rdf_base_src0.cpp
/aux/hubicka/firefox/gfx/skia/trunk/src/core/SkFontStream.cpp:13:0: warning: field âfVersionâ (of type âstruct SkSFNTHeaderâ) violates one definition rule   [-Wodr]
     uint32_t    fVersion;
 ^
/aux/hubicka/firefox/gfx/skia/trunk/src/sfnt/SkSFNTHeader.h:21:0: note: a field with different name is defined in another translation unit
     SK_SFNT_ULONG fontType;
 ^
lto1: note: Conflicting compilation units: /aux/hubicka/firefox/gfx/skia/trunk/src/sfnt/SkOTUtils.cpp and /aux/hubicka/firefox/gfx/skia/trunk/src/core/SkFontStream.cpp
/aux/hubicka/firefox/xpcom/glue/nsTextFormatter.cpp:51:68: warning: field âstuffâ (of type âstruct SprintfStateStrâ) violates one definition rule   [-Wodr]
     int (*stuff)(SprintfState *ss, const char16_t *sp, uint32_t len);
                                                                    ^
/aux/hubicka/firefox/js/src/jsprf.cpp:49:0: note: a field of same name but different type is defined in another translation unit
     int (*stuff)(SprintfState *ss, const char *sp, uint32_t len);
 ^
lto1: note: Conflicting compilation units: /aux/hubicka/build-firefox491-inst4/js/src/Unified_cpp_js_src7.cpp and /aux/hubicka/build-firefox491-inst4/xpcom/build/Unified_cpp_xpcom_build1.cpp

Honza

	* tree.c (type_in_anonymous_namespace_p): Ignore TREE_PUBLIC
	on builtin types.
	* ipa-devirt.c: Include stor-layout.h and intl.h
	(odr_subtypes_equivalent_p): New function.
	(warn_odr): New function.
	(warn_type_mismatch): New function.
	(odr_types_equivalent_p): New function.
	(add_type_duplicate): Use it.
	* common.opt (Wodr): New flag.
	* doc/invoke.texi (Wodr): Document new warning.
Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi     (revision 212222)
+++ doc/invoke.texi     (working copy)
@@ -259,7 +259,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wlogical-op -Wlogical-not-parentheses -Wlong-long @gol
 -Wmain -Wmaybe-uninitialized -Wmissing-braces  -Wmissing-field-initializers @gol
 -Wmissing-include-dirs @gol
--Wno-multichar  -Wnonnull  -Wno-overflow -Wopenmp-simd @gol
+-Wno-multichar  -Wnonnull  -Wodr  -Wno-overflow  -Wopenmp-simd @gol
 -Woverlength-strings  -Wpacked  -Wpacked-bitfield-compat  -Wpadded @gol
 -Wparentheses  -Wpedantic-ms-format -Wno-pedantic-ms-format @gol
 -Wpointer-arith  -Wno-pointer-to-int-cast @gol
@@ -4897,6 +4897,12 @@ attribute.
 @opindex Woverflow
 Do not warn about compile-time overflow in constant expressions.
 
+@opindex Wodr
+@opindex Wno-odr
+@opindex Wodr
+Warn about One Definition Rule violations during link time optimization.
+Require @option{-flto-odr-type-merging} to be enabled. Enabled by default
+
 @item -Wopenmp-simd
 @opindex Wopenm-simd
 Warn if the vectorizer cost model overrides the OpenMP or the Cilk Plus
Index: ipa-devirt.c
===================================================================
--- ipa-devirt.c	(revision 212222)
+++ ipa-devirt.c	(working copy)
@@ -130,6 +130,8 @@ along with GCC; see the file COPYING3.
 #include "tree-dfa.h"
 #include "demangle.h"
 #include "dbgcnt.h"
+#include "stor-layout.h"
+#include "intl.h"
 
 static bool odr_violation_reported = false;
 
@@ -140,6 +142,7 @@ const ipa_polymorphic_call_context ipa_d
 
 /* Pointer set of all call targets appearing in the cache.  */
 static pointer_set_t *cached_polymorphic_call_targets;
+static bool odr_types_equivalent_p (tree t1, tree t2, bool, bool *, pointer_set_t *);
 
 /* The node of type inheritance graph.  For each type unique in
    One Defintion Rule (ODR) sense, we produce one node linking all 
@@ -281,7 +284,13 @@ hash_type_name (tree t)
   if (type_in_anonymous_namespace_p (t))
     return htab_hash_pointer (t);
 
-  /* For polymorphic types, we can simply hash the virtual table.  */
+  /* ODR types have name specified.  */
+  if (TYPE_NAME (t)
+      && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t)))
+    return IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (TYPE_NAME (t)));
+
+  /* For polymorphic types that was compiled with -fno-lto-odr-type-merging
+     we can simply hash the virtual table.  */
   if (TREE_CODE (t) == RECORD_TYPE
       && TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t)))
     {
@@ -299,8 +308,14 @@ hash_type_name (tree t)
       return hash;
     }
 
-  /* Rest is not implemented yet.  */
-  gcc_unreachable ();
+  /* Builtin types may appear as main variants of ODR types and are unique.
+     Sanity check we do not get anything that looks non-builtin.  */
+  gcc_checking_assert (TREE_CODE (t) == INTEGER_TYPE
+		       || TREE_CODE (t) == VOID_TYPE
+		       || TREE_CODE (t) == COMPLEX_TYPE
+		       || TREE_CODE (t) == REAL_TYPE
+		       || TREE_CODE (t) == POINTER_TYPE);
+  return htab_hash_pointer (t);
 }
 
 /* Return the computed hashcode for ODR_TYPE.  */
@@ -312,17 +327,13 @@ odr_hasher::hash (const value_type *odr_
 }
 
 /* For languages with One Definition Rule, work out if
-   types are the same based on their name.
- 
+   types are same even if the tree representation differs. 
    This is non-trivial for LTO where minnor differences in
    the type representation may have prevented type merging
-   to merge two copies of otherwise equivalent type.
-
-   Until we start streaming mangled type names, this function works
-   only for polymorphic types.  */
+   to merge two copies of otherwise equivalent type.  */
 
 bool
-types_same_for_odr (const_tree type1, const_tree type2)
+types_same_for_odr (tree type1, tree type2)
 {
   gcc_checking_assert (TYPE_P (type1) && TYPE_P (type2));
 
@@ -341,30 +352,51 @@ types_same_for_odr (const_tree type1, co
       || type_in_anonymous_namespace_p (type2))
     return false;
 
-  /* At the moment we have no way to establish ODR equivlaence at LTO
-     other than comparing virtual table pointrs of polymorphic types.
-     Eventually we should start saving mangled names in TYPE_NAME.
-     Then this condition will become non-trivial.  */
-
-  if (TREE_CODE (type1) == RECORD_TYPE
-      && TYPE_BINFO (type1) && TYPE_BINFO (type2)
-      && BINFO_VTABLE (TYPE_BINFO (type1))
-      && BINFO_VTABLE (TYPE_BINFO (type2)))
-    {
-      tree v1 = BINFO_VTABLE (TYPE_BINFO (type1));
-      tree v2 = BINFO_VTABLE (TYPE_BINFO (type2));
-      gcc_assert (TREE_CODE (v1) == POINTER_PLUS_EXPR
-		  && TREE_CODE (v2) == POINTER_PLUS_EXPR);
-      return (operand_equal_p (TREE_OPERAND (v1, 1),
-			       TREE_OPERAND (v2, 1), 0)
-	      && DECL_ASSEMBLER_NAME
-		     (TREE_OPERAND (TREE_OPERAND (v1, 0), 0))
-		 == DECL_ASSEMBLER_NAME
-		     (TREE_OPERAND (TREE_OPERAND (v2, 0), 0)));
+  /* ODR name of the type is set in DECL_ASSEMBLER_NAME of its TYPE_NAME.
+
+     Ideally we should never meed types without ODR names here.  It can however
+     happen in two cases:
+
+       1) for builtin types that are not streamed but rebuilt in lto/lto-lang.c
+          Here testing for equivalence is safe, since their MAIN_VARIANTs are
+          unique.
+       2) for units streamed with -fno-lto-odr-type-merging.  Here we can't
+	  establish precise ODR equivalency, but for correctness we care only
+	  about equivalency on complete polymorphic types.  For these we can
+	  compare assembler names of their virtual tables.  */
+  if ((!TYPE_NAME (type1) || !DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (type1)))
+      || (!TYPE_NAME (type2) || !DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (type2))))
+    {
+      /* If names are defined, we do not want to do any structural compare,
+	 so ODR violations are found.  But here we do.  */
+      if (TREE_CODE (type1) != TREE_CODE (type2))
+	return false;
+      if (TREE_CODE (type1) == RECORD_TYPE
+	  && TYPE_BINFO (type1) && TYPE_BINFO (type2)
+	  && BINFO_VTABLE (TYPE_BINFO (type1))
+	  && BINFO_VTABLE (TYPE_BINFO (type2)))
+	{
+	  tree v1 = BINFO_VTABLE (TYPE_BINFO (type1));
+	  tree v2 = BINFO_VTABLE (TYPE_BINFO (type2));
+	  gcc_assert (TREE_CODE (v1) == POINTER_PLUS_EXPR
+		      && TREE_CODE (v2) == POINTER_PLUS_EXPR);
+	  return (operand_equal_p (TREE_OPERAND (v1, 1),
+				   TREE_OPERAND (v2, 1), 0)
+		  && DECL_ASSEMBLER_NAME
+			 (TREE_OPERAND (TREE_OPERAND (v1, 0), 0))
+		     == DECL_ASSEMBLER_NAME
+			 (TREE_OPERAND (TREE_OPERAND (v2, 0), 0)));
+	}
+      return false;
     }
-  gcc_unreachable ();
-}
 
+  gcc_assert (TYPE_NAME (type1)
+              && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (type1)));
+  gcc_assert (TYPE_NAME (type2)
+              && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (type2)));
+  return (DECL_ASSEMBLER_NAME (TYPE_NAME (type1))
+	  == DECL_ASSEMBLER_NAME (TYPE_NAME (type2)));
+}
 
 /* Compare types T1 and T2 and return true if they are
    equivalent.  */
@@ -417,6 +449,484 @@ set_type_binfo (tree type, tree binfo)
       gcc_assert (!TYPE_BINFO (type));
 }
 
+/* Compare T2 and T2 based on name or structure.  */
+
+static bool
+odr_subtypes_equivalent_p (tree t1, tree t2, pointer_set_t *visited)
+{
+  if (t1 == t2)
+    return true;
+  /* This can happen in incomplete types that should be handled earlier.  */
+  gcc_assert (t1 && t2);
+  if (!odr_type_p (t1) || !odr_type_p (t2))
+    {
+      if (pointer_set_insert (visited, t1))
+	return true;
+      return odr_types_equivalent_p (t1, t2, false, NULL, visited);
+    }
+  return types_same_for_odr (t1, t2);
+}
+
+/* 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.
+   If WARN is false, do nothing. Set WARNED if warning was indeed
+   output.  */
+
+void
+warn_odr (tree t1, tree t2, tree st1, tree st2,
+	  bool warn, bool *warned, const char *reason)
+{
+  tree name1 = TYPE_NAME (t1);
+  tree name = TYPE_NAME (t2);
+  tree decl2 = TYPE_NAME (t2);
+
+  if (!warn)
+    return;
+  if (!st1)
+    {
+      if (!warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (t1)), OPT_Wodr,
+		       "type %qT violates one definition rule  ",
+		       t1))
+        return;
+    }
+  else if (TREE_CODE (st1) == FIELD_DECL)
+    {
+      if (!warning_at (DECL_SOURCE_LOCATION (st1), OPT_Wodr,
+		       "field %qD (of type %qT) violates one definition rule  ",
+		       st1, t1))
+	return;
+      decl2 = st2;
+    }
+  else if (TREE_CODE (st1) == FUNCTION_DECL)
+    {
+      if (!warning_at (DECL_SOURCE_LOCATION (t1), OPT_Wodr,
+		       "method %qD (of type %qT) violates one definition rule  ",
+		       st1, t1))
+	return;
+      decl2 = st2;
+    }
+  else
+    return;
+
+  inform (DECL_SOURCE_LOCATION (decl2), reason);
+
+  /* See if we have info about the translation unit.  It may not be around
+     if types was already merged.   */
+  while (TREE_CODE (name) != TRANSLATION_UNIT_DECL)
+    name = TYPE_P (name) ? TYPE_CONTEXT (name) : DECL_CONTEXT (name);
+  while (TREE_CODE (name1) != TRANSLATION_UNIT_DECL)
+    name1 = TYPE_P (name1) ? TYPE_CONTEXT (name1) : DECL_CONTEXT (name1);
+  name = DECL_NAME (name);
+  name1 = DECL_NAME (name1);
+  if (name != name1 && name && name1)
+    inform (UNKNOWN_LOCATION, "Conflicting compilation units: %s and %s",
+	    IDENTIFIER_POINTER (name),
+	    IDENTIFIER_POINTER (name1));
+  *warned = true;
+}
+
+/* We already warned about ODR mismatch.  T1 and T2 ought to be equivalent
+   because they are used on same place in ODR matching types.
+   They are not; inform the user.  */
+
+void
+warn_types_mismatch (tree t1, tree t2)
+{
+  if (!odr_type_p (t1) || !odr_type_p (t2))
+    return;
+  /* In Firefox it is a common bug to have same types but in
+     different namespaces.  Be a bit more informative on
+     this.  */
+  if (TYPE_CONTEXT (t1) && TYPE_CONTEXT (t2)
+      && (((TREE_CODE (TYPE_CONTEXT (t1)) == NAMESPACE_DECL)
+	    != (TREE_CODE (TYPE_CONTEXT (t2)) == NAMESPACE_DECL))
+	   || (TREE_CODE (TYPE_CONTEXT (t1)) == NAMESPACE_DECL
+	       && (DECL_NAME (TYPE_CONTEXT (t1)) !=
+		   DECL_NAME (TYPE_CONTEXT (t2))))))
+    inform (DECL_SOURCE_LOCATION (TYPE_NAME (t1)),
+	    "type %qT should match type %qT but is defined "
+	    "in different namespace  ",
+	    t1, t2);
+  else
+    inform (DECL_SOURCE_LOCATION (TYPE_NAME (t1)),
+	    "type %qT should match type %qT",
+	    t1, t2);
+  inform (DECL_SOURCE_LOCATION (TYPE_NAME (t2)),
+	  "the incompatible type is defined here");
+}
+
+/* Compare T1 and T2, report ODR violations if WARN is true and set
+   WARNED to true if anything is reported.  Return true if types match.
+   If true is returned, the types are also compatible in the sense of
+   gimple_canonical_types_compatible_p.  */
+
+static bool
+odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned, pointer_set_t *visited)
+{
+  /* Check first for the obvious case of pointer identity.  */
+  if (t1 == t2)
+    return true;
+  gcc_assert (!type_in_anonymous_namespace_p (t1));
+  gcc_assert (!type_in_anonymous_namespace_p (t2));
+
+  /* Can't be the same type if the types don't have the same code.  */
+  if (TREE_CODE (t1) != TREE_CODE (t2))
+    {
+      warn_odr (t1, t2, NULL, NULL, warn, warned,
+	        G_("a different type is defined in another translation unit"));
+      return false;
+    }
+
+  if (TYPE_QUALS (t1) != TYPE_QUALS (t2))
+    {
+      warn_odr (t1, t2, NULL, NULL, warn, warned,
+	        G_("a type with different qualifiers is defined in another "
+		   "translation unit"));
+      return false;
+    }
+
+  if (comp_type_attributes (t1, t2) != 1)
+    {
+      warn_odr (t1, t2, NULL, NULL, warn, warned,
+	        G_("a type with attributes "
+		   "is defined in another translation unit"));
+      return false;
+    }
+
+  if (TREE_CODE (t1) == ENUMERAL_TYPE)
+    {
+      tree v1, v2;
+      for (v1 = TYPE_VALUES (t1), v2 = TYPE_VALUES (t2);
+	   v1 && v2 ; v1 = TREE_CHAIN (v1), v2 = TREE_CHAIN (v2))
+	{
+	  if (TREE_PURPOSE (v1) != TREE_PURPOSE (v2))
+	    {
+	      warn_odr (t1, t2, NULL, NULL, warn, warned,
+			G_("an enum with different value name"
+			   " is defined in another translation unit"));
+	      return false;
+	    }
+	  if (TREE_VALUE (v1) != TREE_VALUE (v2))
+	    {
+	      warn_odr (t1, t2, NULL, NULL, warn, warned,
+			G_("an enum with different values is defined"
+			   " in another translation unit"));
+	      return false;
+	    }
+	}
+      if (v1 || v2)
+	{
+	  warn_odr (t1, t2, NULL, NULL, warn, warned,
+		    G_("an enum with mismatching number of values "
+		       "is defined in another translation unit"));
+	  return false;
+	}
+    }
+
+  /* Non-aggregate types can be handled cheaply.  */
+  if (INTEGRAL_TYPE_P (t1)
+      || SCALAR_FLOAT_TYPE_P (t1)
+      || FIXED_POINT_TYPE_P (t1)
+      || TREE_CODE (t1) == VECTOR_TYPE
+      || TREE_CODE (t1) == COMPLEX_TYPE
+      || TREE_CODE (t1) == OFFSET_TYPE
+      || POINTER_TYPE_P (t1))
+    {
+      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2))
+	{
+	  warn_odr (t1, t2, NULL, NULL, warn, warned,
+		    G_("a type with different precision is defined "
+		       "in another translation unit"));
+	  return false;
+	}
+      if (TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
+	{
+	  warn_odr (t1, t2, NULL, NULL, warn, warned,
+		    G_("a type with different signedness is defined "
+		       "in another translation unit"));
+	  return false;
+	}
+
+      if (TREE_CODE (t1) == INTEGER_TYPE
+	  && TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2))
+	{
+	  /* Can this trigger? char WRT uint_8?  */
+	  warn_odr (t1, t2, NULL, NULL, warn, warned,
+		    G_("a different type is defined in another "
+		       "translation unit"));
+	  return false;
+	}
+
+      if (POINTER_TYPE_P (t1))
+	{
+	  if (TYPE_ADDR_SPACE (TREE_TYPE (t1))
+	      != TYPE_ADDR_SPACE (TREE_TYPE (t2)))
+	    {
+	      warn_odr (t1, t2, NULL, NULL, warn, warned,
+			G_("it is defined as a pointer in different address "
+			   "space in another translation unit"));
+	      return false;
+	    }
+
+	  if (!odr_subtypes_equivalent_p (TREE_TYPE (t1), TREE_TYPE (t2), visited))
+	    {
+	      warn_odr (t1, t2, NULL, NULL, warn, warned,
+			G_("it is defined as a pointer to different type "
+			   "in another translation unit"));
+	      if (warn && warned)
+	        warn_types_mismatch (TREE_TYPE (t1), TREE_TYPE (t2));
+	      return false;
+	    }
+	}
+
+      /* Tail-recurse to components.  */
+      if ((TREE_CODE (t1) == VECTOR_TYPE || TREE_CODE (t1) == COMPLEX_TYPE)
+	  && !odr_subtypes_equivalent_p (TREE_TYPE (t1), TREE_TYPE (t2), visited))
+	{
+	  /* Probably specific enough.  */
+	  warn_odr (t1, t2, NULL, NULL, warn, warned,
+		    G_("a different type is defined "
+		       "in another translation unit"));
+	  if (warn && warned)
+	    warn_types_mismatch (TREE_TYPE (t1), TREE_TYPE (t2));
+	  return false;
+	}
+
+      gcc_assert (operand_equal_p (TYPE_SIZE (t1), TYPE_SIZE (t2), 0));
+      gcc_assert (operand_equal_p (TYPE_SIZE_UNIT (t1),
+				   TYPE_SIZE_UNIT (t2), 0));
+      gcc_assert (TYPE_MODE (t1) == TYPE_MODE (t2));
+
+      return true;
+    }
+
+  /* Do type-specific comparisons.  */
+  switch (TREE_CODE (t1))
+    {
+    case ARRAY_TYPE:
+      {
+	/* Array types are the same if the element types are the same and
+	   the number of elements are the same.  */
+	if (!odr_subtypes_equivalent_p (TREE_TYPE (t1), TREE_TYPE (t2), visited))
+	  {
+	    warn_odr (t1, t2, NULL, NULL, warn, warned,
+		      G_("a different type is defined in another "
+			 "translation unit"));
+	    if (warn && warned)
+	      warn_types_mismatch (TREE_TYPE (t1), TREE_TYPE (t2));
+	  }
+	gcc_assert (TYPE_STRING_FLAG (t1) == TYPE_STRING_FLAG (t2));
+	gcc_assert (TYPE_NONALIASED_COMPONENT (t1)
+		    == TYPE_NONALIASED_COMPONENT (t2));
+
+	tree i1 = TYPE_DOMAIN (t1);
+	tree i2 = TYPE_DOMAIN (t2);
+
+	/* For an incomplete external array, the type domain can be
+	   NULL_TREE.  Check this condition also.  */
+	if (i1 == NULL_TREE || i2 == NULL_TREE)
+	  return true;
+
+	tree min1 = TYPE_MIN_VALUE (i1);
+	tree min2 = TYPE_MIN_VALUE (i2);
+	tree max1 = TYPE_MAX_VALUE (i1);
+	tree max2 = TYPE_MAX_VALUE (i2);
+
+	/* In C++, minimums should be always 0.  */
+	gcc_assert (min1 == min2);
+	if (!operand_equal_p (max1, max2, 0))
+	  {
+	    warn_odr (t1, t2, NULL, NULL, warn, warned,
+		      G_("an array of different size is defined "
+			 "in another translation unit"));
+	    return false;
+	  }
+	gcc_assert (operand_equal_p (TYPE_SIZE (t1), TYPE_SIZE (t2), 0));
+	gcc_assert (operand_equal_p (TYPE_SIZE_UNIT (t1),
+				     TYPE_SIZE_UNIT (t2), 0));
+      }
+      return true;
+
+    case METHOD_TYPE:
+    case FUNCTION_TYPE:
+      /* Function types are the same if the return type and arguments types
+	 are the same.  */
+      if (!odr_subtypes_equivalent_p (TREE_TYPE (t1), TREE_TYPE (t2), visited))
+	{
+	  warn_odr (t1, t2, NULL, NULL, warn, warned,
+		    G_("has different return value "
+		       "in another translation unit"));
+	  if (warn && warned)
+	    warn_types_mismatch (TREE_TYPE (t1), TREE_TYPE (t2));
+	  return false;
+	}
+
+      if (TYPE_ARG_TYPES (t1) == TYPE_ARG_TYPES (t2))
+	return true;
+      else
+	{
+	  tree parms1, parms2;
+
+	  for (parms1 = TYPE_ARG_TYPES (t1), parms2 = TYPE_ARG_TYPES (t2);
+	       parms1 && parms2;
+	       parms1 = TREE_CHAIN (parms1), parms2 = TREE_CHAIN (parms2))
+	    {
+	      if (!odr_subtypes_equivalent_p
+		     (TREE_VALUE (parms1), TREE_VALUE (parms2), visited))
+		{
+		  warn_odr (t1, t2, NULL, NULL, warn, warned,
+			    G_("has different parameters in another "
+			       "translation unit"));
+		  if (warn && warned)
+		    warn_types_mismatch (TREE_VALUE (parms1),
+					 TREE_VALUE (parms2));
+		  return false;
+		}
+	    }
+
+	  if (parms1 || parms2)
+	    {
+	      warn_odr (t1, t2, NULL, NULL, warn, warned,
+			G_("has different parameters "
+			   "in another translation unit"));
+	      return false;
+	    }
+
+	  return true;
+	}
+
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      {
+	tree f1, f2;
+
+	/* For aggregate types, all the fields must be the same.  */
+	if (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2))
+	  {
+	    for (f1 = TYPE_FIELDS (t1), f2 = TYPE_FIELDS (t2);
+		 f1 || f2;
+		 f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2))
+	      {
+		/* Skip non-fields.  */
+		while (f1 && TREE_CODE (f1) != FIELD_DECL)
+		  f1 = TREE_CHAIN (f1);
+		while (f2 && TREE_CODE (f2) != FIELD_DECL)
+		  f2 = TREE_CHAIN (f2);
+		if (!f1 || !f2)
+		  break;
+		if (DECL_ARTIFICIAL (f1) != DECL_ARTIFICIAL (f2))
+		  break;
+		if (DECL_NAME (f1) != DECL_NAME (f2)
+		    && !DECL_ARTIFICIAL (f1))
+		  {
+		    warn_odr (t1, t2, f1, f2, warn, warned,
+			      G_("a field with different name is defined "
+				 "in another translation unit"));
+		    return false;
+		  }
+		if (!odr_subtypes_equivalent_p (TREE_TYPE (f1), TREE_TYPE (f2), visited))
+		  {
+		    /* Do not warn about artificial fields and just go into generic
+		       field mismatch warning.  */
+		    if (DECL_ARTIFICIAL (f1))
+		      break;
+
+		    warn_odr (t1, t2, f1, f2, warn, warned,
+			      G_("a field of same name but different type "
+				 "is defined in another translation unit"));
+		    if (warn && warned)
+		      warn_types_mismatch (TREE_TYPE (f1), TREE_TYPE (f2));
+		    return false;
+		  }
+		if (!gimple_compare_field_offset (f1, f2))
+		  {
+		    /* Do not warn about artificial fields and just go into generic
+		       field mismatch warning.  */
+		    if (DECL_ARTIFICIAL (f1))
+		      break;
+		    warn_odr (t1, t2, t1, t2, warn, warned,
+			      G_("fields has different layout "
+				 "in another translation unit"));
+		    return false;
+		  }
+		gcc_assert (DECL_NONADDRESSABLE_P (f1)
+			    == DECL_NONADDRESSABLE_P (f2));
+	      }
+
+	    /* If one aggregate has more fields than the other, they
+	       are not the same.  */
+	    if (f1 || f2)
+	      {
+		warn_odr (t1, t2, NULL, NULL, warn, warned,
+			  G_("a type with different number of fields "
+			     "is defined in another translation unit"));
+		return false;
+	      }
+
+	    /* FIXME: We do not stream main variants, so we do not really get
+	       any warnings from here.  */
+	    if ((TYPE_MAIN_VARIANT (t1) == t1 || TYPE_MAIN_VARIANT (t2) == t2)
+		&& (TYPE_METHODS (TYPE_MAIN_VARIANT (t1))
+		    != TYPE_METHODS (TYPE_MAIN_VARIANT (t2))))
+	      {
+		for (f1 = TYPE_METHODS (TYPE_MAIN_VARIANT (t1)),
+		     f2 = TYPE_METHODS (TYPE_MAIN_VARIANT (t2));
+		     f1 && f2 ; f1 = DECL_CHAIN (f1), f2 = DECL_CHAIN (f2))
+		  {
+		    if (DECL_ASSEMBLER_NAME (f1) != DECL_ASSEMBLER_NAME (f2))
+		      {
+			warn_odr (t1, t2, f1, f2, warn, warned,
+				  G_("a different method of same type "
+				     "is defined in another translation unit"));
+			return false;
+		      }
+		    if (DECL_VIRTUAL_P (f1) != DECL_VIRTUAL_P (f2))
+		      {
+			warn_odr (t1, t2, f1, f2, warn, warned,
+				  G_("s definition that differs by virtual "
+				     "keyword in another translation unit"));
+			return false;
+		      }
+		    if (DECL_VINDEX (f1) != DECL_VINDEX (f2))
+		      {
+			warn_odr (t1, t2, f1, f2, warn, warned,
+				  G_("virtual table layout differs in another "
+				     "translation unit"));
+			return false;
+		      }
+		    if (odr_subtypes_equivalent_p (TREE_TYPE (f1), TREE_TYPE (f2), visited))
+		      {
+			warn_odr (t1, t2, f1, f2, warn, warned,
+				  G_("method with incompatible type is defined "
+				     "in another translation unit"));
+			return false;
+		      }
+		  }
+		if (f1 || f2)
+		  {
+		    warn_odr (t1, t2, NULL, NULL, warn, warned,
+			      G_("a type with different number of methods "
+				 "is defined in another translation unit"));
+		    return false;
+		  }
+	      }
+
+	    /* We matched enough of structure so sizes should match, too.  */
+	    gcc_assert (operand_equal_p (TYPE_SIZE (t1), TYPE_SIZE (t2), 0));
+	    gcc_assert (operand_equal_p (TYPE_SIZE_UNIT (t1),
+					 TYPE_SIZE_UNIT (t2), 0));
+	  }
+
+	return true;
+      }
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* TYPE is equivalent to VAL by ODR, but its tree representation differs
    from VAL->type.  This may happen in LTO where tree merging did not merge
    all variants of the same type.  It may or may not mean the ODR violation.
@@ -445,31 +955,23 @@ add_type_duplicate (odr_type val, tree t
     {
       bool merge = true;
       bool base_mismatch = false;
-      bool warned = 0;
       unsigned int i,j;
+      bool warned = 0;
+      pointer_set_t *visited = pointer_set_create ();
 
       gcc_assert (in_lto_p);
       vec_safe_push (val->types, type);
 
       /* First we compare memory layout.  */
-      if (!types_compatible_p (val->type, type))
+      if (!odr_types_equivalent_p (val->type, type, !flag_ltrans && !val->odr_violated,
+				   &warned, visited))
 	{
 	  merge = false;
 	  odr_violation_reported = true;
-	  if (BINFO_VTABLE (TYPE_BINFO (val->type))
-	      && warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (type)), 0,
-			     "type %qD violates one definition rule  ",
-			     type))
-	    {
-	      inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)),
-		      "a type with the same name but different layout is "
-		      "defined in another translation unit");
-	      warned = true;
-	    }
 	  val->odr_violated = true;
 	  if (cgraph_dump_file)
 	    {
-	      fprintf (cgraph_dump_file, "ODR violation or merging or ODR type bug?\n");
+	      fprintf (cgraph_dump_file, "ODR violation\n");
 	    
 	      print_node (cgraph_dump_file, "", val->type, 0);
 	      putc ('\n',cgraph_dump_file);
@@ -477,6 +979,7 @@ add_type_duplicate (odr_type val, tree t
 	      putc ('\n',cgraph_dump_file);
 	    }
 	}
+      pointer_set_destroy (visited);
 
       /* Next sanity check that bases are the same.  If not, we will end
 	 up producing wrong answers.  */
@@ -493,7 +996,8 @@ add_type_duplicate (odr_type val, tree t
 				      (BINFO_BASE_BINFO (TYPE_BINFO (type),
 							 i)),
 				    true);
-		if (val->bases.length () <= j || val->bases[j] != base)
+	        odr_type base2 = val->bases[j];
+		if (val->bases.length () <= j || base2 != base)
 		  base_mismatch = true;
 		j++;
 	      }
@@ -502,13 +1006,10 @@ add_type_duplicate (odr_type val, tree t
 	      merge = false;
 	      odr_violation_reported = true;
 
-	      if (!warned
-		  && warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (type)), 0,
-			         "type %qD violates one definition rule  ",
-			         type))
-		inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)),
-			"a type with the same name but different bases is "
-			"defined in another translation unit");
+	      if (!warned && !val->odr_violated)
+		warn_odr (type, val->type, NULL, NULL, !warned, &warned,
+			  "a type with the same name but different bases is "
+			  "defined in another translation unit");
 	      val->odr_violated = true;
 	      if (cgraph_dump_file)
 		{
@@ -533,8 +1034,14 @@ add_type_duplicate (odr_type val, tree t
 	 to external declarations of methods that may be defined in the
 	 merged LTO unit.  For this reason we absolutely need to remove
 	 them and replace by internal variants. Not doing so will lead
-         to incomplete answers from possible_polymorphic_call_targets.  */
+         to incomplete answers from possible_polymorphic_call_targets.
+
+	 FIXME: disable for now; because ODR types are now build during
+	 streaming in, the variants do not need to be linked to the type,
+	 yet.  We need to do the merging in cleanup pass to be implemented
+	 soon.  */
       if (!flag_ltrans && merge
+	  && 0
 	  && TREE_CODE (val->type) == RECORD_TYPE
 	  && TREE_CODE (type) == RECORD_TYPE
 	  && TYPE_BINFO (val->type) && TYPE_BINFO (type)
@@ -569,7 +1076,6 @@ add_type_duplicate (odr_type val, tree t
 		      == master_binfo)
 		    set_type_binfo ((*val->types)[i], TYPE_BINFO (type));
 		}
-	      BINFO_TYPE (TYPE_BINFO (type)) = val->type;
 	    }
 	  else
 	    set_type_binfo (type, master_binfo);
@@ -611,7 +1117,6 @@ get_odr_type (tree type, bool insert)
     }
   else
     {
-
       val = ggc_cleared_alloc<odr_type_d> ();
       val->type = type;
       val->bases = vNULL;
@@ -620,15 +1125,13 @@ get_odr_type (tree type, bool insert)
       build_bases = COMPLETE_TYPE_P (val->type);
       insert_to_odr_array = true;
     }
-
-  if (build_bases && TREE_CODE (type) == RECORD_TYPE && TYPE_BINFO (type)
-      && type == TYPE_MAIN_VARIANT (type))
+  if (build_bases && TREE_CODE (type) == RECORD_TYPE && TYPE_BINFO (type))
     {
       tree binfo = TYPE_BINFO (type);
       unsigned int i;
 
       gcc_assert (BINFO_TYPE (TYPE_BINFO (val->type)) = type);
-  
+
       val->all_derivations_known = type_all_derivations_known_p (type);
       *slot = val;
       for (i = 0; i < BINFO_N_BASE_BINFOS (binfo); i++)
@@ -651,7 +1154,7 @@ get_odr_type (tree type, bool insert)
   if (insert_to_odr_array)
     {
       if (odr_types_ptr)
-        val->id = odr_types.length ();
+	val->id = odr_types.length ();
       vec_safe_push (odr_types_ptr, val);
     }
   else if (base_id > val->id)
@@ -667,6 +1170,20 @@ get_odr_type (tree type, bool insert)
   return val;
 }
 
+/* Add TYPE od ODR type hash.  */
+
+void
+register_odr_type (tree type)
+{
+  if (!odr_hash)
+    odr_hash = new odr_hash_type (23);
+  /* Arrange things to be nicer and insert main variants first.  */
+  if (odr_type_p (TYPE_MAIN_VARIANT (type)))
+    get_odr_type (TYPE_MAIN_VARIANT (type), true);
+  if (TYPE_MAIN_VARIANT (type) != type)
+    get_odr_type (type, true);
+}
+
 /* Dump ODR type T and all its derrived type.  INDENT specify indentation for
    recusive printing.  */
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]