diff mbox series

Stream TREE_TYPE of TYPE_DECLs again

Message ID 20181121000454.xszsneee7irfywt5@kam.mff.cuni.cz
State New
Headers show
Series Stream TREE_TYPE of TYPE_DECLs again | expand

Commit Message

Jan Hubicka Nov. 21, 2018, 12:04 a.m. UTC
Hi,
this patch recovers location infomration in the ODR warnings.
Because location info is not attached to types but corresponding
TYPE_DECLs, we need to prevent TYPE_DECLs to be merged when
corresponding types are not merged.

To achieve this I no longer clear TREE_TYPE of TYPE_DECLs which
puts them back to the same SCC as the type itself.  While making
incomplete type variant we need to produce copy of TYPE_DECL. Becuase
it is possible that TYPE_DECL was not processed by free lang data
we can not do copy_node but build it from scratch (because 
the toplevel loops possibly processed all decls). This is not hard
to do, but made me notice few extra flags that are streamed for
TYPE_DECLs and free_lang_data is not seeing them.

I have also extended ipa-devirt to get rid of the duplicated decls
once ODR warnings are done to save ltrans streaming (it actually
added about 10% of ltrans data w/o this change)

I have checked that the patch does not increase number of type
duplicates for cc1 (24), I will also re-do testing for Firefox
which may uncover some extra flags/attributes to care about.

lto-bootstrapped/regtested x86_64-linux OK?

Honza
	
	PR lto/87957
	* tree.c (fld_decl_context): Break out from ...
	(free_lang_data_in_decl): ... here; free TREE_PUBLIC, TREE_PRIVATE
	DECL_ARTIFICIAL of TYPE_DECL; do not free TREE_TYPE of TYPE_DECL.
	(fld_incomplete_type_of): Build copy of TYP_DECL.
	* ipa-devirt.c (free_enum_values): Rename to ...
	(free_odr_warning_data): ... this one; free also duplicated TYPE_DECLs
	and TREE_TYPEs of TYPE_DECLs.

Comments

Jan Hubicka Nov. 21, 2018, 5:32 a.m. UTC | #1
> 	PR lto/87957
> 	* tree.c (fld_decl_context): Break out from ...
> 	(free_lang_data_in_decl): ... here; free TREE_PUBLIC, TREE_PRIVATE
> 	DECL_ARTIFICIAL of TYPE_DECL; do not free TREE_TYPE of TYPE_DECL.
> 	(fld_incomplete_type_of): Build copy of TYP_DECL.
> 	* ipa-devirt.c (free_enum_values): Rename to ...
> 	(free_odr_warning_data): ... this one; free also duplicated TYPE_DECLs
> 	and TREE_TYPEs of TYPE_DECLs.
Hi,
and here are the testcases from the PR which I finally managed to
annotate so they are accepted :)

	PR lto/87957
	* g++.dg/lto/odr-1_0.C: Extend by mismatched enum.
	* g++.dg/lto/odr-1_1.C: Extend by mismatched enum.
	* g++.dg/lto/odr-2_0.C: New.
	* g++.dg/lto/odr-2_0.C: New.
	* g++.dg/lto/odr-3_1.C: New.
	* g++.dg/lto/odr-3_1.C: New.
Index: g++.dg/lto/odr-1_0.C
===================================================================
--- g++.dg/lto/odr-1_0.C	(revision 266333)
+++ g++.dg/lto/odr-1_0.C	(working copy)
@@ -1,8 +1,11 @@
 // PR c++/82414
 // { dg-lto-do link }
+enum vals {aa,cc}; // { dg-lto-warning "6: type 'vals' violates the C\\+\\+ One Definition Rule" }
 struct a { // { dg-lto-warning "8: type 'struct a' violates the C\\+\\+ One Definition Rule" }
   struct b *ptr; // { dg-lto-message "13: the first difference of corresponding definitions is field 'ptr'" }
+  enum vals vals;
 };
-void test(struct a *)
+void test(struct a *a)
 {
+  a->vals = cc;
 }
Index: g++.dg/lto/odr-1_1.C
===================================================================
--- g++.dg/lto/odr-1_1.C	(revision 266333)
+++ g++.dg/lto/odr-1_1.C	(working copy)
@@ -1,12 +1,16 @@
 namespace {
-  struct b;
+  struct b; // { dg-lto-message "type 'struct b' defined in anonymous namespace can not match across the translation unit boundary" }
  }
-struct a {
-  struct b *ptr;
-};
+enum vals {aa,bb,cc}; // { dg-lto-message "an enum with different value name is defined in another translation unit" }
+struct a { // { dg-lto-message "a different type is defined in another translation unit" }
+  struct b *ptr; // { dg-lto-message "a field of same name but different type is defined in another translation unit" }
+  enum vals vals;
+} a;
 void test(struct a *);
 int
 main(void)
 {
-  test (0);
+  test (&a);
+  if (a.vals==aa)
+    return 1;
 }
Index: g++.dg/lto/odr-2_0.C
===================================================================
--- g++.dg/lto/odr-2_0.C	(nonexistent)
+++ g++.dg/lto/odr-2_0.C	(working copy)
@@ -0,0 +1,8 @@
+// { dg-lto-do link }
+// { dg-lto-options { { -O0 -flto }  } 
+enum a {} b; // { dg-lto-warning "6: type 'a' violates the C\\+\\+ One Definition Rule" }
+int
+main(void)
+{
+  return 0;
+}
Index: g++.dg/lto/odr-2_1.C
===================================================================
--- g++.dg/lto/odr-2_1.C	(nonexistent)
+++ g++.dg/lto/odr-2_1.C	(working copy)
@@ -0,0 +1,4 @@
+class a { // { dg-lto-message "a different type is defined in another translation unit" }
+  int *b() const;
+};
+int *a::b() const { return 0; }
Index: g++.dg/lto/odr-3_0.C
===================================================================
--- g++.dg/lto/odr-3_0.C	(nonexistent)
+++ g++.dg/lto/odr-3_0.C	(working copy)
@@ -0,0 +1,12 @@
+// { dg-lto-do link }
+// { dg-lto-options { -O0 -flto }  } 
+
+typedef struct {
+  int a; // { dg-lto-message "the first difference of corresponding definitions is field 'a'" }
+} YYSTYPE; // { dg-lto-warning "3: warning: type ‘struct YYSTYPE’ violates the C\\+\\+ One Definition Rule" }
+union yyalloc { // { dg-lto-warning "7: type ‘union yyalloc’ violates the C\\+\\+ One Definition Rule" }
+  short yyss;
+  YYSTYPE yyvs; // { dg-lto-message "the first difference of corresponding definitions is field ‘yyvs’" }
+};
+void b() { yyalloc c; }
+
Index: g++.dg/lto/odr-3_1.C
===================================================================
--- g++.dg/lto/odr-3_1.C	(nonexistent)
+++ g++.dg/lto/odr-3_1.C	(working copy)
@@ -0,0 +1,9 @@
+typedef struct YYSTYPE { // { dg-lto-message ":16 a different type is defined in another translation unit" }
+} YYSTYPE;
+union yyalloc { 
+  short yyss;
+  YYSTYPE yyvs; // { dg-lto-message "the first difference of corresponding definitions is field ‘yyvs’" }
+
+};
+void a() { yyalloc b; }
+
Richard Biener Nov. 21, 2018, 8:43 a.m. UTC | #2
On Wed, 21 Nov 2018, Jan Hubicka wrote:

