Fortran: Fix ICE and wrong code for assumed-rank arrays [PR100029, PR100040]
authorJosé Rui Faustino de Sousa <jrfsousa@gmail.com>
Sun, 25 Sep 2022 20:48:55 +0000 (22:48 +0200)
committerHarald Anlauf <anlauf@gmx.de>
Sat, 1 Oct 2022 18:09:08 +0000 (20:09 +0200)
gcc/fortran/ChangeLog:

PR fortran/100040
PR fortran/100029
* trans-expr.cc (gfc_conv_class_to_class): Add code to have
assumed-rank arrays recognized as full arrays and fix the type
of the array assignment.
(gfc_conv_procedure_call): Change order of code blocks such that
the free of ALLOCATABLE dummy arguments with INTENT(OUT) occurs
first.

gcc/testsuite/ChangeLog:

PR fortran/100029
* gfortran.dg/PR100029.f90: New test.

PR fortran/100040
* gfortran.dg/PR100040.f90: New test.

gcc/fortran/trans-expr.cc
gcc/testsuite/gfortran.dg/PR100029.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/PR100040.f90 [new file with mode: 0644]

index 4f3ae82..1551a2e 100644 (file)
@@ -1178,8 +1178,10 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts,
     return;
 
   /* Test for FULL_ARRAY.  */
-  if (e->rank == 0 && gfc_expr_attr (e).codimension
-      && gfc_expr_attr (e).dimension)
+  if (e->rank == 0
+      && ((gfc_expr_attr (e).codimension && gfc_expr_attr (e).dimension)
+         || (class_ts.u.derived->components->as
+             && class_ts.u.derived->components->as->type == AS_ASSUMED_RANK)))
     full_array = true;
   else
     gfc_is_class_array_ref (e, &full_array);
@@ -1227,8 +1229,12 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts,
          && e->rank != class_ts.u.derived->components->as->rank)
        {
          if (e->rank == 0)
-           gfc_add_modify (&parmse->post, gfc_class_data_get (parmse->expr),
-                           gfc_conv_descriptor_data_get (ctree));
+           {
+             tmp = gfc_class_data_get (parmse->expr);
+             gfc_add_modify (&parmse->post, tmp,
+                             fold_convert (TREE_TYPE (tmp),
+                                        gfc_conv_descriptor_data_get (ctree)));
+           }
          else
            class_array_data_assign (&parmse->post, parmse->expr, ctree, true);
        }
@@ -6560,23 +6566,6 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
                    base_object = build_fold_indirect_ref_loc (input_location,
                                                               parmse.expr);
 
-                 /* A class array element needs converting back to be a
-                    class object, if the formal argument is a class object.  */
-                 if (fsym && fsym->ts.type == BT_CLASS
-                       && e->ts.type == BT_CLASS
-                       && ((CLASS_DATA (fsym)->as
-                            && CLASS_DATA (fsym)->as->type == AS_ASSUMED_RANK)
-                           || CLASS_DATA (e)->attr.dimension))
-                   gfc_conv_class_to_class (&parmse, e, fsym->ts, false,
-                                    fsym->attr.intent != INTENT_IN
-                                    && (CLASS_DATA (fsym)->attr.class_pointer
-                                        || CLASS_DATA (fsym)->attr.allocatable),
-                                    fsym->attr.optional
-                                    && e->expr_type == EXPR_VARIABLE
-                                    && e->symtree->n.sym->attr.optional,
-                                    CLASS_DATA (fsym)->attr.class_pointer
-                                    || CLASS_DATA (fsym)->attr.allocatable);
-
                  /* If an ALLOCATABLE dummy argument has INTENT(OUT) and is
                     allocated on entry, it must be deallocated.  */
                  if (fsym && fsym->attr.intent == INTENT_OUT
@@ -6637,6 +6626,23 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
                      gfc_add_expr_to_block (&se->pre, tmp);
                    }
 
+                 /* A class array element needs converting back to be a
+                    class object, if the formal argument is a class object.  */
+                 if (fsym && fsym->ts.type == BT_CLASS
+                       && e->ts.type == BT_CLASS
+                       && ((CLASS_DATA (fsym)->as
+                            && CLASS_DATA (fsym)->as->type == AS_ASSUMED_RANK)
+                           || CLASS_DATA (e)->attr.dimension))
+                   gfc_conv_class_to_class (&parmse, e, fsym->ts, false,
+                                    fsym->attr.intent != INTENT_IN
+                                    && (CLASS_DATA (fsym)->attr.class_pointer
+                                        || CLASS_DATA (fsym)->attr.allocatable),
+                                    fsym->attr.optional
+                                    && e->expr_type == EXPR_VARIABLE
+                                    && e->symtree->n.sym->attr.optional,
+                                    CLASS_DATA (fsym)->attr.class_pointer
+                                    || CLASS_DATA (fsym)->attr.allocatable);
+
                  if (fsym && (fsym->ts.type == BT_DERIVED
                               || fsym->ts.type == BT_ASSUMED)
                      && e->ts.type == BT_CLASS
diff --git a/gcc/testsuite/gfortran.dg/PR100029.f90 b/gcc/testsuite/gfortran.dg/PR100029.f90
new file mode 100644 (file)
index 0000000..fd7e4c4
--- /dev/null
@@ -0,0 +1,22 @@
+! { dg-do run }
+!
+! Test the fix for PR100029
+!
+
+program foo_p
+  implicit none
+
+  type :: foo_t
+  end type foo_t
+  
+  class(foo_t), allocatable :: pout
+
+  call foo_s(pout)
+
+contains
+
+  subroutine foo_s(that)
+    class(foo_t), allocatable, intent(out) :: that(..)
+  end subroutine foo_s
+
+end program foo_p
diff --git a/gcc/testsuite/gfortran.dg/PR100040.f90 b/gcc/testsuite/gfortran.dg/PR100040.f90
new file mode 100644 (file)
index 0000000..0a135ff
--- /dev/null
@@ -0,0 +1,36 @@
+! { dg-do run }
+!
+! Test the fix for PR100040
+!
+
+program foo_p
+  implicit none
+
+  integer, parameter :: n = 11
+
+  type :: foo_t
+    integer :: i
+  end type foo_t
+  
+  type(foo_t), parameter :: a = foo_t(n)
+  
+  class(foo_t), allocatable :: pout
+
+  call foo_s(pout)
+  if(.not.allocated(pout)) stop 1
+  if(pout%i/=n) stop 2
+
+contains
+
+  subroutine foo_s(that)
+    class(foo_t), allocatable, intent(out) :: that(..)
+
+    select rank(that)
+    rank(0)
+      that = a
+    rank default
+      stop 3
+    end select
+  end subroutine foo_s
+
+end program foo_p