re PR lto/61886 (LTO breaks fread with _FORTIFY_SOURCE=2)
authorJan Hubicka <hubicka@ucw.cz>
Mon, 7 Dec 2015 17:36:54 +0000 (18:36 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Mon, 7 Dec 2015 17:36:54 +0000 (17:36 +0000)
PR ipa/61886
* symtab.c (ultimate_transparent_alias_target): New inline function.
(symbol_table::assembler_names_equal_p): New method; break out from ...
(symbol_table::decl_assembler_name_equal): ... here.
(symbol_table::change_decl_assembler_name): Also update names and
translation links of transparent aliases.
(symtab_node::dump_base): Dump transparent_alias.
(symtab_node::verify_base): Implement basic transparent alias
verification.
(symtab_node::make_decl_local): Support localization of weakrefs;
recurse to transparent aliases; set TREE_STATIC.
(symtab_node::ultimate_alias_target_1): Handle visibility of
transparent aliases.
(symtab_node::resolve_alias): New parmaeter transparent; handle
transparent aliases; recurse to aliases of aliases to fix comdat
groups.
(symtab_node::get_partitioning_class): Handle transparent aliases.
* ipa-visibility.c (cgraph_externally_visible_p,
varpool_node::externally_visible_p): Visibility of transparent alias
depends on its target.
(function_and_variable_visibility): Do not tweak visibility of
transparent laiases.
(function_and_variable_visibility): Likewise.
* ipa.c (symbol_table::remove_unreachable_nodes): Clear
transparent_alias flag.
* alias.c (cgraph_node::create_alias, cgraph_node::get_availability):
Support transparent aliases.
* cgraph.h (symtab_node): Update prototype of resolve_alias;
add transparent_alias flag.
(symbol_table: Add assembler_names_equal_p.
(symtab_node::real_symbol_p): Skip transparent aliases.
* cgraphunit.c (cgraph_node::reset): Reset transparent_alias flag.
(handle_alias_pairs): Set transparent_alias for weakref.
(cgraph_node::assemble_thunks_and_aliases): Do not asemble transparent
aliases.
* lto-cgraph.c (lto_output_node): When outputting same_comdat_group
skip symbols not put into boundary; stream transparent_alias.
(lto_output_varpool_node): Likewise.
(input_overwrite_node, input_varpool_node): Stream transparent alias.
* varpool.c (ctor_for_folding, varpool_node::get_availability,
varpool_node::assemble_aliases,
symbol_table::remove_unreferenced_decls): Handle transparent aliase.
(varpool_node::create_alias): Set transparent_alias.

* lto-partition.c (add_symbol_to_partition_1, contained_in_symbol,
rename_statics, rename_statics): Handle transparent aliases.

From-SVN: r231373

12 files changed:
gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphunit.c
gcc/ipa-visibility.c
gcc/ipa.c
gcc/lto-cgraph.c
gcc/lto/ChangeLog
gcc/lto/lto-partition.c
gcc/symtab.c
gcc/tree.c
gcc/varpool.c

index abd648e3ce51839c63c042bc2215da99f6577819..d60a6da679c3de8e9c66be5c37584bc1bfa2b63e 100644 (file)
@@ -1,3 +1,49 @@
+2015-12-07  Jan Hubicka  <hubicka@ucw.cz>
+
+       PR ipa/61886
+       * symtab.c (ultimate_transparent_alias_target): New inline function.
+       (symbol_table::assembler_names_equal_p): New method; break out from ...
+       (symbol_table::decl_assembler_name_equal): ... here.
+       (symbol_table::change_decl_assembler_name): Also update names and
+       translation links of transparent aliases.
+       (symtab_node::dump_base): Dump transparent_alias.
+       (symtab_node::verify_base): Implement basic transparent alias
+       verification.
+       (symtab_node::make_decl_local): Support localization of weakrefs;
+       recurse to transparent aliases; set TREE_STATIC.
+       (symtab_node::ultimate_alias_target_1): Handle visibility of
+       transparent aliases.
+       (symtab_node::resolve_alias): New parmaeter transparent; handle
+       transparent aliases; recurse to aliases of aliases to fix comdat
+       groups.
+       (symtab_node::get_partitioning_class): Handle transparent aliases.
+       * ipa-visibility.c (cgraph_externally_visible_p,
+       varpool_node::externally_visible_p): Visibility of transparent alias
+       depends on its target.
+       (function_and_variable_visibility): Do not tweak visibility of
+       transparent laiases.
+       (function_and_variable_visibility): Likewise.
+       * ipa.c (symbol_table::remove_unreachable_nodes): Clear
+       transparent_alias flag.
+       * alias.c (cgraph_node::create_alias, cgraph_node::get_availability):
+       Support transparent aliases.
+       * cgraph.h (symtab_node): Update prototype of resolve_alias;
+       add transparent_alias flag.
+       (symbol_table: Add assembler_names_equal_p.
+       (symtab_node::real_symbol_p): Skip transparent aliases.
+       * cgraphunit.c (cgraph_node::reset): Reset transparent_alias flag.
+       (handle_alias_pairs): Set transparent_alias for weakref.
+       (cgraph_node::assemble_thunks_and_aliases): Do not asemble transparent
+       aliases.
+       * lto-cgraph.c (lto_output_node): When outputting same_comdat_group
+       skip symbols not put into boundary; stream transparent_alias.
+       (lto_output_varpool_node): Likewise.
+       (input_overwrite_node, input_varpool_node): Stream transparent alias.
+       * varpool.c (ctor_for_folding, varpool_node::get_availability,
+       varpool_node::assemble_aliases,
+       symbol_table::remove_unreferenced_decls): Handle transparent aliase.
+       (varpool_node::create_alias): Set transparent_alias.
+
 2015-12-07  Eric Botcazou  <ebotcazou@adacore.com>
 
        PR middle-end/68291
index 2a559785bf8355eb24fdda608fd7a4a8da088b71..35cd98c12f833347563426ad175703154bed60b9 100644 (file)
@@ -560,7 +560,7 @@ cgraph_node::create_alias (tree alias, tree target)
   alias_node->definition = true;
   alias_node->alias = true;
   if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL)
-    alias_node->weakref = true;
+    alias_node->transparent_alias = alias_node->weakref = true;
   return alias_node;
 }
 
@@ -2147,7 +2147,7 @@ cgraph_node::get_availability (void)
     avail = AVAIL_NOT_AVAILABLE;
   else if (local.local)
     avail = AVAIL_LOCAL;
-  else if (alias && weakref)
+  else if (transparent_alias)
     ultimate_alias_target (&avail);
   else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)))
     avail = AVAIL_INTERPOSABLE;
