Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28381 Discussions

Associate construct with function returning a pointer to an array

Peil__Oleg
Beginner
1,716 Views

I would like to expand a bit on a topic discussed in Associate construct with function returning a pointer .

The discussion in that post seemed to have concluded with a point that a function returning a pointer to a variable can be safely used as a selector expression in the ASSOCIATE block, provided that the usual restrictions of the standard are satisfied (concerning the use of the associated name in a variable definition context).

Consider now the code below that is a slight modification of the code posted originally by @Martin1 . Specifically, the integer variable `i` is replaced by an array `i(3)`. The code compiles with Intel 19 but seems to work incorrectly: The `inc` function does not modify the content of the array. At the same time, the code works as expected when the associate block is removed and a pointer `ptr` is used instead (commented part of the code).

Explicit checks of addresses show that the address of the associated name `p` in the ASSOCIATE block does not point to the array.

Is there something I am missing in the standard or is this behavior wrong?

The question is not academic. I stumbled upon a similar situation in my own code and found the above post by @Martin1 that seemed to be relevant.

module mod

implicit none
private

public get
public inc

type, public :: t
   integer :: i(3) = [5, 2, 1]
end type t

contains

function get(x) result(p)
   integer, pointer :: p(:)
   type(t), target, intent(in) :: x
   p => x%i
end function get

subroutine inc(i)
   integer, intent(inout) :: i(:)
   i = i + 1
end subroutine inc

end module mod


program assoc_func_intent

use mod
implicit none

type(t) :: x
!integer, pointer :: ptr(:)

print *,x%i
associate(p => get(x))
   call inc(p)
end associate
!   ptr => get(x)
!   call inc(ptr)
print *,x%i

end program assoc_func_intent

 

P.S. I do not know if the issue is still present in the most recent version of the compiler. The latest version that I can personally test is ifort 19.1.3.304 (build 20200925).

0 Kudos
1 Solution
IanH
Honored Contributor II
1,486 Views

However, the problem is that adding the TARGET attribute to `x` changes nothing in the behavior of the posted code (at least in ifort 19). However, in such a case, with `x` being matched in the TARGET attribute with the dummy argument of `get()`, I do not see a good reason why the returned pointer should become undefined.

There are two things going on:

- the TARGET attribute is missing in the original post (a programming error); and

- the compiler has a bug (assuming it claims support for this language feature, which I think is the case for current compilers).

If you report it, the compiler vendor will probably/eventually fix the bug.  If you leave TARGET off in your [production] code, then there is a chance that, one day, it will cause you grief.

I had an impression that a function evaluation is always "an expression". According to 7.1.2.2 function-reference is a primary expression. Do I miss something here?

7.1.2.2 from Fortran 2008 says things the other way around - it says a primary may be a function-reference.  That doesn't mean, in isolation, that all function-references are primaries.

Fortran 2008 as initially published had some errata in this area, but if you look at Fortran 2018 (or Fortran 2008 with corrigenda) you will see that a variable may be a function-reference too.

The ambiguity as to whether an isolated function-reference as the selector in an associate statement is an primary in an expression or a variable is resolved in Fortran 2018 by (somewhat circular) constraint C1104.  Similar constraints appear for other syntax rules, where such resolution is required (actual arguments, for example).

View solution in original post

0 Kudos
12 Replies
IanH
Honored Contributor II
1,648 Views

While there's probably a compiler bug here, the code, as posted, is non-conforming for the same reason raised in the previous thread - the pointer function result becomes undefined in this case on completion of execution of the function, because it is associated with a dummy pointer argument that is in turn associated with an actual argument that does not have the TARGET attribute.

 

0 Kudos
Peil__Oleg
Beginner
1,615 Views

I understood the comment of Steve on the TARGET attribute differently: The compiler does not have to check that all TARGET attributes match, this is a responsibility of the programmer. But a missing TARGET attribute does not violate the standard, it may just lead to an undefined behavior.

However, as I have now realized the code I posted violates the standard in another way: The associate name `p` is used here in a variable definition context because the dummy argument of function `inc` has INTENT(INOUT). And since, in our case, the selector is not a variable (but a pointer return value of a function) this is prohibited. This is exactly the point I overlooked in the standard.

So, the bug here is that the compiler does not catch these situations and does not issue an error. This is something that Steve points out later in the old post. Case closed.

0 Kudos
FortranFan
Honored Contributor II
1,567 Views

 

 

@Piel__Oleg wrote:
.. However, as I have now realized the code I posted violates the standard in another way: The associate name `p` is used here in a variable definition context because the dummy argument of function `inc` has INTENT(INOUT). And since, in our case, the selector is not a variable (but a pointer return value of a function) this is prohibited. This is exactly the point I overlooked in the standard. ..

 

 

@Peil__Oleg ,

For whatever is worth, I do not think your conclusion above is correct.  My view is here the prohibition in the standard with the selector is with respect to "pointer association context," for it is a function return pointer in this instance.  The standard does not prohibit, from what I can see, the target of said pointer to appear in a variable definition context and to me, that is what is relevant in the subprogram invocation in the ASSOCIATE construct via the associate-name 'p'.

