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.