index e689fcd09d1a41bf8d44c035f69f0873bb208905..7c643502fff60bb2faa626269bc0f5b482349b84 100644 (file)
@@ -249,9 +249,10 @@ public:
   inline symtab_node *next_defined_symbol (void);
 
   /* Add reference recording that symtab node is alias of TARGET.
+     If TRANSPARENT is true make the alias to be transparent alias.
      The function can fail in the case of aliasing cycles; in this case
      it returns false.  */
-  bool resolve_alias (symtab_node *target);
+  bool resolve_alias (symtab_node *target, bool transparent = false);
 
   /* C++ FE sometimes change linkage flags after producing same
      body aliases.  */
@@ -421,6 +422,28 @@ public:
   /* True when symbol is an alias.
      Set by ssemble_alias.  */
   unsigned alias : 1;
+  /* When true the alias is translated into its target symbol either by GCC
+     or assembler (it also may just be a duplicate declaration of the same
+     linker name).
+
+     Currently transparent aliases come in three different flavors
+       - aliases having the same assembler name as their target (aka duplicated
+        declarations). In this case the assembler names compare via
+        assembler_names_equal_p and weakref is false
+       - aliases that are renamed at a time being output to final file
+        by varasm.c. For those DECL_ASSEMBLER_NAME have
+        IDENTIFIER_TRANSPARENT_ALIAS set and thus also their assembler
+        name must be unique.
+        Weakrefs belong to this cateogry when we target assembler without
+        .weakref directive.
+       - weakrefs that are renamed by assembler via .weakref directive.
+        In this case the alias may or may not be definition (depending if
+        target declaration was seen by the compiler), weakref is set.
+        Unless we are before renaming statics, assembler names are different.
+
+     Given that we now support duplicate declarations, the second option is
+     redundant and will be removed.  */
+  unsigned transparent_alias : 1;
   /* True when alias is a weakref.  */
   unsigned weakref : 1;
   /* C++ frontend produce same body aliases and extra name aliases for
@@ -2098,6 +2121,10 @@ public:
   /* Set the DECL_ASSEMBLER_NAME and update symtab hashtables.  */
   void change_decl_assembler_name (tree decl, tree name);
 
+  /* Return true if assembler names NAME1 and NAME2 leads to the same symbol
+     name.  */
+  static bool assembler_names_equal_p (const char *name1, const char *name2);
+
   int cgraph_count;
   int cgraph_max_uid;
   int cgraph_max_summary_uid;
@@ -2251,6 +2278,8 @@ symtab_node::real_symbol_p (void)
 
   if (DECL_ABSTRACT_P (decl))
     return false;
+  if (transparent_alias && definition)
+    return false;
   if (!is_a <cgraph_node *> (this))
     return true;
   cnode = dyn_cast <cgraph_node *> (this);
index 4ab64147e88c9435e39d822f8f9f1f62863ca826..3d86c36488ea589e3950214115c2df235c406d0e 100644 (file)
@@ -369,6 +369,7 @@ cgraph_node::reset (void)
   analyzed = false;
   definition = false;
   alias = false;
+  transparent_alias = false;
   weakref = false;
   cpp_implicit_alias = false;
 
@@ -594,7 +595,7 @@ cgraph_node::analyze (void)
       thunk.alias = NULL;
     }
   if (alias)
-    resolve_alias (cgraph_node::get (alias_target));
+    resolve_alias (cgraph_node::get (alias_target), transparent_alias);
   else if (dispatcher_function)
     {
       /* Generate the dispatcher body of multi-versioned functions.  */
@@ -1254,6 +1255,7 @@ handle_alias_pairs (void)
              node->alias_target = p->target;
              node->weakref = true;
              node->alias = true;
+             node->transparent_alias = true;
            }
          alias_pairs->unordered_remove (i);
          continue;
