# Automatic allocation of string in recursive function unexpected result \[issue with \`ifx\` and bug in \`gfortran\` and \`nvfortran\`\]

**URL:** <https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775>\
**Category:** Help\
**Created:** [October 30, 2024, 5:43pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775 "2024-10-30T17:43:04Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![eelis](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@eelis](https://fortran-lang.discourse.group/u/eelis)\
**Post date:** [October 30, 2024, 5:43pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/1 "2024-10-30T17:43:04Z")

</div>

I am playing around with this function

```fortran
recursive function to_string(tree) result(out)
type(btree_t), pointer :: tree
character(len=:), allocatable :: out
character(len=1024) :: ch
select case(tree%binop)
case(0)
  write(ch,"(i0)") int(tree%v)
  out=trim(ch)
case(1)
  out="("//to_string(tree%l)//"+"//to_string(tree%r)//")"
case(2)
  out="("//to_string(tree%l)//"-"//to_string(tree%r)//")"
case(3)
  out="("//to_string(tree%l)//"*"//to_string(tree%r)//")"
case(4)
  out="("//to_string(tree%l)//"/"//to_string(tree%r)//")"
end select
  out=trim(out)
end function to_string

```

It produces randomly unexpected results.  
If I replace it with

```fortran
recursive function to_string_trim(tree) result(out)
type(btree_t), pointer :: tree
character(len=:), allocatable :: out
character(len=1024) :: ch
select case(tree%binop)
case(0)
  write(ch,"(i0)") int(tree%v)
  out=trim(ch)
case(1)
  out="("//trim(to_string(tree%l))//"+"//trim(to_string(tree%r))//")"
case(2)
  out="("//trim(to_string(tree%l))//"-"//trim(to_string(tree%r))//")"
case(3)
  out="("//trim(to_string(tree%l))//"*"//trim(to_string(tree%r))//")"
case(4)
  out="("//trim(to_string(tree%l))//"/"//trim(to_string(tree%r))//")"
end select
end function to_string_trim

```

It works as expected.

Here is the whole code if you wish to try:

```fortran
implicit none
type :: btree_t
  integer :: id=0
  type(btree_t), pointer :: l=>null()
  type(btree_t), pointer :: r=>null()
  integer :: binop=0
  real :: v=0
end type
type :: dummy_t
end type
type :: btree_p
  type(btree_t), pointer :: p=>null()
end type
interface operator(.op.)
  procedure op_dummy_dummy
  procedure op_dummy_btree
  procedure op_btree_dummy
  procedure op_btree_btree
end interface
type(btree_t), pointer :: e
type(dummy_t) :: a
type(btree_p) :: trees(6)
integer, allocatable :: operators(:)
real, allocatable :: values(:)
trees(1) % p=>((a.op.a).op.a).op.a
trees(2) % p=>(a.op.(a.op.a)).op.a
trees(3) % p=>(a.op.a).op.(a.op.a)
trees(4) % p=>((a.op.a).op.a).op.a
trees(5) % p=>(a.op.(a.op.a)).op.a
trees(6) % p=>(a.op.a).op.(a.op.a)
call swap(trees(4) % p)
call swap(trees(5) % p)
call swap(trees(6) % p)
block
integer :: itree
integer :: iop, jop, kop
!tree_loop: do itree=1,6
!do iop=1,4; do jop=1,4; do kop=1,4
itree=3
  e=>trees(itree)%p
  iop=3;jop=2;kop=3
  operators=[iop,jop,kop]
  values=[1.,1.,1.,13.]
  call filltree(e, operators, values)
! if (eval(e)==24) exit tree_loop
! print"(a,a,i0,4x,3(i0,x))",to_string(e),"=",int(eval(e)),iop,jop,kop !this doesn't print correctly
  print"(a,a,i0,4x,3(i0,x))",to_string_trim(e),"=",int(eval(e)),iop,jop,kop
!enddo;enddo;enddo
!end do tree_loop
!print"(a,a,i0,4x,3(i0,x))",to_string(e),"=",int(eval(e)),iop,jop,kop
end block
contains

function op_dummy_dummy(v1,v2) result(out)
type(dummy_t), intent(in) :: v1
type(dummy_t), intent(in) :: v2
type(btree_t), pointer :: a, b, out
allocate(out, a, b)
out%l=>a
out%r=>b
end function op_dummy_dummy 

function op_btree_dummy(a,v2) result(out)
type(btree_t), intent(in), pointer :: a
type(dummy_t), intent(in) :: v2
type(btree_t), pointer :: b, out
allocate(out, b)
out%l=>a
out%r=>b
end function op_btree_dummy

function op_dummy_btree(v1,b) result(out)
type(dummy_t), intent(in) :: v1
type(btree_t), intent(in), pointer :: b
type(btree_t), pointer :: a, out
allocate(out, a)
out%l=>a
out%r=>b
end function op_dummy_btree

function op_btree_btree(a,b) result(out)
type(btree_t), intent(in), pointer :: a
type(btree_t), intent(in), pointer :: b
type(btree_t), pointer :: out
allocate(out)
out%l=>a
out%r=>b
end function op_btree_btree

recursive subroutine filltree(tree, operators, values)
type(btree_t), pointer :: tree, first, second
integer, allocatable :: operators(:)
integer, allocatable :: nextops(:)
real :: values(:)
if (associated(tree%l).and.associated(tree%r)) then
  tree%binop=operators(1)
  operators=operators(2:)
  call filltree(tree%l, operators, values)
  call filltree(tree%r, operators, values)
else
  tree%v=values(1)
  values=values(2:)
end if
end subroutine filltree

recursive subroutine swap(tree)
type(btree_t), pointer :: tree,a,b
a=>tree%l
b=>tree%r
if (tree%binop>0) then
  call swap(a)
  call swap(b)
  tree%l=>b
  tree%r=>a
end if
end subroutine swap

real recursive function eval(tree) result(out)
type(btree_t), pointer :: tree,a,b
a=>tree%l
b=>tree%r
select case (tree%binop)
case(0)
  out=tree%v
case(1)
  out=eval(a)+eval(b)
case(2)
  out=eval(a)-eval(b)
case(3)
  out=eval(a)*eval(b)
case(4)
  out=eval(a)/eval(b)
end select
end function eval

recursive function to_string_l(tree) result(out)
  type(btree_t), pointer :: tree
  character(len=100) :: out
  character(len=1024) :: ch
  select case(tree%binop)
  case(0)
    write(ch,"(i0)") int(tree%v)
    out=trim(ch)
  case(1)
    out="("//trim(to_string(tree%l))//"+"//trim(to_string(tree%r))//")"
  case(2)
    out="("//trim(to_string(tree%l))//"-"//trim(to_string(tree%r))//")"
  case(3)
    out="("//trim(to_string(tree%l))//"*"//trim(to_string(tree%r))//")"
  case(4)
    out="("//trim(to_string(tree%l))//"/"//trim(to_string(tree%r))//")"
  end select
end function to_string_l

recursive function to_string_trim(tree) result(out)
type(btree_t), pointer :: tree
character(len=:), allocatable :: out
character(len=1024) :: ch
select case(tree%binop)
case(0)
  write(ch,"(i0)") int(tree%v)
  out=trim(ch)
case(1)
  out="("//trim(to_string(tree%l))//"+"//trim(to_string(tree%r))//")"
case(2)
  out="("//trim(to_string(tree%l))//"-"//trim(to_string(tree%r))//")"
case(3)
  out="("//trim(to_string(tree%l))//"*"//trim(to_string(tree%r))//")"
case(4)
  out="("//trim(to_string(tree%l))//"/"//trim(to_string(tree%r))//")"
end select
end function to_string_trim

recursive function to_string(tree) result(out)
type(btree_t), pointer :: tree
character(len=:), allocatable :: out
character(len=1024) :: ch
select case(tree%binop)
case(0)
  write(ch,"(i0)") int(tree%v)
  out=trim(ch)
case(1)
  out="("//to_string(tree%l)//"+"//to_string(tree%r)//")"
case(2)
  out="("//to_string(tree%l)//"-"//to_string(tree%r)//")"
case(3)
  out="("//to_string(tree%l)//"*"//to_string(tree%r)//")"
case(4)
  out="("//to_string(tree%l)//"/"//to_string(tree%r)//")"
end select
  out=trim(out)
end function to_string
end

```

example output:  
unexpected: `((1(1*13))=0 3 2 3`  
expected: `((1-1)*(1*13))=0 3 2 3`

Can someone explain why this happens? Moreover, if you change the tree (`itree`) then it works as expected to some other cases.

---

<div class="post-metadata">

**Author:** ![eelis](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@eelis](https://fortran-lang.discourse.group/u/eelis)\
**Post date:** [November 1, 2024, 3:38pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/2 "2024-11-01T15:38:05Z")

</div>

When I compile with `ifx`, I get compiler errors, like this

```auto
bintree.f90(25): error #7496: A non-pointer actual argument shall have a TARGET attribute when associated with a pointer dummy argument. [OP_DUMMY_DUMMY]
trees(1) % p=>((a.op.a).op.a).op.a
-----------------^

```

I don’t have this issue with `gfortran`. Do you think this is standard conforming behavior? Or should I report it?

But, to compile, I needed to change the program a bit:

```fortran
implicit none
type :: btree_t
  integer :: id=0
  type(btree_t), pointer :: l=>null()
  type(btree_t), pointer :: r=>null()
  integer :: binop=0
  real :: v=0
end type
type :: dummy_t
end type
type :: btree_p
  type(btree_t), pointer :: p=>null()
end type
interface operator(.op.)
  procedure op_dummy_dummy
  procedure op_dummy_btree
  procedure op_btree_dummy
  procedure op_btree_btree
end interface
interface op
  procedure op_dummy_dummy
  procedure op_dummy_btree
  procedure op_btree_dummy
  procedure op_btree_btree
end interface
type(btree_t), pointer :: e
type(dummy_t) :: a
type(btree_p) :: trees(6)
integer, allocatable :: operators(:)
real, allocatable :: values(:)
trees(1) % p=>op(op(op(a,a),a),a)
trees(2) % p=>op(op(a,op(a,a)),a)
trees(3) % p=>op(op(a,a),op(a,a))
trees(4) % p=>op(op(op(a,a),a),a)
trees(5) % p=>op(op(a,op(a,a)),a)
trees(6) % p=>op(op(a,a),op(a,a))
call swap(trees(4) % p)
call swap(trees(5) % p)
call swap(trees(6) % p)
block
integer :: itree
integer :: iop, jop, kop
!tree_loop: do itree=1,6
!do iop=1,4; do jop=1,4; do kop=1,4
itree=3
  e=>trees(itree)%p
  iop=3;jop=2;kop=3
  operators=[iop,jop,kop]
  values=[1.,1.,1.,13.]
  call filltree(e, operators, values)
! if (eval(e)==24) exit tree_loop
! print"(a,a,i0,4x,3(i0,x))",to_string(e),"=",int(eval(e)),iop,jop,kop !this doesn't print correctly
  print"(a,a,i0,4x,3(i0,x))",to_string(e),"=",int(eval(e)),iop,jop,kop
!enddo;enddo;enddo
!end do tree_loop
!print"(a,a,i0,4x,3(i0,x))",to_string(e),"=",int(eval(e)),iop,jop,kop
end block
contains

function op_dummy_dummy(v1,v2) result(out)
type(dummy_t), intent(in) :: v1
type(dummy_t), intent(in) :: v2
type(btree_t), pointer :: a, b, out
allocate(out, a, b)
out%l=>a
out%r=>b
end function op_dummy_dummy 

function op_btree_dummy(a,v2) result(out)
type(btree_t), intent(in), pointer :: a
type(dummy_t), intent(in) :: v2
type(btree_t), pointer :: b, out
allocate(out, b)
out%l=>a
out%r=>b
end function op_btree_dummy

function op_dummy_btree(v1,b) result(out)
type(dummy_t), intent(in) :: v1
type(btree_t), intent(in), pointer :: b
type(btree_t), pointer :: a, out
allocate(out, a)
out%l=>a
out%r=>b
end function op_dummy_btree

function op_btree_btree(a,b) result(out)
type(btree_t), intent(in), pointer :: a
type(btree_t), intent(in), pointer :: b
type(btree_t), pointer :: out
allocate(out)
out%l=>a
out%r=>b
end function op_btree_btree

recursive subroutine filltree(tree, operators, values)
type(btree_t), pointer :: tree, first, second
integer, allocatable :: operators(:)
integer, allocatable :: nextops(:)
real :: values(:)
if (associated(tree%l).and.associated(tree%r)) then
  tree%binop=operators(1)
  operators=operators(2:)
  call filltree(tree%l, operators, values)
  call filltree(tree%r, operators, values)
else
  tree%v=values(1)
  values=values(2:)
end if
end subroutine filltree

recursive subroutine swap(tree)
type(btree_t), pointer :: tree,a,b
a=>tree%l
b=>tree%r
if (tree%binop>0) then
  call swap(a)
  call swap(b)
  tree%l=>b
  tree%r=>a
end if
end subroutine swap

real recursive function eval(tree) result(out)
type(btree_t), pointer :: tree,a,b
a=>tree%l
b=>tree%r
select case (tree%binop)
case(0)
  out=tree%v
case(1)
  out=eval(a)+eval(b)
case(2)
  out=eval(a)-eval(b)
case(3)
  out=eval(a)*eval(b)
case(4)
  out=eval(a)/eval(b)
end select
end function eval

recursive function to_string_l(tree) result(out)
  type(btree_t), pointer :: tree
  character(len=100) :: out
  character(len=1024) :: ch
  select case(tree%binop)
  case(0)
    write(ch,"(i0)") int(tree%v)
    out=trim(ch)
  case(1)
    out="("//trim(to_string(tree%l))//"+"//trim(to_string(tree%r))//")"
  case(2)
    out="("//trim(to_string(tree%l))//"-"//trim(to_string(tree%r))//")"
  case(3)
    out="("//trim(to_string(tree%l))//"*"//trim(to_string(tree%r))//")"
  case(4)
    out="("//trim(to_string(tree%l))//"/"//trim(to_string(tree%r))//")"
  end select
end function to_string_l

recursive function to_string_trim(tree) result(out)
type(btree_t), pointer :: tree
character(len=:), allocatable :: out
character(len=1024) :: ch
select case(tree%binop)
case(0)
  write(ch,"(i0)") int(tree%v)
  out=trim(ch)
case(1)
  out="("//trim(to_string(tree%l))//"+"//trim(to_string(tree%r))//")"
case(2)
  out="("//trim(to_string(tree%l))//"-"//trim(to_string(tree%r))//")"
case(3)
  out="("//trim(to_string(tree%l))//"*"//trim(to_string(tree%r))//")"
case(4)
  out="("//trim(to_string(tree%l))//"/"//trim(to_string(tree%r))//")"
end select
end function to_string_trim

recursive function to_string(tree) result(out)
type(btree_t), pointer :: tree
character(len=:), allocatable :: out
character(len=1024) :: ch
select case(tree%binop)
case(0)
  write(ch,"(i0)") int(tree%v)
  out=trim(ch)
case(1)
  out="("//to_string(tree%l)//"+"//to_string(tree%r)//")"
case(2)
  out="("//to_string(tree%l)//"-"//to_string(tree%r)//")"
case(3)
  out="("//to_string(tree%l)//"*"//to_string(tree%r)//")"
case(4)
  out="("//to_string(tree%l)//"/"//to_string(tree%r)//")"
end select
  out=trim(out)
end function to_string
end

```

Then it works correctly. Moreover, I get expected results from both functions. Even with the modified program, `gfortran` produces unexpected results. So I think `gfortran` has a bug.

edit.  
`nvfortran` accepts both versions and output unexpected

```auto
(0*0)=0 3 2 3

```

So, my understanding is that

1. `ifx` has a restriction that is not standard conforming (`gfortran` and `nvfortran` accept it) =\> I guess I should report it?
2. `gfortran` has some bug that produces unexpected results =\> I’ll have to report that.
3. `nvfortran` has a bug too

---

<div class="post-metadata">

**Author:** ![septc](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/septc/32/77_2.png) [@septc](https://fortran-lang.discourse.group/u/septc)\
**Post date:** [November 1, 2024, 7:49pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/3 "2024-11-01T19:49:34Z")

</div>

I’ve just tried the code (but have not read the program yet because very complicated…). Gfortran with no options indeed gave the “unexpected” results `((1(1*13))=0 3 2 3` (even with `target` attached to all variables on the caller side), but `gfortran -fcheck=all` gave this runtime error:

```auto
At line 113 of file test.f90
Fortran runtime error: Array bound mismatch for dimension 1 of array 'values' (4/3)

```

So some problem might exist besides the possible issue of pointers or compiler bugs…?

---

<div class="post-metadata">

**Author:** ![martin](https://avatars.discourse-cdn.com/v4/letter/m/73ab20/32.png) [@martin](https://fortran-lang.discourse.group/u/martin)\
**Post date:** [November 2, 2024, 7:04am UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/4 "2024-11-02T07:04:20Z")

</div>

Fortran has a bug, creating a static variable for length of auxiliary character variables in complex concatenation expressions like this. With recursive functions this, it might cause bugs like this. See [bug: deferred length…](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113797)

---

<div class="post-metadata">

**Author:** ![cmaapic](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/cmaapic/32/659_2.png) [@cmaapic](https://fortran-lang.discourse.group/u/cmaapic)\
**Post date:** [November 2, 2024, 1:56pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/5 "2024-11-02T13:56:19Z")

</div>

Nag reports an error

C:\document\fortran\4th\_edition\_update\examples\>nagfor fortran\_discourse\_04.f90  
NAG Fortran Compiler Release 7.2(Shin-Urayasu) Build 7211  
Extension(NAG): fortran\_discourse\_04.f90, line 53: Missing blank between PRINT and character constant  
detected at PRINT@‘(a,a,i0,4x,3(i0,x))’  
Warning: fortran\_discourse\_04.f90, line 68: Unused dummy variable V1  
Warning: fortran\_discourse\_04.f90, line 68: Unused dummy variable V2  
Warning: fortran\_discourse\_04.f90, line 78: Unused dummy variable V2  
Warning: fortran\_discourse\_04.f90, line 88: Unused dummy variable V1  
Warning: fortran\_discourse\_04.f90, line 115: Unused local variable FIRST  
Warning: fortran\_discourse\_04.f90, line 115: Unused local variable NEXTOPS  
Warning: fortran\_discourse\_04.f90, line 115: Unused local variable SECOND  
Error: fortran\_discourse\_04.f90, line 53: No spacing specified for X edit descriptor  
[NAG Fortran Compiler error termination, 1 error, 8 warnings]

and won’t compile it.

---

<div class="post-metadata">

**Author:** ![septc](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/septc/32/77_2.png) [@septc](https://fortran-lang.discourse.group/u/septc)\
**Post date:** [November 2, 2024, 4:28pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/6 "2024-11-02T16:28:21Z")

</div>

I remember a similar problem posted some time ago about the result variable of allocatable character string (with OpenMP, replied by @martin with a link to the bug report 113797)

> [@Integer or real to character string: bug with gfortran with OpenMP?](https://fortran-lang.discourse.group/t/integer-or-real-to-character-string-bug-with-gfortran-with-openmp/8408/6):
>
> This looks very similar to what is reported in [Bug 113797](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113797).

If this may be related, the runtime error I encountered above might also be a result / side effect of the same possible bug… (but here without OpenMP). FWIW, the last part of the above bug report says:

> ```auto
> typedef character(kind=1) struct
> character(kind=1)[1:slen.1][1:slen.1];
> pstr.2 = 0B;
> slen.1 = 0;
> 
> ```
> 
> Maybe the order here. slen.1 should be set to 0 before the use inside the typedef.  
> That is kinda of the reason why static works (with not openmp)

Also FWIW, I’ve tried changing the main program to a subroutine (to avoid the complication of the main program), and “-fsanitize=address” gave a memory leak of \>1300 bytes.

A workaround might be to wrap the allocatable string to a derived type (like “variable string”) and use it throughout (including the result variables), or more conveniently, use some existing library for a wrapped string type, but the possible compiler bug above (not sure yet) remains…

---

<div class="post-metadata">

**Author:** ![eelis](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@eelis](https://fortran-lang.discourse.group/u/eelis)\
**Post date:** [November 4, 2024, 3:03pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/7 "2024-11-04T15:03:54Z")

</div>

Thank you for posting the output of Nag compiler. It looks like you are using the version that was modified for `ifx` because it could not handle the pointer valued function through an operator. Did you try the original code with the operator approach?

I have to say, I don’t understand why Nag reports an error. I see that it is pointing at the `print` statement. However, I don’t see any problem with it and other compilers seem to be fine with it. Are you able to modify it so that Nag is happy with it?

---

<div class="post-metadata">

**Author:** ![eelis](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@eelis](https://fortran-lang.discourse.group/u/eelis)\
**Post date:** [November 4, 2024, 3:04pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/8 "2024-11-04T15:04:42Z")

</div>

@martin and @septc, thank you for the information! It indeed looks like a similar issue.

---

<div class="post-metadata">

**Author:** ![eelis](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@eelis](https://fortran-lang.discourse.group/u/eelis)\
**Post date:** [November 4, 2024, 4:53pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/9 "2024-11-04T16:53:33Z")

</div>

I tried with `lfortran`, with the original code I get:

```auto
lfortran bintree_original.f90
syntax error: Token '::' is unexpected here
 --> bintree_original.f90:2:6
  |
2 | type :: btree_t
  | ^^ 

syntax error: Token 'end type' is unexpected here
 --> bintree_original.f90:8:1
  |
8 | end type
  | ^^^^^^^^ 

syntax error: Token 'end type' is unexpected here
  --> bintree_original.f90:13:1
   |
13 | end type
   | ^^^^^^^^ 

Note: Please report unclear, confusing or incorrect messages as bugs at
https://github.com/lfortran/lfortran/issues.

```

This is likely due to missing `program` statement at the start of the program. However, when I add it, then I see

```auto
lfortran bintree_with_program.f90 
semantic error: `op` is not defined in the Struct: `dummy_t`
  --> bintree_with_program.f90:26:17
   |
26 | trees(1) % p=>((a.op.a).op.a).op.a
   | ^^^^^^ 

Note: Please report unclear, confusing or incorrect messages as bugs at
https://github.com/lfortran/lfortran/issues.

```

I wonder if the first one is a “known issue”? @certik? The other is more exotic so I can report it.

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [November 4, 2024, 5:14pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/10 "2024-11-04T17:14:59Z")

</div>

@eelis thanks for trying it. Yes, go ahead and report both bugs, we’ll fix it.

---

<div class="post-metadata">

**Author:** ![eelis](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@eelis](https://fortran-lang.discourse.group/u/eelis)\
**Post date:** [November 4, 2024, 7:52pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/11 "2024-11-04T19:52:17Z")

</div>

Thanks for the reply! I reported this for now: [type cannot be declared without program · Issue #5250 · lfortran/lfortran · GitHub](https://github.com/lfortran/lfortran/issues/5250) because it is simple. I am still working on the main issue and will report it.

---

<div class="post-metadata">

**Author:** ![martin](https://avatars.discourse-cdn.com/v4/letter/m/73ab20/32.png) [@martin](https://fortran-lang.discourse.group/u/martin)\
**Post date:** [November 5, 2024, 9:53am UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/12 "2024-11-05T09:53:41Z")

</div>

A static (i.e. global) variable is fatal both with multiple threads as well as with recursive calls. So it is no surprise that this bug bites in both circumstances.

If there is a short reproducer, then it would probably be helpful to add it to the gfortran bug report as additional testcase. It also shows that this is a broader issue.

---

<div class="post-metadata">

**Author:** ![cmaapic](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/cmaapic/32/659_2.png) [@cmaapic](https://fortran-lang.discourse.group/u/cmaapic)\
**Post date:** [November 5, 2024, 12:18pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/13 "2024-11-05T12:18:17Z")

</div>

It is a question of standard conformance The Nag compiler message is

Error: fortran\_discourse\_04.f90, line 53: No spacing specified for X edit descriptor  
[NAG Fortran Compiler error termination, 1 error, 8 warnings]

Line 53

print"(a,a,i0,4x,3(i0,x))“,to\_string(e),”=",int(eval(e)),iop,jop,kop  
^  
No spacing specified for X edit descriptor

Here are extracts from the Fortran 2018 and Fortran 2023 standards.

13.8.1.3 X editing

The nX edit descriptor indicates that the transmission of the next character to or from a record is  
to occur at The nX edit descriptor indicates that the transmission of the next ch  
the character position n characters forward from the current position.

The following is taken from the Fortran 2018 standard

13.8.1.3 X editing  
1 The nX edit descriptor indicates that the transmission of the next character to or from a record is to occur at  
the character position n characters forward from the current position.

Apologies about the loss of formatting. I

Ian

---

<div class="post-metadata">

**Author:** ![eelis](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@eelis](https://fortran-lang.discourse.group/u/eelis)\
**Post date:** [November 5, 2024, 7:14pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/14 "2024-11-05T19:14:19Z")

</div>

Here is a short reproducer:

```fortran
implicit none
type :: btree_t
  type(btree_t), pointer :: l=>null()
  type(btree_t), pointer :: r=>null()
  integer :: binop=0
  real :: v=0
end type
type(btree_t), pointer :: e
type(btree_t), pointer :: b1, b2, b3, b4, left, right
allocate(e, b1, b2, b3, b4, left, right)
left % l => b1
left % r => b2
right % l => b3
right % r => b4
e % l => left
e % r => right
e % binop=3
left%binop=2
right%binop=3
b1%v=1.
b2%v=1.
b3%v=1.
b4%v=13.
print "(a)",to_string(e)
contains

recursive function to_string(tree) result(out)
type(btree_t), pointer :: tree
character(len=:), allocatable :: out
character(len=1024) :: ch
select case(tree%binop)
case(0)
  write(ch,"(i0)") int(tree%v)
  out=trim(ch)
case(1)
  out="("//to_string(tree%l)//"+"//to_string(tree%r)//")"
case(2)
  out="("//to_string(tree%l)//"-"//to_string(tree%r)//")"
case(3)
  out="("//to_string(tree%l)//"*"//to_string(tree%r)//")"
case(4)
  out="("//to_string(tree%l)//"/"//to_string(tree%r)//")"
end select
  out=trim(out)
end function to_string
end

```

It should give the same problem as the original.  
Here is the working version (with `trim()`):

```fortran
implicit none
type :: btree_t
  type(btree_t), pointer :: l=>null()
  type(btree_t), pointer :: r=>null()
  integer :: binop=0
  real :: v=0
end type
type(btree_t), pointer :: e
type(btree_t), pointer :: b1, b2, b3, b4, left, right
allocate(e, b1, b2, b3, b4, left, right)
left % l => b1
left % r => b2
right % l => b3
right % r => b4
e % l => left
e % r => right
e % binop=3
left%binop=2
right%binop=3
b1%v=1.
b2%v=1.
b3%v=1.
b4%v=13.
print "(a)",to_string_trim(e)
contains

recursive function to_string_trim(tree) result(out)
type(btree_t), pointer :: tree
character(len=:), allocatable :: out
character(len=1024) :: ch
select case(tree%binop)
case(0)
  write(ch,"(i0)") int(tree%v)
  out=trim(ch)
case(1)
  out="("//trim(to_string_trim(tree%l))//"+"//trim(to_string_trim(tree%r))//")"
case(2)
  out="("//trim(to_string_trim(tree%l))//"-"//trim(to_string_trim(tree%r))//")"
case(3)
  out="("//trim(to_string_trim(tree%l))//"*"//trim(to_string_trim(tree%r))//")"
case(4)
  out="("//trim(to_string_trim(tree%l))//"/"//trim(to_string_trim(tree%r))//")"
end select
end function to_string_trim
end

```

Edit. Interesting, `nvfortran` produces correct result with this, but not with the original code.

---

<div class="post-metadata">

**Author:** ![eelis](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@eelis](https://fortran-lang.discourse.group/u/eelis)\
**Post date:** [November 5, 2024, 7:17pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/15 "2024-11-05T19:17:44Z")

</div>

OK, thanks! I think I see the problem now: so we should not have edit descriptor `x` but we should always put the spacing as well `1x`, even if it is just “one”. So standard does not allow to omit it.

What if you run this:

```fortran
implicit none
type :: btree_t
  integer :: id=0
  type(btree_t), pointer :: l=>null()
  type(btree_t), pointer :: r=>null()
  integer :: binop=0
  real :: v=0
end type
type :: dummy_t
end type
type :: btree_p
  type(btree_t), pointer :: p=>null()
end type
interface operator(.op.)
  procedure op_dummy_dummy
  procedure op_dummy_btree
  procedure op_btree_dummy
  procedure op_btree_btree
end interface
type(btree_t), pointer :: e
type(dummy_t) :: a
type(btree_p) :: trees(6)
integer, allocatable :: operators(:)
real, allocatable :: values(:)
trees(1) % p=>((a.op.a).op.a).op.a
trees(2) % p=>(a.op.(a.op.a)).op.a
trees(3) % p=>(a.op.a).op.(a.op.a)
trees(4) % p=>((a.op.a).op.a).op.a
trees(5) % p=>(a.op.(a.op.a)).op.a
trees(6) % p=>(a.op.a).op.(a.op.a)
call swap(trees(4) % p)
call swap(trees(5) % p)
call swap(trees(6) % p)
block
integer :: itree
integer :: iop, jop, kop
!tree_loop: do itree=1,6
!do iop=1,4; do jop=1,4; do kop=1,4
itree=3
  e=>trees(itree)%p
  iop=3;jop=2;kop=3
  operators=[iop,jop,kop]
  values=[1.,1.,1.,13.]
  call filltree(e, operators, values)
! if (eval(e)==24) exit tree_loop
! print "(a,a,i0,4x,3(i0,1x))",to_string(e),"=",int(eval(e)),iop,jop,kop !this doesn't print correctly
  print "(a,a,i0,4x,3(i0,1x))",to_string_trim(e),"=",int(eval(e)),iop,jop,kop
!enddo;enddo;enddo
!end do tree_loop
!print"(a,a,i0,4x,3(i0,x))",to_string(e),"=",int(eval(e)),iop,jop,kop
end block
contains

function op_dummy_dummy(v1,v2) result(out)
type(dummy_t), intent(in) :: v1
type(dummy_t), intent(in) :: v2
type(btree_t), pointer :: a, b, out
allocate(out, a, b)
out%l=>a
out%r=>b
end function op_dummy_dummy 

function op_btree_dummy(a,v2) result(out)
type(btree_t), intent(in), pointer :: a
type(dummy_t), intent(in) :: v2
type(btree_t), pointer :: b, out
allocate(out, b)
out%l=>a
out%r=>b
end function op_btree_dummy

function op_dummy_btree(v1,b) result(out)
type(dummy_t), intent(in) :: v1
type(btree_t), intent(in), pointer :: b
type(btree_t), pointer :: a, out
allocate(out, a)
out%l=>a
out%r=>b
end function op_dummy_btree

function op_btree_btree(a,b) result(out)
type(btree_t), intent(in), pointer :: a
type(btree_t), intent(in), pointer :: b
type(btree_t), pointer :: out
allocate(out)
out%l=>a
out%r=>b
end function op_btree_btree

recursive subroutine filltree(tree, operators, values)
type(btree_t), pointer :: tree, first, second
integer, allocatable :: operators(:)
integer, allocatable :: nextops(:)
real :: values(:)
if (associated(tree%l).and.associated(tree%r)) then
  tree%binop=operators(1)
  operators=operators(2:)
  call filltree(tree%l, operators, values)
  call filltree(tree%r, operators, values)
else
  tree%v=values(1)
  values=values(2:)
end if
end subroutine filltree

recursive subroutine swap(tree)
type(btree_t), pointer :: tree,a,b
a=>tree%l
b=>tree%r
if (tree%binop>0) then
  call swap(a)
  call swap(b)
  tree%l=>b
  tree%r=>a
end if
end subroutine swap

real recursive function eval(tree) result(out)
type(btree_t), pointer :: tree,a,b
a=>tree%l
b=>tree%r
select case (tree%binop)
case(0)
  out=tree%v
case(1)
  out=eval(a)+eval(b)
case(2)
  out=eval(a)-eval(b)
case(3)
  out=eval(a)*eval(b)
case(4)
  out=eval(a)/eval(b)
end select
end function eval

recursive function to_string_l(tree) result(out)
  type(btree_t), pointer :: tree
  character(len=100) :: out
  character(len=1024) :: ch
  select case(tree%binop)
  case(0)
    write(ch,"(i0)") int(tree%v)
    out=trim(ch)
  case(1)
    out="("//trim(to_string(tree%l))//"+"//trim(to_string(tree%r))//")"
  case(2)
    out="("//trim(to_string(tree%l))//"-"//trim(to_string(tree%r))//")"
  case(3)
    out="("//trim(to_string(tree%l))//"*"//trim(to_string(tree%r))//")"
  case(4)
    out="("//trim(to_string(tree%l))//"/"//trim(to_string(tree%r))//")"
  end select
end function to_string_l

recursive function to_string_trim(tree) result(out)
type(btree_t), pointer :: tree
character(len=:), allocatable :: out
character(len=1024) :: ch
select case(tree%binop)
case(0)
  write(ch,"(i0)") int(tree%v)
  out=trim(ch)
case(1)
  out="("//trim(to_string(tree%l))//"+"//trim(to_string(tree%r))//")"
case(2)
  out="("//trim(to_string(tree%l))//"-"//trim(to_string(tree%r))//")"
case(3)
  out="("//trim(to_string(tree%l))//"*"//trim(to_string(tree%r))//")"
case(4)
  out="("//trim(to_string(tree%l))//"/"//trim(to_string(tree%r))//")"
end select
end function to_string_trim

recursive function to_string(tree) result(out)
type(btree_t), pointer :: tree
character(len=:), allocatable :: out
character(len=1024) :: ch
select case(tree%binop)
case(0)
  write(ch,"(i0)") int(tree%v)
  out=trim(ch)
case(1)
  out="("//to_string(tree%l)//"+"//to_string(tree%r)//")"
case(2)
  out="("//to_string(tree%l)//"-"//to_string(tree%r)//")"
case(3)
  out="("//to_string(tree%l)//"*"//to_string(tree%r)//")"
case(4)
  out="("//to_string(tree%l)//"/"//to_string(tree%r)//")"
end select
  out=trim(out)
end function to_string
end

```

---

<div class="post-metadata">

**Author:** ![eelis](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@eelis](https://fortran-lang.discourse.group/u/eelis)\
**Post date:** [November 5, 2024, 7:37pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/16 "2024-11-05T19:37:03Z")

</div>

I reported another one [Segmentation fault at compile time · Issue #5262 · lfortran/lfortran · GitHub](https://github.com/lfortran/lfortran/issues/5262) (code slightly modified due to issue #5250)

edit.

Here is another one: [Operator mistaken for a member of a "Struct" · Issue #5263 · lfortran/lfortran · GitHub](https://github.com/lfortran/lfortran/issues/5263) (this is actually the first I noticed that I wanted to report)

---

<div class="post-metadata">

**Author:** ![eelis](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@eelis](https://fortran-lang.discourse.group/u/eelis)\
**Post date:** [November 5, 2024, 7:53pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/17 "2024-11-05T19:53:45Z")

</div>

This is the short producer of the issue I have with `ifx`:

```fortran
program test
implicit none
type :: btree_t
  integer :: id=0
  type(btree_t), pointer :: l=>null()
  type(btree_t), pointer :: r=>null()
  integer :: binop=0
  real :: v=0
end type
type :: dummy_t
end type
type :: btree_p
  type(btree_t), pointer :: p=>null()
end type
interface operator(.op.)
  procedure op_dummy_dummy
  procedure op_dummy_btree
  procedure op_btree_dummy
  procedure op_btree_btree
end interface
type(btree_t), pointer :: e
type(dummy_t) :: a
type(btree_p) :: trees(6)
integer, allocatable :: operators(:)
real, allocatable :: values(:)
trees(1) % p=>((a.op.a).op.a).op.a
trees(2) % p=>(a.op.(a.op.a)).op.a
trees(3) % p=>(a.op.a).op.(a.op.a)
trees(4) % p=>((a.op.a).op.a).op.a
trees(5) % p=>(a.op.(a.op.a)).op.a
trees(6) % p=>(a.op.a).op.(a.op.a)
contains

function op_dummy_dummy(v1,v2) result(out)
type(dummy_t), intent(in) :: v1
type(dummy_t), intent(in) :: v2
type(btree_t), pointer :: a, b, out
allocate(out, a, b)
out%l=>a
out%r=>b
end function op_dummy_dummy 

function op_btree_dummy(a,v2) result(out)
type(btree_t), intent(in), pointer :: a
type(dummy_t), intent(in) :: v2
type(btree_t), pointer :: b, out
allocate(out, b)
out%l=>a
out%r=>b
end function op_btree_dummy

function op_dummy_btree(v1,b) result(out)
type(dummy_t), intent(in) :: v1
type(btree_t), intent(in), pointer :: b
type(btree_t), pointer :: a, out
allocate(out, a)
out%l=>a
out%r=>b
end function op_dummy_btree

function op_btree_btree(a,b) result(out)
type(btree_t), intent(in), pointer :: a
type(btree_t), intent(in), pointer :: b
type(btree_t), pointer :: out
allocate(out)
out%l=>a
out%r=>b
end function op_btree_btree
end program test

```

Output:

```auto
bintree_build.f90(26): error #7496: A non-pointer actual argument shall have a TARGET attribute when associated with a pointer dummy 
argument. [OP_DUMMY_DUMMY]
trees(1) % p=>((a.op.a).op.a).op.a
-----------------^
bintree_build.f90(26): error #7496: A non-pointer actual argument shall have a TARGET attribute when associated with a pointer dummy 
argument. [OP_BTREE_DUMMY]
trees(1) % p=>((a.op.a).op.a).op.a
-----------------------^
bintree_build.f90(27): error #7496: A non-pointer actual argument shall have a TARGET attribute when associated with a pointer dummy 
argument. [OP_DUMMY_DUMMY]
trees(2) % p=>(a.op.(a.op.a)).op.a
----------------------^
bintree_build.f90(27): error #7496: A non-pointer actual argument shall have a TARGET attribute when associated with a pointer dummy 
argument. [OP_DUMMY_BTREE]
trees(2) % p=>(a.op.(a.op.a)).op.a
----------------^
bintree_build.f90(28): error #7496: A non-pointer actual argument shall have a TARGET attribute when associated with a pointer dummy 
argument. [OP_DUMMY_DUMMY]
trees(3) % p=>(a.op.a).op.(a.op.a)
----------------^
bintree_build.f90(28): error #7496: A non-pointer actual argument shall have a TARGET attribute when associated with a pointer dummy 
argument. [OP_DUMMY_DUMMY]
trees(3) % p=>(a.op.a).op.(a.op.a)
----------------------------^
bintree_build.f90(29): error #7496: A non-pointer actual argument shall have a TARGET attribute when associated with a pointer dummy 
argument. [OP_DUMMY_DUMMY]
trees(4) % p=>((a.op.a).op.a).op.a
-----------------^
bintree_build.f90(29): error #7496: A non-pointer actual argument shall have a TARGET attribute when associated with a pointer dummy 
argument. [OP_BTREE_DUMMY]
trees(4) % p=>((a.op.a).op.a).op.a
-----------------------^
bintree_build.f90(30): error #7496: A non-pointer actual argument shall have a TARGET attribute when associated with a pointer dummy 
argument. [OP_DUMMY_DUMMY]
trees(5) % p=>(a.op.(a.op.a)).op.a
----------------------^
bintree_build.f90(30): error #7496: A non-pointer actual argument shall have a TARGET attribute when associated with a pointer dummy 
argument. [OP_DUMMY_BTREE]
trees(5) % p=>(a.op.(a.op.a)).op.a
----------------^
bintree_build.f90(31): error #7496: A non-pointer actual argument shall have a TARGET attribute when associated with a pointer dummy 
argument. [OP_DUMMY_DUMMY]
trees(6) % p=>(a.op.a).op.(a.op.a)
----------------^
bintree_build.f90(31): error #7496: A non-pointer actual argument shall have a TARGET attribute when associated with a pointer dummy 
argument. [OP_DUMMY_DUMMY]
trees(6) % p=>(a.op.a).op.(a.op.a)
----------------------------^
compilation aborted for bintree_build.f90 (code 1)

```

Any `ifx` aficionados here? How do we report this? (I have never filed an `ifx` bug report)

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [November 5, 2024, 8:20pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/18 "2024-11-05T20:20:22Z")

</div>

@eelis awesome thank you! Much appreciated.

---

<div class="post-metadata">

**Author:** ![themos](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/themos/32/521_2.png) [@themos](https://fortran-lang.discourse.group/u/themos)\
**Post date:** [November 6, 2024, 4:01pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/19 "2024-11-06T16:01:56Z")

</div>

Hmm.

> [@eelis](#):
>
> `recursive subroutine filltree(tree, operators, values)`  
> `real :: values(:)`  
> …  
> `values=values(2:)`

violates the rules (10.2.1.2 Intrinsic assignment statement, par 1, section(3), lines 9-10 of J3/24-007) of standard Fortran, VALUES being a non-allocatable array that is not conformable to VALUES(2:).

---

<div class="post-metadata">

**Author:** ![themos](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/themos/32/521_2.png) [@themos](https://fortran-lang.discourse.group/u/themos)\
**Post date:** [November 7, 2024, 12:13pm UTC](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775/20 "2024-11-07T12:13:54Z")

</div>

You may want to consider this code which gets around the ifx error message. For now, I think ifx is wrong to issue that error message. But data-pointer function-results may still have unclear or contradictory behaviour in the Standard. Anyone have a clear, complete understanding of this?

```auto
type(btree_t), pointer :: q1, q2, q3
q1 => a .op. a
q2 => q1 .op. a
q3 => a .op. q1
trees(1)%p => q2 .op. a
trees(2)%p => q3 .op. a
trees(3)%p => q1 .op. q1
trees(4)%p => q2 .op. a
trees(5)%p => q3 .op. a
trees(6)%p => q1 .op. q1

```

[Next page](https://fortran-lang.discourse.group/t/automatic-allocation-of-string-in-recursive-function-unexpected-result-issue-with-ifx-and-bug-in-gfortran-and-nvfortran/8775.md?page=2)
