https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127881
Bug ID: 127881
Summary: Wrong code: address instead of value passed for
CHARACTER(c_char),VALUE dummy of BIND(C) interface
when actual is a dummy argument or ACHAR() result
Product: gcc
Version: 16.2.1
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: fortran
Assignee: unassigned at gcc dot gnu.org
Reporter: albert at tugraz dot at
Target Milestone: ---
For a BIND(C) interface with a CHARACTER(kind=c_char), VALUE dummy argument,
gfortran passes an address instead of the character value when the actual
argument is
(a) a scalar character dummy argument of the calling procedure, or
(b) an ACHAR() expression.
A local variable, an array element or a literal constant is passed correctly.
The code is standard-conforming (F2018 18.3.6 and Table 18.2: CHARACTER(c_char)
of length 1 with VALUE interoperates with C char).
Testcase (pr.f90):
! gfortran passes an address instead of the value for a CHARACTER(c_char),
! VALUE dummy of a BIND(C) interface when the actual argument is a dummy
! argument of the caller or an ACHAR() expression.
module m
use, intrinsic :: iso_c_binding, only: c_char, c_int
implicit none
interface
function echo_char(a) bind(C, name="echo_char") result(r)
import :: c_char, c_int
character(kind=c_char), value, intent(in) :: a
integer(c_int) :: r
end function echo_char
end interface
contains
integer function via_dummy(c)
character(kind=c_char), intent(in) :: c
via_dummy = echo_char(c)
end function via_dummy
end module m
program pr
use m
implicit none
integer :: i, nbad_local, nbad_dummy, nbad_achar
character(kind=c_char) :: c
nbad_local = 0; nbad_dummy = 0; nbad_achar = 0
do i = 0, 127
c = achar(i)
if (echo_char(c) /= i) nbad_local = nbad_local + 1
if (via_dummy(c) /= i) nbad_dummy = nbad_dummy + 1
if (echo_char(achar(i)) /= i) nbad_achar = nbad_achar + 1
end do
print '(3(a,i0))', 'local variable: ', nbad_local, &
' dummy argument: ', nbad_dummy, ' achar(): ', nbad_achar
if (nbad_local + nbad_dummy + nbad_achar /= 0) stop 1
end program pr
pr.c:
int echo_char(char a) { return (unsigned char)a; }
$ gfortran -O0 pr.f90 pr.c && ./a.out
local variable: 0 dummy argument: 127 achar(): 128
STOP 1
$ gfortran -O2 pr.f90 pr.c && ./a.out
local variable: 0 dummy argument: 127 achar(): 127
STOP 1
Expected (flang 23.1.1 gives this): local variable: 0 dummy argument: 0
achar(): 0
-fdump-tree-original shows the problem:
__result_via_dummy = echo_char (*(character(kind=1) *) &c); <- c is already
a reference parameter
if (echo_char (c[1]{lb: 1 sz: 1}) != i) <- local
variable: correct
if (echo_char (&char.1) != i) <- achar(i):
address passed
At -O2 the dummy-argument case passes the low byte of the pointer (movzbl
%sil,%eax).
The same calls without BIND(C) on the interface work. Reproduced with -O0, -O2,
-O3 -march=native, -flto, -fcheck=all and -fopenmp, and with the C file
compiled by gcc or clang.
GNU Fortran (GCC) 16.2.1 20260810, x86_64-pc-linux-gnu (Arch/CachyOS package).
I could not test older releases. The fix for PR 121727 touched character VALUE
argument passing for 16, so this may be related, but that is unverified.