diff options
author | Mikael Morin <mikael@gcc.gnu.org> | 2013-03-03 17:34:42 +0000 |
---|---|---|
committer | Mikael Morin <mikael@gcc.gnu.org> | 2013-03-03 17:34:42 +0000 |
commit | ab68a73ede62fbcbb3abd07879838ebe81fdd484 (patch) | |
tree | b845cd1c7ec2eb129f2b1ede285390fbfc00a15c /gcc/fortran | |
parent | 4ef9b950005a24aab3b0ea7da77f16292ef587b4 (diff) | |
download | gcc-ab68a73ede62fbcbb3abd07879838ebe81fdd484.zip gcc-ab68a73ede62fbcbb3abd07879838ebe81fdd484.tar.gz gcc-ab68a73ede62fbcbb3abd07879838ebe81fdd484.tar.bz2 |
re PR fortran/54730 (ICE in gfc_typenode_for_spec, at fortran/trans-types.c:1066)
fortran/
PR fortran/54730
* gfortran.h (struct gfc_undo_change_set): New field 'previous'.
(gfc_new_undo_checkpoint, gfc_drop_last_undo_checkpoint,
gfc_restore_last_undo_checkpoint): New prototypes.
* symbol.c (default_undo_chgset_var): Update initialization.
(single_undo_checkpoint_p, gfc_new_undo_checkpoint,
free_undo_change_set_data, pop_undo_change_set,
gfc_drop_last_undo_checkpoint, enforce_single_undo_checkpoint):
New functions.
(save_symbol_data): Handle multiple change sets. Make sure old_symbol
field's previous value is not overwritten. Clear gfc_new field.
(restore_old_symbol): Restore previous old_symbol field.
(gfc_restore_last_undo_checkpoint): New function, using body renamed
from gfc_undo_symbols. Restore the previous change set as current one.
(gfc_undo_symbols): New body.
(gfc_commit_symbols, gfc_commit_symbol, gfc_enforce_clean_symbol_state):
Call enforce_single_undo_checkpoint.
(gfc_symbol_done_2): Ditto. Free change set data.
From-SVN: r196414
Diffstat (limited to 'gcc/fortran')
-rw-r--r-- | gcc/fortran/ChangeLog | 21 | ||||
-rw-r--r-- | gcc/fortran/gfortran.h | 4 | ||||
-rw-r--r-- | gcc/fortran/symbol.c | 168 |
3 files changed, 184 insertions, 9 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 49d9bdb..c9b0ca6 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,5 +1,26 @@ 2013-03-03 Mikael Morin <mikael@gcc.gnu.org> + PR fortran/54730 + * gfortran.h (struct gfc_undo_change_set): New field 'previous'. + (gfc_new_undo_checkpoint, gfc_drop_last_undo_checkpoint, + gfc_restore_last_undo_checkpoint): New prototypes. + * symbol.c (default_undo_chgset_var): Update initialization. + (single_undo_checkpoint_p, gfc_new_undo_checkpoint, + free_undo_change_set_data, pop_undo_change_set, + gfc_drop_last_undo_checkpoint, enforce_single_undo_checkpoint): + New functions. + (save_symbol_data): Handle multiple change sets. Make sure old_symbol + field's previous value is not overwritten. Clear gfc_new field. + (restore_old_symbol): Restore previous old_symbol field. + (gfc_restore_last_undo_checkpoint): New function, using body renamed + from gfc_undo_symbols. Restore the previous change set as current one. + (gfc_undo_symbols): New body. + (gfc_commit_symbols, gfc_commit_symbol, gfc_enforce_clean_symbol_state): + Call enforce_single_undo_checkpoint. + (gfc_symbol_done_2): Ditto. Free change set data. + +2013-03-03 Mikael Morin <mikael@gcc.gnu.org> + * symbol.c (restore_old_symbol): Fix thinko. 2013-03-03 Mikael Morin <mikael@gcc.gnu.org> diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index d6176db..18bbf79 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1281,6 +1281,7 @@ struct gfc_undo_change_set { vec<gfc_symbol *> syms; vec<gfc_typebound_proc *> tbps; + gfc_undo_change_set *previous; }; @@ -2641,6 +2642,9 @@ int gfc_get_sym_tree (const char *, gfc_namespace *, gfc_symtree **, bool); int gfc_get_ha_symbol (const char *, gfc_symbol **); int gfc_get_ha_sym_tree (const char *, gfc_symtree **); +void gfc_new_undo_checkpoint (gfc_undo_change_set &); +void gfc_drop_last_undo_checkpoint (void); +void gfc_restore_last_undo_checkpoint (void); void gfc_undo_symbols (void); void gfc_commit_symbols (void); void gfc_commit_symbol (gfc_symbol *); diff --git a/gcc/fortran/symbol.c b/gcc/fortran/symbol.c index 5613086..ef4076d 100644 --- a/gcc/fortran/symbol.c +++ b/gcc/fortran/symbol.c @@ -99,7 +99,7 @@ gfc_gsymbol *gfc_gsym_root = NULL; gfc_dt_list *gfc_derived_types; -static gfc_undo_change_set default_undo_chgset_var = { vNULL, vNULL }; +static gfc_undo_change_set default_undo_chgset_var = { vNULL, vNULL, NULL }; static gfc_undo_change_set *latest_undo_chgset = &default_undo_chgset_var; @@ -2698,17 +2698,49 @@ gfc_find_symbol (const char *name, gfc_namespace *ns, int parent_flag, } +/* Tells whether there is only one set of changes in the stack. */ + +static bool +single_undo_checkpoint_p (void) +{ + if (latest_undo_chgset == &default_undo_chgset_var) + { + gcc_assert (latest_undo_chgset->previous == NULL); + return true; + } + else + { + gcc_assert (latest_undo_chgset->previous != NULL); + return false; + } +} + /* Save symbol with the information necessary to back it out. */ static void save_symbol_data (gfc_symbol *sym) { + gfc_symbol *s; + unsigned i; - if (sym->gfc_new || sym->old_symbol != NULL) + if (!single_undo_checkpoint_p ()) + { + /* If there is more than one change set, look for the symbol in the + current one. If it is found there, we can reuse it. */ + FOR_EACH_VEC_ELT (latest_undo_chgset->syms, i, s) + if (s == sym) + { + gcc_assert (sym->gfc_new || sym->old_symbol != NULL); + return; + } + } + else if (sym->gfc_new || sym->old_symbol != NULL) return; - sym->old_symbol = XCNEW (gfc_symbol); - *(sym->old_symbol) = *sym; + s = XCNEW (gfc_symbol); + *s = *sym; + sym->old_symbol = s; + sym->gfc_new = 0; latest_undo_chgset->syms.safe_push (sym); } @@ -2879,6 +2911,22 @@ find_common_symtree (gfc_symtree *st, gfc_common_head *head) } +/* Clear the given storage, and make it the current change set for registering + changed symbols. Its contents are freed after a call to + gfc_restore_last_undo_checkpoint or gfc_drop_last_undo_checkpoint, but + it is up to the caller to free the storage itself. It is usually a local + variable, so there is nothing to do anyway. */ + +void +gfc_new_undo_checkpoint (gfc_undo_change_set &chg_syms) +{ + chg_syms.syms = vNULL; + chg_syms.tbps = vNULL; + chg_syms.previous = latest_undo_chgset; + latest_undo_chgset = &chg_syms; +} + + /* Restore previous state of symbol. Just copy simple stuff. */ static void @@ -2933,17 +2981,88 @@ restore_old_symbol (gfc_symbol *p) p->formal = old->formal; } - free (p->old_symbol); - p->old_symbol = NULL; + p->old_symbol = old->old_symbol; + free (old); +} + + +/* Frees the internal data of a gfc_undo_change_set structure. Doesn't free + the structure itself. */ + +static void +free_undo_change_set_data (gfc_undo_change_set &cs) +{ + cs.syms.release (); + cs.tbps.release (); +} + + +/* Given a change set pointer, free its target's contents and update it with + the address of the previous change set. Note that only the contents are + freed, not the target itself (the contents' container). It is not a problem + as the latter will be a local variable usually. */ + +static void +pop_undo_change_set (gfc_undo_change_set *&cs) +{ + free_undo_change_set_data (*cs); + cs = cs->previous; +} + + +static void free_old_symbol (gfc_symbol *sym); + + +/* Merges the current change set into the previous one. The changes themselves + are left untouched; only one checkpoint is forgotten. */ + +void +gfc_drop_last_undo_checkpoint (void) +{ + gfc_symbol *s, *t; + unsigned i, j; + + FOR_EACH_VEC_ELT (latest_undo_chgset->syms, i, s) + { + /* No need to loop in this case. */ + if (s->old_symbol == NULL) + continue; + + /* Remove the duplicate symbols. */ + FOR_EACH_VEC_ELT (latest_undo_chgset->previous->syms, j, t) + if (t == s) + { + latest_undo_chgset->previous->syms.unordered_remove (j); + + /* S->OLD_SYMBOL is the backup symbol for S as it was at the + last checkpoint. We drop that checkpoint, so S->OLD_SYMBOL + shall contain from now on the backup symbol for S as it was + at the checkpoint before. */ + if (s->old_symbol->gfc_new) + { + gcc_assert (s->old_symbol->old_symbol == NULL); + s->gfc_new = s->old_symbol->gfc_new; + free_old_symbol (s); + } + else + restore_old_symbol (s->old_symbol); + break; + } + } + + latest_undo_chgset->previous->syms.safe_splice (latest_undo_chgset->syms); + latest_undo_chgset->previous->tbps.safe_splice (latest_undo_chgset->tbps); + + pop_undo_change_set (latest_undo_chgset); } -/* Undoes all the changes made to symbols in the current statement. +/* 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. */ void -gfc_undo_symbols (void) +gfc_restore_last_undo_checkpoint (void) { gfc_symbol *p; unsigned i; @@ -3011,6 +3130,30 @@ gfc_undo_symbols (void) latest_undo_chgset->syms.truncate (0); latest_undo_chgset->tbps.truncate (0); + + if (!single_undo_checkpoint_p ()) + pop_undo_change_set (latest_undo_chgset); +} + + +/* Makes sure that there is only one set of changes; in other words we haven't + forgotten to pair a call to gfc_new_checkpoint with a call to either + gfc_drop_last_undo_checkpoint or gfc_restore_last_undo_checkpoint. */ + +static void +enforce_single_undo_checkpoint (void) +{ + gcc_checking_assert (single_undo_checkpoint_p ()); +} + + +/* Undoes all the changes made to symbols in the current statement. */ + +void +gfc_undo_symbols (void) +{ + enforce_single_undo_checkpoint (); + gfc_restore_last_undo_checkpoint (); } @@ -3051,6 +3194,8 @@ gfc_commit_symbols (void) gfc_typebound_proc *tbp; unsigned i; + enforce_single_undo_checkpoint (); + FOR_EACH_VEC_ELT (latest_undo_chgset->syms, i, p) { p->mark = 0; @@ -3074,6 +3219,8 @@ gfc_commit_symbol (gfc_symbol *sym) gfc_symbol *p; unsigned i; + enforce_single_undo_checkpoint (); + FOR_EACH_VEC_ELT (latest_undo_chgset->syms, i, p) if (p == sym) { @@ -3357,10 +3504,12 @@ gfc_symbol_init_2 (void) void gfc_symbol_done_2 (void) { - gfc_free_namespace (gfc_current_ns); gfc_current_ns = NULL; gfc_free_dt_list (); + + enforce_single_undo_checkpoint (); + free_undo_change_set_data (*latest_undo_chgset); } @@ -3525,6 +3674,7 @@ gfc_save_all (gfc_namespace *ns) void gfc_enforce_clean_symbol_state(void) { + enforce_single_undo_checkpoint (); gcc_assert (latest_undo_chgset->syms.is_empty ()); } |