> Hi,
> this patch recovers location infomration in the ODR warnings.
> Because location info is not attached to types but corresponding
> TYPE_DECLs, we need to prevent TYPE_DECLs to be merged when
> corresponding types are not merged.
> 
> To achieve this I no longer clear TREE_TYPE of TYPE_DECLs which
> puts them back to the same SCC as the type itself.  While making
> incomplete type variant we need to produce copy of TYPE_DECL. Becuase
> it is possible that TYPE_DECL was not processed by free lang data
> we can not do copy_node but build it from scratch (because 
> the toplevel loops possibly processed all decls). This is not hard
> to do, but made me notice few extra flags that are streamed for
> TYPE_DECLs and free_lang_data is not seeing them.
> 
> I have also extended ipa-devirt to get rid of the duplicated decls
> once ODR warnings are done to save ltrans streaming (it actually
> added about 10% of ltrans data w/o this change)
> 
> I have checked that the patch does not increase number of type
> duplicates for cc1 (24), I will also re-do testing for Firefox
> which may uncover some extra flags/attributes to care about.
> 
> lto-bootstrapped/regtested x86_64-linux OK?

OK if you put a comment ...

> Honza
> 	
> 	PR lto/87957
> 	* tree.c (fld_decl_context): Break out from ...
> 	(free_lang_data_in_decl): ... here; free TREE_PUBLIC, TREE_PRIVATE
> 	DECL_ARTIFICIAL of TYPE_DECL; do not free TREE_TYPE of TYPE_DECL.
> 	(fld_incomplete_type_of): Build copy of TYP_DECL.
> 	* ipa-devirt.c (free_enum_values): Rename to ...
> 	(free_odr_warning_data): ... this one; free also duplicated TYPE_DECLs
> 	and TREE_TYPEs of TYPE_DECLs.
> 
> Index: tree.c
> ===================================================================
> --- tree.c	(revision 266325)
> +++ tree.c	(working copy)
> @@ -5206,6 +5206,24 @@ fld_process_array_type (tree t, tree t2,
>    return array;
>  }
>  
> +/* Return CTX after removal of contexts that are not relevant  */
> +
> +static tree
> +fld_decl_context (tree ctx)
> +{
> +  /* Variably modified types are needed for tree_is_indexable to decide
> +     whether the type needs to go to local or global section.
> +     This code is semi-broken but for now it is easiest to keep contexts
> +     as expected.  */
> +  if (ctx && TYPE_P (ctx)
> +      && !variably_modified_type_p (ctx, NULL_TREE))
> +     {
> +       while (ctx && TYPE_P (ctx))
> +	 ctx = TYPE_CONTEXT (ctx);
> +     }
> +  return ctx;
> +}
> +
>  /* For T being aggregate type try to turn it into a incomplete variant.
>     Return T if no simplification is possible.  */
>  
> @@ -5267,6 +5285,27 @@ fld_incomplete_type_of (tree t, struct f
>  	    }
>  	  else
>  	    TYPE_VALUES (copy) = NULL;
> +
> +	  /* Build copy of TYPE_DECL in TYPE_NAME if necessary.
> +	     This is needed for ODR violation warnings to come out right (we
> +	     want duplicate TYPE_DECLs whenever the type is duplicated because
> +	     of ODR violation.  Because lang data in the TYPE_DECL may not
> +	     have been freed yet, rebuild it from scratch and copy relevant
> +	     fields.  */
> +	  TYPE_NAME (copy) = fld_simplified_type_name (copy);
> +	  tree name = TYPE_NAME (copy);
> +
> +	  if (name && TREE_CODE (name) == TYPE_DECL)
> +	    {
> +	      gcc_checking_assert (TREE_TYPE (name) == t);
> +	      tree name2 = build_decl (DECL_SOURCE_LOCATION (name), TYPE_DECL,
> +				       DECL_NAME (name), copy);
> +	      SET_DECL_ASSEMBLER_NAME (name2, DECL_ASSEMBLER_NAME (name));
> +	      SET_DECL_ALIGN (name2, 0);
> +	      DECL_CONTEXT (name2) = fld_decl_context
> +					 (DECL_CONTEXT (name));
> +	      TYPE_NAME (copy) = name2;
> +	    }
>  	}
>        return copy;
>     }
> @@ -5649,12 +5688,13 @@ free_lang_data_in_decl (tree decl, struc
>      {
>        DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
>        DECL_VISIBILITY_SPECIFIED (decl) = 0;
> -      /* TREE_PUBLIC is used to tell if type is anonymous.  */
> +      TREE_PUBLIC (decl) = 0;
> +      TREE_PRIVATE (decl) = 0;
> +      DECL_ARTIFICIAL (decl) = 0;
>        TYPE_DECL_SUPPRESS_DEBUG (decl) = 0;
>        DECL_INITIAL (decl) = NULL_TREE;
>        DECL_ORIGINAL_TYPE (decl) = NULL_TREE;
>        DECL_MODE (decl) = VOIDmode;
> -      TREE_TYPE (decl) = void_type_node;
>        SET_DECL_ALIGN (decl, 0);
>      }
>    else if (TREE_CODE (decl) == FIELD_DECL)
> @@ -5688,20 +5728,7 @@ free_lang_data_in_decl (tree decl, struc
>    if (TREE_CODE (decl) != FIELD_DECL
>        && ((TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
>            || !DECL_VIRTUAL_P (decl)))
> -    {
> -      tree ctx = DECL_CONTEXT (decl);
> -      /* Variably modified types are needed for tree_is_indexable to decide
> -	 whether the type needs to go to local or global section.
> -	 This code is semi-broken but for now it is easiest to keep contexts
> -	 as expected.  */
> -      if (ctx && TYPE_P (ctx)
> -	  && !variably_modified_type_p (ctx, NULL_TREE))
> -	 {
> -	   while (ctx && TYPE_P (ctx))
> -	     ctx = TYPE_CONTEXT (ctx);
> -	   DECL_CONTEXT (decl) = ctx;
> -	 }
> -    }
> +    DECL_CONTEXT (decl) = fld_decl_context (DECL_CONTEXT (decl));
>  }
>  
>  
> Index: ipa-devirt.c
> ===================================================================
> --- ipa-devirt.c	(revision 266325)
> +++ ipa-devirt.c	(working copy)
> @@ -2289,27 +2289,39 @@ dump_type_inheritance_graph (FILE *f)
>  	   "%i duplicates overall\n", num_all_types, num_types, num_duplicates);
>  }
>  
> -/* Save some WPA->ltrans streaming by freeing enum values.  */
> +/* Save some WPA->ltrans streaming by freeing stuff needed only for good
> +   ODR warnings.  */
>  
>  static void
> -free_enum_values ()
> +free_odr_warning_data ()
>  {
> -  static bool enum_values_freed = false;
> -  if (enum_values_freed || !flag_wpa || !odr_types_ptr)
> +  static bool odr_data_freed = false;
> +
> +  if (odr_data_freed || !flag_wpa || !odr_types_ptr)
>      return;
> -  enum_values_freed = true;
> -  unsigned int i;
> -  for (i = 0; i < odr_types.length (); i++)
> +
> +  odr_data_freed = true;
> +
> +  for (unsigned int i = 0; i < odr_types.length (); i++)
>      if (odr_types[i])
>        {
> -	if (TREE_CODE (odr_types[i]->type) == ENUMERAL_TYPE)
> -	  TYPE_VALUES (odr_types[i]->type) = NULL;
> +	tree t = odr_types[i]->type;
> +
> +	if (TREE_CODE (t) == ENUMERAL_TYPE)
> +	  TYPE_VALUES (t) = NULL;
> +	TREE_TYPE (TYPE_NAME (t)) = void_type_node;

... here explaining the late "free-lang-data".

Richard.

> +
>  	if (odr_types[i]->types)
>            for (unsigned int j = 0; j < odr_types[i]->types->length (); j++)
> -	    if (TREE_CODE ((*odr_types[i]->types)[j]) == ENUMERAL_TYPE)
> -	      TYPE_VALUES ((*odr_types[i]->types)[j]) = NULL;
> +	    {
> +	      tree td = (*odr_types[i]->types)[j];
> +
> +	      if (TREE_CODE (td) == ENUMERAL_TYPE)
> +	        TYPE_VALUES (td) = NULL;
> +	      TYPE_NAME (td) = TYPE_NAME (t);
> +	    }
>        }
> -  enum_values_freed = true;
> +  odr_data_freed = true;
>  }
>  
>  /* Initialize IPA devirt and build inheritance tree graph.  */
> @@ -2323,7 +2335,7 @@ build_type_inheritance_graph (void)
>  
>    if (odr_hash)
>      {
> -      free_enum_values ();
> +      free_odr_warning_data ();
>        return;
>      }
>    timevar_push (TV_IPA_INHERITANCE);
> @@ -2370,7 +2382,7 @@ build_type_inheritance_graph (void)
>        dump_type_inheritance_graph (inheritance_dump_file);
>        dump_end (TDI_inheritance, inheritance_dump_file);
>      }
> -  free_enum_values ();
> +  free_odr_warning_data ();
>    timevar_pop (TV_IPA_INHERITANCE);
>  }
>  
> 
>
Jan Hubicka Nov. 21, 2018, 6:08 p.m. UTC | #3
> 
> OK if you put a comment ...

