re PR fortran/13082 (Function entries and entries with alternate returns not implemented)
authorPaul Brook <paul@codesourcery.com>
Tue, 17 Aug 2004 15:34:12 +0000 (15:34 +0000)
committerPaul Brook <pbrook@gcc.gnu.org>
Tue, 17 Aug 2004 15:34:12 +0000 (15:34 +0000)
2004-08-17  Paul Brook  <paul@codesourcery.com>
Tobias Schlueter  <tobias.schlueter@physik.uni-muenchen.de>

PR fortran/13082
* decl.c (get_proc_name): Update mystery comment.
(gfc_match_entry): Check for errors earlier.  Add entry point to list.
* dump-parse-tree.c (gfc_show_code_node): Print EXEC_ENTRY nodes.
* gfortran.h (symbol_attribute): Add entry_master.  Document entry.
(struct gfc_entry_list): Define.
(gfc_get_entry_list): Define.
(struct gfc_namespace): Add refs and entries.
(enum gfc_exec_op): Add EXEC_ENTRY.
(struct gfc_code): Add ext.entry.
* module.c (ab_attribute, attr_bits): Remove AB_ENTRY.
(mio_symbol_attribute): Don't save/reture addr->entry.
(mio_namespace_ref): Refcount namespaces.
* parse.c (accept_statement): Handle ST_ENTRY.
(gfc_fixup_sibling_symbols): Mark symbol as referenced.
(parse_contained): Fixup sibling references to entry points
after parsing the procedure body.
* resolve.c (resolve_contained_fntype): New function.
(merge_argument_lists, resolve_entries): New functions.
(resolve_contained_functions): Use them.
(resolve_code): Handle EXEC_ENTRY.
(gfc_resolve): Call resolve_entries.
* st.c (gfc_free_statement): Handle EXEC_ENTRY.
* symbol.c (gfc_get_namespace): Refcount namespaces.
(gfc_free_namespace): Ditto.
* trans-array.c (gfc_trans_dummy_array_bias): Treat all args as
optional when multiple entry points are present.
* trans-decl.c (gfc_get_symbol_decl): Remove incorrect check.
(gfc_get_extern_function_decl): Add assertion.  Fix coment.
(create_function_arglist, trans_function_start, build_entry_thunks):
New functions.
(gfc_build_function_decl): Rename ...
(build_function_decl): ... to this.
(gfc_create_function_decl): New function.
(gfc_generate_contained_functions): Use it.
(gfc_trans_entry_master_switch): New function.
(gfc_generate_function_code): Use new functions.
* trans-stmt.c (gfc_trans_entry): New function.
* trans-stmt.h (gfc_trans_entry): Add prototype.
* trans-types.c (gfc_get_function_type): Add entry point argument.
* trans.c (gfc_trans_code): Handle EXEC_ENTRY.
(gfc_generate_module_code): Call gfc_create_function_decl.
* trans.h (gfc_build_function_decl): Remove.
(gfc_create_function_decl): Add prototype.
testsuite/
* gfortran.dg/entry_1.f90: New test.

Co-Authored-By: Tobias Schlüter <tobias.schlueter@physik.uni-muenchen.de>
From-SVN: r86128

18 files changed:
gcc/fortran/ChangeLog
gcc/fortran/decl.c
gcc/fortran/dump-parse-tree.c
gcc/fortran/gfortran.h
gcc/fortran/module.c
gcc/fortran/parse.c
gcc/fortran/resolve.c
gcc/fortran/st.c
gcc/fortran/symbol.c
gcc/fortran/trans-array.c
gcc/fortran/trans-decl.c
gcc/fortran/trans-stmt.c
gcc/fortran/trans-stmt.h
gcc/fortran/trans-types.c
gcc/fortran/trans.c
gcc/fortran/trans.h
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/entry_1.f90 [new file with mode: 0644]

index e0d97f2648c1926dde96ebe7114591514563d8b5..e8af2270fd80ff6eb290a2cff5b4ea1633e7d78c 100644 (file)
@@ -1,3 +1,51 @@
+2004-08-17  Paul Brook  <paul@codesourcery.com>
+       Tobias Schlueter  <tobias.schlueter@physik.uni-muenchen.de>
+
+       PR fortran/13082
+       * decl.c (get_proc_name): Update mystery comment.
+       (gfc_match_entry): Check for errors earlier.  Add entry point to list.
+       * dump-parse-tree.c (gfc_show_code_node): Print EXEC_ENTRY nodes.
+       * gfortran.h (symbol_attribute): Add entry_master.  Document entry.
+       (struct gfc_entry_list): Define.
+       (gfc_get_entry_list): Define.
+       (struct gfc_namespace): Add refs and entries.
+       (enum gfc_exec_op): Add EXEC_ENTRY.
+       (struct gfc_code): Add ext.entry.
+       * module.c (ab_attribute, attr_bits): Remove AB_ENTRY.
+       (mio_symbol_attribute): Don't save/reture addr->entry.
+       (mio_namespace_ref): Refcount namespaces.
+       * parse.c (accept_statement): Handle ST_ENTRY.
+       (gfc_fixup_sibling_symbols): Mark symbol as referenced.
+       (parse_contained): Fixup sibling references to entry points
+       after parsing the procedure body.
+       * resolve.c (resolve_contained_fntype): New function.
+       (merge_argument_lists, resolve_entries): New functions.
+       (resolve_contained_functions): Use them.
+       (resolve_code): Handle EXEC_ENTRY.
+       (gfc_resolve): Call resolve_entries.
+       * st.c (gfc_free_statement): Handle EXEC_ENTRY.
+       * symbol.c (gfc_get_namespace): Refcount namespaces.
+       (gfc_free_namespace): Ditto.
+       * trans-array.c (gfc_trans_dummy_array_bias): Treat all args as
+       optional when multiple entry points are present.
+       * trans-decl.c (gfc_get_symbol_decl): Remove incorrect check.
+       (gfc_get_extern_function_decl): Add assertion.  Fix coment.
+       (create_function_arglist, trans_function_start, build_entry_thunks):
+       New functions.
+       (gfc_build_function_decl): Rename ...
+       (build_function_decl): ... to this.
+       (gfc_create_function_decl): New function.
+       (gfc_generate_contained_functions): Use it.
+       (gfc_trans_entry_master_switch): New function.
+       (gfc_generate_function_code): Use new functions.
+       * trans-stmt.c (gfc_trans_entry): New function.
+       * trans-stmt.h (gfc_trans_entry): Add prototype.
+       * trans-types.c (gfc_get_function_type): Add entry point argument.
+       * trans.c (gfc_trans_code): Handle EXEC_ENTRY.
+       (gfc_generate_module_code): Call gfc_create_function_decl.
+       * trans.h (gfc_build_function_decl): Remove.
+       (gfc_create_function_decl): Add prototype.
+
 2004-08-15  Andrew Pinski  <apinski@apple.com>
 
        PR fortran/17030