@@ -1908,15 +1910,18 @@ cgraph_node::assemble_thunks_and_aliases (void)
   FOR_EACH_ALIAS (this, ref)
     {
       cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
-      bool saved_written = TREE_ASM_WRITTEN (decl);
-
-      /* Force assemble_alias to really output the alias this time instead
-        of buffering it in same alias pairs.  */
-      TREE_ASM_WRITTEN (decl) = 1;
-      do_assemble_alias (alias->decl,
-                        DECL_ASSEMBLER_NAME (decl));
-      alias->assemble_thunks_and_aliases ();
-      TREE_ASM_WRITTEN (decl) = saved_written;
+      if (!alias->transparent_alias)
+       {
+         bool saved_written = TREE_ASM_WRITTEN (decl);
+
+         /* Force assemble_alias to really output the alias this time instead
+            of buffering it in same alias pairs.  */
+         TREE_ASM_WRITTEN (decl) = 1;
+         do_assemble_alias (alias->decl,
+                            DECL_ASSEMBLER_NAME (decl));
+         alias->assemble_thunks_and_aliases ();
+         TREE_ASM_WRITTEN (decl) = saved_written;
+       }
     }
 }
 
index 2eab214243e94dd446f657e56f729ee539f500d3..0423f242af06af937d9319efb2cd72f9f2b0ee10 100644 (file)
@@ -185,6 +185,8 @@ static bool
 cgraph_externally_visible_p (struct cgraph_node *node,
                             bool whole_program)
 {
+  while (node->transparent_alias && node->definition)
+    node = node->get_alias_target ();
   if (!node->definition)
     return false;
   if (!TREE_PUBLIC (node->decl)
@@ -248,6 +250,8 @@ cgraph_externally_visible_p (struct cgraph_node *node,
 bool
 varpool_node::externally_visible_p (void)
 {
+  while (transparent_alias && definition)
+    return get_alias_target ()->externally_visible_p ();
   if (DECL_EXTERNAL (decl))
     return true;
 
@@ -531,7 +535,8 @@ function_and_variable_visibility (bool whole_program)
                  next->set_comdat_group (NULL);
                  if (!next->alias)
                    next->set_section (NULL);
-                 next->make_decl_local ();
+                 if (!next->transparent_alias)
+                   next->make_decl_local ();
                  next->unique_name |= ((next->resolution == LDPR_PREVAILING_DEF_IRONLY
                                         || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
                                        && TREE_PUBLIC (next->decl)
@@ -547,7 +552,8 @@ function_and_variable_visibility (bool whole_program)
            node->set_comdat_group (NULL);
          if (DECL_COMDAT (node->decl) && !node->alias)
            node->set_section (NULL);
-         node->make_decl_local ();
+         if (!node->transparent_alias)
+           node->make_decl_local ();
        }
 
       if (node->thunk.thunk_p
@@ -654,7 +660,7 @@ function_and_variable_visibility (bool whole_program)
                            DECL_ATTRIBUTES (vnode->decl)))
        vnode->no_reorder = 1;
       if (!vnode->externally_visible
-         && !vnode->weakref)
+         && !vnode->transparent_alias)
        {
          gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl));
          vnode->unique_name |= ((vnode->resolution == LDPR_PREVAILING_DEF_IRONLY
@@ -675,11 +681,14 @@ function_and_variable_visibility (bool whole_program)
                  next->set_comdat_group (NULL);
                  if (!next->alias)
                    next->set_section (NULL);
-                 next->make_decl_local ();
-                 next->unique_name |= ((next->resolution == LDPR_PREVAILING_DEF_IRONLY
-                                        || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
-                                       && TREE_PUBLIC (next->decl)
-                                       && !flag_incremental_link);
+                 if (!next->transparent_alias)
+                   {
+                     next->make_decl_local ();
+                     next->unique_name |= ((next->resolution == LDPR_PREVAILING_DEF_IRONLY
+                                            || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
+                                           && TREE_PUBLIC (next->decl)
+                                           && !flag_incremental_link);
+                   }
                }
              vnode->dissolve_same_comdat_group_list ();
            }
@@ -687,8 +696,11 @@ function_and_variable_visibility (bool whole_program)
            vnode->set_comdat_group (NULL);
          if (DECL_COMDAT (vnode->decl) && !vnode->alias)
            vnode->set_section (NULL);
-         vnode->make_decl_local ();
-         vnode->resolution = LDPR_PREVAILING_DEF_IRONLY;
+         if (!vnode->transparent_alias)
+           {
+             vnode->make_decl_local ();
+             vnode->resolution = LDPR_PREVAILING_DEF_IRONLY;
+           }
        }
       update_visibility_by_resolution_info (vnode);
 
index 77f2dd1451dd56e5562ae11dbba609b140ef30f5..ce891e1249e4eacb0d283c3fb20a69bdca687fc7 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -543,6 +543,7 @@ symbol_table::remove_unreachable_nodes (FILE *file)
              node->definition = false;
              node->cpp_implicit_alias = false;
              node->alias = false;
+             node->transparent_alias = false;
              node->thunk.thunk_p = false;
              node->weakref = false;
              /* After early inlining we drop always_inline attributes on
index 67a9024ab28b94c0b1932d66901810898ea4d9cf..e1c259593d95cc44fe1aea97a090bbd4e50fdf06 100644 (file)
@@ -485,11 +485,12 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
 
   if (group)
     {
-      if (node->same_comdat_group && !boundary_p)
+      if (node->same_comdat_group)
        {
-         ref = lto_symtab_encoder_lookup (encoder,
-                                          node->same_comdat_group);
-         gcc_assert (ref != LCC_NOT_FOUND);
+         ref = LCC_NOT_FOUND;
+         for (struct symtab_node *n = node->same_comdat_group; 
+              ref == LCC_NOT_FOUND && n != node; n = n->same_comdat_group)
+           ref = lto_symtab_encoder_lookup (encoder, n);
        }
       else
        ref = LCC_NOT_FOUND;
@@ -523,6 +524,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
   bp_pack_value (&bp, node->lowered, 1);
   bp_pack_value (&bp, in_other_partition, 1);
   bp_pack_value (&bp, node->alias, 1);
+  bp_pack_value (&bp, node->transparent_alias, 1);
   bp_pack_value (&bp, node->weakref, 1);
   bp_pack_value (&bp, node->frequency, 2);
   bp_pack_value (&bp, node->only_called_at_startup, 1);
@@ -599,8 +601,9 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, varpool_node *node,
   bp_pack_value (&bp, node->definition && (encode_initializer_p || node->alias),
                 1);
   bp_pack_value (&bp, node->alias, 1);
+  bp_pack_value (&bp, node->transparent_alias, 1);
   bp_pack_value (&bp, node->weakref, 1);
-  bp_pack_value (&bp, node->analyzed && !boundary_p, 1);
+  bp_pack_value (&bp, node->analyzed && (!boundary_p || node->alias), 1);
   gcc_assert (node->definition || !node->analyzed);
   /* Constant pool initializers can be de-unified into individual ltrans units.
      FIXME: Alternatively at -Os we may want to avoid generating for them the local
@@ -632,11 +635,12 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, varpool_node *node,
 
   if (group)
     {
-      if (node->same_comdat_group && !boundary_p)
+      if (node->same_comdat_group)
        {
-         ref = lto_symtab_encoder_lookup (encoder,
-                                          node->same_comdat_group);
-         gcc_assert (ref != LCC_NOT_FOUND);
+         ref = LCC_NOT_FOUND;
+         for (struct symtab_node *n = node->same_comdat_group; 
+              ref == LCC_NOT_FOUND && n != node; n = n->same_comdat_group)
+           ref = lto_symtab_encoder_lookup (encoder, n);
        }
       else
        ref = LCC_NOT_FOUND;
@@ -1170,6 +1174,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data,
       TREE_STATIC (node->decl) = 0;
     }
   node->alias = bp_unpack_value (bp, 1);
+  node->transparent_alias = bp_unpack_value (bp, 1);
   node->weakref = bp_unpack_value (bp, 1);
   node->frequency = (enum node_frequency)bp_unpack_value (bp, 2);
   node->only_called_at_startup = bp_unpack_value (bp, 1);
@@ -1369,6 +1374,7 @@ input_varpool_node (struct lto_file_decl_data *file_data,
   node->writeonly = bp_unpack_value (&bp, 1);
   node->definition = bp_unpack_value (&bp, 1);
   node->alias = bp_unpack_value (&bp, 1);
+  node->transparent_alias = bp_unpack_value (&bp, 1);
   node->weakref = bp_unpack_value (&bp, 1);
   node->analyzed = bp_unpack_value (&bp, 1);
   node->used_from_other_partition = bp_unpack_value (&bp, 1);
index df2eaa9483e0617891347f4e3ca08efcf68bb94d..bdbc8665a1cff096b3b6ad997bdfb967b9a44c25 100644 (file)
@@ -1,3 +1,9 @@
+2015-12-07  Jan Hubicka  <hubicka@ucw.cz>
+
+       PR ipa/61886
+       * lto-partition.c (add_symbol_to_partition_1, contained_in_symbol,
+       rename_statics, rename_statics): Handle transparent aliases.
+
 2015-12-04  Jan Hubicka  <hubicka@ucw.cz>
 
        * lto-symtab.c (lto_cgraph_replace_node): Update code computing
index 4fd445f6950415e0b184c65b4385c20fbca92145..ac1b618a5e2ed8ecb60f21c9d44414e54b3c9b4b 100644 (file)
@@ -1035,7 +1035,15 @@ rename_statics (lto_symtab_encoder_t encoder, symtab_node *node)
   /* Assign every symbol in the set that shares the same ASM name an unique
      mangled name.  */
   for (s = symtab_node::get_for_asmname (name); s;)
-    if (!s->externally_visible
+    if ((!s->externally_visible || s->weakref)
+       /* Transparent aliases having same name as target are renamed at a
+          time their target gets new name.  Transparent aliases that use
+          separate assembler name require the name to be unique.  */
+       && (!s->transparent_alias || !s->definition || s->weakref
+           || !symbol_table::assembler_names_equal_p
+                (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (s->decl)),
+                 IDENTIFIER_POINTER
+                   (DECL_ASSEMBLER_NAME (s->get_alias_target()->decl))))
        && ((s->real_symbol_p ()
              && !DECL_EXTERNAL (node->decl)
             && !TREE_PUBLIC (node->decl))
index c188710ea92af35e4654fd0910b3459d91e68a13..06d618bb3b4a20a809ab0780e0e3c47e1adf5707 100644 (file)
@@ -52,6 +52,26 @@ const char * const ld_plugin_symbol_resolution_names[]=
   "prevailing_def_ironly_exp"
 };
 
+/* Follow the IDENTIFIER_TRANSPARENT_ALIAS chain starting at ALIAS
+   until we find an identifier that is not itself a transparent alias.  */
+
+static inline tree
+ultimate_transparent_alias_target (tree alias)
+{
+  tree target = alias;
+
+  while (IDENTIFIER_TRANSPARENT_ALIAS (target))
+    {
+      gcc_checking_assert (TREE_CHAIN (target));
+      target = TREE_CHAIN (target);
+    }
+  gcc_checking_assert (! IDENTIFIER_TRANSPARENT_ALIAS (target)
+                      && ! TREE_CHAIN (target));
+
+  return target;
+}
+
+
 /* Hash asmnames ignoring the user specified marks.  */
 
 hashval_t
@@ -73,6 +93,44 @@ symbol_table::decl_assembler_name_hash (const_tree asmname)
   return htab_hash_string (IDENTIFIER_POINTER (asmname));
 }
 
+/* Return true if assembler names NAME1 and NAME2 leads to the same symbol
+   name.  */
+
+bool
+symbol_table::assembler_names_equal_p (const char *name1, const char *name2)
+{
+  if (name1 != name2)
+    {
+      if (name1[0] == '*')
+       {
+         size_t ulp_len = strlen (user_label_prefix);
+
+         name1 ++;
+
+         if (ulp_len == 0)
+           ;
+         else if (strncmp (name1, user_label_prefix, ulp_len) == 0)
+           name1 += ulp_len;
+         else
+           return false;
+       }
+      if (name2[0] == '*')
+       {
+         size_t ulp_len = strlen (user_label_prefix);
+
+         name2 ++;
+
+         if (ulp_len == 0)
+           ;
+         else if (strncmp (name2, user_label_prefix, ulp_len) == 0)
+           name2 += ulp_len;
+         else
+           return false;
+       }
+      return !strcmp (name1, name2);
+    }
+  return true;
+}
 
 /* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL.  */
 
@@ -82,51 +140,13 @@ symbol_table::decl_assembler_name_equal (tree decl, const_tree asmname)
   tree decl_asmname = DECL_ASSEMBLER_NAME (decl);
   const char *decl_str;
   const char *asmname_str;
-  bool test = false;
 
   if (decl_asmname == asmname)
     return true;
 
   decl_str = IDENTIFIER_POINTER (decl_asmname);
   asmname_str = IDENTIFIER_POINTER (asmname);
-
-
-  /* If the target assembler name was set by the user, things are trickier.
-     We have a leading '*' to begin with.  After that, it's arguable what
-     is the correct thing to do with -fleading-underscore.  Arguably, we've
-     historically been doing the wrong thing in assemble_alias by always
-     printing the leading underscore.  Since we're not changing that, make
-     sure user_label_prefix follows the '*' before matching.  */
-  if (decl_str[0] == '*')
-    {
-      size_t ulp_len = strlen (user_label_prefix);
-
-      decl_str ++;
-
-      if (ulp_len == 0)
-       test = true;
-      else if (strncmp (decl_str, user_label_prefix, ulp_len) == 0)
-       decl_str += ulp_len, test=true;
-      else
-       decl_str --;
-    }
-  if (asmname_str[0] == '*')
-    {
-      size_t ulp_len = strlen (user_label_prefix);
-
-      asmname_str ++;
-
-      if (ulp_len == 0)
-       test = true;
-      else if (strncmp (asmname_str, user_label_prefix, ulp_len) == 0)
-       asmname_str += ulp_len, test=true;
-      else
-       asmname_str --;
-    }
-
-  if (!test)
-    return false;
-  return strcmp (decl_str, asmname_str) == 0;
+  return assembler_names_equal_p (decl_str, asmname_str);
 }
 
 
@@ -273,6 +293,8 @@ symbol_table::change_decl_assembler_name (tree decl, tree name)
                    : NULL);
       if (node)
        unlink_from_assembler_name_hash (node, true);
+
+      const char *old_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
       if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
          && DECL_RTL_SET_P (decl))
        warning (0, "%D renamed after being referenced in assembly", decl);
