Constant expression in bind(C) name

Tested with

❯ nvfortran -V

nvfortran 21.3-0 LLVM 64-bit target on x86-64 Linux -tp haswell 
NVIDIA Compilers and Tools
Copyright (c) 2020, NVIDIA CORPORATION.  All rights reserved.
❯ uname -a
Linux saw8203 5.10.32-1-MANJARO #1 SMP Wed Apr 21 14:54:10 UTC 2021 x86_64 GNU/Linux

Using the following snippet:

module m_os
  use, intrinsic :: iso_c_binding
  implicit none
#ifndef _WIN32
  character(len=*), parameter :: chdir_symbol = "chdir"
#else
  character(len=*), parameter :: chdir_symbol = "_chdir"
#endif

  interface
    function chdir(path) result(stat) bind(C, name=chdir_symbol)
      import :: c_char, c_int, chdir_symbol
      character(kind=c_char, len=1), intent(in) :: path(*)
      integer(c_int) :: stat
    end function chdir
  end interface
end module m_os

Compiling with nvfortran yields the following error:

❯ nvfortran test.F90 -c -Mpreprocess
NVFORTRAN-S-0034-Syntax error at or near identifier chdir_symbol (test.F90: 11)
NVFORTRAN-S-0134-Illegal attribute - intent specified for nondummy argument path (test.F90: 13)
NVFORTRAN-S-0050-Assumed size array, path, is not a dummy argument (test.F90)
  0 inform,   0 warnings,   3 severes, 0 fatal for m_os

The code snippet is valid Fortran and should compile correctly.

The code snippet is valid Fortran and should compile correctly.

Which compiler are you using to compile this successfully?

I don’t claim to know the standard well enough to know if this should work, but I thought only quoted strings are allowed for the bind C name? Or maybe it’s a newer Fortran 2018 feature?

Compiling your snip-it with gfortran gives the same error as nvfortran, but if I use “_chdir” for the name, it works for both compilers.

% gfortran --version
GNU Fortran (GCC) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

% gfortran -c test.F90
test.F90:11:51:

   11 |     function chdir(path) result(stat) bind(C, name=chdir_symbol)
      |                                                   1
Error: Parameter ‘chdir_symbol’ at (1) has not been declared or is a variable, which does not reduce to a constant expression
test.F90:12:13:

   12 |       import :: c_char, c_int, chdir_symbol
      |             1
Error: IMPORT statement at (1) only permitted in an INTERFACE body
test.F90:13:21:

   13 |       character(kind=c_char, len=1), intent(in) :: path(*)
      |                     1
Error: Parameter ‘c_char’ at (1) has not been declared or is a variable, which does not reduce to a constant expression
test.F90:14:14:

   14 |       integer(c_int) :: stat
      |              1
Error: Parameter ‘c_int’ at (1) has not been declared or is a variable, which does not reduce to a constant expression
test.F90:15:7:

   15 |     end function chdir
      |       1
Error: Expecting END INTERFACE statement at (1)
% diff -u test2.F90 test.F90
--- test2.F90   2021-06-01 10:34:36.283953729 -0700
+++ test.F90    2021-06-01 10:15:27.025290767 -0700
@@ -8,7 +8,7 @@
 #endif

   interface
-    function chdir(path) result(stat) bind(C, name="_chdir")
+    function chdir(path) result(stat) bind(C, name=chdir_symbol)
       import :: c_char, c_int, chdir_symbol
       character(kind=c_char, len=1), intent(in) :: path(*)
       integer(c_int) :: stat
% gfortran -c test2.F90
% nvfortran -c test2.F90
%

Turns out that there is a bug in gfortran as well. This usage is working with Intel’s and NAG’s Fortran compilers. There is a related discussion on the Fortran discourse about the failure with gfortran and the standard conformance of this code

I decided to post the difficult example with a constant expression imported into an interface body here, but there is also a simpler example with a constant expression inside a module body:

module m_api
  use, intrinsic :: iso_c_binding
  implicit none
  character(len=*), parameter :: namespace = "m_"
contains
  function info_api() result(stat) bind(C, name=namespace//"info")
    integer(c_int) :: stat
    stat = 0_c_int
  end function info_api
end module m_api

which will fail with nvfortran but compile with gfortran:

❯ nvfortran api.f90 -c
NVFORTRAN-S-0034-Syntax error at or near identifier namespace (api.f90: 6)
NVFORTRAN-S-0038-Symbol, info_api, has not been explicitly declared (api.f90)
  0 inform,   0 warnings,   2 severes, 0 fatal for info_api

Sounds good. I filed TPR #30170 with the issue and sent it to our engineers for investigation.

Note out of curiosity and to answer my own question, I looked at the F2003, 2008, and 2018 standards. This section hasn’t changed so this isn’t an issue with a change in the standard.