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

Strange bug with overloading intrinsic sqrt

Harald1
New Contributor II
1,323 Views

The following (almost) minimal code triggers a strange bug with ifort & ifx 2021.2:

module mod1
  implicit none
  real, parameter :: z = sqrt (0.0)
end module mod1

module mod2
  implicit none
  type t
     real :: a = 0.
  end type
  interface sqrt
     module procedure sqrt
  end interface
contains
  function sqrt (a)
    type(t), intent(in) :: a
    type(t)             :: sqrt
    sqrt% a = a% a
  end function sqrt
end module mod2

program test
  use mod1
  use mod2
  implicit none
  type(t) :: x, y
  y    = sqrt (x)
  y% a = sqrt (x% a)
end program test

 

I obtain the following error:

% ifort intel-sqrt-ifc.f90 
intel-sqrt-ifc.f90(28): error #6284: There is no matching specific function for this generic function reference.   [SQRT]
  y% a = sqrt (x% a)
---------^
compilation aborted for intel-sqrt-ifc.f90 (code 1)

 

The code compiles flawlessly with NAG and with Nvidia.

0 Kudos
14 Replies
FortranFan
Honored Contributor II
1,304 Views

Please submit a support request with Intel online service center if you are able to.

In the meantime, if you need to work your code with Intel Fortran in addition to other compilers, you can try this workaround which I expect will work with those other compilers as well:

program test
  use mod1
  use mod2
  implicit none
  type(t) :: x, y
  y    = sqrt (x)
  block
     intrinsic :: sqrt
     y% a = sqrt (x% a)
  end block
end program test

 

0 Kudos
IanH
Honored Contributor II
1,296 Views

Alternatively, rename the specific procedure.

0 Kudos
FortranFan
Honored Contributor II
1,261 Views
@IanH wrote:
Alternatively, rename the specific procedure.

 

Or make it PRIVATE.

module mod2
  implicit none
  private
  type, public :: t
     real :: a = 0.
  end type
  generic, public :: sqrt => sqrt
contains
  function sqrt (a)
    type(t), intent(in) :: a
    type(t)             :: sqrt
    sqrt% a = a% a
  end function sqrt
end module mod2

 

C:\Temp>ifort /c /standard-semantics /warn:all /stand:f18 intel-sqrt-ifc.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.2.0 Build 20210228_000000
Copyright (C) 1985-2021 Intel Corporation.  All rights reserved.


C:\Temp>

 

0 Kudos
andrew_4619
Honored Contributor II
1,288 Views

My contribution should fix your problem but maybe in not the most helpful. Please consider overloading intrinsics as a similar activity as juggling with chain saws. 

0 Kudos
Harald1
New Contributor II
1,246 Views

@andrew_4619 : I strongly disagree.  I overload intrinsics for use with derived types all the time.  This makes programming much easier.

 

0 Kudos
andrew_4619
Honored Contributor II
1,241 Views

The overloading is perfectly legal and may generate some benefits, each to their own. My problem is that I understand Fortran, when you overload you have changed the meaning of an intrinsic. A third party starting to look at the code  reads "apple" and expects it to be an apple when in fact it may now be a pear. If you made a unique thing e.g sqrt_t than you can still have the same functionality whilst being clearer.

0 Kudos
Steve_Lionel
Honored Contributor III
1,230 Views

You cannot replace an intrinsic (for standard argument types) with generic extension. I recall there was a case recently where the Intel compiler was improperly allowing this in some circumstances. The only thing you can do with extension of a generic intrinsic is to define it for argument lists not specified by the standard.

0 Kudos
FortranFan
Honored Contributor II
1,211 Views

 

@Steve_Lionel wrote:
You cannot replace an intrinsic (for standard argument types) with generic extension. I recall there was a case recently where the Intel compiler was improperly allowing this in some circumstances. The only thing you can do with extension of a generic intrinsic is to define it for argument lists not specified by the standard.

 

 

I don't understand what this means.   The standard, per section 15.4.3 Specification of the procedure interface, suggests it is indeed possible to override an intrinsic procedure in the case of "standard argument types".

The confusion that can come about is with the programmer choice of specific procedure names in a generic interface, the standard asks that it be a nonintrinsic procedure with an explicit interface.   Compiler implementations (e.g., gfortran) have had problems with this from what I've seen.  To the extent a coder doesn't make it too confusing, a conforming processor can be expected to handle overrides such as this: as to whether it's advisable is a different matter altogether. 

 

module m
   private
   generic, public :: sqrt => sqrt
contains
   function sqrt( x ) result( r )
      real, intent(in) :: x
      real :: r
      print *, "Using pocket calculator method:" 
      r = exp( 0.5*log(x) ) 
   end function 
end module
   use m 
   print *, "sqrt(2.0) = ", sqrt(2.0)
end
C:\Temp>ifort /standard-semantics /warn:all /stand:f18 q.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.2.0 Build 20210228_000000
Copyright (C) 1985-2021 Intel Corporation.  All rights reserved.

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

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

