Does an intrinsic module have to be part of the standard?

The question originates from this post: How do i allocate an array of strings? - #55 by ivanpribec

The F2018 intepretation document states in section 14.2.1 says:

A module that is provided as an inherent part of the processor is an intrinsic module. A nonintrinsic module is defined by a module program unit or a means other than Fortran.

Procedures and types defined in an intrinsic module are not themselves intrinsic.

Some Fortran processors provide their own non-standard modules. For example Intel provides the ifport portability module:

program main
  use, non_intrinsic :: ifport
  implicit none
  print *, "hello"
end program

The user does not need to specify the location of the module, the compiler already knows it. Changing the module nature from non_intrinsic to intrinsic I get the following error:

$ ifort test_ifport.f90 
test_ifport.f90(2): error #7002: Error in opening the compiled module file.  Check INCLUDE paths.   [IFPORT]
  use, intrinsic :: ifport

On the other hand, in Intrinsic Module Overview section of the NAG Fortran Compiler documentation, we find the following

The non-standard intrinsic modules supplied by NAG are:
[…]

I’ve added emphasis to the part which matches my understanding of the standard, a Fortran processor can have non-standard intrinsic modules.

This leads then to the question, why does ifport not work with intrinsic attribute, despite being provided as part of the processor?

I suppose the following answers my question:

~/fortran$ cat test_nag.f90 
program test_nag
use, intrinsic :: f90_gc
print *, "it works"
end program
~/fortran$ nagfor -o test_nag test_nag.f90 && ./test_nag 
NAG Fortran Compiler Release 7.1(Hanzomon) Build 7101
[NAG Fortran Compiler normal termination]
 it works

So essentially a compiler vendor has an open path to set themselves apart from the competition by providing the “batteries included”.

Hi @ivanpribec ,

Maybe because at Intel, everything that is non-standard is (by consequence) non-intrinsic (to the Fortran Language Standard itself). And so, everything that is standard conformant (i.e. intrinsic to the Fortran Language), should be compatible with any standard conformant processor.
And indeed, feeding a unit including Intel ifport porting module, could not work if and only if using Intel processors.

Evidently, this is not the same thinking process among all processor vendors, causing the “intrinsic” program you report to compile with NAG processors and possibly fail with all the others not providing the same (vendor specific) functionality. Which to me, does not look right.

I’m not familiar enough with these modules to know whether the vendors provide the sources of them for consumption by other Fortran processors.

Judging by the Intel documentation page, they ship a library libifport.a and a .mod file, which will fail to work with other compilers. Even if the objects in the archive use the same calling conventions as other compilers, the difference in implementation of logicals is one potential issue that could prevent correct usage.

In principle one could attempt to write the module with the same behavior from the description of the routines, and observation of their behavior (i.e. clean-room design).

Intel provides sources for both intrinsic and non-intrinsic modules, but they generally contain only interfaces, they do not include definitions (implementations). Which intrinsically creates a dependency on the vendor specific distribution.

Sure. But circumventing things should not be the spirit when trying to resolve issues, IMO.

At least for Intel MKL, I believe I’ve used the modules together with other compilers like gfortran (but if I recall correctly a different archive file was provided). However I don’t have practical experience with other modules like ifport and ifposix. I can see the modules containing interface definitions are available in the /opt/intel/oneapi/compiler/latest/mac/compiler/include folder.

NAG appears to provide three modules at source level, but this is practically irrelevant, because they won’t have the intrinsic status if reused by other compilers (assuming you have the NAG compiler in the first place):

f90_iostat.f90
f90_kind.f90
f90_stat.f90

Intel Fortran conforms to the standard, from what I see:

C1404 (R1409) If module-nature is INTRINSIC, module-name shall be the name of an intrinsic module.
C1405 (R1409) If module-nature is NON_INTRINSIC, module-name shall be the name of a nonintrinsic module.

IFPORT is not the name of an intrinsic module per the standard, so constraint C1404 (per 23-007r1) is not met and the processor is right to detect and report this.

By the way, starting Fortran 2018, there is some good progress toward tightening up some of the aspects of both nonstandard intrinsic modules as well as nonstandard intrinsic procedures and the processors being required to have the capability to detect and report their usage (it may just be some compiler flag or whatever, but something shall be offered).