index 3a78efc65609cbcac7a80f5e914b9ee30d5f09dd..e00a614cd0694e834628226b80892d0d73ebbeda 100644 (file)
@@ -186,7 +186,7 @@ get_proc_name (const char *name, gfc_symbol ** result)
   if (*result == NULL)
     return rc;
 
-  /* Deal with ENTRY problem */
+  /* ??? Deal with ENTRY problem */
 
   st = gfc_new_symtree (&gfc_current_ns->sym_root, name);
 
@@ -1871,44 +1871,59 @@ cleanup:
 match
 gfc_match_entry (void)
 {
-  gfc_symbol *function, *result, *entry;
+  gfc_symbol *proc;
+  gfc_symbol *result;
+  gfc_symbol *entry;
   char name[GFC_MAX_SYMBOL_LEN + 1];
   gfc_compile_state state;
   match m;
+  gfc_entry_list *el;
 
   m = gfc_match_name (name);
   if (m != MATCH_YES)
     return m;
 
+  state = gfc_current_state ();
+  if (state != COMP_SUBROUTINE
+      && state != COMP_FUNCTION)
+    {
+      gfc_error ("ENTRY statement at %C cannot appear within %s",
+                gfc_state_name (gfc_current_state ()));
+      return MATCH_ERROR;
+    }
+
+  if (gfc_current_ns->parent != NULL
+      && gfc_current_ns->parent->proc_name
+      && gfc_current_ns->parent->proc_name->attr.flavor != FL_MODULE)
+    {
+      gfc_error("ENTRY statement at %C cannot appear in a "
+               "contained procedure");
+      return MATCH_ERROR;
+    }
+
   if (get_proc_name (name, &entry))
     return MATCH_ERROR;
 
-  gfc_enclosing_unit (&state);
-  switch (state)
+  proc = gfc_current_block ();
+
+  if (state == COMP_SUBROUTINE)
     {
-    case COMP_SUBROUTINE:
+      /* And entry in a subroutine.  */
       m = gfc_match_formal_arglist (entry, 0, 1);
       if (m != MATCH_YES)
        return MATCH_ERROR;
 
-      if (gfc_current_state () != COMP_SUBROUTINE)
-       goto exec_construct;
-
       if (gfc_add_entry (&entry->attr, NULL) == FAILURE
          || gfc_add_subroutine (&entry->attr, NULL) == FAILURE)
        return MATCH_ERROR;
-
-      break;
-
-    case COMP_FUNCTION:
+    }
+  else
+    {
+      /* An entry in a function.  */
       m = gfc_match_formal_arglist (entry, 0, 0);
       if (m != MATCH_YES)
        return MATCH_ERROR;
 
-      if (gfc_current_state () != COMP_FUNCTION)
-       goto exec_construct;
-      function = gfc_state_stack->sym;
-
       result = NULL;
 
       if (gfc_match_eos () == MATCH_YES)
@@ -1917,12 +1932,12 @@ gfc_match_entry (void)
              || gfc_add_function (&entry->attr, NULL) == FAILURE)
            return MATCH_ERROR;
 
-         entry->result = function->result;
+         entry->result = proc->result;
 
        }
       else
        {
-         m = match_result (function, &result);
+         m = match_result (proc, &result);
          if (m == MATCH_NO)
            gfc_syntax_error (ST_ENTRY);
          if (m != MATCH_YES)
@@ -1934,16 +1949,11 @@ gfc_match_entry (void)
            return MATCH_ERROR;
        }
 
-      if (function->attr.recursive && result == NULL)
+      if (proc->attr.recursive && result == NULL)
        {
          gfc_error ("RESULT attribute required in ENTRY statement at %C");
          return MATCH_ERROR;
        }
-
-      break;
-
-    default:
-      goto exec_construct;
     }
 
   if (gfc_match_eos () != MATCH_YES)
@@ -1952,13 +1962,23 @@ gfc_match_entry (void)
       return MATCH_ERROR;
     }
 
-  return MATCH_YES;
+  entry->attr.recursive = proc->attr.recursive;
+  entry->attr.elemental = proc->attr.elemental;
+  entry->attr.pure = proc->attr.pure;
 
-exec_construct:
-  gfc_error ("ENTRY statement at %C cannot appear within %s",
-            gfc_state_name (gfc_current_state ()));
+  el = gfc_get_entry_list ();
+  el->sym = entry;
+  el->next = gfc_current_ns->entries;
+  gfc_current_ns->entries = el;
+  if (el->next)
+    el->id = el->next->id + 1;
+  else
+    el->id = 1;
 
-  return MATCH_ERROR;
+  new_st.op = EXEC_ENTRY;
+  new_st.ext.entry = el;
+
+  return MATCH_YES;
 }
 
 
index 1c948d94253feecba58f361c4079226f313f3215..e5e56db3fce5c4a9b724a77e4bb7db3f195df4b0 100644 (file)
@@ -800,12 +800,17 @@ gfc_show_code_node (int level, gfc_code * c)
       gfc_status ("CONTINUE");
       break;
 
+    case EXEC_ENTRY:
+      gfc_status ("ENTRY %s", c->ext.entry->sym->name);
+      break;
+
     case EXEC_ASSIGN:
       gfc_status ("ASSIGN ");
       gfc_show_expr (c->expr);
       gfc_status_char (' ');
       gfc_show_expr (c->expr2);
       break;
+
     case EXEC_LABEL_ASSIGN:
       gfc_status ("LABEL ASSIGN ");
       gfc_show_expr (c->expr);
index 80cdbbe9163f7375742bd545c5e943e2b6e93cae..45851610e38d476d8bae67b52467f7e9d1994555 100644 (file)
@@ -386,7 +386,7 @@ typedef struct
   /* Variable attributes.  */
   unsigned allocatable:1, dimension:1, external:1, intrinsic:1,
     optional:1, pointer:1, save:1, target:1,
-    dummy:1, result:1, entry:1, assign:1;
+    dummy:1, result:1, assign:1;
 
   unsigned data:1,             /* Symbol is named in a DATA statement.  */
     use_assoc:1;               /* Symbol has been use-associated.  */
@@ -399,6 +399,14 @@ typedef struct
   unsigned sequence:1, elemental:1, pure:1, recursive:1;
   unsigned unmaskable:1, masked:1, contained:1;
 
+  /* Set if this procedure is an alternate entry point.  These procedures
+     don't have any code associated, and the backend will turn them into
+     thunks to the master function.  */
+  unsigned entry:1;
+  /* Set if this is the master function for a procedure with multiple
+     entry points.  */
+  unsigned entry_master:1;
+
   /* Set if a function must always be referenced by an explicit interface.  */
   unsigned always_explicit:1;
 
@@ -668,7 +676,6 @@ typedef struct gfc_symbol
   struct gfc_namespace *ns;    /* namespace containing this symbol */
 
   tree backend_decl;
