summaryrefslogtreecommitdiff
path: root/gcc/fortran/decl.c
diff options
context:
space:
mode:
authordomob <domob@138bc75d-0d04-0410-961f-82ee72b054a4>2008-08-31 10:00:30 +0000
committerdomob <domob@138bc75d-0d04-0410-961f-82ee72b054a4>2008-08-31 10:00:30 +0000
commite2f06a481e04a81ec821b7748f44cce0378d631d (patch)
treef1e34fc56018b9fd2a92bf9de5854b3ef33fc9bb /gcc/fortran/decl.c
parentf529eb25672cac0bded2a446786242465fc7f4b5 (diff)
downloadgcc-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.c289
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