aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/symbol.c
diff options
context:
space:
mode:
authorMikael Morin <mikael@gcc.gnu.org>2015-10-18 17:17:21 +0000
committerMikael Morin <mikael@gcc.gnu.org>2015-10-18 17:17:21 +0000
commita70ba41f41bca6d1965e617686ab02fc6eb42c5f (patch)
tree825f09b858c7489a7824b502280e56fef764f000 /gcc/fortran/symbol.c
parent45c3fea9baf7690791680ad24eacc01376b6dbd3 (diff)
downloadgcc-a70ba41f41bca6d1965e617686ab02fc6eb42c5f.zip
gcc-a70ba41f41bca6d1965e617686ab02fc6eb42c5f.tar.gz
gcc-a70ba41f41bca6d1965e617686ab02fc6eb42c5f.tar.bz2
Fix common-related error recovery ICE.
Fix an inconsistent state, between the in_common attribute and the common_block pointer. - adding a symbol to a common block list in gfc_match_common is delayed after the call to gfc_add_in_common. - gfc_restore_latest_undo_checkpoint is changed to check the common_block pointer directly instead of the in_common attribute. - gfc_restore_old_symbol is changed to also restore the common-related pointers. This is done using a new function created to factor the related memory management. - In gfc_restore_last_undo_checkpoint, when a symbol has been removed from the common block linked list, its common_next pointer is cleared. PR fortran/67758 gcc/fortran/ * gfortran.h (gfc_symbol): Expand comment. * match.c (gfc_match_common): Delay adding the symbol to the common_block after the gfc_add_in_common call. * symbol.c (gfc_free_symbol): Move common block memory handling... (gfc_set_symbol_common_block): ... here as a new function. (restore_old_symbol): Restore common block fields. (gfc_restore_last_undo_checkpoint): Check the common_block pointer instead of the in_common attribute. When a symbol has been removed from the common block linked list, clear its common_next pointer. gcc/testsuite/ * gfortran.dg/common_25.f90: New file. From-SVN: r228947
Diffstat (limited to 'gcc/fortran/symbol.c')
-rw-r--r--gcc/fortran/symbol.c38
1 files changed, 27 insertions, 11 deletions
diff --git a/gcc/fortran/symbol.c b/gcc/fortran/symbol.c
index 35a3496..a9a0dc0 100644
--- a/gcc/fortran/symbol.c
+++ b/gcc/fortran/symbol.c
@@ -2585,6 +2585,25 @@ gfc_find_uop (const char *name, gfc_namespace *ns)
}
+/* Update a symbol's common_block field, and take care of the associated
+ memory management. */
+
+static void
+set_symbol_common_block (gfc_symbol *sym, gfc_common_head *common_block)
+{
+ if (sym->common_block == common_block)
+ return;
+
+ if (sym->common_block && sym->common_block->name[0] != '\0')
+ {
+ sym->common_block->refs--;
+ if (sym->common_block->refs == 0)
+ free (sym->common_block);
+ }
+ sym->common_block = common_block;
+}
+
+
/* Remove a gfc_symbol structure and everything it points to. */
void
@@ -2612,12 +2631,7 @@ gfc_free_symbol (gfc_symbol *sym)
gfc_free_namespace (sym->f2k_derived);
- if (sym->common_block && sym->common_block->name[0] != '\0')
- {
- sym->common_block->refs--;
- if (sym->common_block->refs == 0)
- free (sym->common_block);
- }
+ set_symbol_common_block (sym, NULL);
free (sym);
}
@@ -3090,6 +3104,9 @@ restore_old_symbol (gfc_symbol *p)
p->formal = old->formal;
}
+ set_symbol_common_block (p, old->common_block);
+ p->common_head = old->common_head;
+
p->old_symbol = old->old_symbol;
free (old);
}
@@ -3178,15 +3195,13 @@ gfc_restore_last_undo_checkpoint (void)
FOR_EACH_VEC_ELT (latest_undo_chgset->syms, i, p)
{
- /* Symbol was new. Or was old and just put in common */
- if ((p->gfc_new
- || (p->attr.in_common && !p->old_symbol->attr.in_common ))
- && p->attr.in_common && p->common_block && p->common_block->head)
+ /* Symbol in a common block was new. Or was old and just put in common */
+ if (p->common_block
+ && (p->gfc_new || !p->old_symbol->common_block))
{
/* If the symbol was added to any common block, it
needs to be removed to stop the resolver looking
for a (possibly) dead symbol. */
-
if (p->common_block->head == p && !p->common_next)
{
gfc_symtree st, *st0;
@@ -3218,6 +3233,7 @@ gfc_restore_last_undo_checkpoint (void)
gcc_assert(cparent->common_next == p);
cparent->common_next = csym->common_next;
}
+ p->common_next = NULL;
}
if (p->gfc_new)
{