public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug fortran/101199] New: program changes the value of a dummy argument
@ 2021-06-24 19:37 ygalklein at gmail dot com
  2021-06-25  5:55 ` [Bug fortran/101199] " ygalklein at gmail dot com
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: ygalklein at gmail dot com @ 2021-06-24 19:37 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101199

            Bug ID: 101199
           Summary: program changes the value of a dummy argument
           Product: gcc
           Version: 11.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: fortran
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ygalklein at gmail dot com
  Target Milestone: ---

I have written the following example code:

```fortran
module mod_original_struct
    implicit none

    private
    public :: original_struct, extended_struct

    type original_struct
        private
        real, PUBLIC :: var1
        real :: var2, var3, var4
        real, dimension(3) :: vec1, vec2

        contains

        private
        procedure, public :: init=>initoriginal_struct
    end type original_struct

    type, extends(original_struct) :: extended_struct
        private
        type(original_struct), dimension(2), public :: origs
        contains
        private
        procedure, public :: init=>initextended_struct, advance
    end type extended_struct

    contains

    subroutine advance(this)
        class(extended_struct), intent(inout) :: this
        print*, 'head of advance, this%var1 = ', this%var1
        call this%init(vec1=this%vec1(:),&
                                vec2=this%vec2(:),&
                                var1=this%var1,&
                                var2=this%var2,&
                                var3=this%var3,&
                                var4=this%var4,&
                                origs=this%origs)
    end subroutine advance

    subroutine initoriginal_struct(this, vec1, vec2, var1, var2, var3, var4,
origs)
        class(original_struct), intent(out) :: this
        real, dimension(3), intent(in) :: vec1, vec2
        real, intent(in) :: var1, var2, var3, var4        
        type(original_struct), intent(in), dimension(2), optional :: origs
        this%vec1(:) = vec1(:)
        this%vec2(:) = vec2(:)
        this%var1 = var1
        this%var2 = var2
        this%var3 = var3
        this%var4 = var4
        if (present(origs)) error stop "initoriginal_struct was called with
origs, this is strange"
    end subroutine initoriginal_struct

    subroutine initextended_struct(this, vec1, vec2, var1, var2, var3, var4,
origs)
        class(extended_struct), intent(out) :: this
        real, dimension(3), intent(in) :: vec1, vec2
        real, intent(in) :: var1, var2, var3, var4       
        type(original_struct), intent(in), dimension(2), optional :: origs   
        print*, 'head of initextended_struct, the input argument var1 = ', var1
        this%vec1(:) = vec1(:)
        this%vec2(:) = vec2(:)
        this%var1 = var1
        this%var2 = var2
        this%var3 = var3
        this%var4 = var4
        if (.not. present(origs)) error stop "initextended_struct was called
without origs"
        this%origs(:) = origs(:)
    end subroutine initextended_struct

end module mod_original_struct

program example
    use mod_original_struct, only: extended_struct, original_struct
    implicit none
    type(original_struct), DIMENSION(2) :: origs
    type(extended_struct) :: extended1
    call origs(1)%init(vec1=[0.5, 0., 0.],&
                        vec2=[0., 0.3, 0.],&
                        var1=3.,&
                        var2=1.2,&
                        var3=0.4,&
                        var4=4.5)
    call origs(2)%init(vec1=[0., 0.8, 0.],&
                        vec2=[0.2, 0., 0.],&
                        var1=4.,&
                        var2=1.5,&
                        var3=0.5,&
                        var4=6.5)
    call extended1%init(vec1=[0., 0., 0.7],&
                         vec2=[0.2, 0., 0.],&
                         var1=10.,&
                         var2=6.,&
                         var3=3.2,&
                         var4=10.,&
                         origs=origs)
    print*, 'bf advance, extended1%var1 = ', extended1%var1
    call extended1%advance()
