Dear All,

These are two rather trivial modifications to permit, 'module' to
appear at any position in the list of prefixes in the procedure
declaration and to allow module procedures to appear within a module
contains section. I was rather astonished at this latter since it does
seem to be rather contrary to having an module interface declaration
for the same procedure. However, from the Fortran 2008 standard:

C1247 (R1225) MODULE shall appear only in the function-stmt or
subroutine-stmt of a module subprogram or of a nonabstract interface
body that is declared in the scoping unit of a module or submodule.

Whilst I was about it, I prevented an ICE from occurring following the
error generated by decl.c(copy_prefix), when prefixes in the interface
are repeated in the procedure declaration. I have not included a test
for this, since I am not convinced that repeating the prefixes is
strictly speaking an error. In fact, it would make a lot of sense to
repeat the interface declaration completely in the submodule
declaration. I will investigate further before committing. The fix is
even more trivial than preventing the ICE.

Since the patch is entirely permissive, it will not prevent correct
code from compiling. In this sense, it is safe for stage 4.

Bootstrapped and regtested on FC21/x86_64. OK for trunk?

Best regards

Paul

2016-03-06  Paul Thomas  <pa...@gcc.gnu.org>

    PR fortran/70031
    * decl.c (gfc_match_prefix): Treat the 'module' prefix in the
    same way as the others, rather than fixing it to come last.
    (gfc_match_function_decl, gfc_match_subroutine): After errors
    in 'copy_prefix', emit them immediately in the case of module
    procedures to prevent a later ICE.

    PR fortran/69524
    * decl.c (gfc_match_submod_proc): Permit 'module procedure'
    declarations within the contains section of modules as well as
    submodules.
    * resolve.c (resolve_fl_procedure): Likewise.
    *trans-decl.c (build_function_decl): Change the gcc_assert to
    allow all forms of module procedure declarations within module
    contains sections.

2016-03-06  Paul Thomas  <pa...@gcc.gnu.org>

    PR fortran/70031
    * gfortran.dg/submodule_14.f08: New test

    PR fortran/69524
    * gfortran.dg/submodule_15.f08: New test
Index: gcc/fortran/decl.c
===================================================================
*** gcc/fortran/decl.c  (revision 233937)
--- gcc/fortran/decl.c  (working copy)
*************** gfc_match_prefix (gfc_typespec *ts)
*** 4606,4611 ****
--- 4606,4624 ----
      {
        found_prefix = false;
  
+       /* MODULE is a prefix like PURE, ELEMENTAL, etc., having a
+        corresponding attribute seems natural and distinguishes these
+        procedures from procedure types of PROC_MODULE, which these are
+        as well.  */
+       if (gfc_match ("module% ") == MATCH_YES)
+       {
+         if (!gfc_notify_std (GFC_STD_F2008, "MODULE prefix at %C"))
+           goto error;
+ 
+         current_attr.module_procedure = 1;
+         found_prefix = true;
+       }
+ 
        if (!seen_type && ts != NULL
          && gfc_match_decl_type_spec (ts, 0) == MATCH_YES
          && gfc_match_space () == MATCH_YES)
*************** gfc_match_prefix (gfc_typespec *ts)
*** 4670,4690 ****
    /* At this point, the next item is not a prefix.  */
    gcc_assert (gfc_matching_prefix);
  
-   /* MODULE should be the last prefix before FUNCTION or SUBROUTINE.
-      Since this is a prefix like PURE, ELEMENTAL, etc., having a
-      corresponding attribute seems natural and distinguishes these
-      procedures from procedure types of PROC_MODULE, which these are
-      as well.  */
-   if ((gfc_current_state () == COMP_INTERFACE
-        || gfc_current_state () == COMP_CONTAINS)
-       && gfc_match ("module% ") == MATCH_YES)
-     {
-       if (!gfc_notify_std (GFC_STD_F2008, "MODULE prefix at %C"))
-       goto error;
-       else
-       current_attr.module_procedure = 1;
-     }
- 
    gfc_matching_prefix = false;
    return MATCH_YES;
  
--- 4683,4688 ----
*************** gfc_match_function_decl (void)
*** 5639,5647 ****
        if (!gfc_add_function (&sym->attr, sym->name, NULL))
        goto cleanup;
  
!       if (!gfc_missing_attr (&sym->attr, NULL)
!         || !copy_prefix (&sym->attr, &sym->declared_at))
        goto cleanup;
  
        /* Delay matching the function characteristics until after the
         specification block by signalling kind=-1.  */
--- 5637,5652 ----
        if (!gfc_add_function (&sym->attr, sym->name, NULL))
        goto cleanup;
  
!       if (!gfc_missing_attr (&sym->attr, NULL))
!       goto cleanup;
! 
!       if (!copy_prefix (&sym->attr, &sym->declared_at))
!       {
!         if(!sym->attr.module_procedure)
            goto cleanup;
+         else
+           gfc_error_check ();
+       }
  
        /* Delay matching the function characteristics until after the
         specification block by signalling kind=-1.  */
*************** gfc_match_function_decl (void)
*** 5666,5671 ****
--- 5671,5677 ----
          sym->result = result;
        }
  
