]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR fortran/36704 (Procedure pointer as function result)
authorJanus Weil <janus@gcc.gnu.org>
Thu, 9 Apr 2009 09:39:09 +0000 (11:39 +0200)
committerJanus Weil <janus@gcc.gnu.org>
Thu, 9 Apr 2009 09:39:09 +0000 (11:39 +0200)
2009-04-09  Janus Weil  <janus@gcc.gnu.org>

PR fortran/36704
* decl.c (add_hidden_procptr_result): New function for handling
procedure pointer return values by adding a hidden result variable.
(variable_decl,match_procedure_decl,gfc_match_function_decl,
gfc_match_subroutine,gfc_match_end,attr_decl1): Handle procedure pointer
return values.
* parse.c (parse_interface): Add EXTERNAL attribute only after
FUNCTION/SUBROUTINE declaration is complete.
* primary.c (replace_hidden_procptr_result): New function for replacing
function symbol by hidden result variable.
(gfc_match_rvalue,match_variable): Replace symbol by hidden result
variable.
* resolve.c (resolve_contained_fntype,resolve_function,resolve_variable,
resolve_symbol): Allow for procedure pointer function results.
(resolve_fl_procedure): Conflict detection moved here from
'check_conflict'.
* symbol.c (gfc_check_function_type): Allow for procedure pointer
function results.
(check_conflict): Move some conflict detection to resolution stage.
* trans-types.c (gfc_sym_type,gfc_get_function_type): Handle hidden
result variables.

2009-04-09  Janus Weil  <janus@gcc.gnu.org>

PR fortran/36704
* gfortran.dg/external_procedures_1.f90: Modified.
* gfortran.dg/proc_ptr_result_1.f90: New.
* gfortran.dg/proc_ptr_result_2.f90: New.
* gfortran.dg/proc_ptr_result_3.f90: New.

From-SVN: r145815

12 files changed:
gcc/fortran/ChangeLog
gcc/fortran/decl.c
gcc/fortran/parse.c
gcc/fortran/primary.c
gcc/fortran/resolve.c
gcc/fortran/symbol.c
gcc/fortran/trans-types.c
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/external_procedures_1.f90
gcc/testsuite/gfortran.dg/proc_ptr_result_1.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/proc_ptr_result_2.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/proc_ptr_result_3.f90 [new file with mode: 0644]

index c0f12e617382d20091040bf89029013ffcdb6d49..d24afdf7cd10581aba3d06ea1019fd88367ea336 100644 (file)
@@ -1,3 +1,27 @@
+2009-04-09  Janus Weil  <janus@gcc.gnu.org>
+
+       PR fortran/36704
+       * decl.c (add_hidden_procptr_result): New function for handling
+       procedure pointer return values by adding a hidden result variable.
+       (variable_decl,match_procedure_decl,gfc_match_function_decl,
+       gfc_match_subroutine,gfc_match_end,attr_decl1): Handle procedure pointer
+       return values.
+       * parse.c (parse_interface): Add EXTERNAL attribute only after
+       FUNCTION/SUBROUTINE declaration is complete.
+       * primary.c (replace_hidden_procptr_result): New function for replacing
+       function symbol by hidden result variable.
+       (gfc_match_rvalue,match_variable): Replace symbol by hidden result
+       variable.
+       * resolve.c (resolve_contained_fntype,resolve_function,resolve_variable,
+       resolve_symbol): Allow for procedure pointer function results.
+       (resolve_fl_procedure): Conflict detection moved here from
+       'check_conflict'.
+       * symbol.c (gfc_check_function_type): Allow for procedure pointer
+       function results.
+       (check_conflict): Move some conflict detection to resolution stage.
+       * trans-types.c (gfc_sym_type,gfc_get_function_type): Handle hidden
+       result variables.
+
 2009-04-08  Jakub Jelinek  <jakub@redhat.com>
 
        * trans-types.c (gfc_init_types): Ensure gfc_integer_types doesn't
index 2e541471f2ba4936833820609688941cd4dda0cc..27fe8ff18fd8b7dd2b49f89d1b9e1b4add72626f 100644 (file)
@@ -1667,6 +1667,17 @@ variable_decl (int elem)
        }
     }
 