end program example
```

when compiling with gfortran 11.1, the program compiles succesfully and the
output is:

 head of initextended_struct, the input argument var1 =    10.000000000000000  
   bf advance, extended1%var1 =    10.000000000000000     
 head of advance, this%var1 =    10.000000000000000     
 head of initextended_struct, the input argument var1 =    0.0000000000000000  

One can see that the value of var1 that was sent to init of the extented struct
in the routine advance has changed its value from the line bf the call to init
to the head of init.

This is a failure of the program.

The same happens with gfortran 10.3 and also gfortran 9.3 and also gfortran 8.2
and also 7.3 and also 6.4 and also 5.4 and also 4.8.2

One should note that compiling with intel compiler 2020u4 - compiles
succesfully and the output is:

 head of initextended_struct, the input argument var1 =    10.00000    
 bf advance, extended1%var1 =    10.00000    
 head of advance, this%var1 =    10.00000    
 head of initextended_struct, the input argument var1 =    10.00000 

as one can see - using intel compiler one has no problem and the value does not
change.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug fortran/101199] program changes the value of a dummy argument
  2021-06-24 19:37 [Bug fortran/101199] New: program changes the value of a dummy argument ygalklein at gmail dot com
@ 2021-06-25  5:55 ` ygalklein at gmail dot com
  2021-06-25  5:59 ` ygalklein at gmail dot com
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: ygalklein at gmail dot com @ 2021-06-25  5:55 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101199

--- Comment #1 from ygal klein <ygalklein at gmail dot com> ---
The problem stays for even a smaller example program:

``` fortran
module mod_original_struct
    implicit none

    private
    public :: extended_struct

    type original_struct
        private
        real, PUBLIC :: var1
        contains

        private
        procedure, public :: init=>initoriginal_struct
    end type original_struct

    type, extends(original_struct) :: extended_struct
        private
        contains
        private
        procedure, public :: init=>initextended_struct, advance
    end type extended_struct

    contains

    subroutine advance(this)
        class(extended_struct), intent(inout) :: this
        print*, 'head of advance, this%var1 = ', this%var1
        call this%init(var1=this%var1)
    end subroutine advance

    subroutine initoriginal_struct(this, var1)
        class(original_struct), intent(out) :: this
        real, intent(in) :: var1
        this%var1 = var1
    end subroutine initoriginal_struct

    subroutine initextended_struct(this, var1)
        class(extended_struct), intent(out) :: this
        real, intent(in) :: var1   
        print*, 'head of initextended_struct, the input argument var1 = ', var1
        this%var1 = var1
    end subroutine initextended_struct

end module mod_original_struct

program example
    use mod_original_struct, only: extended_struct
    implicit none
    type(extended_struct) :: extended1
    call extended1%init(var1=10.)
    print*, 'bf advance, extended1%var1 = ', extended1%var1
    call extended1%advance()
end program example
```

This is the wrong output coming from all gfortran versions (4.8.2, 5.4, 6.4,
7.3, 8.2, 9.3, 10.3 and 11.1):

 head of initextended_struct, the input argument var1 =    10.000000000000000  
   bf advance, extended1%var1 =    10.000000000000000     
 head of advance, this%var1 =    10.000000000000000     
 head of initextended_struct, the input argument var1 =    0.0000000000000000 

the dummy argument var1 changed its value at entrance to init from advance.

using intel 2020u4 provides the right output.

as presented in the first comment: The problem

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug fortran/101199] program changes the value of a dummy argument
  2021-06-24 19:37 [Bug fortran/101199] New: program changes the value of a dummy argument ygalklein at gmail dot com
  2021-06-25  5:55 ` [Bug fortran/101199] " ygalklein at gmail dot com
@ 2021-06-25  5:59 ` ygalklein at gmail dot com
  2021-06-25 13:17 ` juergen.reuter at desy dot de
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: ygalklein at gmail dot com @ 2021-06-25  5:59 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101199

--- Comment #2 from ygal klein <ygalklein at gmail dot com> ---
The problem also persists in an example code that is with no extended type:

```fortran
module mod_original_struct
    implicit none

    private
    public :: original_struct

    type original_struct
        private
        real, PUBLIC :: var1
        contains

        private
        procedure, public :: init=>initoriginal_struct, advance
    end type original_struct

    contains

    subroutine advance(this)
        class(original_struct), intent(inout) :: this
        print*, 'head of advance, this%var1 = ', this%var1
        call this%init(var1=this%var1)
    end subroutine advance

    subroutine initoriginal_struct(this, var1)
        class(original_struct), intent(out) :: this
        real, intent(in) :: var1
        print*, 'head of initoriginal_struct, the input argument var1 = ', var1
        this%var1 = var1
    end subroutine initoriginal_struct

end module mod_original_struct

program example
    use mod_original_struct, only: original_struct
    implicit none
    type(original_struct) :: struct1
    call struct1%init(var1=10.)
    print*, 'bf advance, struct1%var1 = ', struct1%var1
    call struct1%advance()
end program example
```

The gfortran wrong output is:

 head of initoriginal_struct, the input argument var1 =    10.000000000000000   
 bf advance, struct1%var1 =    10.000000000000000     
 head of advance, this%var1 =    10.000000000000000     
 head of initoriginal_struct, the input argument var1 =    0.0000000000000000 