-
 }
 gfc_symbol;
 
@@ -687,6 +694,23 @@ gfc_common_head;
 #define gfc_get_common_head() gfc_getmem(sizeof(gfc_common_head))
 
 
+/* A list of all the alternate entry points for a procedure.  */
+
+typedef struct gfc_entry_list
+{
+  /* The symbol for this entry point.  */
+  gfc_symbol *sym;
+  /* The zero-based id of this entry point.  */
+  int id;
+  /* The LABEL_EXPR marking this entry point.  */
+  tree label;
+  /* The nest item in the list.  */
+  struct gfc_entry_list *next;
+}
+gfc_entry_list;
+
+#define gfc_get_entry_list() \
+  (gfc_entry_list *) gfc_getmem(sizeof(gfc_entry_list))
 
 /* Within a namespace, symbols are pointed to by symtree nodes that
    are linked together in a balanced binary tree.  There can be
@@ -712,6 +736,10 @@ typedef struct gfc_symtree
 gfc_symtree;
 
 
+/* A namespace describes the contents of procedure, module or
+   interface block.  */
+/* ??? Anything else use these?  */
+
 typedef struct gfc_namespace
 {
   /* Tree containing all the symbols in this namespace.  */
@@ -755,6 +783,14 @@ typedef struct gfc_namespace
   gfc_charlen *cl_list;
 
   int save_all, seen_save;
+
+  /* Normally we don't need to refcount namespaces.  However when we read
+     a module containing a function with multiple entry points, this
+     will appear as several functions with the same formal namespace.  */
+  int refs;
+
+  /* A list of all alternate entry points to this procedure (or NULL).  */
+  gfc_entry_list *entries;
 }
 gfc_namespace;
 
@@ -1204,7 +1240,8 @@ gfc_forall_iterator;
 typedef enum
 {
   EXEC_NOP = 1, EXEC_ASSIGN, EXEC_LABEL_ASSIGN, EXEC_POINTER_ASSIGN,
-  EXEC_GOTO, EXEC_CALL, EXEC_RETURN, EXEC_PAUSE, EXEC_STOP, EXEC_CONTINUE,
+  EXEC_GOTO, EXEC_CALL, EXEC_RETURN, EXEC_ENTRY,
+  EXEC_PAUSE, EXEC_STOP, EXEC_CONTINUE,
   EXEC_IF, EXEC_ARITHMETIC_IF, EXEC_DO, EXEC_DO_WHILE, EXEC_SELECT,
   EXEC_FORALL, EXEC_WHERE, EXEC_CYCLE, EXEC_EXIT,
   EXEC_ALLOCATE, EXEC_DEALLOCATE,
@@ -1243,6 +1280,7 @@ typedef struct gfc_code
     gfc_forall_iterator *forall_iterator;
     struct gfc_code *whichloop;
     int stop_code;
+    gfc_entry_list *entry;
   }
   ext;         /* Points to additional structures required by statement */
 
index a9d0fa66c02e0f9eee7d8b6355794f63ef58a38b..cd41e6640f27b3ec8f6fa1fdce37e3f009d84551 100644 (file)
@@ -1367,7 +1367,7 @@ mio_internal_string (char *string)
 typedef enum
 { AB_ALLOCATABLE, AB_DIMENSION, AB_EXTERNAL, AB_INTRINSIC, AB_OPTIONAL,
   AB_POINTER, AB_SAVE, AB_TARGET, AB_DUMMY, AB_RESULT,
-  AB_ENTRY, AB_DATA, AB_IN_NAMELIST, AB_IN_COMMON, 
+  AB_DATA, AB_IN_NAMELIST, AB_IN_COMMON, 
   AB_FUNCTION, AB_SUBROUTINE, AB_SEQUENCE, AB_ELEMENTAL, AB_PURE,
   AB_RECURSIVE, AB_GENERIC, AB_ALWAYS_EXPLICIT
 }
@@ -1385,7 +1385,6 @@ static const mstring attr_bits[] =
     minit ("TARGET", AB_TARGET),
     minit ("DUMMY", AB_DUMMY),
     minit ("RESULT", AB_RESULT),
-    minit ("ENTRY", AB_ENTRY),
     minit ("DATA", AB_DATA),
     minit ("IN_NAMELIST", AB_IN_NAMELIST),
     minit ("IN_COMMON", AB_IN_COMMON),
@@ -1455,8 +1454,7 @@ mio_symbol_attribute (symbol_attribute * attr)
        MIO_NAME(ab_attribute) (AB_DUMMY, attr_bits);
       if (attr->result)
        MIO_NAME(ab_attribute) (AB_RESULT, attr_bits);
-      if (attr->entry)
-       MIO_NAME(ab_attribute) (AB_ENTRY, attr_bits);
+      /* We deliberately don't preserve the "entry" flag.  */
 
       if (attr->data)
        MIO_NAME(ab_attribute) (AB_DATA, attr_bits);
@@ -1529,9 +1527,6 @@ mio_symbol_attribute (symbol_attribute * attr)
            case AB_RESULT:
              attr->result = 1;
              break;
-           case AB_ENTRY:
-             attr->entry = 1;
-             break;
            case AB_DATA:
              attr->data = 1;
              break;
@@ -2628,10 +2623,16 @@ mio_namespace_ref (gfc_namespace ** nsp)
   if (p->type == P_UNKNOWN)
     p->type = P_NAMESPACE;
 
-  if (iomode == IO_INPUT && p->integer != 0 && p->u.pointer == NULL)
+  if (iomode == IO_INPUT && p->integer != 0)
     {
-      ns = gfc_get_namespace (NULL);
-      associate_integer_pointer (p, ns);
+      ns = (gfc_namespace *)p->u.pointer;
+      if (ns == NULL)
+       {
+         ns = gfc_get_namespace (NULL);
+         associate_integer_pointer (p, ns);
+       }
+      else
+       ns->refs++;
     }
 }
 
index bd74139623d629c896d85d550132822a91a0514c..abc3c290d75092da319d6c49870171c7b362d530 100644 (file)
@@ -1076,6 +1076,7 @@ accept_statement (gfc_statement st)
 
       break;
 
+    case ST_ENTRY:
     case_executable:
     case_exec_markers:
       add_statement ();
@@ -2140,6 +2141,7 @@ gfc_fixup_sibling_symbols (gfc_symbol * sym, gfc_namespace * siblings)
   gfc_symtree *st;
   gfc_symbol *old_sym;
 
