Code or Compiler Error?

I am attempting to compile the following on intel MacOS 10.14.6 with what I think is the latest version of the ifort intel compiler.

$ cat cte.f90
use iso_fortran_env, only: compiler_options, compiler_version
character(*), parameter :: compiled_by = compiler_version()
character(*), parameter :: compiled_with = compiler_options()
end

$ ifort --version
ifort (IFORT) 2021.6.0 20220226
Copyright (C) 1985-2022 Intel Corporation.  All rights reserved.

$ ifort -c cte.f90
cte.f90(2): error #6263: This intrinsic function is invalid in constant expressions.   [COMPILER_VERSION]
character(*), parameter :: compiled_by = compiler_version()
-----------------------------------------^
cte.f90(3): error #6263: This intrinsic function is invalid in constant expressions.   [COMPILER_OPTIONS]
character(*), parameter :: compiled_with = compiler_options()
-------------------------------------------^
compilation aborted for cte.f90 (code 1)

This is almost identical to an example in Modern Fortran Explained. These intrinsic functions were introduced in f2008, so I’m not pushing any limits regarding new features. I’m wondering, is this a problem with my code, or with the compiler, or what?

Perhaps it is related to this bug?

Edit: With respect to the inquiry re: a bug in Intel Fortran in the original post, please see this comment post further below in this thread.

The operative word is “almost”: you have the answer in the error message, “This intrinsic function is invalid in constant expressions.” The standard is rather limiting when it comes to what is allows in constant expressions and the standard defined functions from the intrinsic module ISO_FORTRAN_ENV are not among the permitted ones.

You can try this out first where the restrictions of constant expressions with defining named constants do not apply:

   use iso_fortran_env, only: compiler_version
   character(len=:), allocatable :: compiled_by
   compiled_by = compiler_version()
   print *, compiled_by
end

C:\temp>ifort /standard-semantics p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.6.0 Build 20220226_000000
Copyright (C) 1985-2022 Intel Corporation. All rights reserved.

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

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

C:\temp>p.exe
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel
(R) 64, Version 2021.6.0 Build 20220226_000000

1 Like

The only difference in my code and the MFE code is that theirs is in a module. I just put the same statements into a four line main program when I posted it here. MFE says “These functions may be used in initialization expressions, for example…” and then they show their code.

This sentence is in both the f2008 and the f2018 version of MFE. So if it was a mistake, they had 10 years to correct it and they failed to change it.

Can you tell me where in the f2018 standard to look for the list of included/excluded intrinsic functions?

It looks like that bug was fixed in the version of the compiler that I’m using. If it is a bug in the compiler, and not my code, then perhaps they are related bugs.

On a related question, in that example the trim() function was used. I’ve been assuming that the return values for those two functions are already in their trimmed form. At least for the versions of gfortran that I’ve tried where this code works, that has been the case. trim() is easy enough to add, but is it necessary? Are there any known compilers that do not returned trimmed values for those two intrinsic functions?

As I read the standard further, I’m now unsure.

My take earlier was that the standard states, “The types and procedures defined in standard intrinsic modules are not themselves intrinsic.” And thus compiler_version and compiler_option functions are not themselves intrinsic. Then in the section on constant expressions, the standard permits all transformational functions that are “standard intrinsic functions” in constant expressions. But it fails to spike out compiler_version and compiler_option functions as being allowed, so I had felt Intel Fortran was right to issue the diagnostic it did since anything that is not listed as allowed is by definition disallowed per the standard when it comes to constant expressions.

But since OP mentions the example in MFE, I am thinking there might be another “out” for these two functions to appear in constant expressions that Intel Fortran and I have not discovered yet. This is what I will try to check when I have a bit more time.

1 Like

The standard says the length of the returned values are “processor dependent” so the trim() seems prudent even if all the current implementations return it trimmed (not that I know if they do or not).

At least two compilers replace the function call with a fixed string value, which would avoid any problem with using it for initialization:

    .ident  "GCC: (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0"

