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

Associate construct with function returning a pointer

Martin1
New Contributor I
1,269 Views

The code below does not compile with gfortran, but with ifort:

gfortran 8.2.0 gives

assoc_func_intent.f90:38:12:

    call inc(p)

Error: ‘p’ at (1) associated to expression can not be used in a variable definition context (actual argument to INTENT = OUT/INOUT)

Even upon re-reading Metcalf et al., I am not sure whether this is indeed correctly rejected and ifort is at fault. The problem is that the selector get() is both an expression and has the pointer attribute. So it is allowed to change the data associated with p, even if get() is an expression (as ifort assumes) or is gfortran right in rejecting this? Iforts approach in allowing this (and indeed doing the expected) seems at least natural and well-defined.

 

module mod

implicit none
private

public get
public inc

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

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

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

end program assoc_func_intent

0 Kudos
18 Replies
Juergen_R_R
Valued Contributor I
1,269 Views

As far as I read the standard, gfortran and also nagfor are correct in rejecting. Using the 18-007 document (Fortran 2018) standard, 11.1.3.1.1, C1101 (R1104):  "If selector is not a variable [...], neither associate-name nor any subobject thereof shall appear in a variable definition context." Here, selector is not a variable, but an expression, namely the evaluation of the function get whose result is an integer pointer. According to 19.5.1.6.2 the associate name (p in your case) is associated with the target of that pointer, but does not have the pointer attribute. The call of the subroutine inc(p) with the argument being inout meets the criteria of a variable definition context according to 19.6.7.1 point 10, being an "actual argument in a reference to a procedure with an explicit interface (because it is a module procedure) if the corresponding dummy argument has intent(out) or intent(inout)."
 

0 Kudos
FortranFan
Honored Contributor II
1,269 Views

@Martin,

