commit 45190d9eb5123df77bd60a1d6712f05a3af5f42c Author: Sandra Loosemore 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 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))