On Fri, Aug 20, 2021 at 08:48:57AM +0200, Harald Anlauf via Gcc-patches wrote:
> Hi!
>
> > Gesendet: Freitag, 20. August 2021 um 02:21 Uhr
> > Von: "H.J. Lu" <[email protected]>
>
> > This may have broken bootstrap on 32-bit hosts:
> >
> > https://gcc.gnu.org/pipermail/gcc-regression/2021-August/075209.html
>
> I do not understand the error message:
>
> ../../src-master/gcc/fortran/simplify.c: In function ‘bool
> substring_has_constant_len(gfc_expr*)’:
> ../../src-master/gcc/fortran/simplify.c:4557:22: error: unknown conversion
> type character ‘l’ in format [-Werror=format=]
> 4557 | gfc_error ("Substring start index (" HOST_WIDE_INT_PRINT_DEC
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 4558 | ") at %L below 1",
> | ~~~~~~~~~~~~~~~~~
> ../../src-master/gcc/fortran/simplify.c:4557:22: error: format ‘%L’ expects
> argument of type ‘locus*’, but argument 2 has type ‘long long int’
> [-Werror=format=]
> 4557 | gfc_error ("Substring start index (" HOST_WIDE_INT_PRINT_DEC
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 4558 | ") at %L below 1",
> | ~~~~~~~~~~~~~~~~~
> 4559 | istart, &ref->u.ss.start->where);
> | ~~~~~~
> | |
> | long long int
> ../../src-master/gcc/fortran/simplify.c:4557:22: error: too many arguments
> for format [-Werror=format-extra-args]
>
> Is there an issue with HOST_WIDE_INT_PRINT_DEC on 32-bit hosts?
> What is the right way to print a HOST_WIDE_INT?
>
> It works on 64-bit without any warning.
gfc_error etc. aren't *printf family, it has its own format specifier
handling (e.g. it handles %L and %C), and it is even different
from the error/warning handling in middle-end/c-family FEs/backends.
HOST_WIDE_INT_PRINT_DEC is wrong in the above spot for 2 reasons:
1) gfc_error etc. argument is automatically marked for translation
and translated, having a macro in there that expands to various things
depending on host makes it impossible to mark for translation and
a lottery for translation.
2) hwint.h defines:
#define HOST_LONG_FORMAT "l"
#define HOST_LONG_LONG_FORMAT "ll"
#if INT64_T_IS_LONG
# define GCC_PRI64 HOST_LONG_FORMAT
#else
# define GCC_PRI64 HOST_LONG_LONG_FORMAT
#endif
#define PRId64 GCC_PRI64 "d"
#define HOST_WIDE_INT_PRINT_DEC "%" PRId64
but xm-mingw32.h overrides
#define HOST_LONG_LONG_FORMAT "I64"
so effectively HOST_WIDE_INT_PRINT_DEC is "%ld", "%lld" or "%I64d"
Now, gfc_error does handle %d or %ld, but doesn't handle %lld nor
%I64d, so even if the 1) issue didn't exist, this explains why
it works only on some hosts (e.g. x86_64-linux where %ld is used).
But e.g. on i686-linux or many other hosts it is %lld which
gfc_error doesn't handle and on Windows that %I64d.
Now, the non-Fortran FE diagnostic code actually has %wd for this (w
modifier like l modifier), which takes HOST_WIDE_INT/unsigned HOST_WIDE_INT
argument and prints it.
So, either you get through the hops to support that, unfortunately it isn't
just adding support for that in fortran/error.c (error_print) and some
helper functions, which wouldn't be that hard, just add 'w' next to 'l'
handling, TYPE_* for that and union member etc., but one needs to modify
c-family/c-format.c too to register the modifier so that gcc doesn't warn
about it and knows the proper argument type etc.
The other much easier but uglier option is to use a temporary buffer:
char buffer[21];
sprintf (buffer, HOST_WIDE_INT_PRINT_DEC, hwint_val);
gfc_error ("... %s ...", ... buffer ...);
This works, as it uses the host sprintf i.e. *printf family for which
HOST_WIDE_INT_PRINT_DEC macro is designed.
Jakub