Say the code in the original post is made to conform with TARGET attribute on variable 'x' in the main program, say "type(t), target :: x".  That the compiler does not refine the target in such a modified program of the one in the original post is, in my opinion, a bug.

0 Kudos
Peil__Oleg
Beginner
1,530 Views

@FortranFan  Examining sections 8.1.3.1-3 (on the ASSOCIATE construct) of the standard leaves me with an impression that the intent of the authors was to avoid assignments or other modifying operations to/on temporary variables storing a result of an expression. At the same time, it looks like the case of the result being a pointer to a variable was not taken into consideration. For in this case it can be completely legitimate to modify the value through that pointer, even if the latter is a temporary object by itself. That said, the standard in its current form seems to consider any selector containing an expression as a non-variable to which all these restrictions about "variable definition context" apply.

One can say that `p` plays two roles simultaneously: On one hand, it is a result of an expression and, as such, cannot appear in a "variable definition context"; on the other hand, it is a pointer to target which might be suitable for "variable definition context".

As of version 19, the Intel compiler seems to allow assignments to `p` (i.e., no compiler error is issued) but the compiled program does not work as expected (undefined behavior). GNU Fortran (version 9), by the way, simply issues a compilation error complaining about `p` being associated to an expression, that is formally following the standard.

Perhaps, the standard could have been refined by treating pointer selectors within associated blocks differently. For instance, if it is possible to establish that the returned pointer is pointer-associated with a variable declared as TARGET, then the corresponding associate-name may appear in a "variable definition context". But this is a question to the standard committee. From my side, I can only say that such a possibility would be very useful because pointer functions are quite common in programs using encapsulated objects.

0 Kudos
IanH
Honored Contributor II
1,522 Views

 

I understood the comment of Steve on the TARGET attribute differently: The compiler does not have to check that all TARGET attributes match, this is a responsibility of the programmer. But a missing TARGET attribute does not violate the standard, it may just lead to an undefined behavior.

Separate to the probable compiler bug...

"Undefined behaviour" is a term from other languages that means that a program violates the rules of the relevant language standard.

You can associate an actual argument without the TARGET attribute with a dummy argument that has the TARGET attribute - that in isolation is not problematic (and hence not something that compilers will warn you about).  But in that case, pointers that are associated with some part of actual argument become undefined when the procedure completes become undefined.  If such a pointer is not used, there's no problem, but for your example code (and the code originally shown in the other linked post), you do use such a pointer - the function result is used in the associate construct.  Use of an undefined pointer like that is non-conforming.

The fact that it is so easy to miss the TARGET attribute and have a hidden error lurking in a program might make some think twice about having things arranged this way.  Work arounds include making the dummy argument an INTENT(IN), POINTER (forces the actual argument to have the TARGET attribute) or by making the component of the derived type itself a pointer (has other downsides).

There have been some interps over the years to sort out some inconsistencies around how and where the result of a reference to a function with a data pointer result can designate a variable, but I don't think there's really anything up for debate with the remainder of this example.  The piece of syntax `get(x)` in as the selector inside the associate statement is not an expression, it is a variable; the associate name `p` therefore designates that same variable and `p` can be used in a variable definition context; modifications to `p` should change the array component of the derived type object `x`.

0 Kudos
Peil__Oleg
Beginner
1,499 Views

@IanH 

You can associate an actual argument without the TARGET attribute with a dummy argument that has the TARGET attribute - that in isolation is not problematic (and hence not something that compilers will warn you about). But in that case, pointers that are associated with some part of actual argument become undefined when the procedure completes become undefined.

I agree with this point, I see that written explicitly in section 12.5.2.4 (clause 11). However, the problem is that adding the TARGET attribute to `x` changes nothing in the behavior of the posted code (at least in ifort 19). However, in such a case, with `x` being matched in the TARGET attribute with the dummy argument of `get()`, I do not see a good reason why the returned pointer should become undefined. I expect it to point exactly to `x%i` because the rules of argument association state that in this case the dummy argument is associated with the actual argument, which is a variable `x` of the main scope. And, as you point out at the end of your message, I expect that the said pointer could be used to modify the content of `x%i`.

The piece of syntax `get(x)` in as the selector inside the associate statement is not an expression, it is a variable;

Could you clarify this? I had an impression that a function evaluation is always "an expression". According to 7.1.2.2 function-reference is a primary expression. Do I miss something here?

0 Kudos
IanH
Honored Contributor II
1,487 Views

However, the problem is that adding the TARGET attribute to `x` changes nothing in the behavior of the posted code (at least in ifort 19). However, in such a case, with `x` being matched in the TARGET attribute with the dummy argument of `get()`, I do not see a good reason why the returned pointer should become undefined.

There are two things going on:

- the TARGET attribute is missing in the original post (a programming error); and

