Dear all, the attached patch fixes a 16/17 regression I caused when trying to improve the checking of passed character length. When the dummy argument is a scalar character variable and the actual is an array element, the code wrongly looked at the storage size until the end of the array.
Regtested on x86_64-pc-linux-gnu. OK for mainline / 16-backport? Thanks, Harald
From 7df7e43d65ffbdcaf1c13cedc968479dcdbb3f46 Mon Sep 17 00:00:00 2001 From: Harald Anlauf <[email protected]> Date: Thu, 28 May 2026 22:49:26 +0200 Subject: [PATCH] Fortran: checking of passed character length [PR125393] Commit r16-3462 enhanced checking of character length passed to a character dummy. However, when the actual argument was an array element, its storage size was estimated from all elements up to the end of the array. This could give a bogus warning when the dummy argument was of a scalar character type. Fix check for this case to actually compare the character lengths of actual and dummy. PR fortran/125393 gcc/fortran/ChangeLog: * interface.cc (get_expr_storage_size): Additionally return character length. (gfc_compare_actual_formal): When the formal is a scalar character variable, use character lengths, not array storage size for check. gcc/testsuite/ChangeLog: * gfortran.dg/argument_checking_28.f90: New test. --- gcc/fortran/interface.cc | 15 ++++++- .../gfortran.dg/argument_checking_28.f90 | 45 +++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/argument_checking_28.f90 diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc index 8ab2fade283..e809a14c808 100644 --- a/gcc/fortran/interface.cc +++ b/gcc/fortran/interface.cc @@ -3085,7 +3085,7 @@ get_sym_storage_size (gfc_symbol *sym, bool *size_known) units of the actual argument up to the end of the array. */ static unsigned long -get_expr_storage_size (gfc_expr *e, bool *size_known) +get_expr_storage_size (gfc_expr *e, bool *size_known, long int *charlen) { int i; long int strlen, elements; @@ -3094,6 +3094,7 @@ get_expr_storage_size (gfc_expr *e, bool *size_known) gfc_ref *ref; *size_known = false; + *charlen = -1; if (e == NULL) return 0; @@ -3109,6 +3110,7 @@ get_expr_storage_size (gfc_expr *e, bool *size_known) strlen = e->value.character.length; else return 0; + *charlen = strlen; } else strlen = 1; /* Length per element. */ @@ -3365,6 +3367,7 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, gfc_formal_arglist *f; int i, n, na; unsigned long actual_size, formal_size; + long int charlen; bool full_array = false; gfc_array_ref *actual_arr_ref; gfc_array_spec *fas, *aas; @@ -3681,9 +3684,17 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, if (a->expr->expr_type == EXPR_NULL && a->expr->ts.type == BT_UNKNOWN) goto skip_size_check; - actual_size = get_expr_storage_size (a->expr, &actual_size_known); + actual_size = get_expr_storage_size (a->expr, &actual_size_known, &charlen); formal_size = get_sym_storage_size (f->sym, &formal_size_known); + /* If the formal is a scalar character variable, use the charlen of the + actual. */ + if (actual_size_known && formal_size_known && charlen >= 0 + && a->expr->ts.type == BT_CHARACTER + && f->sym->attr.flavor != FL_PROCEDURE + && !f->sym->attr.dimension) + actual_size = charlen; + if (actual_size_known && formal_size_known && actual_size != formal_size && a->expr->ts.type == BT_CHARACTER diff --git a/gcc/testsuite/gfortran.dg/argument_checking_28.f90 b/gcc/testsuite/gfortran.dg/argument_checking_28.f90 new file mode 100644 index 00000000000..fb9ec4d70ea --- /dev/null +++ b/gcc/testsuite/gfortran.dg/argument_checking_28.f90 @@ -0,0 +1,45 @@ +! { dg-do compile } +! { dg-additional-options "-std=f2018 -Wcharacter-truncation" } +! +! PR fortran/125393 - checking of passed character length + +module test + implicit none +contains + + subroutine a(string) + character(len=2) string + end subroutine a + + subroutine b + character(len=2) :: s1 + character(len=2), dimension(2) :: s2 + character(len=1) :: s3(2) + character(len=4) :: s4 + call a(s1) + call a(s1(1:2)) + call a(s2(1)) ! This gave a bogus warning + call a(s2(1)(1:2)) + call a(s3(1)) ! { dg-error "Character length of actual argument shorter" } + call a(s4(1:2)) + call a(c1()) ! { dg-error "Character length of actual argument shorter" } + call a(c2()) + call a(c3()) ! { dg-warning "Character length of actual argument longer" } + end subroutine b + + function c1 () + character(len=1) :: c1 + c1 = "a" + end function c1 + + function c2 () + character(len=2) :: c2 + c2 = "ab" + end function c2 + + function c3 () + character(len=3) :: c3 + c3 = "abc" + end function c3 + +end module test -- 2.51.0
