Dear all,

the attached fixes a missed optimization passing a constant character
string to a scalar dummy with value attribute and shorter than the
actual by truncating the latter at compile time.

Regtested on x86_64-pc-linux-gnu.  OK for mainline?

Thanks,
Harald

From 378e6ee5fc20a2648940e80e5a7faf150cc4a33c Mon Sep 17 00:00:00 2001
From: Harald Anlauf <anl...@gmx.de>
Date: Sun, 31 Aug 2025 20:42:23 +0200
Subject: [PATCH] Fortran: truncate constant string passed to character,value
 dummy [PR121727]

	PR fortran/121727

gcc/fortran/ChangeLog:

	* trans-expr.cc (gfc_const_length_character_type_p): New helper
	function.
	(conv_dummy_value): Use it to determine if a character actual
	argument has a constant length.  If a character actual argument is
	constant and longer than the dummy, truncate it at compile time.

gcc/testsuite/ChangeLog:

	* gfortran.dg/value_10.f90: New test.
---
 gcc/fortran/trans-expr.cc              | 34 ++++++++++++++++++++
 gcc/testsuite/gfortran.dg/value_10.f90 | 43 ++++++++++++++++++++++++++
 2 files changed, 77 insertions(+)
 create mode 100644 gcc/testsuite/gfortran.dg/value_10.f90

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 6a21e8c10e8..97431d9f19e 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -6510,6 +6510,20 @@ conv_cond_temp (gfc_se * parmse, gfc_expr * e, tree cond)
 }
 
 
+/* Returns true if the type specified in TS is a character type whose length
+   is constant.  Otherwise returns false.  */
+
+static bool
+gfc_const_length_character_type_p (gfc_typespec *ts)
+{
+  return (ts->type == BT_CHARACTER
+	  && ts->u.cl
+	  && ts->u.cl->length
+	  && ts->u.cl->length->expr_type == EXPR_CONSTANT
+	  && ts->u.cl->length->ts.type == BT_INTEGER);
+}
+
+
 /* Helper function for the handling of (currently) scalar dummy variables
    with the VALUE attribute.  Argument parmse should already be set up.  */
 static void
@@ -6565,6 +6579,26 @@ conv_dummy_value (gfc_se * parmse, gfc_expr * e, gfc_symbol * fsym,
       return;
     }
 
+  /* Truncate a too long constant character actual argument.  */
+  if (gfc_const_length_character_type_p (&fsym->ts)
+      && e->expr_type == EXPR_CONSTANT
+      && mpz_cmp_ui (fsym->ts.u.cl->length->value.integer,
+		     e->value.character.length) < 0)
+    {
+      gfc_charlen_t flen = mpz_get_ui (fsym->ts.u.cl->length->value.integer);
+
+      /* Truncate actual string argument.  */
+      gfc_conv_expr (parmse, e);
+      parmse->expr = gfc_build_wide_string_const (e->ts.kind, flen,
+						  e->value.character.string);
+      parmse->string_length = build_int_cst (gfc_charlen_type_node, flen);
+
+      /* Indicate value,optional scalar dummy argument as present.  */
+      if (fsym->attr.optional)
+	vec_safe_push (optionalargs, boolean_true_node);
+      return;
+    }
+
   /* gfortran argument passing conventions:
      actual arguments to CHARACTER(len=1),VALUE
      dummy arguments are actually passed by value.
diff --git a/gcc/testsuite/gfortran.dg/value_10.f90 b/gcc/testsuite/gfortran.dg/value_10.f90
new file mode 100644
index 00000000000..b1c8d1d81e9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/value_10.f90
@@ -0,0 +1,43 @@
+! { dg-do compile }
+! { dg-additional-options "-Wcharacter-truncation -fdump-tree-original" }
+! PR fortran/121727
+
+program p
+  use iso_c_binding, only: c_char
+  implicit none
+  call cbind('abcd')   ! { dg-warning "length of actual argument longer" }
+  call one  ('efgh')   ! { dg-warning "length of actual argument longer" }
+  call one4 (4_'IJKL') ! { dg-warning "length of actual argument longer" }
+
+  call two4 (4_'MNOP') ! { dg-warning "length of actual argument longer" }
+  call three('efgh')   ! { dg-warning "length of actual argument longer" }
+  call four ('ijklmn') ! { dg-warning "length of actual argument longer" }
+contains
+  subroutine cbind(c) bind(C)
+    character(kind=c_char,len=1), value :: c
+  end
+
+  subroutine one(x)
+    character(kind=1,len=1), value :: x
+  end
+
+  subroutine one4(w)
+    character(kind=4,len=1), value :: w
+  end
+
+  subroutine two4(y)
+    character(kind=4,len=2), value :: y
+  end
+
+  subroutine three(z)
+    character(kind=1,len=3), value :: z
+  end
+
+  subroutine four(v)
+    character(kind=1,len=4), optional, value :: v
+  end
+end
+
+! { dg-final { scan-tree-dump-times "two4 \\(.*, 2\\);" 1 "original" } }
+! { dg-final { scan-tree-dump-times "three \\(.*, 3\\);" 1 "original" } }
+! { dg-final { scan-tree-dump-times "four \\(.*, 1, 4\\);" 1 "original" } }
-- 
2.51.0

Reply via email to