They might do that and skip generating the error. I sure thought it was not allowed as a parameter value.

Gfortran compiles the code correctly. However, I don’t know if that is an extension or, as MFE states, if that is consistent with f2008+.

The code also compiles with nagfor:
$ nagfor -c cte.f90
NAG Fortran Compiler Release 7.1(Hanzomon) Build 7109
Warning: cte.f90, line 2: Unused PARAMETER COMPILED_BY
Warning: cte.f90, line 3: Unused PARAMETER COMPILED_WITH
[NAG Fortran Compiler normal termination, 2 warnings]

Confirmed this is a bug in Intel Fortran. A support request has been filed with their software team.

The standard states in the section on Specification Expression, “A specification inquiry is a reference to … the COMPILER_VERSION or COMPILER_OPTIONS function from the intrinsic module ISO_FORTRAN_ENV (16.10.2.6, 16.10.2.7).”

The use of a specification inquiry with constant expression arguments are allowed in a constant expression, among other things. There are no parameters to the compiler_version and compiler_options functions, so they are covered.

Thus the use of compiler_version and compiler_options in the definition of a named constant is permitted and Intel Fortran compiler is incorrect in issuing the error diagnostic.

2 Likes

I found a workaround for the Intel bug on compiler_version and compiler_options: putting the function result into an allocatable character scalar because you don’t know in advance how long it will be.
However an Intel oddity remains, as indicated in the comment lines at the beginning of my test program. I don’t know if that is an Intel bug.

! OK in gfortran and ifort. Note: gfortran starts printing the version on
! the same line as 'Compiler version using ' but ifort starts a new line for
! the version if you use neither (2A) nor //. With both the length is chosen
! by the compiler. Analogous results with options instead of version.
program test
  use iso_fortran_env, only: compiler_version
  character(:), allocatable:: version
  version = compiler_version()
  print *,'Compiler_version() length =',len(version)
  print *,'Compiler_version() using ,  is ', version
  print *,'Compiler_version() using // is '//version
  print "(2A)",'Compiler_version() using ,  is ',version
  print "(2A)",'Compiler_version() using // is '//version
end program test

Yes, the intel compiler functions work alright when the functions appear in executable statements. The bug is when they appear in initialization statements such as for character parameters.

Regarding the newline, that is a feature of list-directed i/o. The compiler has great freedom to add spaces and new lines and to choose field widths. If you want to nail down how the output looks, then use some kind of explicit format.

Thank you Ron. I had not realised that list-directed io was free to put a newline between two character variables separated only by a comma. But an additional test made me suspect an ifort bug. The following program won’t compile with ifort but it compiles and runs if the len in it is replaced by len_trim .

program test3
  use iso_fortran_env, only: compiler_version
  character(:),allocatable:: stuff
  stuff = repeat('%',len(compiler_version()))
  print *,'percent = ',stuff
  print *,'version = ',compiler_version()
end program test3

The error message:

test3.f90(4): error #6264: This operator is invalid in a constant expression evaluation.   [LEN]
  stuff = repeat('%',len(compiler_version()))
---------------------^
compilation aborted for test3.f90 (code 1)

I do not see why len is invalid in that executable statement. Gfortran allows it.
By the way ifort’s error message, which I had put between triple back-quotes, was truncated by Fortran Discourse. After ‘expression’ the first line continued with ‘evaluation. [LEN]’

I think the original code is correct, and ifort has a bug.

program test3
  use iso_fortran_env, only: compiler_version
  character(:),allocatable:: stuff
  stuff = repeat('%',len(compiler_version()//''))
  print *,'percent = ',stuff
  print *,'version = ',compiler_version()
end program test3

The above also works alright with ifort. Note that a zero-length character string is appended to the function result. That appears to be enough for ifort to dig itself out of whatever hole it was in.

$ ifort test3.f90 && a.out
 percent = 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 version = 
 Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel
 (R) 64, Version 2021.7.0 Build 20220726_000000

Notice how ifort inserts new lines even within the character strings. That is allowed by list-directed i/o.