public inbox for fortran@gcc.gnu.org
 help / color / mirror / Atom feed
* Overriding intrinsic operators
@ 2021-01-01 16:14 Paul Richard Thomas
       [not found] ` <a23a5712-8381-787e-4583-9ab54bed2a20@stevelionel.com>
  0 siblings, 1 reply; 4+ messages in thread
From: Paul Richard Thomas @ 2021-01-01 16:14 UTC (permalink / raw)
  To: fortran; +Cc: Steve Lionel

[-- Attachment #1: Type: text/plain, Size: 1829 bytes --]

Hi All,

Happy New Year!

I took an interest in a recent clf thread, entitled "comparison between
class(*) instances", and submitted an example of a possible implementation.
I have attached a reduced version of it.

gfortran, back as far as version 7.4.1, gives the expected output:
a & b are type pvar
T
 a & b are type pvar
 F

ifort (IFORT) 2021.1 Beta 20201112 gives:
 a & b are type pvar
 class default: returning false
 class default: returning false
 F
 a & b are type pvar
 class default: returning false
 class default: returning false
 F

This comes about because ifort is using the defined operation to override
the intrinsic uses of the operator as defined in 10.1.5 of the standard.

I believe that gfortran has this one right, since the first paragraph of
15.4.3.4.2 Defined operations has:
"...If the operator is an intrinsic-operator (R608), the number of dummy
arguments shall be consistent with the intrinsic uses of that operator, and
the types, kind type parameters, or ranks of the dummy arguments shall
differ from those required for the intrinsic operation (10.1.5)."

ifort gives the expected result if the interface is moved to the main
program.

Steve, I would be grateful if you would pass this on because my Intel uid
seems to have expired. Of course, your thoughts would be welcome.

The second attachment does away with the select type constructs by
transferring the unlimited polymorphic payloads to deferred length
characters and comparing them. The use of unlimited polymorphic actual
arguments is leading to invalid reads and the loss of 8 bytes in two blocks
because realloc is being finickity about the casting of the arguments.
Also, when u and v carry strings, both storage_size and transfer fail
because the _len field is not used. I will raise PRs on these issues
tomorrow.

Regards

Paul

[-- Attachment #2: equals4.f90 --]
[-- Type: text/x-fortran, Size: 1086 bytes --]

MODULE mytypes
  IMPLICIT none

  TYPE pvar
     character(len=20) :: name
     integer           :: level
  end TYPE pvar

  interface operator (==)
     module procedure pvar_eq
  end interface

contains
  function pvar_eq(a,b)
    implicit none
    class(*), intent(in) ::a,b
    logical ::pvar_eq
    if (.not. same_type_as (a, b)) then
      pvar_eq = .false.
      return
    end if
    select type (a)
      type is (pvar)
      select type (b)
        type is (pvar)
          print *, "a & b are type pvar"
          if((a%level.eq. b%level) .and. (a%name .eq. b%name)) then
            pvar_eq = .true.
          else
            pvar_eq = .false.
          end if
      end select
      class default
        print *, "class default: returning false"
        pvar_eq = .false.
    end select
  end function pvar_eq
end MODULE mytypes

program test_eq
   use mytypes
   implicit none
   type(pvar) x, y
   x = pvar('test 1', 100)
   y = pvar('test 1', 100)
   write(*, *) x == y
   x = pvar('test 1', 100)
   y = pvar('test 2', 100)
   write(*, *) x == y
end program test_eq


[-- Attachment #3: equals5.f90 --]
[-- Type: text/x-fortran, Size: 1156 bytes --]

MODULE mytypes
  IMPLICIT none

  TYPE pvar
     character(len=20) :: name
     integer           :: level
  end TYPE pvar

  interface operator (==)
     module procedure star_eq
  end interface

contains
  function star_eq(a,b)
    implicit none
    class(*), intent(in) ::a,b
    character(len=:), allocatable :: c1, c2
    logical ::star_eq
    integer(8) :: sza, szb
    star_eq = same_type_as (a, b)
    if (.not. star_eq) return
    sza = storage_size (a)/8
    szb = storage_size (b)/8
    if (sza .ne. szb) then
      star_eq = .false.
    else
      allocate(character(len = sza) :: c1)
      allocate(character(len = szb) :: c2)
      c1 = transfer (a, c1)
      c2 = transfer (b, c2)
      star_eq = c1 .eq. c2
    end if
  end function star_eq
end MODULE mytypes

program test_eq
   use mytypes
   implicit none
   type(pvar) :: x, y
   class(*), allocatable :: u, v
   x = pvar('test 1', 100)
   y = pvar('test 1', 100)
   write(*, *) x == y
   u = pvar('test 1', 100)
   v = pvar('test 2', 100)
   write(*, *) u == v
   u = 1.0_4
   v = 2.0_4
   write(*, *) u == v
   v = 1.0_4
   write(*, *) u == v
   deallocate (u,v)
end program test_eq


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

* Re: Overriding intrinsic operators
       [not found] ` <a23a5712-8381-787e-4583-9ab54bed2a20@stevelionel.com>