using intel 2020u4 provides the right output.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug fortran/101199] program changes the value of a dummy argument
  2021-06-24 19:37 [Bug fortran/101199] New: program changes the value of a dummy argument ygalklein at gmail dot com
  2021-06-25  5:55 ` [Bug fortran/101199] " ygalklein at gmail dot com
  2021-06-25  5:59 ` ygalklein at gmail dot com
@ 2021-06-25 13:17 ` juergen.reuter at desy dot de
  2021-06-25 13:33 ` ygalklein at gmail dot com
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: juergen.reuter at desy dot de @ 2021-06-25 13:17 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101199

Jürgen Reuter <juergen.reuter at desy dot de> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |juergen.reuter at desy dot de

--- Comment #3 from Jürgen Reuter <juergen.reuter at desy dot de> ---
I think that indeed this is not something the compiler needs to do as expected,
as it is an aliasing problem. 
In the advance TBP you are calling again the init routine. The init
routines sets the value of this%var1 to the argument with which it is
called. In this%advance you are calling the init routine with the
argument this%var1. However, in the init routine, the struct1 type
is intent(out), so it is not guaranteed that the value of struct1%var1
is accessible when calling the init routine from an earlier initialization of
that type. That is the aliasing problem: advance calls
the init routine, the init routine creates a new instance of struct1
and you are not guaranteed that you can access the struct1%var1 component.
There are several ways out:
(1) define this in the init routine as intent(inout), very unusual for
    an initializer, but then gfortran does what you expect
(2) define a global instance of struct1 in the module, e.g.
    type(original_struct), save, public :: struct_global
    and in advance then call the (before initialized)
      this%init(struct_global%var1)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug fortran/101199] program changes the value of a dummy argument
  2021-06-24 19:37 [Bug fortran/101199] New: program changes the value of a dummy argument ygalklein at gmail dot com
                   ` (2 preceding siblings ...)
  2021-06-25 13:17 ` juergen.reuter at desy dot de
@ 2021-06-25 13:33 ` ygalklein at gmail dot com
  2021-06-25 13:45 ` juergen.reuter at desy dot de
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: ygalklein at gmail dot com @ 2021-06-25 13:33 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101199

--- Comment #4 from ygal klein <ygalklein at gmail dot com> ---
(In reply to Jürgen Reuter from comment #3)
> I think that indeed this is not something the compiler needs to do as
> expected, as it is an aliasing problem. 
> In the advance TBP you are calling again the init routine. The init
> routines sets the value of this%var1 to the argument with which it is
> called. In this%advance you are calling the init routine with the
> argument this%var1. However, in the init routine, the struct1 type
> is intent(out), so it is not guaranteed that the value of struct1%var1
> is accessible when calling the init routine from an earlier initialization
> of that type. That is the aliasing problem: advance calls
> the init routine, the init routine creates a new instance of struct1
> and you are not guaranteed that you can access the struct1%var1 component.
> There are several ways out:
> (1) define this in the init routine as intent(inout), very unusual for
>     an initializer, but then gfortran does what you expect
> (2) define a global instance of struct1 in the module, e.g.
>     type(original_struct), save, public :: struct_global
>     and in advance then call the (before initialized)
>       this%init(struct_global%var1)

Thank you for the reply.

After posting the bug report - I saw that implementing (inout) as your number 1
suggestion - dodges the problem - though as you mentioned having inout for this
in an init routine is somewhat unnatural.

The 2nd suggestion is something that I was trying to avoid in the first place -
i.e copying a whole type (this minimal example is a small type - but originally
it is a type with a lot of instances and procedures)

In fact - I could have had advance as a function that returns a type - but then
I would be paying the price of copyin assignment of a big type.

Anyway - you conclude that gfortran is behaving as it should and that the fact
that ifort works - is somewhat a coincidence?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug fortran/101199] program changes the value of a dummy argument
  2021-06-24 19:37 [Bug fortran/101199] New: program changes the value of a dummy argument ygalklein at gmail dot com
                   ` (3 preceding siblings ...)
  2021-06-25 13:33 ` ygalklein at gmail dot com
