[fortran] PR99124 - [9/10/11 Regression] ICE in gfc_get_class_from_expr, at fortran/trans-expr.c:541

Message ID CAGkQGiLjBoKHxfse0-=9Y905H=SG2ZsGfH0k5mzkRYo0dURXLw@mail.gmail.com
State New
Headers show
Series
  • [fortran] PR99124 - [9/10/11 Regression] ICE in gfc_get_class_from_expr, at fortran/trans-expr.c:541
Related show

Commit Message

Paul Richard Thomas via Gcc-patches Feb. 23, 2021, 11:52 a.m.
Hi All,

This is a straightforward fix that had the side-effect of uncovering an
invalid testcase, class_assign_4.f90. I had worked up a new test, based on
the one in the PR, and found that another brand determined that it is
invalid according to F2018, C15100.

I was unable to find a way to use a typebound operator with a polymorphic
result and so resorted to correcting class_assign_4.f90 with an operator
interface. This respects the purpose of the test. I have left the commented
out lines in place for the review; these will be removed when committing.

Regtested on FC33/x86_64. OK for 9- to 11-branches?

Paul

Fortran: Fix for class functions as associated target [PR99124].

2021-02-23  Paul Thomas  <pault@gcc.gnu.org>

gcc/fortran
PR fortran/99124
* resolve.c (resolve_fl_procedure): Include class results in
the test for F2018, C15100.
* trans-array.c (get_class_info_from_ss): Do not use the saved
descriptor to obtain the class expression for variables. Use
gfc_get_class_from_expr instead.

gcc/testsuite/
PR fortran/99124
* gfortran.dg/class_defined_operator_2.f03 : New test.
* class_assign_4.f90: Correct the non-conforming elemental
function with an allocatable result with an operator interface
with array dummies and result.

Comments

Tobias Burnus Feb. 23, 2021, 12:30 p.m. | #1
Hi Paul,

On 23.02.21 12:52, Paul Richard Thomas via Gcc-patches wrote:
> This is a straightforward fix that had the side-effect of uncovering an

> invalid testcase, class_assign_4.f90. I had worked up a new test, based on

> the one in the PR, and found that another brand determined that it is

> invalid according to F2018, C15100.


Namely: "C15100  All dummy arguments of an elemental procedure ... shall
not have the POINTER or ALLOCATABLE attribute."

The operator does not have to be elemental – as the fixed test case show.

→ Can you add also a testcase that which triggers the error message you
see in the unpatched  class_assign_4.f90?
> I was unable to find a way to use a typebound operator with a polymorphic

> result


