aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/c/c-objc-common.cc4
-rw-r--r--gcc/config/aarch64/aarch64.cc1
-rw-r--r--gcc/config/arm/arm.cc1
-rw-r--r--gcc/config/i386/i386.cc1
-rw-r--r--gcc/config/loongarch/loongarch.cc1
-rw-r--r--gcc/config/riscv/riscv-vector-costs.cc1
-rw-r--r--gcc/config/riscv/riscv.cc1
-rw-r--r--gcc/config/rs6000/rs6000.cc1
-rw-r--r--gcc/cp/error.cc106
-rw-r--r--gcc/diagnostic-event-id.h6
-rw-r--r--gcc/diagnostic-format-sarif.cc605
-rw-r--r--gcc/diagnostic.cc2
-rw-r--r--gcc/dump-context.h45
-rw-r--r--gcc/dumpfile.cc348
-rw-r--r--gcc/fortran/error.cc5
-rw-r--r--gcc/fortran/trans-io.cc3
-rw-r--r--gcc/gimple-loop-interchange.cc1
-rw-r--r--gcc/gimple-loop-jam.cc1
-rw-r--r--gcc/gimple-loop-versioning.cc1
-rw-r--r--gcc/graphite-dependences.cc1
-rw-r--r--gcc/graphite-isl-ast-to-gimple.cc1
-rw-r--r--gcc/graphite-optimize-isl.cc1
-rw-r--r--gcc/graphite-poly.cc1
-rw-r--r--gcc/graphite-scop-detection.cc1
-rw-r--r--gcc/graphite-sese-to-poly.cc1
-rw-r--r--gcc/graphite.cc1
-rw-r--r--gcc/opt-problem.cc4
-rw-r--r--gcc/optinfo.cc8
-rw-r--r--gcc/optinfo.h11
-rw-r--r--gcc/pretty-print-format-impl.h489
-rw-r--r--gcc/pretty-print-markup.h10
-rw-r--r--gcc/pretty-print-urlifier.h2
-rw-r--r--gcc/pretty-print.cc1202
-rw-r--r--gcc/pretty-print.h88
-rw-r--r--gcc/sese.cc1
-rw-r--r--gcc/targhooks.cc1
-rw-r--r--gcc/testsuite/gcc.dg/plugin/dump_plugin.c1
-rw-r--r--gcc/testsuite/gcc.dg/sarif-output/bad-pragma.c16
-rw-r--r--gcc/testsuite/gcc.dg/sarif-output/test-bad-pragma.py38
-rw-r--r--gcc/testsuite/gcc.dg/sarif-output/test-include-chain-2.py6
-rw-r--r--gcc/testsuite/gfortran.dg/use_rename_12.f9027
-rw-r--r--gcc/tree-data-ref.cc1
-rw-r--r--gcc/tree-diagnostic.cc2
-rw-r--r--gcc/tree-diagnostic.h2
-rw-r--r--gcc/tree-if-conv.cc1
-rw-r--r--gcc/tree-loop-distribution.cc1
-rw-r--r--gcc/tree-parloops.cc1
-rw-r--r--gcc/tree-predcom.cc1
-rw-r--r--gcc/tree-ssa-live.cc1
-rw-r--r--gcc/tree-ssa-loop-ivcanon.cc1
-rw-r--r--gcc/tree-ssa-loop-ivopts.cc1
-rw-r--r--gcc/tree-ssa-loop-prefetch.cc1
-rw-r--r--gcc/tree-ssa-loop-unswitch.cc1
-rw-r--r--gcc/tree-ssa-phiopt.cc1
-rw-r--r--gcc/tree-ssa-threadbackward.cc1
-rw-r--r--gcc/tree-ssa-threadupdate.cc1
-rw-r--r--gcc/tree-vect-data-refs.cc1
-rw-r--r--gcc/tree-vect-generic.cc1
-rw-r--r--gcc/tree-vect-loop-manip.cc1
-rw-r--r--gcc/tree-vect-loop.cc1
-rw-r--r--gcc/tree-vect-patterns.cc1
-rw-r--r--gcc/tree-vect-slp-patterns.cc1
-rw-r--r--gcc/tree-vect-slp.cc1
-rw-r--r--gcc/tree-vect-stmts.cc1
-rw-r--r--gcc/tree-vectorizer.cc1
65 files changed, 2333 insertions, 738 deletions
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index fde9ae6..9d39fcd 100644
--- a/gcc/c/c-objc-common.cc
+++ b/gcc/c/c-objc-common.cc
@@ -34,7 +34,7 @@ along with GCC; see the file COPYING3. If not see
#include "dwarf2.h"
static bool c_tree_printer (pretty_printer *, text_info *, const char *,
- int, bool, bool, bool, bool *, const char **);
+ int, bool, bool, bool, bool *, pp_token_list &);
/* Info for C language features which can be queried through
__has_{feature,extension}. */
@@ -318,7 +318,7 @@ pp_markup::element_quoted_type::print_type (pp_markup::context &ctxt)
static bool
c_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
int precision, bool wide, bool set_locus, bool hash,
- bool *quoted, const char **)
+ bool *quoted, pp_token_list &)
{
tree t = NULL_TREE;
// FIXME: the next cast should be a dynamic_cast, when it is permitted.
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 033ea61..27e24ba 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -22,6 +22,7 @@
#define INCLUDE_STRING
#define INCLUDE_ALGORITHM
+#define INCLUDE_MEMORY
#define INCLUDE_VECTOR
#include "config.h"
#include "system.h"
diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc
index d54564a..1748544 100644
--- a/gcc/config/arm/arm.cc
+++ b/gcc/config/arm/arm.cc
@@ -23,6 +23,7 @@
#define IN_TARGET_CODE 1
#include "config.h"
+#define INCLUDE_MEMORY
#define INCLUDE_STRING
#include "system.h"
#include "coretypes.h"
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 224a78c..a1f65d4 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -17,6 +17,7 @@ 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/>. */
+#define INCLUDE_MEMORY
#define INCLUDE_STRING
#define IN_TARGET_CODE 1
diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index c7a0210..f956ee4 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
#define IN_TARGET_CODE 1
+#define INCLUDE_MEMORY
#include "config.h"
#include "system.h"
#include "coretypes.h"
diff --git a/gcc/config/riscv/riscv-vector-costs.cc b/gcc/config/riscv/riscv-vector-costs.cc
index a80e167..25570bd 100644
--- a/gcc/config/riscv/riscv-vector-costs.cc
+++ b/gcc/config/riscv/riscv-vector-costs.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
#define IN_TARGET_CODE 1
+#define INCLUDE_MEMORY
#define INCLUDE_STRING
#include "config.h"
#include "system.h"
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 3f5dfb8..496dd17 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
#define IN_TARGET_CODE 1
+#define INCLUDE_MEMORY
#define INCLUDE_STRING
#include "config.h"
#include "system.h"
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 94c0db4..08579bc 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -22,6 +22,7 @@
#define IN_TARGET_CODE 1
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 879e5a1..420fad2 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3. If not see
#include "c-family/c-type-mismatch.h"
#include "cp-name-hint.h"
#include "attribs.h"
+#include "pretty-print-format-impl.h"
+#include "make-unique.h"
#define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',')
#define pp_separate_with_semicolon(PP) pp_cxx_separate_with (PP, ';')
@@ -109,7 +111,7 @@ static void cp_print_error_function (diagnostic_context *,
const diagnostic_info *);
static bool cp_printer (pretty_printer *, text_info *, const char *,
- int, bool, bool, bool, bool *, const char **);
+ int, bool, bool, bool, bool *, pp_token_list &);
/* Color names for highlighting "%qH" vs "%qI" values,
and ranges corresponding to them. */
@@ -123,22 +125,50 @@ class deferred_printed_type
{
public:
deferred_printed_type ()
- : m_tree (NULL_TREE), m_buffer_ptr (NULL), m_verbose (false), m_quote (false)
+ : m_tree (NULL_TREE),
+ m_printed_text (),
+ m_token_list (nullptr),
+ m_verbose (false), m_quote (false)
{}
- deferred_printed_type (tree type, const char **buffer_ptr, bool verbose,
+ deferred_printed_type (tree type,
+ pp_token_list &token_list,
+ bool verbose,
bool quote)
- : m_tree (type), m_buffer_ptr (buffer_ptr), m_verbose (verbose),
+ : m_tree (type),
+ m_printed_text (),
+ m_token_list (&token_list),
+ m_verbose (verbose),
m_quote (quote)
{
gcc_assert (type);
- gcc_assert (buffer_ptr);
+ }
+
+ void set_text_for_token_list (const char *text, bool quote)
+ {
+ /* Replace the contents of m_token_list with a text token for TEXT,
+ possibly wrapped by BEGIN_QUOTE/END_QUOTE (if QUOTE is true).
+ This allows us to ignore any {BEGIN,END}_QUOTE tokens added
+ by %qH and %qI, and instead use the quoting from type_to_string,
+ and its logic for "aka". */
+ while (m_token_list->m_first)
+ m_token_list->pop_front ();
+
+ if (quote)
+ m_token_list->push_back<pp_token_begin_quote> ();
+
+ // TEXT is gc-allocated, so we can borrow it
+ m_token_list->push_back_text (label_text::borrow (text));
+
+ if (quote)
+ m_token_list->push_back<pp_token_end_quote> ();
}
/* The tree is not GTY-marked: they are only non-NULL within a
call to pp_format. */
tree m_tree;
- const char **m_buffer_ptr;
+ label_text m_printed_text;
+ pp_token_list *m_token_list;
bool m_verbose;
bool m_quote;
};
@@ -4401,26 +4431,7 @@ append_formatted_chunk (pretty_printer *pp, const char *content)
{
output_buffer *buffer = pp_buffer (pp);
chunk_info *chunk_array = buffer->cur_chunk_array;
- chunk_array->append_formatted_chunk (content);
-}
-
-/* Create a copy of CONTENT, with quotes added, and,
- potentially, with colorization.
- No escaped is performed on CONTENT.
- The result is in a GC-allocated buffer. */
-
-static const char *
-add_quotes (const char *content, bool show_color)
-{
- pretty_printer tmp_pp;
- pp_show_color (&tmp_pp) = show_color;
-
- /* We have to use "%<%s%>" rather than "%qs" here in order to avoid
- quoting colorization bytes within the results and using either
- pp_quote or pp_begin_quote doesn't work the same. */
- pp_printf (&tmp_pp, "%<%s%>", content);
-
- return pp_ggc_formatted_text (&tmp_pp);
+ chunk_array->append_formatted_chunk (buffer->chunk_obstack, content);
}
#if __GNUC__ >= 10
@@ -4428,8 +4439,8 @@ add_quotes (const char *content, bool show_color)
#endif
/* If we had %H and %I, and hence deferred printing them,
- print them now, storing the result into the chunk_info
- for pp_format. Quote them if 'q' was provided.
+ print them now, storing the result into custom_token_value
+ for the custom pp_token. Quote them if 'q' was provided.
Also print the difference in tree form, adding it as
an additional chunk. */
@@ -4447,13 +4458,13 @@ cxx_format_postprocessor::handle (pretty_printer *pp)
= show_highlight_colors ? highlight_colors::percent_i : nullptr;
/* Avoid reentrancy issues by working with a copy of
m_type_a and m_type_b, resetting them now. */
- deferred_printed_type type_a = m_type_a;
- deferred_printed_type type_b = m_type_b;
+ deferred_printed_type type_a = std::move (m_type_a);
+ deferred_printed_type type_b = std::move (m_type_b);
m_type_a = deferred_printed_type ();
m_type_b = deferred_printed_type ();
- gcc_assert (type_a.m_buffer_ptr);
- gcc_assert (type_b.m_buffer_ptr);
+ gcc_assert (type_a.m_token_list);
+ gcc_assert (type_b.m_token_list);
bool show_color = pp_show_color (pp);
@@ -4494,13 +4505,8 @@ cxx_format_postprocessor::handle (pretty_printer *pp)
percent_i);
}
- if (type_a.m_quote)
- type_a_text = add_quotes (type_a_text, show_color);
- *type_a.m_buffer_ptr = type_a_text;
-
- if (type_b.m_quote)
- type_b_text = add_quotes (type_b_text, show_color);
- *type_b.m_buffer_ptr = type_b_text;
+ type_a.set_text_for_token_list (type_a_text, type_a.m_quote);
+ type_b.set_text_for_token_list (type_b_text, type_b.m_quote);
}
}
@@ -4525,9 +4531,12 @@ cxx_format_postprocessor::handle (pretty_printer *pp)
pretty_printer's m_format_postprocessor hook.
This is called in phase 2 of pp_format, when it is accumulating
- a series of formatted chunks. We stash the location of the chunk
- we're meant to have written to, so that we can write to it in the
- m_format_postprocessor hook.
+ a series of pp_token lists. Since we have to interact with the
+ fiddly quoting logic for "aka", we store the pp_token_list *
+ and in the m_format_postprocessor hook we generate text for the type
+ (possibly with quotes and colors), then replace all tokens in that token list
+ (such as [BEGIN_QUOTE, END_QUOTE]) with a text token containing the
+ freshly generated text.
We also need to stash whether a 'q' prefix was provided (the QUOTE
param) so that we can add the quotes when writing out the delayed
@@ -4535,12 +4544,13 @@ cxx_format_postprocessor::handle (pretty_printer *pp)
static void
defer_phase_2_of_type_diff (deferred_printed_type *deferred,
- tree type, const char **buffer_ptr,
+ tree type,
+ pp_token_list &formatted_token_list,
bool verbose, bool quote)
{
gcc_assert (deferred->m_tree == NULL_TREE);
- gcc_assert (deferred->m_buffer_ptr == NULL);
- *deferred = deferred_printed_type (type, buffer_ptr, verbose, quote);
+ *deferred = deferred_printed_type (type, formatted_token_list,
+ verbose, quote);
}
/* Implementation of pp_markup::element_quoted_type::print_type
@@ -4577,7 +4587,7 @@ pp_markup::element_quoted_type::print_type (pp_markup::context &ctxt)
static bool
cp_printer (pretty_printer *pp, text_info *text, const char *spec,
int precision, bool wide, bool set_locus, bool verbose,
- bool *quoted, const char **buffer_ptr)
+ bool *quoted, pp_token_list &formatted_token_list)
{
gcc_assert (pp_format_postprocessor (pp));
cxx_format_postprocessor *postprocessor
@@ -4617,11 +4627,11 @@ cp_printer (pretty_printer *pp, text_info *text, const char *spec,
case 'F': result = fndecl_to_string (next_tree, verbose); break;
case 'H':
defer_phase_2_of_type_diff (&postprocessor->m_type_a, next_tree,
- buffer_ptr, verbose, *quoted);
+ formatted_token_list, verbose, *quoted);
return true;
case 'I':
defer_phase_2_of_type_diff (&postprocessor->m_type_b, next_tree,
- buffer_ptr, verbose, *quoted);
+ formatted_token_list, verbose, *quoted);
return true;
case 'L': result = language_to_string (next_lang); break;
case 'O': result = op_to_string (false, next_tcode); break;
diff --git a/gcc/diagnostic-event-id.h b/gcc/diagnostic-event-id.h
index 78c2ccb..8237ba3 100644
--- a/gcc/diagnostic-event-id.h
+++ b/gcc/diagnostic-event-id.h
@@ -41,6 +41,12 @@ class diagnostic_event_id_t
bool known_p () const { return m_index != UNKNOWN_EVENT_IDX; }
+ int zero_based () const
+ {
+ gcc_assert (known_p ());
+ return m_index;
+ }
+
int one_based () const
{
gcc_assert (known_p ());
diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc
index 59d9cd7..9d9e7ae 100644
--- a/gcc/diagnostic-format-sarif.cc
+++ b/gcc/diagnostic-format-sarif.cc
@@ -45,6 +45,8 @@ along with GCC; see the file COPYING3. If not see
#include "selftest-diagnostic-show-locus.h"
#include "selftest-json.h"
#include "text-range-label.h"
+#include "pretty-print-format-impl.h"
+#include "pretty-print-urlifier.h"
/* Forward decls. */
class sarif_builder;
@@ -385,7 +387,12 @@ private:
class sarif_result : public sarif_location_manager
{
public:
- sarif_result () : m_related_locations_arr (nullptr) {}
+ sarif_result (unsigned idx_within_parent)
+ : m_related_locations_arr (nullptr),
+ m_idx_within_parent (idx_within_parent)
+ {}
+
+ unsigned get_index_within_parent () const { return m_idx_within_parent; }
void
on_nested_diagnostic (diagnostic_context &context,
@@ -402,6 +409,7 @@ public:
private:
json::array *m_related_locations_arr; // borrowed
+ const unsigned m_idx_within_parent;
};
/* Subclass of sarif_object for SARIF "location" objects
@@ -460,7 +468,39 @@ private:
/* Subclass of sarif_object for SARIF "codeFlow" objects
(SARIF v2.1.0 section 3.36). */
-class sarif_code_flow : public sarif_object {};
+class sarif_code_flow : public sarif_object
+{
+public:
+ sarif_code_flow (sarif_result &parent,
+ unsigned idx_within_parent);
+
+ sarif_result &get_parent () const { return m_parent; }
+ unsigned get_index_within_parent () const { return m_idx_within_parent; }
+
+ sarif_thread_flow &
+ get_or_append_thread_flow (const diagnostic_thread &thread,
+ diagnostic_thread_id_t thread_id);
+
+ sarif_thread_flow &
+ get_thread_flow (diagnostic_thread_id_t thread_id);
+
+ void add_location (sarif_thread_flow_location &);
+
+ sarif_thread_flow_location &
+ get_thread_flow_loc_obj (diagnostic_event_id_t event_id) const;
+
+private:
+ sarif_result &m_parent;
+ const unsigned m_idx_within_parent;
+
+ hash_map<int_hash<diagnostic_thread_id_t, -1, -2>,
+ sarif_thread_flow *> m_thread_id_map; // borrowed ptr
+ json::array *m_thread_flows_arr; // borrowed
+
+ /* Vec of borrowed ptr, allowing for going easily from
+ an event_id to the corresponding threadFlowLocation object. */
+ std::vector<sarif_thread_flow_location *> m_all_tfl_objs;
+};
/* Subclass of sarif_object for SARIF "threadFlow" objects
(SARIF v2.1.0 section 3.37). */
@@ -468,20 +508,41 @@ class sarif_code_flow : public sarif_object {};
class sarif_thread_flow : public sarif_object
{
public:
- sarif_thread_flow (const diagnostic_thread &thread);
+ sarif_thread_flow (sarif_code_flow &parent,
+ const diagnostic_thread &thread,
+ unsigned idx_within_parent);
- void
- add_location
- (std::unique_ptr<sarif_thread_flow_location> thread_flow_loc_obj);
+ sarif_code_flow &get_parent () const { return m_parent; }
+ unsigned get_index_within_parent () const { return m_idx_within_parent; }
+
+ sarif_thread_flow_location &add_location ();
private:
+ sarif_code_flow &m_parent;
json::array *m_locations_arr; // borrowed
+ const unsigned m_idx_within_parent;
};
/* Subclass of sarif_object for SARIF "threadFlowLocation" objects
(SARIF v2.1.0 section 3.38). */
-class sarif_thread_flow_location : public sarif_object {};
+class sarif_thread_flow_location : public sarif_object
+{
+public:
+ sarif_thread_flow_location (sarif_thread_flow &parent,
+ unsigned idx_within_parent)
+ : m_parent (parent),
+ m_idx_within_parent (idx_within_parent)
+ {
+ }
+
+ sarif_thread_flow &get_parent () const { return m_parent; }
+ unsigned get_index_within_parent () const { return m_idx_within_parent; }
+
+private:
+ sarif_thread_flow &m_parent;
+ const unsigned m_idx_within_parent;
+};
/* Subclass of sarif_object for SARIF "reportingDescriptor" objects
(SARIF v2.1.0 section 3.49). */
@@ -632,11 +693,33 @@ public:
std::unique_ptr<sarif_artifact_location>
make_artifact_location_object (const char *filename);
+ const sarif_code_flow *
+ get_code_flow_for_event_ids () const
+ {
+ return m_current_code_flow;
+ }
+
+ token_printer &get_token_printer () { return m_token_printer; }
+
private:
+ class sarif_token_printer : public token_printer
+ {
+ public:
+ sarif_token_printer (sarif_builder &builder)
+ : m_builder (builder)
+ {
+ }
+ void print_tokens (pretty_printer *pp,
+ const pp_token_list &tokens) final override;
+ private:
+ sarif_builder &m_builder;
+ };
+
std::unique_ptr<sarif_result>
make_result_object (diagnostic_context &context,
const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind);
+ diagnostic_t orig_diag_kind,
+ unsigned idx_within_parent);
void
add_any_include_chain (sarif_location_manager &loc_mgr,
sarif_location &location_obj,
@@ -650,11 +733,13 @@ private:
enum diagnostic_artifact_role role);
std::unique_ptr<sarif_code_flow>
make_code_flow_object (sarif_result &result,
+ unsigned idx_within_parent,
const diagnostic_path &path);
- std::unique_ptr<sarif_thread_flow_location>
- make_thread_flow_location_object (sarif_result &result,
- const diagnostic_event &event,
- int path_event_idx);
+ void
+ populate_thread_flow_location_object (sarif_result &result,
+ sarif_thread_flow_location &thread_flow_loc_obj,
+ const diagnostic_event &event,
+ int event_execution_idx);
std::unique_ptr<json::array>
maybe_make_kinds_array (diagnostic_event::meaning m) const;
std::unique_ptr<sarif_physical_location>
@@ -725,6 +810,7 @@ private:
diagnostic_context &m_context;
const line_maps *m_line_maps;
+ sarif_token_printer m_token_printer;
/* The JSON object for the invocation object. */
std::unique_ptr<sarif_invocation> m_invocation_obj;
@@ -751,6 +837,9 @@ private:
int m_tabstop;
bool m_formatted;
+
+ unsigned m_next_result_idx;
+ sarif_code_flow *m_current_code_flow;
};
/* class sarif_object : public json::object. */
@@ -1294,9 +1383,67 @@ lazily_add_kind (enum location_relationship_kind kind)
kinds_arr->append_string (kind_str);
}
+/* class sarif_code_flow : public sarif_object. */
+
+sarif_code_flow::sarif_code_flow (sarif_result &parent,
+ unsigned idx_within_parent)
+: m_parent (parent),
+ m_idx_within_parent (idx_within_parent)
+{
+ /* "threadFlows" property (SARIF v2.1.0 section 3.36.3). */
+ auto thread_flows_arr = ::make_unique<json::array> ();
+ m_thread_flows_arr = thread_flows_arr.get (); // borrowed
+ set<json::array> ("threadFlows", std::move (thread_flows_arr));
+}
+
+sarif_thread_flow &
+sarif_code_flow::get_or_append_thread_flow (const diagnostic_thread &thread,
+ diagnostic_thread_id_t thread_id)
+{
+ sarif_thread_flow **slot = m_thread_id_map.get (thread_id);
+ if (slot)
+ return **slot;
+
+ unsigned next_thread_flow_idx = m_thread_flows_arr->size ();
+ auto thread_flow_obj
+ = ::make_unique<sarif_thread_flow> (*this, thread, next_thread_flow_idx);
+ m_thread_id_map.put (thread_id, thread_flow_obj.get ()); // borrowed
+ sarif_thread_flow *result = thread_flow_obj.get ();
+ m_thread_flows_arr->append<sarif_thread_flow> (std::move (thread_flow_obj));
+ return *result;
+}
+
+sarif_thread_flow &
+sarif_code_flow::get_thread_flow (diagnostic_thread_id_t thread_id)
+{
+ sarif_thread_flow **slot = m_thread_id_map.get (thread_id);
+ gcc_assert (slot); // it must already have one
+ return **slot;
+}
+
+void
+sarif_code_flow::add_location (sarif_thread_flow_location &tfl_obj)
+{
+ m_all_tfl_objs.push_back (&tfl_obj);
+}
+
+sarif_thread_flow_location &
+sarif_code_flow::get_thread_flow_loc_obj (diagnostic_event_id_t event_id) const
+{
+ gcc_assert (event_id.known_p ());
+ gcc_assert ((size_t)event_id.zero_based () < m_all_tfl_objs.size ());
+ sarif_thread_flow_location *tfl_obj = m_all_tfl_objs[event_id.zero_based ()];
+ gcc_assert (tfl_obj);
+ return *tfl_obj;
+}
+
/* class sarif_thread_flow : public sarif_object. */
-sarif_thread_flow::sarif_thread_flow (const diagnostic_thread &thread)
+sarif_thread_flow::sarif_thread_flow (sarif_code_flow &parent,
+ const diagnostic_thread &thread,
+ unsigned idx_within_parent)
+: m_parent (parent),
+ m_idx_within_parent (idx_within_parent)
{
/* "id" property (SARIF v2.1.0 section 3.37.2). */
label_text name (thread.get_name (false));
@@ -1310,11 +1457,18 @@ sarif_thread_flow::sarif_thread_flow (const diagnostic_thread &thread)
set ("locations", m_locations_arr);
}
-void
-sarif_thread_flow::
-add_location (std::unique_ptr<sarif_thread_flow_location> thread_flow_loc_obj)
+/* Add a sarif_thread_flow_location to this threadFlow object, but
+ don't populate it yet. */
+
+sarif_thread_flow_location &
+sarif_thread_flow::add_location ()
{
- m_locations_arr->append (std::move (thread_flow_loc_obj));
+ const unsigned thread_flow_location_idx = m_locations_arr->size ();
+ sarif_thread_flow_location *thread_flow_loc_obj
+ = new sarif_thread_flow_location (*this, thread_flow_location_idx);
+ m_locations_arr->append (thread_flow_loc_obj);
+ m_parent.add_location (*thread_flow_loc_obj);
+ return *thread_flow_loc_obj;
}
/* class sarif_builder. */
@@ -1327,6 +1481,7 @@ sarif_builder::sarif_builder (diagnostic_context &context,
bool formatted)
: m_context (context),
m_line_maps (line_maps),
+ m_token_printer (*this),
m_invocation_obj
(::make_unique<sarif_invocation> (*this,
context.get_original_argv ())),
@@ -1336,7 +1491,9 @@ sarif_builder::sarif_builder (diagnostic_context &context,
m_rule_id_set (),
m_rules_arr (new json::array ()),
m_tabstop (context.m_tabstop),
- m_formatted (formatted)
+ m_formatted (formatted),
+ m_next_result_idx (0),
+ m_current_code_flow (nullptr)
{
gcc_assert (m_line_maps);
@@ -1376,7 +1533,8 @@ sarif_builder::on_report_diagnostic (diagnostic_context &context,
{
/* Top-level diagnostic. */
m_cur_group_result
- = make_result_object (context, diagnostic, orig_diag_kind);
+ = make_result_object (context, diagnostic, orig_diag_kind,
+ m_next_result_idx++);
}
}
@@ -1476,9 +1634,10 @@ make_rule_id_for_diagnostic_kind (diagnostic_t diag_kind)
std::unique_ptr<sarif_result>
sarif_builder::make_result_object (diagnostic_context &context,
const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind)
+ diagnostic_t orig_diag_kind,
+ unsigned idx_within_parent)
{
- auto result_obj = ::make_unique<sarif_result> ();
+ auto result_obj = ::make_unique<sarif_result> (idx_within_parent);
/* "ruleId" property (SARIF v2.1.0 section 3.27.5). */
/* Ideally we'd have an option_name for these. */
@@ -1552,8 +1711,10 @@ sarif_builder::make_result_object (diagnostic_context &context,
if (const diagnostic_path *path = diagnostic.richloc->get_path ())
{
auto code_flows_arr = ::make_unique<json::array> ();
+ const unsigned code_flow_index = 0;
code_flows_arr->append<sarif_code_flow>
(make_code_flow_object (*result_obj.get (),
+ code_flow_index,
*path));
result_obj->set<json::array> ("codeFlows", std::move (code_flows_arr));
}
@@ -2272,83 +2433,115 @@ make_sarif_logical_location_object (const logical_location &logical_loc)
return logical_loc_obj;
}
+label_text
+make_sarif_url_for_event (const sarif_code_flow *code_flow,
+ diagnostic_event_id_t event_id)
+{
+ gcc_assert (event_id.known_p ());
+
+ if (!code_flow)
+ return label_text ();
+
+ const sarif_thread_flow_location &tfl_obj
+ = code_flow->get_thread_flow_loc_obj (event_id);
+ const int location_idx = tfl_obj.get_index_within_parent ();
+
+ const sarif_thread_flow &thread_flow_obj = tfl_obj.get_parent ();
+ const int thread_flow_idx = thread_flow_obj.get_index_within_parent ();
+
+ const sarif_code_flow &code_flow_obj = thread_flow_obj.get_parent ();
+ const int code_flow_idx = code_flow_obj.get_index_within_parent ();
+
+ const sarif_result &result_obj = code_flow_obj.get_parent ();
+ const int result_idx = result_obj.get_index_within_parent ();
+
+ /* We only support a single run object in the log. */
+ const int run_idx = 0;
+
+ char *buf = xasprintf
+ ("sarif:/runs/%i/results/%i/codeFlows/%i/threadFlows/%i/locations/%i",
+ run_idx, result_idx, code_flow_idx, thread_flow_idx, location_idx);
+ return label_text::take (buf);
+}
+
/* Make a "codeFlow" object (SARIF v2.1.0 section 3.36) for PATH. */
std::unique_ptr<sarif_code_flow>
sarif_builder::make_code_flow_object (sarif_result &result,
+ unsigned idx_within_parent,
const diagnostic_path &path)
{
- auto code_flow_obj = ::make_unique <sarif_code_flow> ();
+ auto code_flow_obj
+ = ::make_unique <sarif_code_flow> (result, idx_within_parent);
- /* "threadFlows" property (SARIF v2.1.0 section 3.36.3). */
- auto thread_flows_arr = ::make_unique<json::array> ();
-
- /* Walk the events, consolidating into per-thread threadFlow objects,
- using the index with PATH as the overall executionOrder. */
- hash_map<int_hash<diagnostic_thread_id_t, -1, -2>,
- sarif_thread_flow *> thread_id_map; // borrowed
+ /* First pass:
+ Create threadFlows and threadFlowLocation objects within them,
+ effectively recording a mapping from event_id to threadFlowLocation
+ so that we can later go from an event_id to a URI within the
+ SARIF file. */
for (unsigned i = 0; i < path.num_events (); i++)
{
const diagnostic_event &event = path.get_event (i);
const diagnostic_thread_id_t thread_id = event.get_thread_id ();
- sarif_thread_flow *thread_flow_obj;
- if (sarif_thread_flow **slot = thread_id_map.get (thread_id))
- thread_flow_obj = *slot;
- else
- {
- const diagnostic_thread &thread = path.get_thread (thread_id);
- thread_flow_obj = new sarif_thread_flow (thread);
- thread_id_map.put (thread_id, thread_flow_obj); // borrowed
- thread_flows_arr->append (thread_flow_obj);
- }
+ sarif_thread_flow &thread_flow_obj
+ = code_flow_obj->get_or_append_thread_flow (path.get_thread (thread_id),
+ thread_id);
+ thread_flow_obj.add_location ();
+ }
- /* Add event to thread's threadFlow object. */
- std::unique_ptr<sarif_thread_flow_location> thread_flow_loc_obj
- = make_thread_flow_location_object (result, event, i);
- thread_flow_obj->add_location (std::move (thread_flow_loc_obj));
+ /* Second pass: walk the events, populating the tfl objs. */
+ m_current_code_flow = code_flow_obj.get ();
+ for (unsigned i = 0; i < path.num_events (); i++)
+ {
+ const diagnostic_event &event = path.get_event (i);
+ sarif_thread_flow_location &thread_flow_loc_obj
+ = code_flow_obj->get_thread_flow_loc_obj (i);
+ populate_thread_flow_location_object (result,
+ thread_flow_loc_obj,
+ event,
+ i);
}
- code_flow_obj->set<json::array> ("threadFlows", std::move (thread_flows_arr));
+ m_current_code_flow = nullptr;
return code_flow_obj;
}
-/* Make a "threadFlowLocation" object (SARIF v2.1.0 section 3.38) for EVENT. */
+/* Populate TFL_OBJ, a "threadFlowLocation" object (SARIF v2.1.0 section 3.38)
+ based on EVENT. */
-std::unique_ptr<sarif_thread_flow_location>
-sarif_builder::make_thread_flow_location_object (sarif_result &result,
- const diagnostic_event &ev,
- int path_event_idx)
+void
+sarif_builder::
+populate_thread_flow_location_object (sarif_result &result,
+ sarif_thread_flow_location &tfl_obj,
+ const diagnostic_event &ev,
+ int event_execution_idx)
{
- auto thread_flow_loc_obj = ::make_unique<sarif_thread_flow_location> ();
-
/* Give diagnostic_event subclasses a chance to add custom properties
via a property bag. */
- ev.maybe_add_sarif_properties (*thread_flow_loc_obj);
+ ev.maybe_add_sarif_properties (tfl_obj);
/* "location" property (SARIF v2.1.0 section 3.38.3). */
- thread_flow_loc_obj->set<sarif_location>
+ tfl_obj.set<sarif_location>
("location",
make_location_object (result, ev, diagnostic_artifact_role::traced_file));
/* "kinds" property (SARIF v2.1.0 section 3.38.8). */
diagnostic_event::meaning m = ev.get_meaning ();
if (auto kinds_arr = maybe_make_kinds_array (m))
- thread_flow_loc_obj->set<json::array> ("kinds", std::move (kinds_arr));
+ tfl_obj.set<json::array> ("kinds", std::move (kinds_arr));
/* "nestingLevel" property (SARIF v2.1.0 section 3.38.10). */
- thread_flow_loc_obj->set_integer ("nestingLevel", ev.get_stack_depth ());
+ tfl_obj.set_integer ("nestingLevel", ev.get_stack_depth ());
/* "executionOrder" property (SARIF v2.1.0 3.38.11).
Offset by 1 to match the human-readable values emitted by %@. */
- thread_flow_loc_obj->set_integer ("executionOrder", path_event_idx + 1);
+ tfl_obj.set_integer ("executionOrder", event_execution_idx + 1);
/* It might be nice to eventually implement the following for -fanalyzer:
- the "stack" property (SARIF v2.1.0 section 3.38.5)
- the "state" property (SARIF v2.1.0 section 3.38.9)
- the "importance" property (SARIF v2.1.0 section 3.38.13). */
-
- return thread_flow_loc_obj;
}
/* If M has any known meaning, make a json array suitable for the "kinds"
@@ -2933,6 +3126,8 @@ public:
m_builder.emit_diagram (m_context, diagram);
}
+ sarif_builder &get_builder () { return m_builder; }
+
protected:
sarif_output_format (diagnostic_context &context,
const line_maps *line_maps,
@@ -3008,11 +3203,128 @@ private:
char *m_base_file_name;
};
+/* Print the start of an embedded link to PP, as per 3.11.6. */
+
+static void
+sarif_begin_embedded_link (pretty_printer *pp)
+{
+ pp_character (pp, '[');
+}
+
+/* Print the end of an embedded link to PP, as per 3.11.6. */
+
+static void
+sarif_end_embedded_link (pretty_printer *pp,
+ const char *url)
+{
+ pp_string (pp, "](");
+ /* TODO: does the URI need escaping?
+ See https://github.com/oasis-tcs/sarif-spec/issues/657 */
+ pp_string (pp, url);
+ pp_character (pp, ')');
+}
+
+/* class sarif_token_printer : public token_printer. */
+
+/* Implementation of pretty_printer::token_printer for SARIF output.
+ Emit URLs as per 3.11.6 ("Messages with embedded links"). */
+
+void
+sarif_builder::sarif_token_printer::print_tokens (pretty_printer *pp,
+ const pp_token_list &tokens)
+{
+ /* Convert to text, possibly with colorization, URLs, etc. */
+ label_text current_url;
+ for (auto iter = tokens.m_first; iter; iter = iter->m_next)
+ switch (iter->m_kind)
+ {
+ default:
+ gcc_unreachable ();
+
+ case pp_token::kind::text:
+ {
+ const pp_token_text *sub = as_a <const pp_token_text *> (iter);
+ const char * const str = sub->m_value.get ();
+ if (current_url.get ())
+ {
+ /* Write iter->m_value, but escaping any
+ escaped link characters as per 3.11.6. */
+ for (const char *ptr = str; *ptr; ptr++)
+ {
+ const char ch = *ptr;
+ switch (ch)
+ {
+ default:
+ pp_character (pp, ch);
+ break;
+ case '\\':
+ case '[':
+ case ']':
+ pp_character (pp, '\\');
+ pp_character (pp, ch);
+ break;
+ }
+ }
+ }
+ else
+ /* TODO: is other escaping needed? (e.g. of '[')
+ See https://github.com/oasis-tcs/sarif-spec/issues/658 */
+ pp_string (pp, str);
+ }
+ break;
+
+ case pp_token::kind::begin_color:
+ case pp_token::kind::end_color:
+ /* These are no-ops. */
+ break;
+
+ case pp_token::kind::begin_quote:
+ pp_begin_quote (pp, pp_show_color (pp));
+ break;
+ case pp_token::kind::end_quote:
+ pp_end_quote (pp, pp_show_color (pp));
+ break;
+
+ /* Emit URLs as per 3.11.6 ("Messages with embedded links"). */
+ case pp_token::kind::begin_url:
+ {
+ pp_token_begin_url *sub = as_a <pp_token_begin_url *> (iter);
+ sarif_begin_embedded_link (pp);
+ current_url = std::move (sub->m_value);
+ }
+ break;
+ case pp_token::kind::end_url:
+ gcc_assert (current_url.get ());
+ sarif_end_embedded_link (pp, current_url.get ());
+ current_url = label_text::borrow (nullptr);
+ break;
+
+ case pp_token::kind::event_id:
+ {
+ pp_token_event_id *sub = as_a <pp_token_event_id *> (iter);
+ gcc_assert (sub->m_event_id.known_p ());
+ const sarif_code_flow *code_flow
+ = m_builder.get_code_flow_for_event_ids ();
+ label_text url = make_sarif_url_for_event (code_flow,
+ sub->m_event_id);
+ if (url.get ())
+ sarif_begin_embedded_link (pp);
+ pp_character (pp, '(');
+ pp_decimal_int (pp, sub->m_event_id.one_based ());
+ pp_character (pp, ')');
+ if (url.get ())
+ sarif_end_embedded_link (pp, url.get ());
+ }
+ break;
+ }
+}
+
/* Populate CONTEXT in preparation for SARIF output (either to stderr, or
to a file). */
static void
-diagnostic_output_format_init_sarif (diagnostic_context &context)
+diagnostic_output_format_init_sarif (diagnostic_context &context,
+ std::unique_ptr<sarif_output_format> fmt)
{
/* Suppress normal textual path output. */
context.set_path_format (DPF_NONE);
@@ -3023,6 +3335,10 @@ diagnostic_output_format_init_sarif (diagnostic_context &context)
/* Don't colorize the text. */
pp_show_color (context.printer) = false;
context.set_show_highlight_colors (false);
+
+ context.printer->set_token_printer
+ (&fmt->get_builder ().get_token_printer ());
+ context.set_output_format (fmt.release ());
}
/* Populate CONTEXT in preparation for SARIF output to stderr. */
@@ -3034,13 +3350,13 @@ diagnostic_output_format_init_sarif_stderr (diagnostic_context &context,
bool formatted)
{
gcc_assert (line_maps);
- diagnostic_output_format_init_sarif (context);
- context.set_output_format
- (new sarif_stream_output_format (context,
- line_maps,
- main_input_filename_,
- formatted,
- stderr));
+ diagnostic_output_format_init_sarif
+ (context,
+ ::make_unique<sarif_stream_output_format> (context,
+ line_maps,
+ main_input_filename_,
+ formatted,
+ stderr));
}
/* Populate CONTEXT in preparation for SARIF output to a file named
@@ -3054,13 +3370,13 @@ diagnostic_output_format_init_sarif_file (diagnostic_context &context,
const char *base_file_name)
{
gcc_assert (line_maps);
- diagnostic_output_format_init_sarif (context);
- context.set_output_format
- (new sarif_file_output_format (context,
- line_maps,
- main_input_filename_,
- formatted,
- base_file_name));
+ diagnostic_output_format_init_sarif
+ (context,
+ ::make_unique<sarif_file_output_format> (context,
+ line_maps,
+ main_input_filename_,
+ formatted,
+ base_file_name));
}
/* Populate CONTEXT in preparation for SARIF output to STREAM. */
@@ -3073,13 +3389,13 @@ diagnostic_output_format_init_sarif_stream (diagnostic_context &context,
FILE *stream)
{
gcc_assert (line_maps);
- diagnostic_output_format_init_sarif (context);
- context.set_output_format
- (new sarif_stream_output_format (context,
- line_maps,
- main_input_filename_,
- formatted,
- stream));
+ diagnostic_output_format_init_sarif
+ (context,
+ ::make_unique<sarif_stream_output_format> (context,
+ line_maps,
+ main_input_filename_,
+ formatted,
+ stream));
}
#if CHECKING_P
@@ -3095,13 +3411,12 @@ class test_sarif_diagnostic_context : public test_diagnostic_context
public:
test_sarif_diagnostic_context (const char *main_input_filename)
{
- diagnostic_output_format_init_sarif (*this);
-
- m_format = new buffered_output_format (*this,
- line_table,
- main_input_filename,
- true);
- set_output_format (m_format); // give ownership;
+ auto format = ::make_unique<buffered_output_format> (*this,
+ line_table,
+ main_input_filename,
+ true);
+ m_format = format.get (); // borrowed
+ diagnostic_output_format_init_sarif (*this, std::move (format));
}
std::unique_ptr<sarif_log> flush_to_object ()
@@ -3175,7 +3490,7 @@ test_make_location_object (const line_table_case &case_)
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
richloc.set_escape_on_output (true);
- sarif_result result;
+ sarif_result result (0);
std::unique_ptr<sarif_location> location_obj
= builder.make_location_object
@@ -3471,6 +3786,119 @@ test_simple_log_2 (const line_table_case &case_)
}
}
+/* Assuming that a single diagnostic has been emitted within
+ LOG, get a json::object for the result object. */
+
+static const json::object *
+get_result_from_log (const sarif_log *log)
+{
+ auto runs = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (log, "runs"); // 3.13.4
+ ASSERT_EQ (runs->size (), 1);
+
+ // 3.14 "run" object:
+ auto run = (*runs)[0];
+
+ // 3.14.23:
+ auto results = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (run, "results");
+ ASSERT_EQ (results->size (), 1);
+
+ // 3.27 "result" object:
+ auto result = (*results)[0];
+ return expect_json_object (SELFTEST_LOCATION, result);
+}
+
+/* Assuming that a single diagnostic has been emitted to
+ DC, get a json::object for the messsage object within
+ the result. */
+
+static const json::object *
+get_message_from_log (const sarif_log *log)
+{
+ auto result_obj = get_result_from_log (log);
+
+ // 3.27.11:
+ auto message_obj
+ = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (result_obj, "message");
+ return message_obj;
+}
+
+/* Tests of messages with embedded links; see SARIF v2.1.0 3.11.6. */
+
+static void
+test_message_with_embedded_link ()
+{
+ auto_fix_quotes fix_quotes;
+ {
+ test_sarif_diagnostic_context dc ("test.c");
+ rich_location richloc (line_table, UNKNOWN_LOCATION);
+ dc.report (DK_ERROR, richloc, nullptr, 0,
+ "before %{text%} after",
+ "http://example.com");
+ std::unique_ptr<sarif_log> log = dc.flush_to_object ();
+
+ auto message_obj = get_message_from_log (log.get ());
+ ASSERT_JSON_STRING_PROPERTY_EQ
+ (message_obj, "text",
+ "before [text](http://example.com) after");
+ }
+
+ /* Escaping in message text.
+ This is "EXAMPLE 1" from 3.11.6. */
+ {
+ test_sarif_diagnostic_context dc ("test.c");
+ rich_location richloc (line_table, UNKNOWN_LOCATION);
+
+ /* Disable "unquoted sequence of 2 consecutive punctuation
+ characters `]\' in format" warning. */
+#if __GNUC__ >= 10
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wformat-diag"
+#endif
+ dc.report (DK_ERROR, richloc, nullptr, 0,
+ "Prohibited term used in %{para[0]\\spans[2]%}.",
+ "1");
+#if __GNUC__ >= 10
+# pragma GCC diagnostic pop
+#endif
+
+ std::unique_ptr<sarif_log> log = dc.flush_to_object ();
+
+ auto message_obj = get_message_from_log (log.get ());
+ ASSERT_JSON_STRING_PROPERTY_EQ
+ (message_obj, "text",
+ "Prohibited term used in [para\\[0\\]\\\\spans\\[2\\]](1).");
+ /* This isn't exactly what EXAMPLE 1 of the spec has; reported as
+ https://github.com/oasis-tcs/sarif-spec/issues/656 */
+ }
+
+ /* Urlifier. */
+ {
+ class test_urlifier : public urlifier
+ {
+ public:
+ char *
+ get_url_for_quoted_text (const char *p, size_t sz) const final override
+ {
+ if (!strncmp (p, "-foption", sz))
+ return xstrdup ("http://example.com");
+ return nullptr;
+ }
+ };
+
+ test_sarif_diagnostic_context dc ("test.c");
+ dc.set_urlifier (new test_urlifier ());
+ rich_location richloc (line_table, UNKNOWN_LOCATION);
+ dc.report (DK_ERROR, richloc, nullptr, 0,
+ "foo %<-foption%> %<unrecognized%> bar");
+ std::unique_ptr<sarif_log> log = dc.flush_to_object ();
+
+ auto message_obj = get_message_from_log (log.get ());
+ ASSERT_JSON_STRING_PROPERTY_EQ
+ (message_obj, "text",
+ "foo `[-foption](http://example.com)' `unrecognized' bar");
+ }
+}
+
/* Run all of the selftests within this file. */
void
@@ -3479,6 +3907,7 @@ diagnostic_format_sarif_cc_tests ()
for_each_line_table_case (test_make_location_object);
test_simple_log ();
for_each_line_table_case (test_simple_log_2);
+ test_message_with_embedded_link ();
}
} // namespace selftest
diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index 381a050..a80e16b 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -1407,7 +1407,7 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
m_output_format->on_begin_group ();
m_diagnostic_groups.m_emission_count++;
- pp_format (this->printer, &diagnostic->message, m_urlifier);
+ pp_format (this->printer, &diagnostic->message);
/* Call vfunc in the output format. This is responsible for
phase 3 of formatting, and for printing the result. */
m_output_format->on_report_diagnostic (*diagnostic, orig_diag_kind);
diff --git a/gcc/dump-context.h b/gcc/dump-context.h
index b2aed28..e90c4ee 100644
--- a/gcc/dump-context.h
+++ b/gcc/dump-context.h
@@ -120,7 +120,7 @@ class dump_context
void end_any_optinfo ();
void emit_optinfo (const optinfo *info);
- void emit_item (optinfo_item *item, dump_flags_t dump_kind);
+ void emit_item (const optinfo_item &item, dump_flags_t dump_kind);
bool apply_dump_filter_p (dump_flags_t dump_kind, dump_flags_t filter) const;
@@ -154,47 +154,52 @@ class dump_context
};
/* A subclass of pretty_printer for implementing dump_context::dump_printf_va.
- In particular, the formatted chunks are captured as optinfo_item instances,
- thus retaining metadata about the entities being dumped (e.g. source
- locations), rather than just as plain text. */
+ In particular, the formatted chunks are captured as optinfo_item instances
+ as pp_token_custom_data, thus retaining metadata about the entities being
+ dumped (e.g. source locations), rather than just as plain text.
+ These custom items are retained through to the end of stage 3 of formatted
+ printing; the printer uses a custom token_printer subclass to emit them to
+ the active optinfo (if any). */
class dump_pretty_printer : public pretty_printer
{
public:
dump_pretty_printer (dump_context *context, dump_flags_t dump_kind);
- void emit_items (optinfo *dest);
+ void set_optinfo (optinfo *info) { m_token_printer.m_optinfo = info; }
private:
- /* Information on an optinfo_item that was generated during phase 2 of
- formatting. */
- class stashed_item
+ struct custom_token_printer : public token_printer
{
- public:
- stashed_item (const char **buffer_ptr_, optinfo_item *item_)
- : buffer_ptr (buffer_ptr_), item (item_) {}
- const char **buffer_ptr;
- optinfo_item *item;
+ custom_token_printer (dump_pretty_printer &dump_pp)
+ : m_dump_pp (dump_pp),
+ m_optinfo (nullptr)
+ {}
+ void print_tokens (pretty_printer *pp,
+ const pp_token_list &tokens) final override;
+ void emit_any_pending_textual_chunks ();
+
+ dump_pretty_printer &m_dump_pp;
+ optinfo *m_optinfo;
};
static bool format_decoder_cb (pretty_printer *pp, text_info *text,
const char *spec, int /*precision*/,
bool /*wide*/, bool /*set_locus*/,
bool /*verbose*/, bool */*quoted*/,
- const char **buffer_ptr);
+ pp_token_list &formatted_tok_list);
bool decode_format (text_info *text, const char *spec,
- const char **buffer_ptr);
+ pp_token_list &formatted_tok_list);
- void stash_item (const char **buffer_ptr, optinfo_item *item);
+ void stash_item (pp_token_list &formatted_tok_list,
+ std::unique_ptr<optinfo_item> item);
- void emit_any_pending_textual_chunks (optinfo *dest);
-
- void emit_item (optinfo_item *item, optinfo *dest);
+ void emit_item (std::unique_ptr<optinfo_item> item, optinfo *dest);
dump_context *m_context;
dump_flags_t m_dump_kind;
- auto_vec<stashed_item> m_stashed_items;
+ custom_token_printer m_token_printer;
};
/* An RAII-style class for use in debug dumpers for temporarily using a
diff --git a/gcc/dumpfile.cc b/gcc/dumpfile.cc
index 6353c08..da36718 100644
--- a/gcc/dumpfile.cc
+++ b/gcc/dumpfile.cc
@@ -41,6 +41,8 @@ along with GCC; see the file COPYING3. If not see
#include "optinfo-emit-json.h"
#include "stringpool.h" /* for get_identifier. */
#include "spellcheck.h"
+#include "make-unique.h"
+#include "pretty-print-format-impl.h"
/* If non-NULL, return one past-the-end of the matching SUBPART of
the WHOLE string. */
@@ -628,7 +630,7 @@ dump_context::dump_loc_immediate (dump_flags_t dump_kind,
/* Make an item for the given dump call, equivalent to print_gimple_stmt. */
-static optinfo_item *
+static std::unique_ptr<optinfo_item>
make_item_for_dump_gimple_stmt (gimple *stmt, int spc, dump_flags_t dump_flags)
{
pretty_printer pp;
@@ -636,9 +638,10 @@ make_item_for_dump_gimple_stmt (gimple *stmt, int spc, dump_flags_t dump_flags)
pp_gimple_stmt_1 (&pp, stmt, spc, dump_flags);
pp_newline (&pp);
- optinfo_item *item
- = new optinfo_item (OPTINFO_ITEM_KIND_GIMPLE, gimple_location (stmt),
- xstrdup (pp_formatted_text (&pp)));
+ std::unique_ptr<optinfo_item> item
+ = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_GIMPLE,
+ gimple_location (stmt),
+ xstrdup (pp_formatted_text (&pp)));
return item;
}
@@ -650,17 +653,15 @@ dump_context::dump_gimple_stmt (const dump_metadata_t &metadata,
dump_flags_t extra_dump_flags,
gimple *gs, int spc)
{
- optinfo_item *item
+ auto item
= make_item_for_dump_gimple_stmt (gs, spc, dump_flags | extra_dump_flags);
- emit_item (item, metadata.get_dump_flags ());
+ emit_item (*item.get (), metadata.get_dump_flags ());
if (optinfo_enabled_p ())
{
optinfo &info = ensure_pending_optinfo (metadata);
- info.add_item (item);
+ info.add_item (std::move (item));
}
- else
- delete item;
}
/* Similar to dump_gimple_stmt, except additionally print source location. */
@@ -677,7 +678,7 @@ dump_context::dump_gimple_stmt_loc (const dump_metadata_t &metadata,
/* Make an item for the given dump call, equivalent to print_gimple_expr. */
-static optinfo_item *
+static std::unique_ptr<optinfo_item>
make_item_for_dump_gimple_expr (gimple *stmt, int spc, dump_flags_t dump_flags)
{
dump_flags |= TDF_RHS_ONLY;
@@ -685,9 +686,10 @@ make_item_for_dump_gimple_expr (gimple *stmt, int spc, dump_flags_t dump_flags)
pp_needs_newline (&pp) = true;
pp_gimple_stmt_1 (&pp, stmt, spc, dump_flags);
- optinfo_item *item
- = new optinfo_item (OPTINFO_ITEM_KIND_GIMPLE, gimple_location (stmt),
- xstrdup (pp_formatted_text (&pp)));
+ std::unique_ptr<optinfo_item> item
+ = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_GIMPLE,
+ gimple_location (stmt),
+ xstrdup (pp_formatted_text (&pp)));
return item;
}
@@ -700,17 +702,15 @@ dump_context::dump_gimple_expr (const dump_metadata_t &metadata,
dump_flags_t extra_dump_flags,
gimple *gs, int spc)
{
- optinfo_item *item
+ std::unique_ptr<optinfo_item> item
= make_item_for_dump_gimple_expr (gs, spc, dump_flags | extra_dump_flags);
- emit_item (item, metadata.get_dump_flags ());
+ emit_item (*item.get (), metadata.get_dump_flags ());
if (optinfo_enabled_p ())
{
optinfo &info = ensure_pending_optinfo (metadata);
- info.add_item (item);
+ info.add_item (std::move (item));
}
- else
- delete item;
}
/* Similar to dump_gimple_expr, except additionally print source location. */
@@ -728,7 +728,7 @@ dump_context::dump_gimple_expr_loc (const dump_metadata_t &metadata,
/* Make an item for the given dump call, equivalent to print_generic_expr. */
-static optinfo_item *
+static std::unique_ptr<optinfo_item>
make_item_for_dump_generic_expr (tree node, dump_flags_t dump_flags)
{
pretty_printer pp;
@@ -740,9 +740,9 @@ make_item_for_dump_generic_expr (tree node, dump_flags_t dump_flags)
if (EXPR_HAS_LOCATION (node))
loc = EXPR_LOCATION (node);
- optinfo_item *item
- = new optinfo_item (OPTINFO_ITEM_KIND_TREE, loc,
- xstrdup (pp_formatted_text (&pp)));
+ std::unique_ptr<optinfo_item> item
+ = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TREE, loc,
+ xstrdup (pp_formatted_text (&pp)));
return item;
}
@@ -754,17 +754,15 @@ dump_context::dump_generic_expr (const dump_metadata_t &metadata,
dump_flags_t extra_dump_flags,
tree t)
{
- optinfo_item *item
+ std::unique_ptr<optinfo_item> item
= make_item_for_dump_generic_expr (t, dump_flags | extra_dump_flags);
- emit_item (item, metadata.get_dump_flags ());
+ emit_item (*item.get (), metadata.get_dump_flags ());
if (optinfo_enabled_p ())
{
optinfo &info = ensure_pending_optinfo (metadata);
- info.add_item (item);
+ info.add_item (std::move (item));
}
- else
- delete item;
}
@@ -783,123 +781,75 @@ dump_context::dump_generic_expr_loc (const dump_metadata_t &metadata,
/* Make an item for the given dump call. */
-static optinfo_item *
+static std::unique_ptr<optinfo_item>
make_item_for_dump_symtab_node (symtab_node *node)
{
location_t loc = DECL_SOURCE_LOCATION (node->decl);
- optinfo_item *item
- = new optinfo_item (OPTINFO_ITEM_KIND_SYMTAB_NODE, loc,
- xstrdup (node->dump_name ()));
+ std::unique_ptr<optinfo_item> item
+ = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_SYMTAB_NODE, loc,
+ xstrdup (node->dump_name ()));
return item;
}
-/* dump_pretty_printer's ctor. */
-
-dump_pretty_printer::dump_pretty_printer (dump_context *context,
- dump_flags_t dump_kind)
-: pretty_printer (), m_context (context), m_dump_kind (dump_kind),
- m_stashed_items ()
+struct wrapped_optinfo_item : public pp_token_custom_data::value
{
- pp_format_decoder (this) = format_decoder_cb;
-}
-
-/* Phase 3 of formatting; compare with pp_output_formatted_text.
-
- Emit optinfo_item instances for the various formatted chunks from phases
- 1 and 2 (i.e. pp_format).
-
- Some chunks may already have had their items built (during decode_format).
- These chunks have been stashed into m_stashed_items; we emit them here.
-
- For all other purely textual chunks, they are printed into
- buffer->formatted_obstack, and then emitted as a textual optinfo_item.
- This consolidates multiple adjacent text chunks into a single text
- optinfo_item. */
-
-void
-dump_pretty_printer::emit_items (optinfo *dest)
-{
- output_buffer *buffer = pp_buffer (this);
- chunk_info *chunk_array = buffer->cur_chunk_array;
- const char * const *args = chunk_array->get_args ();
-
- gcc_assert (buffer->obstack == &buffer->formatted_obstack);
- gcc_assert (buffer->line_length == 0);
-
- unsigned stashed_item_idx = 0;
- for (unsigned chunk = 0; args[chunk]; chunk++)
- {
- if (stashed_item_idx < m_stashed_items.length ()
- && args[chunk] == *m_stashed_items[stashed_item_idx].buffer_ptr)
- {
- emit_any_pending_textual_chunks (dest);
- /* This chunk has a stashed item: use it. */
- emit_item (m_stashed_items[stashed_item_idx++].item, dest);
- }
- else
- /* This chunk is purely textual. Print it (to
- buffer->formatted_obstack), so that we can consolidate adjacent
- chunks into one textual optinfo_item. */
- pp_string (this, args[chunk]);
- }
+ wrapped_optinfo_item (std::unique_ptr<optinfo_item> item)
+ : m_optinfo_item (std::move (item))
+ {
+ gcc_assert (m_optinfo_item.get ());
+ }
- emit_any_pending_textual_chunks (dest);
+ void dump (FILE *out) const final override
+ {
+ fprintf (out, "OPTINFO(\"%s\")", m_optinfo_item->get_text ());
+ }
- /* Ensure that we consumed all of stashed_items. */
- gcc_assert (stashed_item_idx == m_stashed_items.length ());
+ bool as_standard_tokens (pp_token_list &) final override
+ {
+ /* Keep as a custom token. */
+ return false;
+ }
- chunk_array->pop_from_output_buffer (*buffer);
-}
+ std::unique_ptr<optinfo_item> m_optinfo_item;
+};
-/* Subroutine of dump_pretty_printer::emit_items
- for consolidating multiple adjacent pure-text chunks into single
- optinfo_items (in phase 3). */
+/* dump_pretty_printer's ctor. */
-void
-dump_pretty_printer::emit_any_pending_textual_chunks (optinfo *dest)
+dump_pretty_printer::dump_pretty_printer (dump_context *context,
+ dump_flags_t dump_kind)
+: pretty_printer (),
+ m_context (context),
+ m_dump_kind (dump_kind),
+ m_token_printer (*this)
{
- output_buffer *const buffer = pp_buffer (this);
- gcc_assert (buffer->obstack == &buffer->formatted_obstack);
-
- /* Don't emit an item if the pending text is empty. */
- if (output_buffer_last_position_in_text (buffer) == NULL)
- return;
-
- char *formatted_text = xstrdup (pp_formatted_text (this));
- optinfo_item *item
- = new optinfo_item (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
- formatted_text);
- emit_item (item, dest);
-
- /* Clear the pending text by unwinding formatted_text back to the start
- of the buffer (without deallocating). */
- obstack_free (&buffer->formatted_obstack,
- buffer->formatted_obstack.object_base);
+ pp_format_decoder (this) = format_decoder_cb;
+ set_token_printer (&m_token_printer);
}
/* Emit ITEM and take ownership of it. If DEST is non-NULL, add ITEM
to DEST; otherwise delete ITEM. */
void
-dump_pretty_printer::emit_item (optinfo_item *item, optinfo *dest)
+dump_pretty_printer::emit_item (std::unique_ptr<optinfo_item> item,
+ optinfo *dest)
{
- m_context->emit_item (item, m_dump_kind);
+ m_context->emit_item (*item.get (), m_dump_kind);
if (dest)
- dest->add_item (item);
- else
- delete item;
+ dest->add_item (std::move (item));
}
-/* Record that ITEM (generated in phase 2 of formatting) is to be used for
- the chunk at BUFFER_PTR in phase 3 (by emit_items). */
+/* Append a custom pp_token for ITEM (generated in phase 2 of formatting)
+ into FORMATTTED_TOK_LIST, so that it can be emitted in phase 2. */
void
-dump_pretty_printer::stash_item (const char **buffer_ptr, optinfo_item *item)
+dump_pretty_printer::stash_item (pp_token_list &formatted_tok_list,
+ std::unique_ptr<optinfo_item> item)
{
- gcc_assert (buffer_ptr);
- gcc_assert (item);
+ gcc_assert (item.get ());
- m_stashed_items.safe_push (stashed_item (buffer_ptr, item));
+ auto custom_data
+ = ::make_unique<wrapped_optinfo_item> (std::move (item));
+ formatted_tok_list.push_back<pp_token_custom_data> (std::move (custom_data));
}
/* pp_format_decoder callback for dump_pretty_printer, and thus for
@@ -912,10 +862,10 @@ dump_pretty_printer::format_decoder_cb (pretty_printer *pp, text_info *text,
const char *spec, int /*precision*/,
bool /*wide*/, bool /*set_locus*/,
bool /*verbose*/, bool */*quoted*/,
- const char **buffer_ptr)
+ pp_token_list &formatted_tok_list)
{
dump_pretty_printer *opp = static_cast <dump_pretty_printer *> (pp);
- return opp->decode_format (text, spec, buffer_ptr);
+ return opp->decode_format (text, spec, formatted_tok_list);
}
/* Format decoder for dump_pretty_printer, and thus for dump_printf and
@@ -942,7 +892,7 @@ dump_pretty_printer::format_decoder_cb (pretty_printer *pp, text_info *text,
bool
dump_pretty_printer::decode_format (text_info *text, const char *spec,
- const char **buffer_ptr)
+ pp_token_list &formatted_tok_list)
{
/* Various format codes that imply making an optinfo_item and stashed it
for later use (to capture metadata, rather than plain text). */
@@ -953,8 +903,8 @@ dump_pretty_printer::decode_format (text_info *text, const char *spec,
cgraph_node *node = va_arg (*text->m_args_ptr, cgraph_node *);
/* Make an item for the node, and stash it. */
- optinfo_item *item = make_item_for_dump_symtab_node (node);
- stash_item (buffer_ptr, item);
+ auto item = make_item_for_dump_symtab_node (node);
+ stash_item (formatted_tok_list, std::move (item));
return true;
}
@@ -963,8 +913,8 @@ dump_pretty_printer::decode_format (text_info *text, const char *spec,
gimple *stmt = va_arg (*text->m_args_ptr, gimple *);
/* Make an item for the stmt, and stash it. */
- optinfo_item *item = make_item_for_dump_gimple_expr (stmt, 0, TDF_SLIM);
- stash_item (buffer_ptr, item);
+ auto item = make_item_for_dump_gimple_expr (stmt, 0, TDF_SLIM);
+ stash_item (formatted_tok_list, std::move (item));
return true;
}
@@ -973,8 +923,8 @@ dump_pretty_printer::decode_format (text_info *text, const char *spec,
gimple *stmt = va_arg (*text->m_args_ptr, gimple *);
/* Make an item for the stmt, and stash it. */
- optinfo_item *item = make_item_for_dump_gimple_stmt (stmt, 0, TDF_SLIM);
- stash_item (buffer_ptr, item);
+ auto item = make_item_for_dump_gimple_stmt (stmt, 0, TDF_SLIM);
+ stash_item (formatted_tok_list, std::move (item));
return true;
}
@@ -983,8 +933,8 @@ dump_pretty_printer::decode_format (text_info *text, const char *spec,
tree t = va_arg (*text->m_args_ptr, tree);
/* Make an item for the tree, and stash it. */
- optinfo_item *item = make_item_for_dump_generic_expr (t, TDF_SLIM);
- stash_item (buffer_ptr, item);
+ auto item = make_item_for_dump_generic_expr (t, TDF_SLIM);
+ stash_item (formatted_tok_list, std::move (item));
return true;
}
@@ -993,10 +943,92 @@ dump_pretty_printer::decode_format (text_info *text, const char *spec,
}
}
+void
+dump_pretty_printer::custom_token_printer::
+print_tokens (pretty_printer *pp,
+ const pp_token_list &tokens)
+{
+ /* Accumulate text whilst emitting items. */
+ for (auto iter = tokens.m_first; iter; iter = iter->m_next)
+ switch (iter->m_kind)
+ {
+ default:
+ gcc_unreachable ();
+
+ case pp_token::kind::text:
+ {
+ pp_token_text *sub = as_a <pp_token_text *> (iter);
+ gcc_assert (sub->m_value.get ());
+ pp_string (pp, sub->m_value.get ());
+ }
+ break;
+
+ case pp_token::kind::begin_color:
+ case pp_token::kind::end_color:
+ /* No-op for dumpfiles. */
+ break;
+
+ case pp_token::kind::begin_quote:
+ pp_begin_quote (pp, pp_show_color (pp));
+ break;
+ case pp_token::kind::end_quote:
+ pp_end_quote (pp, pp_show_color (pp));
+ break;
+
+ case pp_token::kind::begin_url:
+ case pp_token::kind::end_url:
+ /* No-op for dumpfiles. */
+ break;
+
+ case pp_token::kind::custom_data:
+ {
+ emit_any_pending_textual_chunks ();
+ pp_token_custom_data *sub = as_a <pp_token_custom_data *> (iter);
+ gcc_assert (sub->m_value.get ());
+ wrapped_optinfo_item *custom_data
+ = static_cast<wrapped_optinfo_item *> (sub->m_value.get ());
+ m_dump_pp.emit_item (std::move (custom_data->m_optinfo_item),
+ m_optinfo);
+ }
+ break;
+ }
+
+ emit_any_pending_textual_chunks ();
+}
+
+/* Subroutine of dump_pretty_printer::custom_token_printer::print_tokens
+ for consolidating multiple adjacent pure-text chunks into single
+ optinfo_items (in phase 3). */
+
+void
+dump_pretty_printer::custom_token_printer::
+emit_any_pending_textual_chunks ()
+{
+ dump_pretty_printer *pp = &m_dump_pp;
+ output_buffer *const buffer = pp_buffer (pp);
+ gcc_assert (buffer->obstack == &buffer->formatted_obstack);
+
+ /* Don't emit an item if the pending text is empty. */
+ if (output_buffer_last_position_in_text (buffer) == nullptr)
+ return;
+
+ char *formatted_text = xstrdup (pp_formatted_text (pp));
+ std::unique_ptr<optinfo_item> item
+ = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
+ formatted_text);
+ pp->emit_item (std::move (item), m_optinfo);
+
+ /* Clear the pending text by unwinding formatted_text back to the start
+ of the buffer (without deallocating). */
+ obstack_free (&buffer->formatted_obstack,
+ buffer->formatted_obstack.object_base);
+}
+
/* Output a formatted message using FORMAT on appropriate dump streams. */
void
-dump_context::dump_printf_va (const dump_metadata_t &metadata, const char *format,
+dump_context::dump_printf_va (const dump_metadata_t &metadata,
+ const char *format,
va_list *ap)
{
dump_pretty_printer pp (this, metadata.get_dump_flags ());
@@ -1006,14 +1038,16 @@ dump_context::dump_printf_va (const dump_metadata_t &metadata, const char *forma
/* Phases 1 and 2, using pp_format. */
pp_format (&pp, &text);
- /* Phase 3. */
+ /* Phase 3: update the custom token_printer with any active optinfo. */
if (optinfo_enabled_p ())
{
optinfo &info = ensure_pending_optinfo (metadata);
- pp.emit_items (&info);
+ pp.set_optinfo (&info);
}
else
- pp.emit_items (NULL);
+ pp.set_optinfo (nullptr);
+
+ pp_output_formatted_text (&pp, nullptr);
}
/* Similar to dump_printf, except source location is also printed, and
@@ -1031,7 +1065,7 @@ dump_context::dump_printf_loc_va (const dump_metadata_t &metadata,
/* Make an item for the given dump call, equivalent to print_dec. */
template<unsigned int N, typename C>
-static optinfo_item *
+static std::unique_ptr<optinfo_item>
make_item_for_dump_dec (const poly_int<N, C> &value)
{
STATIC_ASSERT (poly_coeff_traits<C>::signedness >= 0);
@@ -1051,9 +1085,9 @@ make_item_for_dump_dec (const poly_int<N, C> &value)
}
}
- optinfo_item *item
- = new optinfo_item (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
- xstrdup (pp_formatted_text (&pp)));
+ auto item
+ = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
+ xstrdup (pp_formatted_text (&pp)));
return item;
}
@@ -1061,35 +1095,33 @@ make_item_for_dump_dec (const poly_int<N, C> &value)
template<unsigned int N, typename C>
void
-dump_context::dump_dec (const dump_metadata_t &metadata, const poly_int<N, C> &value)
+dump_context::dump_dec (const dump_metadata_t &metadata,
+ const poly_int<N, C> &value)
{
- optinfo_item *item = make_item_for_dump_dec (value);
- emit_item (item, metadata.get_dump_flags ());
+ auto item = make_item_for_dump_dec (value);
+ emit_item (*item.get (), metadata.get_dump_flags ());
if (optinfo_enabled_p ())
{
optinfo &info = ensure_pending_optinfo (metadata);
- info.add_item (item);
+ info.add_item (std::move (item));
}
- else
- delete item;
}
/* Output the name of NODE on appropriate dump streams. */
void
-dump_context::dump_symtab_node (const dump_metadata_t &metadata, symtab_node *node)
+dump_context::dump_symtab_node (const dump_metadata_t &metadata,
+ symtab_node *node)
{
- optinfo_item *item = make_item_for_dump_symtab_node (node);
- emit_item (item, metadata.get_dump_flags ());
+ auto item = make_item_for_dump_symtab_node (node);
+ emit_item (*item.get (), metadata.get_dump_flags ());
if (optinfo_enabled_p ())
{
optinfo &info = ensure_pending_optinfo (metadata);
- info.add_item (item);
+ info.add_item (std::move (item));
}
- else
- delete item;
}
/* Get the current dump scope-nesting depth.
@@ -1132,10 +1164,10 @@ dump_context::begin_scope (const char *name,
pretty_printer pp;
pp_printf (&pp, "%s %s %s", "===", name, "===");
pp_newline (&pp);
- optinfo_item *item
- = new optinfo_item (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
- xstrdup (pp_formatted_text (&pp)));
- emit_item (item, MSG_NOTE);
+ std::unique_ptr<optinfo_item> item
+ = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
+ xstrdup (pp_formatted_text (&pp)));
+ emit_item (*item.get (), MSG_NOTE);
if (optinfo_enabled_p ())
{
@@ -1143,11 +1175,9 @@ dump_context::begin_scope (const char *name,
= begin_next_optinfo (dump_metadata_t (MSG_NOTE, impl_location),
user_location);
info.m_kind = OPTINFO_KIND_SCOPE;
- info.add_item (item);
+ info.add_item (std::move (item));
end_any_optinfo ();
}
- else
- delete item;
}
/* Pop a nested dump scope. */
@@ -1226,17 +1256,17 @@ dump_context::emit_optinfo (const optinfo *info)
consolidation into optinfo instances). */
void
-dump_context::emit_item (optinfo_item *item, dump_flags_t dump_kind)
+dump_context::emit_item (const optinfo_item &item, dump_flags_t dump_kind)
{
if (dump_file && apply_dump_filter_p (dump_kind, pflags))
- fprintf (dump_file, "%s", item->get_text ());
+ fprintf (dump_file, "%s", item.get_text ());
if (alt_dump_file && apply_dump_filter_p (dump_kind, alt_flags))
- fprintf (alt_dump_file, "%s", item->get_text ());
+ fprintf (alt_dump_file, "%s", item.get_text ());
/* Support for temp_dump_context in selftests. */
if (m_test_pp && apply_dump_filter_p (dump_kind, m_test_pp_flags))
- pp_string (m_test_pp, item->get_text ());
+ pp_string (m_test_pp, item.get_text ());
}
/* The current singleton dump_context, and its default. */
diff --git a/gcc/fortran/error.cc b/gcc/fortran/error.cc
index e896676..a588462 100644
--- a/gcc/fortran/error.cc
+++ b/gcc/fortran/error.cc
@@ -1125,7 +1125,7 @@ gfc_notify_std (int std, const char *gmsgid, ...)
static bool
gfc_format_decoder (pretty_printer *pp, text_info *text, const char *spec,
int precision, bool wide, bool set_locus, bool hash,
- bool *quoted, const char **buffer_ptr)
+ bool *quoted, pp_token_list &formatted_token_list)
{
switch (*spec)
{
@@ -1170,7 +1170,8 @@ gfc_format_decoder (pretty_printer *pp, text_info *text, const char *spec,
etc. diagnostics can use the FE printer while the FE is still
active. */
return default_tree_printer (pp, text, spec, precision, wide,
- set_locus, hash, quoted, buffer_ptr);
+ set_locus, hash, quoted,
+ formatted_token_list);
}
}
diff --git a/gcc/fortran/trans-io.cc b/gcc/fortran/trans-io.cc
index 7ab82fa..c0baa71 100644
--- a/gcc/fortran/trans-io.cc
+++ b/gcc/fortran/trans-io.cc
@@ -1692,7 +1692,8 @@ transfer_namelist_element (stmtblock_t * block, const char * var_name,
gcc_assert (sym || c);
/* Build the namelist object name. */
- if (sym && !sym->attr.use_only && sym->attr.use_rename)
+ if (sym && !sym->attr.use_only && sym->attr.use_rename
+ && sym->ns->use_stmts->rename)
string = gfc_build_cstring_const (sym->ns->use_stmts->rename->local_name);
else
string = gfc_build_cstring_const (var_name);
diff --git a/gcc/gimple-loop-interchange.cc b/gcc/gimple-loop-interchange.cc
index b422804..a4ea818 100644
--- a/gcc/gimple-loop-interchange.cc
+++ b/gcc/gimple-loop-interchange.cc
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/gimple-loop-jam.cc b/gcc/gimple-loop-jam.cc
index 306d5ce..bf01e0b 100644
--- a/gcc/gimple-loop-jam.cc
+++ b/gcc/gimple-loop-jam.cc
@@ -18,6 +18,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "tree-pass.h"
diff --git a/gcc/gimple-loop-versioning.cc b/gcc/gimple-loop-versioning.cc
index adea207..107b002 100644
--- a/gcc/gimple-loop-versioning.cc
+++ b/gcc/gimple-loop-versioning.cc
@@ -18,6 +18,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/graphite-dependences.cc b/gcc/graphite-dependences.cc
index a35f712..41e1114 100644
--- a/gcc/graphite-dependences.cc
+++ b/gcc/graphite-dependences.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define INCLUDE_ISL
+#define INCLUDE_MEMORY
#include "config.h"
diff --git a/gcc/graphite-isl-ast-to-gimple.cc b/gcc/graphite-isl-ast-to-gimple.cc
index a27402b..ff539b1 100644
--- a/gcc/graphite-isl-ast-to-gimple.cc
+++ b/gcc/graphite-isl-ast-to-gimple.cc
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define INCLUDE_ISL
+#define INCLUDE_MEMORY
#include "config.h"
diff --git a/gcc/graphite-optimize-isl.cc b/gcc/graphite-optimize-isl.cc
index 2222dd6..ff3dd6b 100644
--- a/gcc/graphite-optimize-isl.cc
+++ b/gcc/graphite-optimize-isl.cc
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define INCLUDE_ISL
+#define INCLUDE_MEMORY
#include "config.h"
diff --git a/gcc/graphite-poly.cc b/gcc/graphite-poly.cc
index c78ff98..76aba03 100644
--- a/gcc/graphite-poly.cc
+++ b/gcc/graphite-poly.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define INCLUDE_ISL
+#define INCLUDE_MEMORY
#include "config.h"
diff --git a/gcc/graphite-scop-detection.cc b/gcc/graphite-scop-detection.cc
index 9e44f10..de7c111 100644
--- a/gcc/graphite-scop-detection.cc
+++ b/gcc/graphite-scop-detection.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define INCLUDE_ISL
+#define INCLUDE_MEMORY
#include "config.h"
diff --git a/gcc/graphite-sese-to-poly.cc b/gcc/graphite-sese-to-poly.cc
index 5ce8985..1e7818a 100644
--- a/gcc/graphite-sese-to-poly.cc
+++ b/gcc/graphite-sese-to-poly.cc
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define INCLUDE_ISL
+#define INCLUDE_MEMORY
#include "config.h"
diff --git a/gcc/graphite.cc b/gcc/graphite.cc
index 80e6a5d..65b970f 100644
--- a/gcc/graphite.cc
+++ b/gcc/graphite.cc
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see
the related work. */
#define INCLUDE_ISL
+#define INCLUDE_MEMORY
#include "config.h"
#include "system.h"
diff --git a/gcc/opt-problem.cc b/gcc/opt-problem.cc
index f40f481..fc29333 100644
--- a/gcc/opt-problem.cc
+++ b/gcc/opt-problem.cc
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
@@ -70,7 +71,8 @@ opt_problem::opt_problem (const dump_location_t &loc,
/* Phase 3: dump the items to the "immediate" dump destinations,
and storing them into m_optinfo for later retrieval. */
- pp.emit_items (&m_optinfo);
+ pp.set_optinfo (&m_optinfo);
+ pp_output_formatted_text (&pp, nullptr);
}
}
diff --git a/gcc/optinfo.cc b/gcc/optinfo.cc
index 7a82561..48a270cbf 100644
--- a/gcc/optinfo.cc
+++ b/gcc/optinfo.cc
@@ -84,10 +84,10 @@ optinfo::~optinfo ()
/* Add ITEM to this optinfo. */
void
-optinfo::add_item (optinfo_item *item)
+optinfo::add_item (std::unique_ptr<optinfo_item> item)
{
- gcc_assert (item);
- m_items.safe_push (item);
+ gcc_assert (item.get ());
+ m_items.safe_push (item.release ());
}
/* Get MSG_* flags corresponding to KIND. */
@@ -123,7 +123,7 @@ optinfo::emit_for_opt_problem () const
unsigned i;
optinfo_item *item;
FOR_EACH_VEC_ELT (m_items, i, item)
- dump_context::get ().emit_item (item, dump_kind);
+ dump_context::get ().emit_item (*item, dump_kind);
/* Re-emit to "non-immediate" destinations. */
dump_context::get ().emit_optinfo (this);
diff --git a/gcc/optinfo.h b/gcc/optinfo.h
index 986ef75..db92294 100644
--- a/gcc/optinfo.h
+++ b/gcc/optinfo.h
@@ -21,6 +21,15 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_OPTINFO_H
#define GCC_OPTINFO_H
+/* This header uses std::unique_ptr, but <memory> can't be directly
+ included due to issues with macros. Hence <memory> must be included
+ from system.h by defining INCLUDE_MEMORY in any source file using
+ optinfo.h. */
+
+#ifndef INCLUDE_MEMORY
+# error "You must define INCLUDE_MEMORY before including system.h to use optinfo.h"
+#endif
+
/* An "optinfo" is a bundle of information describing part of an
optimization, which can be emitted to zero or more of several
destinations, such as:
@@ -119,7 +128,7 @@ class optinfo
location_t get_location_t () const { return m_loc.get_location_t (); }
profile_count get_count () const { return m_loc.get_count (); }
- void add_item (optinfo_item *item);
+ void add_item (std::unique_ptr<optinfo_item> item);
void emit_for_opt_problem () const;
diff --git a/gcc/pretty-print-format-impl.h b/gcc/pretty-print-format-impl.h
new file mode 100644
index 0000000..f199628
--- /dev/null
+++ b/gcc/pretty-print-format-impl.h
@@ -0,0 +1,489 @@
+/* Implementation detail of pp_format.
+ Copyright (C) 2002-2024 Free Software Foundation, Inc.
+ Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
+
+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_PRETTY_PRINT_FORMAT_IMPL_H
+#define GCC_PRETTY_PRINT_FORMAT_IMPL_H
+
+#include "pretty-print.h"
+#include "diagnostic-event-id.h"
+
+/* A struct representing a pending item to be printed within
+ pp_format.
+
+ These can represent:
+ - a run of text within one of the output_buffers's obstacks
+ - begin/end named color
+ - open/close quote
+ - begin/end URL
+ - event IDs
+ - custom data (for the formatter, for the pretty_printer,
+ or the output format)
+
+ These are built into pp_token_list instances.
+
+ Doing so allows for interaction between:
+
+ - pretty_printer formatting codes (such as C++'s %H and %I,
+ which can't be printed until we've seen both)
+
+ - output formats, such as text vs SARIF (so each can handle URLs
+ and event IDs it its own way)
+
+ - optimization records, where we want to stash data into the
+ formatted messages
+
+ - urlifiers: these can be run in phase 3 of formatting
+
+ without needing lots of fragile logic on char pointers.
+
+ To avoid needing lots of heap allocation/deallocation, pp_token
+ instances are allocated in the pretty_printer's chunk_obstack:
+ they must not outlive phase 3 of formatting of the given
+ chunk_info level. */
+
+struct pp_token
+{
+public:
+ enum class kind
+ {
+ text,
+
+ begin_color,
+ end_color,
+
+ begin_quote,
+ end_quote,
+
+ begin_url,
+ end_url,
+
+ event_id,
+
+ custom_data,
+
+ NUM_KINDS
+ };
+
+ pp_token (enum kind k);
+
+ pp_token (const pp_token &) = delete;
+ pp_token (pp_token &&) = delete;
+
+ virtual ~pp_token () = default;
+
+ pp_token &operator= (const pp_token &) = delete;
+ pp_token &operator= (pp_token &&) = delete;
+
+ void dump (FILE *out) const;
+ void DEBUG_FUNCTION dump () const { dump (stderr); }
+
+ static void *operator new (size_t sz, obstack &s);
+ static void operator delete (void *);
+
+ enum kind m_kind;
+
+ // Intrusive doubly-linked list
+ pp_token *m_prev;
+ pp_token *m_next;
+};
+
+/* Subclasses of pp_token for the various kinds of token. */
+
+struct pp_token_text : public pp_token
+{
+ pp_token_text (label_text &&value)
+ : pp_token (kind::text),
+ m_value (std::move (value))
+ {
+ gcc_assert (m_value.get ());
+ }
+
+ label_text m_value;
+};
+
+template <>
+template <>
+inline bool
+is_a_helper <pp_token_text *>::test (pp_token *tok)
+{
+ return tok->m_kind == pp_token::kind::text;
+}
+
+template <>
+template <>
+inline bool
+is_a_helper <const pp_token_text *>::test (const pp_token *tok)
+{
+ return tok->m_kind == pp_token::kind::text;
+}
+
+struct pp_token_begin_color : public pp_token
+{
+ pp_token_begin_color (label_text &&value)
+ : pp_token (kind::begin_color),
+ m_value (std::move (value))
+ {
+ gcc_assert (m_value.get ());
+ }
+
+ label_text m_value;
+};
+
+template <>
+template <>
+inline bool
+is_a_helper <pp_token_begin_color *>::test (pp_token *tok)
+{
+ return tok->m_kind == pp_token::kind::begin_color;
+}
+
+template <>
+template <>
+inline bool
+is_a_helper <const pp_token_begin_color *>::test (const pp_token *tok)
+{
+ return tok->m_kind == pp_token::kind::begin_color;
+}
+
+struct pp_token_end_color : public pp_token
+{
+ pp_token_end_color ()
+ : pp_token (kind::end_color)
+ {
+ }
+};
+
+struct pp_token_begin_quote : public pp_token
+{
+ pp_token_begin_quote ()
+ : pp_token (kind::begin_quote)
+ {
+ }
+};
+
+struct pp_token_end_quote : public pp_token
+{
+ pp_token_end_quote ()
+ : pp_token (kind::end_quote)
+ {
+ }
+};
+
+struct pp_token_begin_url : public pp_token
+{
+ pp_token_begin_url (label_text &&value)
+ : pp_token (kind::begin_url),
+ m_value (std::move (value))
+ {
+ gcc_assert (m_value.get ());
+ }
+
+ label_text m_value;
+};
+
+template <>
+template <>
+inline bool
+is_a_helper <pp_token_begin_url*>::test (pp_token *tok)
+{
+ return tok->m_kind == pp_token::kind::begin_url;
+}
+
+template <>
+template <>
+inline bool
+is_a_helper <const pp_token_begin_url*>::test (const pp_token *tok)
+{
+ return tok->m_kind == pp_token::kind::begin_url;
+}
+
+struct pp_token_end_url : public pp_token
+{
+ pp_token_end_url ()
+ : pp_token (kind::end_url)
+ {
+ }
+};
+
+struct pp_token_event_id : public pp_token
+{
+ pp_token_event_id (diagnostic_event_id_t event_id)
+ : pp_token (kind::event_id),
+ m_event_id (event_id)
+ {
+ gcc_assert (event_id.known_p ());
+ }
+
+ diagnostic_event_id_t m_event_id;
+};
+
+template <>
+template <>
+inline bool
+is_a_helper <pp_token_event_id *>::test (pp_token *tok)
+{
+ return tok->m_kind == pp_token::kind::event_id;
+}
+
+template <>
+template <>
+inline bool
+is_a_helper <const pp_token_event_id *>::test (const pp_token *tok)
+{
+ return tok->m_kind == pp_token::kind::event_id;
+}
+
+struct pp_token_custom_data : public pp_token
+{
+ class value
+ {
+ public:
+ virtual ~value () {}
+ virtual void dump (FILE *out) const = 0;
+
+ /* Hook for lowering a custom_data token to standard tokens.
+ Return true and write to OUT if possible.
+ Return false for custom_data that is to be handled by
+ the token_printer. */
+ virtual bool as_standard_tokens (pp_token_list &out) = 0;
+ };
+
+ pp_token_custom_data (std::unique_ptr<value> val)
+ : pp_token (kind::custom_data),
+ m_value (std::move (val))
+ {
+ gcc_assert (m_value.get ());
+ }
+
+ std::unique_ptr<value> m_value;
+};
+
+template <>
+template <>
+inline bool
+is_a_helper <pp_token_custom_data *>::test (pp_token *tok)
+{
+ return tok->m_kind == pp_token::kind::custom_data;
+}
+
+template <>
+template <>
+inline bool
+is_a_helper <const pp_token_custom_data *>::test (const pp_token *tok)
+{
+ return tok->m_kind == pp_token::kind::custom_data;
+}
+
+/* A list of pp_token, with ownership of the tokens, using
+ a particular obstack to allocate its tokens. These are
+ also allocated on the obstack during formatting (or, occasionally,
+ the stack). */
+
+class pp_token_list
+{
+public:
+ // Allocate a new pp_token_list within S.
+ static pp_token_list *make (obstack &s)
+ {
+ return new (s) pp_token_list (s);
+ }
+ static void *operator new (size_t sz, obstack &s);
+ static void operator delete (void *);
+
+ pp_token_list (obstack &s);
+ pp_token_list (const pp_token_list &) = delete;
+ pp_token_list (pp_token_list &&);
+
+ ~pp_token_list ();
+
+ pp_token &operator= (const pp_token_list &) = delete;
+ pp_token &operator= (pp_token_list &&) = delete;
+
+/* Make a pp_token of the given subclass, using the relevant obstack to provide
+ the memory. The pp_token must therefore not outlive the current chunk_info
+ level during formatting. */
+ template<typename Subclass, typename... Args>
+ std::unique_ptr<pp_token>
+ make_token (Args&&... args)
+ {
+ return std::unique_ptr<pp_token>
+ (new (m_obstack) Subclass (std::forward<Args> (args)...));
+ }
+
+ template<typename Subclass, typename... Args>
+ void push_back (Args&&... args)
+ {
+ auto tok = make_token<Subclass> (std::forward<Args> (args)...);
+ push_back (std::move (tok));
+ }
+ void push_back_text (label_text &&text);
+ void push_back (std::unique_ptr<pp_token> tok);
+ void push_back_list (pp_token_list &&list);
+
+ std::unique_ptr<pp_token> pop_front ();
+
+ std::unique_ptr<pp_token> remove_token (pp_token *tok);
+
+ void insert_after (std::unique_ptr<pp_token> new_tok,
+ pp_token *relative_tok);
+
+ void replace_custom_tokens ();
+ void merge_consecutive_text_tokens ();
+ void apply_urlifier (const urlifier &urlifier);
+
+ void dump (FILE *out) const;
+ void DEBUG_FUNCTION dump () const { dump (stderr); }
+
+ obstack &m_obstack;
+
+ pp_token *m_first;
+ pp_token *m_end;
+};
+
+/* The chunk_info data structure forms a stack of the results from the
+ first phase of formatting (pp_format) which have not yet been
+ output (pp_output_formatted_text). A stack is necessary because
+ the diagnostic starter may decide to generate its own output by way
+ of the formatter. */
+class chunk_info
+{
+ friend class pretty_printer;
+ friend class pp_markup::context;
+
+public:
+ pp_token_list * const * get_token_lists () const { return m_args; }
+
+ void append_formatted_chunk (obstack &s, const char *content);
+
+ void pop_from_output_buffer (output_buffer &buf);
+
+ void dump (FILE *out) const;
+ void DEBUG_FUNCTION dump () const { dump (stderr); }
+
+private:
+ void on_begin_quote (const output_buffer &buf,
+ unsigned chunk_idx,
+ const urlifier *urlifier);
+
+ void on_end_quote (pretty_printer *pp,
+ output_buffer &buf,
+ unsigned chunk_idx,
+ const urlifier *urlifier);
+
+ /* Pointer to previous chunk on the stack. */
+ chunk_info *m_prev;
+
+ /* Array of chunks to output. Each chunk is a doubly-linked list of
+ pp_token.
+
+ The chunks can be printed via chunk_info::dump ().
+
+ In the first phase of formatting, even-numbered chunks are
+ to be output verbatim, odd-numbered chunks are format specifiers.
+ For example, given:
+ pp_format (pp,
+ "foo: %i, bar: %s, opt: %qs",
+ 42, "baz", "-foption");
+
+ after phase 1 we might have:
+ (gdb) call buffer->cur_chunk_array->dump()
+ 0: [TEXT("foo: ")]
+ 1: [TEXT("i")]
+ 2: [TEXT(", bar: ")]
+ 3: [TEXT("s")]
+ 4: [TEXT(", opt: ")]
+ 5: [TEXT("qs")]
+
+ The second phase replaces all odd-numbered chunks with formatted
+ token lists. In the above example, after phase 2 we might have:
+ (gdb) call pp->m_buffer->cur_chunk_array->dump()
+ 0: [TEXT("foo: ")]
+ 1: [TEXT("42")]
+ 2: [TEXT(", bar: ")]
+ 3: [TEXT("baz")]
+ 4: [TEXT(", opt: ")]
+ 5: [BEGIN_QUOTE, TEXT("-foption"), END_QUOTE]
+ For example the %qs has become the three tokens:
+ [BEGIN_QUOTE, TEXT("-foption"), END_QUOTE]
+
+ The third phase (in pp_output_formatted_text):
+
+ (1) merges the tokens from all the chunks into one list,
+ giving e.g.
+ (gdb) call tokens.dump()
+ [TEXT("foo: "), TEXT("42"), TEXT(", bar: "), TEXT("baz"),
+ TEXT(", opt: "), BEGIN_QUOTE, TEXT("-foption"), END_QUOTE]
+
+ (2) lowers some custom tokens into non-custom tokens
+
+ (3) merges consecutive text tokens, giving e.g.:
+ (gdb) call tokens.dump()
+ [TEXT("foo: 42, bar: baz, option: "),
+ BEGIN_QUOTE, TEXT("-foption"), END_QUOTE]
+
+ (4) if provided with a urlifier, tries to apply it to quoted text,
+ giving e.g:
+ (gdb) call tokens.dump()
+ [TEXT("foo: 42, bar: baz, option: "), BEGIN_QUOTE,
+ BEGIN_URL("http://example.com"), TEXT("-foption"), END_URL, END_QUOTE]
+
+ (5) emits all tokens in sequence with appropriate line-wrapping. This
+ can be overridded via the pretty_printer's token_printer, allowing for
+ output formats to e.g. override how URLs are handled, or to handle
+ custom_data that wasn't lowered in (2) above, e.g. for handling JSON
+ output of optimization records. */
+ pp_token_list *m_args[PP_NL_ARGMAX * 2];
+
+ /* The pp_tokens, pp_token_lists, and the accumulated text buffers are
+ allocated within the output_buffer's chunk_obstack. In the above
+ example, the in-memory layout of the chunk_obstack might look like
+ this after phase 1:
+
+ + pp_token_list for chunk 0 (m_first: *) <--- START of chunk_info level
+ | |
+ + "foo: \0" <-------------\ |
+ | | |
+ + pp_token_text (borrowed: *) <-------/
+ |
+ + pp_token_list for chunk 1
+ |
+ + "i\0" <------------------\
+ | |
+ + pp_token_text (borrowed: *)
+ |
+ + ...etc for chunks 2 to 4...
+ |
+ + pp_token_list for chunk 5
+ |
+ + "qs\0" <-----------------\
+ | |
+ + pp_token_text (borrowed: *)
+ |
+ |
+ V
+ obstack grows this way
+
+ At each stage, allocation of additional text buffers, tokens, and lists
+ grow forwards in the obstack (though the internal pointers in linked
+ lists might point backwards to earlier objects within the same
+ chunk_info level). */
+};
+
+#endif /* GCC_PRETTY_PRINT_FORMAT_IMPL_H */
diff --git a/gcc/pretty-print-markup.h b/gcc/pretty-print-markup.h
index b35632a..ce2c5e9 100644
--- a/gcc/pretty-print-markup.h
+++ b/gcc/pretty-print-markup.h
@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-color.h"
+class pp_token_list;
+
namespace pp_markup {
class context
@@ -31,12 +33,12 @@ public:
output_buffer &buf,
unsigned chunk_idx,
bool &quoted,
- const urlifier *urlifier)
+ pp_token_list *formatted_token_list)
: m_pp (pp),
m_buf (buf),
m_chunk_idx (chunk_idx),
m_quoted (quoted),
- m_urlifier (urlifier)
+ m_formatted_token_list (formatted_token_list)
{
}
@@ -46,11 +48,13 @@ public:
void begin_highlight_color (const char *color_name);
void end_highlight_color ();
+ void push_back_any_text ();
+
pretty_printer &m_pp;
output_buffer &m_buf;
unsigned m_chunk_idx;
bool &m_quoted;
- const urlifier *m_urlifier;
+ pp_token_list *m_formatted_token_list;
};
/* Abstract base class for use in pp_format for handling "%e".
diff --git a/gcc/pretty-print-urlifier.h b/gcc/pretty-print-urlifier.h
index 3e63e62..3feb809 100644
--- a/gcc/pretty-print-urlifier.h
+++ b/gcc/pretty-print-urlifier.h
@@ -20,7 +20,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_PRETTY_PRINT_URLIFIER_H
#define GCC_PRETTY_PRINT_URLIFIER_H
-/* Abstract base class for optional use in pp_format for adding URLs
+/* Abstract base class for optional use in pretty-printing for adding URLs
to quoted text strings. */
class urlifier
diff --git a/gcc/pretty-print.cc b/gcc/pretty-print.cc
index 1d91da8..fe6b6090 100644
--- a/gcc/pretty-print.cc
+++ b/gcc/pretty-print.cc
@@ -19,16 +19,19 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "intl.h"
#include "pretty-print.h"
+#include "pretty-print-format-impl.h"
#include "pretty-print-markup.h"
#include "pretty-print-urlifier.h"
#include "diagnostic-color.h"
#include "diagnostic-event-id.h"
#include "diagnostic-highlight-colors.h"
+#include "make-unique.h"
#include "selftest.h"
#if HAVE_ICONV
@@ -709,6 +712,10 @@ static int
decode_utf8_char (const unsigned char *, size_t len, unsigned int *);
static void pp_quoted_string (pretty_printer *, const char *, size_t = -1);
+static void
+default_token_printer (pretty_printer *pp,
+ const pp_token_list &tokens);
+
/* Overwrite the given location/range within this text_info's rich_location.
For use e.g. when implementing "+" in client format decoders. */
@@ -1062,196 +1069,418 @@ pp_indent (pretty_printer *pp)
static const char *get_end_url_string (pretty_printer *);
-/* Append STR to OSTACK, without a null-terminator. */
+/* struct pp_token. */
-static void
-obstack_append_string (obstack *ostack, const char *str)
+pp_token::pp_token (enum kind k)
+: m_kind (k),
+ m_prev (nullptr),
+ m_next (nullptr)
{
- obstack_grow (ostack, str, strlen (str));
}
-/* Append STR to OSTACK, without a null-terminator. */
-
-static void
-obstack_append_string (obstack *ostack, const char *str, size_t len)
-{
- obstack_grow (ostack, str, len);
-}
-
-/* Given quoted text within the buffer OBSTACK
- at the half-open interval [QUOTED_TEXT_START_IDX, QUOTED_TEXT_END_IDX),
- potentially use URLIFIER (if non-null) to see if there's a URL for the
- quoted text.
-
- If so, replace the quoted part of the text in the buffer with a URLified
- version of the text, using PP's settings.
-
- For example, given this is the buffer:
- "this is a test `hello worldTRAILING-CONTENT"
- .................^~~~~~~~~~~
- with the quoted text starting at the 'h' of "hello world", the buffer
- becomes:
- "this is a test `BEGIN_URL(URL)hello worldEND(URL)TRAILING-CONTENT"
- .................^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- .................-----------replacement-----------
-
- Return the new offset into the buffer of the quoted text endpoint i.e.
- the offset of "TRAILING-CONTENT" in the above. */
-
-static size_t
-urlify_quoted_string (pretty_printer *pp,
- obstack *obstack,
- const urlifier *urlifier,
- size_t quoted_text_start_idx,
- size_t quoted_text_end_idx)
-{
- if (!pp->supports_urls_p ())
- return quoted_text_end_idx;
- if (!urlifier)
- return quoted_text_end_idx;
-
- const size_t quoted_len = quoted_text_end_idx - quoted_text_start_idx;
- if (quoted_len == 0)
- /* Empty quoted string; do nothing. */
- return quoted_text_end_idx;
- const char *start = (obstack->object_base + quoted_text_start_idx);
- char *url = urlifier->get_url_for_quoted_text (start, quoted_len);
- if (!url)
- /* No URL for this quoted text; do nothing. */
- return quoted_text_end_idx;
-
- /* Stash a copy of the remainder of the chunk. */
- char *text = xstrndup (start,
- obstack_object_size (obstack) - quoted_text_start_idx);
-
- /* Replace quoted text... */
- obstack->next_free = obstack->object_base + quoted_text_start_idx;
-
- /* ...with URLified version of the text. */
- /* Begin URL. */
- switch (pp->get_url_format ())
+void
+pp_token::dump (FILE *out) const
+{
+ switch (m_kind)
{
default:
- case URL_FORMAT_NONE:
gcc_unreachable ();
- case URL_FORMAT_ST:
- obstack_append_string (obstack, "\33]8;;");
- obstack_append_string (obstack, url);
- obstack_append_string (obstack, "\33\\");
+ case kind::text:
+ {
+ const pp_token_text *sub = as_a <const pp_token_text *> (this);
+ gcc_assert (sub->m_value.get ());
+ fprintf (out, "TEXT(\"%s\")", sub->m_value.get ());
+ }
break;
- case URL_FORMAT_BEL:
- obstack_append_string (obstack, "\33]8;;");
- obstack_append_string (obstack, url);
- obstack_append_string (obstack, "\a");
+ case kind::begin_color:
+ {
+ const pp_token_begin_color *sub
+ = as_a <const pp_token_begin_color *> (this);
+ gcc_assert (sub->m_value.get ());
+ fprintf (out, "BEGIN_COLOR(\"%s\")", sub->m_value.get ());
+ break;
+ }
+ case kind::end_color:
+ fprintf (out, "END_COLOR");
+ break;
+ case kind::begin_quote:
+ fprintf (out, "BEGIN_QUOTE");
+ break;
+ case kind::end_quote:
+ fprintf (out, "END_QUOTE");
+ break;
+ case kind::begin_url:
+ {
+ const pp_token_begin_url *sub
+ = as_a <const pp_token_begin_url *> (this);
+ gcc_assert (sub->m_value.get ());
+ fprintf (out, "BEGIN_URL(\"%s\")", sub->m_value.get ());
+ }
+ break;
+ case kind::end_url:
+ fprintf (out, "END_URL");
+ break;
+
+ case kind::event_id:
+ {
+ const pp_token_event_id *sub
+ = as_a <const pp_token_event_id *> (this);
+ gcc_assert (sub->m_event_id.known_p ());
+ fprintf (out, "EVENT((%i))", sub->m_event_id.one_based ());
+ }
+ break;
+
+ case kind::custom_data:
+ {
+ const pp_token_custom_data *sub
+ = as_a <const pp_token_custom_data *> (this);
+ gcc_assert (sub->m_value.get ());
+ fprintf (out, "CUSTOM(");
+ sub->m_value->dump (out);
+ fprintf (out, ")");
+ }
break;
}
- /* Add back the quoted part of the text. */
- obstack_append_string (obstack, text, quoted_len);
- /* End URL. */
- obstack_append_string (obstack,
- get_end_url_string (pp));
+}
+
+/* Allocate SZ bytes within S, which must not be half-way through
+ building another object. */
- size_t new_end_idx = obstack_object_size (obstack);
+static void *
+allocate_object (size_t sz, obstack &s)
+{
+ /* We must not be half-way through an object. */
+ gcc_assert (obstack_base (&s) == obstack_next_free (&s));
- /* Add back the remainder of the text after the quoted part. */
- obstack_append_string (obstack, text + quoted_len);
- free (text);
- free (url);
- return new_end_idx;
+ obstack_grow (&s, obstack_base (&s), sz);
+ void *buf = obstack_finish (&s);
+ return buf;
}
-/* A class for tracking quoted text within a buffer for
- use by a urlifier. */
+/* Make room for a pp_token instance within obstack S. */
-class quoting_info
+void *
+pp_token::operator new (size_t sz, obstack &s)
{
-public:
- /* Called when quoted text is begun in phase 1 or 2. */
- void on_begin_quote (const output_buffer &buf,
- unsigned chunk_idx)
- {
- /* Stash location of start of quoted string. */
- size_t byte_offset = obstack_object_size (&buf.chunk_obstack);
- m_loc_last_open_quote = location (chunk_idx, byte_offset);
- }
+ return allocate_object (sz, s);
+}
- /* Called when quoted text is ended in phase 1 or 2. */
- void on_end_quote (pretty_printer *pp,
- output_buffer &buf,
- unsigned chunk_idx,
- const urlifier &urlifier)
- {
- /* If possible, do urlification now. */
- if (chunk_idx == m_loc_last_open_quote.m_chunk_idx)
- {
- urlify_quoted_string (pp,
- &buf.chunk_obstack,
- &urlifier,
- m_loc_last_open_quote.m_byte_offset,
- obstack_object_size (&buf.chunk_obstack));
- m_loc_last_open_quote = location ();
- return;
- }
- /* Otherwise the quoted text straddles multiple chunks.
- Stash the location of end of quoted string for use in phase 3. */
- size_t byte_offset = obstack_object_size (&buf.chunk_obstack);
- m_phase_3_quotes.push_back (run (m_loc_last_open_quote,
- location (chunk_idx, byte_offset)));
- m_loc_last_open_quote = location ();
- }
+void
+pp_token::operator delete (void *)
+{
+ /* No-op: pp_tokens are allocated within obstacks, so
+ the memory will be reclaimed when the obstack is freed. */
+}
- bool has_phase_3_quotes_p () const
- {
- return m_phase_3_quotes.size () > 0;
- }
- void handle_phase_3 (pretty_printer *pp,
- const urlifier &urlifier);
+/* class pp_token_list. */
-private:
- struct location
- {
- location ()
- : m_chunk_idx (UINT_MAX),
- m_byte_offset (SIZE_MAX)
+/* Make room for a pp_token_list instance within obstack S. */
+
+void *
+pp_token_list::operator new (size_t sz, obstack &s)
+{
+ return allocate_object (sz, s);
+}
+
+void
+pp_token_list::operator delete (void *)
+{
+ /* No-op: pp_token_list allocated within obstacks don't
+ need their own reclaim the memory will be reclaimed when
+ the obstack is freed. */
+}
+
+pp_token_list::pp_token_list (obstack &s)
+: m_obstack (s),
+ m_first (nullptr),
+ m_end (nullptr)
+{
+}
+
+pp_token_list::pp_token_list (pp_token_list &&other)
+: m_obstack (other.m_obstack),
+ m_first (other.m_first),
+ m_end (other.m_end)
+{
+ other.m_first = nullptr;
+ other.m_end = nullptr;
+}
+
+pp_token_list::~pp_token_list ()
+{
+ for (auto iter = m_first; iter; )
{
+ pp_token *next = iter->m_next;
+ delete iter;
+ iter = next;
}
+}
+
+void
+pp_token_list::push_back_text (label_text &&text)
+{
+ if (text.get ()[0] == '\0')
+ return; // pushing empty string is a no-op
+ push_back<pp_token_text> (std::move (text));
+}
- location (unsigned chunk_idx,
- size_t byte_offset)
- : m_chunk_idx (chunk_idx),
- m_byte_offset (byte_offset)
+void
+pp_token_list::push_back (std::unique_ptr<pp_token> tok)
+{
+ if (!m_first)
+ {
+ gcc_assert (m_end == nullptr);
+ m_first = tok.get ();
+ m_end = tok.get ();
+ }
+ else
{
+ gcc_assert (m_end != nullptr);
+ m_end->m_next = tok.get ();
+ tok->m_prev = m_end;
+ m_end = tok.get ();
}
+ tok.release ();
+}
- unsigned m_chunk_idx;
- size_t m_byte_offset;
- };
+void
+pp_token_list::push_back_list (pp_token_list &&list)
+{
+ while (auto tok = list.pop_front ())
+ push_back (std::move (tok));
+}
- struct run
- {
- run (location start, location end)
- : m_start (start), m_end (end)
+std::unique_ptr<pp_token>
+pp_token_list::pop_front ()
+{
+ pp_token *result = m_first;
+ if (result == nullptr)
+ return nullptr;
+
+ gcc_assert (result->m_prev == nullptr);
+ m_first = result->m_next;
+ if (result->m_next)
+ {
+ gcc_assert (result != m_end);
+ m_first->m_prev = nullptr;
+ }
+ else
{
+ gcc_assert (result == m_end);
+ m_end = nullptr;
}
+ result->m_next = nullptr;
+ return std::unique_ptr<pp_token> (result);
+}
- location m_start;
- location m_end;
- };
+std::unique_ptr<pp_token>
+pp_token_list::remove_token (pp_token *tok)
+{
+ gcc_assert (tok);
+ if (tok->m_prev)
+ {
+ gcc_assert (tok != m_first);
+ tok->m_prev->m_next = tok->m_next;
+ }
+ else
+ {
+ gcc_assert (tok == m_first);
+ m_first = tok->m_next;
+ }
+ if (tok->m_next)
+ {
+ gcc_assert (tok != m_end);
+ tok->m_next->m_prev = tok->m_prev;
+ }
+ else
+ {
+ gcc_assert (tok == m_end);
+ m_end = tok->m_prev;
+ }
+ tok->m_prev = nullptr;
+ tok->m_next = nullptr;
+ gcc_assert (m_first != tok);
+ gcc_assert (m_end != tok);
+ return std::unique_ptr<pp_token> (tok);
+}
+
+/* Insert NEW_TOK after RELATIVE_TOK. */
+
+void
+pp_token_list::insert_after (std::unique_ptr<pp_token> new_tok_up,
+ pp_token *relative_tok)
+{
+ pp_token *new_tok = new_tok_up.release ();
+
+ gcc_assert (new_tok);
+ gcc_assert (new_tok->m_prev == nullptr);
+ gcc_assert (new_tok->m_next == nullptr);
+ gcc_assert (relative_tok);
+
+ if (relative_tok->m_next)
+ {
+ gcc_assert (relative_tok != m_end);
+ relative_tok->m_next->m_prev = new_tok;
+ }
+ else
+ {
+ gcc_assert (relative_tok == m_end);
+ m_end = new_tok;
+ }
+ new_tok->m_prev = relative_tok;
+ new_tok->m_next = relative_tok->m_next;
+ relative_tok->m_next = new_tok;
+}
+
+void
+pp_token_list::replace_custom_tokens ()
+{
+ pp_token *iter = m_first;
+ while (iter)
+ {
+ pp_token *next = iter->m_next;
+ if (iter->m_kind == pp_token::kind::custom_data)
+ {
+ pp_token_list tok_list (m_obstack);
+ pp_token_custom_data *sub = as_a <pp_token_custom_data *> (iter);
+ if (sub->m_value->as_standard_tokens (tok_list))
+ {
+ while (auto tok = tok_list.pop_front ())
+ {
+ /* The resulting token list must not contain any
+ custom data. */
+ gcc_assert (tok->m_kind != pp_token::kind::custom_data);
+ insert_after (std::move (tok), iter);
+ }
+ remove_token (iter);
+ }
+ }
+ iter = next;
+ }
+}
+
+/* Merge any runs of consecutive text tokens within this list
+ into individual text tokens. */
+
+void
+pp_token_list::merge_consecutive_text_tokens ()
+{
+ pp_token *start_of_run = m_first;
+ while (start_of_run)
+ {
+ if (start_of_run->m_kind != pp_token::kind::text)
+ {
+ start_of_run = start_of_run->m_next;
+ continue;
+ }
+ pp_token *end_of_run = start_of_run;
+ while (end_of_run->m_next
+ && end_of_run->m_next->m_kind == pp_token::kind::text)
+ end_of_run = end_of_run->m_next;
+ if (end_of_run != start_of_run)
+ {
+ /* start_of_run through end_of_run are a run of consecutive
+ text tokens. */
+
+ /* Calculate size of buffer for merged text. */
+ size_t sz = 0;
+ for (auto iter = start_of_run; iter != end_of_run->m_next;
+ iter = iter->m_next)
+ {
+ pp_token_text *iter_text = static_cast<pp_token_text *> (iter);
+ sz += strlen (iter_text->m_value.get ());
+ }
+
+ /* Allocate and populate buffer for merged text
+ (within m_obstack). */
+ char * const buf = (char *)allocate_object (sz + 1, m_obstack);
+ char *p = buf;
+ for (auto iter = start_of_run; iter != end_of_run->m_next;
+ iter = iter->m_next)
+ {
+ pp_token_text *iter_text = static_cast<pp_token_text *> (iter);
+ size_t iter_sz = strlen (iter_text->m_value.get ());
+ memcpy (p, iter_text->m_value.get (), iter_sz);
+ p += iter_sz;
+ }
+ *p = '\0';
+
+ /* Replace start_of_run's buffer pointer with the new buffer. */
+ static_cast<pp_token_text *> (start_of_run)->m_value
+ = label_text::borrow (buf);
+
+ /* Remove all the other text tokens in the run. */
+ pp_token * const next = end_of_run->m_next;
+ while (start_of_run->m_next != next)
+ remove_token (start_of_run->m_next);
+ start_of_run = next;
+ }
+ else
+ start_of_run = end_of_run->m_next;
+ }
+}
+
+/* Apply URLIFIER to this token list.
+ Find BEGIN_QUOTE, TEXT, END_QUOTE triples, and if URLIFIER has a url
+ for the value of TEXT, then wrap TEXT in a {BEGIN,END}_URL pair. */
+
+void
+pp_token_list::apply_urlifier (const urlifier &urlifier)
+{
+ for (pp_token *iter = m_first; iter; )
+ {
+ if (iter->m_kind == pp_token::kind::begin_quote
+ && iter->m_next
+ && iter->m_next->m_kind == pp_token::kind::text
+ && iter->m_next->m_next
+ && iter->m_next->m_next->m_kind == pp_token::kind::end_quote)
+ {
+ pp_token *begin_quote = iter;
+ pp_token_text *text = as_a <pp_token_text *> (begin_quote->m_next);
+ pp_token *end_quote = text->m_next;
+ if (char *url = urlifier.get_url_for_quoted_text
+ (text->m_value.get (),
+ strlen (text->m_value.get ())))
+ {
+ auto begin_url
+ = make_token<pp_token_begin_url> (label_text::take (url));
+ auto end_url = make_token<pp_token_end_url> ();
+ insert_after (std::move (begin_url), begin_quote);
+ insert_after (std::move (end_url), text);
+ }
+ iter = end_quote->m_next;
+ }
+ else
+ iter = iter->m_next;
+ }
+}
+
+void
+pp_token_list::dump (FILE *out) const
+{
+ fprintf (out, "[");
+ for (auto iter = m_first; iter; iter = iter->m_next)
+ {
+ iter->dump (out);
+ if (iter->m_next)
+ fprintf (out, ", ");
+ }
+ fprintf (out, "]\n");
+}
- location m_loc_last_open_quote;
- std::vector<run> m_phase_3_quotes;
-};
/* Adds a chunk to the end of formatted output, so that it
will be printed by pp_output_formatted_text. */
void
-chunk_info::append_formatted_chunk (const char *content)
+chunk_info::append_formatted_chunk (obstack &s, const char *content)
{
unsigned int chunk_idx;
for (chunk_idx = 0; m_args[chunk_idx]; chunk_idx++)
;
- m_args[chunk_idx++] = content;
+ pp_token_list *tokens = pp_token_list::make (s);
+ tokens->push_back_text (label_text::borrow (content));
+ m_args[chunk_idx++] = tokens;
m_args[chunk_idx] = nullptr;
}
@@ -1261,34 +1490,33 @@ chunk_info::append_formatted_chunk (const char *content)
void
chunk_info::pop_from_output_buffer (output_buffer &buf)
{
- delete m_quotes;
buf.cur_chunk_array = m_prev;
obstack_free (&buf.chunk_obstack, this);
}
void
-chunk_info::on_begin_quote (const output_buffer &buf,
- unsigned chunk_idx,
- const urlifier *urlifier)
+chunk_info::dump (FILE *out) const
{
- if (!urlifier)
- return;
- if (!m_quotes)
- m_quotes = new quoting_info ();
- m_quotes->on_begin_quote (buf, chunk_idx);
+ for (size_t idx = 0; m_args[idx]; ++idx)
+ {
+ fprintf (out, "%i: ", (int)idx);
+ m_args[idx]->dump (out);
+ }
}
-void
-chunk_info::on_end_quote (pretty_printer *pp,
- output_buffer &buf,
- unsigned chunk_idx,
- const urlifier *urlifier)
+/* Finish any text accumulating within CUR_OBSTACK,
+ terminating it.
+ Push a text pp_token to the end of TOK_LIST containing
+ a borrowed copy of the text in CUR_OBSTACK. */
+
+static void
+push_back_any_text (pp_token_list *tok_list,
+ obstack *cur_obstack)
{
- if (!urlifier)
- return;
- if (!m_quotes)
- m_quotes = new quoting_info ();
- m_quotes->on_end_quote (pp, buf, chunk_idx, *urlifier);
+ obstack_1grow (cur_obstack, '\0');
+ tok_list->push_back_text
+ (label_text::borrow (XOBFINISH (cur_obstack,
+ const char *)));
}
/* The following format specifiers are recognized as being client independent:
@@ -1338,36 +1566,22 @@ chunk_info::on_end_quote (pretty_printer *pp,
/* Implementation of pp_format.
Formatting phases 1 and 2: render TEXT->format_spec plus
text->m_args_ptr into a series of chunks in pp_buffer (PP)->args[].
- Phase 3 is in pp_output_formatted_text.
-
- If URLIFIER is non-NULL, then use it to add URLs for quoted
- strings, so that e.g.
- "before %<quoted%> after"
- with a URLIFIER that has a URL for "quoted" might be emitted as:
- "before `BEGIN_URL(http://example.com)quotedEND_URL' after"
- This is handled here for message fragments that are:
- - quoted entirely in phase 1 (e.g. "%<this is quoted%>"), or
- - quoted entirely in phase 2 (e.g. "%qs"),
- Quoted fragments that use a mixture of both phases
- (e.g. "%<this is a mixture: %s %>")
- are stashed into the output_buffer's m_quotes for use in phase 3. */
+ Phase 3 is in pp_output_formatted_text. */
void
-pretty_printer::format (text_info *text,
- const urlifier *urlifier)
+pretty_printer::format (text_info *text)
{
output_buffer * const buffer = m_buffer;
unsigned int chunk = 0, argno;
- const char **formatters[PP_NL_ARGMAX];
+ pp_token_list **formatters[PP_NL_ARGMAX];
/* Allocate a new chunk structure. */
chunk_info *new_chunk_array = XOBNEW (&buffer->chunk_obstack, chunk_info);
new_chunk_array->m_prev = buffer->cur_chunk_array;
- new_chunk_array->m_quotes = nullptr;
buffer->cur_chunk_array = new_chunk_array;
- const char **args = new_chunk_array->m_args;
+ pp_token_list **args = new_chunk_array->m_args;
/* Formatting phase 1: split up TEXT->format_spec into chunks in
pp_buffer (PP)->args[]. Even-numbered chunks are to be output
@@ -1379,6 +1593,8 @@ pretty_printer::format (text_info *text,
unsigned int curarg = 0;
bool any_unnumbered = false, any_numbered = false;
+ pp_token_list *cur_token_list;
+ args[chunk++] = cur_token_list = pp_token_list::make (buffer->chunk_obstack);
for (const char *p = text->m_format_spec; *p; )
{
while (*p != '\0' && *p != '%')
@@ -1402,44 +1618,39 @@ pretty_printer::format (text_info *text,
case '<':
{
- obstack_grow (&buffer->chunk_obstack,
- open_quote, strlen (open_quote));
- const char *colorstr = colorize_start (m_show_color, "quote");
- obstack_grow (&buffer->chunk_obstack, colorstr, strlen (colorstr));
+ push_back_any_text (cur_token_list, &buffer->chunk_obstack);
+ cur_token_list->push_back<pp_token_begin_quote> ();
p++;
-
- buffer->cur_chunk_array->on_begin_quote (*buffer, chunk, urlifier);
continue;
}
case '>':
{
- buffer->cur_chunk_array->on_end_quote (this, *buffer, chunk, urlifier);
-
- const char *colorstr = colorize_stop (m_show_color);
- obstack_grow (&buffer->chunk_obstack, colorstr, strlen (colorstr));
+ push_back_any_text (cur_token_list, &buffer->chunk_obstack);
+ cur_token_list->push_back<pp_token_end_quote> ();
+ p++;
+ continue;
}
- /* FALLTHRU */
case '\'':
- obstack_grow (&buffer->chunk_obstack,
- close_quote, strlen (close_quote));
- p++;
+ {
+ push_back_any_text (cur_token_list, &buffer->chunk_obstack);
+ cur_token_list->push_back<pp_token_end_quote> ();
+ p++;
+ }
continue;
case '}':
{
- const char *endurlstr = get_end_url_string (this);
- obstack_grow (&buffer->chunk_obstack, endurlstr,
- strlen (endurlstr));
+ push_back_any_text (cur_token_list, &buffer->chunk_obstack);
+ cur_token_list->push_back<pp_token_end_url> ();
+ p++;
}
- p++;
continue;
case 'R':
{
- const char *colorstr = colorize_stop (m_show_color);
- obstack_grow (&buffer->chunk_obstack, colorstr,
- strlen (colorstr));
+ push_back_any_text (cur_token_list, &buffer->chunk_obstack);
+ cur_token_list->push_back<pp_token_end_color> ();
p++;
continue;
}
@@ -1454,11 +1665,14 @@ pretty_printer::format (text_info *text,
default:
/* Handled in phase 2. Terminate the plain chunk here. */
- obstack_1grow (&buffer->chunk_obstack, '\0');
- args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
+ push_back_any_text (cur_token_list, &buffer->chunk_obstack);
break;
}
+ /* Start a new token list for the formatting args. */
+ args[chunk] = cur_token_list
+ = pp_token_list::make (buffer->chunk_obstack);
+
if (ISDIGIT (*p))
{
char *end;
@@ -1478,7 +1692,7 @@ pretty_printer::format (text_info *text,
}
gcc_assert (argno < PP_NL_ARGMAX);
gcc_assert (!formatters[argno]);
- formatters[argno] = &args[chunk];
+ formatters[argno] = &args[chunk++];
do
{
obstack_1grow (&buffer->chunk_obstack, *p);
@@ -1530,17 +1744,24 @@ pretty_printer::format (text_info *text,
}
}
if (*p == '\0')
- break;
+ {
+ push_back_any_text (cur_token_list, &buffer->chunk_obstack);
+ break;
+ }
obstack_1grow (&buffer->chunk_obstack, '\0');
+ push_back_any_text (cur_token_list, &buffer->chunk_obstack);
+
+ /* Start a new token list for the next (non-formatted) text. */
gcc_assert (chunk < PP_NL_ARGMAX * 2);
- args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
+ args[chunk++] = cur_token_list
+ = pp_token_list::make (buffer->chunk_obstack);
}
obstack_1grow (&buffer->chunk_obstack, '\0');
+ push_back_any_text (cur_token_list, &buffer->chunk_obstack);
gcc_assert (chunk < PP_NL_ARGMAX * 2);
- args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
- args[chunk] = 0;
+ args[chunk] = nullptr;
/* Set output to the argument obstack, and switch line-wrapping and
prefixing off. */
@@ -1548,6 +1769,15 @@ pretty_printer::format (text_info *text,
const int old_line_length = buffer->line_length;
const pp_wrapping_mode_t old_wrapping_mode = pp_set_verbatim_wrapping (this);
+ /* Note that you can debug the state of the chunk arrays here using
+ (gdb) call buffer->cur_chunk_array->dump()
+ which, given e.g. "foo: %s bar: %s" might print:
+ 0: [TEXT("foo: ")]
+ 1: [TEXT("s")]
+ 2: [TEXT(" bar: ")]
+ 3: [TEXT("s")]
+ */
+
/* Second phase. Replace each formatter with the formatted text it
corresponds to. */
@@ -1561,10 +1791,20 @@ pretty_printer::format (text_info *text,
const char *p;
+ /* We expect a single text token containing the formatter. */
+ pp_token_list *tok_list = *(formatters[argno]);
+ gcc_assert (tok_list);
+ gcc_assert (tok_list->m_first == tok_list->m_end);
+ gcc_assert (tok_list->m_first->m_kind == pp_token::kind::text);
+
+ /* Accumulate the value of the formatted text into here. */
+ pp_token_list *formatted_tok_list
+ = pp_token_list::make (buffer->chunk_obstack);
+
/* We do not attempt to enforce any ordering on the modifier
characters. */
- for (p = *formatters[argno];; p++)
+ for (p = as_a <pp_token_text *> (tok_list->m_first)->m_value.get ();; p++)
{
switch (*p)
{
@@ -1611,16 +1851,18 @@ pretty_printer::format (text_info *text,
if (quote)
{
- pp_begin_quote (this, m_show_color);
- buffer->cur_chunk_array->on_begin_quote (*buffer, chunk, urlifier);
+ push_back_any_text (formatted_tok_list, &buffer->chunk_obstack);
+ formatted_tok_list->push_back<pp_token_begin_quote> ();
}
switch (*p)
{
case 'r':
- pp_string (this, colorize_start (m_show_color,
- va_arg (*text->m_args_ptr,
- const char *)));
+ {
+ const char *color = va_arg (*text->m_args_ptr, const char *);
+ formatted_tok_list->push_back<pp_token_begin_color>
+ (label_text::borrow (color));
+ }
break;
case 'c':
@@ -1752,17 +1994,16 @@ pretty_printer::format (text_info *text,
diagnostic_event_id_ptr event_id
= va_arg (*text->m_args_ptr, diagnostic_event_id_ptr);
gcc_assert (event_id->known_p ());
-
- pp_string (this, colorize_start (m_show_color, "path"));
- pp_character (this, '(');
- pp_decimal_int (this, event_id->one_based ());
- pp_character (this, ')');
- pp_string (this, colorize_stop (m_show_color));
+ formatted_tok_list->push_back<pp_token_event_id> (*event_id);
}
break;
case '{':
- begin_url (va_arg (*text->m_args_ptr, const char *));
+ {
+ const char *url = va_arg (*text->m_args_ptr, const char *);
+ formatted_tok_list->push_back<pp_token_begin_url>
+ (label_text::borrow (url));
+ }
break;
case 'e':
@@ -1771,7 +2012,7 @@ pretty_printer::format (text_info *text,
= va_arg (*text->m_args_ptr, pp_element *);
pp_markup::context ctxt (*this, *buffer, chunk,
quote, /* by reference */
- urlifier);
+ formatted_tok_list);
element->add_to_phase_2 (ctxt);
}
break;
@@ -1786,22 +2027,23 @@ pretty_printer::format (text_info *text,
(e.g. when printing "'TYPEDEF' aka 'TYPE'" in the C family
of frontends). */
gcc_assert (pp_format_decoder (this));
+ gcc_assert (formatted_tok_list);
ok = m_format_decoder (this, text, p,
precision, wide, plus, hash, &quote,
- formatters[argno]);
+ *formatted_tok_list);
gcc_assert (ok);
}
}
if (quote)
{
- buffer->cur_chunk_array->on_end_quote (this, *buffer,
- chunk, urlifier);
- pp_end_quote (this, m_show_color);
+ push_back_any_text (formatted_tok_list, &buffer->chunk_obstack);
+ formatted_tok_list->push_back<pp_token_end_quote> ();
}
- obstack_1grow (&buffer->chunk_obstack, '\0');
- *formatters[argno] = XOBFINISH (&buffer->chunk_obstack, const char *);
+ push_back_any_text (formatted_tok_list, &buffer->chunk_obstack);
+ delete *formatters[argno];
+ *formatters[argno] = formatted_tok_list;
}
if (CHECKING_P)
@@ -1832,6 +2074,8 @@ struct auto_obstack
obstack_free (&m_obstack, NULL);
}
+ operator obstack & () { return m_obstack; }
+
void grow (const void *src, size_t length)
{
obstack_grow (&m_obstack, src, length);
@@ -1850,130 +2094,117 @@ struct auto_obstack
obstack m_obstack;
};
-/* Subroutine of pp_output_formatted_text for the awkward case where
- quoted text straddles multiple chunks.
-
- Flush PP's buffer's chunks to PP's output buffer, whilst inserting
- URLs for any quoted text that should be URLified.
-
- For example, given:
- | pp_format (pp,
- | "unrecognized option %qs; did you mean %<-%s%>",
- | "foo", "foption");
- we would have these chunks:
- | chunk 0: "unrecognized option "
- | chunk 1: "`foo'" (already checked for urlification)
- | chunk 2: "; did you mean `-"
- | ^*
- | chunk 3: "foption"
- | *******
- | chunk 4: "'"
- | ^
- and this quoting_info would have recorded the open quote near the end
- of chunk 2 and close quote at the start of chunk 4; this function would
- check the combination of the end of chunk 2 and all of chunk 3 ("-foption")
- for urlification. */
+/* Format of a message pointed to by TEXT.
+ If URLIFIER is non-null then use it on any quoted text that was not
+ handled in phases 1 or 2 to potentially add URLs. */
void
-quoting_info::handle_phase_3 (pretty_printer *pp,
- const urlifier &urlifier)
+pp_output_formatted_text (pretty_printer *pp,
+ const urlifier *urlifier)
{
- unsigned int chunk;
output_buffer * const buffer = pp_buffer (pp);
+ gcc_assert (buffer->obstack == &buffer->formatted_obstack);
+
chunk_info *chunk_array = buffer->cur_chunk_array;
- const char * const *args = chunk_array->get_args ();
- quoting_info *quoting = chunk_array->get_quoting_info ();
-
- /* We need to construct the string into an intermediate buffer
- for this case, since using pp_string can introduce prefixes
- and line-wrapping, and omit whitespace at the start of lines. */
- auto_obstack combined_buf;
-
- /* Iterate simultaneously through both
- - the chunks and
- - the runs of quoted characters
- Accumulate text from the chunks into combined_buf, and handle
- runs of quoted characters when handling the chunks they
- correspond to. */
- size_t start_of_run_byte_offset = 0;
- std::vector<quoting_info::run>::const_iterator iter_run
- = quoting->m_phase_3_quotes.begin ();
- std::vector<quoting_info::run>::const_iterator end_runs
- = quoting->m_phase_3_quotes.end ();
- for (chunk = 0; args[chunk]; chunk++)
- {
- size_t start_of_chunk_idx = combined_buf.object_size ();
+ pp_token_list * const *token_lists = chunk_array->get_token_lists ();
- combined_buf.grow (args[chunk], strlen (args[chunk]));
+ {
+ /* Consolidate into one token list. */
+ pp_token_list tokens (buffer->chunk_obstack);
+ for (unsigned chunk = 0; token_lists[chunk]; chunk++)
+ {
+ tokens.push_back_list (std::move (*token_lists[chunk]));
+ delete token_lists[chunk];
+ }
- if (iter_run != end_runs
- && chunk == iter_run->m_end.m_chunk_idx)
- {
- /* A run is ending; consider for it urlification. */
- const size_t end_of_run_byte_offset
- = start_of_chunk_idx + iter_run->m_end.m_byte_offset;
- const size_t end_offset
- = urlify_quoted_string (pp,
- &combined_buf.m_obstack,
- &urlifier,
- start_of_run_byte_offset,
- end_of_run_byte_offset);
+ tokens.replace_custom_tokens ();
- /* If URLification occurred it will have grown the buffer.
- We need to update start_of_chunk_idx so that offsets
- relative to it are still correct, for the case where
- we have a chunk that both ends a quoted run and starts
- another quoted run. */
- gcc_assert (end_offset >= end_of_run_byte_offset);
- start_of_chunk_idx += end_offset - end_of_run_byte_offset;
+ tokens.merge_consecutive_text_tokens ();
- iter_run++;
- }
- if (iter_run != end_runs
- && chunk == iter_run->m_start.m_chunk_idx)
- {
- /* Note where the run starts w.r.t. the composed buffer. */
- start_of_run_byte_offset
- = start_of_chunk_idx + iter_run->m_start.m_byte_offset;
- }
- }
+ if (urlifier)
+ tokens.apply_urlifier (*urlifier);
- /* Now print to PP. */
- const char *start
- = static_cast <const char *> (combined_buf.object_base ());
- pp_maybe_wrap_text (pp, start, start + combined_buf.object_size ());
+ /* This is a third phase, first 2 phases done in pp_format_args.
+ Now we actually print it. */
+ if (pp->m_token_printer)
+ pp->m_token_printer->print_tokens (pp, tokens);
+ else
+ default_token_printer (pp, tokens);
+
+ /* Close the scope here to ensure that "tokens" above is fully cleared up
+ before popping the current chunk_info, since that latter will pop
+ the chunk_obstack, and "tokens" may be using blocks within
+ the current chunk_info's chunk_obstack level. */
+ }
+
+ chunk_array->pop_from_output_buffer (*buffer);
}
-/* Format of a message pointed to by TEXT.
- If URLIFIER is non-null then use it on any quoted text that was not
- handled in phases 1 or 2 to potentially add URLs. */
+/* Default implementation of token printing. */
-void
-pp_output_formatted_text (pretty_printer *pp,
- const urlifier *urlifier)
+static void
+default_token_printer (pretty_printer *pp,
+ const pp_token_list &tokens)
{
- unsigned int chunk;
- output_buffer * const buffer = pp_buffer (pp);
- chunk_info *chunk_array = buffer->cur_chunk_array;
- const char * const *args = chunk_array->get_args ();
- quoting_info *quoting = chunk_array->get_quoting_info ();
+ /* Convert to text, possibly with colorization, URLs, etc. */
+ for (auto iter = tokens.m_first; iter; iter = iter->m_next)
+ switch (iter->m_kind)
+ {
+ default:
+ gcc_unreachable ();
- gcc_assert (buffer->obstack == &buffer->formatted_obstack);
+ case pp_token::kind::text:
+ {
+ pp_token_text *sub = as_a <pp_token_text *> (iter);
+ pp_string (pp, sub->m_value.get ());
+ }
+ break;
- /* This is a third phase, first 2 phases done in pp_format_args.
- Now we actually print it. */
+ case pp_token::kind::begin_color:
+ {
+ pp_token_begin_color *sub = as_a <pp_token_begin_color *> (iter);
+ pp_string (pp, colorize_start (pp_show_color (pp),
+ sub->m_value.get ()));
+ }
+ break;
+ case pp_token::kind::end_color:
+ pp_string (pp, colorize_stop (pp_show_color (pp)));
+ break;
- /* If we have any deferred urlification, handle it now. */
- if (urlifier
- && pp->supports_urls_p ()
- && quoting
- && quoting->has_phase_3_quotes_p ())
- quoting->handle_phase_3 (pp, *urlifier);
- else
- for (chunk = 0; args[chunk]; chunk++)
- pp_string (pp, args[chunk]);
+ case pp_token::kind::begin_quote:
+ pp_begin_quote (pp, pp_show_color (pp));
+ break;
+ case pp_token::kind::end_quote:
+ pp_end_quote (pp, pp_show_color (pp));
+ break;
- chunk_array->pop_from_output_buffer (*buffer);
+ case pp_token::kind::begin_url:
+ {
+ pp_token_begin_url *sub = as_a <pp_token_begin_url *> (iter);
+ pp_begin_url (pp, sub->m_value.get ());
+ }
+ break;
+ case pp_token::kind::end_url:
+ pp_end_url (pp);
+ break;
+
+ case pp_token::kind::event_id:
+ {
+ pp_token_event_id *sub = as_a <pp_token_event_id *> (iter);
+ gcc_assert (sub->m_event_id.known_p ());
+ pp_string (pp, colorize_start (pp_show_color (pp), "path"));
+ pp_character (pp, '(');
+ pp_decimal_int (pp, sub->m_event_id.one_based ());
+ pp_character (pp, ')');
+ pp_string (pp, colorize_stop (pp_show_color (pp)));
+ }
+ break;
+
+ case pp_token::kind::custom_data:
+ /* These should have been eliminated by replace_custom_tokens. */
+ gcc_unreachable ();
+ break;
+ }
}
/* Helper subroutine of output_verbatim and verbatim. Do the appropriate
@@ -2112,6 +2343,7 @@ pretty_printer::pretty_printer (int maximum_length)
m_wrapping (),
m_format_decoder (nullptr),
m_format_postprocessor (NULL),
+ m_token_printer (nullptr),
m_emitted_prefix (false),
m_need_newline (false),
m_translate_identifiers (true),
@@ -2137,6 +2369,7 @@ pretty_printer::pretty_printer (const pretty_printer &other)
m_wrapping (other.m_wrapping),
m_format_decoder (other.m_format_decoder),
m_format_postprocessor (NULL),
+ m_token_printer (other.m_token_printer),
m_emitted_prefix (other.m_emitted_prefix),
m_need_newline (other.m_need_newline),
m_translate_identifiers (other.m_translate_identifiers),
@@ -2742,8 +2975,9 @@ void
pp_markup::context::begin_quote ()
{
gcc_assert (!m_quoted);
- pp_begin_quote (&m_pp, pp_show_color (&m_pp));
- m_buf.cur_chunk_array->on_begin_quote (m_buf, m_chunk_idx, m_urlifier);
+ gcc_assert (m_formatted_token_list);
+ push_back_any_text ();
+ m_formatted_token_list->push_back<pp_token_begin_quote> ();
m_quoted = true;
}
@@ -2754,8 +2988,9 @@ pp_markup::context::end_quote ()
printing a type emitting "TYPEDEF' {aka `TYPE'}". */
if (!m_quoted)
return;
- m_buf.cur_chunk_array->on_end_quote (&m_pp, m_buf, m_chunk_idx, m_urlifier);
- pp_end_quote (&m_pp, pp_show_color (&m_pp));
+ gcc_assert (m_formatted_token_list);
+ push_back_any_text ();
+ m_formatted_token_list->push_back<pp_token_end_quote> ();
m_quoted = false;
}
@@ -2764,7 +2999,10 @@ pp_markup::context::begin_highlight_color (const char *color_name)
{
if (!pp_show_highlight_colors (&m_pp))
return;
- pp_string (&m_pp, colorize_start (pp_show_color (&m_pp), color_name));
+
+ push_back_any_text ();
+ m_formatted_token_list->push_back <pp_token_begin_color>
+ (label_text::borrow (color_name));
}
void
@@ -2772,10 +3010,20 @@ pp_markup::context::end_highlight_color ()
{
if (!pp_show_highlight_colors (&m_pp))
return;
- const char *colorstr = colorize_stop (pp_show_color (&m_pp));
- obstack_grow (&m_buf.chunk_obstack, colorstr, strlen (colorstr));
+
+ push_back_any_text ();
+ m_formatted_token_list->push_back<pp_token_end_color> ();
}
+void
+pp_markup::context::push_back_any_text ()
+{
+ obstack *cur_obstack = m_buf.obstack;
+ obstack_1grow (cur_obstack, '\0');
+ m_formatted_token_list->push_back_text
+ (label_text::borrow (XOBFINISH (cur_obstack,
+ const char *)));
+}
/* Color names for expressing "expected" vs "actual" values. */
const char *const highlight_colors::expected = "highlight-a";
@@ -3038,6 +3286,245 @@ test_pp_format ()
1776, "second");
}
+static void
+test_merge_consecutive_text_tokens ()
+{
+ auto_obstack s;
+ pp_token_list list (s);
+ list.push_back_text (label_text::borrow ("hello"));
+ list.push_back_text (label_text::borrow (" "));
+ list.push_back_text (label_text::take (xstrdup ("world")));
+ list.push_back_text (label_text::borrow ("!"));
+
+ list.merge_consecutive_text_tokens ();
+ // We expect a single text token, with concatenated text
+ ASSERT_EQ (list.m_first, list.m_end);
+ pp_token *tok = list.m_first;
+ ASSERT_NE (tok, nullptr);
+ ASSERT_EQ (tok->m_kind, pp_token::kind::text);
+ ASSERT_STREQ (as_a <pp_token_text *> (tok)->m_value.get (), "hello world!");
+}
+
+/* Verify that we can create custom tokens that can be lowered
+ in phase 3. */
+
+static void
+test_custom_tokens_1 ()
+{
+ struct custom_token_adder : public pp_element
+ {
+ public:
+ struct value : public pp_token_custom_data::value
+ {
+ value (custom_token_adder &adder)
+ : m_adder (adder)
+ {
+ m_adder.m_num_living_values++;
+ }
+ value (const value &other)
+ : m_adder (other.m_adder)
+ {
+ m_adder.m_num_living_values++;
+ }
+ value (value &&other)
+ : m_adder (other.m_adder)
+ {
+ m_adder.m_num_living_values++;
+ }
+ value &operator= (const value &other) = delete;
+ value &operator= (value &&other) = delete;
+ ~value ()
+ {
+ m_adder.m_num_living_values--;
+ }
+
+ void dump (FILE *out) const final override
+ {
+ fprintf (out, "\"%s\"", m_adder.m_name);
+ }
+
+ bool as_standard_tokens (pp_token_list &out) final override
+ {
+ ASSERT_TRUE (m_adder.m_num_living_values > 0);
+ out.push_back<pp_token_text> (label_text::borrow (m_adder.m_name));
+ return true;
+ }
+
+ custom_token_adder &m_adder;
+ };
+
+ custom_token_adder (const char *name)
+ : m_name (name),
+ m_num_living_values (0)
+ {
+ }
+
+ void add_to_phase_2 (pp_markup::context &ctxt) final override
+ {
+ auto val_ptr = make_unique<value> (*this);
+ ctxt.m_formatted_token_list->push_back<pp_token_custom_data>
+ (std::move (val_ptr));
+ }
+
+ const char *m_name;
+ int m_num_living_values;
+ };
+
+ custom_token_adder e1 ("foo");
+ custom_token_adder e2 ("bar");
+ ASSERT_EQ (e1.m_num_living_values, 0);
+ ASSERT_EQ (e2.m_num_living_values, 0);
+
+ pretty_printer pp;
+ pp_printf (&pp, "before %e middle %e after", &e1, &e2);
+
+ /* Verify that instances were cleaned up. */
+ ASSERT_EQ (e1.m_num_living_values, 0);
+ ASSERT_EQ (e2.m_num_living_values, 0);
+
+ ASSERT_STREQ (pp_formatted_text (&pp),
+ "before foo middle bar after");
+}
+
+/* Verify that we can create custom tokens that aren't lowered
+ in phase 3, but instead are handled by a custom token_printer.
+ Use this to verify the inputs seen by such token_printers. */
+
+static void
+test_custom_tokens_2 ()
+{
+ struct custom_token_adder : public pp_element
+ {
+ struct value : public pp_token_custom_data::value
+ {
+ public:
+ value (custom_token_adder &adder)
+ : m_adder (adder)
+ {
+ m_adder.m_num_living_values++;
+ }
+ value (const value &other)
+ : m_adder (other.m_adder)
+ {
+ m_adder.m_num_living_values++;
+ }
+ value (value &&other)
+ : m_adder (other.m_adder)
+ {
+ m_adder.m_num_living_values++;
+ }
+ value &operator= (const value &other) = delete;
+ value &operator= (value &&other) = delete;
+ ~value ()
+ {
+ m_adder.m_num_living_values--;
+ }
+
+ void dump (FILE *out) const final override
+ {
+ fprintf (out, "\"%s\"", m_adder.m_name);
+ }
+
+ bool as_standard_tokens (pp_token_list &) final override
+ {
+ return false;
+ }
+
+ custom_token_adder &m_adder;
+ };
+
+ custom_token_adder (const char *name)
+ : m_name (name),
+ m_num_living_values (0)
+ {
+ }
+
+ void add_to_phase_2 (pp_markup::context &ctxt) final override
+ {
+ auto val_ptr = make_unique<value> (*this);
+ ctxt.m_formatted_token_list->push_back<pp_token_custom_data>
+ (std::move (val_ptr));
+ }
+
+ const char *m_name;
+ int m_num_living_values;
+ };
+
+ class custom_token_printer : public token_printer
+ {
+ void print_tokens (pretty_printer *pp,
+ const pp_token_list &tokens) final override
+ {
+ /* Verify that TOKENS has:
+ [TEXT("before "), CUSTOM("foo"), TEXT(" middle "), CUSTOM("bar"),
+ TEXT(" after")] */
+ pp_token *tok_0 = tokens.m_first;
+ ASSERT_NE (tok_0, nullptr);
+ ASSERT_EQ (tok_0->m_kind, pp_token::kind::text);
+ ASSERT_STREQ (as_a<pp_token_text *> (tok_0)->m_value.get (),
+ "before ");
+
+ pp_token *tok_1 = tok_0->m_next;
+ ASSERT_NE (tok_1, nullptr);
+ ASSERT_EQ (tok_1->m_prev, tok_0);
+ ASSERT_EQ (tok_1->m_kind, pp_token::kind::custom_data);
+
+ custom_token_adder::value *v1
+ = static_cast <custom_token_adder::value *>
+ (as_a<pp_token_custom_data *> (tok_1)->m_value.get ());
+ ASSERT_STREQ (v1->m_adder.m_name, "foo");
+ ASSERT_TRUE (v1->m_adder.m_num_living_values > 0);
+
+ pp_token *tok_2 = tok_1->m_next;
+ ASSERT_NE (tok_2, nullptr);
+ ASSERT_EQ (tok_2->m_prev, tok_1);
+ ASSERT_EQ (tok_2->m_kind, pp_token::kind::text);
+ ASSERT_STREQ (as_a<pp_token_text *> (tok_2)->m_value.get (),
+ " middle ");
+
+ pp_token *tok_3 = tok_2->m_next;
+ ASSERT_NE (tok_3, nullptr);
+ ASSERT_EQ (tok_3->m_prev, tok_2);
+ ASSERT_EQ (tok_3->m_kind, pp_token::kind::custom_data);
+ custom_token_adder::value *v3
+ = static_cast <custom_token_adder::value *>
+ (as_a<pp_token_custom_data *> (tok_3)->m_value.get ());
+ ASSERT_STREQ (v3->m_adder.m_name, "bar");
+ ASSERT_TRUE (v3->m_adder.m_num_living_values > 0);
+
+ pp_token *tok_4 = tok_3->m_next;
+ ASSERT_NE (tok_4, nullptr);
+ ASSERT_EQ (tok_4->m_prev, tok_3);
+ ASSERT_EQ (tok_4->m_kind, pp_token::kind::text);
+ ASSERT_STREQ (as_a<pp_token_text *> (tok_4)->m_value.get (),
+ " after");
+ ASSERT_EQ (tok_4->m_next, nullptr);
+
+ /* Normally we'd loop over the tokens, printing them to PP
+ and handling the custom tokens.
+ Instead, print a message to PP to verify that we were called. */
+ pp_string (pp, "print_tokens was called");
+ }
+ };
+
+ custom_token_adder e1 ("foo");
+ custom_token_adder e2 ("bar");
+ ASSERT_EQ (e1.m_num_living_values, 0);
+ ASSERT_EQ (e2.m_num_living_values, 0);
+
+ custom_token_printer tp;
+ pretty_printer pp;
+ pp.set_token_printer (&tp);
+ pp_printf (&pp, "before %e middle %e after", &e1, &e2);
+
+ /* Verify that instances were cleaned up. */
+ ASSERT_EQ (e1.m_num_living_values, 0);
+ ASSERT_EQ (e2.m_num_living_values, 0);
+
+ ASSERT_STREQ (pp_formatted_text (&pp),
+ "print_tokens was called");
+}
+
/* A subclass of pretty_printer for use by test_prefixes_and_wrapping. */
class test_pretty_printer : public pretty_printer
@@ -3247,7 +3734,7 @@ pp_printf_with_urlifier (pretty_printer *pp,
va_start (ap, msg);
text_info text (msg, &ap, errno);
- pp_format (pp, &text, urlifier);
+ pp_format (pp, &text);
pp_output_formatted_text (pp, urlifier);
va_end (ap);
}
@@ -3403,6 +3890,18 @@ test_urlification ()
("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar",
pp_formatted_text (&pp));
}
+
+ /* Test the example from pretty-print-format-impl.h. */
+ {
+ pretty_printer pp;
+ pp.set_url_format (URL_FORMAT_ST);
+ pp_printf_with_urlifier (&pp, &urlifier,
+ "foo: %i, bar: %s, option: %qs",
+ 42, "baz", "-foption");
+ ASSERT_STREQ (pp_formatted_text (&pp),
+ "foo: 42, bar: baz, option:"
+ " `]8;;http://example.com\\-foption]8;;\\'");
+ }
}
/* Test multibyte awareness. */
@@ -3452,6 +3951,9 @@ pretty_print_cc_tests ()
{
test_basic_printing ();
test_pp_format ();
+ test_merge_consecutive_text_tokens ();
+ test_custom_tokens_1 ();
+ test_custom_tokens_2 ();
test_prefixes_and_wrapping ();
test_urls ();
test_urls_from_braces ();
diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h
index d28814a..e0505b2 100644
--- a/gcc/pretty-print.h
+++ b/gcc/pretty-print.h
@@ -69,58 +69,15 @@ enum diagnostic_prefixing_rule_t
DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE = 0x2
};
-class quoting_info;
+class chunk_info;
class output_buffer;
+class pp_token_list;
class urlifier;
namespace pp_markup {
class context;
} // namespace pp_markup
-/* The chunk_info data structure forms a stack of the results from the
- first phase of formatting (pp_format) which have not yet been
- output (pp_output_formatted_text). A stack is necessary because
- the diagnostic starter may decide to generate its own output by way
- of the formatter. */
-class chunk_info
-{
- friend class pretty_printer;
- friend class pp_markup::context;
-
-public:
- const char * const *get_args () const { return m_args; }
- quoting_info *get_quoting_info () const { return m_quotes; }
-
- void append_formatted_chunk (const char *content);
-
- void pop_from_output_buffer (output_buffer &buf);
-
-private:
- void on_begin_quote (const output_buffer &buf,
- unsigned chunk_idx,
- const urlifier *urlifier);
-
- void on_end_quote (pretty_printer *pp,
- output_buffer &buf,
- unsigned chunk_idx,
- const urlifier *urlifier);
-
- /* Pointer to previous chunk on the stack. */
- chunk_info *m_prev;
-
- /* Array of chunks to output. Each chunk is a NUL-terminated string.
- In the first phase of formatting, even-numbered chunks are
- to be output verbatim, odd-numbered chunks are format specifiers.
- The second phase replaces all odd-numbered chunks with formatted
- text, and the third phase simply emits all the chunks in sequence
- with appropriate line-wrapping. */
- const char *m_args[PP_NL_ARGMAX * 2];
-
- /* If non-null, information on quoted text runs within the chunks
- for use by a urlifier. */
- quoting_info *m_quotes;
-};
-
/* The output buffer datatype. This is best seen as an abstract datatype
whose fields should not be accessed directly by clients. */
class output_buffer
@@ -220,7 +177,7 @@ struct pp_wrapping_mode_t
A client-supplied formatter returns true if everything goes well,
otherwise it returns false. */
typedef bool (*printer_fn) (pretty_printer *, text_info *, const char *,
- int, bool, bool, bool, bool *, const char **);
+ int, bool, bool, bool, bool *, pp_token_list &);
/* Base class for an optional client-supplied object for doing additional
processing between stages 2 and 3 of formatted printing. */
@@ -232,6 +189,18 @@ class format_postprocessor
virtual void handle (pretty_printer *) = 0;
};
+/* Abstract base class for writing formatted tokens to the pretty_printer's
+ text buffer, allowing for output formats and dumpfiles to override
+ how different kinds of tokens are handled. */
+
+class token_printer
+{
+public:
+ virtual ~token_printer () {}
+ virtual void print_tokens (pretty_printer *pp,
+ const pp_token_list &tokens) = 0;
+};
+
inline bool & pp_needs_newline (pretty_printer *pp);
/* True if PRETTY-PRINTER is in line-wrapping mode. */
@@ -279,6 +248,9 @@ public:
friend format_postprocessor *& pp_format_postprocessor (pretty_printer *pp);
friend bool & pp_show_highlight_colors (pretty_printer *pp);
+ friend void pp_output_formatted_text (pretty_printer *,
+ const urlifier *);
+
/* Default construct a pretty printer with specified
maximum line length cut off limit. */
explicit pretty_printer (int = 0);
@@ -293,12 +265,16 @@ public:
m_buffer->stream = outfile;
}
+ void set_token_printer (token_printer* tp)
+ {
+ m_token_printer = tp; // borrowed
+ }
+
void set_prefix (char *prefix);
void emit_prefix ();
- void format (text_info *text,
- const urlifier *urlifier);
+ void format (text_info *text);
void maybe_space ();
@@ -357,8 +333,9 @@ private:
If the BUFFER needs additional characters from the format string, it
should advance the TEXT->format_spec as it goes. When FORMAT_DECODER
returns, TEXT->format_spec should point to the last character processed.
- The QUOTE and BUFFER_PTR are passed in, to allow for deferring-handling
- of format codes (e.g. %H and %I in the C++ frontend). */
+ The QUOTE and FORMATTED_TOKEN_LIST are passed in, to allow for
+ deferring-handling of format codes (e.g. %H and %I in
+ the C++ frontend). */
printer_fn m_format_decoder;
/* If non-NULL, this is called by pp_format once after all format codes
@@ -367,6 +344,12 @@ private:
format codes (which interract with each other). */
format_postprocessor *m_format_postprocessor;
+ /* This is used by pp_output_formatted_text after it has converted all
+ formatted chunks into a single list of tokens.
+ Can be nullptr.
+ Borrowed from the output format or from dump_pretty_printer. */
+ token_printer *m_token_printer;
+
/* Nonzero if current PREFIX was emitted at least once. */
bool m_emitted_prefix;
@@ -586,10 +569,9 @@ extern void pp_verbatim (pretty_printer *, const char *, ...)
ATTRIBUTE_GCC_PPDIAG(2,3);
extern void pp_flush (pretty_printer *);
extern void pp_really_flush (pretty_printer *);
-inline void pp_format (pretty_printer *pp, text_info *text,
- const urlifier *urlifier = nullptr)
+inline void pp_format (pretty_printer *pp, text_info *text)
{
- pp->format (text, urlifier);
+ pp->format (text);
}
extern void pp_output_formatted_text (pretty_printer *,
const urlifier * = nullptr);
diff --git a/gcc/sese.cc b/gcc/sese.cc
index e5c4605..e9b17fa 100644
--- a/gcc/sese.cc
+++ b/gcc/sese.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index 793932a..dc040df 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -47,6 +47,7 @@ along with GCC; see the file COPYING3. If not see
comment can thus be removed at that point. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "target.h"
diff --git a/gcc/testsuite/gcc.dg/plugin/dump_plugin.c b/gcc/testsuite/gcc.dg/plugin/dump_plugin.c
index 12573d6..fc76d69 100644
--- a/gcc/testsuite/gcc.dg/plugin/dump_plugin.c
+++ b/gcc/testsuite/gcc.dg/plugin/dump_plugin.c
@@ -1,5 +1,6 @@
/* Plugin for testing dumpfile.c. */
+#define INCLUDE_MEMORY
#include "gcc-plugin.h"
#include "config.h"
#include "system.h"
diff --git a/gcc/testsuite/gcc.dg/sarif-output/bad-pragma.c b/gcc/testsuite/gcc.dg/sarif-output/bad-pragma.c
new file mode 100644
index 0000000..db274de
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/sarif-output/bad-pragma.c
@@ -0,0 +1,16 @@
+/* Verify that SARIF output can capture URLs in diagnostics
+ related to a bad pragma. */
+
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-format=sarif-file -Wpragmas" } */
+
+#pragma GCC diagnostic ignored "-Wmisleading-indenttion"
+
+int nonempty;
+
+/* Verify that some JSON was written to a file with the expected name:
+ { dg-final { verify-sarif-file } } */
+
+/* Use a Python script to verify various properties about the generated
+ .sarif file:
+ { dg-final { run-sarif-pytest bad-pragma.c "test-bad-pragma.py" } } */
diff --git a/gcc/testsuite/gcc.dg/sarif-output/test-bad-pragma.py b/gcc/testsuite/gcc.dg/sarif-output/test-bad-pragma.py
new file mode 100644
index 0000000..140bb33
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/sarif-output/test-bad-pragma.py
@@ -0,0 +1,38 @@
+from sarif import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def sarif():
+ return sarif_from_env()
+
+def test_messages_have_embedded_urls(sarif):
+ runs = sarif['runs']
+ run = runs[0]
+ results = run['results']
+
+ # We expect a single warning with a secondary location.
+ #
+ # The textual form of the diagnostic would look like this:
+ # . PATH/bad-pragma.c:7:32: warning: unknown option after '#pragma GCC diagnostic' kind [-Wpragmas]
+ # . 7 | #pragma GCC diagnostic ignored "-Wmisleading-indenttion"
+ # . | ^~~~~~~~~~~~~~~~~~~~~~~~~
+ # . PATH/bad-pragma.c:7:32: note: did you mean '-Wmisleading-indentation'?
+ assert len(results) == 1
+
+ result = results[0]
+ assert result['ruleId'] == '-Wpragmas'
+ assert result['level'] == 'warning'
+ assert result['message']['text'] \
+ == "unknown option after '[#pragma GCC diagnostic](https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html)' kind"
+ # Note how we expect an embedded link in the above for the docs for #pragma GCC diagnostic
+
+ # We expect one related location, for the note.
+ relatedLocations = result['relatedLocations']
+ assert len(relatedLocations) == 1
+
+ rel_loc = relatedLocations[0]
+ assert rel_loc['message']['text'] \
+ == "did you mean '[-Wmisleading-indentation](https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wmisleading-indentation)'?"
+ # Again, we expect an embedded link in the above, this time to the
+ # docs for the suggested option
diff --git a/gcc/testsuite/gcc.dg/sarif-output/test-include-chain-2.py b/gcc/testsuite/gcc.dg/sarif-output/test-include-chain-2.py
index 761fe1b..843f89a 100644
--- a/gcc/testsuite/gcc.dg/sarif-output/test-include-chain-2.py
+++ b/gcc/testsuite/gcc.dg/sarif-output/test-include-chain-2.py
@@ -96,9 +96,11 @@ def test_location_relationships(sarif):
== " __builtin_free (ptr); // 1st\n"
assert threadFlow['locations'][0]['kinds'] == ['release', 'memory']
assert threadFlow['locations'][0]['executionOrder'] == 1
-
+
+ # We should have an embedded link in this event's message to the
+ # other event's location within the SARIF file:
assert threadFlow['locations'][1]['location']['message']['text'] \
- == "second 'free' here; first 'free' was at (1)"
+ == "second 'free' here; first 'free' was at [(1)](sarif:/runs/0/results/0/codeFlows/0/threadFlows/0/locations/0)"
assert threadFlow['locations'][1]['location']['physicalLocation']['contextRegion']['snippet']['text'] \
== " __builtin_free (ptr); // 2nd\n"
assert threadFlow['locations'][1]['kinds'] == ['danger']
diff --git a/gcc/testsuite/gfortran.dg/use_rename_12.f90 b/gcc/testsuite/gfortran.dg/use_rename_12.f90
new file mode 100644
index 0000000..0447d5f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/use_rename_12.f90
@@ -0,0 +1,27 @@
+! { dg-do compile }
+! PR fortran/116530 - ICE with member of namelist renamed by use module
+!
+! Reported by philippe.wautelet at cnrs.fr
+
+module mod_nml1
+ implicit none
+ logical :: ldiag
+ namelist /nam_nml1/ldiag
+end module mod_nml1
+
+module mod_interm
+ use mod_nml1
+end module mod_interm
+
+program ice_nml
+ use mod_nml1, ldiag_nml1 => ldiag
+ use mod_nml1, only : ldiag_only => ldiag
+ use mod_interm
+ implicit none
+ integer :: ilu = 10
+ read(unit=ilu,nml=nam_nml1)
+ write(unit=*,nml=nam_nml1)
+ print *, ldiag
+ print *, ldiag_nml1
+ print *, ldiag_only
+end program ice_nml
diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc
index bd61069..48798f4 100644
--- a/gcc/tree-data-ref.cc
+++ b/gcc/tree-data-ref.cc
@@ -74,6 +74,7 @@ along with GCC; see the file COPYING3. If not see
*/
#define INCLUDE_ALGORITHM
+#define INCLUDE_MEMORY
#include "config.h"
#include "system.h"
#include "coretypes.h"
diff --git a/gcc/tree-diagnostic.cc b/gcc/tree-diagnostic.cc
index fc78231..466725f 100644
--- a/gcc/tree-diagnostic.cc
+++ b/gcc/tree-diagnostic.cc
@@ -55,7 +55,7 @@ default_tree_diagnostic_starter (diagnostic_context *context,
bool
default_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
int precision, bool wide, bool set_locus, bool hash,
- bool *, const char **)
+ bool *, pp_token_list &)
{
tree t;
diff --git a/gcc/tree-diagnostic.h b/gcc/tree-diagnostic.h
index 6ebac38..98ca654 100644
--- a/gcc/tree-diagnostic.h
+++ b/gcc/tree-diagnostic.h
@@ -53,6 +53,6 @@ void diagnostic_report_current_function (diagnostic_context *,
void tree_diagnostics_defaults (diagnostic_context *context);
bool default_tree_printer (pretty_printer *, text_info *, const char *,
- int, bool, bool, bool, bool *, const char **);
+ int, bool, bool, bool, bool *, pp_token_list &);
#endif /* ! GCC_TREE_DIAGNOSTIC_H */
diff --git a/gcc/tree-if-conv.cc b/gcc/tree-if-conv.cc
index 735e477..0346a13 100644
--- a/gcc/tree-if-conv.cc
+++ b/gcc/tree-if-conv.cc
@@ -81,6 +81,7 @@ along with GCC; see the file COPYING3. If not see
*/
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-loop-distribution.cc b/gcc/tree-loop-distribution.cc
index 10f261a..f0430ed 100644
--- a/gcc/tree-loop-distribution.cc
+++ b/gcc/tree-loop-distribution.cc
@@ -90,6 +90,7 @@ along with GCC; see the file COPYING3. If not see
data reuse. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-parloops.cc b/gcc/tree-parloops.cc
index 888a834f..f446865 100644
--- a/gcc/tree-parloops.cc
+++ b/gcc/tree-parloops.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-predcom.cc b/gcc/tree-predcom.cc
index 9844fee..eed878b 100644
--- a/gcc/tree-predcom.cc
+++ b/gcc/tree-predcom.cc
@@ -205,6 +205,7 @@ along with GCC; see the file COPYING3. If not see
i * i with ii_last + 2 * i + 1), to generalize strength reduction. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-ssa-live.cc b/gcc/tree-ssa-live.cc
index 60dfc05..0739faa 100644
--- a/gcc/tree-ssa-live.cc
+++ b/gcc/tree-ssa-live.cc
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-ssa-loop-ivcanon.cc b/gcc/tree-ssa-loop-ivcanon.cc
index 5ef24a9..a8d25ad 100644
--- a/gcc/tree-ssa-loop-ivcanon.cc
+++ b/gcc/tree-ssa-loop-ivcanon.cc
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see
info). */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-ssa-loop-ivopts.cc b/gcc/tree-ssa-loop-ivopts.cc
index c3218a3..dfe1b254 100644
--- a/gcc/tree-ssa-loop-ivopts.cc
+++ b/gcc/tree-ssa-loop-ivopts.cc
@@ -90,6 +90,7 @@ along with GCC; see the file COPYING3. If not see
profitable. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-ssa-loop-prefetch.cc b/gcc/tree-ssa-loop-prefetch.cc
index bb5d5de..52ea3ba 100644
--- a/gcc/tree-ssa-loop-prefetch.cc
+++ b/gcc/tree-ssa-loop-prefetch.cc
@@ -18,6 +18,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-ssa-loop-unswitch.cc b/gcc/tree-ssa-loop-unswitch.cc
index 14b0df1..7601d91 100644
--- a/gcc/tree-ssa-loop-unswitch.cc
+++ b/gcc/tree-ssa-loop-unswitch.cc
@@ -18,6 +18,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
index 95bac33..9a009e1 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -18,6 +18,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-ssa-threadbackward.cc b/gcc/tree-ssa-threadbackward.cc
index ea8d7b8..4bc72ec 100644
--- a/gcc/tree-ssa-threadbackward.cc
+++ b/gcc/tree-ssa-threadbackward.cc
@@ -18,6 +18,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-ssa-threadupdate.cc b/gcc/tree-ssa-threadupdate.cc
index fa61ba9..c88cc1d 100644
--- a/gcc/tree-ssa-threadupdate.cc
+++ b/gcc/tree-ssa-threadupdate.cc
@@ -18,6 +18,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc
index 5b0d548..fe7fdec 100644
--- a/gcc/tree-vect-data-refs.cc
+++ b/gcc/tree-vect-data-refs.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-vect-generic.cc b/gcc/tree-vect-generic.cc
index 4bcab71..3041fb8 100644
--- a/gcc/tree-vect-generic.cc
+++ b/gcc/tree-vect-generic.cc
@@ -18,6 +18,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc
index 57dbcbe..cb7843f 100644
--- a/gcc/tree-vect-loop-manip.cc
+++ b/gcc/tree-vect-loop-manip.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
index 6456220..1fb7bbd 100644
--- a/gcc/tree-vect-loop.cc
+++ b/gcc/tree-vect-loop.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define INCLUDE_ALGORITHM
+#define INCLUDE_MEMORY
#include "config.h"
#include "system.h"
#include "coretypes.h"
diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc
index 9158af9..3162250 100644
--- a/gcc/tree-vect-patterns.cc
+++ b/gcc/tree-vect-patterns.cc
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-vect-slp-patterns.cc b/gcc/tree-vect-slp-patterns.cc
index 4a582ec..8adae8a 100644
--- a/gcc/tree-vect-slp-patterns.cc
+++ b/gcc/tree-vect-slp-patterns.cc
@@ -18,6 +18,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
index fe49811..cfdf59a 100644
--- a/gcc/tree-vect-slp.cc
+++ b/gcc/tree-vect-slp.cc
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
#include "config.h"
#define INCLUDE_ALGORITHM
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
index 9eb73a5..03c65f0 100644
--- a/gcc/tree-vect-stmts.cc
+++ b/gcc/tree-vect-stmts.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"
diff --git a/gcc/tree-vectorizer.cc b/gcc/tree-vectorizer.cc
index 1fb4fb3..0efabcb 100644
--- a/gcc/tree-vectorizer.cc
+++ b/gcc/tree-vectorizer.cc
@@ -55,6 +55,7 @@ along with GCC; see the file COPYING3. If not see
*/
#include "config.h"
+#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "backend.h"