I have adde comments to both free_lang_data referring that some fields
are freed late and comment to the new freeing pass.
While testing I noticed stupid bug in need_assembler_name_p which in
case TYPE_DECL does not satisfy the elaborate conditional for type to be
ODR it falls into "return true" rather than false.  Fixing that
uncovered bug in -fno-odr-type-merging path of ipa-devirt where vtable
hash was no longer initialized. Fixed thus.

lto-bootstrapped/regtested x86_64-linux, comitted.
	
	PR lto/87957
	* tree.c (fld_decl_context): Break out from ...
	(free_lang_data_in_decl): ... here; free TREE_PUBLIC, TREE_PRIVATE
	DECL_ARTIFICIAL of TYPE_DECL; do not free TREE_TYPE of TYPE_DECL.
	(fld_incomplete_type_of): Build copy of TYP_DECL.
	* ipa-devirt.c (free_enum_values): Rename to ...
	(free_odr_warning_data): ... this one; free also duplicated TYPE_DECLs
	and TREE_TYPEs of TYPE_DECLs.
	(get_odr_type): Initialize odr_vtable_hash if needed.

Index: ipa-devirt.c
===================================================================
--- ipa-devirt.c	(revision 266334)
+++ ipa-devirt.c	(working copy)
@@ -2025,6 +2025,8 @@ get_odr_type (tree type, bool insert)
   if ((!slot || !*slot) && in_lto_p && can_be_vtable_hashed_p (type))
     {
       hash = hash_odr_vtable (type);
+      if (!odr_vtable_hash)
+        odr_vtable_hash = new odr_vtable_hash_type (23);
       vtable_slot = odr_vtable_hash->find_slot_with_hash (type, hash,
 					           insert ? INSERT : NO_INSERT);
     }
@@ -2289,27 +2291,43 @@ dump_type_inheritance_graph (FILE *f)
 	   "%i duplicates overall\n", num_all_types, num_types, num_duplicates);
 }
 
-/* Save some WPA->ltrans streaming by freeing enum values.  */
+/* Save some WPA->ltrans streaming by freeing stuff needed only for good
+   ODR warnings.
+   We free TYPE_VALUES of enums and also make TYPE_DECLs to not point back
+   to the type (which is needed to keep them in the same SCC and preserve
+   location information to output warnings) and subsequently we make all
+   TYPE_DECLS of same assembler name equivalent.  */
 
 static void
-free_enum_values ()
+free_odr_warning_data ()
 {
-  static bool enum_values_freed = false;
-  if (enum_values_freed || !flag_wpa || !odr_types_ptr)
+  static bool odr_data_freed = false;
+
+  if (odr_data_freed || !flag_wpa || !odr_types_ptr)
     return;
-  enum_values_freed = true;
-  unsigned int i;
-  for (i = 0; i < odr_types.length (); i++)
+
+  odr_data_freed = true;
+
+  for (unsigned int i = 0; i < odr_types.length (); i++)
     if (odr_types[i])
       {
-	if (TREE_CODE (odr_types[i]->type) == ENUMERAL_TYPE)
-	  TYPE_VALUES (odr_types[i]->type) = NULL;
+	tree t = odr_types[i]->type;
+
+	if (TREE_CODE (t) == ENUMERAL_TYPE)
+	  TYPE_VALUES (t) = NULL;
+	TREE_TYPE (TYPE_NAME (t)) = void_type_node;
+
 	if (odr_types[i]->types)
           for (unsigned int j = 0; j < odr_types[i]->types->length (); j++)
-	    if (TREE_CODE ((*odr_types[i]->types)[j]) == ENUMERAL_TYPE)
-	      TYPE_VALUES ((*odr_types[i]->types)[j]) = NULL;
+	    {
+	      tree td = (*odr_types[i]->types)[j];
+
+	      if (TREE_CODE (td) == ENUMERAL_TYPE)
+	        TYPE_VALUES (td) = NULL;
+	      TYPE_NAME (td) = TYPE_NAME (t);
+	    }
       }
-  enum_values_freed = true;
+  odr_data_freed = true;
 }
 
 /* Initialize IPA devirt and build inheritance tree graph.  */