+ 
        /* Warn if this procedure has the same name as an intrinsic.  */
        do_warn_intrinsic_shadow (sym, true);
  
*************** gfc_match_subroutine (void)
*** 6108,6114 ****
--- 6114,6125 ----
      }
  
    if (!copy_prefix (&sym->attr, &sym->declared_at))
+     {
+       if(!sym->attr.module_procedure)
        return MATCH_ERROR;
+       else
+       gfc_error_check ();
+     }
  
    /* Warn if it has the same name as an intrinsic.  */
    do_warn_intrinsic_shadow (sym, false);
*************** gfc_match_submod_proc (void)
*** 7697,7703 ****
  
    if (gfc_current_state () != COMP_CONTAINS
        || !(gfc_state_stack->previous
!          && gfc_state_stack->previous->state == COMP_SUBMODULE))
      return MATCH_NO;
  
    m = gfc_match (" module% procedure% %n", name);
--- 7708,7715 ----
  
    if (gfc_current_state () != COMP_CONTAINS
        || !(gfc_state_stack->previous
!          && (gfc_state_stack->previous->state == COMP_SUBMODULE
!              || gfc_state_stack->previous->state == COMP_MODULE)))
      return MATCH_NO;
  
    m = gfc_match (" module% procedure% %n", name);
Index: gcc/fortran/resolve.c
===================================================================
*** gcc/fortran/resolve.c       (revision 233937)
--- gcc/fortran/resolve.c       (working copy)
*************** resolve_fl_procedure (gfc_symbol *sym, i
*** 11905,11911 ****
                     "in %qs at %L", sym->name, &sym->declared_at);
          return false;
        }
!       if (sym->attr.external && sym->attr.function
          && ((sym->attr.if_source == IFSRC_DECL && !sym->attr.procedure)
              || sym->attr.contained))
        {
--- 11905,11911 ----
                     "in %qs at %L", sym->name, &sym->declared_at);
          return false;
        }
