https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103828
--- Comment #2 from Francois-Xavier Coudert <fxcoudert at gcc dot gnu.org> ---
So, even modifying gfc_sym_type() in trans-types.c to emit the proper type does
not fix the issue. Why? Because the rug is pulled under our feet later. Turns
out there is a function that deals with this, much later in the front-end:
gfc_conv_scalar_char_value()
But that function is really wrong. It's called in generate_local_decl(), which
says:
/* Modify the tree type for scalar character dummy arguments of bind(c)
procedures if they are passed by value. The tree type for them will
be promoted to INTEGER_TYPE for the middle end, which appears to be
what C would do with characters passed by-value. The value attribute
implies the dummy is a scalar. */
and gfc_conv_scalar_char_value() does this:
/* This becomes the nominal_type in
function.c:assign_parm_find_data_types. */
TREE_TYPE (sym->backend_decl) = unsigned_char_type_node;
/* This becomes the passed_type in
function.c:assign_parm_find_data_types. C promotes char to
integer for argument passing. */
DECL_ARG_TYPE (sym->backend_decl) = unsigned_type_node;
But this is completely wrong. In C, `char` arguments are only promoted to `int`
when the destination type is unknown, i.e., in unprototyped functions (K&R
style) or variadic arguments. C interoperability only interoperates with
prototyped C functions, so this promotion should not happen, and `char` should
be passed as `char`!
I am attaching the patch under testing.