@@ -283,8 +305,48 @@ symbol_table::change_decl_assembler_name (tree decl, tree name)
          IDENTIFIER_TRANSPARENT_ALIAS (name) = 1;
          TREE_CHAIN (name) = alias;
        }
+      /* If we change assembler name, also all transparent aliases must
+        be updated.  There are three kinds - those having same assembler name,
+        those being renamed in varasm.c and weakref being renamed by the
+        assembler.  */
       if (node)
-       insert_to_assembler_name_hash (node, true);
+       {
+         insert_to_assembler_name_hash (node, true);
+         ipa_ref *ref;
+         for (unsigned i = 0; node->iterate_direct_aliases (i, ref); i++)
+           {
+             struct symtab_node *alias = ref->referring;
+             if (alias->transparent_alias && !alias->weakref
+                 && symbol_table::assembler_names_equal_p
+                        (old_name, IDENTIFIER_POINTER (
+                                     DECL_ASSEMBLER_NAME (alias->decl))))
+               change_decl_assembler_name (alias->decl, name);
+             else if (alias->transparent_alias
+                      && IDENTIFIER_TRANSPARENT_ALIAS (alias->decl))
+               {
+                 gcc_assert (TREE_CHAIN (DECL_ASSEMBLER_NAME (alias->decl))
+                             && IDENTIFIER_TRANSPARENT_ALIAS
+                                    (DECL_ASSEMBLER_NAME (alias->decl)));
+
+                 TREE_CHAIN (DECL_ASSEMBLER_NAME (alias->decl)) = 
+                   ultimate_transparent_alias_target
+                        (DECL_ASSEMBLER_NAME (node->decl));
+               }
+#ifdef ASM_OUTPUT_WEAKREF
+            else gcc_assert (!alias->transparent_alias || alias->weakref);
+#else
+            else gcc_assert (!alias->transparent_alias);
+#endif
+           }
+         gcc_assert (!node->transparent_alias || !node->definition
+                     || node->weakref
+                     || TREE_CHAIN (DECL_ASSEMBLER_NAME (decl))
+                     || symbol_table::assembler_names_equal_p
+                         (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+                          IDENTIFIER_POINTER
+                            (DECL_ASSEMBLER_NAME
+                                (node->get_alias_target ()->decl))));
+       }
     }
 }
 
