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