gfc_user_op *gfc_get_uop (const char *);
gfc_user_op *gfc_find_uop (const char *, gfc_namespace *);
void gfc_free_symbol (gfc_symbol *&);
-void gfc_release_symbol (gfc_symbol *&);
+bool gfc_release_symbol (gfc_symbol *&);
gfc_symbol *gfc_new_symbol (const char *, gfc_namespace *);
gfc_symtree* gfc_find_symtree_in_proc (const char *, gfc_namespace *);
int gfc_find_symbol (const char *, gfc_namespace *, int, gfc_symbol **);
}
-/* Decrease the reference counter and free memory when we reach zero. */
+/* Decrease the reference counter and free memory when we reach zero.
+ Returns true if the symbol has been freed, false otherwise. */
-void
+bool
gfc_release_symbol (gfc_symbol *&sym)
{
if (sym == NULL)
- return;
+ return false;
if (sym->formal_ns != NULL && sym->refs == 2 && sym->formal_ns != sym->ns
&& (!sym->attr.entry || !sym->module))
sym->refs--;
if (sym->refs > 0)
- return;
+ return false;
gcc_assert (sym->refs == 0);
gfc_free_symbol (sym);
+ return true;
}
}
+/* Remove the reference to the symbol SYM in the symbol tree held by NS
+ and free SYM if the last reference to it has been removed.
+ Returns whether the symbol has been freed. */
+
+static bool
+delete_symbol_from_ns (gfc_symbol *sym, gfc_namespace *ns)
+{
+ if (ns == nullptr)
+ return false;
+
+ /* The derived type is saved in the symtree with the first
+ letter capitalized; the all lower-case version to the
+ derived type contains its associated generic function. */
+ const char *sym_name = gfc_fl_struct (sym->attr.flavor)
+ ? gfc_dt_upper_string (sym->name)
+ : sym->name;
+
+ gfc_delete_symtree (&ns->sym_root, sym_name);
+
+ return gfc_release_symbol (sym);
+}
+
+
/* Undoes all the changes made to symbols since the previous checkpoint.
This subroutine is made simpler due to the fact that attributes are
never removed once added. */
}
if (p->gfc_new)
{
- /* The derived type is saved in the symtree with the first
- letter capitalized; the all lower-case version to the
- derived type contains its associated generic function. */
- if (gfc_fl_struct (p->attr.flavor))
- gfc_delete_symtree (&p->ns->sym_root,gfc_dt_upper_string (p->name));
- else
- gfc_delete_symtree (&p->ns->sym_root, p->name);
-
- gfc_release_symbol (p);
+ bool freed = delete_symbol_from_ns (p, p->ns);
+
+ /* If the symbol is a procedure (function or subroutine), remove
+ it from the procedure body namespace as well as from the outer
+ namespace. */
+ if (!freed
+ && p->formal_ns != p->ns)
+ freed = delete_symbol_from_ns (p, p->formal_ns);
+
+ /* If the formal_ns field has not been set yet, the previous
+ conditional does nothing. In that case, we can assume that
+ gfc_current_ns is the procedure body namespace, and remove the
+ symbol from there. */
+ if (!freed
+ && gfc_current_ns != p->ns
+ && gfc_current_ns != p->formal_ns)
+ freed = delete_symbol_from_ns (p, gfc_current_ns);
}
else
restore_old_symbol (p);