+  sym->attr.referenced = 1;
   for (ns = siblings; ns; ns = ns->sibling)
     {
       gfc_find_sym_tree (sym->name, ns, 0, &st);
@@ -2174,6 +2176,7 @@ parse_contained (int module)
   gfc_state_data s1, s2;
   gfc_statement st;
   gfc_symbol *sym;
+  gfc_entry_list *el;
 
   push_state (&s1, COMP_CONTAINS, NULL);
   parent_ns = gfc_current_ns;
@@ -2234,10 +2237,13 @@ parse_contained (int module)
           sym->attr.contained = 1;
          sym->attr.referenced = 1;
 
+         parse_progunit (ST_NONE);
+
           /* Fix up any sibling functions that refer to this one.  */
           gfc_fixup_sibling_symbols (sym, gfc_current_ns);
-
-         parse_progunit (ST_NONE);
+         /* Or refer to any of its alternate entry points.  */
+         for (el = gfc_current_ns->entries; el; el = el->next)
+           gfc_fixup_sibling_symbols (el->sym, gfc_current_ns);
 
          gfc_current_ns->code = s2.head;
          gfc_current_ns = parent_ns;
index 00d9e3daa6347c79c1ad927b66b672dba48d0fc1..1dc4db8a35d7b4e480c2e866b41519854160f8d8 100644 (file)
@@ -247,6 +247,162 @@ resolve_formal_arglists (gfc_namespace * ns)
 }
 
 
+static void
+resolve_contained_fntype (gfc_symbol * sym, gfc_namespace * ns)
+{
+  try t;
+  
+  /* If this namespace is not a function, ignore it.  */
+  if (! sym
+      || !(sym->attr.function
+          || sym->attr.flavor == FL_VARIABLE))
+    return;
+
+  /* Try to find out of what type the function is.  If there was an
+     explicit RESULT clause, try to get the type from it.  If the
+     function is never defined, set it to the implicit type.  If
+     even that fails, give up.  */
+  if (sym->result != NULL)
+    sym = sym->result;
+
+  if (sym->ts.type == BT_UNKNOWN)
+    {
+      /* Assume we can find an implicit type.  */
+      t = SUCCESS;
+
+      if (sym->result == NULL)
+       t = gfc_set_default_type (sym, 0, ns);
+      else
+       {
+         if (sym->result->ts.type == BT_UNKNOWN)
+           t = gfc_set_default_type (sym->result, 0, NULL);
+
+         sym->ts = sym->result->ts;
+       }
+
+      if (t == FAILURE)
+       gfc_error ("Contained function '%s' at %L has no IMPLICIT type",
+                   sym->name, &sym->declared_at); /* FIXME */
+    }
+}
+
+
+/* Add NEW_ARGS to the formal argument list of PROC, taking care not to
+   introduce duplicates.   */
+
+static void
+merge_argument_lists (gfc_symbol *proc, gfc_formal_arglist *new_args)
+{
+  gfc_formal_arglist *f, *new_arglist;
+  gfc_symbol *new_sym;
+
+  for (; new_args != NULL; new_args = new_args->next)
+    {
+      new_sym = new_args->sym;
+      /* See if ths arg is already in the formal argument list.  */
+      for (f = proc->formal; f; f = f->next)
+       {
+         if (new_sym == f->sym)
+           break;
+       }
+
+      if (f)
+       continue;
+
+      /* Add a new argument.  Argument order is not important.  */
+      new_arglist = gfc_get_formal_arglist ();
+      new_arglist->sym = new_sym;
+      new_arglist->next = proc->formal;
+      proc->formal  = new_arglist;
+    }
+}
+
+
+/* Resolve alternate entry points.  If a symbol has multiple entry points we
+   create a new master symbol for the main routine, and turn the existing
+   symbol into an entry point.  */
+
+static void
+resolve_entries (gfc_namespace * ns)
+{
+  gfc_namespace *old_ns;
+  gfc_code *c;
+  gfc_symbol *proc;
+  gfc_entry_list *el;
+  char name[GFC_MAX_SYMBOL_LEN + 1];
+  static int master_count = 0;
+
+  if (ns->proc_name == NULL)
+    return;
+
+  /* No need to do anything if this procedure doesn't have alternate entry
+     points.  */
+  if (!ns->entries)
+    return;
+
+  /* We may already have resolved alternate entry points.  */
+  if (ns->proc_name->attr.entry_master)
+    return;
+
+  /* If this isn't a procedure something as gone horribly wrong.   */
+  assert (ns->proc_name->attr.flavor == FL_PROCEDURE);
+  
+  /* Remember the current namespace.  */
+  old_ns = gfc_current_ns;
+
+  gfc_current_ns = ns;
+
+  /* Add the main entry point to the list of entry points.  */
+  el = gfc_get_entry_list ();
+  el->sym = ns->proc_name;
+  el->id = 0;
+  el->next = ns->entries;
+  ns->entries = el;
+  ns->proc_name->attr.entry = 1;
+
+  /* Add an entry statement for it.  */
+  c = gfc_get_code ();
+  c->op = EXEC_ENTRY;
+  c->ext.entry = el;
+  c->next = ns->code;
+  ns->code = c;
+
+  /* Create a new symbol for the master function.  */
+  /* Give the internal function a unique name (within this file).
+     Also include teh function name so the user has some hope of figuring
+     out whats going on.  */
+  snprintf (name, GFC_MAX_SYMBOL_LEN, "master.%d.%s",
+           master_count++, ns->proc_name->name);
+  name[GFC_MAX_SYMBOL_LEN] = '\0';
+  gfc_get_ha_symbol (name, &proc);
+  assert (proc != NULL);
+
+  gfc_add_procedure (&proc->attr, PROC_INTERNAL, NULL);
+  if (ns->proc_name->attr.subroutine)
+    gfc_add_subroutine (&proc->attr, NULL);
+  else
+    {
+      gfc_add_function (&proc->attr, NULL);
+      gfc_internal_error ("TODO: Functions with alternate entry points");
+    }
+  proc->attr.access = ACCESS_PRIVATE;
+  proc->attr.entry_master = 1;
+
+  /* Merge all the entry point arguments.  */
+  for (el = ns->entries; el; el = el->next)
+    merge_argument_lists (proc, el->sym->formal);
+
+  /* And use it for the function body.  */
+  ns->proc_name = proc;
+
+  /* FInalize the new symbols.  */
+  gfc_commit_symbols ();
+
+  /* Restore the original namespace.  */
+  gfc_current_ns = old_ns;
+}
+
+
 /* Resolve contained function types.  Because contained functions can call one
    another, they have to be worked out before any of the contained procedures
    can be resolved.
@@ -259,65 +415,20 @@ resolve_formal_arglists (gfc_namespace * ns)
 static void
 resolve_contained_functions (gfc_namespace * ns)
 {
-  gfc_symbol *contained_sym, *sym_lower;
   gfc_namespace *child;
-  try t;
+  gfc_entry_list *el;
 
   resolve_formal_arglists (ns);
 
   for (child = ns->contained; child; child = child->sibling)
     {
-      sym_lower = child->proc_name;
-
-      /* If this namespace is not a function, ignore it.  */
-      if (! sym_lower
-         || !( sym_lower->attr.function
-               || sym_lower->attr.flavor == FL_VARIABLE))
-       continue;
-
-      /* Find the contained symbol in the current namespace.  */
-      gfc_find_symbol (sym_lower->name, ns, 0, &contained_sym);
-
-      if (contained_sym == NULL)
-       gfc_internal_error ("resolve_contained_functions(): Contained "
-                           "function not found in parent namespace");
-
-      /* Try to find out of what type the function is.  If there was an
-        explicit RESULT clause, try to get the type from it.  If the
-        function is never defined, set it to the implicit type.  If
-        even that fails, give up.  */
-      if (sym_lower->result != NULL)
-       sym_lower = sym_lower->result;
-
-      if (sym_lower->ts.type == BT_UNKNOWN)
-       {
-         /* Assume we can find an implicit type.  */
-         t = SUCCESS;
-
-         if (sym_lower->result == NULL)
-           t = gfc_set_default_type (sym_lower, 0, child);
-         else
-           {
-             if (sym_lower->result->ts.type == BT_UNKNOWN)
-               t = gfc_set_default_type (sym_lower->result, 0, NULL);
-
-             sym_lower->ts = sym_lower->result->ts;
-           }
-
-         if (t == FAILURE)
-           gfc_error ("Contained function '%s' at %L has no IMPLICIT type",
-                       sym_lower->name, &sym_lower->declared_at); /* FIXME */
-       }
+      /* Resolve alternate entry points first.  */
+      resolve_entries (child); 
 
