new file mode 100644
@@ -0,0 +1,131 @@
+# Make-lang.in -- Top level -*- makefile -*- fragment for gcc JSON "frontend".
+
+# 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/>.
+
+# This file provides the language dependent support in the main Makefile.
+
+# The name for selecting json in LANGUAGES.
+json: json-replay$(exeext)
+
+.PHONY: json
+
+JSON_OBJS = json/json-frontend.o json/json-replay.o \
+ attribs.o deferred-locations.o json-reader.o
+json_OBJS = $(JSON_OBJS)
+
+json-replay$(exeext): $(JSON_OBJS) $(BACKEND) $(LIBDEPS)
+ @$(call LINK_PROGRESS,$(INDEX.json),start)
+ +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+ $(JSON_OBJS) $(BACKEND) $(LIBS) $(BACKENDLIBS)
+ @$(call LINK_PROGRESS,$(INDEX.json),end)
+
+# Build hooks.
+
+json.all.cross:
+json.start.encap:
+json.rest.encap:
+
+json.info:
+json.man:
+
+lang_checks += check-json
+
+# No json-specific selftests
+selftest-json:
+
+# Install hooks.
+
+json.install-common: installdirs
+ -rm -f $(DESTDIR)$(bindir)/$(GCCJSON_INSTALL_NAME)$(exeext)
+ $(INSTALL_PROGRAM) gccjson$(exeext) $(DESTDIR)$(bindir)/$(GCCJSON_INSTALL_NAME)$(exeext)
+ -if test -f json-replay$(exeext); then \
+ if test -f gccjson-cross$(exeext); then \
+ :; \
+ else \
+ rm -f $(DESTDIR)$(bindir)/$(GCCJSON_TARGET_INSTALL_NAME)$(exeext); \
+ ( cd $(DESTDIR)$(bindir) && \
+ $(LN) $(GCCJSON_INSTALL_NAME)$(exeext) $(GCCJSON_TARGET_INSTALL_NAME)$(exeext) ); \
+ fi; \
+ fi
+
+json.install-plugin:
+
+json.install-info: $(DESTDIR)$(infodir)/gccjson.info
+
+json.install-pdf: doc/gccjson.pdf
+ @$(NORMAL_INSTALL)
+ test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc"
+ @for p in doc/gccjson.pdf; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(pdf__strip_dir) \
+ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \
+ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \
+ done
+
+json.install-html: $(build_htmldir)/json
+ @$(NORMAL_INSTALL)
+ test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)"
+ @for p in $(build_htmldir)/json; do \
+ if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \
+ f=$(html__strip_dir) \
+ if test -d "$$d$$p"; then \
+ echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \
+ $(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
+ echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
+ $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \
+ else \
+ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \
+ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \
+ fi; \
+ done
+
+json.install-man: $(DESTDIR)$(man1dir)/$(GCCJSON_INSTALL_NAME)$(man1ext)
+
+
+json.uninstall:
+ rm -rf $(DESTDIR)$(bindir)/$(GCCJSON_INSTALL_NAME)$(exeext)
+ rm -rf $(DESTDIR)$(man1dir)/$(GCCJSON_INSTALL_NAME)$(man1ext)
+ rm -rf $(DESTDIR)$(bindir)/$(GCCJSON_TARGET_INSTALL_NAME)$(exeext)
+ rm -rf $(DESTDIR)$(infodir)/gccjson.info*
+
+# Clean hooks.
+
+json.mostlyclean:
+ -rm -f json/*$(objext)
+ -rm -f json/*$(coverageexts)
+ -rm -f gccjson$(exeext) gccjson-cross$(exeext) json-replay$(exeext)
+json.clean:
+json.distclean:
+json.maintainer-clean:
+ -rm -f $(docobjdir)/gccjson.1
+
+# Stage hooks.
+
+json.stage1: stage1-start
+ -mv json/*$(objext) stage1/json
+json.stage2: stage2-start
+ -mv json/*$(objext) stage2/json
+json.stage3: stage3-start
+ -mv json/*$(objext) stage3/json
+json.stage4: stage4-start
+ -mv json/*$(objext) stage4/json
+json.stageprofile: stageprofile-start
+ -mv json/*$(objext) stageprofile/json
+json.stagefeedback: stagefeedback-start
+ -mv json/*$(objext) stagefeedback/json
new file mode 100644
@@ -0,0 +1,34 @@
+# config-lang.in -- Top level configure fragment for gcc JSON "frontend".
+
+# 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/>.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language - name of language as it would appear in $(LANGUAGES)
+# compilers - value to add to $(COMPILERS)
+
+language="json"
+
+compilers="json-replay\$(exeext)"
+
+gtfiles="\$(srcdir)/json/json-frontend.cc"
+
+# Build by default.
+build_by_default="yes"
new file mode 100644
@@ -0,0 +1,176 @@
+/* The dummy "frontend" for re-emitting diagnostics saved in JSON form.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ 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/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "debug.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "json/json-replay.h"
+#include "opts.h"
+#include "diagnostic.h"
+
+/* Placeholder implementation; needed by a frontend. */
+
+tree
+convert (tree, tree)
+{
+ gcc_unreachable ();
+ return NULL_TREE;
+}
+
+/* Language-dependent contents of a type. */
+
+struct GTY(()) lang_type
+{
+ char dummy;
+};
+
+/* Language-dependent contents of a decl. */
+
+struct GTY((variable_size)) lang_decl
+{
+ char dummy;
+};
+
+/* Language-dependent contents of an identifier. This must include a
+ tree_identifier. */
+
+struct GTY(()) lang_identifier
+{
+ struct tree_identifier common;
+};
+
+/* The resulting tree type. */
+
+union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+ chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
+lang_tree_node
+{
+ union tree_node GTY((tag ("0"),
+ desc ("tree_node_structure (&%h)"))) generic;
+ struct lang_identifier GTY((tag ("1"))) identifier;
+};
+
+/* We don't use language_function. */
+
+struct GTY(()) language_function
+{
+ int dummy;
+};
+
+/* Language hooks. */
+
+static bool
+json_langhook_init (void)
+{
+ replay_json (main_input_filename);
+ return false;
+}
+
+static unsigned int
+json_langhook_option_lang_mask (void)
+{
+ return CL_JSON;
+}
+
+static bool
+json_langhook_handle_option (size_t scode,
+ const char *arg,
+ HOST_WIDE_INT value,
+ int kind,
+ location_t loc,
+ const struct cl_option_handlers *handlers)
+{
+ bool result = true;
+
+ switch (scode)
+ {
+ default:
+ if (cl_options[scode].flags & json_langhook_option_lang_mask ())
+ break;
+ result = false;
+ }
+
+ JSON_handle_option_auto (&global_options, &global_options_set,
+ scode, arg, value,
+ json_langhook_option_lang_mask (), kind,
+ loc, handlers, global_dc);
+
+ return result;
+}
+
+static tree
+json_langhook_type_for_mode (machine_mode, int)
+{
+ gcc_unreachable ();
+ return NULL_TREE;
+}
+
+static bool
+json_langhook_global_bindings_p (void)
+{
+ return true;
+}
+
+static tree
+json_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
+{
+ gcc_unreachable ();
+}
+
+static tree
+json_langhook_getdecls (void)
+{
+ return NULL;
+}
+#undef LANG_HOOKS_NAME
+#define LANG_HOOKS_NAME "json"
+
+#undef LANG_HOOKS_INIT
+#define LANG_HOOKS_INIT json_langhook_init
+
+#undef LANG_HOOKS_OPTION_LANG_MASK
+#define LANG_HOOKS_OPTION_LANG_MASK json_langhook_option_lang_mask
+
+#undef LANG_HOOKS_HANDLE_OPTION
+#define LANG_HOOKS_HANDLE_OPTION json_langhook_handle_option
+
+#undef LANG_HOOKS_TYPE_FOR_MODE
+#define LANG_HOOKS_TYPE_FOR_MODE json_langhook_type_for_mode
+
+#undef LANG_HOOKS_GLOBAL_BINDINGS_P
+#define LANG_HOOKS_GLOBAL_BINDINGS_P json_langhook_global_bindings_p
+
+#undef LANG_HOOKS_PUSHDECL
+#define LANG_HOOKS_PUSHDECL json_langhook_pushdecl
+
+#undef LANG_HOOKS_GETDECLS
+#define LANG_HOOKS_GETDECLS json_langhook_getdecls
+
+#undef LANG_HOOKS_DEEP_UNSHARING
+#define LANG_HOOKS_DEEP_UNSHARING true
+
+struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+#include "gt-json-json-frontend.h"
+#include "gtype-json.h"
new file mode 100644
@@ -0,0 +1,614 @@
+/* Re-emitting diagnostics saved in JSON form.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ 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/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "diagnostic.h"
+#include "diagnostic-metadata.h"
+#include "diagnostic-path.h"
+#include "line-map.h"
+#include "stringpool.h"
+#include "gcc-rich-location.h"
+#include "json-parsing.h"
+#include "json-reader.h"
+#include "deferred-locations.h"
+#include "diagnostic-client-data-hooks.h"
+#include "json/json-replay.h"
+
+class json_replayer;
+
+/* Concrete subclass of diagnostic_client_data_hooks, for
+ use when replaying a json file.
+
+ Takes ownership of the json_replayer and toplevel json::value objects. */
+
+class json_replayer_diagnostic_client_data_hooks
+ : public diagnostic_client_data_hooks
+{
+ public:
+ json_replayer_diagnostic_client_data_hooks (json_replayer *replayer)
+ : m_replayer (replayer),
+ m_toplevel_jv (NULL)
+ {}
+
+ ~json_replayer_diagnostic_client_data_hooks ();
+
+ const client_version_info *get_any_version_info () const final override
+ {
+ /* The JSON dump doesn't contain any version info. */
+ return NULL;
+ }
+ const logical_location *get_current_logical_location () const final override
+ {
+ return NULL; // TODO
+ }
+ const char *
+ maybe_get_sarif_source_language (const char *) const final override
+ {
+ return NULL;
+ }
+
+ void stash (json::value *toplevel_jv)
+ {
+ m_toplevel_jv = toplevel_jv;
+ }
+
+ json_replayer *m_replayer;
+ json::value *m_toplevel_jv;
+};
+
+/* A bundle of state for replaying a GCC diagnostic json file. */
+
+class json_replayer : public json_reader
+{
+public:
+ json_replayer (const char *filename) : json_reader (filename) {}
+ ~json_replayer ();
+
+ void emit_json_as_diagnostics (json::value *jv);
+
+ /* Get the value of property ATTR_NAME within OBJ,
+ exiting with an error if it is not present. */
+ json::value *
+ get_required_attr (json::object *obj, const char *attr_name)
+ {
+ json::value *attr_val = obj->get (attr_name);
+ if (!attr_val)
+ fatal_error (obj,
+ "expected a %qs within object", attr_name);
+ return attr_val;
+ }
+
+ /* Get the value of optional property ATTR_NAME within OBJ,
+ exiting with an error if it is not a string. */
+ const char *
+ get_optional_string_attr (json::object *obj, const char *attr_name)
+ {
+ json::value *attr_val = obj->get (attr_name);
+ if (!attr_val)
+ return NULL;
+ json::string *attr_str = dyn_cast <json::string *> (attr_val);
+ if (!attr_str)
+ fatal_error (attr_val,
+ "expected the value of %qs to be a string", attr_name);
+ return attr_str->get_string ();
+ }
+
+ /* Get the value of property ATTR_NAME within OBJ,
+ exiting with an error if it is not present or is not a string. */
+ const char *
+ get_required_string_attr (json::object *obj, const char *attr_name)
+ {
+ json::value *attr_val = get_required_attr (obj, attr_name);
+ json::string *attr_str = dyn_cast <json::string *> (attr_val);
+ if (!attr_str)
+ fatal_error (attr_val,
+ "expected the value of %qs to be a string", attr_name);
+ return attr_str->get_string ();
+ }
+
+ /* Get the value of optional property ATTR_NAME within OBJ,
+ exiting with an error if it is not an object. */
+ json::object *
+ get_optional_object_attr (json::object *obj, const char *attr_name)
+ {
+ json::value *attr_val = obj->get (attr_name);
+ if (!attr_val)
+ return NULL;
+ json::object *attr_obj = dyn_cast <json::object *> (attr_val);
+ if (!attr_obj)
+ fatal_error (attr_val,
+ "expected the value of %qs to be an object", attr_name);
+ return attr_obj;
+ }
+
+ /* Get the value of property ATTR_NAME within OBJ,
+ exiting with an error if it is not present or is not an object. */
+ json::object *
+ get_required_object_attr (json::object *obj, const char *attr_name)
+ {
+ json::value *attr_val = get_required_attr (obj, attr_name);
+ json::object *attr_obj = dyn_cast <json::object *> (attr_val);
+ if (!attr_obj)
+ fatal_error (attr_val,
+ "expected the value of %qs to be an object", attr_name);
+ return attr_obj;
+ }
+
+ /* Get the value of optional property ATTR_NAME within OBJ,
+ exiting with an error if it is not an array. */
+ json::array *
+ get_optional_array_attr (json::object *obj, const char *attr_name)
+ {
+ json::value *attr_val = obj->get (attr_name);
+ if (!attr_val)
+ return NULL;
+ json::array *attr_arr = dyn_cast <json::array *> (attr_val);
+ if (!attr_arr)
+ fatal_error (attr_val,
+ "expected the value of %qs to be an array", attr_name);
+ return attr_arr;
+ }
+
+ /* Get the value of property ATTR_NAME within OBJ,
+ exiting with an error if it is not present or is not an integer. */
+ long
+ get_required_long_attr (json::object *obj, const char *attr_name)
+ {
+ json::value *attr_val = get_required_attr (obj, attr_name);
+ json::integer_number *attr_int
+ = dyn_cast <json::integer_number *> (attr_val);
+ if (!attr_int)
+ fatal_error (attr_val,
+ "expected the value of %qs to be an integer number",
+ attr_name);
+ return attr_int->get ();
+ }
+
+ /* If OBJ has optional property ATTR_NAME within OBJ and it is an integer,
+ return true and write its value to *OUT.
+ If it is not present, return false.
+ If it is not an integer, exit with an error. */
+ bool
+ get_optional_long_attr (json::object *obj, const char *attr_name, long *out)
+ {
+ json::value *attr_val = obj->get (attr_name);
+ if (!attr_val)
+ return false;
+ json::integer_number *attr_int
+ = dyn_cast <json::integer_number *> (attr_val);
+ if (!attr_int)
+ fatal_error (attr_val,
+ "expected the value of %qs to be an integer number",
+ attr_name);
+ *out = attr_int->get ();
+ return true;
+ }
+
+ json::object *
+ require_object (json::value *jv)
+ {
+ if (json::object *obj = dyn_cast <json::object *> (jv))
+ return obj;
+ fatal_error (jv, "expected an object");
+ return NULL;
+ }
+
+ location_t
+ get_required_expanded_location_attr (json::object *obj, const char *attr_name,
+ deferred_locations *deferred_locs,
+ int pass);
+
+ location_t
+ get_optional_expanded_location_attr (json::object *obj, const char *attr_name,
+ deferred_locations *deferred_locs,
+ int pass);
+private:
+ void emit_diag_obj (json::object *diag_obj,
+ deferred_locations *deferred_locs,
+ int pass);
+ location_t
+ get_location_from_expanded_location_obj (json::object *loc_obj,
+ deferred_locations *deferred_locs,
+ int pass);
+
+ diagnostic_t get_diagnostic_kind (json::object *diag_obj);
+
+ hash_map<json::object *, location_t *> m_map_loc_obj_to_loc_t;
+};
+
+/* class json_replayer_diagnostic_client_data_hooks
+ : public diagnostic_client_data_hooks. */
+
+json_replayer_diagnostic_client_data_hooks::
+~json_replayer_diagnostic_client_data_hooks ()
+{
+ delete m_replayer;
+ delete m_toplevel_jv;
+}
+
+/* class json_replayer : public json_reader. */
+
+json_replayer::~json_replayer ()
+{
+ for (auto iter : m_map_loc_obj_to_loc_t)
+ delete iter.second;
+}
+
+/* In pass 0, defer the creation of a location_t for OBJ (originally created
+ by json_from_expanded_location).
+ In pass 1, look up the location_t that was created. */
+
+location_t
+json_replayer::
+get_location_from_expanded_location_obj (json::object *loc_obj,
+ deferred_locations *deferred_locs,
+ int pass)
+{
+ expanded_location exp_loc = {NULL, 0, 0, NULL, false};
+ exp_loc.file = get_optional_string_attr (loc_obj, "file");
+ long line;
+ if (get_optional_long_attr (loc_obj, "line", &line))
+ exp_loc.line = line;
+ long column;
+ if (get_optional_long_attr (loc_obj, "column", &column))
+ exp_loc.column = column;
+ if (pass)
+ return **m_map_loc_obj_to_loc_t.get (loc_obj);
+ else
+ {
+ location_t *loc = new location_t;
+ deferred_locs->add_location (exp_loc, loc);
+ m_map_loc_obj_to_loc_t.put (loc_obj, loc);
+ return UNKNOWN_LOCATION;
+ }
+}
+
+/* Get the value of property ATTR_NAME within OBJ,
+ exiting with an error if it is not present or not a location.
+ In pass 0, defer the creation of a location_t for the value (originally
+ created by json_from_expanded_location).
+ In pass 1, look up the location_t that was created. */
+
+location_t
+json_replayer::
+get_required_expanded_location_attr (json::object *obj, const char *attr_name,
+ deferred_locations *deferred_locs,
+ int pass)
+{
+ json::object *loc_obj = get_required_object_attr (obj, attr_name);
+ return get_location_from_expanded_location_obj (loc_obj, deferred_locs, pass);
+}
+
+/* As get_required_expanded_location_attr, but return UNKNOWN_LOCATION
+ if ATTR_NAME is not present within OBJ. */
+
+location_t
+json_replayer::
+get_optional_expanded_location_attr (json::object *obj, const char *attr_name,
+ deferred_locations *deferred_locs,
+ int pass)
+{
+ json::object *loc_obj = get_optional_object_attr (obj, attr_name);
+ if (!loc_obj)
+ return UNKNOWN_LOCATION;
+ return get_location_from_expanded_location_obj (loc_obj, deferred_locs, pass);
+}
+
+/* Get the diagnostic_t kind for DIAG_OBJ. */
+
+diagnostic_t
+json_replayer::get_diagnostic_kind (json::object *diag_obj)
+{
+ const char *kind_str = get_required_string_attr (diag_obj, "kind");
+
+ static const char *const diagnostic_kind_text[] = {
+#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T),
+#include "diagnostic.def"
+#undef DEFINE_DIAGNOSTIC_KIND
+ "must-not-happen"
+ };
+ for (unsigned i = 0; i < ARRAY_SIZE (diagnostic_kind_text); i++)
+ {
+ /* Compare, without the trailing ": ". */
+ const char *kind_text = diagnostic_kind_text[i];
+ size_t len = strlen (kind_text);
+ if (len <= 2)
+ continue;
+ gcc_assert (kind_text[len - 2] == ':');
+ gcc_assert (kind_text[len - 1] == ' ');
+ if (0 == strncmp (kind_text, kind_str, len - 2)
+ && kind_str[len - 2] == '\0')
+ return static_cast<diagnostic_t> (i);
+ }
+ fatal_error (diag_obj,
+ "unrecognized value for %qs: %qs", "kind", kind_str);
+}
+
+static hash_map<tree, tree> map_id_to_fndecl;
+
+/* Create a placeholder void -> void function declaration for a function
+ named FUNC_STR. */
+
+static tree
+make_placeholder_fndecl (const char *func_str)
+{
+ tree id = get_identifier (func_str);
+ if (tree *slot = map_id_to_fndecl.get (id))
+ return *slot;
+ tree fndecl = build_fn_decl (func_str, NULL_TREE/*fn_type*/);
+ map_id_to_fndecl.put (id, fndecl);
+ return fndecl;
+}
+
+/* Custom subclass of rich_location, relating to replaying a specific
+ diagnostic serialized to JSON. */
+
+class json_rich_location : public rich_location
+{
+public:
+ json_rich_location (json_replayer *replayer,
+ json::object *diag_obj, deferred_locations *deferred_locs,
+ int pass)
+ : rich_location (line_table, UNKNOWN_LOCATION)
+ {
+ json::value *locations_val
+ = replayer->get_required_attr (diag_obj, "locations");
+ json::array *locations_arr = dyn_cast <json::array *> (locations_val);
+ if (!locations_arr)
+ replayer->fatal_error (locations_val,
+ "expected an array for the value of %qs",
+ "locations");
+ m_ranges.truncate (0);
+ for (auto loc_iter : *locations_arr)
+ {
+ json::object *loc_obj = dyn_cast<json::object *> (loc_iter);
+ if (!loc_obj)
+ replayer->fatal_error (loc_iter,
+ "expected an object within the %qs array",
+ "locations");
+ /* Compare with diagnostic-format-json.cc:json_from_location_range. */
+ location_t caret_loc
+ = replayer->get_required_expanded_location_attr (loc_obj, "caret",
+ deferred_locs, pass);
+ location_t start_loc
+ = replayer->get_optional_expanded_location_attr (loc_obj, "start",
+ deferred_locs, pass);
+ location_t finish_loc
+ = replayer->get_optional_expanded_location_attr (loc_obj, "finish",
+ deferred_locs, pass);
+ if (start_loc == UNKNOWN_LOCATION)
+ start_loc = caret_loc;
+ if (finish_loc == UNKNOWN_LOCATION)
+ finish_loc = caret_loc;
+ const char *label_str
+ = replayer->get_optional_string_attr (loc_obj, "label");
+ range_label *label
+ = label_str ? new text_range_label (label_str) : NULL;
+ location_t range_loc = make_location (caret_loc, start_loc, finish_loc);
+ add_range (range_loc, SHOW_RANGE_WITH_CARET, label);
+ }
+
+ json::array *fixits_arr
+ = replayer->get_optional_array_attr (diag_obj, "fixits");
+ if (fixits_arr)
+ for (auto fixit_iter : *fixits_arr)
+ {
+ json::object *fixit_obj = dyn_cast<json::object *> (fixit_iter);
+ if (!fixit_obj)
+ replayer->fatal_error (fixit_iter,
+ "expected an object within the %qs array",
+ "fixits");
+ on_fixit_obj (replayer, fixit_obj, deferred_locs, pass);
+ }
+
+ json::array *path_arr
+ = replayer->get_optional_array_attr (diag_obj, "path");
+ if (path_arr)
+ {
+ pretty_printer pp;
+ simple_diagnostic_path *path = new simple_diagnostic_path (&pp);
+ set_path (path);
+ for (auto event_iter : *path_arr)
+ {
+ json::object *event_obj = dyn_cast<json::object *> (event_iter);
+ if (!event_obj)
+ replayer->fatal_error (event_iter,
+ "expected an object within the %qs array",
+ "path");
+ location_t loc
+ = replayer->get_optional_expanded_location_attr (event_obj,
+ "location",
+ deferred_locs,
+ pass);
+ const char *desc_str
+ = replayer->get_required_string_attr (event_obj, "description");
+ tree fndecl = NULL_TREE;
+ if (const char *func_str
+ = replayer->get_optional_string_attr (event_obj, "function"))
+ fndecl = make_placeholder_fndecl (func_str);
+ long depth = replayer->get_required_long_attr (event_obj, "depth");
+ path->add_event (loc, fndecl, depth, "%s", desc_str);
+ }
+ }
+ }
+
+private:
+ /* Compare with diagnostic-format-json.cc:json_from_fixit_hint. */
+ void on_fixit_obj (json_replayer *replayer,
+ json::object *fixit_obj,
+ deferred_locations *deferred_locs, int pass)
+ {
+ location_t start_loc
+ = replayer->get_required_expanded_location_attr (fixit_obj, "start",
+ deferred_locs, pass);
+ location_t next_loc
+ = replayer->get_required_expanded_location_attr (fixit_obj, "next",
+ deferred_locs, pass);
+ const char *string
+ = replayer->get_required_string_attr (fixit_obj, "string");
+ if (pass)
+ maybe_add_fixit (start_loc, next_loc, string);
+ }
+};
+
+class json_replayer_rule : public diagnostic_metadata::rule
+{
+public:
+ json_replayer_rule (json_replayer *replayer, json::object *diag_obj)
+ : m_replayer (replayer), m_diag_obj (diag_obj)
+ {}
+
+ char *make_description () const final override
+ {
+ if (const char *option
+ = m_replayer->get_optional_string_attr (m_diag_obj, "option"))
+ return xstrdup (option);
+ return NULL;
+ }
+
+ char *make_url () const final override
+ {
+ if (const char *option_url
+ = m_replayer->get_optional_string_attr (m_diag_obj, "option_url"))
+ return xstrdup (option_url);
+ return NULL;
+ }
+
+private:
+ json_replayer *m_replayer;
+ json::object *m_diag_obj;
+};
+
+
+/* Replay the diagnotic DIAG_OBJ to global_dc.
+ In pass 0, do everything except actually replay the diagnostic,
+ deferring the creation of location_t values.
+ In pass 1, actually emit the diagostic, using real location_t values.
+ Exit with an error if DIAG_OBJ does not match the expected output format. */
+
+void
+json_replayer::emit_diag_obj (json::object *diag_obj,
+ deferred_locations *deferred_locs,
+ int pass)
+{
+ auto_diagnostic_group d;
+
+ diagnostic_t kind = get_diagnostic_kind (diag_obj);
+ const char *message_str = get_required_string_attr (diag_obj, "message");
+
+ json_rich_location rich_loc (this, diag_obj, deferred_locs, pass);
+
+ diagnostic_metadata meta;
+
+ if (json::object *metadata_obj = get_optional_object_attr (diag_obj,
+ "metadata"))
+ {
+ long cwe_long;
+ if (get_optional_long_attr (metadata_obj, "cwe", &cwe_long))
+ meta.add_cwe (cwe_long);
+ }
+
+ bool emitted = true;
+ if (pass == 1)
+ {
+ const int option = 0;
+ json_replayer_rule rule (this, diag_obj);
+ meta.add_rule (rule);
+ emitted = emit_diagnostic (kind, &rich_loc, &meta, option,
+ "%s", message_str);
+ }
+
+ if (emitted)
+ if (json::value *children_val = diag_obj->get ("children"))
+ {
+ json::array *children_arr = dyn_cast <json::array *> (children_val);
+ if (!children_arr)
+ fatal_error (children_val,
+ "expected an array for the value of %qs",
+ "children");
+ for (auto child_val : *children_arr)
+ {
+ /* We expect an array of objects. */
+ json::object *child_obj = dyn_cast <json::object *> (child_val);
+ if (!child_obj)
+ fatal_error (child_val,
+ "expected an object within the %qs array",
+ "children");
+ emit_diag_obj (child_obj, deferred_locs, pass);
+ }
+ }
+}
+
+/* Replay the diagnotics in JV to global_dc.
+ Exit with an error if JV does not match the expected output format. */
+
+void
+json_replayer::emit_json_as_diagnostics (json::value *jv)
+{
+ /* We expect an array as the top-level value. */
+ json::array *toplev_arr = dyn_cast <json::array *> (jv);
+ if (!toplev_arr)
+ fatal_error (jv, "expected an array as the top-level value");
+
+ deferred_locations deferred_locs;
+
+ for (int pass = 0; pass < 2; pass++)
+ {
+ for (auto diag_val : *toplev_arr)
+ {
+ /* We expect an object. */
+ json::object *diag_obj = require_object (diag_val);
+ emit_diag_obj (diag_obj, &deferred_locs, pass);
+ }
+ if (pass == 0)
+ deferred_locs.generate_location_t_values ();
+ }
+}
+
+/* Attempt to load a json file from FILENAME and replay it.
+ Exit on any errors. */
+
+void
+replay_json (const char *filename)
+{
+ json_replayer *p = new json_replayer (filename);
+ json_replayer_diagnostic_client_data_hooks *hooks
+ = new json_replayer_diagnostic_client_data_hooks (p);
+ global_dc->m_client_data_hooks = hooks;
+
+ char *content = read_file (filename);
+ json::error *err = NULL;
+ json::value *jv = p->parse_utf8_string (content, flag_allow_comments, &err);
+ if (err)
+ {
+ p->fatal_error (err);
+ delete err;
+ }
+ free (content);
+
+ if (jv)
+ {
+ hooks->stash (jv);
+ p->emit_json_as_diagnostics (jv);
+ }
+}
new file mode 100644
@@ -0,0 +1,26 @@
+/* Re-emitting diagnostics saved in JSON form.
+ 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_JSON_REPLAY_H
+#define GCC_JSON_JSON_REPLAY_H
+
+extern void replay_json (const char *filename);
+
+#endif /* GCC_JSON_JSON_H */
new file mode 100644
@@ -0,0 +1,26 @@
+/* lang-specs.h -- gcc driver specs for the JSON "frontend".
+ 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/>. */
+
+/* This is the contribution to the `default_compilers' array in gcc.cc
+ for the json "frontend". */
+
+{".json", "@json", 0, 1, 0},
+/* FIXME: */
+{"@json", "json-replay %i %(cc1_options)",
+ 0, 1, 0},
new file mode 100644
@@ -0,0 +1,31 @@
+; Options for the JSON front end.
+; 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/>.
+
+; See the GCC internals manual for a description of this file's format.
+
+; Please try to keep this file in ASCII collating order.
+
+Language
+JSON
+
+fallow-comments
+JSON Var(flag_allow_comments)
+Extend JSON to support comments
+
+; This comment is to ensure we retain the blank line above.
new file mode 100644
@@ -0,0 +1,6 @@
+[ "foo", "bar" "baz"] // { dg-error "expected ',' or '\]'; got string" }
+
+{ dg-begin-multiline-output "" }
+ 1 | [ "foo", "bar" "baz"]
+ | ^~~~~
+{ dg-end-multiline-output "" }
new file mode 100644
@@ -0,0 +1,6 @@
+[ 0, 1, 2, ] /* { dg-error "expected a JSON value but got '\\\]'" } */
+
+{ dg-begin-multiline-output "" }
+ 1 | [ 0, 1, 2, ]
+ | ^
+{ dg-end-multiline-output "" }
new file mode 100644
@@ -0,0 +1,6 @@
+ not a valid JSON file // { dg-error "invalid JSON token: unexpected character: 'n'" }
+
+{ dg-begin-multiline-output "" }
+ 1 | not a valid JSON file
+ | ^
+{ dg-end-multiline-output "" }
new file mode 100644
@@ -0,0 +1,7 @@
+{ "foo": "bar"
+ "baz": 42 } // { dg-error "expected ',' or '\}'; got string" }
+
+{ dg-begin-multiline-output "" }
+ 2 | "baz": 42 }
+ | ^~~~~
+{ dg-end-multiline-output "" }
new file mode 100644
@@ -0,0 +1,6 @@
+{ "foo": "bar", } /* { dg-error "expected string for object key after ','; got '\\\}'" } */
+
+{ dg-begin-multiline-output "" }
+ 1 | { "foo": "bar", }
+ | ^
+{ dg-end-multiline-output "" }
new file mode 100644
@@ -0,0 +1,6 @@
+[ 42 ] /* { dg-error "expected an object" } */
+
+/* { dg-begin-multiline-output "" }
+ 1 | [ 42 ]
+ | ^~
+ { dg-end-multiline-output "" } */
new file mode 100644
@@ -0,0 +1,20 @@
+[
+ {
+ "kind": 42, /* { dg-error "expected the value of 'kind' to be a string" } */
+ "locations": [],
+ "column-origin": 1,
+ "option": "-Wanalyzer-unsafe-call-within-signal-handler",
+ "escape-source": false,
+ "children": [],
+ "option_url": "https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-unsafe-call-within-signal-handler",
+ "message": "call to \u2018fprintf\u2019 from within signal handler",
+ "metadata": {
+ "cwe": 479
+ }
+ }
+]
+
+/* { dg-begin-multiline-output "" }
+ 3 | "kind": 42,
+ | ^~
+ { dg-end-multiline-output "" } */
new file mode 100644
@@ -0,0 +1,6 @@
+{ "foo": "bar" } /* { dg-error "expected an array as the top-level value" } */
+
+/* { dg-begin-multiline-output "" }
+ 1 | { "foo": "bar" }
+ | ^~~~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
new file mode 100644
@@ -0,0 +1,50 @@
+# Copyright (C) 2004-2022 Free Software Foundation, Inc.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib json-dg.exp
+
+#load_lib dg.exp
+#load_lib prune.exp
+#load_lib target-supports.exp
+#load_lib gcc-defs.exp
+#load_lib timeout.exp
+#load_lib target-libpath.exp
+#load_lib gcc.exp
+#load_lib g++.exp
+#load_lib dejagnu.exp
+#load_lib prune.exp
+#load_lib gcc-defs.exp
+#load_lib timeout.exp
+#load_lib target-libpath.exp
+#load_lib target-supports.exp
+#load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_JSON_FLAGS
+if ![info exists DEFAULT_JSON_FLAGS] then {
+ set DEFAULT_JSON_FLAGS "-fallow-comments"
+}
+# Initialize `dg'.
+dg-init
+
+dg-runtest [lsort \
+ [glob -nocomplain $srcdir/$subdir/*.json ] ] "" $DEFAULT_JSON_FLAGS
+
+# All done.
+dg-finish
new file mode 100644
@@ -0,0 +1,131 @@
+[
+ {
+ "kind": "warning",
+ "locations": [
+ {
+ "finish": {
+ "byte-column": 33,
+ "display-column": 33,
+ "line": 13,
+ "file": "../../src/gcc/testsuite/gcc.dg/analyzer/signal-1.c",
+ "column": 33
+ },
+ "caret": {
+ "byte-column": 3,
+ "display-column": 3,
+ "line": 13,
+ "file": "../../src/gcc/testsuite/gcc.dg/analyzer/signal-1.c",
+ "column": 3
+ }
+ }
+ ],
+ "path": [
+ {
+ "location": {
+ "byte-column": 5,
+ "display-column": 5,
+ "line": 21,
+ "file": "../../src/gcc/testsuite/gcc.dg/analyzer/signal-1.c",
+ "column": 5
+ },
+ "description": "entry to \u2018main\u2019",
+ "depth": 1,
+ "function": "main"
+ },
+ {
+ "location": {
+ "byte-column": 3,
+ "display-column": 3,
+ "line": 25,
+ "file": "../../src/gcc/testsuite/gcc.dg/analyzer/signal-1.c",
+ "column": 3
+ },
+ "description": "registering \u2018handler\u2019 as signal handler",
+ "depth": 1,
+ "function": "main"
+ },
+ {
+ "description": "later on, when the signal is delivered to the process",
+ "depth": 0
+ },
+ {
+ "location": {
+ "byte-column": 13,
+ "display-column": 13,
+ "line": 16,
+ "file": "../../src/gcc/testsuite/gcc.dg/analyzer/signal-1.c",
+ "column": 13
+ },
+ "description": "entry to \u2018handler\u2019",
+ "depth": 1,
+ "function": "handler"
+ },
+ {
+ "location": {
+ "byte-column": 3,
+ "display-column": 3,
+ "line": 18,
+ "file": "../../src/gcc/testsuite/gcc.dg/analyzer/signal-1.c",
+ "column": 3
+ },
+ "description": "calling \u2018custom_logger\u2019 from \u2018handler\u2019",
+ "depth": 1,
+ "function": "handler"
+ },
+ {
+ "location": {
+ "byte-column": 6,
+ "display-column": 6,
+ "line": 11,
+ "file": "../../src/gcc/testsuite/gcc.dg/analyzer/signal-1.c",
+ "column": 6
+ },
+ "description": "entry to \u2018custom_logger\u2019",
+ "depth": 2,
+ "function": "custom_logger"
+ },
+ {
+ "location": {
+ "byte-column": 3,
+ "display-column": 3,
+ "line": 13,
+ "file": "../../src/gcc/testsuite/gcc.dg/analyzer/signal-1.c",
+ "column": 3
+ },
+ "description": "call to \u2018fprintf\u2019 from within signal handler",
+ "depth": 2,
+ "function": "custom_logger"
+ }
+ ],
+ "column-origin": 1,
+ "option": "-Wanalyzer-unsafe-call-within-signal-handler",
+ "escape-source": false,
+ "children": [],
+ "option_url": "https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-unsafe-call-within-signal-handler",
+ "message": "call to \u2018fprintf\u2019 from within signal handler",
+ "metadata": {
+ "cwe": 479
+ }
+ }
+]
+
+/* { dg-begin-multiline-output "" }
+../../src/gcc/testsuite/gcc.dg/analyzer/signal-1.c:13:3: warning: call to ‘fprintf’ from within signal handler [CWE-479] [-Wanalyzer-unsafe-call-within-signal-handler]
+ 'main': events 1-2
+ |
+ |......
+ |
+ event 3
+ |
+ |json-replay:
+ | (3): later on, when the signal is delivered to the process
+ |
+ +--> 'handler': events 4-5
+ |
+ |
+ +--> 'custom_logger': events 6-7
+ |
+ |
+ { dg-end-multiline-output "" } */
+
+// TODO: various things wrong here
new file mode 100644
@@ -0,0 +1,233 @@
+# Copyright (C) 2004-2022 Free Software Foundation, Inc.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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/>.
+
+load_lib gcc-dg.exp
+load_lib torture-options.exp
+
+#FIXME: copied from gfortran-dg.exp
+
+# Define json callbacks for dg.exp.
+
+proc json-dg-test { prog do_what extra_tool_flags } {
+ set result \
+ [gcc-dg-test-1 json_target_compile $prog $do_what $extra_tool_flags]
+
+ set comp_output [lindex $result 0]
+ set output_file [lindex $result 1]
+
+ # gcc's default is to print the caret and source code, but
+ # most test cases implicitly use the flag -fno-diagnostics-show-caret
+ # to disable caret (and source code) printing.
+ #
+ # However, a few test cases override this back to the default by
+ # explicily supplying "-fdiagnostics-show-caret", so that we can have
+ # test coverage for caret/source code printing.
+ #
+ # json error messages with caret-printing look like this:
+ # [name]:[locus]:
+ #
+ # some code
+ # 1
+ # Error: Some error at (1)
+ # or
+ # [name]:[locus]:
+ #
+ # some code
+ # 1
+ # [name]:[locus2]:
+ #
+ # some other code
+ # 2
+ # Error: Some error at (1) and (2)
+ # or
+ # [name]:[locus]:
+ #
+ # some code and some more code
+ # 1 2
+ # Error: Some error at (1) and (2)
+ #
+ # If this is such a test case, skip the rest of this function, so
+ # that the test case can explicitly verify the output that it expects.
+ if {[string first "-fdiagnostics-show-caret" $extra_tool_flags] >= 0} {
+ return [list $comp_output $output_file]
+ }
+
+ # Otherwise, caret-printing is disabled.
+ # json errors with caret-printing disabled look like this:
+ # [name]:[locus]: Error: Some error
+ # or
+ # [name]:[locus]: Error: (1)
+ # [name]:[locus2]: Error: Some error at (1) and (2)
+ #
+ # Where [locus] is either [line] or [line].[column] or
+ # [line].[column]-[column] .
+ #
+ # We collapse these to look like:
+ # [name]:[line]:[column]: Error: Some error at (1) and (2)
+ # or
+ # [name]:[line]:[column]: Error: Some error at (1) and (2)
+ # [name]:[line2]:[column]: Error: Some error at (1) and (2)
+ #
+ # Note that these regexps only make sense in the combinations used below.
+ # Note also that is imperative that we first deal with the form with
+ # two loci.
+ set locus_regexp "(\[^\n\]+:\[0-9\]+)\[\.:\](\[0-9\]+)(-\[0-9\]+)?:\n\n\[^\n\]+\n\[^\n\]+\n"
+ set diag_regexp "(\[^\n\]+)\n"
+
+ # We proceed in steps:
+
+ # 1. We add first a column number if none exists.
+ # (Some Fortran diagnostics have the locus after Warning|Error)
+ set colnum_regexp "(^|\n)(Warning: |Error: )?(\[^:\n\]+:\[0-9\]+):(\[ \n\])"
+ regsub -all $colnum_regexp $comp_output "\\1\\3:0:\\4\\2" comp_output
+ verbose "comput_output0:\n$comp_output"
+
+ # 2. We deal with the form with two different locus lines,
+ set two_loci "(^|\n)$locus_regexp$locus_regexp$diag_regexp"
+ regsub -all $two_loci $comp_output "\\1\\2:\\3: \\8\n\\5\:\\6: \\8\n" comp_output
+ verbose "comput_output1:\n$comp_output"
+
+ set locus_prefix "(\[^:\n\]+:\[0-9\]+:\[0-9\]+: )(Warning: |Error: )"
+ set two_loci2 "(^|\n)$locus_prefix\\(1\\)\n$locus_prefix$diag_regexp"
+ regsub -all $two_loci2 $comp_output "\\1\\2\\3\\6\n\\4\\5\\6\n" comp_output
+ verbose "comput_output2:\n$comp_output"
+
+ # 3. then with the form with only one locus line.
+ set single_locus "(^|\n)$locus_regexp$diag_regexp"
+ regsub -all $single_locus $comp_output "\\1\\2:\\3: \\5\n" comp_output
+ verbose "comput_output3:\n$comp_output"
+
+ # 4. Add a line number if none exists
+ regsub -all "(^|\n)(Warning: |Error: )" $comp_output "\\1:0:0: \\2" comp_output
+ verbose "comput_output4:\n$comp_output"
+ return [list $comp_output $output_file]
+}
+
+proc json-dg-prune { system text } {
+ return [gcc-dg-prune $system $text]
+}
+
+# Utility routines.
+
+# Modified dg-runtest that can cycle through a list of optimization options
+# as c-torture does.
+proc json-dg-runtest { testcases flags default-extra-flags } {
+ global runtests
+ global torture_with_loops
+
+ # Some callers set torture options themselves; don't override those.
+ set existing_torture_options [torture-options-exist]
+ if { $existing_torture_options == 0 } {
+ global DG_TORTURE_OPTIONS
+ torture-init
+ set-torture-options $DG_TORTURE_OPTIONS
+ }
+ dump-torture-options
+
+ foreach test $testcases {
+ # If we're only testing specific files and this isn't one of
+ # them, skip it.
+ if ![runtest_file_p $runtests $test] {
+ continue
+ }
+
+ # look if this is dg-do-run test, in which case
+ # we cycle through the option list, otherwise we don't
+ if [expr [search_for $test "dg-do run"]] {
+ set option_list $torture_with_loops
+ } else {
+ set option_list [list { -O } ]
+ }
+
+ set nshort [file tail [file dirname $test]]/[file tail $test]
+ list-module-names $test
+
+ foreach flags_t $option_list {
+ verbose "Testing $nshort, $flags $flags_t" 1
+ dg-test $test "$flags $flags_t" ${default-extra-flags}
+ cleanup-modules ""
+ }
+ }
+
+ if { $existing_torture_options == 0 } {
+ torture-finish
+ }
+}
+
+proc json-dg-debug-runtest { target_compile trivial opt_opts testcases } {
+ global srcdir subdir DEBUG_TORTURE_OPTIONS
+
+ if ![info exists DEBUG_TORTURE_OPTIONS] {
+ set DEBUG_TORTURE_OPTIONS ""
+ set type_list [list "-gstabs" "-gstabs+" "-gxcoff" "-gxcoff+" "-gdwarf-2" ]
+ foreach type $type_list {
+ set comp_output [$target_compile \
+ "$srcdir/$subdir/$trivial" "trivial.S" assembly \
+ "additional_flags=$type"]
+ if { [string match "exit status *" $comp_output] } {
+ continue
+ }
+ if { [string match \
+ "* target system does not support the * debug format*" \
+ $comp_output]
+ } {
+ continue
+ }
+ remove-build-file "trivial.S"
+ foreach level {1 "" 3} {
+ if { ($type == "-gdwarf-2") && ($level != "") } {
+ lappend DEBUG_TORTURE_OPTIONS [list "${type}" "-g${level}"]
+ foreach opt $opt_opts {
+ lappend DEBUG_TORTURE_OPTIONS \
+ [list "${type}" "-g${level}" "$opt" ]
+ }
+ } else {
+ lappend DEBUG_TORTURE_OPTIONS [list "${type}${level}"]
+ foreach opt $opt_opts {
+ lappend DEBUG_TORTURE_OPTIONS \
+ [list "${type}${level}" "$opt" ]
+ }
+ }
+ }
+ }
+ }
+
+ verbose -log "Using options $DEBUG_TORTURE_OPTIONS"
+
+ global runtests
+
+ foreach test $testcases {
+ # If we're only testing specific files and this isn't one of
+ # them, skip it.
+ if ![runtest_file_p $runtests $test] {
+ continue
+ }
+
+ set nshort [file tail [file dirname $test]]/[file tail $test]
+ list-module-names $test
+
+ foreach flags $DEBUG_TORTURE_OPTIONS {
+ set doit 1
+ # gcc-specific checking removed here
+
+ if { $doit } {
+ verbose -log "Testing $nshort, $flags" 1
+ dg-test $test $flags ""
+ cleanup-modules ""
+ }
+ }
+ }
+}
new file mode 100644
@@ -0,0 +1,36 @@
+# Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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/>.
+
+# FIXME: copied from gfortran.exp
+
+# This file is just 'sed -e 's/77/fortran/g' \
+# -e 's/f2c/gfortran' g77.exp > gfortran.exp'
+#
+# with some minor modifications to make it work.
+
+#
+# json support library routines
+#
+load_lib prune.exp
+load_lib gcc-defs.exp
+load_lib timeout.exp
+load_lib target-libpath.exp
+load_lib target-supports.exp
+
+proc json_target_compile { source dest type options } {
+ set return_val [target_compile $source $dest $type $options]
+ return $return_val;
+}