I am confused – the attach testcase does seem to work fine with current
GCC. (And if we don't have such a testcase, it should be added.)

Can you elaborate?

> and so resorted to correcting class_assign_4.f90 with an operator

> interface. This respects the purpose of the test. I have left the commented

> out lines in place for the review; these will be removed when committing.

>

> Regtested on FC33/x86_64. OK for 9- to 11-branches?


The patch itself LGTM, except for testing the newly shown error message
and for the confusion about the type-bound operator.

Thanks,

Tobias

> Fortran: Fix for class functions as associated target [PR99124].

>

> 2021-02-23  Paul Thomas  <pault@gcc.gnu.org>

>

> gcc/fortran

> PR fortran/99124

> * resolve.c (resolve_fl_procedure): Include class results in

> the test for F2018, C15100.

> * trans-array.c (get_class_info_from_ss): Do not use the saved

> descriptor to obtain the class expression for variables. Use

> gfc_get_class_from_expr instead.

>

> gcc/testsuite/

> PR fortran/99124

> * gfortran.dg/class_defined_operator_2.f03 : New test.

> * class_assign_4.f90: Correct the non-conforming elemental

> function with an allocatable result with an operator interface

> with array dummies and result.

-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstrasse 201, 80634 München Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Frank Thürauf
module m
type t1
   integer :: i
contains
    PROCEDURE :: add_t1
    GENERIC :: OPERATOR(+) => add_t1
end type

type, extends(t1):: t2
  integer j
end type
contains
  function add_t1 (a, b) result (c)
    class(t1), intent(in) :: a, b
    class(t1), allocatable :: c
    allocate (c, mold = a)
    c%i = a%i + b%i
    select type(c)
     class is (t2)
      select type(a)
       class is (t2)
        select type(b)
          class is (t2)
            c%j = a%j + b%j
          class default
            c%j = a%j
        end select
      end select
    end select
  end
end module m

use m
type(t1) :: v1, v1a
type(t2) :: v2, v2a
class(t1), allocatable :: c1, c2

v1 = t1(42)
v1a = t1(43)
v2 = t2(11,22)
v2a = t2(55,66)

c1 = v1 + v1a
select type (c1); class is (t1); if (c1%i /= 42 + 43) stop 1; class default; stop 2; end select
c1 = v1; c2 = v1a
c1 = c1 + c2
select type (c1); class is (t1); if (c1%i /= 42 + 43) stop 3; class default; stop 4; end select

c1 = v1 + v2
select type (c1); class is (t1); if (c1%i /= 42 + 11) stop 5; class default; stop 6; end select
c1 = v1; c2 = v2
c1 = c1 + c2
select type (c1); class is (t1); if (c1%i /= 42 + 11) stop 7; class default; stop 8; end select

c1 = v2 + v1
select type (c1); class is (t2); if (c1%i /= 11 + 42.or.c1%j /= 22) stop 9; class default; stop 10; end select
c1 = v2; c2 = v1
c1 = c1 + c2
select type (c1); class is (t2); if (c1%i /= 11 + 42.or.c1%j /= 22) stop 11; class default; stop 12; end select
end
Paul Richard Thomas via Gcc-patches Feb. 23, 2021, 5:39 p.m. | #2
Hi Tobias,

→ Can you add also a testcase that which triggers the error message you
> see in the unpatched  class_assign_4.f90?

> > I was unable to find a way to use a typebound operator with a polymorphic

> > result



> I am confused – the attach testcase does seem to work fine with current

> GCC. (And if we don't have such a testcase, it should be added.)



> Can you elaborate?

>




The polymorphic result must be allocatable or pointer for the dynamic type
to be transmitted. This means that the function cannot be elemental. If the
result of the non-elemental function is an array, gfc responds with:
"Error: Passed-object dummy argument of ‘f’ at (1) must be scalar"
If the procedure declaration is made nopass, the response is:
"Type-bound operator at (1) cannot be NOPASS"

See the attached elemental_result_2.f90, which tests the new error message.

From these points, I concluded that a typebound operator could not provide
the required polymorphic array result. If I am wrong about this, please let
me know and I will change the patch accordingly.

The interface operator does not have these constraints and so was
implemented in class_assign_4.f90.

The patch itself LGTM, except for testing the newly shown error message
> and for the confusion about the type-bound operator.

>


 All done. Note that the patch has changed slightly in resolve.c because
(1) it was the wrong version and (2) it sporadically segfaulted at line
13240.

Thanks

Paul
! { dg-do compile }
!
! Test part of the fix for PR99124 which adds errors for class results
! That violate F2018, C15100.
!
! Contributed by Gerhard Steinmetz  <gscfq@t-online.de>
!
module m
   type t
      integer :: i
   contains
      procedure :: f
      generic :: operator(+) => f
   end type
contains
   elemental function f(a, b) &
   result(c)                     ! { dg-error "shall not have an ALLOCATABLE or POINTER attribute" }
      class(t), intent(in) :: a, b
      class(t), allocatable :: c
      c = t(a%i + b%i)
   end
   elemental function g(a, b) &
   result(c)                     ! { dg-error "shall not have an ALLOCATABLE or POINTER attribute" }
      class(t), intent(in) :: a, b
      class(t), pointer :: c
      c => null ()
   end
   elemental function h(a, b) &  ! { dg-error "must have a scalar result" }
   result(c)                     ! { dg-error "must be dummy, allocatable or pointer" }
      class(t), intent(in) :: a, b
      class(t) :: c(2)
   end
end
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
index 11b5dbc7a03..de62266e96b 100644
--- a/gcc/fortran/resolve.c
+++ b/gcc/fortran/resolve.c
@@ -13051,6 +13051,7 @@ static bool
 resolve_fl_procedure (gfc_symbol *sym, int mp_flag)
 {
   gfc_formal_arglist *arg;
+  bool allocatable_or_pointer;
 
   if (sym->attr.function
       && !resolve_fl_var_and_proc (sym, mp_flag))
@@ -13235,8 +13236,15 @@ resolve_fl_procedure (gfc_symbol *sym, int mp_flag)
   /* F2018, C15100: "The result of an elemental function shall be scalar,
      and shall not have the POINTER or ALLOCATABLE attribute."  The scalar
      pointer is tested and caught elsewhere.  */
+  if (sym->result)
+    allocatable_or_pointer = sym->result->ts.type == BT_CLASS && CLASS_DATA (sym->result) ?
+			     (CLASS_DATA (sym->result)->attr.allocatable
+			      || CLASS_DATA (sym->result)->attr.pointer) :
+			     (sym->result->attr.allocatable
+			      || sym->result->attr.pointer);
+
   if (sym->attr.elemental && sym->result
-      && (sym->result->attr.allocatable || sym->result->attr.pointer))
+      && allocatable_or_pointer)
     {
       gfc_error ("Function result variable %qs at %L of elemental "
 		 "function %qs shall not have an ALLOCATABLE or POINTER "
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index c346183e129..c6725659093 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -1167,8 +1167,11 @@ get_class_info_from_ss (stmtblock_t * pre, gfc_ss *ss, tree *eltype)
       && rhs_ss->info->expr->ts.type == BT_CLASS
       && rhs_ss->info->data.array.descriptor)
     {
-      rhs_class_expr
-	= gfc_get_class_from_expr (rhs_ss->info->data.array.descriptor);
+      if (rhs_ss->info->expr->expr_type != EXPR_VARIABLE)
+	rhs_class_expr
+	  = gfc_get_class_from_expr (rhs_ss->info->data.array.descriptor);
+      else
+	rhs_class_expr = gfc_get_class_from_gfc_expr (rhs_ss->info->expr);
       unlimited_rhs = UNLIMITED_POLY (rhs_ss->info->expr);
       if (rhs_ss->info->expr->expr_type == EXPR_FUNCTION)
 	rhs_function = true;
diff --git a/gcc/testsuite/gfortran.dg/class_assign_4.f90 b/gcc/testsuite/gfortran.dg/class_assign_4.f90
index 517e3121cc8..c6c54bbaed2 100644
--- a/gcc/testsuite/gfortran.dg/class_assign_4.f90
+++ b/gcc/testsuite/gfortran.dg/class_assign_4.f90
@@ -11,17 +11,21 @@ module m
   type :: t1
     integer :: i
   CONTAINS
-    PROCEDURE :: add_t1
-    GENERIC :: OPERATOR(+) => add_t1
+!    PROCEDURE :: add_t1
+!    GENERIC :: OPERATOR(+) => add_t1
   end type
   type, extends(t1) :: t2
     real :: r
   end type
 
+  interface operator(+)
+    module procedure add_t1
+  end interface
+
 contains
-  impure elemental function add_t1 (a, b) result (c)
-    class(t1), intent(in) :: a, b
-    class(t1), allocatable :: c
+  function add_t1 (a, b) result (c)
+    class(t1), intent(in) :: a(:), b(:)
+    class(t1), allocatable :: c(:)
     allocate (c, source = a)
     c%i = a%i + b%i
     select type (c)
Tobias Burnus Feb. 23, 2021, 6:06 p.m. | #3
Hi Paul,

On 23.02.21 18:39, Paul Richard Thomas via Fortran wrote:
>> Can you elaborate?

> The polymorphic result must be allocatable or pointer for the dynamic type

> to be transmitted. This means that the function cannot be elemental. If the

> result of the non-elemental function is an array, gfc responds with:

> "Error: Passed-object dummy argument of ‘f’ at (1) must be scalar"


Ok, I think I understood the issue: The problem is that with 'pass', you
get a scalar as argument; and with scalars, you'd need 'elemental',
which is not permitted.

Sorry, I missed the 'pass' → 'scalar' step. I did get the 'elemental' →
nonalloc step.

> All done. Note that the patch has changed slightly in resolve.c because

> (1) it was the wrong version and (2) it sporadically segfaulted at line

> 13240.


Ups!

LGTM. Thanks for the patch!

Tobias

-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstrasse 201, 80634 München Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Frank Thürauf

Patch

diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
index 11b5dbc7a03..b4dd32163af 100644
--- a/gcc/fortran/resolve.c
+++ b/gcc/fortran/resolve.c
@@ -13051,6 +13051,7 @@  static bool
 resolve_fl_procedure (gfc_symbol *sym, int mp_flag)
 {
   gfc_formal_arglist *arg;
+  bool allocatable_or_pointer;
 
   if (sym->attr.function
       && !resolve_fl_var_and_proc (sym, mp_flag))
@@ -13235,8 +13236,16 @@  resolve_fl_procedure (gfc_symbol *sym, int mp_flag)
   /* F2018, C15100: "The result of an elemental function shall be scalar,
      and shall not have the POINTER or ALLOCATABLE attribute."  The scalar
      pointer is tested and caught elsewhere.  */
+  if (sym->result)
+    allocatable_or_pointer = sym->ts.type == BT_CLASS ?
+			     (CLASS_DATA (sym->result)->attr.allocatable
+			      || CLASS_DATA (sym->result)->attr.pointer) :
+			     (sym->result->attr.allocatable
+			      || sym->result->attr.pointer);
+
   if (sym->attr.elemental && sym->result
-      && (sym->result->attr.allocatable || sym->result->attr.pointer))
+      && sym->result->ts.type != BT_CLASS
+      && allocatable_or_pointer)
     {
       gfc_error ("Function result variable %qs at %L of elemental "
 		 "function %qs shall not have an ALLOCATABLE or POINTER "
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index c346183e129..c6725659093 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -1167,8 +1167,11 @@  get_class_info_from_ss (stmtblock_t * pre, gfc_ss *ss, tree *eltype)
       && rhs_ss->info->expr->ts.type == BT_CLASS
       && rhs_ss->info->data.array.descriptor)
     {
-      rhs_class_expr
-	= gfc_get_class_from_expr (rhs_ss->info->data.array.descriptor);
+      if (rhs_ss->info->expr->expr_type != EXPR_VARIABLE)
+	rhs_class_expr
+	  = gfc_get_class_from_expr (rhs_ss->info->data.array.descriptor);
+      else
+	rhs_class_expr = gfc_get_class_from_gfc_expr (rhs_ss->info->expr);
       unlimited_rhs = UNLIMITED_POLY (rhs_ss->info->expr);
       if (rhs_ss->info->expr->expr_type == EXPR_FUNCTION)
 	rhs_function = true;
diff --git a/gcc/testsuite/gfortran.dg/class_assign_4.f90 b/gcc/testsuite/gfortran.dg/class_assign_4.f90
index 517e3121cc8..c6c54bbaed2 100644
--- a/gcc/testsuite/gfortran.dg/class_assign_4.f90
+++ b/gcc/testsuite/gfortran.dg/class_assign_4.f90
@@ -11,17 +11,21 @@  module m
   type :: t1
     integer :: i
   CONTAINS
-    PROCEDURE :: add_t1
-    GENERIC :: OPERATOR(+) => add_t1
+!    PROCEDURE :: add_t1
+!    GENERIC :: OPERATOR(+) => add_t1
   end type
   type, extends(t1) :: t2
     real :: r
   end type
 
+  interface operator(+)
+    module procedure add_t1
+  end interface
+
 contains
-  impure elemental function add_t1 (a, b) result (c)
-    class(t1), intent(in) :: a, b
-    class(t1), allocatable :: c
+  function add_t1 (a, b) result (c)
+    class(t1), intent(in) :: a(:), b(:)
+    class(t1), allocatable :: c(:)
     allocate (c, source = a)
     c%i = a%i + b%i
     select type (c)