new file mode 100644
@@ -0,0 +1,122 @@
+/* Integration of JSON parsing with GCC diagnostics.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic.h"
+#include "json-reader.h"
+
+/* Read the contents of PATH into memory, returning a 0-terminated buffer
+ that must be freed by the caller.
+ Issue a fatal error if there are any problems. */
+
+char *
+read_file (const char *path)
+{
+ FILE *f_in = fopen (path, "r");
+ if (!f_in)
+ fatal_error (UNKNOWN_LOCATION, "unable to open file %qs: %s",
+ path, xstrerror (errno));
+
+ /* Read content, allocating a buffer for it. */
+ char *result = NULL;
+ size_t total_sz = 0;
+ size_t alloc_sz = 0;
+ char buf[4096];
+ size_t iter_sz_in;
+
+ while ( (iter_sz_in = fread (buf, 1, sizeof (buf), f_in)) )
+ {
+ gcc_assert (alloc_sz >= total_sz);
+ size_t old_total_sz = total_sz;
+ total_sz += iter_sz_in;
+ /* Allow 1 extra byte for 0-termination. */
+ if (alloc_sz < (total_sz + 1))
+ {
+ size_t new_alloc_sz = alloc_sz ? alloc_sz * 2: total_sz + 1;
+ result = (char *)xrealloc (result, new_alloc_sz);
+ alloc_sz = new_alloc_sz;
+ }
+ memcpy (result + old_total_sz, buf, iter_sz_in);
+ }
+
+ if (!feof (f_in))
+ fatal_error (UNKNOWN_LOCATION, "error reading from %qs: %s", path,
+ xstrerror (errno));
+
+ fclose (f_in);
+
+ /* 0-terminate the buffer. */
+ gcc_assert (total_sz < alloc_sz);
+ result[total_sz] = '\0';
+
+ return result;
+}
+
+/* json_reader's ctor. */
+
+json_reader::json_reader (const char *filename)
+: m_filename (filename),
+ m_json_loc_map (filename, line_table)
+{
+}
+
+/* Parse UTF8, capturing source location information in m_json_loc_map.
+ If successful, return the top-level value.
+ Otherwise, return NULL and write to *ERR_OUT. */
+
+json::value *
+json_reader::parse_utf8_string (const char *utf8, bool allow_comments,
+ json::error **err_out)
+{
+ json::value *result
+ = json::parse_utf8_string (utf8, allow_comments, err_out, &m_json_loc_map);
+ return result;
+}
+
+/* Issue an error diagnostic for GMSGID at the location of JV, and exit. */
+
+void
+json_reader::fatal_error (json::value *jv, const char *gmsgid, ...)
+{
+ location_t loc = m_json_loc_map.get_range_for_value (jv);
+
+ auto_diagnostic_group d;
+ va_list ap;
+ va_start (ap, gmsgid);
+ rich_location richloc (line_table, loc);
+ emit_diagnostic_valist (DK_ERROR, &richloc, NULL, 0, gmsgid, &ap);
+ va_end (ap);
+ exit (1);
+ /* Ideally we'd use ::fatal_error here, but we seem to need to use
+ DK_ERROR for it to be usable from DejaGnu. */
+}
+
+/* Issue an error diagnostic for ERR, and exit. */
+
+void
+json_reader::fatal_error (json::error *err)
+{
+ location_t loc = m_json_loc_map.make_location_for_range (err->get_range ());
+ ::error_at (loc, "%s", err->get_msg ());
+ exit (1);
+ /* Ideally we'd use ::fatal_error here, but we seem to need to use
+ DK_ERROR for it to be usable from DejaGnu. */
+}
new file mode 100644
@@ -0,0 +1,107 @@
+/* Integration of JSON parsing with GCC diagnostics.
+ Copyright (C) 2022 David Malcolm <dmalcolm@redhat.com>.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_JSON_READER_H
+#define GCC_JSON_READER_H
+
+#include "json-parsing.h"
+
+/* Concrete implementation of json::location_map that integrates
+ with a line_table, creating location_t values for the locations
+ in the JSON file. */
+
+class json_line_map : public json::location_map
+{
+public:
+ json_line_map (const char *filename,
+ line_maps *line_table)
+ : m_filename (filename),
+ m_line_table (line_table)
+ {
+ linemap_add (m_line_table, LC_ENTER, false, xstrdup (m_filename), 0);
+ }
+
+ void record_range_for_value (json::value *jv, const range &r) final override
+ {
+ location_t loc = make_location_for_range (r);
+ m_map.put (jv, loc);
+ }
+
+ void on_finished_parsing () final override
+ {
+ linemap_add (m_line_table, LC_LEAVE, false, NULL, 0);
+ }
+
+ location_t get_range_for_value (json::value *jv)
+ {
+ if (location_t *slot = m_map.get (jv))
+ return *slot;
+ return UNKNOWN_LOCATION;
+ }
+
+ location_t make_location_for_range (const range &r)
+ {
+ location_t start = make_location_for_point (r.m_start);
+ location_t end = make_location_for_point (r.m_end);
+ return make_location (start, start, end);
+ }
+
+private:
+ location_t make_location_for_point (const point &p)
+ {
+ /* json::location_map::point columns are zero-based,
+ whereas libcpp/gcc columns are 1-based. */
+ const int gcc_column = p.m_column + 1;
+ const int max_column = MAX (1024, gcc_column);
+ linemap_line_start (m_line_table, p.m_line, max_column);
+ return linemap_position_for_column (m_line_table, gcc_column);
+ }
+
+ const char *m_filename;
+ hash_map<json::value *, location_t> m_map;
+ line_maps *m_line_table;
+};
+
+/* Class for reading a JSON file, capturing location_t values for
+ the json::values, and emitting fatal error messages. */
+
+class json_reader
+{
+public:
+ json_reader (const char *filename);
+ json::value *parse_utf8_string (const char *utf8, bool allow_comments,
+ json::error **err_out);
+
+ void fatal_error (json::value *jv,
+ const char *gmsgid, ...)
+ ATTRIBUTE_GCC_DIAG(3,4)
+ ATTRIBUTE_NORETURN;
+
+ void fatal_error (json::error *err)
+ ATTRIBUTE_NORETURN;
+
+protected:
+ const char *m_filename;
+ json_line_map m_json_loc_map;
+};
+
+extern char *read_file (const char *path);
+
+#endif /* GCC_JSON_READER_H */
This patch adds classes that better integrate the JSON parser with GCC's diagnostic subsystem (e.g. line_maps). gcc/ChangeLog: * json-reader.cc: New file. * json-reader.h: New file. Signed-off-by: David Malcolm <dmalcolm@redhat.com> --- gcc/json-reader.cc | 122 +++++++++++++++++++++++++++++++++++++++++++++ gcc/json-reader.h | 107 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 gcc/json-reader.cc create mode 100644 gcc/json-reader.h