Message ID | CAGkQGiLjBoKHxfse0-=9Y905H=SG2ZsGfH0k5mzkRYo0dURXLw@mail.gmail.com |
---|---|
State | New |
Headers | show |
Series |
|
Related | show |
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
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)
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
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)