!       if (sym->attr.external && sym->attr.function && 
!sym->attr.module_procedure
          && ((sym->attr.if_source == IFSRC_DECL && !sym->attr.procedure)
              || sym->attr.contained))
        {
Index: gcc/fortran/trans-decl.c
===================================================================
*** gcc/fortran/trans-decl.c    (revision 233937)
--- gcc/fortran/trans-decl.c    (working copy)
*************** build_function_decl (gfc_symbol * sym, b
*** 2062,2068 ****
    tree result_decl;
    gfc_formal_arglist *f;
  
!   gcc_assert (!sym->attr.external);
  
    if (sym->backend_decl)
      return;
--- 2062,2073 ----
    tree result_decl;
    gfc_formal_arglist *f;
  
!   bool module_procedure = sym->attr.module_procedure
!                         && sym->ns
!                         && sym->ns->proc_name
!                         && sym->ns->proc_name->attr.flavor == FL_MODULE;
! 
!   gcc_assert (!sym->attr.external || module_procedure);
  
    if (sym->backend_decl)
      return;
Index: gcc/testsuite/gfortran.dg/submodule_14.f08
===================================================================
*** gcc/testsuite/gfortran.dg/submodule_14.f08  (revision 0)
--- gcc/testsuite/gfortran.dg/submodule_14.f08  (working copy)
***************
*** 0 ****
--- 1,49 ----
+ ! { dg-do compile }
+ !
+ ! Check the fix for PR70031, where the 'module' prefix had to preceed
+ ! 'function/subroutine' in the interface (or in the CONTAINS section.
+ !
+ ! As reported by "Bulova" on
+ ! https://groups.google.com/forum/#!topic/comp.lang.fortran/hE8LkVMhghQ
+ !
+ module test
+   Interface
+     Module Recursive Subroutine sub1 (x)
+       Integer, Intent (InOut) :: x
+     End Subroutine sub1
+     module recursive function fcn1 (x) result(res)
+       integer, intent (inout) :: x
+       integer :: res
+     end function
+   End Interface
+ end module test
+ 
+ submodule(test) testson
+   integer :: n = 10
+ contains
+   Module Procedure sub1
+     If (x < n) Then
+         x = x + 1
+         Call sub1 (x)
+     End If
+   End Procedure sub1
+   module function fcn1 (x) result(res)
+     integer, intent (inout) :: x
+     integer :: res
+     res = x - 1
+     if (x > 0) then
+       x = fcn1 (res)
+     else
+       res = x
+     end if
+   end function
+ end submodule testson
+ 
+   use test
+   integer :: x = 5
+   call sub1(x)
+   if (x .ne. 10) call abort
+   x = 10
+   if (fcn1 (x) .ne. 0) call abort
+ end
+ 
Index: gcc/testsuite/gfortran.dg/submodule_15.f08
===================================================================
*** gcc/testsuite/gfortran.dg/submodule_15.f08  (revision 0)
--- gcc/testsuite/gfortran.dg/submodule_15.f08  (working copy)
***************
*** 0 ****
--- 1,58 ----
+ ! { dg-do run }
+ !
+ ! Check the fix for PR69524, where module procedures were not permitted
+ ! in a module CONTAINS section.
+ !
+ ! Reorted by Kirill Yukhin  <kyuk...@gcc.gnu.org>
+ !
+ module A
+   implicit none
+   interface
+      module subroutine A1(i)
+        integer, intent(inout) :: i
+      end subroutine A1
+      module subroutine A2(i)
+        integer, intent(inout) :: i
+      end subroutine A2
+      integer module function A3(i)
+        integer, intent(inout) :: i
+      end function A3
+      module subroutine B1(i)
+        integer, intent(inout) :: i
+      end subroutine B1
+   end interface
+   integer :: incr         ! Make sure that everybody can access a module 
variable
+ contains
+   module subroutine A1(i) ! Full declaration
+     integer, intent(inout) :: i
+     call b1 (i)           ! Call the submodule procedure
+     incr = incr + 1
+   end subroutine A1
+ 
+   module PROCEDURE A2     ! Abreviated declaration
+     call b1 (i)           ! Call the submodule procedure
+     incr = incr + 1
+   end procedure A2
+ 
+   module PROCEDURE A3     ! Abreviated declaration
+     call a1 (i)           ! Call the module procedure in the module
+     call a2 (i)           !            ditto
+     call b1 (i)           ! Call the submodule procedure
+     incr = incr + 1
+     a3 = i + incr
+   end procedure A3
+ end module A
+ 
+ submodule (A) a_son
+   implicit none
+ contains
+   module procedure b1
+     i = i + incr
+   end procedure
+ end submodule
+ 
+   use A
+   integer :: i = 1
+   incr = 1
+   if (a3(i) .ne. 11) call abort
+ end

Reply via email to