+  /* Procedure pointer as function result.  */
+  if (gfc_current_state () == COMP_FUNCTION
+      && strcmp ("ppr@", gfc_current_block ()->name) == 0
+      && strcmp (name, gfc_current_block ()->ns->proc_name->name) == 0)
+    strcpy (name, "ppr@");
+
+  if (gfc_current_state () == COMP_FUNCTION
+      && strcmp (name, gfc_current_block ()->name) == 0
+      && gfc_current_block ()->result
+      && strcmp ("ppr@", gfc_current_block ()->result->name) == 0)
+    strcpy (name, "ppr@");
 
   /* OK, we've successfully matched the declaration.  Now put the
      symbol in the current namespace, because it might be used in the
@@ -4069,6 +4080,66 @@ gfc_match_suffix (gfc_symbol *sym, gfc_symbol **result)
 }
 
 
+/* Procedure pointer return value without RESULT statement:
+   Add "hidden" result variable named "ppr@".  */
+
+static gfc_try
+add_hidden_procptr_result (gfc_symbol *sym)
+{
+  bool case1,case2;
+
+  if (gfc_notification_std (GFC_STD_F2003) == ERROR)
+    return FAILURE;
+
+  /* First usage case: PROCEDURE and EXTERNAL statements.  */
+  case1 = gfc_current_state () == COMP_FUNCTION && gfc_current_block ()
+         && strcmp (gfc_current_block ()->name, sym->name) == 0
+         && sym->attr.external;
+  /* Second usage case: INTERFACE statements.  */
+  case2 = gfc_current_state () == COMP_INTERFACE && gfc_state_stack->previous
+         && gfc_state_stack->previous->state == COMP_FUNCTION
+         && strcmp (gfc_state_stack->previous->sym->name, sym->name) == 0;
+
+  if (case1 || case2)
+    {
+      gfc_symtree *stree;
+      if (case1)
+        gfc_get_sym_tree ("ppr@", gfc_current_ns, &stree);
+      else if (case2)
+        gfc_get_sym_tree ("ppr@", gfc_current_ns->parent, &stree);
+      sym->result = stree->n.sym;
+
+      sym->result->attr.proc_pointer = sym->attr.proc_pointer;
+      sym->result->attr.pointer = sym->attr.pointer;
+      sym->result->attr.external = sym->attr.external;
+      sym->result->attr.referenced = sym->attr.referenced;
+      sym->attr.proc_pointer = 0;
+      sym->attr.pointer = 0;
+      sym->attr.external = 0;
+      if (sym->result->attr.external && sym->result->attr.pointer)
+       {
+         sym->result->attr.pointer = 0;
+         sym->result->attr.proc_pointer = 1;
+       }
+
+      return gfc_add_result (&sym->result->attr, sym->result->name, NULL);
+    }
+  /* POINTER after PROCEDURE/EXTERNAL/INTERFACE statement.  */
+  else if (sym->attr.function && !sym->attr.external && sym->attr.pointer
+          && sym->result && sym->result != sym && sym->result->attr.external
+          && sym == gfc_current_ns->proc_name
+          && sym == sym->result->ns->proc_name
+          && strcmp ("ppr@", sym->result->name) == 0)
+    {
+      sym->result->attr.proc_pointer = 1;
+      sym->attr.pointer = 0;
+      return SUCCESS;
+    }
+  else
+    return FAILURE;
+}
+
+
 /* Match a PROCEDURE declaration (R1211).  */
 
 static match
@@ -4201,6 +4272,10 @@ got_ts:
 
       if (gfc_add_external (&sym->attr, NULL) == FAILURE)
        return MATCH_ERROR;
+
+      if (add_hidden_procptr_result (sym) == SUCCESS)
+       sym = sym->result;
+
       if (gfc_add_proc (&sym->attr, sym->name, NULL) == FAILURE)
        return MATCH_ERROR;
 
@@ -4415,6 +4490,10 @@ gfc_match_function_decl (void)
     }
   if (get_proc_name (name, &sym, false))
     return MATCH_ERROR;
+
+  if (add_hidden_procptr_result (sym) == SUCCESS)
+    sym = sym->result;
+
   gfc_new_block = sym;
 
   m = gfc_match_formal_arglist (sym, 0, 0);
@@ -4812,6 +4891,10 @@ gfc_match_subroutine (void)
 
   if (get_proc_name (name, &sym, false))
     return MATCH_ERROR;
