Dear all,

the attached patch is mostly obvious and self-explaining.
As Albert found out, a CHARACTER(c_char),VALUE dummy of BIND(C)
interface was mistreated, passing the argument by address rather
than by value.

Regtested on x86_64-pc-linux-gnu for bind_c* and value* testcases.
OK for mainline?

Shall this be backported to older branches (at least 16)?

Thanks,
Harald

From 3709e653a42eb9e9c7d1d10cd7048af45eb0c5fa Mon Sep 17 00:00:00 2001
From: Harald Anlauf <[email protected]>
Date: Sun, 18 Oct 2026 23:09:16 +0200
Subject: [PATCH] fortran: Fix CHARACTER(c_char),VALUE dummy of BIND(C)
 interface [PR127881]

For a procedure declared with a BIND(C) interface, a scalar character dummy
with the VALUE attribute shall always be passed by value.  Only a single
character shall be passed.

	PR fortran/127881

gcc/fortran/ChangeLog:

	* trans-expr.cc (conv_scalar_char_value): Fix passing of the case of
	non-constant strings: always pass first first character by value.

gcc/testsuite/ChangeLog:

	* gfortran.dg/bind_c_char_value.f90: New test.
	* gfortran.dg/bind_c_char_value_aux.c: New test.
---
 gcc/fortran/trans-expr.cc                     | 25 ++------
 .../gfortran.dg/bind_c_char_value.f90         | 57 +++++++++++++++++++
 .../gfortran.dg/bind_c_char_value_aux.c       |  4 ++
 3 files changed, 67 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/bind_c_char_value.f90
 create mode 100644 gcc/testsuite/gfortran.dg/bind_c_char_value_aux.c

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index b4a4cede15d..1bdf554d8f6 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -4501,26 +4501,13 @@ conv_scalar_char_value (gfc_symbol *sym, gfc_se *se, gfc_expr **expr)
 					(*expr)->value.character.string[0]);
       gfc_replace_expr (*expr, tmp);
     }
-  else if (se != NULL && (*expr)->expr_type == EXPR_VARIABLE)
+  else if (se != NULL)
     {
-      if ((*expr)->ref == NULL)
-	{
-	  se->expr = gfc_string_to_single_character
-	    (integer_one_node,
-	      gfc_build_addr_expr (gfc_get_pchar_type ((*expr)->ts.kind),
-				  gfc_get_symbol_decl
-				  ((*expr)->symtree->n.sym)),
-	      (*expr)->ts.kind);
-	}
-      else
-	{
-	  gfc_conv_variable (se, *expr);
-	  se->expr = gfc_string_to_single_character
-	    (integer_one_node,
-	      gfc_build_addr_expr (gfc_get_pchar_type ((*expr)->ts.kind),
-				  se->expr),
-	      (*expr)->ts.kind);
-	}
+      gfc_conv_expr (se, *expr);
+      gfc_conv_string_parameter (se);
+      se->expr = gfc_string_to_single_character (integer_one_node,
+						 se->expr, (*expr)->ts.kind);
+      se->string_length = integer_one_node;
     }
 }
 
diff --git a/gcc/testsuite/gfortran.dg/bind_c_char_value.f90 b/gcc/testsuite/gfortran.dg/bind_c_char_value.f90
new file mode 100644
index 00000000000..994668e15e0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/bind_c_char_value.f90
@@ -0,0 +1,57 @@
+! { dg-do run }
+! { dg-additional-sources bind_c_char_value_aux.c }
+!
+! PR fortran/127881 - CHARACTER(c_char),VALUE dummy of BIND(C) interface
+!
+! Contributed by Christopher Albert <[email protected]>
+
+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
+    character(kind=c_char,len=2) :: cc
+    integer :: res, tmp, n = 2
+    via_dummy = echo_char(c)
+    res = via_dummy
+    ! test non-variable argument a and len(a) /= 1
+    tmp = echo_char ((c))
+    if (tmp /= res) error stop 11
+    cc = c // c
+    tmp = echo_char (cc)
+    if (tmp /= res) error stop 12
+    tmp = echo_char ((cc))
+    if (tmp /= res) error stop 13
+    tmp = echo_char (c // c)
+    if (tmp /= res) error stop 14
+    tmp = echo_char(repeat (c,n))
+    if (tmp /= res) error stop 15
+  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
+  if (nbad_local + nbad_dummy + nbad_achar /= 0) then
+     print '(3(a,i0))', 'local variable: ', nbad_local, &
+          '  dummy argument: ', nbad_dummy, '  achar(): ', nbad_achar
+     stop 1
+  end if
+end program pr
diff --git a/gcc/testsuite/gfortran.dg/bind_c_char_value_aux.c b/gcc/testsuite/gfortran.dg/bind_c_char_value_aux.c
new file mode 100644
index 00000000000..87bdc032ef8
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/bind_c_char_value_aux.c
@@ -0,0 +1,4 @@
+/* Used by bind_c_char_value.f90.  */
+/* PR fortran/127881.  */
+
+int echo_char (char a) { return (unsigned char) a; }
-- 
2.51.0

Reply via email to