@@ -2323,7 +2341,7 @@ build_type_inheritance_graph (void)
 
   if (odr_hash)
     {
-      free_enum_values ();
+      free_odr_warning_data ();
       return;
     }
   timevar_push (TV_IPA_INHERITANCE);
@@ -2370,7 +2388,7 @@ build_type_inheritance_graph (void)
       dump_type_inheritance_graph (inheritance_dump_file);
       dump_end (TDI_inheritance, inheritance_dump_file);
     }
-  free_enum_values ();
+  free_odr_warning_data ();
   timevar_pop (TV_IPA_INHERITANCE);
 }
 
Index: tree.c
===================================================================
--- tree.c	(revision 266325)
+++ tree.c	(working copy)
@@ -5206,6 +5206,24 @@ fld_process_array_type (tree t, tree t2,
   return array;
 }
 
+/* Return CTX after removal of contexts that are not relevant  */
+
+static tree
+fld_decl_context (tree ctx)
+{
+  /* Variably modified types are needed for tree_is_indexable to decide
+     whether the type needs to go to local or global section.
+     This code is semi-broken but for now it is easiest to keep contexts
+     as expected.  */
+  if (ctx && TYPE_P (ctx)
+      && !variably_modified_type_p (ctx, NULL_TREE))
+     {
+       while (ctx && TYPE_P (ctx))
+	 ctx = TYPE_CONTEXT (ctx);
+     }
+  return ctx;
+}
+
 /* For T being aggregate type try to turn it into a incomplete variant.
    Return T if no simplification is possible.  */
 
@@ -5267,6 +5285,28 @@ fld_incomplete_type_of (tree t, struct f
 	    }
 	  else
 	    TYPE_VALUES (copy) = NULL;
+
+	  /* Build copy of TYPE_DECL in TYPE_NAME if necessary.
+	     This is needed for ODR violation warnings to come out right (we
+	     want duplicate TYPE_DECLs whenever the type is duplicated because
+	     of ODR violation.  Because lang data in the TYPE_DECL may not
+	     have been freed yet, rebuild it from scratch and copy relevant
+	     fields.  */
+	  TYPE_NAME (copy) = fld_simplified_type_name (copy);
+	  tree name = TYPE_NAME (copy);
+
+	  if (name && TREE_CODE (name) == TYPE_DECL)
+	    {
+	      gcc_checking_assert (TREE_TYPE (name) == t);
+	      tree name2 = build_decl (DECL_SOURCE_LOCATION (name), TYPE_DECL,
+				       DECL_NAME (name), copy);
+	      if (DECL_ASSEMBLER_NAME_SET_P (name))
+	        SET_DECL_ASSEMBLER_NAME (name2, DECL_ASSEMBLER_NAME (name));
+	      SET_DECL_ALIGN (name2, 0);
+	      DECL_CONTEXT (name2) = fld_decl_context
+					 (DECL_CONTEXT (name));
+	      TYPE_NAME (copy) = name2;
+	    }
 	}
       return copy;
    }
