[PATCH 1 of 2] Fortran: allow character(len=*), value dummy [PR49802]
Jerry D <[email protected]> Sat, 13 Jun 2026 13:27:20 -0700
| Newsgroups | gmane.comp.gcc.patches,gmane.comp.gcc.fortran |
|---|---|
| Message-ID | <[email protected]> |
This bug has been around a long time. The attached is the first of two patches. Several test cases added. Some modified where restrictions changed. Regression tested on x86_64. OK for mainline? Regards, Jerry --- Fortran: allow character(len=*), value dummy [PR49802] Fortran 2003 C558 prohibited assumed-length character dummies with VALUE, but Fortran 2008 removed that restriction. gfortran was still rejecting it, and also rejected character dummies with VALUE whose length is a non-constant specified-length expression (e.g. another dummy argument). This patch has three parts: resolve.cc: Relax the constraint to allow character(len=*) with VALUE, using gfc_notify_std(GFC_STD_F2008) so -std=f2003 still rejects it. The same Fortran 2008 allowance is extended to character dummies with VALUE and a specified but non-constant length. The C-interop checks are consolidated into a single "must have length one" condition (which also covers, and rejects, the assumed-length and non-constant-length cases since C has no equivalent), checked ahead of the Fortran 2008 allowance so C-interop dummies always get the same diagnostic. trans-types.cc (gfc_sym_type): Assumed-length and non-constant-length VALUE character dummies now use byref=1, giving them a pointer-based ABI consistent with the callee's VLA parameter passing. Without this, the callee compiled as a pointer-receiving function while the caller packed bytes by value into registers, causing an ABI mismatch. trans-expr.cc (conv_dummy_value): For assumed-length or non-constant- length CHARACTER VALUE dummies, generate a caller-side copy (VLA alloca + memcpy) and pass its address, so the callee operates on the copy and VALUE semantics are preserved. This lives in conv_dummy_value, the common dummy-value conversion routine, rather than only in gfc_conv_procedure_call's argument-walking loop, so the copy is made on every path that converts a VALUE character dummy, not just direct procedure-call arguments. Assisted by: Claude Sonnet 4.6 PR fortran/49802 gcc/fortran/ChangeLog: * resolve.cc: Allow character(len=*) VALUE from Fortran 2008, and likewise a specified but non-constant length; use gfc_notify_std for F2003 compatibility, and consolidate the C-interop length checks into a single "must have length one" check (covering assumed and non-constant length too) 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 via DECL_EXPR alloca and gfc_build_memcpy_call, then pass its address. * trans-types.cc (gfc_sym_type): Use byref=1 for assumed-length or non-constant-length VALUE character dummies so the ABI uses pointer passing. 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 (foo4), and update the C-interop bar4 error expectation to match the consolidated diagnostic; the F2008 acceptance case is covered separately by pr49802.f90 and pr49802_1.f90. * gfortran.dg/pr49802.f90: New test - run test for correctness with assumed-length VALUE character dummies. * gfortran.dg/pr49802_1.f90: New test - compile/error test for -std=f2003 rejection. * gfortran.dg/pr49802_2.f90: New test - run test for correctness with a non-constant specified-length VALUE character dummy. ---
PR49802-1of2-char-len-star-value-dummy.patch
(text/x-patch, 11.8 KB)
From 45f27e33268e9f880992b43252725d5f1994104c Mon Sep 17 00:00:00 2001 From: Jerry DeLisle <[email protected]> Date: Fri, 12 Jun 2026 10:27:40 -0700 Subject: [PATCH] Fortran: allow character(len=*), value dummy [PR49802] Fortran 2003 C558 prohibited assumed-length character dummies with VALUE, but Fortran 2008 removed that restriction. gfortran was still rejecting it, and also rejected character dummies with VALUE whose length is a non-constant specified-length expression (e.g. another dummy argument). This patch has three parts: resolve.cc: Relax the constraint to allow character(len=*) with VALUE, using gfc_notify_std(GFC_STD_F2008) so -std=f2003 still rejects it. The same Fortran 2008 allowance is extended to character dummies with VALUE and a specified but non-constant length. The C-interop checks are consolidated into a single "must have length one" condition (which also covers, and rejects, the assumed-length and non-constant-length cases since C has no equivalent), checked ahead of the Fortran 2008 allowance so C-interop dummies always get the same diagnostic. trans-types.cc (gfc_sym_type): Assumed-length and non-constant-length VALUE character dummies now use byref=1, giving them a pointer-based ABI consistent with the callee's VLA parameter passing. Without this, the callee compiled as a pointer-receiving function while the caller packed bytes by value into registers, causing an ABI mismatch. trans-expr.cc (conv_dummy_value): For assumed-length or non-constant- length CHARACTER VALUE dummies, generate a caller-side copy (VLA alloca + memcpy) and pass its address, so the callee operates on the copy and VALUE semantics are preserved. This lives in conv_dummy_value, the common dummy-value conversion routine, rather than only in gfc_conv_procedure_call's argument-walking loop, so the copy is made on every path that converts a VALUE character dummy, not just direct procedure-call arguments. Assisted by: Claude Sonnet 4.6 PR fortran/49802 gcc/fortran/ChangeLog: * resolve.cc: Allow character(len=*) VALUE from Fortran 2008, and likewise a specified but non-constant length; use gfc_notify_std for F2003 compatibility, and consolidate the C-interop length checks into a single "must have length one" check (covering assumed and non-constant length too) 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 via DECL_EXPR alloca and gfc_build_memcpy_call, then pass its address. * trans-types.cc (gfc_sym_type): Use byref=1 for assumed-length or non-constant-length VALUE character dummies so the ABI uses pointer passing. 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 (foo4), and update the C-interop bar4 error expectation to match the consolidated diagnostic; the F2008 acceptance case is covered separately by pr49802.f90 and pr49802_1.f90. * gfortran.dg/pr49802.f90: New test - run test for correctness with assumed-length VALUE character dummies. * gfortran.dg/pr49802_1.f90: New test - compile/error test for -std=f2003 rejection. * gfortran.dg/pr49802_2.f90: New test - run test for correctness with a non-constant specified-length VALUE character dummy. --- gcc/fortran/resolve.cc | 26 ++++++++++++++++++++-- gcc/fortran/trans-expr.cc | 26 ++++++++++++++++++++++ gcc/fortran/trans-types.cc | 6 ++++- gcc/testsuite/gfortran.dg/pr49802.f90 | 29 +++++++++++++++++++++++++ gcc/testsuite/gfortran.dg/pr49802_1.f90 | 9 ++++++++ gcc/testsuite/gfortran.dg/pr49802_2.f90 | 17 +++++++++++++++ gcc/testsuite/gfortran.dg/value_5.f90 | 10 +++++++-- 7 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/pr49802.f90 create mode 100644 gcc/testsuite/gfortran.dg/pr49802_1.f90 create mode 100644 gcc/testsuite/gfortran.dg/pr49802_2.f90 diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc index c326bc4f3d1..dffa0501858 100644 --- a/gcc/fortran/resolve.cc +++ b/gcc/fortran/resolve.cc @@ -18757,7 +18757,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", @@ -18765,14 +18765,36 @@ skip_interfaces: return; } + /* C interoperable character dummies must have length one; this + also rules out assumed and non-constant length, so check it + ahead of the Fortran 2008 assumed-length allowance below. */ 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 with VALUE is valid from Fortran 2008 + (Fortran 2003 C558 prohibited it). */ + 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 (e.g. another + dummy argument used as the 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 7bbfaa51ef9..a8c5f34cbf1 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -6739,6 +6739,32 @@ conv_dummy_value (gfc_se * parmse, gfc_expr * e, gfc_symbol * fsym, return; } + /* Assumed-length or non-constant-length CHARACTER VALUE: the dummy uses + pointer-based passing (byref=1 in gfc_sym_type), so make a caller-side + copy here to satisfy VALUE semantics -- changes to the dummy must not + propagate back to the actual argument. Fall through afterwards so the + OPTIONAL handling below still runs. */ + 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); + 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), + fold_convert (size_type_node, len)); + 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 5bccea960aa..1c35e114db9 100644 --- a/gcc/fortran/trans-types.cc +++ b/gcc/fortran/trans-types.cc @@ -2516,7 +2516,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/pr49802.f90 b/gcc/testsuite/gfortran.dg/pr49802.f90 new file mode 100644 index 00000000000..1167c09bfb2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr49802.f90 @@ -0,0 +1,29 @@ +! { dg-do run } +! PR fortran/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/pr49802_1.f90 b/gcc/testsuite/gfortran.dg/pr49802_1.f90 new file mode 100644 index 00000000000..b3650be9a36 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr49802_1.f90 @@ -0,0 +1,9 @@ +! { dg-do compile } +! { dg-options "-std=f2003" } +! PR fortran/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 diff --git a/gcc/testsuite/gfortran.dg/pr49802_2.f90 b/gcc/testsuite/gfortran.dg/pr49802_2.f90 new file mode 100644 index 00000000000..5bc5edeba50 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr49802_2.f90 @@ -0,0 +1,17 @@ +! { dg-do run } +! PR fortran/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_5.f90 b/gcc/testsuite/gfortran.dg/value_5.f90 index 4b0dcefb340..32f22d509bb 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 +! pr49802.f90 and pr49802_1.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 -- 2.54.0