@ 2021-06-25 13:45 ` juergen.reuter at desy dot de
  2021-07-12 14:58 ` tkoenig at gcc dot gnu.org
  2021-07-12 16:26 ` tkoenig at gcc dot gnu.org
  6 siblings, 0 replies; 8+ messages in thread
From: juergen.reuter at desy dot de @ 2021-06-25 13:45 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101199

--- Comment #5 from Jürgen Reuter <juergen.reuter at desy dot de> ---
(In reply to ygal klein from comment #4)
>)
> 
> Thank you for the reply.
> 
> After posting the bug report - I saw that implementing (inout) as your
> number 1 suggestion - dodges the problem - though as you mentioned having
> inout for this in an init routine is somewhat unnatural.
> 
> The 2nd suggestion is something that I was trying to avoid in the first
> place - i.e copying a whole type (this minimal example is a small type - but
> originally it is a type with a lot of instances and procedures)
> 
> In fact - I could have had advance as a function that returns a type - but
> then I would be paying the price of copyin assignment of a big type.
> 
> Anyway - you conclude that gfortran is behaving as it should and that the
> fact that ifort works - is somewhat a coincidence?

Let's see what the gfortran developers have to say about this. In any case it
looks strange if you try to call an init routine from a different TBP of the
same object. An init routine is usually called only at the very instantiation
of the object. If you want a shallow copy then you need a pointer.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug fortran/101199] program changes the value of a dummy argument
  2021-06-24 19:37 [Bug fortran/101199] New: program changes the value of a dummy argument ygalklein at gmail dot com
                   ` (4 preceding siblings ...)
  2021-06-25 13:45 ` juergen.reuter at desy dot de
@ 2021-07-12 14:58 ` tkoenig at gcc dot gnu.org
  2021-07-12 16:26 ` tkoenig at gcc dot gnu.org
  6 siblings, 0 replies; 8+ messages in thread
From: tkoenig at gcc dot gnu.org @ 2021-07-12 14:58 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101199

Thomas Koenig <tkoenig at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |tkoenig at gcc dot gnu.org

--- Comment #6 from Thomas Koenig <tkoenig at gcc dot gnu.org> ---
(In reply to Jürgen Reuter from comment #5)
> (In reply to ygal klein from comment #4)
> >)
> > 
> > Thank you for the reply.
> > 
> > After posting the bug report - I saw that implementing (inout) as your
> > number 1 suggestion - dodges the problem - though as you mentioned having
> > inout for this in an init routine is somewhat unnatural.
> > 
> > The 2nd suggestion is something that I was trying to avoid in the first
> > place - i.e copying a whole type (this minimal example is a small type - but
> > originally it is a type with a lot of instances and procedures)
> > 
> > In fact - I could have had advance as a function that returns a type - but
> > then I would be paying the price of copyin assignment of a big type.
> > 
> > Anyway - you conclude that gfortran is behaving as it should and that the
> > fact that ifort works - is somewhat a coincidence?
> 
> Let's see what the gfortran developers have to say about this. In any case
> it looks strange if you try to call an init routine from a different TBP of
> the same object. An init routine is usually called only at the very
> instantiation of the object. If you want a shallow copy then you need a
> pointer.

I can confirm Jürgen's analysis.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug fortran/101199] program changes the value of a dummy argument
  2021-06-24 19:37 [Bug fortran/101199] New: program changes the value of a dummy argument ygalklein at gmail dot com
                   ` (5 preceding siblings ...)
  2021-07-12 14:58 ` tkoenig at gcc dot gnu.org
@ 2021-07-12 16:26 ` tkoenig at gcc dot gnu.org
  6 siblings, 0 replies; 8+ messages in thread
From: tkoenig at gcc dot gnu.org @ 2021-07-12 16:26 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101199

Thomas Koenig <tkoenig at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |RESOLVED
         Resolution|---                         |INVALID
           See Also|                            |https://gcc.gnu.org/bugzill
                   |                            |a/show_bug.cgi?id=30373

--- Comment #7 from Thomas Koenig <tkoenig at gcc dot gnu.org> ---
This is indeed a problem with aliasing and INTENT(OUT).

When passing this to initoriginal_struct, specifying
intent(out) is telling the compiler that this%var1
contains random garbage, in other words, that you could also write

    subroutine initoriginal_struct(this, var1)
        class(original_struct), intent(out) :: this
        real, intent(in) :: var1
        call random_number(this%var1)
        print*, 'head of initoriginal_struct, the input argument var1 = ', var1
        this%var1 = var1
    end subroutine initoriginal_struct

This will then show up the aliasing problem because var1 is aliased
to this%var1.

gfortran currently does not detect this. There is a longstanding
feature request about this, PR 30373.

Resolving as invalid.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-07-12 16:26 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-24 19:37 [Bug fortran/101199] New: program changes the value of a dummy argument ygalklein at gmail dot com
2021-06-25  5:55 ` [Bug fortran/101199] " ygalklein at gmail dot com
2021-06-25  5:59 ` ygalklein at gmail dot com
2021-06-25 13:17 ` juergen.reuter at desy dot de
2021-06-25 13:33 ` ygalklein at gmail dot com
2021-06-25 13:45 ` juergen.reuter at desy dot de
2021-07-12 14:58 ` tkoenig at gcc dot gnu.org
2021-07-12 16:26 ` tkoenig at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).