Skip to content

Commit f598a1c

Browse files
author
Paul Thomas
committed
Fortran: Fix wrong recursive errors and class initialization [PR112407]
2024-04-02 Paul Thomas <pault@gcc.gnu.org> gcc/fortran PR fortran/112407 * resolve.cc (resolve_procedure_expression): Change the test for for recursion in the case of hidden procedures from modules. (resolve_typebound_static): Add warning for possible recursive calls to typebound procedures. * trans-expr.cc (gfc_trans_class_init_assign): Do not apply default initializer to class dummy where component initializers are all null. gcc/testsuite/ PR fortran/112407 * gfortran.dg/pr112407a.f90: New test. * gfortran.dg/pr112407b.f90: New test. (cherry picked from commit 35408b3)
1 parent 9f204cc commit f598a1c

File tree

4 files changed

+164
-4
lines changed

4 files changed

+164
-4
lines changed

gcc/fortran/resolve.cc

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,12 +1950,20 @@ resolve_procedure_expression (gfc_expr* expr)
19501950
|| (sym->attr.function && sym->result == sym))
19511951
return true;
19521952

1953-
/* A non-RECURSIVE procedure that is used as procedure expression within its
1953+
/* A non-RECURSIVE procedure that is used as procedure expression within its
19541954
own body is in danger of being called recursively. */
19551955
if (is_illegal_recursion (sym, gfc_current_ns))
1956-
gfc_warning (0, "Non-RECURSIVE procedure %qs at %L is possibly calling"
1957-
" itself recursively. Declare it RECURSIVE or use"
1958-
" %<-frecursive%>", sym->name, &expr->where);
1956+
{
1957+
if (sym->attr.use_assoc && expr->symtree->name[0] == '@')
1958+
gfc_warning (0, "Non-RECURSIVE procedure %qs from module %qs is "
1959+
" possibly calling itself recursively in procedure %qs. "
1960+
" Declare it RECURSIVE or use %<-frecursive%>",
1961+
sym->name, sym->module, gfc_current_ns->proc_name->name);
1962+
else
1963+
gfc_warning (0, "Non-RECURSIVE procedure %qs at %L is possibly calling"
1964+
" itself recursively. Declare it RECURSIVE or use"
1965+
" %<-frecursive%>", sym->name, &expr->where);
1966+
}
19591967

19601968
return true;
19611969
}
@@ -6624,6 +6632,13 @@ resolve_typebound_static (gfc_expr* e, gfc_symtree** target,
66246632
if (st)
66256633
*target = st;
66266634
}
6635+
6636+
if (is_illegal_recursion ((*target)->n.sym, gfc_current_ns)
6637+
&& !e->value.compcall.tbp->deferred)
6638+
gfc_warning (0, "Non-RECURSIVE procedure %qs at %L is possibly calling"
6639+
" itself recursively. Declare it RECURSIVE or use"
6640+
" %<-frecursive%>", (*target)->n.sym->name, &e->where);
6641+
66276642
return true;
66286643
}
66296644

gcc/fortran/trans-expr.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,7 @@ gfc_trans_class_init_assign (gfc_code *code)
16921692
tree tmp;
16931693
gfc_se dst,src,memsz;
16941694
gfc_expr *lhs, *rhs, *sz;
1695+
gfc_component *cmp;
16951696

16961697
gfc_start_block (&block);
16971698

@@ -1708,6 +1709,21 @@ gfc_trans_class_init_assign (gfc_code *code)
17081709
/* The _def_init is always scalar. */
17091710
rhs->rank = 0;
17101711

