]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fortran: Source allocation of pure function result rejected [PR119948]
authorPaul Thomas <pault@gcc.gnu.org>
Thu, 1 May 2025 14:22:54 +0000 (15:22 +0100)
committerJerry DeLisle <jvdelisle@gcc.gnu.org>
Wed, 25 Jun 2025 19:55:39 +0000 (12:55 -0700)
2025-05-07  Paul Thomas  <pault@gcc.gnu.org>
    and Steven G. Kargl  <kargl@gcc.gnu.org>

gcc/fortran
PR fortran/119948
* resolve.cc (gfc_impure_variable): The result of a module
procedure with an interface declaration is not impure even if
the current namespace is not the same as the symbol's.
* primary.cc (match_variable): Module procedures with sym the
same as result can be treated as variables, although marked
external.

gcc/testsuite/
PR fortran/119948
* gfortran.dg/pr119948.f90: New test.

(cherry picked from commit 0abc77da9d704bba55a376bb5c162a54826ab94a)

gcc/fortran/primary.cc
gcc/fortran/resolve.cc
gcc/testsuite/gfortran.dg/pr119948.f90 [new file with mode: 0644]

index b5dddde5481b7260e19c7da8b1b957cf318ba217..f0e1fef6812eef1e2a2207df58b3d669b74dc69f 100644 (file)
@@ -4448,7 +4448,7 @@ match_variable (gfc_expr **result, int equiv_flag, int host_flag)
     case FL_PROCEDURE:
       /* Check for a nonrecursive function result variable.  */
       if (sym->attr.function
-         && !sym->attr.external
+         && (!sym->attr.external || sym->abr_modproc_decl)
          && sym->result == sym
          && (gfc_is_function_return_value (sym, gfc_current_ns)
              || (sym->attr.entry
index c5c10205dadf349c03f9ba147975fde62dcdc7b1..ee5b22a728d4704ed6f8d9ee62f0a733a7279606 100644 (file)
@@ -18478,6 +18478,16 @@ gfc_impure_variable (gfc_symbol *sym)
   if (sym->attr.use_assoc || sym->attr.in_common)
     return 1;
 
+  /* The namespace of a module procedure interface holds the arguments and
+     symbols, and so the symbol namespace can be different to that of the
+     procedure.  */
+  if (sym->ns != gfc_current_ns
+      && gfc_current_ns->proc_name->abr_modproc_decl
+      && sym->ns->proc_name->attr.function
+      && sym->attr.result
+      && !strcmp (sym->ns->proc_name->name, gfc_current_ns->proc_name->name))
+    return 0;
+
   /* Check if the symbol's ns is inside the pure procedure.  */
   for (ns = gfc_current_ns; ns; ns = ns->parent)
     {
diff --git a/gcc/testsuite/gfortran.dg/pr119948.f90 b/gcc/testsuite/gfortran.dg/pr119948.f90
new file mode 100644 (file)
index 0000000..2e36fae
--- /dev/null
@@ -0,0 +1,83 @@
+! { dg-do run }
+!
+! Test the fix for PR119948, which used to fail as indicated below with:
+! (1) "Error: Bad allocate-object at (1) for a PURE procedure"
+! (2) "Error: â€˜construct_test2 at (1) is not a variable"
+!
+! Contributed by Damian Rouson  <damian@archaeologic.codes>
+!
+module test_m
+  implicit none
+
+  type test_t
+    integer, allocatable :: i
+  end type
+
+  interface
+    pure module function construct_test(arg) result(test)
+      implicit none
+      type(test_t) :: test
+      type(test_t), intent(in) :: arg
+    end function
+
+    pure module function construct_test2(arg)
+      implicit none
+      type(test_t) construct_test2
+      type(test_t), intent(in) :: arg
+    end function
+
+    pure module function construct_test_3(arg) result(test)
+      implicit none
+      type(test_t) :: test
+      type(test_t), intent(in) :: arg
+    end function
+
+    pure module function construct_test_4(arg)
+      implicit none
+      type(test_t) :: construct_test_4
+      type(test_t), intent(in) :: arg
+    end function
+  end interface
+
+contains
+  module procedure construct_test
+    allocate(test%i, source = arg%i) ! Fail #1
+  end procedure
+
+  module procedure construct_test2
+    allocate(construct_test2%i, source = arg%i)    ! Fail #2
+  end procedure
+end module
+
+submodule (test_m)test_s
+contains
+  module procedure construct_test_3
+    allocate(test%i, source = arg%i) ! This was OK.
+  end procedure
+
+  module procedure construct_test_4
+    allocate(construct_test_4%i, source = arg%i) ! This was OK.
+  end procedure
+end submodule
+
+  use test_m
+  type(test_t) :: res, dummy
+!
+  dummy%i = int (rand () * 1e6)
+  res = construct_test (dummy)
+  if (res%i /= dummy%i) stop 1
+!
+  dummy%i = int (rand () * 1e6)
+  res = construct_test2 (dummy)
+  if (res%i /= dummy%i) stop 2
+!
+  dummy%i = int (rand () * 1e6)
+  res = construct_test_3 (dummy)
+  if (res%i /= dummy%i) stop 3
+
+  dummy%i = int (rand () * 1e6)
+  res = construct_test_4 (dummy)
+  if (res%i /= dummy%i) stop 4
+
+  deallocate (res%i, dummy%i)
+end