| ! { dg-do run } |
| ! Tests the fic for PR44582, where gfortran was found to |
| ! produce an incorrect result when the result of a function |
| ! was aliased by a host or use associated variable, to which |
| ! the function is assigned. In these cases a temporary is |
| ! required in the function assignments. The check has to be |
| ! rather restrictive. Whilst the cases marked below might |
| ! not need temporaries, the TODOs are going to be tough. |
| ! |
| ! Reported by Yin Ma <yin@absoft.com> and |
| ! elaborated by Tobias Burnus <burnus@gcc.gnu.org> |
| ! |
| module foo |
| INTEGER, PARAMETER :: ONE = 1 |
| INTEGER, PARAMETER :: TEN = 10 |
| INTEGER, PARAMETER :: FIVE = TEN/2 |
| INTEGER, PARAMETER :: TWO = 2 |
| integer :: foo_a(ONE) |
| integer :: check(ONE) = TEN |
| LOGICAL :: abort_flag = .false. |
| contains |
| function foo_f() |
| integer :: foo_f(ONE) |
| foo_f = -FIVE |
| foo_f = foo_a - foo_f |
| end function foo_f |
| subroutine bar |
| foo_a = FIVE |
| ! This aliases 'foo_a' by host association. |
| foo_a = foo_f () |
| if (any (foo_a .ne. check)) call myabort (0) |
| end subroutine bar |
| subroutine myabort(fl) |
| integer :: fl |
| print *, fl |
| abort_flag = .true. |
| end subroutine myabort |
| end module foo |
| |
| function h_ext() |
| use foo |
| integer :: h_ext(ONE) |
| h_ext = -FIVE |
| h_ext = FIVE - h_ext |
| end function h_ext |
| |
| function i_ext() result (h) |
| use foo |
| integer :: h(ONE) |
| h = -FIVE |
| h = FIVE - h |
| end function i_ext |
| |
| subroutine tobias |
| use foo |
| integer :: a(ONE) |
| a = FIVE |
| call sub1(a) |
| if (any (a .ne. check)) call myabort (1) |
| contains |
| subroutine sub1(x) |
| integer :: x(ONE) |
| ! 'x' is aliased by host association in 'f'. |
| x = f() |
| end subroutine sub1 |
| function f() |
| integer :: f(ONE) |
| f = ONE |
| f = a + FIVE |
| end function f |
| end subroutine tobias |
| |
| program test |
| use foo |
| implicit none |
| common /foo_bar/ c |
| integer :: a(ONE), b(ONE), c(ONE), d(ONE) |
| interface |
| function h_ext() |
| use foo |
| integer :: h_ext(ONE) |
| end function h_ext |
| end interface |
| interface |
| function i_ext() result (h) |
| use foo |
| integer :: h(ONE) |
| end function i_ext |
| end interface |
| |
| a = FIVE |
| ! This aliases 'a' by host association |
| a = f() |
| if (any (a .ne. check)) call myabort (2) |
| a = FIVE |
| if (any (f() .ne. check)) call myabort (3) |
| call bar |
| foo_a = FIVE |
| ! This aliases 'foo_a' by host association. |
| foo_a = g () |
| if (any (foo_a .ne. check)) call myabort (4) |
| a = FIVE |
| a = h() ! TODO: Needs no temporary |
| if (any (a .ne. check)) call myabort (5) |
| a = FIVE |
| a = i() ! TODO: Needs no temporary |
| if (any (a .ne. check)) call myabort (6) |
| a = FIVE |
| a = h_ext() ! Needs no temporary - was OK |
| if (any (a .ne. check)) call myabort (15) |
| a = FIVE |
| a = i_ext() ! Needs no temporary - was OK |
| if (any (a .ne. check)) call myabort (16) |
| c = FIVE |
| ! This aliases 'c' through the common block. |
| c = j() |
| if (any (c .ne. check)) call myabort (7) |
| call aaa |
| call tobias |
| if (abort_flag) STOP 1 |
| contains |
| function f() |
| integer :: f(ONE) |
| f = -FIVE |
| f = a - f |
| end function f |
| function g() |
| integer :: g(ONE) |
| g = -FIVE |
| g = foo_a - g |
| end function g |
| function h() |
| integer :: h(ONE) |
| h = -FIVE |
| h = FIVE - h |
| end function h |
| function i() result (h) |
| integer :: h(ONE) |
| h = -FIVE |
| h = FIVE - h |
| end function i |
| function j() |
| common /foo_bar/ cc |
| integer :: j(ONE), cc(ONE) |
| j = -FIVE |
| j = cc - j |
| end function j |
| subroutine aaa() |
| d = TEN - TWO |
| ! This aliases 'd' through 'get_d'. |
| d = bbb() |
| if (any (d .ne. check)) call myabort (8) |
| end subroutine aaa |
| function bbb() |
| integer :: bbb(ONE) |
| bbb = TWO |
| bbb = bbb + get_d() |
| end function bbb |
| function get_d() |
| integer :: get_d(ONE) |
| get_d = d |
| end function get_d |
| end program test |