1712+
/* Check def_init for initializers. If this is a dummy with all default
1713+
initializer components NULL, return NULL_TREE and use the passed value as
1714+
required by F2018(8.5.10). */
1715+
if (!lhs->ref && lhs->symtree->n.sym->attr.dummy)
1716+
{
1717+
cmp = rhs->ref->next->u.c.component->ts.u.derived->components;
1718+
for (; cmp; cmp = cmp->next)
1719+
{
1720+
if (cmp->initializer)
1721+
break;
1722+
else if (!cmp->next)
1723+
return build_empty_stmt (input_location);
1724+
}
1725+
}
1726+
17111727
if (code->expr1->ts.type == BT_CLASS
17121728
&& CLASS_DATA (code->expr1)->attr.dimension)
17131729
{
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
! { dg-do run }
2+
! Test of an issue found in the investigation of PR112407
3+
! Contributed by Tomas Trnka <trnka@scm.com>
4+
!
5+
module m
6+
private new_t
7+
8+
type s
9+
procedure(),pointer,nopass :: op
10+
end type
11+
12+
type :: t
13+
integer :: i
14+
type (s) :: s
15+
contains
16+
procedure :: new_t
17+
procedure :: bar
18+
procedure :: add_t
19+
generic :: new => new_t, bar
20+
generic, public :: assignment(=) => add_t
21+
final :: final_t
22+
end type
23+
24+
integer :: i = 0, finals = 0
25+
26+
contains
27+
recursive subroutine new_t (arg1, arg2)
28+
class(t), intent(out) :: arg1
29+
type(t), intent(in) :: arg2
30+
i = i + 1
31+
32+
print "(a,2i4)", "new_t", arg1%i, arg2%i
33+
if (i .ge. 10) return
34+
35+
! According to F2018(8.5.10), arg1 should be undefined on invocation, unless
36+
! any sub-components are default initialised. gfc used to set arg1%i = 0.
37+
if (arg1%i .ne. arg2%i) then
38+
arg1%i = arg2%i
39+
call arg1%new(arg2)
40+
endif
41+
end
42+
43+
subroutine bar(arg)
44+
class(t), intent(out) :: arg
45+
call arg%new(t(42, s(new_t)))
46+
end
47+
48+
subroutine add_t (arg1, arg2)
49+
class(t), intent(out) :: arg1
50+
type(t), intent(in) :: arg2
51+
call arg1%new (arg2)
52+
end
53+
54+
impure elemental subroutine final_t (arg1)
55+
type(t), intent(in) :: arg1
56+
finals = finals + 1
57+
end
58+
end
59+
60+
use m
61+
class(t), allocatable :: x
62+
allocate(x)
63+
x%i = 0
64+
call x%new() ! gfortran used to output 10*'new_t'
65+
print "(3i4)", x%i, i, finals ! -||- 0 10 11
66+
!
67+
! The other brands output 2*'new_t' + 42 2 3 and now so does gfc :-)
68+
if (x%i .ne. 42) stop 1
69+
if (i .ne. 2) stop 2
70+
if (finals .ne. 3) stop 3
71+
end
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
! { dg-do compile }
2+
! { dg-options "-std=f2008" }
3+
! Test of an issue found in the investigation of PR112407. The dg-option is
4+
! set to avoid regression once the F2018 RECURSIVE by default in implemented.
5+
! Contributed by Tomas Trnka <trnka@scm.com>
6+
!
7+
module m
8+
private new_t
9+
10+
type s
11+
procedure(),pointer,nopass :: op
12+
end type
13+
14+
type :: t
15+
integer :: i
16+
type (s) :: s
17+
contains
18+
procedure :: new_t
19+
procedure :: bar
20+
procedure :: add_t
21+
generic :: new => new_t, bar
22+
generic, public :: assignment(=) => add_t
23+
final :: final_t
24+
end type
25+
26+
integer :: i = 0, finals = 0
27+
28+
contains
29+
subroutine new_t (arg1, arg2) ! gfortran didn't detect the recursion
30+
class(t), intent(out) :: arg1
31+
type(t), intent(in) :: arg2
32+
i = i + 1
33+
34+
print *, "new_t", arg1%i, arg2%i
35+
if (i .ge. 10) return
36+
37+
if (arg1%i .ne. arg2%i) then
38+
arg1%i = arg2%i
39+
call arg1%new(arg2) ! { dg-warning "possibly calling itself recursively" }
40+
endif
41+
end
42+
43+
subroutine bar(arg)
44+
class(t), intent(out) :: arg
45+
call arg%new(t(42, s(new_t)))
46+
end
47+
48+
subroutine add_t (arg1, arg2)
49+
class(t), intent(out) :: arg1
50+
type(t), intent(in) :: arg2
51+
call arg1%new (arg2)
52+
end
53+
54+
impure elemental subroutine final_t (arg1)
55+
type(t), intent(in) :: arg1
56+
finals = finals + 1
57+
end
58+
end

0 commit comments

Comments
 (0)