@@ -5423,7 +5463,8 @@ free_lang_data_in_type (tree type, struc
       if (TREE_CODE (type) == ENUMERAL_TYPE)
 	{
 	  /* Type values are used only for C++ ODR checking.  Drop them
-	     for all type variants and non-ODR types.  */
+	     for all type variants and non-ODR types.
+	     For ODR types the data is freed in free_odr_warning_data.  */
 	  if (TYPE_MAIN_VARIANT (type) != type
 	      || !type_with_linkage_p (type))
 	    TYPE_VALUES (type) = NULL;
@@ -5455,11 +5496,7 @@ free_lang_data_in_type (tree type, struc
       TYPE_CONTEXT (type) = ctx;
     }
 
-  /* Drop TYPE_DECLs in TYPE_NAME in favor of the identifier in the
-     TYPE_DECL if the type doesn't have linkage.
-     this must match fld_  */
-  if (type != TYPE_MAIN_VARIANT (type) || ! type_with_linkage_p (type))
-    TYPE_STUB_DECL (type) = NULL;
+  TYPE_STUB_DECL (type) = NULL;
   TYPE_NAME (type) = fld_simplified_type_name (type);
 }
 
@@ -5486,16 +5523,19 @@ need_assembler_name_p (tree decl)
      e.g.  -fno-signed-char/-fsigned-char mismatches to be handled well.
      See cp/mangle.c:write_builtin_type for details.  */
 
-  if (flag_lto_odr_type_mering
-      && TREE_CODE (decl) == TYPE_DECL
-      && DECL_NAME (decl)
-      && decl == TYPE_NAME (TREE_TYPE (decl))
-      && TYPE_MAIN_VARIANT (TREE_TYPE (decl)) == TREE_TYPE (decl)
-      && !TYPE_ARTIFICIAL (TREE_TYPE (decl))
-      && (type_with_linkage_p (TREE_TYPE (decl))
-	  || TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE)
-      && !variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
-    return !DECL_ASSEMBLER_NAME_SET_P (decl);
+  if (TREE_CODE (decl) == TYPE_DECL)
+    {
+      if (flag_lto_odr_type_mering
+	  && DECL_NAME (decl)
+	  && decl == TYPE_NAME (TREE_TYPE (decl))
+	  && TYPE_MAIN_VARIANT (TREE_TYPE (decl)) == TREE_TYPE (decl)
+	  && !TYPE_ARTIFICIAL (TREE_TYPE (decl))
+	  && (type_with_linkage_p (TREE_TYPE (decl))
+	      || TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE)
+	  && !variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
+	return !DECL_ASSEMBLER_NAME_SET_P (decl);
+      return false;
+    }
   /* Only FUNCTION_DECLs and VAR_DECLs are considered.  */
   if (!VAR_OR_FUNCTION_DECL_P (decl))
     return false;
@@ -5649,13 +5689,15 @@ free_lang_data_in_decl (tree decl, struc
     {
       DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
       DECL_VISIBILITY_SPECIFIED (decl) = 0;
-      /* TREE_PUBLIC is used to tell if type is anonymous.  */
+      TREE_PUBLIC (decl) = 0;
+      TREE_PRIVATE (decl) = 0;
+      DECL_ARTIFICIAL (decl) = 0;
       TYPE_DECL_SUPPRESS_DEBUG (decl) = 0;
       DECL_INITIAL (decl) = NULL_TREE;
       DECL_ORIGINAL_TYPE (decl) = NULL_TREE;
       DECL_MODE (decl) = VOIDmode;
-      TREE_TYPE (decl) = void_type_node;
       SET_DECL_ALIGN (decl, 0);
+      /* TREE_TYPE is cleared at WPA time in free_odr_warning_data.  */
     }
   else if (TREE_CODE (decl) == FIELD_DECL)
     {
@@ -5688,20 +5730,7 @@ free_lang_data_in_decl (tree decl, struc
   if (TREE_CODE (decl) != FIELD_DECL
       && ((TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
           || !DECL_VIRTUAL_P (decl)))
-    {
-      tree ctx = DECL_CONTEXT (decl);
-      /* Variably modified types are needed for tree_is_indexable to decide
-	 whether the type needs to go to local or global section.
-	 This code is semi-broken but for now it is easiest to keep contexts
-	 as expected.  */
-      if (ctx && TYPE_P (ctx)
-	  && !variably_modified_type_p (ctx, NULL_TREE))
-	 {
-	   while (ctx && TYPE_P (ctx))
-	     ctx = TYPE_CONTEXT (ctx);
-	   DECL_CONTEXT (decl) = ctx;
-	 }
-    }
+    DECL_CONTEXT (decl) = fld_decl_context (DECL_CONTEXT (decl));
 }
Andreas Schwab Nov. 22, 2018, 10:42 a.m. UTC | #4
* g++.dg/lto/odr-2_0.C: Remove extra brace

diff --git a/gcc/testsuite/g++.dg/lto/odr-2_0.C b/gcc/testsuite/g++.dg/lto/odr-2_0.C
index 222fa2c1db..3ebb49efa2 100644
--- a/gcc/testsuite/g++.dg/lto/odr-2_0.C
+++ b/gcc/testsuite/g++.dg/lto/odr-2_0.C
@@ -1,5 +1,5 @@
 // { dg-lto-do link }
-// { dg-lto-options { { -O0 -flto }  } 
+// { dg-lto-options { -O0 -flto } }
 enum a {} b; // { dg-lto-warning "6: type 'a' violates the C\\+\\+ One Definition Rule" }
 int
 main(void)
Jan Hubicka Nov. 22, 2018, 4:30 p.m. UTC | #5
> 	* g++.dg/lto/odr-2_0.C: Remove extra brace
> 
> diff --git a/gcc/testsuite/g++.dg/lto/odr-2_0.C b/gcc/testsuite/g++.dg/lto/odr-2_0.C
> index 222fa2c1db..3ebb49efa2 100644
> --- a/gcc/testsuite/g++.dg/lto/odr-2_0.C
> +++ b/gcc/testsuite/g++.dg/lto/odr-2_0.C
> @@ -1,5 +1,5 @@
>  // { dg-lto-do link }
> -// { dg-lto-options { { -O0 -flto }  } 
> +// { dg-lto-options { -O0 -flto } }

Doesn't this make the testcase to be run twice, once with -O0 and second
time with -flto rather than running it once with -O0 -flto?

Honza

>  enum a {} b; // { dg-lto-warning "6: type 'a' violates the C\\+\\+ One Definition Rule" }
>  int
>  main(void)
> -- 
> 2.19.1
> 
> -- 
> Andreas Schwab, SUSE Labs, schwab@suse.de
> GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
> "And now for something completely different."
Andreas Schwab Nov. 22, 2018, 4:37 p.m. UTC | #6
On Nov 22 2018, Jan Hubicka <hubicka@ucw.cz> wrote:

>> 	* g++.dg/lto/odr-2_0.C: Remove extra brace
>> 
>> diff --git a/gcc/testsuite/g++.dg/lto/odr-2_0.C b/gcc/testsuite/g++.dg/lto/odr-2_0.C
>> index 222fa2c1db..3ebb49efa2 100644
>> --- a/gcc/testsuite/g++.dg/lto/odr-2_0.C
>> +++ b/gcc/testsuite/g++.dg/lto/odr-2_0.C
>> @@ -1,5 +1,5 @@
>>  // { dg-lto-do link }
>> -// { dg-lto-options { { -O0 -flto }  } 
>> +// { dg-lto-options { -O0 -flto } }
>
> Doesn't this make the testcase to be run twice, once with -O0 and second
> time with -flto rather than running it once with -O0 -flto?

It matches what odr-3_0.C does.

Andreas.
Richard Biener Nov. 22, 2018, 5:46 p.m. UTC | #7
On November 22, 2018 5:30:14 PM GMT+01:00, Jan Hubicka <hubicka@ucw.cz> wrote:
>> 	* g++.dg/lto/odr-2_0.C: Remove extra brace
>> 
>> diff --git a/gcc/testsuite/g++.dg/lto/odr-2_0.C
>b/gcc/testsuite/g++.dg/lto/odr-2_0.C
>> index 222fa2c1db..3ebb49efa2 100644
>> --- a/gcc/testsuite/g++.dg/lto/odr-2_0.C
>> +++ b/gcc/testsuite/g++.dg/lto/odr-2_0.C
>> @@ -1,5 +1,5 @@
>>  // { dg-lto-do link }
>> -// { dg-lto-options { { -O0 -flto }  } 
>> +// { dg-lto-options { -O0 -flto } }
>
>Doesn't this make the testcase to be run twice, once with -O0 and
>second
>time with -flto rather than running it once with -O0 -flto?

Yes. 

>Honza
>
>>  enum a {} b; // { dg-lto-warning "6: type 'a' violates the C\\+\\+
>One Definition Rule" }
>>  int
>>  main(void)
>> -- 
>> 2.19.1
>> 
>> -- 
>> Andreas Schwab, SUSE Labs, schwab@suse.de
>> GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA
>B9D7
>> "And now for something completely different."
Jan Hubicka Nov. 22, 2018, 6:14 p.m. UTC | #8
> On November 22, 2018 5:30:14 PM GMT+01:00, Jan Hubicka <hubicka@ucw.cz> wrote:
> >> 	* g++.dg/lto/odr-2_0.C: Remove extra brace
> >> 
> >> diff --git a/gcc/testsuite/g++.dg/lto/odr-2_0.C
> >b/gcc/testsuite/g++.dg/lto/odr-2_0.C
> >> index 222fa2c1db..3ebb49efa2 100644
> >> --- a/gcc/testsuite/g++.dg/lto/odr-2_0.C
> >> +++ b/gcc/testsuite/g++.dg/lto/odr-2_0.C
> >> @@ -1,5 +1,5 @@
> >>  // { dg-lto-do link }
> >> -// { dg-lto-options { { -O0 -flto }  } 
> >> +// { dg-lto-options { -O0 -flto } }
> >
> >Doesn't this make the testcase to be run twice, once with -O0 and
> >second
> >time with -flto rather than running it once with -O0 -flto?
> 
> Yes. 

Actually it would be useful to have ODR tested with optimization on
because streaming is somewhat optimization level specific. I will rework
the testcases today so they do not need dg-lto-options

Honza
Christophe Lyon Nov. 22, 2018, 7:32 p.m. UTC | #9
On Thu, 22 Nov 2018 at 19:14, Jan Hubicka <hubicka@ucw.cz> wrote:
>
> > On November 22, 2018 5:30:14 PM GMT+01:00, Jan Hubicka <hubicka@ucw.cz> wrote:
> > >>    * g++.dg/lto/odr-2_0.C: Remove extra brace
> > >>
> > >> diff --git a/gcc/testsuite/g++.dg/lto/odr-2_0.C
> > >b/gcc/testsuite/g++.dg/lto/odr-2_0.C
> > >> index 222fa2c1db..3ebb49efa2 100644
> > >> --- a/gcc/testsuite/g++.dg/lto/odr-2_0.C
> > >> +++ b/gcc/testsuite/g++.dg/lto/odr-2_0.C
> > >> @@ -1,5 +1,5 @@
> > >>  // { dg-lto-do link }
> > >> -// { dg-lto-options { { -O0 -flto }  }
> > >> +// { dg-lto-options { -O0 -flto } }
> > >
> > >Doesn't this make the testcase to be run twice, once with -O0 and
> > >second
> > >time with -flto rather than running it once with -O0 -flto?
> >
> > Yes.
>
> Actually it would be useful to have ODR tested with optimization on
> because streaming is somewhat optimization level specific. I will rework
> the testcases today so they do not need dg-lto-options
>

At least the extra {  or missing } causes Tcl errors:
ERROR: tcl error sourcing /gcc/testsuite/g++.dg/lto/lto.exp.
ERROR: unmatched open brace in list
    while executing
"foreach op $tmp {
        set cmd [lindex $op 0]
        verbose "cmd is $cmd"
        if { [string match "dg-skip-if" $cmd]  || [string match
"dg-require-*" $cmd] } {
          ..."
    (procedure "lto-get-options-main" line 26)




> Honza
Jan Hubicka Nov. 22, 2018, 8:31 p.m. UTC | #10
Hi,
I have tweaked the testcases as follows.  They now work with -O2
and additionally test better for locations of individual warnings.
The output is as follows:

../../gcc/testsuite/g++.dg/lto/odr-3_0.C:5:3: warning: type ‘struct YYSTYPE’ violates the C++ One Definition Rule [-Wodr]
    5 | } YYSTYPE; // { dg-lto-message "violates the C\\+\\+ One Definition Rule" 2 }
      |   ^
../../gcc/testsuite/g++.dg/lto/odr-3_1.C:1:16: note: a different type is defined in another translation unit
    1 | typedef struct YYSTYPE { // { dg-lto-message "type" 2 }
      |                ^
../../gcc/testsuite/g++.dg/lto/odr-3_0.C:4:7: note: the first difference of corresponding definitions is field ‘a’
    4 |   int a; // { dg-lto-message "the first difference of corresponding definitions is field 'a'" }
      |       ^
../../gcc/testsuite/g++.dg/lto/odr-3_1.C:1:16: note: a type with different number of fields is defined in another translation unit
    1 | typedef struct YYSTYPE { // { dg-lto-message "type" 2 }
      |                ^
../../gcc/testsuite/g++.dg/lto/odr-3_0.C:9:7: warning: type ‘union yyalloc’ violates the C++ One Definition Rule [-Wodr]
    9 | union yyalloc { // { dg-lto-warning "7: type 'union yyalloc' violates the C\\+\\+ One Definition Rule" }
      |       ^
../../gcc/testsuite/g++.dg/lto/odr-3_1.C:6:7: note: a different type is defined in another translation unit
    6 | union yyalloc { // { dg-lto-message "type" 2 }
      |       ^
../../gcc/testsuite/g++.dg/lto/odr-3_0.C:11:11: note: the first difference of corresponding definitions is field ‘yyvs’
   11 |   YYSTYPE yyvs; // { dg-lto-message "the first difference of corresponding definitions is field 'yyvs'" }
      |           ^
../../gcc/testsuite/g++.dg/lto/odr-3_1.C:11:11: note: a field of same name but different type is defined in another translation unit
   11 |   YYSTYPE yyvs; // { dg-lto-message "field of same name but different type is defined in another translation unit" }
      |           ^
../../gcc/testsuite/g++.dg/lto/odr-3_0.C:5:3: note: type ‘struct YYSTYPE’ itself violates the C++ One Definition Rule
    5 | } YYSTYPE; // { dg-lto-message "violates the C\\+\\+ One Definition Rule" 2 }
      |   ^
../../gcc/testsuite/g++.dg/lto/odr-3_0.C:13:16: warning: ‘a’ violates the C++ One Definition Rule [-Wodr]
   13 | extern yyalloc a; // { dg-lto-warning "16: 'a' violates the C\\+\\+ One Definition Rule" }
      |                ^
../../gcc/testsuite/g++.dg/lto/odr-3_1.C:6:7: note: type ‘union yyalloc’ itself violates the C++ One Definition Rule
    6 | union yyalloc { // { dg-lto-message "type" 2 }
      |       ^
../../gcc/testsuite/g++.dg/lto/odr-3_0.C:9:7: note: the incompatible type is defined here
    9 | union yyalloc { // { dg-lto-warning "7: type 'union yyalloc' violates the C\\+\\+ One Definition Rule" }
      |       ^
../../gcc/testsuite/g++.dg/lto/odr-3_1.C:15:9: note: ‘a’ was previously declared here
   15 | yyalloc a;  // { dg-lto-message "'a' was previously declared here" }
      |         ^
../../gcc/testsuite/g++.dg/lto/odr-3_1.C:15:9: note: code may be misoptimized unless -fno-strict-aliasing is used

which I hope is informative enough.  One problem is that I not know how
to pattern match warning and note or multiple notes pointing to single
location, so I have added somewhat generic dg-message patterns. Help
would be apprechiated.

I think ODR warnings should be in reasonable shape and it would be nice
to have more testsuite coverage. I find it very time consuming to write
the pattern matching, hope I will improve with time :)

The reason for verbosity is that they are often very cryptic to analyze
when difference comes from some ifdefs or other things not obvious in
the sources.

Honza


	* g++.dg/lto/odr-2_0.C: Drop dg-lto-options.
	* g++.dg/lto/odr-3_0.C: Likewise; harden for optimizing compilatoin.
Index: g++.dg/lto/odr-2_0.C
===================================================================
--- g++.dg/lto/odr-2_0.C	(revision 266382)
+++ g++.dg/lto/odr-2_0.C	(working copy)
@@ -1,5 +1,4 @@
 // { dg-lto-do link }
-// { dg-lto-options { -O0 -flto } }
 enum a {} b; // { dg-lto-warning "6: type 'a' violates the C\\+\\+ One Definition Rule" }
 int
 main(void)
Index: g++.dg/lto/odr-3_0.C
===================================================================
--- g++.dg/lto/odr-3_0.C	(revision 266382)
+++ g++.dg/lto/odr-3_0.C	(working copy)
@@ -1,12 +1,32 @@
 // { dg-lto-do link }
-// { dg-lto-options { -O0 -flto }  } 
 
 typedef struct {
   int a; // { dg-lto-message "the first difference of corresponding definitions is field 'a'" }
-} YYSTYPE; // { dg-lto-warning "3: warning: type ‘struct YYSTYPE’ violates the C\\+\\+ One Definition Rule" }
-union yyalloc { // { dg-lto-warning "7: type ‘union yyalloc’ violates the C\\+\\+ One Definition Rule" }
+} YYSTYPE; // { dg-lto-message "violates the C\\+\\+ One Definition Rule" 2 } 
+  // Here we get warning and a note:
+  // warning: type 'struct YYSTYPE' violates the C++ One Definition Rule
+  // note: type 'struct YYSTYPE' itself violates the C++ One Definition Rule
+union yyalloc { // { dg-lto-warning "7: type 'union yyalloc' violates the C\\+\\+ One Definition Rule" }
   short yyss;
-  YYSTYPE yyvs; // { dg-lto-message "the first difference of corresponding definitions is field ‘yyvs’" }
+  YYSTYPE yyvs; // { dg-lto-message "the first difference of corresponding definitions is field 'yyvs'" }
 };
-void b() { yyalloc c; }
+extern yyalloc a; // { dg-lto-warning "16: 'a' violates the C\\+\\+ One Definition Rule" }
+int
+main (void) {return a.yyss;}
 
+/* Match warnings as follows:
+  odr-3_0.C:5:3: warning: type 'struct YYSTYPE' violates the C++ One Definition Rule [-Wodr]
+  odr-3_1.C:1:16: note: a different type is defined in another translation unit^
+  odr-3_0.C:4:7: note: the first difference of corresponding definitions is field 'a'
+  odr-3_1.C:1:16: note: a type with different number of fields is defined in another translation unit
+  odr-3_0.C:9:7: warning: type 'union yyalloc' violates the C++ One Definition Rule [-Wodr]
+  odr-3_1.C:6:7: note: a different type is defined in another translation unit
+  odr-3_0.C:11:11: note: the first difference of corresponding definitions is field 'yyvs'
+  odr-3_1.C:11:11: note: a field of same name but different type is defined in another translation unit
+  odr-3_0.C:5:3: note: type 'struct YYSTYPE' itself violates the C++ One Definition Rule
+  odr-3_0.C:13:16: warning: 'a' violates the C++ One Definition Rule [-Wodr]
+  odr-3_1.C:6:7: note: type 'union yyalloc' itself violates the C++ One Definition Rule
+  odr-3_0.C:9:7: note: the incompatible type is defined here
+  odr-3_1.C:15:9: note: 'a' was previously declared here
+  odr-3_1.C:15:9: note: code may be misoptimized unless -fno-strict-aliasing is used
+*/
Index: g++.dg/lto/odr-3_1.C
===================================================================
--- g++.dg/lto/odr-3_1.C	(revision 266382)
+++ g++.dg/lto/odr-3_1.C	(working copy)
@@ -1,9 +1,16 @@
-typedef struct YYSTYPE { // { dg-lto-message ":16 a different type is defined in another translation unit" }
+typedef struct YYSTYPE { // { dg-lto-message "type" 2 }
+   // We get two notes here:
+   // note: a different type is defined in another translation unit
+   // note: a type with different number of fields is defined in another translation unit
 } YYSTYPE;
-union yyalloc { 
+union yyalloc { // { dg-lto-message "type" 2 }
+   // We get here three notes:
+   // note: a different type is defined in another translation unit
+   // note: type 'union yyalloc' itself violates the C++ One Definition Rule
   short yyss;
-  YYSTYPE yyvs; // { dg-lto-message "the first difference of corresponding definitions is field ‘yyvs’" }
+  YYSTYPE yyvs; // { dg-lto-message "field of same name but different type is defined in another translation unit" }
 
-};
-void a() { yyalloc b; }
+}; 
+
+yyalloc a;  // { dg-lto-message "'a' was previously declared here" }
Bernhard Reutner-Fischer Nov. 23, 2018, 9:14 p.m. UTC | #11
Honza, 

One nit.

On 21 November 2018 19:08:43 CET, Jan Hubicka <hubicka@ucw.cz> wrote:
>> 

>Index: ipa-devirt.c
>===================================================================
>--- ipa-devirt.c	(revision 266334)
>+++ ipa-devirt.c	(working copy)

>@@ -2289,27 +2291,43 @@ dump_type_inheritance_graph (FILE *f)
>	   "%i duplicates overall\n", num_all_types, num_types,
>num_duplicates);
> }
> 
>-/* Save some WPA->ltrans streaming by freeing enum values.  */
>+/* Save some WPA->ltrans streaming by freeing stuff needed only for
>good
>+   ODR warnings.
>+   We free TYPE_VALUES of enums and also make TYPE_DECLs to not point
>back
>+   to the type (which is needed to keep them in the same SCC and
>preserve
>+   location information to output warnings) and subsequently we make
>all
>+   TYPE_DECLS of same assembler name equivalent.  */
> 
> static void
>-free_enum_values ()
>+free_odr_warning_data ()
> {
>-  static bool enum_values_freed = false;
>-  if (enum_values_freed || !flag_wpa || !odr_types_ptr)
>+  static bool odr_data_freed = false;
>+
>+  if (odr_data_freed || !flag_wpa || !odr_types_ptr)
>     return;
>-  enum_values_freed = true;
>-  unsigned int i;
>-  for (i = 0; i < odr_types.length (); i++)
>+
>+  odr_data_freed = true;

First store to odr_data_freed is here. 

>+
>+  for (unsigned int i = 0; i < odr_types.length (); i++)
>     if (odr_types[i])
>       {
>-	if (TREE_CODE (odr_types[i]->type) == ENUMERAL_TYPE)
>-	  TYPE_VALUES (odr_types[i]->type) = NULL;
>+	tree t = odr_types[i]->type;
>+
>+	if (TREE_CODE (t) == ENUMERAL_TYPE)
>+	  TYPE_VALUES (t) = NULL;
>+	TREE_TYPE (TYPE_NAME (t)) = void_type_node;
>+
> 	if (odr_types[i]->types)
>      for (unsigned int j = 0; j < odr_types[i]->types->length (); j++)
>-	    if (TREE_CODE ((*odr_types[i]->types)[j]) == ENUMERAL_TYPE)
>-	      TYPE_VALUES ((*odr_types[i]->types)[j]) = NULL;
>+	    {
>+	      tree td = (*odr_types[i]->types)[j];
>+
>+	      if (TREE_CODE (td) == ENUMERAL_TYPE)
>+	        TYPE_VALUES (td) = NULL;
>+	      TYPE_NAME (td) = TYPE_NAME (t);
>+	    }
>       }
>-  enum_values_freed = true;
>+  odr_data_freed = true;

So please remove this second store.
Thanks,
> }
>
diff mbox series

Patch

Index: tree.c
===================================================================
--- tree.c	(revision 266325)
+++ tree.c	(working copy)
@@ -5206,6 +5206,24 @@  fld_process_array_type (tree t, tree t2,
   return array;
 }
 
+/* Return CTX after removal of contexts that are not relevant  */
+
+static tree
+fld_decl_context (tree ctx)
+{
+  /* Variably modified types are needed for tree_is_indexable to decide
+     whether the type needs to go to local or global section.
+     This code is semi-broken but for now it is easiest to keep contexts
+     as expected.  */
+  if (ctx && TYPE_P (ctx)
+      && !variably_modified_type_p (ctx, NULL_TREE))
+     {
+       while (ctx && TYPE_P (ctx))
+	 ctx = TYPE_CONTEXT (ctx);
+     }
+  return ctx;
+}
+
 /* For T being aggregate type try to turn it into a incomplete variant.
    Return T if no simplification is possible.  */
 
@@ -5267,6 +5285,27 @@  fld_incomplete_type_of (tree t, struct f
 	    }
 	  else
 	    TYPE_VALUES (copy) = NULL;
+
+	  /* Build copy of TYPE_DECL in TYPE_NAME if necessary.
+	     This is needed for ODR violation warnings to come out right (we
+	     want duplicate TYPE_DECLs whenever the type is duplicated because
+	     of ODR violation.  Because lang data in the TYPE_DECL may not
+	     have been freed yet, rebuild it from scratch and copy relevant
+	     fields.  */
+	  TYPE_NAME (copy) = fld_simplified_type_name (copy);
+	  tree name = TYPE_NAME (copy);
+
+	  if (name && TREE_CODE (name) == TYPE_DECL)
+	    {
+	      gcc_checking_assert (TREE_TYPE (name) == t);
+	      tree name2 = build_decl (DECL_SOURCE_LOCATION (name), TYPE_DECL,
+				       DECL_NAME (name), copy);
+	      SET_DECL_ASSEMBLER_NAME (name2, DECL_ASSEMBLER_NAME (name));
+	      SET_DECL_ALIGN (name2, 0);
+	      DECL_CONTEXT (name2) = fld_decl_context
+					 (DECL_CONTEXT (name));
+	      TYPE_NAME (copy) = name2;
+	    }
 	}
       return copy;
    }
@@ -5649,12 +5688,13 @@  free_lang_data_in_decl (tree decl, struc
     {
       DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
       DECL_VISIBILITY_SPECIFIED (decl) = 0;
-      /* TREE_PUBLIC is used to tell if type is anonymous.  */
+      TREE_PUBLIC (decl) = 0;
+      TREE_PRIVATE (decl) = 0;
+      DECL_ARTIFICIAL (decl) = 0;
       TYPE_DECL_SUPPRESS_DEBUG (decl) = 0;
       DECL_INITIAL (decl) = NULL_TREE;
       DECL_ORIGINAL_TYPE (decl) = NULL_TREE;
       DECL_MODE (decl) = VOIDmode;
-      TREE_TYPE (decl) = void_type_node;
       SET_DECL_ALIGN (decl, 0);
     }
   else if (TREE_CODE (decl) == FIELD_DECL)
@@ -5688,20 +5728,7 @@  free_lang_data_in_decl (tree decl, struc
   if (TREE_CODE (decl) != FIELD_DECL
       && ((TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
           || !DECL_VIRTUAL_P (decl)))
-    {
-      tree ctx = DECL_CONTEXT (decl);
-      /* Variably modified types are needed for tree_is_indexable to decide
-	 whether the type needs to go to local or global section.
-	 This code is semi-broken but for now it is easiest to keep contexts
-	 as expected.  */
-      if (ctx && TYPE_P (ctx)
-	  && !variably_modified_type_p (ctx, NULL_TREE))
-	 {
-	   while (ctx && TYPE_P (ctx))
-	     ctx = TYPE_CONTEXT (ctx);
-	   DECL_CONTEXT (decl) = ctx;
-	 }
-    }
+    DECL_CONTEXT (decl) = fld_decl_context (DECL_CONTEXT (decl));
 }
 
 
Index: ipa-devirt.c
===================================================================
--- ipa-devirt.c	(revision 266325)
+++ ipa-devirt.c	(working copy)
@@ -2289,27 +2289,39 @@  dump_type_inheritance_graph (FILE *f)
 	   "%i duplicates overall\n", num_all_types, num_types, num_duplicates);
 }
 
-/* Save some WPA->ltrans streaming by freeing enum values.  */
+/* Save some WPA->ltrans streaming by freeing stuff needed only for good
+   ODR warnings.  */
 
 static void
-free_enum_values ()
+free_odr_warning_data ()
 {
-  static bool enum_values_freed = false;
-  if (enum_values_freed || !flag_wpa || !odr_types_ptr)
+  static bool odr_data_freed = false;
+
+  if (odr_data_freed || !flag_wpa || !odr_types_ptr)
     return;
-  enum_values_freed = true;
-  unsigned int i;
-  for (i = 0; i < odr_types.length (); i++)
+
+  odr_data_freed = true;
+
+  for (unsigned int i = 0; i < odr_types.length (); i++)
     if (odr_types[i])
       {
-	if (TREE_CODE (odr_types[i]->type) == ENUMERAL_TYPE)
-	  TYPE_VALUES (odr_types[i]->type) = NULL;
+	tree t = odr_types[i]->type;
+
+	if (TREE_CODE (t) == ENUMERAL_TYPE)
+	  TYPE_VALUES (t) = NULL;
+	TREE_TYPE (TYPE_NAME (t)) = void_type_node;
+
 	if (odr_types[i]->types)
           for (unsigned int j = 0; j < odr_types[i]->types->length (); j++)
-	    if (TREE_CODE ((*odr_types[i]->types)[j]) == ENUMERAL_TYPE)
-	      TYPE_VALUES ((*odr_types[i]->types)[j]) = NULL;
+	    {
+	      tree td = (*odr_types[i]->types)[j];
+
+	      if (TREE_CODE (td) == ENUMERAL_TYPE)
+	        TYPE_VALUES (td) = NULL;
+	      TYPE_NAME (td) = TYPE_NAME (t);
+	    }
       }
-  enum_values_freed = true;
+  odr_data_freed = true;
 }
 
 /* Initialize IPA devirt and build inheritance tree graph.  */
@@ -2323,7 +2335,7 @@  build_type_inheritance_graph (void)
 
   if (odr_hash)
     {
-      free_enum_values ();
+      free_odr_warning_data ();
       return;
     }
   timevar_push (TV_IPA_INHERITANCE);
@@ -2370,7 +2382,7 @@  build_type_inheritance_graph (void)
       dump_type_inheritance_graph (inheritance_dump_file);
       dump_end (TDI_inheritance, inheritance_dump_file);
     }
-  free_enum_values ();
+  free_odr_warning_data ();
   timevar_pop (TV_IPA_INHERITANCE);
 }