See attached 2 of 5 patch

Regression tested on x86_64

Regards,

Jerry

---

fortran: [PR49802]-2 Allow VALUE on assumed-length
 CHARACTER dummies

Fortran 2003 C528 prohibited the VALUE attribute on a CHARACTER dummy
whose length is not one.  Fortran 2008 relaxed this with C557, and
F2023 Annex C.2 lists it as a Fortran 2008 feature that the Fortran
2008 Introduction did not mention.  gfortran was still rejecting both
an assumed length and a specified but non-constant length, such as
another dummy argument used as the length.

resolve.cc relaxes the constant-length requirement, gated by
gfc_notify_std so that -std=f2003 still rejects it, and consolidates
the C-interop length checks into a single "must have length one"
condition ordered ahead of the Fortran 2008 allowance.

trans-types.cc keeps such a dummy passed by reference, since VALUE now
means copy-in-only semantics rather than pass-by-value of the raw data,
and conv_dummy_value makes the caller-side copy.  The copy size is
scaled by the size of the character kind, so that a kind wider than one
byte copies the whole string rather than its first bytes.

        PR fortran/49802

gcc/fortran/ChangeLog:

        * resolve.cc (resolve_symbol): Allow character(len=*) VALUE and a
        specified but non-constant length under Fortran 2008; consolidate
        the C-interop length checks into a single "must have length one"
        check ordered ahead of the Fortran 2008 allowance.
        * trans-expr.cc (conv_dummy_value): For assumed-length or
        non-constant-length CHARACTER VALUE dummies, make a caller-side
        copy and pass its address; scale the copy size by the size of the
        character kind.
        * trans-types.cc (gfc_sym_type): Use byref=1 for assumed-length or
        non-constant-length VALUE character dummies, so the ABI still
        passes by reference.

gcc/testsuite/ChangeLog:

        * gfortran.dg/value_5.f90: Compile under -std=f2003 so the Fortran
        2008 assumed-length VALUE relaxation is exercised as a rejection,
        and update the C-interop error expectation to match the
        consolidated diagnostic.
        * gfortran.dg/value_6.f90: New test.
        * gfortran.dg/value_7.f90: New test.
        * gfortran.dg/value_11.f90: New test.
        * gfortran.dg/value_14.f90: New test.
---
From d4f981a93d715a3f713d9f938552706b291d263f Mon Sep 17 00:00:00 2001
From: Jerry DeLisle <[email protected]>
Date: Sun, 23 Aug 2026 18:28:54 -0700
Subject: [PATCH 2/5] fortran: [PR49802]-2 Allow VALUE on assumed-length
 CHARACTER dummies

Fortran 2003 C528 prohibited the VALUE attribute on a CHARACTER dummy
whose length is not one.  Fortran 2008 relaxed this with C557, and
F2023 Annex C.2 lists it as a Fortran 2008 feature that the Fortran
2008 Introduction did not mention.  gfortran was still rejecting both
an assumed length and a specified but non-constant length, such as
another dummy argument used as the length.

resolve.cc relaxes the constant-length requirement, gated by
gfc_notify_std so that -std=f2003 still rejects it, and consolidates
the C-interop length checks into a single "must have length one"
condition ordered ahead of the Fortran 2008 allowance.

trans-types.cc keeps such a dummy passed by reference, since VALUE now
means copy-in-only semantics rather than pass-by-value of the raw data,
and conv_dummy_value makes the caller-side copy.  The copy size is
scaled by the size of the character kind, so that a kind wider than one
byte copies the whole string rather than its first bytes.

	PR fortran/49802

gcc/fortran/ChangeLog:

	* resolve.cc (resolve_symbol): Allow character(len=*) VALUE and a
	specified but non-constant length under Fortran 2008; consolidate
	the C-interop length checks into a single "must have length one"
	check ordered ahead of the Fortran 2008 allowance.
	* trans-expr.cc (conv_dummy_value): For assumed-length or
	non-constant-length CHARACTER VALUE dummies, make a caller-side
	copy and pass its address; scale the copy size by the size of the
	character kind.
	* trans-types.cc (gfc_sym_type): Use byref=1 for assumed-length or
	non-constant-length VALUE character dummies, so the ABI still
	passes by reference.