-      /* If the symbol in the parent of the contained namespace is not
-        the same as the one in contained namespace itself, copy over
-        the type information.  */
-      /* ??? Shouldn't we replace the symbol with the parent symbol instead?  */
-      if (contained_sym != sym_lower)
-       {
-         contained_sym->ts = sym_lower->ts;
-         contained_sym->as = gfc_copy_array_spec (sym_lower->as);
-       }
+      /* Then check function return types.  */
+      resolve_contained_fntype (child->proc_name, child);
+      for (el = child->entries; el; el = el->next)
+       resolve_contained_fntype (el->sym, child);
     }
 }
 
@@ -3458,6 +3569,7 @@ resolve_code (gfc_code * code, gfc_namespace * ns)
        case EXEC_CONTINUE:
        case EXEC_DT_END:
        case EXEC_TRANSFER:
+       case EXEC_ENTRY:
          break;
 
        case EXEC_WHERE:
@@ -4440,6 +4552,8 @@ gfc_resolve (gfc_namespace * ns)
   old_ns = gfc_current_ns;
   gfc_current_ns = ns;
 
+  resolve_entries (ns);
+
   resolve_contained_functions (ns);
 
   gfc_traverse_ns (ns, resolve_symbol);
index 743769c2c9781df0657ea904df9e5984fada0830..f3e3671cac844d74e600484d8de06f987ec88254 100644 (file)
@@ -106,7 +106,7 @@ gfc_free_statement (gfc_code * p)
     case EXEC_CONTINUE:
     case EXEC_TRANSFER:
     case EXEC_LABEL_ASSIGN:
-
+    case EXEC_ENTRY:
     case EXEC_ARITHMETIC_IF:
       break;
 
index 4b6c6e416dcb8eb860dfedb0b4eda7dea9cfed73..c12586557746750d3407102bac27bf49743b397c 100644 (file)
@@ -25,6 +25,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <assert.h>
 
 #include "gfortran.h"
 #include "parse.h"
@@ -1614,6 +1615,8 @@ gfc_get_namespace (gfc_namespace * parent)
        }
     }
 
+  ns->refs = 1;
+
   return ns;
 }
 
@@ -2228,6 +2231,11 @@ gfc_free_namespace (gfc_namespace * ns)
   if (ns == NULL)
     return;
 
+  ns->refs--;
+  if (ns->refs > 0)
+    return;
+  assert (ns->refs == 0);
+
   gfc_free_statements (ns->code);
 
   free_sym_tree (ns->sym_root);
index a6dea46b9c0d6afa72bb2963e646b83069726712..3abb1959ebe1760db6a4d494d0f2fac9165919c8 100644 (file)
@@ -3074,6 +3074,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, tree body)
   int n;
   int checkparm;
   int no_repack;
+  bool optional_arg;
 
   /* Do nothing for pointer and allocatable arrays.  */
   if (sym->attr.pointer || sym->attr.allocatable)
@@ -3281,7 +3282,8 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, tree body)
 
   /* Only do the entry/initialization code if the arg is present.  */
   dumdesc = GFC_DECL_SAVED_DESCRIPTOR (tmpdesc);
-  if (sym->attr.optional)
+  optional_arg = sym->attr.optional || sym->ns->proc_name->attr.entry_master;
+  if (optional_arg)
     {
       tmp = gfc_conv_expr_present (sym);
       stmt = build_v (COND_EXPR, tmp, stmt, build_empty_stmt ());
@@ -3318,7 +3320,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, tree body)
       tmp = build (NE_EXPR, boolean_type_node, tmp, tmpdesc);
       stmt = build_v (COND_EXPR, tmp, stmt, build_empty_stmt ());
 