+
+  if (add_hidden_procptr_result (sym) == SUCCESS)
+    sym = sym->result;
+
   gfc_new_block = sym;
 
   /* Check what next non-whitespace character is so we can tell if there
@@ -5259,12 +5342,21 @@ gfc_match_end (gfc_statement *st)
   if (block_name == NULL)
     goto syntax;
 
-  if (strcmp (name, block_name) != 0)
+  if (strcmp (name, block_name) != 0 && strcmp (block_name, "ppr@") != 0)
     {
       gfc_error ("Expected label '%s' for %s statement at %C", block_name,
                 gfc_ascii_statement (*st));
       goto cleanup;
     }
+  /* Procedure pointer as function result.  */
+  else if (strcmp (block_name, "ppr@") == 0
+          && strcmp (name, gfc_current_block ()->ns->proc_name->name) != 0)
+    {
+      gfc_error ("Expected label '%s' for %s statement at %C",
+                gfc_current_block ()->ns->proc_name->name,
+                gfc_ascii_statement (*st));
+      goto cleanup;
+    }
 
   if (gfc_match_eos () == MATCH_YES)
     return MATCH_YES;
@@ -5375,6 +5467,8 @@ attr_decl1 (void)
       goto cleanup;
     }
 
+  add_hidden_procptr_result (sym);
+
   return MATCH_YES;
 
 cleanup:
index 19251984c1d2c65df037f3cb236d04c9968b4fe5..81e4591b9be4bf7ffee0292a03c8862597937d49 100644 (file)
@@ -2113,14 +2113,6 @@ loop:
          gfc_free_namespace (gfc_current_ns);
          goto loop;
        }
-      if (current_interface.type != INTERFACE_ABSTRACT &&
-        !gfc_new_block->attr.dummy &&
-        gfc_add_external (&gfc_new_block->attr, &gfc_current_locus) == FAILURE)
-       {
-         reject_statement ();
-         gfc_free_namespace (gfc_current_ns);
-         goto loop;
-       }
       break;
 
     case ST_PROCEDURE:
@@ -2213,6 +2205,10 @@ decl:
       goto decl;
     }
 
+  /* Add EXTERNAL attribute to function or subroutine.  */
+  if (current_interface.type != INTERFACE_ABSTRACT && !prog_unit->attr.dummy)
+    gfc_add_external (&prog_unit->attr, &gfc_current_locus);
+
   current_interface = save;
   gfc_add_interface (prog_unit);
   pop_state ();
index cb6f98883b0f648add319ab8896203cc1f79a0dd..cab8f82edfbd44d009a8a70d36e0391b96ff1526 100644 (file)
@@ -2358,6 +2358,30 @@ check_for_implicit_index (gfc_symtree **st, gfc_symbol **sym)
 }
 
 
+/* Procedure pointer as function result: Replace the function symbol by the
+   auto-generated hidden result variable named "ppr@".  */
+
+static gfc_try
+replace_hidden_procptr_result (gfc_symbol **sym, gfc_symtree **st)
+{
+  /* Check for procedure pointer result variable.  */
+  if ((*sym)->attr.function && !(*sym)->attr.external
+      && (*sym)->result && (*sym)->result != *sym
+      && (*sym)->result->attr.proc_pointer
+      && (*sym) == gfc_current_ns->proc_name
+      && (*sym) == (*sym)->result->ns->proc_name
+      && strcmp ("ppr@", (*sym)->result->name) == 0)
+    {
+      /* Automatic replacement with "hidden" result variable.  */
+      (*sym)->result->attr.referenced = (*sym)->attr.referenced;
+      *sym = (*sym)->result;
+      *st = gfc_find_symtree ((*sym)->ns->sym_root, (*sym)->name);
+      return SUCCESS;
+    }
+  return FAILURE;
+}
+
+
 /* Matches a variable name followed by anything that might follow it--
    array reference, argument list of a function, etc.  */
 
@@ -2394,6 +2418,8 @@ gfc_match_rvalue (gfc_expr **result)
   e = NULL;
   where = gfc_current_locus;
 
+  replace_hidden_procptr_result (&sym, &symtree);
+
   /* If this is an implicit do loop index and implicitly typed,
      it should not be host associated.  */
   m = check_for_implicit_index (&symtree, &sym);
@@ -2583,6 +2609,8 @@ gfc_match_rvalue (gfc_expr **result)
       gfc_get_ha_sym_tree (name, &symtree);    /* Can't fail */
       sym = symtree->n.sym;
 
