]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/symtab.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / symtab.c
index a88f45c43416ffe9eeae5bf9f06206338c9c8721..c7ea8ecef74f8ac9d112328466c56ebb5f8e0abe 100644 (file)
@@ -1,5 +1,5 @@
 /* Symbol table.
-   Copyright (C) 2012-2019 Free Software Foundation, Inc.
+   Copyright (C) 2012-2021 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
 This file is part of GCC.
@@ -368,6 +368,36 @@ section_name_hasher::equal (section_hash_entry *n1, const char *name)
   return n1->name == name || !strcmp (n1->name, name);
 }
 
+/* Bump the reference count on ENTRY so that it is retained.  */
+
+static section_hash_entry *
+retain_section_hash_entry (section_hash_entry *entry)
+{
+  entry->ref_count++;
+  return entry;
+}
+
+/* Drop the reference count on ENTRY and remove it if the reference
+   count drops to zero.  */
+
+static void
+release_section_hash_entry (section_hash_entry *entry)
+{
+  if (entry)
+    {
+      entry->ref_count--;
+      if (!entry->ref_count)
+       {
+         hashval_t hash = htab_hash_string (entry->name);
+         section_hash_entry **slot
+           = symtab->section_hash->find_slot_with_hash (entry->name,
+                                                hash, INSERT);
+         ggc_free (entry);
+         symtab->section_hash->clear_slot (slot);
+       }
+    }
+}
+
 /* Add node into symbol table.  This function is not used directly, but via
    cgraph/varpool node creation routines.  */
 
@@ -408,10 +438,11 @@ symtab_node::remove_from_same_comdat_group (void)
 }
 
 /* Remove node from symbol table.  This function is not used directly, but via
-   cgraph/varpool node removal routines.  */
+   cgraph/varpool node removal routines.
+   INFO is a clone info to attach to new root of clone tree (if any).  */
 
 void
-symtab_node::unregister (void)
+symtab_node::unregister (clone_info *info)
 {
   remove_all_references ();
   remove_all_referring ();
@@ -430,7 +461,7 @@ symtab_node::unregister (void)
     {
       symtab_node *replacement_node = NULL;
       if (cgraph_node *cnode = dyn_cast <cgraph_node *> (this))
-       replacement_node = cnode->find_replacement ();
+       replacement_node = cnode->find_replacement (info);
       decl->decl_with_vis.symtab_node = replacement_node;
     }
   if (!is_a <varpool_node *> (this) || !DECL_HARD_REGISTER (decl))
@@ -473,6 +504,17 @@ symtab_node::add_to_same_comdat_group (symtab_node *old_node)
        ;
       n->same_comdat_group = this;
     }
+
+  cgraph_node *n;
+  if (comdat_local_p ()
+      && (n = dyn_cast <cgraph_node *> (this)) != NULL)
+    {
+      for (cgraph_edge *e = n->callers; e; e = e->next_caller)
+       if (e->caller->inlined_to)
+         e->caller->inlined_to->calls_comdat_local = true;
+       else
+         e->caller->calls_comdat_local = true;
+    }
 }
 
 /* Dissolve the same_comdat_group list in which NODE resides.  */