@@ -727,6 +789,8 @@ symtab_node::dump_base (FILE *f)
     fprintf (f, " analyzed");
   if (alias)
     fprintf (f, " alias");
+  if (transparent_alias)
+    fprintf (f, " transparent_alias");
   if (weakref)
     fprintf (f, " weakref");
   if (cpp_implicit_alias)
@@ -973,9 +1037,14 @@ symtab_node::verify_base (void)
       error ("node is alias but not definition");
       error_found = true;
     }
-  if (weakref && !alias)
+  if (weakref && !transparent_alias)
     {
-      error ("node is weakref but not an alias");
+      error ("node is weakref but not an transparent_alias");
+      error_found = true;
+    }
+  if (transparent_alias && !alias)
+    {
+      error ("node is transparent_alias but not an alias");
       error_found = true;
     }
   if (same_comdat_group)
@@ -1061,6 +1130,29 @@ symtab_node::verify_base (void)
       get_alias_target ()->dump (stderr);
       error_found = true;
     }
+  if (transparent_alias && definition && !weakref)
+    {
+      symtab_node *to = get_alias_target ();
+      const char *name1
+       = IDENTIFIER_POINTER (
+           ultimate_transparent_alias_target (DECL_ASSEMBLER_NAME (decl)));
+      const char *name2
+       = IDENTIFIER_POINTER (
+           ultimate_transparent_alias_target (DECL_ASSEMBLER_NAME (to->decl)));
+      if (!symbol_table::assembler_names_equal_p (name1, name2))
+       {
+         error ("Transparent alias and target's assembler names differs");
+         get_alias_target ()->dump (stderr);
+         error_found = true;
+       }
+    }
+  if (transparent_alias && definition
+      && get_alias_target()->transparent_alias && get_alias_target()->analyzed)
+    {
+      error ("Chained transparent aliases");
+      get_alias_target ()->dump (stderr);
+      error_found = true;
+    }
 
   return error_found;
 }