+      replace_hidden_procptr_result (&sym, &symtree);
+
       e = gfc_get_expr ();
       e->symtree = symtree;
       e->expr_type = EXPR_FUNCTION;
@@ -2912,7 +2940,8 @@ match_variable (gfc_expr **result, int equiv_flag, int host_flag)
          break;
        }
 
-      if (sym->attr.proc_pointer)
+      if (sym->attr.proc_pointer
+         || replace_hidden_procptr_result (&sym, &st) == SUCCESS)
        break;
 
       /* Fall through to error */
index 1b866d9cc491f18ccd9e14ebf203ae21da97575f..438b0d642ec6e7e7899cf69805041ea7ad790559 100644 (file)
@@ -344,7 +344,7 @@ resolve_contained_fntype (gfc_symbol *sym, gfc_namespace *ns)
          if (sym->result == sym)
            gfc_error ("Contained function '%s' at %L has no IMPLICIT type",
                       sym->name, &sym->declared_at);
-         else
+         else if (!sym->result->attr.proc_pointer)
            gfc_error ("Result '%s' of contained function '%s' at %L has "
                       "no IMPLICIT type", sym->result->name, sym->name,
                       &sym->result->declared_at);
@@ -2530,7 +2530,8 @@ resolve_function (gfc_expr *expr)
   if (expr->ts.type == BT_UNKNOWN)
     {
       if (expr->symtree->n.sym->result
-           && expr->symtree->n.sym->result->ts.type != BT_UNKNOWN)
+           && expr->symtree->n.sym->result->ts.type != BT_UNKNOWN
+           && !expr->symtree->n.sym->result->attr.proc_pointer)
        expr->ts = expr->symtree->n.sym->result->ts;
     }
 
@@ -4196,7 +4197,11 @@ resolve_variable (gfc_expr *e)
     return FAILURE;
 
   sym = e->symtree->n.sym;
-  if (sym->attr.flavor == FL_PROCEDURE && !sym->attr.function)
+  if (sym->attr.flavor == FL_PROCEDURE
+      && (!sym->attr.function
+         || (sym->attr.function && sym->result
+             && sym->result->attr.proc_pointer
+             && !sym->result->attr.function)))
     {
       e->ts.type = BT_PROCEDURE;
       goto resolve_procedure;
@@ -8034,18 +8039,41 @@ resolve_fl_procedure (gfc_symbol *sym, int mp_flag)
        }
     }
   
-  if (sym->attr.save == SAVE_EXPLICIT && !sym->attr.proc_pointer)
-    {
-      gfc_error ("PROCEDURE attribute conflicts with SAVE attribute "
-                "in '%s' at %L", sym->name, &sym->declared_at);
-      return FAILURE;
-    }
-
-  if (sym->attr.intent && !sym->attr.proc_pointer)
+  if (!sym->attr.proc_pointer)
     {
-      gfc_error ("PROCEDURE attribute conflicts with INTENT attribute "
-                "in '%s' at %L", sym->name, &sym->declared_at);
-      return FAILURE;
+      if (sym->attr.save == SAVE_EXPLICIT)
+       {
+         gfc_error ("PROCEDURE attribute conflicts with SAVE attribute "
+                    "in '%s' at %L", sym->name, &sym->declared_at);
+         return FAILURE;
+       }
+      if (sym->attr.intent)
+       {
+         gfc_error ("PROCEDURE attribute conflicts with INTENT attribute "
+                    "in '%s' at %L", sym->name, &sym->declared_at);
+         return FAILURE;
+       }
+      if (sym->attr.subroutine && sym->attr.result)
+       {
+         gfc_error ("PROCEDURE attribute conflicts with RESULT attribute "
+                    "in '%s' at %L", sym->name, &sym->declared_at);
+         return FAILURE;
+       }
+      if (sym->attr.external && sym->attr.function
+         && ((sym->attr.if_source == IFSRC_DECL && !sym->attr.procedure)
+             || sym->attr.contained))
+       {
+         gfc_error ("EXTERNAL attribute conflicts with FUNCTION attribute "
+                    "in '%s' at %L", sym->name, &sym->declared_at);
+         return FAILURE;
+       }
+      if (strcmp ("ppr@", sym->name) == 0)
+       {
+         gfc_error ("Procedure pointer result '%s' at %L "
+                    "is missing the pointer attribute",
+                    sym->ns->proc_name->name, &sym->declared_at);
+         return FAILURE;
+       }
     }
 
   return SUCCESS;