gcc/testsuite/ChangeLog:

	* gfortran.dg/value_5.f90: Compile under -std=f2003 so the Fortran
	2008 assumed-length VALUE relaxation is exercised as a rejection,
	and update the C-interop error expectation to match the
	consolidated diagnostic.
	* gfortran.dg/value_6.f90: New test.
	* gfortran.dg/value_7.f90: New test.
	* gfortran.dg/value_11.f90: New test.
	* gfortran.dg/value_14.f90: New test.
---
 gcc/fortran/resolve.cc                 | 22 ++++++++++++++--
 gcc/fortran/trans-expr.cc              | 29 +++++++++++++++++++++
 gcc/fortran/trans-types.cc             |  6 ++++-
 gcc/testsuite/gfortran.dg/value_11.f90 | 17 +++++++++++++
 gcc/testsuite/gfortran.dg/value_14.f90 | 35 ++++++++++++++++++++++++++
 gcc/testsuite/gfortran.dg/value_5.f90  | 10 ++++++--
 gcc/testsuite/gfortran.dg/value_6.f90  | 29 +++++++++++++++++++++
 gcc/testsuite/gfortran.dg/value_7.f90  |  9 +++++++
 8 files changed, 152 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/value_11.f90
 create mode 100644 gcc/testsuite/gfortran.dg/value_14.f90
 create mode 100644 gcc/testsuite/gfortran.dg/value_6.f90
 create mode 100644 gcc/testsuite/gfortran.dg/value_7.f90

diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 31cac1dd818..f1577f482b9 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -18886,7 +18886,7 @@ skip_interfaces:
   if (sym->attr.value && sym->ts.type == BT_CHARACTER)
     {
       gfc_charlen *cl = sym->ts.u.cl;
-      if (!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT)
+      if (!cl)
 	{
 	  gfc_error ("Character dummy variable %qs at %L with VALUE "
 		     "attribute must have constant length",
@@ -18894,14 +18894,32 @@ skip_interfaces:
 	  return;
 	}
 
+      /* C interoperable character dummies must have length one.  */
       if (sym->ts.is_c_interop
-	  && mpz_cmp_si (cl->length->value.integer, 1) != 0)
+	  && (!cl->length
+	      || cl->length->expr_type != EXPR_CONSTANT
+	      || mpz_cmp_si (cl->length->value.integer, 1) != 0))
 	{
 	  gfc_error ("C interoperable character dummy variable %qs at %L "
 		     "with VALUE attribute must have length one",
 		     sym->name, &sym->declared_at);
 	  return;
 	}
+
+      /* Assumed-length character dummy with VALUE, valid since F2008.  */
+      if (!cl->length
+	  && !gfc_notify_std (GFC_STD_F2008, "Assumed-length character "
+			      "dummy variable %qs at %L with VALUE attribute",
+			      sym->name, &sym->declared_at))
+	return;
+
+      /* Likewise for a specified but non-constant length.  */
+      if (cl->length && cl->length->expr_type != EXPR_CONSTANT
+	  && !gfc_notify_std (GFC_STD_F2008, "Character dummy variable "
+			      "%qs at %L with VALUE attribute and "
+			      "non-constant length",
+			      sym->name, &sym->declared_at))
+	return;
     }
 
   if (sym->ts.type == BT_DERIVED && !sym->attr.is_iso_c
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 960026692a2..1bc96864eeb 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -6772,6 +6772,35 @@ conv_dummy_value (gfc_se * parmse, gfc_expr * e, gfc_symbol * fsym,
       return;
     }
 
+  /* Assumed-length or non-constant-length CHARACTER VALUE dummy: copy
+     the actual argument and pass the copy.  */
+  if (fsym->ts.type == BT_CHARACTER
+      && (!fsym->ts.u.cl || !fsym->ts.u.cl->length
+	  || fsym->ts.u.cl->length->expr_type != EXPR_CONSTANT))
+    {
+      gfc_conv_string_parameter (parmse);
+      tree len = fold_convert (gfc_charlen_type_node, parmse->string_length);
+      tree chartype = gfc_get_character_type_len (fsym->ts.kind, len);
+      tree val_copy = gfc_create_var (chartype, "val_copy");
+      tmp = fold_build1_loc (input_location, DECL_EXPR, chartype, val_copy);
+      gfc_add_expr_to_block (&parmse->pre, tmp);
+      /* The copy size is in bytes, not in characters.  */
+      tree bytes
+	= fold_build2_loc (input_location, MULT_EXPR, size_type_node,
+			   fold_convert (size_type_node, len),
+			   fold_convert (size_type_node,
+					 TYPE_SIZE_UNIT (gfc_get_char_type
+							 (fsym->ts.kind))));
+      tmp = gfc_build_memcpy_call (
+	fold_convert (pvoid_type_node,
+		      gfc_build_addr_expr (NULL_TREE, val_copy)),
+	fold_convert (pvoid_type_node, parmse->expr), bytes);
+      gfc_add_expr_to_block (&parmse->pre, tmp);
+      parmse->expr = fold_convert (
+	build_pointer_type (gfc_get_char_type (fsym->ts.kind)),
+	gfc_build_addr_expr (NULL_TREE, val_copy));
+    }
+
   /* Truncate a too long constant character actual argument.  */
   if (gfc_const_length_character_type_p (&fsym->ts)
       && e->expr_type == EXPR_CONSTANT
diff --git a/gcc/fortran/trans-types.cc b/gcc/fortran/trans-types.cc
index ea4395c67dd..d9e6a12068e 100644
--- a/gcc/fortran/trans-types.cc
+++ b/gcc/fortran/trans-types.cc
@@ -2521,7 +2521,11 @@ gfc_sym_type (gfc_symbol * sym, bool is_bind_c)
   else
     type = gfc_typenode_for_spec (&sym->ts, sym->attr.codimension);
 
-  if (sym->attr.dummy && !sym->attr.function && !sym->attr.value
+  if (sym->attr.dummy && !sym->attr.function
+      && (!sym->attr.value
+	  || (sym->ts.type == BT_CHARACTER
+	      && (!sym->ts.u.cl || !sym->ts.u.cl->length
+		  || sym->ts.u.cl->length->expr_type != EXPR_CONSTANT)))
       && !sym->pass_as_value)
     byref = 1;
   else
diff --git a/gcc/testsuite/gfortran.dg/value_11.f90 b/gcc/testsuite/gfortran.dg/value_11.f90
new file mode 100644
index 00000000000..6fa79605ce9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/value_11.f90
@@ -0,0 +1,17 @@
+! { dg-do run }
+! PR 49802
+! character(len=n), value with a non-constant specified length (n is a
+! dummy argument) was rejected with "must have constant length".  Verify
+! that it compiles and that VALUE semantics hold.
+
+program test
+  implicit none
+  call sub_char1_n ("abc", 3)
+contains
+  subroutine sub_char1_n (x, n)
+    integer, intent(in)            :: n
+    character(len=n), value :: x
+    x(1:1) = "1"
+    if (x(1:1) /= "1") error stop 23
+  end subroutine sub_char1_n
+end program test
diff --git a/gcc/testsuite/gfortran.dg/value_14.f90 b/gcc/testsuite/gfortran.dg/value_14.f90
new file mode 100644
index 00000000000..f309b92e0f9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/value_14.f90
@@ -0,0 +1,35 @@
+! { dg-do run }
+! PR 49802
+! The caller-side copy made for an assumed-length CHARACTER VALUE dummy
+! copied a number of bytes equal to the character count, which is wrong
+! for a character kind wider than one byte.
+
+program test
+  implicit none
+  character(kind=4,len=10) :: s4
+  character(kind=1,len=10) :: s1
+
+  s4 = 4_"abcdefghij"
+  call by_value_k4 (s4)
+  if (s4 /= 4_"abcdefghij") stop 1
+
+  s1 = "abcdefghij"
+  call by_value_k1 (s1)
+  if (s1 /= "abcdefghij") stop 2
+
+contains
+
+  subroutine by_value_k4 (y)
+    character(kind=4,len=*), value :: y
+    if (len (y) /= 10) stop 3
+    if (y /= 4_"abcdefghij") stop 4
+    y = 4_"ZZZZZZZZZZ"
+  end subroutine
+
+  subroutine by_value_k1 (y)
+    character(kind=1,len=*), value :: y
+    if (y /= "abcdefghij") stop 5
+    y = "ZZZZZZZZZZ"
+  end subroutine
+
+end program
diff --git a/gcc/testsuite/gfortran.dg/value_5.f90 b/gcc/testsuite/gfortran.dg/value_5.f90
index 4b0dcefb340..9060bbe2193 100644
--- a/gcc/testsuite/gfortran.dg/value_5.f90
+++ b/gcc/testsuite/gfortran.dg/value_5.f90
@@ -1,9 +1,15 @@
 ! { dg-do compile }
+! { dg-options "-std=f2003" }
 ! Length of character dummy variable with VALUE attribute:
 ! - must be initialization expression or omitted
 ! - C interoperable: must be initialization expression of length one
 !   or omitted
 !
+! Compiled as -std=f2003 because Fortran 2008 relaxed C558 to allow
+! assumed-length character dummies with the VALUE attribute; that case
+! (foo4) and its rejection under -std=f2003 are exercised separately in
+! value_6.f90 and value_7.f90.
+!
 ! Contributed by Tobias Burnus
 program x
   implicit none
@@ -36,7 +42,7 @@ contains
     value :: a
   end subroutine foo3
 
-  subroutine foo4(a) ! { dg-error "VALUE attribute must have constant length" }
+  subroutine foo4(a) ! { dg-error "Assumed-length character" }
     character(*) :: a
     value :: a
   end subroutine foo4
@@ -60,7 +66,7 @@ contains
     value :: a
   end subroutine bar3
 
-  subroutine bar4(a) ! { dg-error "VALUE attribute must have constant length" }
+  subroutine bar4(a) ! { dg-error "VALUE attribute must have length one" }
     use iso_c_binding, only: c_char
     character(kind=c_char,len=*) :: a
     value :: a
diff --git a/gcc/testsuite/gfortran.dg/value_6.f90 b/gcc/testsuite/gfortran.dg/value_6.f90
new file mode 100644
index 00000000000..ac5c7c2d85b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/value_6.f90
@@ -0,0 +1,29 @@
+! { dg-do run }
+! PR 49802
+! character(len=*), value was rejected by gfortran despite being valid
+! from Fortran 2008 onwards.  Verify that it compiles and that VALUE
+! semantics are correct: modifications to the dummy do not affect the
+! actual argument, and len() returns the actual argument's length.
+
+program test
+  implicit none
+  character(len=10) :: str
+
+  str = "123456789"
+  call by_value (str)
+  if (str /= "123456789") stop 1
+
+contains
+
+  subroutine by_value (y)
+    character(len=*), value :: y
+    if (len (y) /= 10) stop 2
+    if (y /= "123456789 ") stop 3
+    y = "abcdefghij"
+    if (y /= "abcdefghij") stop 4
+    ! str is accessible via host association; VALUE must not let
+    ! the assignment to y propagate back.
+    if (str /= "123456789") stop 5
+  end subroutine
+
+end program
diff --git a/gcc/testsuite/gfortran.dg/value_7.f90 b/gcc/testsuite/gfortran.dg/value_7.f90
new file mode 100644
index 00000000000..1338f77452a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/value_7.f90
@@ -0,0 +1,9 @@
+! { dg-do compile }
+! { dg-options "-std=f2003" }
+! PR 49802
+! Fortran 2003 C558 prohibited assumed-length character with VALUE.
+! Verify that -std=f2003 rejects it.
+
+subroutine sub (y)  ! { dg-error "Assumed-length character" }
+  character(len=*), value :: y
+end subroutine
-- 
2.55.0

Reply via email to