But what is an intrinsic module? According to the paragraph I quoted above it is

A module that is provided as an inherent part of the processor is an intrinsic module.

Obviously, NAG sees it’s own f90_* modules as intrinsic ones, and typically the NAG compiler is seen by practitioners as the one with the strictest interpretation of the standard.

“Intrinsic” here means that it is recognized specially by the compiler. Consider intrinsic functions - many compilers provide intrinsic functions not mentioned by the standard. In the case of Intel’s ifport, it’s just an ordinary module the compiler finds by the same process it uses for user modules; it’s not intrinsic.

The purpose of USE, INTRINSIC is to prevent a user module from overriding an intrinsic module. Intel, for example, uses a different file type for the compiled intrinsic modules.

1 Like

But that only applies up to the point where the developer of that compiler (also the standard Editor) has had the time to implement revisions from the standard.

From the NAG website, they have long ways to go to implement current standard (2018). Until they do, the compiler response cannot be seen as conformant by default, it needs study to check whether it is or not.

This line of reasoning extended to modules would allow me to believe the option of having a non-standard intrinsic module is permissible.

Both the standard committee and the vendors will be wise to firm up the language in the standard as to what is an intrinsic module and to update the processor response accordingly.

ISO_FORTRAN_ENV, ISO_C_BINDING, IEEE_ARITHMETIC, etc are recognized by the standard as intrinsic modules and specified in the standard document.

Any arbitrary processor deeming some of it’s compiler developer creations, say f90_kinds, as intrinsic will mostly cause confusion and be harmful than beneficial. Intel has the better approach here.

Oh yes, in principle it has been since Fortran 90 revision that first introduced MODULEs.

To reiterate a separate point re: your apparent motivation with this thread as you state in the original post with a string type: it’s best if such a type does not call for an USE statement a la CHARACTER type. Note intrinsic modules do require USE. For something as basic and crucial as strong, it’s best if it is truly an intrinsic type like CHARACTER.

Yes, that was intentional, just as non-standard intrinsic procedures are permissible, and the standard provides mechanisms for the user to say they want an intrinsic thing instead of a non-intrinsic thing, or vice-versa.

Regardless of the actual mechanism, the goal is generally to be able to distinguish between what external references are a standard part of the Fortran specification, a non-portable compiler-specific capability, or a third-party or in-house procedure.

When I see a USE statement it is useful to know if it is an intrinsic from the standard that is portable. If that is the primary meaning of USE,INTRINSIC then also allowing it to reference vendor-specific modules is confusing and it would have been better to have had three modifiers or to allow something like an additional STD option.

If the purpose is only to prevent you from calling anything else but what the compiler supplies or to be able to be sure you are not calling something supplied by the compiler then the function fits the current directive.

I have come to believe the intent is the second functional meaning and not the first more descriptive meaning that is more useful to someone reading the code.

So it is primarily useful to have the NON-INTRINSIC specification to prevent the use of compiler-supplied procedures where a name clash could easily exist if compiler vendors are free to create arbitrarily-named “intrinsic” modules (which it seems they are).

The INTRINSIC option is then left to mean to make sure the compiler-provided version is used, whether that is an intrinsic module or a vendor-specific one; and not an alternate provided by the user.

Think of it that way and it is simple. Think of the INTRINSIC keyword as meaning “standard-supplied” which is what I thought it meant when I first encountered it you will be found wrong
at some point.

So if the vendor is supplying something that can only be used with their compiler and not defining it as INTRINSIC I think they are defeating the basic functional meaning of the INTRINSIC and NON-INTRINSIC modifiers; but the way the standard description is written I can see how they might consider only modules supplied as part of the standard INTRINSIC.

So as others have mentioned, I think the Fortran standard is not restrictive enough in its definition to prevent suppliers from making up different meanings for its use.

I agree an intrinsic string type would be practical but with this thread I was more interested in the practical consequences for vendoring a library like the Fortran-Lang stdlib.

By vendoring I mean the following:

Vendoring is the act of making your own copy of the 3rd party packages your project is using. Those copies are traditionally placed inside each project and then saved in the project repository.