@@ -9310,11 +9338,14 @@ resolve_symbol (gfc_symbol *sym)
              /* Result may be in another namespace.  */
              resolve_symbol (sym->result);
 
-             sym->ts = sym->result->ts;
-             sym->as = gfc_copy_array_spec (sym->result->as);
-             sym->attr.dimension = sym->result->attr.dimension;
-             sym->attr.pointer = sym->result->attr.pointer;
-             sym->attr.allocatable = sym->result->attr.allocatable;
+             if (!sym->result->attr.proc_pointer)
+               {
+                 sym->ts = sym->result->ts;
+                 sym->as = gfc_copy_array_spec (sym->result->as);
+                 sym->attr.dimension = sym->result->attr.dimension;
+                 sym->attr.pointer = sym->result->attr.pointer;
+                 sym->attr.allocatable = sym->result->attr.allocatable;
+               }
            }
        }
     }
index 6ffd869a30e858594f51d9f38f6583fb0ba4981f..a4f43a5f6700ebb182ba97f7cc07556fca9495ff 100644 (file)
@@ -320,7 +320,7 @@ gfc_check_function_type (gfc_namespace *ns)
              proc->attr.allocatable = proc->result->attr.allocatable;
            }
        }
-      else
+      else if (!proc->result->attr.proc_pointer)
        {
          gfc_error ("Function result '%s' at %L has no IMPLICIT type",
                     proc->result->name, &proc->result->declared_at);
@@ -453,10 +453,7 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
   conf (entry, intrinsic);
 
   if ((attr->if_source == IFSRC_DECL && !attr->procedure) || attr->contained)
-    {
-      conf (external, subroutine);
-      conf (external, function);
-    }
+    conf (external, subroutine);
 
   conf (allocatable, pointer);
   conf_std (allocatable, dummy, GFC_STD_F2003);
@@ -626,14 +623,13 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
       break;
 
     case FL_PROCEDURE:
-      /* Conflicts with INTENT will be checked at resolution stage,
-        see "resolve_fl_procedure".  */
+      /* Conflicts with INTENT, SAVE and RESULT will be checked
+        at resolution stage, see "resolve_fl_procedure".  */
 
       if (attr->subroutine)
        {
          conf2 (target);
          conf2 (allocatable);
-         conf2 (result);
          conf2 (in_namelist);
          conf2 (dimension);
          conf2 (function);
index 7cb336346049fa9cbb0bf63d30b246431fbbfa92..e83215c068628df50aa120434e9de641a4da9a5a 100644 (file)
@@ -1616,8 +1616,8 @@ gfc_sym_type (gfc_symbol * sym)
   tree type;
   int byref;
 
-  /* Procedure Pointers inside COMMON blocks or as function result.  */
-  if (sym->attr.proc_pointer && (sym->attr.in_common || sym->attr.result))
+  /* Procedure Pointers inside COMMON blocks.  */
+  if (sym->attr.proc_pointer && sym->attr.in_common)
     {
       /* Unset proc_pointer as gfc_get_function_type calls gfc_sym_type.  */
       sym->attr.proc_pointer = 0;
@@ -2156,7 +2156,18 @@ gfc_get_function_type (gfc_symbol * sym)
     }
   else if (sym->result && sym->result->attr.proc_pointer)
     /* Procedure pointer return values.  */
-    type = gfc_sym_type (sym->result);
+    {
+      if (sym->result->attr.result && strcmp (sym->name,"ppr@") != 0)
+       {
+         /* Unset proc_pointer as gfc_get_function_type
+            is called recursively.  */
+         sym->result->attr.proc_pointer = 0;
+         type = build_pointer_type (gfc_get_function_type (sym->result));
+         sym->result->attr.proc_pointer = 1;
+       }
+      else
+       type = gfc_sym_type (sym->result);
+    }
   else
     type = gfc_sym_type (sym);
 
index 0a2ff3a1548e5aa773e642ec42ca957b516f8eb4..de58d166f2bf0ce0fa5f535bb1e72ca78cb0140e 100644 (file)
@@ -1,3 +1,11 @@
+2009-04-09  Janus Weil  <janus@gcc.gnu.org>
+
+       PR fortran/36704
+       * gfortran.dg/external_procedures_1.f90: Modified.
+       * gfortran.dg/proc_ptr_result_1.f90: New.
+       * gfortran.dg/proc_ptr_result_2.f90: New.
+       * gfortran.dg/proc_ptr_result_3.f90: New.
+
 2009-04-09  Richard Guenther  <rguenther@suse.de>
 
        * gcc.dg/vect/vect-54.c: Make constant input data file-scope
index 6e833be16e2eb2ed86af42ff5c8f86b73371602e..de273d52ea0aae02281f1ab8aa8ef3504da99630 100644 (file)
@@ -1,14 +1,17 @@
 ! { dg-do compile }
+! { dg-options "-std=f95" }
+!
 ! This tests the patch for PR25024.
 
 ! PR25024 - The external attribute for subroutine a would cause an ICE.
   subroutine A ()
     EXTERNAL A  ! { dg-error "EXTERNAL attribute conflicts with SUBROUTINE" }
   END
-function ext (y)
+
+function ext (y)  ! { dg-error "EXTERNAL attribute conflicts with FUNCTION" }
   real ext, y
-  external ext      ! { dg-error "EXTERNAL attribute conflicts with FUNCTION" }
-  ext = y * y
+  external ext
+  !ext = y * y
 end function ext
 
 function ext1 (y)
@@ -24,18 +27,18 @@ program main
   interface
     function ext1 (y)
       real ext1, y
-      external ext1  ! { dg-error "Duplicate EXTERNAL attribute" }
-    end function ext1
+      external ext1
+    end function ext1  ! { dg-error "Duplicate EXTERNAL attribute" }
   end interface
   inval = 1.0
   print *, ext(inval)
   print *, ext1(inval)
   print *, inv(inval)
 contains
-  function inv (y)
+  function inv (y)  ! { dg-error "EXTERNAL attribute conflicts with FUNCTION" }
     real inv, y
-    external inv     ! { dg-error "EXTERNAL attribute conflicts with FUNCTION" }
-    inv = y * y * y
+    external inv
+    !inv = y * y * y
   end function inv
 end program main
 
diff --git a/gcc/testsuite/gfortran.dg/proc_ptr_result_1.f90 b/gcc/testsuite/gfortran.dg/proc_ptr_result_1.f90
new file mode 100644 (file)
index 0000000..dc09f04
--- /dev/null
@@ -0,0 +1,173 @@
+! { dg-do run }
+!
+! PR 36704: Procedure pointer as function result
+!
+! Contributed by Janus Weil <janus@gcc.gnu.org>
+
+module mo
+contains
+
+  function j()
+    procedure(),pointer :: j
+    intrinsic iabs
+    j => iabs
+  end function
+
+  subroutine sub(y)
+    integer,intent(inout) :: y
+    y = y**2
+  end subroutine
+
+end module
+
+
+program proc_ptr_14
+use mo
+implicit none
+intrinsic :: iabs
+integer :: x
+procedure(integer),pointer :: p,p2
+procedure(sub),pointer :: ps
+
+p => a()
+if (p(-1)/=1) call abort()
+p => b()
+if (p(-2)/=2) call abort()
+p => c()
+if (p(-3)/=3) call abort()
+p => d()
+if (p(-4)/=4) call abort()
+p => dd()
+if (p(-4)/=4) call abort()
+p => e(iabs)
+if (p(-5)/=5) call abort()
+p => ee()
+if (p(-5)/=5) call abort()
+p => f()
+if (p(-6)/=6) call abort()
+p => g()
+if (p(-7)/=7) call abort()
+
+ps => h(sub)
+x = 2
+call ps(x)
+if (x/=4) call abort()
+
+p => i()
+if (p(-8)/=8) call abort()
+p => j()
+if (p(-9)/=9) call abort()
+
+p => k(p2)
+if (p(-10)/=p2(-10)) call abort()
+
+p => l()
+if (p(-11)/=11) call abort()
+
+contains
+
+  function a()
+    procedure(integer),pointer :: a
+    a => iabs
+  end function
+
+  function b()
+    procedure(integer) :: b
+    pointer :: b
+    b => iabs
+  end function
+
+  function c()
+    pointer :: c
+    procedure(integer) :: c
+    c => iabs
+  end function
+
+  function d()
+    pointer :: d
+    external d
+    d => iabs
+  end function
+
+  function dd()
+    pointer :: dd
+    external :: dd
+    integer :: dd
+    dd => iabs
+  end function
+
+  function e(arg)
+    external :: e,arg
+    pointer :: e
+    e => arg
+  end function
+
+  function ee()
+    integer :: ee
+    external :: ee
+    pointer :: ee
+    ee => iabs
+  end function
+
+  function f()
+    pointer :: f
+    interface
+      integer function f(x)
+        integer :: x
+      end function
+    end interface
+    f => iabs
+  end function
+
+  function g()
+    interface
+      integer function g(x)
+        integer :: x
+      end function g
+    end interface
+    pointer :: g
+    g => iabs
+  end function
+
+  function h(arg)
+    interface
+      subroutine arg(b)
+        integer :: b
+      end subroutine arg
+    end interface
+    pointer :: h
+    interface
+      subroutine h(a)
+        integer :: a
+      end subroutine h
+    end interface
+    h => arg
+  end function
+
+  function i()
+    pointer :: i
+    interface
+      function i(x)
+        integer :: i,x
+      end function i
+    end interface
+    i => iabs
+  end function
+
+  function k(arg)
+    procedure(),pointer :: k,arg
+    k => iabs
+    arg => k
+  end function
+
+  function l()
+    procedure(iabs),pointer :: l
+    integer :: i
+    l => iabs
+    if (l(-11)/=11) call abort()
+  end function 
+
+end
+
+! { dg-final { cleanup-modules "mo" } }
+
diff --git a/gcc/testsuite/gfortran.dg/proc_ptr_result_2.f90 b/gcc/testsuite/gfortran.dg/proc_ptr_result_2.f90
new file mode 100644 (file)
index 0000000..362a1f7
--- /dev/null
@@ -0,0 +1,62 @@
+! { dg-do compile }
+!
+! PR 36704: Procedure pointer as function result
+!
+! Contributed by Janus Weil <janus@gcc.gnu.org>
+
+module proc_ptr_15
+
+  interface
+    function e(x)
+      real :: x
+      procedure(), pointer :: e
+    end function e
+  end interface
+
+  interface
+    function f(x)
+      real :: x
+      external :: f
+      pointer :: f
+    end function
+  end interface
+
+  interface
+    function g(x)
+      real :: x
+      pointer :: g
+      external :: g
+    end function
+  end interface
+
+contains
+
+  subroutine point_fun()
+    call set_fun(aux)
+  end subroutine
+
+  subroutine set_fun(y)
+    external :: y
+  end subroutine
+
+  function aux()
+    external aux
+    pointer aux
+    intrinsic sin
+    aux => sin
+  end function
+
+  function foo(x)
+    real :: x
+    interface
+      subroutine foo(i)  ! { dg-error "attribute conflicts with" }
+        integer :: i
+      end subroutine
+    end interface
+    !pointer :: foo
+  end function
+
+end
+
+! { dg-final { cleanup-modules "proc_ptr_15" } }
+
diff --git a/gcc/testsuite/gfortran.dg/proc_ptr_result_3.f90 b/gcc/testsuite/gfortran.dg/proc_ptr_result_3.f90
new file mode 100644 (file)
index 0000000..a84ff24
--- /dev/null
@@ -0,0 +1,56 @@
+!{ dg-do run }
+!
+! PR 36704: Procedure pointer as function result
+!
+! Original test case from James Van Buskirk.
+!
+! Adapted by Janus Weil <janus@gcc.gnu.org>
+
+module store_subroutine
+   implicit none
+
+   abstract interface
+      subroutine sub(i)
+        integer, intent(inout) :: i
+      end subroutine sub
+   end interface
+
+   procedure(sub), pointer, private :: psub => NULL()
+
+contains
+
+   subroutine set_sub(x)
+      procedure(sub) x
+      psub => x
+   end subroutine set_sub
+
+   function get_sub()
+      procedure(sub), pointer :: get_sub
+      get_sub => psub
+   end function get_sub
+
+end module store_subroutine
+
+program test
+   use store_subroutine
+   implicit none
+   procedure(sub), pointer :: qsub
+   integer :: k = 1
+
+   call my_sub(k)
+   if (k/=3) call abort
+   qsub => get_sub()
+   call qsub(k)
+   if (k/=9) call abort
+end program test
+
+recursive subroutine my_sub(j)
+   use store_subroutine
+   implicit none
+   integer, intent(inout) :: j
+   j = j*3
+   call set_sub(my_sub)
+end subroutine my_sub
+
+! { dg-final { cleanup-modules "store_subroutine" } }
+