@ 2021-01-01 18:31   ` Paul Richard Thomas
  2021-01-02  9:45   ` Paul Richard Thomas
  2021-01-03 12:22   ` Paul Richard Thomas
  2 siblings, 0 replies; 4+ messages in thread
From: Paul Richard Thomas @ 2021-01-01 18:31 UTC (permalink / raw)
  To: Steve Lionel; +Cc: fortran

Hi Steve,

Thanks for coming back so promptly. Yes, I was aware of the rules of
generic interfaces and thought for a while that your diagnosis is correct.
I started digging through our interface handling to understand what I would
have to do to fix it. However, my interpretation is that 15.4.3.4.2
overrides the generic interface rules since it says that the table in
10.1.5 stands no matter what.

In fact, there is a practical consideration here in that the version of the
testcase posted to clf leads to a stack overflow because of the infinite
recursion that is caused.

Let's indeed go for an interpretation request. IMHO even if gfortran is
wrong, it leads to a more usable implementation.

Cheers

Paul


On Fri, 1 Jan 2021 at 18:20, Steve Lionel <steve@stevelionel.com> wrote:

> On 1/1/2021 11:14 AM, Paul Richard Thomas wrote:
>
> This comes about because ifort is using the defined operation to override
> the intrinsic uses of the operator as defined in 10.1.5 of the standard.
>
> I believe that gfortran has this one right, since the first paragraph of
> 15.4.3.4.2 Defined operations has:
> "...If the operator is an intrinsic-operator (R608), the number of dummy
> arguments shall be consistent with the intrinsic uses of that operator, and
> the types, kind type parameters, or ranks of the dummy arguments shall
> differ from those required for the intrinsic operation (10.1.5)."
>
> This is a fascinating issue, but I am afraid I must be the bearer of bad
> news - I believe ifort is more right here than gfortran; but I also think
> there is need for an interpretation.
>
>
> Look at this in terms of the rules for generic interfaces that specify
> whether signatures are distinguishable (15.4.3.4.5).  We'll start with:
>
> C1511 Within the scope of a generic operator, if two procedures with that
> identifier have the same number of arguments, one shall have a dummy
> argument that corresponds by position in the argument list to a dummy
> argument of the other that is distinguishable from it.
>
> In equals4.f90, you have a defined operator for == with class(*) dummy
> arguments. The text in 15.4.3.4.2 that says [TKR] "shall differ" really
> wants to say "is distinguishable from". class(*) objects have no type and
> they are type compatible with EVERYTHING! So ifort is not wrong to call the
> defined operator procedure for comparing integers (or in equals5, character
> strings.)  I think the standard needs to use different wording than "shall
> differ" and I'll write up an interp about it. Intrinsic operations should
> be considered built-in generic interfaces that can be "extended", and that
> the rules for distinguishing generics should apply to defined operators.
>
>
> The reason that equals4 works when the defined operator declaration is
> moved to the main program is that it no longer applies to pvar_eq.
>
>
> In support of my position, I observe that NAG Fortran 7.0.7036 behaves
> identically here to ifort, including, for equals5, having star_eq
> recursively call itself until it runs out of stack. I believe that the
> correct resolution is that declaring a defined operator with class(*) dummy
> arguments is a violation of C1511 and should be diagnosed by compilers. I
> know this is not the answer the c.l.f poster wants to hear.
>
>
> ifort DOES have a bug exposed by equals5.f90, in that it complains that
> star_eq is called recursively. As a claimed F18-conforming compiler,
> star_eq is RECURSIVE by default. I will report that to Intel.
>
>
> Steve
>


-- 
"If you can't explain it simply, you don't understand it well enough" -
Albert Einstein

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

* Re: Overriding intrinsic operators
       [not found] ` <a23a5712-8381-787e-4583-9ab54bed2a20@stevelionel.com>
  2021-01-01 18:31   ` Paul Richard Thomas
@ 2021-01-02  9:45   ` Paul Richard Thomas
  2021-01-03 12:22   ` Paul Richard Thomas
  2 siblings, 0 replies; 4+ messages in thread
From: Paul Richard Thomas @ 2021-01-02  9:45 UTC (permalink / raw)
  To: fortran; +Cc: Steve Lionel

This is now PR98498. I have set its status to "waiting", pending an
interpretation request.

Paul


On Fri, 1 Jan 2021 at 18:20, Steve Lionel <steve@stevelionel.com> wrote:

> On 1/1/2021 11:14 AM, Paul Richard Thomas wrote:
>
> This comes about because ifort is using the defined operation to override
> the intrinsic uses of the operator as defined in 10.1.5 of the standard.
>
> I believe that gfortran has this one right, since the first paragraph of
> 15.4.3.4.2 Defined operations has:
> "...If the operator is an intrinsic-operator (R608), the number of dummy
> arguments shall be consistent with the intrinsic uses of that operator, and
> the types, kind type parameters, or ranks of the dummy arguments shall
> differ from those required for the intrinsic operation (10.1.5)."
>
> This is a fascinating issue, but I am afraid I must be the bearer of bad
> news - I believe ifort is more right here than gfortran; but I also think
> there is need for an interpretation.
>
>
> Look at this in terms of the rules for generic interfaces that specify
> whether signatures are distinguishable (15.4.3.4.5).  We'll start with:
>
> C1511 Within the scope of a generic operator, if two procedures with that
> identifier have the same number of arguments, one shall have a dummy
> argument that corresponds by position in the argument list to a dummy
> argument of the other that is distinguishable from it.
>
> In equals4.f90, you have a defined operator for == with class(*) dummy
> arguments. The text in 15.4.3.4.2 that says [TKR] "shall differ" really
> wants to say "is distinguishable from". class(*) objects have no type and
> they are type compatible with EVERYTHING! So ifort is not wrong to call the
> defined operator procedure for comparing integers (or in equals5, character
> strings.)  I think the standard needs to use different wording than "shall
> differ" and I'll write up an interp about it. Intrinsic operations should
> be considered built-in generic interfaces that can be "extended", and that
> the rules for distinguishing generics should apply to defined operators.
>
>
> The reason that equals4 works when the defined operator declaration is
> moved to the main program is that it no longer applies to pvar_eq.
>
>
> In support of my position, I observe that NAG Fortran 7.0.7036 behaves
> identically here to ifort, including, for equals5, having star_eq
> recursively call itself until it runs out of stack. I believe that the
> correct resolution is that declaring a defined operator with class(*) dummy
> arguments is a violation of C1511 and should be diagnosed by compilers. I
> know this is not the answer the c.l.f poster wants to hear.
>
>
> ifort DOES have a bug exposed by equals5.f90, in that it complains that
> star_eq is called recursively. As a claimed F18-conforming compiler,
> star_eq is RECURSIVE by default. I will report that to Intel.
>
>
> Steve
>


-- 
"If you can't explain it simply, you don't understand it well enough" -
Albert Einstein

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

* Re: Overriding intrinsic operators
       [not found] ` <a23a5712-8381-787e-4583-9ab54bed2a20@stevelionel.com>
  2021-01-01 18:31   ` Paul Richard Thomas
  2021-01-02  9:45   ` Paul Richard Thomas
@ 2021-01-03 12:22   ` Paul Richard Thomas
  2 siblings, 0 replies; 4+ messages in thread
From: Paul Richard Thomas @ 2021-01-03 12:22 UTC (permalink / raw)
  To: Steve Lionel; +Cc: fortran

Hi Steve,

> ifort DOES have a bug exposed by equals5.f90, in that it complains that
> star_eq is called recursively. As a claimed F18-conforming compiler,
> star_eq is RECURSIVE by default. I will report that to Intel.
>
Oddly enough, when I patch gfortran to comply with ifort and NAG, it
exposes exactly the same error:-) (The patch is attached to PR98498.)

Cheers

Paul

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

end of thread, other threads:[~2021-01-03 12:23 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-01 16:14 Overriding intrinsic operators Paul Richard Thomas
     [not found] ` <a23a5712-8381-787e-4583-9ab54bed2a20@stevelionel.com>
2021-01-01 18:31   ` Paul Richard Thomas
2021-01-02  9:45   ` Paul Richard Thomas
2021-01-03 12:22   ` Paul Richard Thomas

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).