- the compiler has a bug (assuming it claims support for this language feature, which I think is the case for current compilers).

If you report it, the compiler vendor will probably/eventually fix the bug.  If you leave TARGET off in your [production] code, then there is a chance that, one day, it will cause you grief.

I had an impression that a function evaluation is always "an expression". According to 7.1.2.2 function-reference is a primary expression. Do I miss something here?

7.1.2.2 from Fortran 2008 says things the other way around - it says a primary may be a function-reference.  That doesn't mean, in isolation, that all function-references are primaries.

Fortran 2008 as initially published had some errata in this area, but if you look at Fortran 2018 (or Fortran 2008 with corrigenda) you will see that a variable may be a function-reference too.

The ambiguity as to whether an isolated function-reference as the selector in an associate statement is an primary in an expression or a variable is resolved in Fortran 2018 by (somewhat circular) constraint C1104.  Similar constraints appear for other syntax rules, where such resolution is required (actual arguments, for example).

0 Kudos
Peil__Oleg
Beginner
1,428 Views

I would report the issue as a bug if

1). there is a certainty that the code is definitely standard-conforming and the described behavior is indeed a compiler bug;

2). someone could confirm that result does not change if one uses the latest version of the compiler (2021?). Unfortunately, I have access only to version 2019.

Below is a simplified (function `inc` removed because it is irrelevant to the question) code that demonstrates the issue. My expectation is that this code should compile without errors and produce `[6, 3, 2]` as a result (now it produces [5, 2, 1]).

 

module mod
implicit none
private

public get

type, public :: t
   integer :: i(3) = [5, 2, 1]
end type t

contains
function get(x) result(p)
   integer, pointer :: p(:)
   type(t), target, intent(in) :: x
   p => x%i
end function get

end module mod

program assoc_func_intent

use mod
implicit none

type(t), target :: x

print *,x%i
associate(p => get(x))
   p(:) = p(:) + 1
end associate
print *,x%i

end program assoc_func_intent

 

0 Kudos
IanH
Honored Contributor II
1,421 Views

It is standard conforming, it is still a bug in version 2021.1.2.

0 Kudos
FortranFan
Honored Contributor II
1,418 Views

@Peil__Oleg .

Here're my views:

  1. Technically one does NOT file a bug report at Intel OSC but instead one submits a support request.  Intel support staff will then determine if there is a compiler bug at play and if so, they will file a bug report for you.  As a customer, an inquiry you seek to clarify the program behavior with Intel Fortran compiler vis-a-vis your understanding of what the compiler claims to support in its documentation, or the ISO IEC standard is a valid request.  Hence you do not need continued affirmation from readers here or elsewhere to open a support incident: it's your discretion as a customer to do so,
  2. Nonetheless, you can update your test case with a target data object of rank-0 i.e., as a scalar in place of your rank-1 component at present and the program behavior is as I expect - see below.  But now the semantics, as per the standard, is the same in both the cases.  To me, this suggests a faulty interpretation in Intel Fortran compiler of what constitutes an expression that is a pointer function reference when the pointer has rank-1 (or higher rank) i.e., a compiler bug,
  3. IFORT classic compiler as part of oneAPI 2021.1 i.e., the latest version shows the same behavior as what you notice with your rank-1 case using IFORT v19.
  4. In case you were unaware, the latest version of IFORT 2021.1 is available for free to all users as part of oneAPI HPC toolkit (you may need the Base toolkit on certain platforms for debugging facility).  See the Intel website for details.
module mod
implicit none
private

public get

type, public :: t
   integer :: i = 5
end type t

contains
function get(x) result(p)
   integer, pointer :: p
   type(t), target, intent(in) :: x
   p => x%i
end function get

end module mod

program assoc_func_intent

use mod
implicit none

type(t), target :: x

print *,x%i, "; expected is 5"
associate(p => get(x))
   p = p + 1
end associate
print *,x%i, "; expected is 6"

end program assoc_func_intent
C:\Temp>ifort /standard-semantics /warn:all /stand:f18 p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.1.2 Build 20201208_000000
Copyright (C) 1985-2020 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.28.29337.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\Temp>p.exe
 5 ; expected is 5
 6 ; expected is 6

C:\Temp>

 

Peil__Oleg
Beginner
1,364 Views

Thanks to everyone for the discussion and clarifications.

I tried to submit a ticket but apparently something has changed in the policies of Intel Support because they said that they closed the ticket since there was no supported product associated with my account. Well, I find this strange to say the least. I use the Intel compiler on a cluster of an HPC facility and of course the license does not belong to me personally. Does the support expect that I will go through the admins of the cluster to submit a simple ticket?

Somehow, last year this was no such problem and I successfully submitted a ticket with a bug that was eventually fixed.

0 Kudos
Steve_Lionel
Honored Contributor III
1,356 Views

Yes, they do expect that, but what happens depends on the attitude of the particular support person who initially handles your request. The first thing I would do is reopen the request and include the serial number for your license.

 
0 Kudos
Reply