@@ -1132,15 +1224,35 @@ symtab_node::make_decl_local (void)
 {
   rtx rtl, symbol;
 
+  if (weakref)
+    {
+      weakref = false;
+      IDENTIFIER_TRANSPARENT_ALIAS (DECL_ASSEMBLER_NAME (decl)) = 0;
+      TREE_CHAIN (DECL_ASSEMBLER_NAME (decl)) = NULL_TREE;
+      symtab->change_decl_assembler_name
+        (decl, DECL_ASSEMBLER_NAME (get_alias_target ()->decl));
+      DECL_ATTRIBUTES (decl) = remove_attribute ("weakref",
+                                                DECL_ATTRIBUTES (decl));
+    }
   /* Avoid clearing comdat_groups on comdat-local decls.  */
-  if (TREE_PUBLIC (decl) == 0)
+  else if (TREE_PUBLIC (decl) == 0)
     return;
 
+  /* Localizing a symbol also make all its transparent aliases local.  */
+  ipa_ref *ref;
+  for (unsigned i = 0; iterate_direct_aliases (i, ref); i++)
+    {
+      struct symtab_node *alias = ref->referring;
+      if (alias->transparent_alias)
+       alias->make_decl_local ();
+    }
+
   if (TREE_CODE (decl) == VAR_DECL)
     {
       DECL_COMMON (decl) = 0;
       /* ADDRESSABLE flag is not defined for public symbols.  */
       TREE_ADDRESSABLE (decl) = 1;
+      TREE_STATIC (decl) = 1;
     }
   else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
 
@@ -1175,29 +1287,28 @@ symtab_node::make_decl_local (void)
 symtab_node *
 symtab_node::ultimate_alias_target_1 (enum availability *availability)
 {
-  bool weakref_p = false;
+  bool transparent_p = false;
 
   /* To determine visibility of the target, we follow ELF semantic of aliases.
      Here alias is an alternative assembler name of a given definition. Its
      availability prevails the availability of its target (i.e. static alias of
      weak definition is available.
 
-     Weakref is a different animal (and not part of ELF per se). It is just
-     alternative name of a given symbol used within one complation unit
-     and is translated prior hitting the object file.  It inherits the
-     visibility of its target (i.e. weakref of non-overwritable definition
-     is non-overwritable, while weakref of weak definition is weak).
+     Transaparent alias is just alternative anme of a given symbol used within
+     one compilation unit and is translated prior hitting the object file.  It
+     inherits the visibility of its target.
+     Weakref is a different animal (and noweak definition is weak).
 
      If we ever get into supporting targets with different semantics, a target
      hook will be needed here.  */
 
   if (availability)
     {
-      weakref_p = weakref;
-      if (!weakref_p)
+      transparent_p = transparent_alias;
+      if (!transparent_p)
        *availability = get_availability ();
       else
-       *availability = AVAIL_LOCAL;
+       *availability = AVAIL_NOT_AVAILABLE;
     }
 
   symtab_node *node = this;
@@ -1207,27 +1318,19 @@ symtab_node::ultimate_alias_target_1 (enum availability *availability)
        node = node->get_alias_target ();
       else
        {
-         if (!availability)
+         if (!availability || (!transparent_p && node->analyzed))
            ;
-         else if (node->analyzed)
-           {
-             if (weakref_p)
-               {
-                 enum availability a = node->get_availability ();
-                 if (a < *availability)
-                   *availability = a;
-               }
-           }
+         else if (node->analyzed && !node->transparent_alias)
+           *availability = node->get_availability ();
          else
            *availability = AVAIL_NOT_AVAILABLE;
          return node;
        }
-      if (node && availability && weakref_p)
+      if (node && availability && transparent_p
+         && node->transparent_alias)
        {
-         enum availability a = node->get_availability ();
-         if (a < *availability)
-           *availability = a;
-          weakref_p = node->weakref;
+         *availability = node->get_availability ();
+         transparent_p = false;
        }
     }
   if (availability)
@@ -1442,7 +1545,7 @@ symtab_node::set_implicit_section (symtab_node *n,
    it returns false.  */
 
 bool
-symtab_node::resolve_alias (symtab_node *target)
+symtab_node::resolve_alias (symtab_node *target, bool transparent)
 {
   symtab_node *n;
 
@@ -1468,6 +1571,11 @@ symtab_node::resolve_alias (symtab_node *target)
   definition = true;
   alias = true;
   analyzed = true;
+  transparent |= transparent_alias;
+  transparent_alias = transparent;
+  if (transparent)
+    while (target->transparent_alias && target->analyzed)
+      target = target->get_alias_target ();
   create_reference (target, IPA_REF_ALIAS, NULL);
 
   /* Add alias into the comdat group of its target unless it is already there.  */
@@ -1492,19 +1600,29 @@ symtab_node::resolve_alias (symtab_node *target)
      when renaming symbols.  */
   alias_target = NULL;
 
-  if (cpp_implicit_alias && symtab->state >= CONSTRUCTION)
+  if (!transparent && cpp_implicit_alias && symtab->state >= CONSTRUCTION)
     fixup_same_cpp_alias_visibility (target);
 
   /* If alias has address taken, so does the target.  */
   if (address_taken)
     target->ultimate_alias_target ()->address_taken = true;
 
-  /* All non-weakref aliases of THIS are now in fact aliases of TARGET.  */
+  /* All non-transparent aliases of THIS are now in fact aliases of TARGET.
+     If alias is transparent, also all transparent aliases of THIS are now
+     aliases of TARGET.
+     Also merge same comdat group lists.  */
   ipa_ref *ref;
   for (unsigned i = 0; iterate_direct_aliases (i, ref);)
     {
       struct symtab_node *alias_alias = ref->referring;
-      if (!alias_alias->weakref)
+      if (alias_alias->get_comdat_group ())
+       {
+         alias_alias->remove_from_same_comdat_group ();
+         alias_alias->set_comdat_group (NULL);
+         if (target->get_comdat_group ())
+           alias_alias->add_to_same_comdat_group (target);
+       }
+      if (!alias_alias->transparent_alias || transparent)
        {
          alias_alias->remove_all_references ();
          alias_alias->create_reference (target, IPA_REF_ALIAS, NULL);
@@ -1648,9 +1766,9 @@ symtab_node::get_partitioning_class (void)
   if (cnode && cnode->global.inlined_to)
     return SYMBOL_DUPLICATE;
 
-  /* Weakref aliases are always duplicated.  */
-  if (weakref)
-    return SYMBOL_DUPLICATE;
+  /* Transparent aliases are always duplicated.  */
+  if (transparent_alias)
+    return definition ? SYMBOL_DUPLICATE : SYMBOL_EXTERNAL;
 
   /* External declarations are external.  */
   if (DECL_EXTERNAL (decl))
index c8b3ab8531cc19788352623a5c2b6b08c7dcfe17..de67c4fdd8734d99f43a932dc053d8b3b22402bd 100644 (file)
@@ -13423,6 +13423,12 @@ gimple_canonical_types_compatible_p (const_tree t1, const_tree t2,
       {
        tree f1, f2;
 
+       /* Don't try to compare variants of an incomplete type, before
+          TYPE_FIELDS has been copied around.  */
+       if (!COMPLETE_TYPE_P (t1) && !COMPLETE_TYPE_P (t2))
+         return true;
+
+
        if (TYPE_REVERSE_STORAGE_ORDER (t1) != TYPE_REVERSE_STORAGE_ORDER (t2))
          return false;
 
@@ -13709,28 +13715,35 @@ verify_type (const_tree t)
        }
     }
   else if (RECORD_OR_UNION_TYPE_P (t))
-    for (tree fld = TYPE_FIELDS (t); fld; fld = TREE_CHAIN (fld))
-      {
-       /* TODO: verify properties of decls.  */
-       if (TREE_CODE (fld) == FIELD_DECL)
-         ;
-       else if (TREE_CODE (fld) == TYPE_DECL)
-         ;
-       else if (TREE_CODE (fld) == CONST_DECL)
-         ;
-       else if (TREE_CODE (fld) == VAR_DECL)
-         ;
-       else if (TREE_CODE (fld) == TEMPLATE_DECL)
-         ;
-       else if (TREE_CODE (fld) == USING_DECL)
-         ;
-       else
-         {
-           error ("Wrong tree in TYPE_FIELDS list");
-           debug_tree (fld);
-           error_found = true;
-         }
-      }
+    {
+      if (TYPE_FIELDS (t) && !COMPLETE_TYPE_P (t) && in_lto_p)
+       {
+         error ("TYPE_FIELDS defined in incomplete type");
+         error_found = true;
+       }
+      for (tree fld = TYPE_FIELDS (t); fld; fld = TREE_CHAIN (fld))
+       {
+         /* TODO: verify properties of decls.  */
+         if (TREE_CODE (fld) == FIELD_DECL)
+           ;
+         else if (TREE_CODE (fld) == TYPE_DECL)
+           ;
+         else if (TREE_CODE (fld) == CONST_DECL)
+           ;
+         else if (TREE_CODE (fld) == VAR_DECL)
+           ;
+         else if (TREE_CODE (fld) == TEMPLATE_DECL)
+           ;
+         else if (TREE_CODE (fld) == USING_DECL)
+           ;
+         else
+           {
+             error ("Wrong tree in TYPE_FIELDS list");
+             debug_tree (fld);
+             error_found = true;
+           }
+       }
+    }
   else if (TREE_CODE (t) == INTEGER_TYPE
           || TREE_CODE (t) == BOOLEAN_TYPE
           || TREE_CODE (t) == OFFSET_TYPE
index 36f19a62ba825cf33250f7bcd748877cdff61bad..ffbec6d727a40f3349471f3566832133d1d7162c 100644 (file)
@@ -440,7 +440,7 @@ ctor_for_folding (tree decl)
       gcc_assert (!DECL_INITIAL (decl)
                  || (node->alias && node->get_alias_target () == real_node)
                  || DECL_INITIAL (decl) == error_mark_node);
-      if (node->weakref)
+      while (node->transparent_alias && node->analyzed)
        {
          node = node->get_alias_target ();
          decl = node->decl;
@@ -490,11 +490,11 @@ varpool_node::get_availability (void)
   if (DECL_IN_CONSTANT_POOL (decl)
       || DECL_VIRTUAL_P (decl))
     return AVAIL_AVAILABLE;
-  if (alias && weakref)
+  if (transparent_alias)
     {
       enum availability avail;
 
-      ultimate_alias_target (&avail)->get_availability ();
+      ultimate_alias_target (&avail);
       return avail;
     }
   /* If the variable can be overwritten, return OVERWRITABLE.  Takes
@@ -536,8 +536,9 @@ varpool_node::assemble_aliases (void)
   FOR_EACH_ALIAS (this, ref)
     {
       varpool_node *alias = dyn_cast <varpool_node *> (ref->referring);
-      do_assemble_alias (alias->decl,
-                        DECL_ASSEMBLER_NAME (decl));
+      if (!alias->transparent_alias)
+       do_assemble_alias (alias->decl,
+                          DECL_ASSEMBLER_NAME (decl));
       alias->assemble_aliases ();
     }
 }
@@ -665,7 +666,14 @@ symbol_table::remove_unreferenced_decls (void)
              && vnode->analyzed)
            enqueue_node (vnode, &first);
          else
-           referenced.add (node);
+           {
+             referenced.add (node);
+             while (node->alias && node->definition)
+               {
+                 node = node->get_alias_target ();
+                 referenced.add (node);
+               }
+           }
        }
     }
   if (dump_file)
@@ -760,7 +768,7 @@ varpool_node::create_alias (tree alias, tree decl)
   alias_node->definition = true;
   alias_node->alias_target = decl;
   if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL)
-    alias_node->weakref = true;
+    alias_node->weakref = alias_node->transparent_alias = true;
   return alias_node;
 }