-      if (sym->attr.optional)
+      if (optional_arg)
         {
           tmp = gfc_conv_expr_present (sym);
           stmt = build_v (COND_EXPR, tmp, stmt, build_empty_stmt ());
index d9476b8220135cf51e5182ef8b301592f58d80c3..9dfcc186f0ff90adf0e95b26bac458d937c5313c 100644 (file)
@@ -740,9 +740,6 @@ gfc_get_symbol_decl (gfc_symbol * sym)
   if (sym->backend_decl)
     return sym->backend_decl;
 
-  if (sym->attr.entry)
-    gfc_todo_error ("alternate entry");
-
   /* Catch function declarations.  Only used for actual parameters.  */
   if (sym->attr.flavor == FL_PROCEDURE)
     {
@@ -876,6 +873,11 @@ gfc_get_extern_function_decl (gfc_symbol * sym)
   if (sym->backend_decl)
     return sym->backend_decl;
 
+  /* We should never be creating external decls for alternate entry points.
+     The procedure may be an alternate entry point, but we don't want/need
+     to know that.  */
+  assert (!(sym->attr.entry || sym->attr.entry_master));
+
   if (sym->attr.intrinsic)
     {
       /* Call the resolution function to get the actual name.  This is
@@ -949,7 +951,7 @@ gfc_get_extern_function_decl (gfc_symbol * sym)
       /* TODO: check if pure SUBROUTINEs don't have INTENT(OUT)
         parameters and don't use alternate returns (is this
         allowed?). In that case, calls to them are meaningless, and
-        can be optimized away. See also in gfc_build_function_decl().  */
+        can be optimized away. See also in build_function_decl().  */
       TREE_SIDE_EFFECTS (fndecl) = 0;
     }
 
@@ -963,16 +965,16 @@ gfc_get_extern_function_decl (gfc_symbol * sym)
 
 
 /* Create a declaration for a procedure.  For external functions (in the C
-   sense) use gfc_get_extern_function_decl.  */
+   sense) use gfc_get_extern_function_decl.  HAS_ENTRIES is true if this is
+   a master function with alternate entry points.  */
 
-void
-gfc_build_function_decl (gfc_symbol * sym)
+static void
+build_function_decl (gfc_symbol * sym)
 {
-  tree fndecl, type, result_decl, typelist, arglist;
-  tree length;
+  tree fndecl, type;
   symbol_attribute attr;
+  tree result_decl;
   gfc_formal_arglist *f;
-  tree parm;
 
   assert (!sym->backend_decl);
   assert (!sym->attr.external);
@@ -1048,7 +1050,8 @@ gfc_build_function_decl (gfc_symbol * sym)
 
   /* This specifies if a function is globaly visible, ie. it is
      the opposite of declaring static in C.  */
-  if (DECL_CONTEXT (fndecl) == NULL_TREE)
+  if (DECL_CONTEXT (fndecl) == NULL_TREE
+      && !sym->attr.entry_master)
     TREE_PUBLIC (fndecl) = 1;
 
   /* TREE_STATIC means the function body is defined here.  */
@@ -1070,11 +1073,45 @@ gfc_build_function_decl (gfc_symbol * sym)
   /* Layout the function declaration and put it in the binding level
      of the current function.  */
   pushdecl (fndecl);
+
+  sym->backend_decl = fndecl;
+}
+
+
+/* Create the DECL_ARGUMENTS for a procedure.  */
+
+static void
+create_function_arglist (gfc_symbol * sym)
+{
+  tree fndecl;
+  gfc_formal_arglist *f;
+  tree typelist;
+  tree arglist;
+  tree length;
+  tree type;
+  tree parm;
+
+  fndecl = sym->backend_decl;
+
   /* Build formal argument list. Make sure that their TREE_CONTEXT is
      the new FUNCTION_DECL node.  */
-  current_function_decl = fndecl;
   arglist = NULL_TREE;
   typelist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+
+  if (sym->attr.entry_master)
+    {
+      type = TREE_VALUE (typelist);
+      parm = build_decl (PARM_DECL, get_identifier ("__entry"), type);
+      
+      DECL_CONTEXT (parm) = fndecl;
+      DECL_ARG_TYPE (parm) = type;
+      TREE_READONLY (parm) = 1;
+      gfc_finish_decl (parm, NULL_TREE);
+
+      arglist = chainon (arglist, parm);
+      typelist = TREE_CHAIN (typelist);
+    }
+
   if (gfc_return_by_reference (sym))
     {
       type = TREE_VALUE (typelist);
@@ -1201,14 +1238,224 @@ gfc_build_function_decl (gfc_symbol * sym)
 
   assert (TREE_VALUE (typelist) == void_type_node);
   DECL_ARGUMENTS (fndecl) = arglist;
+}
 
-  /* Restore the old context.  */
-  current_function_decl = DECL_CONTEXT (fndecl);
 
-  sym->backend_decl = fndecl;
+/* Finalize DECL and all nested functions with cgraph.  */
+
+static void
+gfc_finalize (tree decl)
+{
+  struct cgraph_node *cgn;
+
+  cgn = cgraph_node (decl);
+  for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
+    gfc_finalize (cgn->decl);
+
+  cgraph_finalize_function (decl, false);
 }
 
 
+/* Convert FNDECL's code to GIMPLE and handle any nested functions.  */
+
+static void
+gfc_gimplify_function (tree fndecl)
+{
+  struct cgraph_node *cgn;
+
+  gimplify_function_tree (fndecl);
+  dump_function (TDI_generic, fndecl);
+
+  /* Convert all nested functions to GIMPLE now.  We do things in this order
+     so that items like VLA sizes are expanded properly in the context of the
+     correct function.  */
+  cgn = cgraph_node (fndecl);
+  for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+    gfc_gimplify_function (cgn->decl);
+}
+
+
+/* Do the setup necessary before generating the body of a function.  */
+
+static void
+trans_function_start (gfc_symbol * sym)
+{
+  tree fndecl;
+
+  fndecl = sym->backend_decl;
+
+  /* let GCC know the current scope is this function */
+  current_function_decl = fndecl;
+
+  /* Let the world know what e're about to do.  */
+  announce_function (fndecl);
+
+  if (DECL_CONTEXT (fndecl) == NULL_TREE)
+    {
+      /* create RTL for function declaration */
+      rest_of_decl_compilation (fndecl, 1, 0);
+    }
+
+  /* create RTL for function definition */
+  make_decl_rtl (fndecl);
+
+  /* Set the line and filename.  sym->decalred_at seems to point to the
+     last statement for subroutines, but it'll do for now.  */
+  gfc_set_backend_locus (&sym->declared_at);
+
+  init_function_start (fndecl);
+
+  /* Even though we're inside a function body, we still don't want to
+     call expand_expr to calculate the size of a variable-sized array.
+     We haven't necessarily assigned RTL to all variables yet, so it's
+     not safe to try to expand expressions involving them.  */
+  cfun->x_dont_save_pending_sizes_p = 1;
+
+  /* function.c requires a push at the start of the function */
+  pushlevel (0);
+}
+
+/* Create thunks for alternate entry points.  */
+
+static void
+build_entry_thunks (gfc_namespace * ns)
+{
+  gfc_formal_arglist *formal;
+  gfc_formal_arglist *thunk_formal;
+  gfc_entry_list *el;
+  gfc_symbol *thunk_sym;
+  stmtblock_t body;
+  tree thunk_fndecl;
+  tree args;
+  tree string_args;
+  tree tmp;
+
+  /* This should always be a toplevel function.  */
+  assert (current_function_decl == NULL_TREE);
+
+  /* Remeber the master function argument decls.  */
+  for (formal = ns->proc_name->formal; formal; formal = formal->next)
+    {
+    }
+  
+  for (el = ns->entries; el; el = el->next)
+    {
+      thunk_sym = el->sym;
+      
+      build_function_decl (thunk_sym);
+      create_function_arglist (thunk_sym);
+
+      trans_function_start (thunk_sym);
+
+      thunk_fndecl = thunk_sym->backend_decl;
+
+      gfc_start_block (&body);
+
+      /* Pass extra parater identifying this entry point.  */
+      tmp = build_int_cst (gfc_array_index_type, el->id, 0);
+      args = tree_cons (NULL_TREE, tmp, NULL_TREE);
+      string_args = NULL_TREE;
+
+      /* TODO: Pass return by reference parameters.  */
+      if (ns->proc_name->attr.function)
+       gfc_todo_error ("Functons with multiple entry points");
+      
+      for (formal = ns->proc_name->formal; formal; formal = formal->next)
+       {
+         /* We don't have a clever way of identifying arguments, so resort to
+            a brute-force search.  */
+         for (thunk_formal = thunk_sym->formal;
+              thunk_formal;
+              thunk_formal = thunk_formal->next)
+           {
+             if (thunk_formal->sym == formal->sym)
+               break;
+           }
+
+         if (thunk_formal)
+           {
+             /* Pass the argument.  */
+             args = tree_cons (NULL_TREE, thunk_formal->sym->backend_decl,
+                               args);
+             if (formal->sym->ts.type == BT_CHARACTER)
+               {
+                 tmp = thunk_formal->sym->ts.cl->backend_decl;
+                 string_args = tree_cons (NULL_TREE, tmp, string_args);
+               }
+           }
+         else
+           {
+             /* Pass NULL for a missing argument.  */
+             args = tree_cons (NULL_TREE, null_pointer_node, args);
+             if (formal->sym->ts.type == BT_CHARACTER)
+               {
+                 tmp = convert (gfc_strlen_type_node, integer_zero_node);
+                 string_args = tree_cons (NULL_TREE, tmp, string_args);
+               }
+           }
+       }
+
+      /* Call the master function.  */
+      args = nreverse (args);
+      args = chainon (args, nreverse (string_args));
+      tmp = ns->proc_name->backend_decl;
+      tmp = gfc_build_function_call (tmp, args);
+      /* TODO: function return value.  */
+      gfc_add_expr_to_block (&body, tmp);
+
+      /* Finish off this function and send it for code generation.  */
+      DECL_SAVED_TREE (thunk_fndecl) = gfc_finish_block (&body);
+      poplevel (1, 0, 1);
+      BLOCK_SUPERCONTEXT (DECL_INITIAL (thunk_fndecl)) = thunk_fndecl;
+
+      /* Output the GENERIC tree.  */
+      dump_function (TDI_original, thunk_fndecl);
+
+      /* Store the end of the function, so that we get good line number
+        info for the epilogue.  */
+      cfun->function_end_locus = input_location;
+
+      /* We're leaving the context of this function, so zap cfun.
+        It's still in DECL_STRUCT_FUNCTION, and we'll restore it in
+        tree_rest_of_compilation.  */
+      cfun = NULL;
+
+      current_function_decl = NULL_TREE;
+
+      gfc_gimplify_function (thunk_fndecl);
+      lower_nested_functions (thunk_fndecl);
+      gfc_finalize (thunk_fndecl);
+
+      /* We share the symbols in the formal argument list with other entry
+        points and the master function.  Clear them so that they are
+        recreated for each function.  */
+      for (formal = thunk_sym->formal; formal; formal = formal->next)
+       {
+         formal->sym->backend_decl = NULL_TREE;
+         if (formal->sym->ts.type == BT_CHARACTER)
+           formal->sym->ts.cl->backend_decl = NULL_TREE;
+       }
+    }
+}
+
+
+/* Create a decl for a function, and create any thunks for alternate entry
+   points.  */
+
+void
+gfc_create_function_decl (gfc_namespace * ns)
+{
+  /* Create a declaration for the master function.  */
+  build_function_decl (ns->proc_name);
+
+  /* Compile teh entry thunks.  */
+  if (ns->entries)
+    build_entry_thunks (ns);
+
+  /* Now create the read argument list.  */
+  create_function_arglist (ns->proc_name);
+}
+
 /* Return the decl used to hold the function return value.  */
 
 tree
@@ -1811,7 +2058,7 @@ gfc_generate_contained_functions (gfc_namespace * parent)
       if (ns->parent != parent)
        continue;
 
-      gfc_build_function_decl (ns->proc_name);
+      gfc_create_function_decl (ns);
     }
 
   for (ns = parent->contained; ns; ns = ns->sibling)
@@ -1856,37 +2103,44 @@ generate_local_vars (gfc_namespace * ns)
 }
 
 