@@ -580,9 +622,9 @@ symtab_node::create_reference (symtab_node *referred_node,
   gcc_checking_assert (use_type != IPA_REF_ALIAS || !stmt);
 
   list = &ref_list;
-  old_references = vec_safe_address (list->references);
-  vec_safe_grow (list->references, vec_safe_length (list->references) + 1);
-  ref = &list->references->last ();
+  old_references = list->references.address ();
+  list->references.safe_grow (list->references.length () + 1, false);
+  ref = &list->references.last ();
 
   list2 = &referred_node->ref_list;
 
@@ -605,11 +647,12 @@ symtab_node::create_reference (symtab_node *referred_node,
   ref->referred = referred_node;
   ref->stmt = stmt;
   ref->lto_stmt_uid = 0;
+  ref->speculative_id = 0;
   ref->use = use_type;
   ref->speculative = 0;
 
   /* If vector was moved in memory, update pointers.  */
-  if (old_references != list->references->address ())
+  if (old_references != list->references.address ())
     {
       int i;
       for (i = 0; iterate_reference(i, ref2); i++)
@@ -658,10 +701,12 @@ symtab_node::clone_references (symtab_node *node)
     {
       bool speculative = ref->speculative;
       unsigned int stmt_uid = ref->lto_stmt_uid;
+      unsigned int spec_id = ref->speculative_id;
 
       ref2 = create_reference (ref->referred, ref->use, ref->stmt);
       ref2->speculative = speculative;
       ref2->lto_stmt_uid = stmt_uid;
+      ref2->speculative_id = spec_id;
     }
 }
 
@@ -676,10 +721,12 @@ symtab_node::clone_referring (symtab_node *node)
     {
       bool speculative = ref->speculative;
       unsigned int stmt_uid = ref->lto_stmt_uid;
+      unsigned int spec_id = ref->speculative_id;
 
       ref2 = ref->referring->create_reference (this, ref->use, ref->stmt);
       ref2->speculative = speculative;
       ref2->lto_stmt_uid = stmt_uid;
+      ref2->speculative_id = spec_id;
     }
 }
 
@@ -690,11 +737,13 @@ symtab_node::clone_reference (ipa_ref *ref, gimple *stmt)
 {
   bool speculative = ref->speculative;
   unsigned int stmt_uid = ref->lto_stmt_uid;
+  unsigned int spec_id = ref->speculative_id;
   ipa_ref *ref2;
 
   ref2 = create_reference (ref->referred, ref->use, stmt);
   ref2->speculative = speculative;
   ref2->lto_stmt_uid = stmt_uid;
+  ref2->speculative_id = spec_id;
   return ref2;
 }
 
@@ -733,7 +782,8 @@ symtab_node::remove_stmt_references (gimple *stmt)
       i++;
 }
 
-/* Remove all stmt references in non-speculative references.
+/* Remove all stmt references in non-speculative references in THIS
+   and all clones.
    Those are not maintained during inlining & cloning.
    The exception are speculative references that are updated along
    with callgraph edges associated with them.  */
@@ -749,7 +799,15 @@ symtab_node::clear_stmts_in_references (void)
       {
        r->stmt = NULL;
        r->lto_stmt_uid = 0;
+       r->speculative_id = 0;
       }
+  cgraph_node *cnode = dyn_cast <cgraph_node *> (this);
+  if (cnode)
+    {
+      if (cnode->clones)
+       for (cnode = cnode->clones; cnode; cnode = cnode->next_sibling_clone)
+         cnode->clear_stmts_in_references ();
+    }
 }
 
 /* Remove all references in ref list.  */
@@ -757,9 +815,9 @@ symtab_node::clear_stmts_in_references (void)
 void
 symtab_node::remove_all_references (void)
 {
-  while (vec_safe_length (ref_list.references))
-    ref_list.references->last ().remove_reference ();
-  vec_free (ref_list.references);
+  while (ref_list.references.length ())
+    ref_list.references.last ().remove_reference ();
+  ref_list.references.release ();
 }
 
 /* Remove all referring items in ref list.  */
@@ -781,11 +839,10 @@ symtab_node::dump_references (FILE *file)
   int i;
   for (i = 0; iterate_reference (i, ref); i++)
     {
-      fprintf (file, "%s (%s)",
-              ref->referred->dump_asm_name (),
-              ipa_ref_use_name [ref->use]);
+      fprintf (file, "%s (%s) ", ref->referred->dump_asm_name (),
+              ipa_ref_use_name[ref->use]);
       if (ref->speculative)
-       fprintf (file, " (speculative)");
+       fprintf (file, "(speculative) ");
     }
   fprintf (file, "\n");
 }