In this case the “project” would be LFortran, or Intel oneAPI HPC toolkit, or GCC, or flang, etc.

If I understand correctly, a processor such as LFortran (or any other for that matter) are free to provide stdlib as an intrinsic module if they so choose.

use, intrinsic :: stdlib      ! use the vendored version

Compiler vendors are free to do this.

2 Likes

It seems quite reasonable one could provide an alternative ifport and inject some fake (and potentially malevolent) subroutines:

module ifport
    public
    character(len=*), parameter :: msg = "hello"
end module

program main
  use ifport   ! oops, not the Intel one
  implicit none
  print *, msg
end program
$ ifort test_ifport.f90 
$ ./a.out
 hello

One can move the mock ifport module into a separate file, but the search order for use puts the source folder on the top:

When the compiler is looking for .mod and .smod files, directories are searched in this order:

  1. In the directory of the source file that contains the USE statement
  2. In the directories specified by compiler option module path
  3. In the current working directory
  4. In the directories specified by compiler options -Idir (Linux* and macOS) or /include (Windows*)
  5. In the directories specified with environment variables CPATH or INCLUDE
  6. In the standard system directories

Addendum: Security issues of Fortran have been discussed in this thread What about security issues in Fortran?

Looking into ISO/IEC/JTC 1/SC 22/WG 23 DOCUMENT REGISTER, the document N1319 on Fortran Vulnerability states in Section 4.4

The Fortran standard defines a set of intrinsic procedures and intrinsic modules, and allows a processor to extend this set with further procedures and modules. A program that uses an intrinsic procedure or module not defined by the standard is not standard-conforming. A program that uses an entity not defined by the standard from a module defined by the standard is not standard-conforming. Use of intrinsic procedures or modules not defined by the standard should be avoided. Processors are able to detect and report the use of intrinsic procedures or modules not defined by the standard.

I must say the paragraph is confusing…

  • The first sentence implies intrinsic modules are defined by the standard.
  • The second sentence says that using an intrinsic module not defined by the standard is not standard conforming, which would imply what NAG does goes against the standard.
  • The third sentence seems reasonable, standard modules should not define anything extra.
  • The fourth sentence recommends to avoid using non-standard intrinsic procedures or modules.
  • And the last sentence states processors should be able to report when a non-standard intrinsic procedure or module is used.

Section 6.45 of N1319 is more clear:

6.45 Extra intrinsics [LRM]

6.45.1 Applicability to language
The vulnerability specified in ISO/IEC 24772-1:2019 clause 6.45 applies to Fortran.
Fortran permits a processor to supply extra intrinsic procedures or extra intrinsic modules but requires
language processors to be able to diagnose their usage. The use of such intrinsics is not standard-conforming, even if the processor that provides them is standard-conforming.

6.45.2 Avoidance mechanisms for language users
Fortran software developers can avoid the vulnerability or mitigate its ill effects in the following ways. They can:

  • Use the avoidance mechanisms of ISO/IEC 24772-1:2019 clause 6.45.5;
  • Specify that a procedure has the intrinsic attribute in a scope where the intrinsic procedure is referenced;
  • Specify intrinsic or non_intrinsic on a use statement for a module;
  • Use compiler options to detect use of non-standard intrinsic procedures and modules.

So the bottom line is intrinsic means only “provided by the processor”, and not necessarily part of the standard. Or in other words standard procedures and modules are a subset of the intrinsic ones.

I think the way intrinsic modules work is that the definitions, interfaces, and procedures are provided by the compiler without any extra effort. For a user module, that extra effort is locating the .mod file and the .o file. For an intrinsic module, those files do not really need to exist, the compiler is allowed to make everything available “as if” they exist during the compile step and then later during the link step.

If an intrinsic module is defined by the standard, then I think its name starts with iso_. If it is a nonstandard intrinsic module, e.g. one provided by a specific compiler, then I think its name should not begin with iso_, that would be confusing. That goes also for user modules, they should not begin with iso_, although, as far as I know, that is allowed by the standard.

The intrinsic and non_intrinsic clauses allow the programmer to avoid name conflicts and to pick the right module when those conflicts do occur.

Not necessarily, there is IEEE_ARITHMETIC for instance.

1 Like