-/* Finalize DECL and all nested functions with cgraph.  */
+/* Generate a switch statement to jump to the correct entry point.  Also
+   creates the label decls for the entry points.  */
 
-static void
-gfc_finalize (tree decl)
+static tree
+gfc_trans_entry_master_switch (gfc_entry_list * el)
 {
-  struct cgraph_node *cgn;
-
-  cgn = cgraph_node (decl);
-  for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
-    gfc_finalize (cgn->decl);
+  stmtblock_t block;
+  tree label;
+  tree tmp;
+  tree val;
 
-  cgraph_finalize_function (decl, false);
+  gfc_init_block (&block);
+  for (; el; el = el->next)
+    {
+      /* Add the case label.  */
+      label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+      DECL_CONTEXT (label) = current_function_decl;
+      val = build_int_cst (gfc_array_index_type, el->id, 0);
+      tmp = build_v (CASE_LABEL_EXPR, val, NULL_TREE, label);
+      gfc_add_expr_to_block (&block, tmp);
+      
+      /* And jump to the actual entry point.  */
+      label = gfc_build_label_decl (NULL_TREE);
+      TREE_USED (label) = 1;
+      DECL_CONTEXT (label) = current_function_decl;
+      tmp = build1_v (GOTO_EXPR, label);
+      gfc_add_expr_to_block (&block, tmp);
+
+      /* Save the label decl.  */
+      el->label = label;
+    }
+  tmp = gfc_finish_block (&block);
+  /* The first argument selects the entry point.  */
+  val = DECL_ARGUMENTS (current_function_decl);
+  tmp = build_v (SWITCH_EXPR, val, tmp, NULL_TREE);
+  return tmp;
 }
 
-/* Convert FNDECL's code to GIMPLE and handle any nested functions.  */
-
-static void
-gfc_gimplify_function (tree fndecl)
-{
-  struct cgraph_node *cgn;
-
-  gimplify_function_tree (fndecl);
-  dump_function (TDI_generic, fndecl);
-
-  /* Convert all nested functions to GIMPLE now.  We do things in this order
-     so that items like VLA sizes are expanded properly in the context of the
-     correct function.  */
-  cgn = cgraph_node (fndecl);
-  for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
-    gfc_gimplify_function (cgn->decl);
-}
 
 /* Generate code for a function.  */
 
@@ -1903,14 +2157,14 @@ gfc_generate_function_code (gfc_namespace * ns)
   gfc_symbol *sym;
 
   sym = ns->proc_name;
+
   /* Check that the frontend isn't still using this.  */
   assert (sym->tlink == NULL);
-
   sym->tlink = sym;
 
   /* Create the declaration for functions with global scope.  */
   if (!sym->backend_decl)
-    gfc_build_function_decl (ns->proc_name);
+    gfc_create_function_decl (ns);
 
   fndecl = sym->backend_decl;
   old_context = current_function_decl;
@@ -1922,41 +2176,11 @@ gfc_generate_function_code (gfc_namespace * ns)
       saved_function_decls = NULL_TREE;
     }
 
