When I was reading code in conjunction with fixing PR101317, I noticed
an unrelated bug in the implementation of CFI_allocate and
CFI_select_part: they were mis-handling the CFI_signed_char type as if
it were a Fortran character type for the purposes of deciding whether to
use the elem_len argument to those functions. It's really an integer
type that has the size of signed char. I checked similar code in other
functions in ISO_Fortran_binding.c and these were the only two that were
incorrect.
The part of the patch to add tests for this goes on top of my base
TS29113 testsuite patch, which hasn't been reviewed or committed yet. I
can refactor that into the same commit as the rest of the testsuite,
assuming everything eventually gets approved.
https://gcc.gnu.org/pipermail/gcc-patches/2021-July/574576.html
-Sandra
commit 45190d9eb5123df77bd60a1d6712f05a3af5f42c
Author: Sandra Loosemore <san...@codesourcery.com>
Date: Thu Jul 15 16:51:55 2021 -0700
Bind(c): signed char is not a Fortran character type
CFI_allocate and CFI_select_part were incorrectly treating
CFI_type_signed_char as a Fortran character type for the purpose of
deciding whether or not to use the elem_len argument. It is a Fortran
integer type per table 18.2 in the 2018 Fortran standard.
Other functions in ISO_Fortran_binding.c appeared to handle this case
correctly already.
2021-07-15 Sandra Loosemore <san...@codesourcery.com>
gcc/testsuite/
* gfortran.dg/ts29113/library/allocate-c.c (ctest): Also test
handling of elem_len for CFI_type_char vs CFI_type_signed_char.
* gfortran.dg/ts29113/library/select-c.c (ctest): Likewise.
libgfortran/
* runtime/ISO_Fortran_binding.c (CFI_allocate)
diff --git a/gcc/testsuite/gfortran.dg/ts29113/library/allocate-c.c b/gcc/testsuite/gfortran.dg/ts29113/library/allocate-c.c
index 0208e5a..6343d28 100644
--- a/gcc/testsuite/gfortran.dg/ts29113/library/allocate-c.c
+++ b/gcc/testsuite/gfortran.dg/ts29113/library/allocate-c.c
@@ -135,5 +135,34 @@ ctest (void)
CFI_deallocate (dv));
if (dv->base_addr != NULL)
abort ();
+
+ /* Signed char is not a Fortran character type. Here we expect it to
+ ignore the elem_len argument and use the size of the type. */
+ ex[0] = 3;
+ ex[1] = 4;
+ ex[2] = 5;
+ check_CFI_status ("CFI_establish",
+ CFI_establish (dv, NULL, CFI_attribute_allocatable,
+ CFI_type_signed_char, 4, 3, ex));
+ lb[0] = 1;
+ lb[1] = 2;
+ lb[2] = 3;
+ ub[0] = 10;
+ ub[1] = 5;
+ ub[2] = 10;
+ sm = sizeof (double);
+ check_CFI_status ("CFI_allocate",
+ CFI_allocate (dv, lb, ub, sm));
+ dump_CFI_cdesc_t (dv);
+ if (dv->base_addr == NULL)
+ abort ();
+ if (dv->elem_len != sizeof (signed char))
+ abort ();
+
+ check_CFI_status ("CFI_deallocate",
+ CFI_deallocate (dv));
+ if (dv->base_addr != NULL)
+ abort ();
+
}
diff --git a/gcc/testsuite/gfortran.dg/ts29113/library/select-c.c b/gcc/testsuite/gfortran.dg/ts29113/library/select-c.c
index df6172c..9bcbc01 100644
--- a/gcc/testsuite/gfortran.dg/ts29113/library/select-c.c
+++ b/gcc/testsuite/gfortran.dg/ts29113/library/select-c.c
@@ -8,6 +8,8 @@
/* Declare some source arrays. */
struct ss {
+ char c[4];
+ signed char b[4];
int i, j, k;
} s[10][5][3];
@@ -61,6 +63,31 @@ ctest (void)
if (result->dim[2].sm != source->dim[2].sm)
abort ();
+ /* Check that we use the given elem_size for char but not for
+ signed char, which is considered an integer type instead of a Fortran
+ character type. */
+ check_CFI_status ("CFI_establish",
+ CFI_establish (result, NULL, CFI_attribute_pointer,
+ CFI_type_char, 4, 3, NULL));
+ if (result->elem_len != 4)
+ abort ();
+ offset = offsetof (struct ss, c);
+ check_CFI_status ("CFI_select_part",
+ CFI_select_part (result, source, offset, 4));
+ if (result->elem_len != 4)
+ abort ();
+
+ check_CFI_status ("CFI_establish",
+ CFI_establish (result, NULL, CFI_attribute_pointer,
+ CFI_type_signed_char, 4, 3, NULL));
+ if (result->elem_len != sizeof (signed char))
+ abort ();
+ offset = offsetof (struct ss, c);
+ check_CFI_status ("CFI_select_part",
+ CFI_select_part (result, source, offset, 4));
+ if (result->elem_len != sizeof (signed char))
+ abort ();
+
/* Extract an array of character substrings. */
offset = 2;
check_CFI_status ("CFI_establish",
diff --git a/libgfortran/runtime/ISO_Fortran_binding.c b/libgfortran/runtime/ISO_Fortran_binding.c
index 78953d0..9fe3a85 100644
--- a/libgfortran/runtime/ISO_Fortran_binding.c
+++ b/libgfortran/runtime/ISO_Fortran_binding.c
@@ -229,10 +229,9 @@ CFI_allocate (CFI_cdesc_t *dv, const CFI_index_t lower_bounds[],
}
}
- /* If the type is a character, the descriptor's element length is replaced
- by the elem_len argument. */
- if (dv->type == CFI_type_char || dv->type == CFI_type_ucs4_char ||
- dv->type == CFI_type_signed_char)
+ /* If the type is a Fortran character type, the descriptor's element
+ length is replaced by the elem_len argument. */
+ if (dv->type == CFI_type_char || dv->type == CFI_type_ucs4_char)
dv->elem_len = elem_len;
/* Dimension information and calculating the array length. */
@@ -759,9 +758,9 @@ int CFI_select_part (CFI_cdesc_t *result, const CFI_cdesc_t *source,
}
}
- /* Element length. */
- if (result->type == CFI_type_char || result->type == CFI_type_ucs4_char ||
- result->type == CFI_type_signed_char)
+ /* Element length is ignored unless result->type specifies a Fortran
+ character type. */
+ if (result->type == CFI_type_char || result->type == CFI_type_ucs4_char)
result->elem_len = elem_len;
if (unlikely (compile_options.bounds_check))