Bug 49802 - [F03] [F08] Wrong code with VALUE, VALUE with arrays/DIMENSION
Summary: [F03] [F08] Wrong code with VALUE, VALUE with arrays/DIMENSION
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 4.7.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Keywords: ice-on-valid-code, rejects-valid
Depends on: 35203
Blocks: F2003 F2008
  Show dependency treegraph
Reported: 2011-07-21 09:04 UTC by Tobias Burnus
Modified: 2016-11-08 14:25 UTC (History)
1 user (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed: 2013-06-17 00:00:00

Patch for the resolver/parse part - not for the actual implementation (1022 bytes, patch)
2011-07-21 09:55 UTC, Tobias Burnus
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Tobias Burnus 2011-07-21 09:04:35 UTC
Fortran 2008 relaxed the constrains with regards to VALUE. While Fortran 2003 only allowed it for objects which can be transferred by pass-by-value (in sprite of BIND(C) dummys/C nonpointer parameters), Fortran 2003 now allows for everything which may be copied in, which is nearly everything.

Fortran 2008 has:

C557  An entity with the VALUE attribute shall be a dummy data object
      that is not an assumed-size array or a coarray, and does not have
      a coarray ultimate component.

C558  An entity with the VALUE attribute shall not have the ALLOCATABLE,

Fortran 2003 has:

C527 (R501)   If the VALUE attribute is specified, the PARAMETER, EXTERNAL,
     attribute shall not be specified.

Thus: DIMENSION has been removed and just attr.codimension/attr.coarray_comp are prohibited - as a dummy with assumed size as there copy-in/copy-out will fail.
Comment 1 Tobias Burnus 2011-07-21 09:20:22 UTC
Additionally, the follow constraint of Fortran 2003 is gone:

C528 (R501)   If the VALUE attribute is specified, the length type
              parameter values shall be omitted or specified by
              initialization expressions.
Comment 2 Tobias Burnus 2011-07-21 09:55:16 UTC
Created attachment 24803 [details]
Patch for the resolver/parse part - not for the actual implementation

Implementation strategy:

* For scalar types, continue to pass by value (for optimization purpose)

* For strings, arrays, and complicated DT: Copy the data and pass by reference.

* For VALUE + OPTIONAL - also for scalars: copy and pass by reference

Note: For generating a copy one needs - as already currently - do a deep copy to capture also the allocatable components.

Example for alloc components with VALUE. The example fails (wrong result) with NAG, ifort, gfortran and g95; pgi gets an ICE and crayftn states "The array syntax statement is not conformable", which also looks bogus.

I believe that the test case is valid Fortran 2003.

implicit none
type t
  integer, allocatable :: A(:)
end type t

integer :: i
type(t) :: x

x%A = [(i, i = 1, 8)]

call by_value(x)
print *, x%A

if (any (x%A /= [(i, i = 1, 8)])) call abort()

  subroutine by_value(y)
    type(t), value :: y
    y%A = [(-10*i, i=1,9)]
    print *, y%A
  end subroutine
Comment 3 Tobias Burnus 2011-07-21 10:13:33 UTC
As postscript: Using strings works - but only as long as the length is known at compile time (as F2003 mandates). If not, the dump looks OK at a glance but it does not work:

   by_value (str, 10);
   by_value (character(kind=1)[1:_y] y, integer(kind=4) _y)
      D.1554 = _y;
      _gfortran_transfer_integer_write (&dt_parm.0, &D.1554, 4);

but the latter does not print the expected "10" but some seemingly random number. Obviously, passing strings by value fails if the length is not known - one should thus go back to pass them by reference after copying.

Test case: Change "(*)" to "(10)" for a working program:

implicit none
character(len=10) :: str

str = "123456789"
call by_value(str)
print *, str
if (str /= "123456789") call abort()

  subroutine by_value(y)
    character(len=*), value :: y
    print *, len(y)
    if (len(y) /= 10) call abort()
    print *, y
    y = "abcdefghij"
    print *, y
    if (str /= "abcdefghij") call abort()
  end subroutine
Comment 4 Tobias Burnus 2011-07-21 10:21:22 UTC
(In reply to comment #3)
>    by_value (character(kind=1)[1:_y] y, integer(kind=4) _y)

Technically, it makes sense that it does not work: The caller passes <m>+<n> bytes: sizeof(str) and sizeof(strlen); in this example: 10 bytes for str and 4 bytes for the length (value: 10). How should the poor callee know which bytes belong to the string length?

That's different to printf(char *format, ...): There one first knows what to expect before the unknown data comes.
Comment 5 Tobias Burnus 2013-03-21 16:19:56 UTC
The following gives an ICE:

call foo()
call foo("abc")
subroutine foo(str)
character(len=3), value, optional :: str
if (present(str)) print *, str
end subroutine foo
Comment 6 Dominique d'Humieres 2013-06-17 15:05:05 UTC
The test in comment #3 (with  "(*)" changed to "(10)") aborts because the test

    if (str /= "abcdefghij") call abort()

fails (str=="123456789"). Is it expected?

I also confirm that compiling the test in comment #5 gives an ICE

pr49802_2.f90:6:0: internal compiler error: in fold_convert_loc, at fold-const.c:2075
 if (present(str)) print *, str
Comment 7 Dominique d'Humieres 2014-03-23 00:23:41 UTC
No idea why I set it to WAITING, moved to NEW.
Comment 8 Dominique d'Humieres 2014-07-20 18:41:26 UTC
> I also confirm that compiling the test in comment #5 gives an ICE

I get the same ICE with the following code

  call pr53876

subroutine pr53876
  TYPE :: individual
    integer :: icomp ! Add an extra component to test offset
  CLASS(individual), DIMENSION(:), ALLOCATABLE :: indv, indv1
  allocate (indv(2), source = [individual(1, [99,999]), &
                               individual(2, [999,9999])])
!  allocate (indv1(2), source = [indv(1),indv(2)])
  print *, fun([indv(1),indv(2)])
  elemental function fun(x) result(res)
     integer :: res
     class(individual), intent(in) :: x
     res = x%genes(1)