-  /* let GCC know the current scope is this function */
-  current_function_decl = fndecl;
-
-  /* print function name on the console at compile time
-     (unless this feature was switched of by command line option "-quiet" */
-  announce_function (fndecl);
-
-  if (DECL_CONTEXT (fndecl) == NULL_TREE)
-    {
-      /* create RTL for function declaration */
-      rest_of_decl_compilation (fndecl, 1, 0);
-    }
-
-  /* create RTL for function definition */
-  make_decl_rtl (fndecl);
-
-  /* Set the line and filename.  sym->decalred_at seems to point to the last
-     statement for subroutines, but it'll do for now.  */
-  gfc_set_backend_locus (&sym->declared_at);
-
-  /* line and file should not be 0 */
-  init_function_start (fndecl);
-
-  /* Even though we're inside a function body, we still don't want to
-     call expand_expr to calculate the size of a variable-sized array.
-     We haven't necessarily assigned RTL to all variables yet, so it's
-     not safe to try to expand expressions involving them.  */
-  cfun->x_dont_save_pending_sizes_p = 1;
+  trans_function_start (sym);
 
   /* Will be created as needed.  */
   current_fake_result_decl = NULL_TREE;
 
-  /* function.c requires a push at the start of the function */
-  pushlevel (0);
-
   gfc_start_block (&block);
 
   gfc_generate_contained_functions (ns);
@@ -1979,6 +2203,13 @@ gfc_generate_function_code (gfc_namespace * ns)
       gfc_add_modify_expr (&body, alternate_return, integer_zero_node);
     }
 
+  if (ns->entries)
+    {
+      /* Jump to the correct entry point.  */
+      tmp = gfc_trans_entry_master_switch (ns->entries);
+      gfc_add_expr_to_block (&body, tmp);
+    }
+
   tmp = gfc_trans_code (ns->code);
   gfc_add_expr_to_block (&body, tmp);
 
index 261bf77d1d4da65405f555325c153ce1395df51c..dbe4422356fd3f70a4b3fd5a5b08230695ebdb39 100644 (file)
@@ -179,6 +179,14 @@ gfc_trans_goto (gfc_code * code)
 }
 
 
+/* Translate an ENTRY statement.  Just adds a label for this entry point.  */
+tree
+gfc_trans_entry (gfc_code * code)
+{
+  return build1_v (LABEL_EXPR, code->ext.entry->label);
+}
+
+
 /* Translate the CALL statement.  Builds a call to an F95 subroutine.  */
 
 tree
index e9d66e8c928c714c95da2ee83c3791753608367b..c7dc229784ea35aa213b6805ad37ce33f601b0d7 100644 (file)
@@ -35,6 +35,7 @@ tree gfc_trans_exit (gfc_code *);
 tree gfc_trans_label_assign (gfc_code *);
 tree gfc_trans_label_here (gfc_code *);
 tree gfc_trans_goto (gfc_code *);
+tree gfc_trans_entry (gfc_code *);
 tree gfc_trans_pause (gfc_code *);
 tree gfc_trans_stop (gfc_code *);
 tree gfc_trans_call (gfc_code *);
index b01298deb93f0dd07618bf8f80a081d09bbebbd4..85c13fa1a21ef7677a5e92d888e3a687c7c4b044 100644 (file)
@@ -1155,6 +1155,13 @@ gfc_get_function_type (gfc_symbol * sym)
   nstr = 0;
   alternate_return = 0;
   typelist = NULL_TREE;
+
+  if (sym->attr.entry_master)
+    {
+      /* Additional parameter for selecting an entry point.  */
+      typelist = gfc_chainon_list (typelist, gfc_array_index_type);
+    }
+
   /* Some functions we use an extra parameter for the return value.  */
   if (gfc_return_by_reference (sym))
     {
index 052da5525a401028b4295a87e23376f3a704f0d2..1ac8931bd4ef0c9c12d3b6e068a4906c211659e7 100644 (file)
@@ -516,6 +516,10 @@ gfc_trans_code (gfc_code * code)
          res = gfc_trans_goto (code);
          break;
 
+       case EXEC_ENTRY:
+         res = gfc_trans_entry (code);
+         break;
+
        case EXEC_PAUSE:
          res = gfc_trans_pause (code);
          break;
@@ -679,7 +683,7 @@ gfc_generate_module_code (gfc_namespace * ns)
       if (!n->proc_name)
         continue;
 
-      gfc_build_function_decl (n->proc_name);
+      gfc_create_function_decl (n);
     }
 
   for (n = ns->contained; n; n = n->sibling)
index 7f9e997f83b493824afa9e547ab0bbe2b65f7ea5..3faf4001b87a0aa6bbe28b1e8893ff868d281709 100644 (file)
@@ -394,7 +394,7 @@ void gfc_allocate_lang_decl (tree);
 tree gfc_advance_chain (tree, int);
 
 /* Create a decl for a function.  */
-void gfc_build_function_decl (gfc_symbol *);
+void gfc_create_function_decl (gfc_namespace *);
 /* Generate the code for a function.  */
 void gfc_generate_function_code (gfc_namespace *);
 /* Output a decl for a module variable.  */
index a4952b1268cf0b852a2ca032ffd9fde246a12fe7..7ceee259881f3446b80f1243ae8a57a7832dde11 100644 (file)
@@ -1,3 +1,8 @@
+2004-08-17  Paul Brook  <paul@codesourcery.com>
+
+       PR fortran/13082
+       * gfortran.dg/entry_1.f90: New test.
+
 2004-08-17  Andrew Pinski  <apinski@apple.com>
 
        * gcc.dg/darwin-20040812-1.c: Compile only on darwin.
diff --git a/gcc/testsuite/gfortran.dg/entry_1.f90 b/gcc/testsuite/gfortran.dg/entry_1.f90
new file mode 100644 (file)
index 0000000..0e7f296
--- /dev/null
@@ -0,0 +1,44 @@
+! Test alternate entry points in a module procedure
+! Also check that references to sibling entry points are resolved correctly.
+module m
+contains
+subroutine indirecta (p)
+  call p (3, 4)
+end subroutine
+subroutine indirectb (p)
+  call p (5)
+end subroutine
+
+subroutine test1
+  implicit none
+  call indidecta (foo)
+  call indirectb (bar)
+end subroutine
+
+subroutine foo(a, b)
+  integer a, b
+  logical, save :: was_foo = .false.
+  if ((a .ne. 3) .or. (b .ne. 4)) call abort
+  was_foo = .true.
+entry bar(a)
+  if (was_foo) then
+    if ((a .ne. 3) .or. (b .ne. 4)) call abort
+  else
+    if (a .ne. 5) call abort
+  end if
+  was_foo = .false.
+end subroutine
+
+subroutine test2
+  call foo (3, 4)
+  call bar (5)
+end subroutine
+end module
+
+program p
+  use m
+  call foo (3, 4)
+  call bar (5)
+  call test1 ()
+  call test2 ()
+end program