@@ -799,11 +856,10 @@ symtab_node::dump_referring (FILE *file)
   int i;
   for (i = 0; iterate_referring(i, ref); i++)
     {
-      fprintf (file, "%s (%s)",
-              ref->referring->dump_asm_name (),
-              ipa_ref_use_name [ref->use]);
+      fprintf (file, "%s (%s) ", ref->referring->dump_asm_name (),
+              ipa_ref_use_name[ref->use]);
       if (ref->speculative)
-       fprintf (file, " (speculative)");
+       fprintf (file, "(speculative) ");
     }
   fprintf (file, "\n");
 }
@@ -1068,6 +1124,11 @@ symtab_node::verify_base (void)
       error ("node has unknown type");
       error_found = true;
     }
+  if (order < 0 || order >= symtab->order)
+    {
+      error ("node has invalid order %i", order);
+      error_found = true;
+    }
    
   if (symtab->state != LTO_STREAMING)
     {
@@ -1156,6 +1217,22 @@ symtab_node::verify_base (void)
       error ("node is symver but not alias");
       error_found = true;
     }
+  /* Limitation of gas requires us to output targets of symver aliases as
+     global symbols.  This is binutils PR 25295.  */
+  if (symver
+      && (!TREE_PUBLIC (get_alias_target ()->decl)
+         || DECL_VISIBILITY (get_alias_target ()->decl) != VISIBILITY_DEFAULT))
+    {
+      error ("symver target is not exported with default visibility");
+      error_found = true;
+    }
+  if (symver
+      && (!TREE_PUBLIC (decl)
+         || DECL_VISIBILITY (decl) != VISIBILITY_DEFAULT))
+    {
+      error ("symver is not exported with default visibility");
+      error_found = true;
+    }
   if (same_comdat_group)
     {
       symtab_node *n = same_comdat_group;
@@ -1293,6 +1370,14 @@ symtab_node::verify_symtab_nodes (void)
 {
   symtab_node *node;
   hash_map<tree, symtab_node *> comdat_head_map (251);
+  asm_node *anode;
+
+  for (anode = symtab->first_asm_symbol (); anode; anode = anode->next)
+    if (anode->order < 0 || anode->order >= symtab->order)
+       {
+         error ("invalid order in asm node %i", anode->order);
+         internal_error ("symtab_node::verify failed");
+       }
 
   FOR_EACH_SYMBOL (node)
     {
@@ -1429,8 +1514,7 @@ symtab_node::copy_visibility_from (symtab_node *n)
   DECL_DLLIMPORT_P (decl) = DECL_DLLIMPORT_P (n->decl);
   resolution = n->resolution;
   set_comdat_group (n->get_comdat_group ());
-  call_for_symbol_and_aliases (symtab_node::set_section,
-                            const_cast<char *>(n->get_section ()), true);
+  set_section (*n);
   externally_visible = n->externally_visible;
   if (!DECL_RTL_SET_P (decl))
     return;
@@ -1555,57 +1639,76 @@ void
 symtab_node::set_section_for_node (const char *section)
 {
   const char *current = get_section ();
-  section_hash_entry **slot;
 
   if (current == section
       || (current && section
          && !strcmp (current, section)))
     return;
 
-  if (current)
-    {
-      x_section->ref_count--;
-      if (!x_section->ref_count)
-       {
-         hashval_t hash = htab_hash_string (x_section->name);
-         slot = symtab->section_hash->find_slot_with_hash (x_section->name,
-                                                           hash, INSERT);
-         ggc_free (x_section);
-         symtab->section_hash->clear_slot (slot);
-       }
-      x_section = NULL;
-    }
+  release_section_hash_entry (x_section);
   if (!section)
     {
+      x_section = NULL;
       implicit_section = false;
       return;
     }
   if (!symtab->section_hash)
     symtab->section_hash = hash_table<section_name_hasher>::create_ggc (10);
-  slot = symtab->section_hash->find_slot_with_hash (section,
-                                                   htab_hash_string (section),
-                                                   INSERT);
+  section_hash_entry **slot = symtab->section_hash->find_slot_with_hash
+    (section, htab_hash_string (section), INSERT);
   if (*slot)
-    x_section = (section_hash_entry *)*slot;
+    x_section = retain_section_hash_entry (*slot);
   else
     {
       int len = strlen (section);
       *slot = x_section = ggc_cleared_alloc<section_hash_entry> ();
+      x_section->ref_count = 1;
       x_section->name = ggc_vec_alloc<char> (len + 1);
       memcpy (x_section->name, section, len + 1);
     }
-  x_section->ref_count++;
 }
 
-/* Worker for set_section.  */
+/* Set the section of node THIS to be the same as the section
+   of node OTHER.  Keep reference counts of the sections
+   up-to-date as needed.  */
+
+void
+symtab_node::set_section_for_node (const symtab_node &other)
+{
+  if (x_section == other.x_section)
+    return;
+  if (get_section () && other.get_section ())
+    gcc_checking_assert (strcmp (get_section (), other.get_section ()) != 0);
+  release_section_hash_entry (x_section);
+  if (other.x_section)
+    x_section = retain_section_hash_entry (other.x_section);
+  else
+    {
+      x_section = NULL;
+      implicit_section = false;
+    }
+}
+
+/* Workers for set_section.  */
 
 bool
-symtab_node::set_section (symtab_node *n, void *s)
+symtab_node::set_section_from_string (symtab_node *n, void *s)
 {
   n->set_section_for_node ((char *)s);
   return false;
 }
 
+/* Set the section of node N to be the same as the section
+   of node O.  */
+
+bool
+symtab_node::set_section_from_node (symtab_node *n, void *o)
+{
+  const symtab_node &other = *static_cast<const symtab_node *> (o);
+  n->set_section_for_node (other);
+  return false;
+}
+
 /* Set section of symbol and its aliases.  */
 
 void
@@ -1613,7 +1716,14 @@ symtab_node::set_section (const char *section)
 {
   gcc_assert (!this->alias || !this->analyzed);
   call_for_symbol_and_aliases
-    (symtab_node::set_section, const_cast<char *>(section), true);
+    (symtab_node::set_section_from_string, const_cast<char *>(section), true);
+}
+
+void
+symtab_node::set_section (const symtab_node &other)
+{
+  call_for_symbol_and_aliases
+    (symtab_node::set_section_from_node, const_cast<symtab_node *>(&other), true);
 }
 
 /* Return the initialization priority.  */
@@ -1718,7 +1828,7 @@ symtab_node::resolve_alias (symtab_node *target, bool transparent)
 {
   symtab_node *n;
 
-  gcc_assert (!analyzed && !vec_safe_length (ref_list.references));
+  gcc_assert (!analyzed && !ref_list.references.length ());
 
   /* Never let cycles to creep into the symbol table alias references;
      those will make alias walkers to be infinite.  */
@@ -1759,8 +1869,7 @@ symtab_node::resolve_alias (symtab_node *target, bool transparent)
     {
       error ("section of alias %q+D must match section of its target", decl);
     }
-  call_for_symbol_and_aliases (symtab_node::set_section,
-                            const_cast<char *>(target->get_section ()), true);
+  set_section (*target);
   if (target->implicit_section)
     call_for_symbol_and_aliases (set_implicit_section, NULL, true);
 
@@ -1843,18 +1952,30 @@ symtab_node::noninterposable_alias (void)
   symtab_node *node = ultimate_alias_target ();
   gcc_assert (!node->alias && !node->weakref);
   node->call_for_symbol_and_aliases (symtab_node::noninterposable_alias,
-                                  (void *)&new_node, true);
+                                    (void *)&new_node, true);
   if (new_node)
     return new_node;
 
   /* If aliases aren't supported by the assembler, fail.  */
   if (!TARGET_SUPPORTS_ALIASES)
     return NULL;
+  else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (node->decl)))
+    return NULL;
 
   /* Otherwise create a new one.  */
   new_decl = copy_node (node->decl);
   DECL_DLLIMPORT_P (new_decl) = 0;
-  DECL_NAME (new_decl) = clone_function_name (node->decl, "localalias");
+  tree name = clone_function_name (node->decl, "localalias");
+  if (!flag_wpa)
+    {
+      unsigned long num = 0;
+      /* In the rare case we already have a localalias, but the above
+        node->call_for_symbol_and_aliases call didn't find any suitable,
+        iterate until we find one not used yet.  */
+      while (symtab_node::get_for_asmname (name))
+       name = clone_function_name (node->decl, "localalias", num++);
+    }
+  DECL_NAME (new_decl) = name;
   if (TREE_CODE (new_decl) == FUNCTION_DECL)
     DECL_STRUCT_FUNCTION (new_decl) = NULL;
   DECL_INITIAL (new_decl) = NULL;
@@ -1941,7 +2062,7 @@ symtab_node::get_partitioning_class (void)
   if (DECL_ABSTRACT_P (decl))
     return SYMBOL_EXTERNAL;
 
-  if (cnode && cnode->inlined_to)
+  if (cnode && (cnode->inlined_to || cnode->declare_variant_alt))
     return SYMBOL_DUPLICATE;
 
   /* Transparent aliases are always duplicated.  */
@@ -1952,6 +2073,11 @@ symtab_node::get_partitioning_class (void)
   if (DECL_EXTERNAL (decl))
     return SYMBOL_EXTERNAL;
 
+  /* Even static aliases of external functions as external.  Those can happen
+     when COMDAT got resolved to non-IL implementation.  */
+  if (alias && DECL_EXTERNAL (ultimate_alias_target ()->decl))
+    return SYMBOL_EXTERNAL;
+
   if (varpool_node *vnode = dyn_cast <varpool_node *> (this))
     {
       if (alias && definition && !ultimate_alias_target ()->definition)
@@ -2022,22 +2148,22 @@ symtab_node::nonzero_address ()
      bind to NULL. This is on by default on embedded targets only.
 
      Otherwise all non-WEAK symbols must be defined and thus non-NULL or
-     linking fails.  Important case of WEAK we want to do well are comdats.
-     Those are handled by later check for definition.
+     linking fails.  Important case of WEAK we want to do well are comdats,
+     which also must be defined somewhere.
 
      When parsing, beware the cases when WEAK attribute is added later.  */
-  if (!DECL_WEAK (decl)
+  if ((!DECL_WEAK (decl) || DECL_COMDAT (decl))
       && flag_delete_null_pointer_checks)
     {
       refuse_visibility_changes = true;
       return true;
     }
 
-  /* If target is defined and either comdat or not extern, we know it will be
+  /* If target is defined and not extern, we know it will be
      output and thus it will bind to non-NULL.
      Play safe for flag_delete_null_pointer_checks where weak definition may
      be re-defined by NULL.  */
-  if (definition && (!DECL_EXTERNAL (decl) || DECL_COMDAT (decl))
+  if (definition && !DECL_EXTERNAL (decl)
       && (flag_delete_null_pointer_checks || !DECL_WEAK (decl)))
     {
       if (!DECL_WEAK (decl))
@@ -2329,7 +2455,7 @@ symbol_table::symbol_suffix_separator ()
 bool
 symtab_node::binds_to_current_def_p (symtab_node *ref)
 {
-  if (!definition)
+  if (!definition && !in_other_partition)
     return false;
   if (transparent_alias)
     return definition
@@ -2402,10 +2528,7 @@ symtab_node::output_to_lto_symbol_table_p (void)
         in libraries so make sure to output references into the symbol table to
         make those libraries referenced.  Note this is incomplete handling for
         now and only covers math functions.  */
-      if (builtin_with_linkage_p (decl))
-       return true;
-      else
-       return false;
+      return builtin_with_linkage_p (decl);
     }
 
   /* We have real symbol that should be in symbol table.  However try to trim