diff options
author | domob <domob@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-08-31 10:00:30 +0000 |
---|---|---|
committer | domob <domob@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-08-31 10:00:30 +0000 |
commit | e2f06a481e04a81ec821b7748f44cce0378d631d (patch) | |
tree | f1e34fc56018b9fd2a92bf9de5854b3ef33fc9bb /gcc/fortran/decl.c | |
parent | f529eb25672cac0bded2a446786242465fc7f4b5 (diff) | |
download | gcc-e2f06a481e04a81ec821b7748f44cce0378d631d.tar.gz |
2008-08-31 Daniel Kraft <d@domob.eu>
* gfortran.h (enum gfc_statement): New entry `ST_GENERIC'.
(struct gfc_tbp_generic): New type.
(struct gfc_typebound_proc): Removed `target' and added union with
`specific' and `generic' members; new members `overridden',
`subroutine', `function' and `is_generic'.
(struct gfc_expr): New members `derived' and `name' in compcall union
member and changed type of `tbp' to gfc_typebound_proc.
(gfc_compare_interfaces), (gfc_compare_actual_formal): Made public.
* match.h (gfc_typebound_default_access): New global.
(gfc_match_generic): New method.
* decl.c (gfc_match_generic): New method.
(match_binding_attributes): New argument `generic' and handle it.
(match_procedure_in_type): Mark matched binding as non-generic.
* interface.c (gfc_compare_interfaces): Made public.
(gfc_compare_actual_formal): Ditto.
(check_interface_1), (compare_parameter): Use new public names.
(gfc_procedure_use), (gfc_search_interface): Ditto.
* match.c (match_typebound_call): Set base-symbol referenced.
* module.c (binding_generic): New global array.
(current_f2k_derived): New global.
(mio_typebound_proc): Handle IO of GENERIC bindings.
(mio_f2k_derived): Record current f2k-namespace in current_f2k_derived.
* parse.c (decode_statement): Handle GENERIC statement.
(gfc_ascii_statement): Ditto.
(typebound_default_access), (set_typebound_default_access): Removed.
(gfc_typebound_default_access): New global.
(parse_derived_contains): New default-access implementation and handle
GENERIC statements encountered.
* primary.c (gfc_match_varspec): Adapted to new gfc_typebound_proc
structure and removed check for SUBROUTINE/FUNCTION from here.
* resolve.c (extract_compcall_passed_object): New method.
(update_compcall_arglist): Use it.
(resolve_typebound_static): Adapted to new gfc_typebound_proc structure.
(resolve_typebound_generic_call): New method.
(resolve_typebound_call): Check target is a SUBROUTINE and handle calls
to GENERIC bindings.
(resolve_compcall): Ditto (check for target being FUNCTION).
(check_typebound_override): Handle GENERIC bindings.
(check_generic_tbp_ambiguity), (resolve_typebound_generic): New methods.
(resolve_typebound_procedure): Handle GENERIC bindings and set new
attributes subroutine, function and overridden in gfc_typebound_proc.
(resolve_fl_derived): Ensure extended type is resolved before the
extending one is.
* st.c (gfc_free_statement): Fix bug with free'ing EXEC_COMPCALL's.
* symbol.c (gfc_find_typebound_proc): Adapt for GENERIC changes.
2008-08-31 Daniel Kraft <d@domob.eu>
* gfortran.dg/typebound_generic_1.f03: New test.
* gfortran.dg/typebound_generic_2.f03: New test.
* gfortran.dg/typebound_generic_3.f03: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@139822 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fortran/decl.c')
-rw-r--r-- | gcc/fortran/decl.c | 289 |
1 files changed, 219 insertions, 70 deletions
diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c index 2b50ea33be8..b3ec1a66e22 100644 --- a/gcc/fortran/decl.c +++ b/gcc/fortran/decl.c @@ -6721,7 +6721,7 @@ cleanup: /* Match binding attributes. */ static match -match_binding_attributes (gfc_typebound_proc* ba) +match_binding_attributes (gfc_typebound_proc* ba, bool generic) { bool found_passing = false; match m; @@ -6736,120 +6736,135 @@ match_binding_attributes (gfc_typebound_proc* ba) /* If we find a comma, we believe there are binding attributes. */ if (gfc_match_char (',') == MATCH_NO) - return MATCH_NO; + { + ba->access = gfc_typebound_default_access; + return MATCH_NO; + } do { - /* NOPASS flag. */ - m = gfc_match (" nopass"); + /* Access specifier. */ + + m = gfc_match (" public"); if (m == MATCH_ERROR) goto error; if (m == MATCH_YES) { - if (found_passing) + if (ba->access != ACCESS_UNKNOWN) { - gfc_error ("Binding attributes already specify passing, illegal" - " NOPASS at %C"); + gfc_error ("Duplicate access-specifier at %C"); goto error; } - found_passing = true; - ba->nopass = 1; + ba->access = ACCESS_PUBLIC; continue; } - /* NON_OVERRIDABLE flag. */ - m = gfc_match (" non_overridable"); + m = gfc_match (" private"); if (m == MATCH_ERROR) goto error; if (m == MATCH_YES) { - if (ba->non_overridable) + if (ba->access != ACCESS_UNKNOWN) { - gfc_error ("Duplicate NON_OVERRIDABLE at %C"); + gfc_error ("Duplicate access-specifier at %C"); goto error; } - ba->non_overridable = 1; + ba->access = ACCESS_PRIVATE; continue; } - /* DEFERRED flag. */ - /* TODO: Handle really once implemented. */ - m = gfc_match (" deferred"); - if (m == MATCH_ERROR) - goto error; - if (m == MATCH_YES) - { - gfc_error ("DEFERRED not yet implemented at %C"); - goto error; - } - - /* PASS possibly including argument. */ - m = gfc_match (" pass"); - if (m == MATCH_ERROR) - goto error; - if (m == MATCH_YES) + /* If inside GENERIC, the following is not allowed. */ + if (!generic) { - char arg[GFC_MAX_SYMBOL_LEN + 1]; - if (found_passing) + /* NOPASS flag. */ + m = gfc_match (" nopass"); + if (m == MATCH_ERROR) + goto error; + if (m == MATCH_YES) { - gfc_error ("Binding attributes already specify passing, illegal" - " PASS at %C"); - goto error; + if (found_passing) + { + gfc_error ("Binding attributes already specify passing," + " illegal NOPASS at %C"); + goto error; + } + + found_passing = true; + ba->nopass = 1; + continue; } - m = gfc_match (" ( %n )", arg); + /* NON_OVERRIDABLE flag. */ + m = gfc_match (" non_overridable"); if (m == MATCH_ERROR) goto error; if (m == MATCH_YES) - ba->pass_arg = xstrdup (arg); - gcc_assert ((m == MATCH_YES) == (ba->pass_arg != NULL)); - - found_passing = true; - ba->nopass = 0; - continue; - } + { + if (ba->non_overridable) + { + gfc_error ("Duplicate NON_OVERRIDABLE at %C"); + goto error; + } - /* Access specifier. */ + ba->non_overridable = 1; + continue; + } - m = gfc_match (" public"); - if (m == MATCH_ERROR) - goto error; - if (m == MATCH_YES) - { - if (ba->access != ACCESS_UNKNOWN) + /* DEFERRED flag. */ + /* TODO: Handle really once implemented. */ + m = gfc_match (" deferred"); + if (m == MATCH_ERROR) + goto error; + if (m == MATCH_YES) { - gfc_error ("Duplicate access-specifier at %C"); + gfc_error ("DEFERRED not yet implemented at %C"); goto error; } - ba->access = ACCESS_PUBLIC; - continue; - } - - m = gfc_match (" private"); - if (m == MATCH_ERROR) - goto error; - if (m == MATCH_YES) - { - if (ba->access != ACCESS_UNKNOWN) + /* PASS possibly including argument. */ + m = gfc_match (" pass"); + if (m == MATCH_ERROR) + goto error; + if (m == MATCH_YES) { - gfc_error ("Duplicate access-specifier at %C"); - goto error; + char arg[GFC_MAX_SYMBOL_LEN + 1]; + + if (found_passing) + { + gfc_error ("Binding attributes already specify passing," + " illegal PASS at %C"); + goto error; + } + + m = gfc_match (" ( %n )", arg); + if (m == MATCH_ERROR) + goto error; + if (m == MATCH_YES) + ba->pass_arg = xstrdup (arg); + gcc_assert ((m == MATCH_YES) == (ba->pass_arg != NULL)); + + found_passing = true; + ba->nopass = 0; + continue; } - ba->access = ACCESS_PRIVATE; - continue; } /* Nothing matching found. */ - gfc_error ("Expected binding attribute at %C"); + if (generic) + gfc_error ("Expected access-specifier at %C"); + else + gfc_error ("Expected binding attribute at %C"); goto error; } while (gfc_match_char (',') == MATCH_YES); + if (ba->access == ACCESS_UNKNOWN) + ba->access = gfc_typebound_default_access; + return MATCH_YES; error: @@ -6890,9 +6905,10 @@ match_procedure_in_type (void) /* Construct the data structure. */ tb = gfc_get_typebound_proc (); tb->where = gfc_current_locus; + tb->is_generic = 0; /* Match binding attributes. */ - m = match_binding_attributes (tb); + m = match_binding_attributes (tb, false); if (m == MATCH_ERROR) return m; seen_attrs = (m == MATCH_YES); @@ -6962,9 +6978,10 @@ match_procedure_in_type (void) gcc_assert (ns); /* See if we already have a binding with this name in the symtree which would - be an error. */ + be an error. If a GENERIC already targetted this binding, it may be + already there but then typebound is still NULL. */ stree = gfc_find_symtree (ns->sym_root, name); - if (stree) + if (stree && stree->typebound) { gfc_error ("There's already a procedure with binding name '%s' for the" " derived type '%s' at %C", name, block->name); @@ -6974,14 +6991,146 @@ match_procedure_in_type (void) /* Insert it and set attributes. */ if (gfc_get_sym_tree (name, ns, &stree)) return MATCH_ERROR; - if (gfc_get_sym_tree (target, gfc_current_ns, &tb->target)) + if (gfc_get_sym_tree (target, gfc_current_ns, &tb->u.specific)) return MATCH_ERROR; + gfc_set_sym_referenced (tb->u.specific->n.sym); stree->typebound = tb; return MATCH_YES; } +/* Match a GENERIC procedure binding inside a derived type. */ + +match +gfc_match_generic (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symbol* block; + gfc_typebound_proc tbattr; /* Used for match_binding_attributes. */ + gfc_typebound_proc* tb; + gfc_symtree* st; + gfc_namespace* ns; + match m; + + /* Check current state. */ + if (gfc_current_state () == COMP_DERIVED) + { + gfc_error ("GENERIC at %C must be inside a derived-type CONTAINS"); + return MATCH_ERROR; + } + if (gfc_current_state () != COMP_DERIVED_CONTAINS) + return MATCH_NO; + block = gfc_state_stack->previous->sym; + ns = block->f2k_derived; + gcc_assert (block && ns); + + /* See if we get an access-specifier. */ + m = match_binding_attributes (&tbattr, true); + if (m == MATCH_ERROR) + goto error; + + /* Now the colons, those are required. */ + if (gfc_match (" ::") != MATCH_YES) + { + gfc_error ("Expected '::' at %C"); + goto error; + } + + /* The binding name and =>. */ + m = gfc_match (" %n =>", name); + if (m == MATCH_ERROR) + return MATCH_ERROR; + if (m == MATCH_NO) + { + gfc_error ("Expected generic name at %C"); + goto error; + } + + /* If there's already something with this name, check that it is another + GENERIC and then extend that rather than build a new node. */ + st = gfc_find_symtree (ns->sym_root, name); + if (st) + { + if (!st->typebound || !st->typebound->is_generic) + { + gfc_error ("There's already a non-generic procedure with binding name" + " '%s' for the derived type '%s' at %C", + name, block->name); + goto error; + } + + tb = st->typebound; + if (tb->access != tbattr.access) + { + gfc_error ("Binding at %C must have the same access as already" + " defined binding '%s'", name); + goto error; + } + } + else + { + if (gfc_get_sym_tree (name, ns, &st)) + return MATCH_ERROR; + + st->typebound = tb = gfc_get_typebound_proc (); + tb->where = gfc_current_locus; + tb->access = tbattr.access; + tb->is_generic = 1; + tb->u.generic = NULL; + } + + /* Now, match all following names as specific targets. */ + do + { + gfc_symtree* target_st; + gfc_tbp_generic* target; + + m = gfc_match_name (name); + if (m == MATCH_ERROR) + goto error; + if (m == MATCH_NO) + { + gfc_error ("Expected specific binding name at %C"); + goto error; + } + + if (gfc_get_sym_tree (name, ns, &target_st)) + goto error; + + /* See if this is a duplicate specification. */ + for (target = tb->u.generic; target; target = target->next) + if (target_st == target->specific_st) + { + gfc_error ("'%s' already defined as specific binding for the" + " generic '%s' at %C", name, st->n.sym->name); + goto error; + } + + gfc_set_sym_referenced (target_st->n.sym); + + target = gfc_get_tbp_generic (); + target->specific_st = target_st; + target->specific = NULL; + target->next = tb->u.generic; + tb->u.generic = target; + } + while (gfc_match (" ,") == MATCH_YES); + + /* Here should be the end. */ + if (gfc_match_eos () != MATCH_YES) + { + gfc_error ("Junk after GENERIC binding at %C"); + goto error; + } + + return MATCH_YES; + +error: + return MATCH_ERROR; +} + + /* Match a FINAL declaration inside a derived type. */ match |