Message ID | Zw0Y8QXanDVM1Fuk@tucnak |
---|---|
State | New |
Headers | show |
Series | genmatch: Revert recent genmatch changes, instead add custom diag_vfprintf routine [PR117110] | expand |
On Mon, 14 Oct 2024, Jakub Jelinek wrote: > Hi! > > My recent changes to genmatch apparently broke bootstrap on FreeBSD > and Darwin and perhaps others, and also broke $build != $host > builds including canadian cross. > > The change was to link in libcommon.a into build/genmatch, so that > we can use pp_format_verbatim. Unfortunately that has various > dependencies in libcommon.a, and more importantly, libcommon.a is > a host library, while build/genmatch carefully links with build/vec.o > etc., build version of libcpp. > So, in order to use pretty-print.o stuff, we'd need to build a build/ > version of all those objects and worse ensure there is and we properly > link build version of libintl and/or libiconv when needed (those 2 are > the reasons for FreeBSD/Darwin failures). > > The following patch just reverts those changes and instead adds a very > simple variant of gcc_diag style vfprintf, which prints the result > directly into a stream. > We don't need anything fancy, like UTF-8 quotes, colors, URLs, in the > usual case genmatch shouldn't print anything at all. > The patch implements what pretty-print.cc implements, except the fancy > stuff (no colors, no URLs printed, quotes always printed just as > 'something', strings even in %qs printed normally rather than trying to > pass through ASCII and valid UTF-8 and use <80><35> style printing for the > rest) and except %@ and %e (neither libcpp nor genmatch.cc use those > currently and they need extra structures etc. which aren't used in libcpp > at all). It handles both "%.*s %d" and "%3$.*2$s %1$d" styles just in case > something got translated (although at least the cross-compiler and stage1 > genmatch shouldn't be translating anything, but stage2+ native can). > > I've tested it with hacking up most of pretty-print.cc self-tests > to just use warning_at ((location_t) 1, ...) and doing manual verification > of what was printed vs. what was expected (with a few additions for the > %M$ style formats); as it goes into a FILE * directly, I'm afraid self-tests > of this aren't easily possible. > > Built on x86_64-linux, ok for trunk if it passes full bootstrap/regtest? Can you do a clean revert and separately instantiate the new feature? I think we probably want diag_vfprintf and dependences in a separate file so it could be re-used from other build tools when required? Alternatively OK as-is if there's no quick clean revert way to restore build on the affected platforms. Thanks, Richard. > 2024-10-14 Jakub Jelinek <jakub@redhat.com> > > PR bootstrap/117110 > * Makefile.in (generated_files, generated_match_files, > build/genmatch$(build_exeext), LINKER_FOR_BUILD): Revert > 2024-10-12 changes. > * genmatch.cc: Don't include pretty-print.h and input.h. > (fatal, ggc_internal_cleared_alloc, ggc_free, line_table, > linemap_client_expand_location_to_spelling_point): Revert > 2024-10-12 changes. > (DIAG_ARGMAX): Define. > (diag_integer_with_precision): Define. > (diag_vfprintf): New function. > (diagnostic_cb): Use diag_vfprintf instead of pp_format_verbatim. > (output_line_directive): Revert 2024-10-12 changes. > > --- gcc/Makefile.in.jj 2024-10-12 13:47:41.936073327 +0200 > +++ gcc/Makefile.in 2024-10-14 09:07:21.565459016 +0200 > @@ -2957,12 +2957,12 @@ generated_files = config.h tm.h $(TM_P_H > $(ALL_GTFILES_H) gtype-desc.cc gtype-desc.h version.h \ > options.h target-hooks-def.h insn-opinit.h \ > common/common-target-hooks-def.h pass-instances.def \ > + $(GIMPLE_MATCH_PD_SEQ_SRC) $(GENERIC_MATCH_PD_SEQ_SRC) \ > + gimple-match-auto.h generic-match-auto.h \ > c-family/c-target-hooks-def.h d/d-target-hooks-def.h \ > $(TM_RUST_H) rust/rust-target-hooks-def.h \ > case-cfn-macros.h \ > cfn-operators.pd omp-device-properties.h > -generated_match_files = gimple-match-auto.h generic-match-auto.h \ > - $(GIMPLE_MATCH_PD_SEQ_SRC) $(GENERIC_MATCH_PD_SEQ_SRC) > > # > # How to compile object files to run on the build machine. > @@ -3145,14 +3145,8 @@ build/genmatch$(build_exeext): BUILD_LIB > build/genmatch$(build_exeext): BUILD_LIBS += $(LIBINTL) $(LIBICONV) > endif > > -# genmatch links in libcommon.a, which could have been compiled with > -# $(PICFLAG) set to -fno-PIE. Make sure to link genmatch with -no-pie > -# in that case. > -build/genmatch$(build_exeext): LINKER_FOR_BUILD += $(findstring -no-pie,$(LD_PICFLAG)) > - > build/genmatch$(build_exeext) : $(BUILD_CPPLIB) \ > - build/vec.o build/hash-table.o build/sort.o libcommon.a \ > - $(LIBBACKTRACE) > + $(BUILD_ERRORS) build/vec.o build/hash-table.o build/sort.o > > # These programs are not linked with the MD reader. > build/gengtype$(build_exeext) : build/gengtype-lex.o build/gengtype-parse.o \ > @@ -4581,8 +4575,6 @@ po/gcc.pot: force > # objects from $(OBJS) as early as possible, build all their > # prerequisites strictly before all objects. > $(ALL_HOST_OBJS) : | $(generated_files) > -# build/genmatch depends on libcommon.a, so avoid circular dependencies. > -$(filter-out $(OBJS-libcommon),$(ALL_HOST_OBJS)) : | $(generated_match_files) > > # Include the auto-generated dependencies for all host objects. > DEPFILES = \ > --- gcc/genmatch.cc.jj 2024-10-12 10:50:41.055854519 +0200 > +++ gcc/genmatch.cc 2024-10-14 14:54:18.101231009 +0200 > @@ -31,22 +31,19 @@ along with GCC; see the file COPYING3. > #include "hash-set.h" > #include "is-a.h" > #include "ordered-hash-map.h" > -#include "pretty-print.h" > -#include "input.h" > > -void > -fatal (const char *format, ...) > -{ > - va_list ap; > > - va_start (ap, format); > - fprintf (stderr, "%s: ", progname); > - vfprintf (stderr, format, ap); > - va_end (ap); > - fputc ('\n', stderr); > - exit (FATAL_EXIT_CODE); > +/* Stubs for GGC referenced through instantiations triggered by hash-map. */ > +void *ggc_internal_cleared_alloc (size_t, void (*)(void *), > + size_t, size_t MEM_STAT_DECL) > +{ > + return NULL; > +} > +void ggc_free (void *) > +{ > } > > + > /* Global state. */ > > /* Verboseness. 0 is quiet, 1 adds some warnings, 2 is for debugging. */ > @@ -55,6 +52,538 @@ unsigned verbose; > > /* libccp helpers. */ > > +static class line_maps *line_table; > + > +/* The rich_location class within libcpp requires a way to expand > + location_t instances, and relies on the client code > + providing a symbol named > + linemap_client_expand_location_to_spelling_point > + to do this. > + > + This is the implementation for genmatch. */ > + > +expanded_location > +linemap_client_expand_location_to_spelling_point (const line_maps *set, > + location_t loc, > + enum location_aspect) > +{ > + const struct line_map_ordinary *map; > + loc = linemap_resolve_location (set, loc, LRK_SPELLING_LOCATION, &map); > + return linemap_expand_location (set, map, loc); > +} > + > +#define DIAG_ARGMAX 30 > + > +#define diag_integer_with_precision(FS, ARG, PREC, T, F) \ > + do \ > + switch (PREC) \ > + { \ > + case 0: \ > + fprintf (FS, "%" F, ARG.m_##T); \ > + break; \ > + \ > + case 1: \ > + fprintf (FS, "%l" F, ARG.m_long_##T); \ > + break; \ > + \ > + case 2: \ > + fprintf (FS, "%" HOST_LONG_LONG_FORMAT F, \ > + ARG.m_long_long_##T); \ > + break; \ > + \ > + case 3: \ > + if (T (-1) < T (0)) \ > + fprintf (FS, "%" GCC_PRISZ F, \ > + (fmt_size_t) ARG.m_ssize_t); \ > + else \ > + fprintf (FS, "%" GCC_PRISZ F, \ > + (fmt_size_t) ARG.m_size_t); \ > + break; \ > + \ > + case 4: \ > + if (T (-1) >= T (0)) \ > + { \ > + unsigned long long a = ARG.m_ptrdiff_t; \ > + unsigned long long m = PTRDIFF_MAX; \ > + m = 2 * m + 1; \ > + fprintf (FS, "%" HOST_LONG_LONG_FORMAT F, \ > + a & m); \ > + } \ > + else if (sizeof (ptrdiff_t) <= sizeof (int)) \ > + fprintf (FS, "%" F, (int) ARG.m_ptrdiff_t); \ > + else if (sizeof (ptrdiff_t) <= sizeof (long)) \ > + fprintf (FS, "%l" F, (long) ARG.m_ptrdiff_t); \ > + else \ > + fprintf (FS, "%" HOST_LONG_LONG_FORMAT F, \ > + (long long int) ARG.m_ptrdiff_t); \ > + break; \ > + \ > + default: \ > + break; \ > + } \ > + while (0) > + > +/* This is a simplified version of pretty-print.cc (pp_format) > + which emits the diagnostics to F stream directly. > + It needs to support everything that libcpp needs in its diagnostics, > + but doesn't have to bother with colors, UTF-8 quoting, URL pretty > + printing, etc. */ > +#if GCC_VERSION >= 4001 > +__attribute__((format (gcc_diag, 3, 0))) > +#endif > +static void > +diag_vfprintf (FILE *f, int err_no, const char *msg, va_list *ap) > +{ > + unsigned int curarg = 0; > + bool any_numbered = false; > + bool any_unnumbered = false; > + enum arg_kind { > + arg_kind_none, > + arg_kind_int, > + arg_kind_long_int, > + arg_kind_long_long_int, > + arg_kind_unsigned, > + arg_kind_long_unsigned, > + arg_kind_long_long_unsigned, > + arg_kind_hwi, > + arg_kind_uhwi, > + arg_kind_size_t, > + arg_kind_ssize_t, > + arg_kind_ptrdiff_t, > + arg_kind_cst_pchar, > + arg_kind_pvoid, > + arg_kind_double, > + arg_kind_Z > + }; > + union { > + enum arg_kind m_kind; > + int m_int; > + long m_long_int; > + long long m_long_long_int; > + unsigned m_unsigned; > + unsigned long m_long_unsigned; > + unsigned long long m_long_long_unsigned; > + HOST_WIDE_INT m_hwi; > + unsigned HOST_WIDE_INT m_uhwi; > + size_t m_size_t; > + ssize_t m_ssize_t; > + ptrdiff_t m_ptrdiff_t; > + const char *m_cst_pchar; > + void *m_pvoid; > + double m_double; > + struct { int *p; unsigned len; } m_Z; > + } args[DIAG_ARGMAX]; > + memset (args, 0, sizeof (args)); > + for (const char *p = strchr (msg, '%'); p; p = strchr (p, '%')) > + { > + ++p; > + switch (*p) > + { > + case '\0': > + gcc_unreachable (); > + case '%': > + case '<': > + case '>': > + case '\'': > + case '}': > + case 'R': > + case 'm': > + /* These don't need any arguments. */ > + ++p; > + continue; > + default: > + break; > + } > + unsigned argno; > + if (ISDIGIT (*p)) > + { > + char *end; > + argno = strtoul (p, &end, 10) - 1; > + p = end; > + gcc_assert (*p == '$'); > + p++; > + > + any_numbered = true; > + gcc_assert (!any_unnumbered); > + } > + else > + { > + argno = curarg++; > + any_unnumbered = true; > + gcc_assert (!any_numbered); > + } > + gcc_assert (argno < DIAG_ARGMAX); > + gcc_assert (args[argno].m_kind == arg_kind_none); > + int precision = 0; > + bool wide = false; > + for (; *p; ++p) > + { > + switch (*p) > + { > + case 'q': > + case '+': > + case '#': > + continue; > + case 'w': > + gcc_assert (!wide); > + wide = true; > + continue; > + case 'z': > + gcc_assert (!precision); > + precision = 3; > + continue; > + case 't': > + gcc_assert (!precision); > + precision = 4; > + continue; > + case 'l': > + gcc_assert (precision < 2); > + ++precision; > + continue; > + default: > + break; > + } > + break; > + } > + if (*p == '.') > + { > + /* We handle '%.Ns' and '%.*s' or '%M$.*N$s' > + (where M == N + 1). */ > + ++p; > + if (ISDIGIT (*p)) > + { > + while (ISDIGIT (*p)) > + ++p; > + gcc_assert (*p == 's'); > + } > + else > + { > + gcc_assert (*p == '*'); > + ++p; > + if (ISDIGIT (*p)) > + { > + char *end; > + unsigned int argno2 = strtoul (p, &end, 10) - 1; > + p = end; > + gcc_assert (argno2 == argno - 1); > + gcc_assert (!any_unnumbered); > + gcc_assert (*p == '$'); > + ++p; > + args[argno2].m_kind = arg_kind_int; > + } > + else > + { > + gcc_assert (!any_numbered); > + args[argno].m_kind = arg_kind_int; > + ++argno; > + ++curarg; > + } > + } > + gcc_assert (*p == 's'); > + } > + enum arg_kind kind = arg_kind_none; > + switch (*p) > + { > + case 'r': > + kind = arg_kind_cst_pchar; > + break; > + case 'c': > + kind = arg_kind_int; > + break; > + case 'd': > + case 'i': > + if (wide) > + kind = arg_kind_hwi; > + else > + switch (precision) > + { > + case 0: > + kind = arg_kind_int; > + break; > + case 1: > + kind = arg_kind_long_int; > + break; > + case 2: > + kind = arg_kind_long_long_int; > + break; > + case 3: > + kind = arg_kind_ssize_t; > + break; > + case 4: > + kind = arg_kind_ptrdiff_t; > + break; > + } > + break; > + case 'o': > + case 'u': > + case 'x': > + if (wide) > + kind = arg_kind_uhwi; > + else > + switch (precision) > + { > + case 0: > + kind = arg_kind_unsigned; > + break; > + case 1: > + kind = arg_kind_long_unsigned; > + break; > + case 2: > + kind = arg_kind_long_long_unsigned; > + break; > + case 3: > + kind = arg_kind_size_t; > + break; > + case 4: > + kind = arg_kind_ptrdiff_t; > + break; > + } > + break; > + case 's': > + case '{': > + kind = arg_kind_cst_pchar; > + break; > + case 'p': > + kind = arg_kind_pvoid; > + break; > + case 'f': > + kind = arg_kind_double; > + break; > + case 'Z': > + kind = arg_kind_Z; > + break; > + case '@': > + case 'e': > + /* These two are unhandled, hopefully libcpp doesn't use them. */ > + default: > + gcc_unreachable (); > + } > + gcc_assert (kind != arg_kind_none); > + args[argno].m_kind = kind; > + } > + for (int i = 0; i < DIAG_ARGMAX; ++i) > + switch (args[i].m_kind) > + { > + case arg_kind_none: > + for (++i; i < DIAG_ARGMAX; ++i) > + gcc_assert (args[i].m_kind == arg_kind_none); > + break; > + case arg_kind_int: > + args[i].m_int = va_arg (*ap, int); > + break; > + case arg_kind_long_int: > + args[i].m_long_int = va_arg (*ap, long); > + break; > + case arg_kind_long_long_int: > + args[i].m_long_long_int = va_arg (*ap, long long); > + break; > + case arg_kind_unsigned: > + args[i].m_unsigned = va_arg (*ap, unsigned); > + break; > + case arg_kind_long_unsigned: > + args[i].m_long_unsigned = va_arg (*ap, unsigned long); > + break; > + case arg_kind_long_long_unsigned: > + args[i].m_long_long_unsigned = va_arg (*ap, unsigned long long); > + break; > + case arg_kind_hwi: > + args[i].m_hwi = va_arg (*ap, HOST_WIDE_INT); > + break; > + case arg_kind_uhwi: > + args[i].m_uhwi = va_arg (*ap, unsigned HOST_WIDE_INT); > + break; > + case arg_kind_size_t: > + args[i].m_size_t = va_arg (*ap, size_t); > + break; > + case arg_kind_ssize_t: > + args[i].m_ssize_t = va_arg (*ap, ssize_t); > + break; > + case arg_kind_ptrdiff_t: > + args[i].m_ptrdiff_t = va_arg (*ap, ptrdiff_t); > + break; > + case arg_kind_cst_pchar: > + args[i].m_cst_pchar = va_arg (*ap, const char *); > + break; > + case arg_kind_pvoid: > + args[i].m_pvoid = va_arg (*ap, void *); > + break; > + case arg_kind_double: > + args[i].m_double = va_arg (*ap, double); > + break; > + case arg_kind_Z: > + args[i].m_Z.p = va_arg (*ap, int *); > + args[i].m_Z.len = va_arg (*ap, unsigned); > + break; > + default: > + gcc_unreachable (); > + } > + curarg = 0; > + const char *q = msg; > + for (const char *p = strchr (msg, '%'); p; p = strchr (p, '%')) > + { > + if (q != p) > + fprintf (f, "%.*s", (int) (p - q), q); > + ++p; > + q = p + 1; > + switch (*p) > + { > + case '%': > + fputc ('%', f); > + ++p; > + continue; > + case '<': > + case '>': > + case '\'': > + fputc ('\'', f); > + ++p; > + continue; > + case '}': > + case 'R': > + ++p; > + continue; > + case 'm': > + fprintf (f, "%s", xstrerror (err_no)); > + ++p; > + continue; > + default: > + break; > + } > + unsigned argno; > + if (ISDIGIT (*p)) > + { > + char *end; > + argno = strtoul (p, &end, 10) - 1; > + p = end; > + p++; > + } > + else > + argno = curarg++; > + int precision = 0; > + bool quote = false; > + bool wide = false; > + for (; *p; ++p) > + { > + switch (*p) > + { > + case 'q': > + gcc_assert (!quote); > + quote = true; > + fputc ('\'', f); > + continue; > + case '+': > + case '#': > + continue; > + case 'w': > + wide = true; > + continue; > + case 'z': > + precision = 3; > + continue; > + case 't': > + precision = 4; > + continue; > + case 'l': > + ++precision; > + continue; > + default: > + break; > + } > + break; > + } > + q = p + 1; > + switch (*p) > + { > + case 'r': > + break; > + case 'c': > + fputc (args[argno].m_int, f); > + break; > + case 'd': > + case 'i': > + if (wide) > + fprintf (f, HOST_WIDE_INT_PRINT_DEC, args[argno].m_hwi); > + else > + diag_integer_with_precision (f, args[argno], precision, > + int, "d"); > + break; > + case 'o': > + if (wide) > + fprintf (f, "%" HOST_WIDE_INT_PRINT "o", args[argno].m_uhwi); > + else > + diag_integer_with_precision (f, args[argno], precision, > + unsigned, "o"); > + break; > + case 'u': > + if (wide) > + fprintf (f, HOST_WIDE_INT_PRINT_UNSIGNED, args[argno].m_uhwi); > + else > + diag_integer_with_precision (f, args[argno], precision, > + unsigned, "u"); > + break; > + case 'x': > + if (wide) > + fprintf (f, HOST_WIDE_INT_PRINT_HEX, args[argno].m_uhwi); > + else > + diag_integer_with_precision (f, args[argno], precision, > + unsigned, "x"); > + break; > + case 's': > + fprintf (f, "%s", args[argno].m_cst_pchar); > + break; > + case '.': > + { > + int n; > + const char *s; > + ++p; > + if (ISDIGIT (*p)) > + { > + char *end; > + n = strtoul (p, &end, 10); > + p = end; > + } > + else > + { > + p = strchr (p, 's'); > + if (any_unnumbered) > + { > + n = args[argno].m_int; > + ++argno; > + ++curarg; > + } > + else > + n = args[argno - 1].m_int; > + } > + q = p + 1; > + s = args[argno].m_cst_pchar; > + size_t len = n < 0 ? strlen (s) : strnlen (s, n); > + fprintf (f, "%.*s", (int) len, s); > + break; > + } > + case '{': > + break; > + case 'p': > + fprintf (f, "%p", args[argno].m_pvoid); > + break; > + case 'f': > + fprintf (f, "%f", args[argno].m_double); > + break; > + case 'Z': > + for (unsigned i = 0; i < args[argno].m_Z.len; ++i) > + { > + fprintf (f, "%i", args[argno].m_Z.p[i]); > + if (i < args[argno].m_Z.len - 1) > + fprintf (f, ", "); > + } > + break; > + default: > + gcc_unreachable (); > + } > + if (quote) > + fputc ('\'', f); > + } > + fprintf (f, "%s", q); > +} > + > static bool > #if GCC_VERSION >= 4001 > __attribute__((format (gcc_diag, 5, 0))) > @@ -64,16 +593,13 @@ diagnostic_cb (cpp_reader *, enum cpp_di > const char *msg, va_list *ap) > { > const line_map_ordinary *map; > + int err_no = errno; > location_t location = richloc->get_loc (); > linemap_resolve_location (line_table, location, LRK_SPELLING_LOCATION, &map); > expanded_location loc = linemap_expand_location (line_table, map, location); > fprintf (stderr, "%s:%d:%d %s: ", loc.file, loc.line, loc.column, > (errtype == CPP_DL_WARNING) ? "warning" : "error"); > - pretty_printer pp; > - pp.set_output_stream (stderr); > - text_info text (msg, ap, errno); > - pp_format_verbatim (&pp, &text); > - pp_flush (&pp); > + diag_vfprintf (stderr, err_no, msg, ap); > fprintf (stderr, "\n"); > FILE *f = fopen (loc.file, "r"); > if (f) > @@ -254,8 +780,8 @@ output_line_directive (FILE *f, location > bool dumpfile = false, bool fnargs = false, > bool indirect_line_numbers = false) > { > - typedef pair_hash<nofree_string_hash, int_hash<int, -1>> loc_hash; > - static hash_map<loc_hash, int> loc_id_map; > + typedef pair_hash<nofree_string_hash, int_hash<int, -1>> location_hash; > + static hash_map<location_hash, int> loc_id_map; > const line_map_ordinary *map; > linemap_resolve_location (line_table, location, LRK_SPELLING_LOCATION, &map); > expanded_location loc = linemap_expand_location (line_table, map, location); > > Jakub > >
On Mon, Oct 14, 2024 at 03:16:44PM +0200, Richard Biener wrote: > Can you do a clean revert and separately instantiate the new feature? I'd need to revert the libcpp changes too and wanted to avoid that. Even in genmatch.cc itself the patch kept half of the changes. > I think we probably want diag_vfprintf and dependences in a separate file > so it could be re-used from other build tools when required? If we have some other user, sure. But perhaps the splitting can be done only when that happens? Jakub
On Mon, 2024-10-14 at 15:13 +0200, Jakub Jelinek wrote: > Hi! > > My recent changes to genmatch apparently broke bootstrap on FreeBSD > and Darwin and perhaps others, and also broke $build != $host > builds including canadian cross. > > The change was to link in libcommon.a into build/genmatch, so that > we can use pp_format_verbatim. Unfortunately that has various > dependencies in libcommon.a, and more importantly, libcommon.a is > a host library, while build/genmatch carefully links with build/vec.o > etc., build version of libcpp. > So, in order to use pretty-print.o stuff, we'd need to build a build/ > version of all those objects and worse ensure there is and we > properly > link build version of libintl and/or libiconv when needed (those 2 > are > the reasons for FreeBSD/Darwin failures). Possibly a silly idea, but rather than reimplementing pretty-print, could it be possible to provide a stub version of libintl etc at build time that doesn't do any internalization? > > The following patch just reverts those changes and instead adds a > very > simple variant of gcc_diag style vfprintf, which prints the result > directly into a stream. > We don't need anything fancy, like UTF-8 quotes, colors, URLs, in the > usual case genmatch shouldn't print anything at all. > The patch implements what pretty-print.cc implements, except the > fancy > stuff (no colors, no URLs printed, quotes always printed just as > 'something', strings even in %qs printed normally rather than trying > to > pass through ASCII and valid UTF-8 and use <80><35> style printing > for the > rest) and except %@ and %e (neither libcpp nor genmatch.cc use those > currently and they need extra structures etc. which aren't used in > libcpp > at all). It handles both "%.*s %d" and "%3$.*2$s %1$d" styles just > in case > something got translated (although at least the cross-compiler and > stage1 > genmatch shouldn't be translating anything, but stage2+ native can). > > I've tested it with hacking up most of pretty-print.cc self-tests > to just use warning_at ((location_t) 1, ...) and doing manual > verification > of what was printed vs. what was expected (with a few additions for > the > %M$ style formats); as it goes into a FILE * directly, I'm afraid > self-tests > of this aren't easily possible. Would it be possible to use fmemopen or fopencookie on configurations that support those? Dave > > Built on x86_64-linux, ok for trunk if it passes full > bootstrap/regtest? > > 2024-10-14 Jakub Jelinek <jakub@redhat.com> > > PR bootstrap/117110 > * Makefile.in (generated_files, generated_match_files, > build/genmatch$(build_exeext), LINKER_FOR_BUILD): Revert > 2024-10-12 changes. > * genmatch.cc: Don't include pretty-print.h and input.h. > (fatal, ggc_internal_cleared_alloc, ggc_free, line_table, > linemap_client_expand_location_to_spelling_point): Revert > 2024-10-12 changes. > (DIAG_ARGMAX): Define. > (diag_integer_with_precision): Define. > (diag_vfprintf): New function. > (diagnostic_cb): Use diag_vfprintf instead of > pp_format_verbatim. > (output_line_directive): Revert 2024-10-12 changes. > > --- gcc/Makefile.in.jj 2024-10-12 13:47:41.936073327 +0200 > +++ gcc/Makefile.in 2024-10-14 09:07:21.565459016 +0200 > @@ -2957,12 +2957,12 @@ generated_files = config.h tm.h $(TM_P_H > $(ALL_GTFILES_H) gtype-desc.cc gtype-desc.h version.h \ > options.h target-hooks-def.h insn-opinit.h \ > common/common-target-hooks-def.h pass-instances.def \ > + $(GIMPLE_MATCH_PD_SEQ_SRC) $(GENERIC_MATCH_PD_SEQ_SRC) \ > + gimple-match-auto.h generic-match-auto.h \ > c-family/c-target-hooks-def.h d/d-target-hooks-def.h \ > $(TM_RUST_H) rust/rust-target-hooks-def.h \ > case-cfn-macros.h \ > cfn-operators.pd omp-device-properties.h > -generated_match_files = gimple-match-auto.h generic-match-auto.h \ > - $(GIMPLE_MATCH_PD_SEQ_SRC) $(GENERIC_MATCH_PD_SEQ_SRC) > > # > # How to compile object files to run on the build machine. > @@ -3145,14 +3145,8 @@ build/genmatch$(build_exeext): BUILD_LIB > build/genmatch$(build_exeext): BUILD_LIBS += $(LIBINTL) $(LIBICONV) > endif > > -# genmatch links in libcommon.a, which could have been compiled with > -# $(PICFLAG) set to -fno-PIE. Make sure to link genmatch with -no- > pie > -# in that case. > -build/genmatch$(build_exeext): LINKER_FOR_BUILD += $(findstring -no- > pie,$(LD_PICFLAG)) > - > build/genmatch$(build_exeext) : $(BUILD_CPPLIB) \ > - build/vec.o build/hash-table.o build/sort.o libcommon.a \ > - $(LIBBACKTRACE) > + $(BUILD_ERRORS) build/vec.o build/hash-table.o build/sort.o > > # These programs are not linked with the MD reader. > build/gengtype$(build_exeext) : build/gengtype-lex.o build/gengtype- > parse.o \ > @@ -4581,8 +4575,6 @@ po/gcc.pot: force > # objects from $(OBJS) as early as possible, build all their > # prerequisites strictly before all objects. > $(ALL_HOST_OBJS) : | $(generated_files) > -# build/genmatch depends on libcommon.a, so avoid circular > dependencies. > -$(filter-out $(OBJS-libcommon),$(ALL_HOST_OBJS)) : | > $(generated_match_files) > > # Include the auto-generated dependencies for all host objects. > DEPFILES = \ > --- gcc/genmatch.cc.jj 2024-10-12 10:50:41.055854519 +0200 > +++ gcc/genmatch.cc 2024-10-14 14:54:18.101231009 +0200 > @@ -31,22 +31,19 @@ along with GCC; see the file COPYING3. > #include "hash-set.h" > #include "is-a.h" > #include "ordered-hash-map.h" > -#include "pretty-print.h" > -#include "input.h" > > -void > -fatal (const char *format, ...) > -{ > - va_list ap; > > - va_start (ap, format); > - fprintf (stderr, "%s: ", progname); > - vfprintf (stderr, format, ap); > - va_end (ap); > - fputc ('\n', stderr); > - exit (FATAL_EXIT_CODE); > +/* Stubs for GGC referenced through instantiations triggered by > hash-map. */ > +void *ggc_internal_cleared_alloc (size_t, void (*)(void *), > + size_t, size_t MEM_STAT_DECL) > +{ > + return NULL; > +} > +void ggc_free (void *) > +{ > } > > + > /* Global state. */ > > /* Verboseness. 0 is quiet, 1 adds some warnings, 2 is for > debugging. */ > @@ -55,6 +52,538 @@ unsigned verbose; > > /* libccp helpers. */ > > +static class line_maps *line_table; > + > +/* The rich_location class within libcpp requires a way to expand > + location_t instances, and relies on the client code > + providing a symbol named > + linemap_client_expand_location_to_spelling_point > + to do this. > + > + This is the implementation for genmatch. */ > + > +expanded_location > +linemap_client_expand_location_to_spelling_point (const line_maps > *set, > + location_t loc, > + enum > location_aspect) > +{ > + const struct line_map_ordinary *map; > + loc = linemap_resolve_location (set, loc, LRK_SPELLING_LOCATION, > &map); > + return linemap_expand_location (set, map, loc); > +} > + > +#define DIAG_ARGMAX 30 > + > +#define diag_integer_with_precision(FS, ARG, PREC, T, F) \ > + do \ > + switch (PREC) \ > + > { \ > + case 0: \ > + fprintf (FS, "%" F, > ARG.m_##T); \ > + break; \ > + \ > + case 1: \ > + fprintf (FS, "%l" F, ARG.m_long_##T); \ > + break; \ > + \ > + case 2: \ > + fprintf (FS, "%" HOST_LONG_LONG_FORMAT F, \ > + ARG.m_long_long_##T); \ > + break; \ > + \ > + case 3: \ > + if (T (-1) < T (0)) \ > + fprintf (FS, "%" GCC_PRISZ > F, \ > + (fmt_size_t) > ARG.m_ssize_t); \ > + else \ > + fprintf (FS, "%" GCC_PRISZ > F, \ > + (fmt_size_t) ARG.m_size_t); \ > + break; \ > + \ > + case 4: \ > + if (T (-1) >= T (0)) \ > + { \ > + unsigned long long a = ARG.m_ptrdiff_t; \ > + unsigned long long m = > PTRDIFF_MAX; \ > + m = 2 * m + 1; \ > + fprintf (FS, "%" HOST_LONG_LONG_FORMAT F, \ > + a & m); \ > + } \ > + else if (sizeof (ptrdiff_t) <= sizeof (int)) \ > + fprintf (FS, "%" F, (int) ARG.m_ptrdiff_t); \ > + else if (sizeof (ptrdiff_t) <= sizeof (long)) \ > + fprintf (FS, "%l" F, (long) > ARG.m_ptrdiff_t); \ > + else \ > + fprintf (FS, "%" HOST_LONG_LONG_FORMAT F, \ > + (long long int) ARG.m_ptrdiff_t); \ > + break; \ > + \ > + default: \ > + break; \ > + > } \ > + while (0) > + > +/* This is a simplified version of pretty-print.cc (pp_format) > + which emits the diagnostics to F stream directly. > + It needs to support everything that libcpp needs in its > diagnostics, > + but doesn't have to bother with colors, UTF-8 quoting, URL pretty > + printing, etc. */ > +#if GCC_VERSION >= 4001 > +__attribute__((format (gcc_diag, 3, 0))) > +#endif > +static void > +diag_vfprintf (FILE *f, int err_no, const char *msg, va_list *ap) > +{ > + unsigned int curarg = 0; > + bool any_numbered = false; > + bool any_unnumbered = false; > + enum arg_kind { > + arg_kind_none, > + arg_kind_int, > + arg_kind_long_int, > + arg_kind_long_long_int, > + arg_kind_unsigned, > + arg_kind_long_unsigned, > + arg_kind_long_long_unsigned, > + arg_kind_hwi, > + arg_kind_uhwi, > + arg_kind_size_t, > + arg_kind_ssize_t, > + arg_kind_ptrdiff_t, > + arg_kind_cst_pchar, > + arg_kind_pvoid, > + arg_kind_double, > + arg_kind_Z > + }; > + union { > + enum arg_kind m_kind; > + int m_int; > + long m_long_int; > + long long m_long_long_int; > + unsigned m_unsigned; > + unsigned long m_long_unsigned; > + unsigned long long m_long_long_unsigned; > + HOST_WIDE_INT m_hwi; > + unsigned HOST_WIDE_INT m_uhwi; > + size_t m_size_t; > + ssize_t m_ssize_t; > + ptrdiff_t m_ptrdiff_t; > + const char *m_cst_pchar; > + void *m_pvoid; > + double m_double; > + struct { int *p; unsigned len; } m_Z; > + } args[DIAG_ARGMAX]; > + memset (args, 0, sizeof (args)); > + for (const char *p = strchr (msg, '%'); p; p = strchr (p, '%')) > + { > + ++p; > + switch (*p) > + { > + case '\0': > + gcc_unreachable (); > + case '%': > + case '<': > + case '>': > + case '\'': > + case '}': > + case 'R': > + case 'm': > + /* These don't need any arguments. */ > + ++p; > + continue; > + default: > + break; > + } > + unsigned argno; > + if (ISDIGIT (*p)) > + { > + char *end; > + argno = strtoul (p, &end, 10) - 1; > + p = end; > + gcc_assert (*p == '$'); > + p++; > + > + any_numbered = true; > + gcc_assert (!any_unnumbered); > + } > + else > + { > + argno = curarg++; > + any_unnumbered = true; > + gcc_assert (!any_numbered); > + } > + gcc_assert (argno < DIAG_ARGMAX); > + gcc_assert (args[argno].m_kind == arg_kind_none); > + int precision = 0; > + bool wide = false; > + for (; *p; ++p) > + { > + switch (*p) > + { > + case 'q': > + case '+': > + case '#': > + continue; > + case 'w': > + gcc_assert (!wide); > + wide = true; > + continue; > + case 'z': > + gcc_assert (!precision); > + precision = 3; > + continue; > + case 't': > + gcc_assert (!precision); > + precision = 4; > + continue; > + case 'l': > + gcc_assert (precision < 2); > + ++precision; > + continue; > + default: > + break; > + } > + break; > + } > + if (*p == '.') > + { > + /* We handle '%.Ns' and '%.*s' or '%M$.*N$s' > + (where M == N + 1). */ > + ++p; > + if (ISDIGIT (*p)) > + { > + while (ISDIGIT (*p)) > + ++p; > + gcc_assert (*p == 's'); > + } > + else > + { > + gcc_assert (*p == '*'); > + ++p; > + if (ISDIGIT (*p)) > + { > + char *end; > + unsigned int argno2 = strtoul (p, &end, 10) - 1; > + p = end; > + gcc_assert (argno2 == argno - 1); > + gcc_assert (!any_unnumbered); > + gcc_assert (*p == '$'); > + ++p; > + args[argno2].m_kind = arg_kind_int; > + } > + else > + { > + gcc_assert (!any_numbered); > + args[argno].m_kind = arg_kind_int; > + ++argno; > + ++curarg; > + } > + } > + gcc_assert (*p == 's'); > + } > + enum arg_kind kind = arg_kind_none; > + switch (*p) > + { > + case 'r': > + kind = arg_kind_cst_pchar; > + break; > + case 'c': > + kind = arg_kind_int; > + break; > + case 'd': > + case 'i': > + if (wide) > + kind = arg_kind_hwi; > + else > + switch (precision) > + { > + case 0: > + kind = arg_kind_int; > + break; > + case 1: > + kind = arg_kind_long_int; > + break; > + case 2: > + kind = arg_kind_long_long_int; > + break; > + case 3: > + kind = arg_kind_ssize_t; > + break; > + case 4: > + kind = arg_kind_ptrdiff_t; > + break; > + } > + break; > + case 'o': > + case 'u': > + case 'x': > + if (wide) > + kind = arg_kind_uhwi; > + else > + switch (precision) > + { > + case 0: > + kind = arg_kind_unsigned; > + break; > + case 1: > + kind = arg_kind_long_unsigned; > + break; > + case 2: > + kind = arg_kind_long_long_unsigned; > + break; > + case 3: > + kind = arg_kind_size_t; > + break; > + case 4: > + kind = arg_kind_ptrdiff_t; > + break; > + } > + break; > + case 's': > + case '{': > + kind = arg_kind_cst_pchar; > + break; > + case 'p': > + kind = arg_kind_pvoid; > + break; > + case 'f': > + kind = arg_kind_double; > + break; > + case 'Z': > + kind = arg_kind_Z; > + break; > + case '@': > + case 'e': > + /* These two are unhandled, hopefully libcpp doesn't use > them. */ > + default: > + gcc_unreachable (); > + } > + gcc_assert (kind != arg_kind_none); > + args[argno].m_kind = kind; > + } > + for (int i = 0; i < DIAG_ARGMAX; ++i) > + switch (args[i].m_kind) > + { > + case arg_kind_none: > + for (++i; i < DIAG_ARGMAX; ++i) > + gcc_assert (args[i].m_kind == arg_kind_none); > + break; > + case arg_kind_int: > + args[i].m_int = va_arg (*ap, int); > + break; > + case arg_kind_long_int: > + args[i].m_long_int = va_arg (*ap, long); > + break; > + case arg_kind_long_long_int: > + args[i].m_long_long_int = va_arg (*ap, long long); > + break; > + case arg_kind_unsigned: > + args[i].m_unsigned = va_arg (*ap, unsigned); > + break; > + case arg_kind_long_unsigned: > + args[i].m_long_unsigned = va_arg (*ap, unsigned long); > + break; > + case arg_kind_long_long_unsigned: > + args[i].m_long_long_unsigned = va_arg (*ap, unsigned long > long); > + break; > + case arg_kind_hwi: > + args[i].m_hwi = va_arg (*ap, HOST_WIDE_INT); > + break; > + case arg_kind_uhwi: > + args[i].m_uhwi = va_arg (*ap, unsigned HOST_WIDE_INT); > + break; > + case arg_kind_size_t: > + args[i].m_size_t = va_arg (*ap, size_t); > + break; > + case arg_kind_ssize_t: > + args[i].m_ssize_t = va_arg (*ap, ssize_t); > + break; > + case arg_kind_ptrdiff_t: > + args[i].m_ptrdiff_t = va_arg (*ap, ptrdiff_t); > + break; > + case arg_kind_cst_pchar: > + args[i].m_cst_pchar = va_arg (*ap, const char *); > + break; > + case arg_kind_pvoid: > + args[i].m_pvoid = va_arg (*ap, void *); > + break; > + case arg_kind_double: > + args[i].m_double = va_arg (*ap, double); > + break; > + case arg_kind_Z: > + args[i].m_Z.p = va_arg (*ap, int *); > + args[i].m_Z.len = va_arg (*ap, unsigned); > + break; > + default: > + gcc_unreachable (); > + } > + curarg = 0; > + const char *q = msg; > + for (const char *p = strchr (msg, '%'); p; p = strchr (p, '%')) > + { > + if (q != p) > + fprintf (f, "%.*s", (int) (p - q), q); > + ++p; > + q = p + 1; > + switch (*p) > + { > + case '%': > + fputc ('%', f); > + ++p; > + continue; > + case '<': > + case '>': > + case '\'': > + fputc ('\'', f); > + ++p; > + continue; > + case '}': > + case 'R': > + ++p; > + continue; > + case 'm': > + fprintf (f, "%s", xstrerror (err_no)); > + ++p; > + continue; > + default: > + break; > + } > + unsigned argno; > + if (ISDIGIT (*p)) > + { > + char *end; > + argno = strtoul (p, &end, 10) - 1; > + p = end; > + p++; > + } > + else > + argno = curarg++; > + int precision = 0; > + bool quote = false; > + bool wide = false; > + for (; *p; ++p) > + { > + switch (*p) > + { > + case 'q': > + gcc_assert (!quote); > + quote = true; > + fputc ('\'', f); > + continue; > + case '+': > + case '#': > + continue; > + case 'w': > + wide = true; > + continue; > + case 'z': > + precision = 3; > + continue; > + case 't': > + precision = 4; > + continue; > + case 'l': > + ++precision; > + continue; > + default: > + break; > + } > + break; > + } > + q = p + 1; > + switch (*p) > + { > + case 'r': > + break; > + case 'c': > + fputc (args[argno].m_int, f); > + break; > + case 'd': > + case 'i': > + if (wide) > + fprintf (f, HOST_WIDE_INT_PRINT_DEC, args[argno].m_hwi); > + else > + diag_integer_with_precision (f, args[argno], precision, > + int, "d"); > + break; > + case 'o': > + if (wide) > + fprintf (f, "%" HOST_WIDE_INT_PRINT "o", > args[argno].m_uhwi); > + else > + diag_integer_with_precision (f, args[argno], precision, > + unsigned, "o"); > + break; > + case 'u': > + if (wide) > + fprintf (f, HOST_WIDE_INT_PRINT_UNSIGNED, > args[argno].m_uhwi); > + else > + diag_integer_with_precision (f, args[argno], precision, > + unsigned, "u"); > + break; > + case 'x': > + if (wide) > + fprintf (f, HOST_WIDE_INT_PRINT_HEX, > args[argno].m_uhwi); > + else > + diag_integer_with_precision (f, args[argno], precision, > + unsigned, "x"); > + break; > + case 's': > + fprintf (f, "%s", args[argno].m_cst_pchar); > + break; > + case '.': > + { > + int n; > + const char *s; > + ++p; > + if (ISDIGIT (*p)) > + { > + char *end; > + n = strtoul (p, &end, 10); > + p = end; > + } > + else > + { > + p = strchr (p, 's'); > + if (any_unnumbered) > + { > + n = args[argno].m_int; > + ++argno; > + ++curarg; > + } > + else > + n = args[argno - 1].m_int; > + } > + q = p + 1; > + s = args[argno].m_cst_pchar; > + size_t len = n < 0 ? strlen (s) : strnlen (s, n); > + fprintf (f, "%.*s", (int) len, s); > + break; > + } > + case '{': > + break; > + case 'p': > + fprintf (f, "%p", args[argno].m_pvoid); > + break; > + case 'f': > + fprintf (f, "%f", args[argno].m_double); > + break; > + case 'Z': > + for (unsigned i = 0; i < args[argno].m_Z.len; ++i) > + { > + fprintf (f, "%i", args[argno].m_Z.p[i]); > + if (i < args[argno].m_Z.len - 1) > + fprintf (f, ", "); > + } > + break; > + default: > + gcc_unreachable (); > + } > + if (quote) > + fputc ('\'', f); > + } > + fprintf (f, "%s", q); > +} > + > static bool > #if GCC_VERSION >= 4001 > __attribute__((format (gcc_diag, 5, 0))) > @@ -64,16 +593,13 @@ diagnostic_cb (cpp_reader *, enum cpp_di > const char *msg, va_list *ap) > { > const line_map_ordinary *map; > + int err_no = errno; > location_t location = richloc->get_loc (); > linemap_resolve_location (line_table, location, > LRK_SPELLING_LOCATION, &map); > expanded_location loc = linemap_expand_location (line_table, map, > location); > fprintf (stderr, "%s:%d:%d %s: ", loc.file, loc.line, loc.column, > (errtype == CPP_DL_WARNING) ? "warning" : "error"); > - pretty_printer pp; > - pp.set_output_stream (stderr); > - text_info text (msg, ap, errno); > - pp_format_verbatim (&pp, &text); > - pp_flush (&pp); > + diag_vfprintf (stderr, err_no, msg, ap); > fprintf (stderr, "\n"); > FILE *f = fopen (loc.file, "r"); > if (f) > @@ -254,8 +780,8 @@ output_line_directive (FILE *f, location > bool dumpfile = false, bool fnargs = false, > bool indirect_line_numbers = false) > { > - typedef pair_hash<nofree_string_hash, int_hash<int, -1>> loc_hash; > - static hash_map<loc_hash, int> loc_id_map; > + typedef pair_hash<nofree_string_hash, int_hash<int, -1>> > location_hash; > + static hash_map<location_hash, int> loc_id_map; > const line_map_ordinary *map; > linemap_resolve_location (line_table, location, > LRK_SPELLING_LOCATION, &map); > expanded_location loc = linemap_expand_location (line_table, map, > location); > > Jakub >
On Mon, Oct 14, 2024 at 10:23:22AM -0400, David Malcolm wrote: > On Mon, 2024-10-14 at 15:13 +0200, Jakub Jelinek wrote: > > Hi! > > > > My recent changes to genmatch apparently broke bootstrap on FreeBSD > > and Darwin and perhaps others, and also broke $build != $host > > builds including canadian cross. > > > > The change was to link in libcommon.a into build/genmatch, so that > > we can use pp_format_verbatim. Unfortunately that has various > > dependencies in libcommon.a, and more importantly, libcommon.a is > > a host library, while build/genmatch carefully links with build/vec.o > > etc., build version of libcpp. > > So, in order to use pretty-print.o stuff, we'd need to build a build/ > > version of all those objects and worse ensure there is and we > > properly > > link build version of libintl and/or libiconv when needed (those 2 > > are > > the reasons for FreeBSD/Darwin failures). > > Possibly a silly idea, but rather than reimplementing pretty-print, > could it be possible to provide a stub version of libintl etc at build > time that doesn't do any internalization? That was my first thought, but I'm afraid that is hard, because libintl nor libiconv aren't included in gcc tree anymore, so one doesn't really know what functions it needs to stub (whether gettext, ngettext, etc., or libintl_gettext, libintl_ngettext, etc., or something else). And more importantly, we'd need to build build/ versions of all of libcommon.a as well (at least for the stage1 or cross compilers case). > Would it be possible to use fmemopen or fopencookie on configurations > that support those? That would be possible, sure. But I'm not really sure if the selftest infrastructure is usable in the generator programs, we'd need a build/ version of selftest.o at least, and possibly any dependencies. Though sure, I could just do the checks with gcc_unreachable () or something similar, just would need checks for fmemopen/fopencookie in configure. Though, that complicates stuff again, because I think auto-host.h checks are for host, not build. Maybe just hack it up under #ifdef __GLIBC_PREREQ #if __GLIBC_PREREQ (2, 30) or whatever (likely fmemopen is much older). Jakub
> Am 14.10.2024 um 15:27 schrieb Jakub Jelinek <jakub@redhat.com>: > > On Mon, Oct 14, 2024 at 03:16:44PM +0200, Richard Biener wrote: >> Can you do a clean revert and separately instantiate the new feature? > > I'd need to revert the libcpp changes too and wanted to avoid that. > Even in genmatch.cc itself the patch kept half of the changes. > >> I think we probably want diag_vfprintf and dependences in a separate file >> so it could be re-used from other build tools when required? > > If we have some other user, sure. But perhaps the splitting can be done > only when that happens? Sure. Go ahead then. Richard > Jakub >
--- gcc/Makefile.in.jj 2024-10-12 13:47:41.936073327 +0200 +++ gcc/Makefile.in 2024-10-14 09:07:21.565459016 +0200 @@ -2957,12 +2957,12 @@ generated_files = config.h tm.h $(TM_P_H $(ALL_GTFILES_H) gtype-desc.cc gtype-desc.h version.h \ options.h target-hooks-def.h insn-opinit.h \ common/common-target-hooks-def.h pass-instances.def \ + $(GIMPLE_MATCH_PD_SEQ_SRC) $(GENERIC_MATCH_PD_SEQ_SRC) \ + gimple-match-auto.h generic-match-auto.h \ c-family/c-target-hooks-def.h d/d-target-hooks-def.h \ $(TM_RUST_H) rust/rust-target-hooks-def.h \ case-cfn-macros.h \ cfn-operators.pd omp-device-properties.h -generated_match_files = gimple-match-auto.h generic-match-auto.h \ - $(GIMPLE_MATCH_PD_SEQ_SRC) $(GENERIC_MATCH_PD_SEQ_SRC) # # How to compile object files to run on the build machine. @@ -3145,14 +3145,8 @@ build/genmatch$(build_exeext): BUILD_LIB build/genmatch$(build_exeext): BUILD_LIBS += $(LIBINTL) $(LIBICONV) endif -# genmatch links in libcommon.a, which could have been compiled with -# $(PICFLAG) set to -fno-PIE. Make sure to link genmatch with -no-pie -# in that case. -build/genmatch$(build_exeext): LINKER_FOR_BUILD += $(findstring -no-pie,$(LD_PICFLAG)) - build/genmatch$(build_exeext) : $(BUILD_CPPLIB) \ - build/vec.o build/hash-table.o build/sort.o libcommon.a \ - $(LIBBACKTRACE) + $(BUILD_ERRORS) build/vec.o build/hash-table.o build/sort.o # These programs are not linked with the MD reader. build/gengtype$(build_exeext) : build/gengtype-lex.o build/gengtype-parse.o \ @@ -4581,8 +4575,6 @@ po/gcc.pot: force # objects from $(OBJS) as early as possible, build all their # prerequisites strictly before all objects. $(ALL_HOST_OBJS) : | $(generated_files) -# build/genmatch depends on libcommon.a, so avoid circular dependencies. -$(filter-out $(OBJS-libcommon),$(ALL_HOST_OBJS)) : | $(generated_match_files) # Include the auto-generated dependencies for all host objects. DEPFILES = \ --- gcc/genmatch.cc.jj 2024-10-12 10:50:41.055854519 +0200 +++ gcc/genmatch.cc 2024-10-14 14:54:18.101231009 +0200 @@ -31,22 +31,19 @@ along with GCC; see the file COPYING3. #include "hash-set.h" #include "is-a.h" #include "ordered-hash-map.h" -#include "pretty-print.h" -#include "input.h" -void -fatal (const char *format, ...) -{ - va_list ap; - va_start (ap, format); - fprintf (stderr, "%s: ", progname); - vfprintf (stderr, format, ap); - va_end (ap); - fputc ('\n', stderr); - exit (FATAL_EXIT_CODE); +/* Stubs for GGC referenced through instantiations triggered by hash-map. */ +void *ggc_internal_cleared_alloc (size_t, void (*)(void *), + size_t, size_t MEM_STAT_DECL) +{ + return NULL; +} +void ggc_free (void *) +{ } + /* Global state. */ /* Verboseness. 0 is quiet, 1 adds some warnings, 2 is for debugging. */ @@ -55,6 +52,538 @@ unsigned verbose; /* libccp helpers. */ +static class line_maps *line_table; + +/* The rich_location class within libcpp requires a way to expand + location_t instances, and relies on the client code + providing a symbol named + linemap_client_expand_location_to_spelling_point + to do this. + + This is the implementation for genmatch. */ + +expanded_location +linemap_client_expand_location_to_spelling_point (const line_maps *set, + location_t loc, + enum location_aspect) +{ + const struct line_map_ordinary *map; + loc = linemap_resolve_location (set, loc, LRK_SPELLING_LOCATION, &map); + return linemap_expand_location (set, map, loc); +} + +#define DIAG_ARGMAX 30 + +#define diag_integer_with_precision(FS, ARG, PREC, T, F) \ + do \ + switch (PREC) \ + { \ + case 0: \ + fprintf (FS, "%" F, ARG.m_##T); \ + break; \ + \ + case 1: \ + fprintf (FS, "%l" F, ARG.m_long_##T); \ + break; \ + \ + case 2: \ + fprintf (FS, "%" HOST_LONG_LONG_FORMAT F, \ + ARG.m_long_long_##T); \ + break; \ + \ + case 3: \ + if (T (-1) < T (0)) \ + fprintf (FS, "%" GCC_PRISZ F, \ + (fmt_size_t) ARG.m_ssize_t); \ + else \ + fprintf (FS, "%" GCC_PRISZ F, \ + (fmt_size_t) ARG.m_size_t); \ + break; \ + \ + case 4: \ + if (T (-1) >= T (0)) \ + { \ + unsigned long long a = ARG.m_ptrdiff_t; \ + unsigned long long m = PTRDIFF_MAX; \ + m = 2 * m + 1; \ + fprintf (FS, "%" HOST_LONG_LONG_FORMAT F, \ + a & m); \ + } \ + else if (sizeof (ptrdiff_t) <= sizeof (int)) \ + fprintf (FS, "%" F, (int) ARG.m_ptrdiff_t); \ + else if (sizeof (ptrdiff_t) <= sizeof (long)) \ + fprintf (FS, "%l" F, (long) ARG.m_ptrdiff_t); \ + else \ + fprintf (FS, "%" HOST_LONG_LONG_FORMAT F, \ + (long long int) ARG.m_ptrdiff_t); \ + break; \ + \ + default: \ + break; \ + } \ + while (0) + +/* This is a simplified version of pretty-print.cc (pp_format) + which emits the diagnostics to F stream directly. + It needs to support everything that libcpp needs in its diagnostics, + but doesn't have to bother with colors, UTF-8 quoting, URL pretty + printing, etc. */ +#if GCC_VERSION >= 4001 +__attribute__((format (gcc_diag, 3, 0))) +#endif +static void +diag_vfprintf (FILE *f, int err_no, const char *msg, va_list *ap) +{ + unsigned int curarg = 0; + bool any_numbered = false; + bool any_unnumbered = false; + enum arg_kind { + arg_kind_none, + arg_kind_int, + arg_kind_long_int, + arg_kind_long_long_int, + arg_kind_unsigned, + arg_kind_long_unsigned, + arg_kind_long_long_unsigned, + arg_kind_hwi, + arg_kind_uhwi, + arg_kind_size_t, + arg_kind_ssize_t, + arg_kind_ptrdiff_t, + arg_kind_cst_pchar, + arg_kind_pvoid, + arg_kind_double, + arg_kind_Z + }; + union { + enum arg_kind m_kind; + int m_int; + long m_long_int; + long long m_long_long_int; + unsigned m_unsigned; + unsigned long m_long_unsigned; + unsigned long long m_long_long_unsigned; + HOST_WIDE_INT m_hwi; + unsigned HOST_WIDE_INT m_uhwi; + size_t m_size_t; + ssize_t m_ssize_t; + ptrdiff_t m_ptrdiff_t; + const char *m_cst_pchar; + void *m_pvoid; + double m_double; + struct { int *p; unsigned len; } m_Z; + } args[DIAG_ARGMAX]; + memset (args, 0, sizeof (args)); + for (const char *p = strchr (msg, '%'); p; p = strchr (p, '%')) + { + ++p; + switch (*p) + { + case '\0': + gcc_unreachable (); + case '%': + case '<': + case '>': + case '\'': + case '}': + case 'R': + case 'm': + /* These don't need any arguments. */ + ++p; + continue; + default: + break; + } + unsigned argno; + if (ISDIGIT (*p)) + { + char *end; + argno = strtoul (p, &end, 10) - 1; + p = end; + gcc_assert (*p == '$'); + p++; + + any_numbered = true; + gcc_assert (!any_unnumbered); + } + else + { + argno = curarg++; + any_unnumbered = true; + gcc_assert (!any_numbered); + } + gcc_assert (argno < DIAG_ARGMAX); + gcc_assert (args[argno].m_kind == arg_kind_none); + int precision = 0; + bool wide = false; + for (; *p; ++p) + { + switch (*p) + { + case 'q': + case '+': + case '#': + continue; + case 'w': + gcc_assert (!wide); + wide = true; + continue; + case 'z': + gcc_assert (!precision); + precision = 3; + continue; + case 't': + gcc_assert (!precision); + precision = 4; + continue; + case 'l': + gcc_assert (precision < 2); + ++precision; + continue; + default: + break; + } + break; + } + if (*p == '.') + { + /* We handle '%.Ns' and '%.*s' or '%M$.*N$s' + (where M == N + 1). */ + ++p; + if (ISDIGIT (*p)) + { + while (ISDIGIT (*p)) + ++p; + gcc_assert (*p == 's'); + } + else + { + gcc_assert (*p == '*'); + ++p; + if (ISDIGIT (*p)) + { + char *end; + unsigned int argno2 = strtoul (p, &end, 10) - 1; + p = end; + gcc_assert (argno2 == argno - 1); + gcc_assert (!any_unnumbered); + gcc_assert (*p == '$'); + ++p; + args[argno2].m_kind = arg_kind_int; + } + else + { + gcc_assert (!any_numbered); + args[argno].m_kind = arg_kind_int; + ++argno; + ++curarg; + } + } + gcc_assert (*p == 's'); + } + enum arg_kind kind = arg_kind_none; + switch (*p) + { + case 'r': + kind = arg_kind_cst_pchar; + break; + case 'c': + kind = arg_kind_int; + break; + case 'd': + case 'i': + if (wide) + kind = arg_kind_hwi; + else + switch (precision) + { + case 0: + kind = arg_kind_int; + break; + case 1: + kind = arg_kind_long_int; + break; + case 2: + kind = arg_kind_long_long_int; + break; + case 3: + kind = arg_kind_ssize_t; + break; + case 4: + kind = arg_kind_ptrdiff_t; + break; + } + break; + case 'o': + case 'u': + case 'x': + if (wide) + kind = arg_kind_uhwi; + else + switch (precision) + { + case 0: + kind = arg_kind_unsigned; + break; + case 1: + kind = arg_kind_long_unsigned; + break; + case 2: + kind = arg_kind_long_long_unsigned; + break; + case 3: + kind = arg_kind_size_t; + break; + case 4: + kind = arg_kind_ptrdiff_t; + break; + } + break; + case 's': + case '{': + kind = arg_kind_cst_pchar; + break; + case 'p': + kind = arg_kind_pvoid; + break; + case 'f': + kind = arg_kind_double; + break; + case 'Z': + kind = arg_kind_Z; + break; + case '@': + case 'e': + /* These two are unhandled, hopefully libcpp doesn't use them. */ + default: + gcc_unreachable (); + } + gcc_assert (kind != arg_kind_none); + args[argno].m_kind = kind; + } + for (int i = 0; i < DIAG_ARGMAX; ++i) + switch (args[i].m_kind) + { + case arg_kind_none: + for (++i; i < DIAG_ARGMAX; ++i) + gcc_assert (args[i].m_kind == arg_kind_none); + break; + case arg_kind_int: + args[i].m_int = va_arg (*ap, int); + break; + case arg_kind_long_int: + args[i].m_long_int = va_arg (*ap, long); + break; + case arg_kind_long_long_int: + args[i].m_long_long_int = va_arg (*ap, long long); + break; + case arg_kind_unsigned: + args[i].m_unsigned = va_arg (*ap, unsigned); + break; + case arg_kind_long_unsigned: + args[i].m_long_unsigned = va_arg (*ap, unsigned long); + break; + case arg_kind_long_long_unsigned: + args[i].m_long_long_unsigned = va_arg (*ap, unsigned long long); + break; + case arg_kind_hwi: + args[i].m_hwi = va_arg (*ap, HOST_WIDE_INT); + break; + case arg_kind_uhwi: + args[i].m_uhwi = va_arg (*ap, unsigned HOST_WIDE_INT); + break; + case arg_kind_size_t: + args[i].m_size_t = va_arg (*ap, size_t); + break; + case arg_kind_ssize_t: + args[i].m_ssize_t = va_arg (*ap, ssize_t); + break; + case arg_kind_ptrdiff_t: + args[i].m_ptrdiff_t = va_arg (*ap, ptrdiff_t); + break; + case arg_kind_cst_pchar: + args[i].m_cst_pchar = va_arg (*ap, const char *); + break; + case arg_kind_pvoid: + args[i].m_pvoid = va_arg (*ap, void *); + break; + case arg_kind_double: + args[i].m_double = va_arg (*ap, double); + break; + case arg_kind_Z: + args[i].m_Z.p = va_arg (*ap, int *); + args[i].m_Z.len = va_arg (*ap, unsigned); + break; + default: + gcc_unreachable (); + } + curarg = 0; + const char *q = msg; + for (const char *p = strchr (msg, '%'); p; p = strchr (p, '%')) + { + if (q != p) + fprintf (f, "%.*s", (int) (p - q), q); + ++p; + q = p + 1; + switch (*p) + { + case '%': + fputc ('%', f); + ++p; + continue; + case '<': + case '>': + case '\'': + fputc ('\'', f); + ++p; + continue; + case '}': + case 'R': + ++p; + continue; + case 'm': + fprintf (f, "%s", xstrerror (err_no)); + ++p; + continue; + default: + break; + } + unsigned argno; + if (ISDIGIT (*p)) + { + char *end; + argno = strtoul (p, &end, 10) - 1; + p = end; + p++; + } + else + argno = curarg++; + int precision = 0; + bool quote = false; + bool wide = false; + for (; *p; ++p) + { + switch (*p) + { + case 'q': + gcc_assert (!quote); + quote = true; + fputc ('\'', f); + continue; + case '+': + case '#': + continue; + case 'w': + wide = true; + continue; + case 'z': + precision = 3; + continue; + case 't': + precision = 4; + continue; + case 'l': + ++precision; + continue; + default: + break; + } + break; + } + q = p + 1; + switch (*p) + { + case 'r': + break; + case 'c': + fputc (args[argno].m_int, f); + break; + case 'd': + case 'i': + if (wide) + fprintf (f, HOST_WIDE_INT_PRINT_DEC, args[argno].m_hwi); + else + diag_integer_with_precision (f, args[argno], precision, + int, "d"); + break; + case 'o': + if (wide) + fprintf (f, "%" HOST_WIDE_INT_PRINT "o", args[argno].m_uhwi); + else + diag_integer_with_precision (f, args[argno], precision, + unsigned, "o"); + break; + case 'u': + if (wide) + fprintf (f, HOST_WIDE_INT_PRINT_UNSIGNED, args[argno].m_uhwi); + else + diag_integer_with_precision (f, args[argno], precision, + unsigned, "u"); + break; + case 'x': + if (wide) + fprintf (f, HOST_WIDE_INT_PRINT_HEX, args[argno].m_uhwi); + else + diag_integer_with_precision (f, args[argno], precision, + unsigned, "x"); + break; + case 's': + fprintf (f, "%s", args[argno].m_cst_pchar); + break; + case '.': + { + int n; + const char *s; + ++p; + if (ISDIGIT (*p)) + { + char *end; + n = strtoul (p, &end, 10); + p = end; + } + else + { + p = strchr (p, 's'); + if (any_unnumbered) + { + n = args[argno].m_int; + ++argno; + ++curarg; + } + else + n = args[argno - 1].m_int; + } + q = p + 1; + s = args[argno].m_cst_pchar; + size_t len = n < 0 ? strlen (s) : strnlen (s, n); + fprintf (f, "%.*s", (int) len, s); + break; + } + case '{': + break; + case 'p': + fprintf (f, "%p", args[argno].m_pvoid); + break; + case 'f': + fprintf (f, "%f", args[argno].m_double); + break; + case 'Z': + for (unsigned i = 0; i < args[argno].m_Z.len; ++i) + { + fprintf (f, "%i", args[argno].m_Z.p[i]); + if (i < args[argno].m_Z.len - 1) + fprintf (f, ", "); + } + break; + default: + gcc_unreachable (); + } + if (quote) + fputc ('\'', f); + } + fprintf (f, "%s", q); +} + static bool #if GCC_VERSION >= 4001 __attribute__((format (gcc_diag, 5, 0))) @@ -64,16 +593,13 @@ diagnostic_cb (cpp_reader *, enum cpp_di const char *msg, va_list *ap) { const line_map_ordinary *map; + int err_no = errno; location_t location = richloc->get_loc (); linemap_resolve_location (line_table, location, LRK_SPELLING_LOCATION, &map); expanded_location loc = linemap_expand_location (line_table, map, location); fprintf (stderr, "%s:%d:%d %s: ", loc.file, loc.line, loc.column, (errtype == CPP_DL_WARNING) ? "warning" : "error"); - pretty_printer pp; - pp.set_output_stream (stderr); - text_info text (msg, ap, errno); - pp_format_verbatim (&pp, &text); - pp_flush (&pp); + diag_vfprintf (stderr, err_no, msg, ap); fprintf (stderr, "\n"); FILE *f = fopen (loc.file, "r"); if (f) @@ -254,8 +780,8 @@ output_line_directive (FILE *f, location bool dumpfile = false, bool fnargs = false, bool indirect_line_numbers = false) { - typedef pair_hash<nofree_string_hash, int_hash<int, -1>> loc_hash; - static hash_map<loc_hash, int> loc_id_map; + typedef pair_hash<nofree_string_hash, int_hash<int, -1>> location_hash; + static hash_map<location_hash, int> loc_id_map; const line_map_ordinary *map; linemap_resolve_location (line_table, location, LRK_SPELLING_LOCATION, &map); expanded_location loc = linemap_expand_location (line_table, map, location);