I suggest you submit a support request on this at the Intel Online Support Center (OSC).  And also, call attention to this matter with Steve Lionel (in case he doesn't notice this thread himself), for his input will be valuable as well.

I suggest the above because my own (rather simple-minded) understanding inclines me to believe Intel Fortran is correct with respect to the code you show in the original post, that it conforms to current standard (Fortran 2018, recently published) whereas gfortran is not, perhaps only because gfortran might have remnants of restrictions from the earlier revision i.e., Fortran 2003. .

Current Fortran standard, as posted in Quote #2 by Juergen R., states in section 11.1.3.1.1 with constraint C1101, "If selector is not a variable or is a variable that has a vector subscript, neither associate-name nor any subobject thereof shall appear in a variable definition context (19.6.7)".  Note it references section 19.6.7 for "variable definition context".  Now this section has in paragraph 2, "If a reference to a function appears in a variable definition context the result of the function reference shall be a pointer that is associated with a definable target. That target is the variable that becomes defined or undefined,"  One can then argue the selector in your code is indeed a variable i.e., component i of local object x.  This would be a consequence of an interpretation based on paragraph 2 in section 19.6.7 that within the context of a function reference to a pointer, what one ordinarily thinks of "variable definition" is essentially pointer association (as described in section 19.6.8) and such pointer association is the context where the standard states the ASSOCIATE selector "shall not" appear when it comes to constraint C1101..

Your code in the original post is equivalent to what is shown below which entirely conforms to the standard:

module mod
   type, public :: t
      integer :: i = 5
   end type t
contains
   subroutine inc(i)
      integer, intent(inout) :: i
      i = i + 1
   end subroutine inc
end module mod
   use mod
   type(t) :: x
   print *,x%i
   associate ( p => x%i )
      call inc(p)
   end associate
   print *,x%i
end

So my hunch is the "intent" of the standard is to support code such as yours following the enhancement in Fortran 2008 revision to allow functions returning pointers to appear in a variable definition context, especially considering the code I show here.  The question might be whether the "letter" of the standard agrees with the "intent".

By the way, if your code is not supported by NAg compiler, an explanation could be that is because it too is more of a Fortran 2003 conformant compiler, that it does not yet support the Fortran 2008 enhancement re: pointer reference being a variable.

Just my 2 cents,

 

0 Kudos
Steve_Lionel
Honored Contributor III
1,269 Views

I mostly agree here with FortranFan - the code conforms to Fortran 2008. (F2018 is not relevant here.) I don't agree, though, with his restatement of the code as I don't think that is equivalent.

In the original case, get(x) is a function reference that returns a data pointer. This qualifies as a "variable" according to F2008 (quotes here are from F2018, but this hasn't changed since F2008):

R902 variable is designator
                       or function-reference

C902 (R902) function-reference shall have a data pointer result.

And then for ASSOCIATE:

C1101 (R1104) If selector is not a variable or is a variable that has a vector subscript, neither associate-name nor any subobject thereof shall appear in a variable definition context (19.6.7).

But it is a variable here, so it's perfectly acceptable as an INOUT argument to inc.

Neither gfortran nor nagfor fully support F2008 (gfortran doesn't yet fully support F2003, as far as I know.)

0 Kudos
FortranFan
Honored Contributor II
1,269 Views

Steve Lionel (Ret.) wrote:

I mostly agree here with FortranFan - the code conforms to Fortran 2008. (F2018 is not relevant here.) I don't agree, though, with his restatement of the code as I don't think that is equivalent.

In the original case, get(x) is a function reference that returns a data pointer. This qualifies as a "variable" according to F2008 (quotes here are from F2018, but this hasn't changed since F2008):

R902 variable is designator
                       or function-reference

C902 (R902) function-reference shall have a data pointer result.

..

Re: "F2018 is not relevant here" - It's not just a matter of relevance also of expediency.  If one has taken the time to fully go through each point in section 4.3.3 on Fortran 2008 compatibility that includes items that were *allowed* per Fortran 2008 but which are not permitted now with 2018 and noted the applicability or lack thereof in a given situation, then good.  Otherwise, my suggested good practice for readers will be to base discussion on standard related matters on the current "official" standard which is now Fortran 2018

Re: "don't agree, though, with his restatement of the code as I don't think that is equivalent" - how so?

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,269 Views

Steve,

With respect to post #1, in the PROGRAM section, should TARGET attribute have been required on:

   type(t) :: x

IOW

   type(t), target :: x

i.e. as/was written the get function was (essentially) casting the TARGET attribute to a non-TARGET variable(x. and thus i within x).

Jim Dempsey

0 Kudos
Steve_Lionel
Honored Contributor III
1,269 Views

FF, I don't think your code is equivalent because the critical point is that get(x) is a function returning a pointer. This is the F2008 feature that the other compilers don't support.

Jim, you are right. For correctness, x should have the TARGET attribute. Because TARGET is not one of the attributes that contributes to "characteristics of a dummy argument", so the compiler doesn't detect the problem.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,269 Views

Steve,

Due to the fact (in this example #1) that the function get was a module function, and thus the interface was known (knowable), shouldn't the compiler have asserted the requirement of x having TARGET attribute? IOW shouldn't this be a bug in that no error or warning was issued.

Jim Dempsey

0 Kudos
Steve_Lionel
Honored Contributor III
1,269 Views

No - as I wrote above, there is no requirement in the standard that TARGET attributes match for arguments. In general, this is fine - the function may do something with the dummy as a target internally, but once it returns there is no pointer left. In this case there is, but the compiler can't see that (not from the interface, anyway). The standard places the requirement on the user:

"The TARGET attribute specifies that a data object may have a pointer associated with it (10.2.2). An object without the TARGET attribute shall not have a pointer associated with it."

This is not a constraint, so compilers aren't required to check it (and realistically they can't reliably.)

0 Kudos
Martin1
New Contributor I
1,269 Views

Thanks for the many detailed answers. I have to admit that I got somewhat lost.

So I guess I will open a bug report for gfortran.

0 Kudos
Martin1
New Contributor I
1,269 Views

@Juergen: Thanks for reporting the bug for gfortran!

 

0 Kudos
Steve_Lionel
Honored Contributor III
1,269 Views

I don’t see it as a bug but rather an unimplemented feature. gfortran doesn’t claim to be a F2008 compiler. You can certainly point it out as a missing feature.

0 Kudos
Martin1
New Contributor I
1,269 Views

Ah, that was not clear to me.

0 Kudos
FortranFan
Honored Contributor II
1,269 Views

Steve Lionel (Ret.) wrote:

I don’t see it as a bug but rather an unimplemented feature. gfortran doesn’t claim to be a F2008 compiler. You can certainly point it out as a missing feature.

I disagree with Steve: gfortran "generally" supports the Fortran 2008 feature of pointer reference as a variable, just not in the ASSOCIATE block construct; in fact, gfortran started supporting this Fortran 2008 (and a few other features from that revision) ahead of Intel Fortran.  A developer might consider it a partial implementation but to users it comes across as a defect and it is best handled as a bug report.

0 Kudos
Juergen_R_R
Valued Contributor I
1,269 Views

I disagree with Steve: gfortran "generally" supports the Fortran 2008 feature of pointer reference as a variable, just not in the ASSOCIATE block construct; in fact, gfortran started supporting this Fortran 2008 (and a few other features from that revision) ahead of Intel Fortran.  A developer might consider it a partial implementation but to users it comes across as a defect and it is best handled as a bug report.

I disagree with this. gfortran explicitly states this as an unsupported feature at the end of the page: https://gcc.gnu.org/wiki/Fortran2008Status   ;

But this is all nitpicking, same like taking standards at face value, and complaining that ifort compiles the above code without warning or error when using the flag -std03 (which it shouldn't).

 

0 Kudos
FortranFan
Honored Contributor II
1,269 Views

Juergen R. wrote:

I disagree with Steve: gfortran "generally" supports the Fortran 2008 feature of pointer reference as a variable, just not in the ASSOCIATE block construct; in fact, gfortran started supporting this Fortran 2008 (and a few other features from that revision) ahead of Intel Fortran.  A developer might consider it a partial implementation but to users it comes across as a defect and it is best handled as a bug report.

I disagree with this. gfortran explicitly states this as an unsupported feature at the end of the page: https://gcc.gnu.org/wiki/Fortran2008Status   

But this is all nitpicking, same like taking standards at face value, and complaining that ifort compiles the above code without warning or error when using the flag -std03 (which it shouldn't).

 

The nits in this thread are in other Quotes.

The fact is lots of standard feature implementations with gfortran are partial or too buggy to be useful but they are presented online, including at the gcc.gnu.org site, as being implemented in full starting with a particular version, notwithstanding some instances of a line or a comment elsewhere about that not being the case.  Net effect is there are gfortran users who are negatively impacted and have their time wasted; I know of this first-hand trying to help a retired colleague friend who wanted to do something with Fortran in a pet personal project using gfortran and who gave up due to one issue after another and moved to another language.

Under the circumstances, it's entirely a nit to suggest to users to expend further effort pondering and delineating support requests as a missing feature vs a defect, they are all goddamn bugs, particularly when the gfortran pages indicate something misleading as implemented in full in 6.0, "pointer functions as lvalue" (gee.. umm.. what will it be since lvalue is not part of Fortran standard terminology?); or with 8.0 on parameterized derived types (mostly nonfunctional); on and on. 

0 Kudos
Juergen_R_R
Valued Contributor I
1,269 Views

Well, for us gfortran works perfectly well, it always depends which cornercases you meet. Definitely, gfortran is much more reliable than e.g. Portland which claims to be fully F2003 compliant but definitely isn't.

0 Kudos
Steve_Lionel
Honored Contributor III
1,269 Views

There is one aspect I overlooked earlier. Within the ASSOCIATE construct, the selector (p) is not a pointer. It is an ordinary variable with the TARGET attribute. This is still legal F08.

I had not noticed or seen that ifort fails to issue a warning when F03 checking is enabled. This is a very interesting issue.

In F2008, get(x) is an expression that meets the criteria for being a variable. In F2003, it's just an expression. As such, the associate-name p is not allowed to be used in a "variable definition context", which includes being an actual argument where the corresponding dummy is INTENT(INOUT).  I'm not at all astonished that ifort doesn't catch this, and I will send in a bug report on it.

0 Kudos
Ron_Green
Moderator
1,269 Views

Ifort 19.1.1 released yesterday has a fix for this.

ifort -c -stand f03 t.f90

t.f90(37): warning #8915: F2003 does not allow associate name to appear in a variable definition context.

associate(p => get(x))

0 Kudos
Reply