C:\Temp>q.exe
 Using pocket calculator method:
 1.414214

C:\Temp>

 

 

The case where Intel compiler was non-conforming had to do with intrinsic operations, not intrinsic procedures.  The standard never intended an override of intrinsic operations but that is different from intrinsic procedures.

 

0 Kudos
Steve_Lionel
Honored Contributor III
1,201 Views

@FortranFan , would you please point to the specific paragraph or lines of the standard that, according to you, allows one to replace an intrinsic procedure through generic extension? I don't think this is correct, especially as it would violate 15.4.3.4.1p2, which says (in part), "The rules specifying how any two procedures with the same generic identifier shall differ are given in 15.4.3.4.5. They ensure that any generic invocation applies to at most one specific procedure."

The same applies to generic operators. You can extend them by adding meanings the standard does not provide, but you can't, for example, make "2+2" call your own addition routine, just as you can't replace SQRT(REAL) unless you completely replace the standard intrinsic name in a scope.

0 Kudos
FortranFan
Honored Contributor II
1,168 Views

 

@Steve_Lionel wrote:
.. would you please point to the specific paragraph or lines of the standard that, according to you, allows one to replace an intrinsic procedure through generic extension? ..

 

It will be more helpful if you first explain what you meant by, "You cannot replace an intrinsic (for standard argument types) with generic extension."  By this statement, did you meant the following code does not conform to the standard? (note: it's a variant of the snippet upthread but the Fortran 2018 GENERIC statement has been replaced by the Fortran 90 and later INTERFACE block to allow parsing with different compilers).  If that is what you meant, then you will find the standard and almost all the compilers disagree. 

module m
   interface sqrt
      module procedure sqrt
   end interface
   public :: sqrt !<-- superfluous; included for one compiler's sake 
contains
   function sqrt( x ) result(r)
      real, intent(in) :: x
      real :: r
      write(*,*) "Using pocket calculator method:"
      r = exp( 0.5*log(x) )
   end function 
end module
   use m, only : sqrt
   real :: x
   x = sqrt(2.0)
   write(*, "('sqrt(2.0) = ', f14.6)") x
end

Here the generic interface identifier is "overriding" the intrinsic SQRT procedure; one then has to employ the INTRINSIC attribute to reference the intrinsic SQRT.  

Arguably what the standard does is effectively permission-by-omission here.   Unlike with defined operations where in section 15.4.3.4.2 Defined operations, paragraph 1, lines 10 thru' 13 (page 305) where the standard states, "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)," there is no corresponding stipulation with intrinsic procedures and my take is it's by design.

The notion of allowing an override of an intrinsic procedure is then spread subtly across section 15.4.3.  And statements such as, "If a generic invocation is consistent with both a specific procedure from an interface and an accessible intrinsic procedure, it is the specific procedure from the interface that is referenced," provide a gentle hint toward its support.  One will be hard-pressed to find a processor conformant to Fortran 90 even that does not compile the code posted in this thread to a program giving the following output:

C:\Temp>f90 q.f90
Compaq Visual Fortran Optimizing Compiler Version 6.6 (Update C)
Copyright 2003 Compaq Computer Corp. All rights reserved.

q.f90
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/subsystem:console
..
/out:q.exe

C:\Temp>q.exe
 Using pocket calculator method:
sqrt(2.0) =       1.414214

C:\Temp>

 

0 Kudos
Steve_Lionel
Honored Contributor III
1,142 Views

You are correct. I was confusing the rule for operators with that for intrinsics.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,273 Views

A generic interface (replacing an intrinsic interface) does not extend the interface with alternate arguments (as is done with C++). It replaces it.

You may have luck defining the interface sqrt to use, for example, three interface functions:

sqrt_t(ArgOfType_t)
sqrt_real(ArgOfType_real)
sqrt_double(ArgOfType_double)

In the case of the implementation of the last two, you would have to hide your generic interface from the intrinsic interface (as mentioned by earlier post or by other means).

Jim Dempsey

0 Kudos
FortranFan
Honored Contributor II
1,263 Views
@jimdempseyatthecove wrote:
A generic interface (replacing an intrinsic interface) does not extend the interface with alternate arguments (as is done with C++). It replaces it. ..

Jim, I don't understand what you mean here.

Fortran standard document only seems to mention the "replaces it" aspect i.e., an override semantics when a generic invocation is consistent with a specific procedure in a generic interface and an intrinsic procedure.  This is not the case with the original post where the generic interface can be viewed as "extending" the interface.

0 Kudos
Harald1
New Contributor II
1,243 Views

@jimdempseyatthecove :

Jim, I do not see any replacement of an intrinsic.  It was always legal to add interfaces to an existing one, which is sort of implicit for the intrinsics.

Let me note that replacing in the main the line

use mod1

by

use mod1, only: z

makes the code compile.  Thus module mod1 is the/a troublemaker.

My question is: how can that happen?

0 Kudos
Reply