@@ -18,19 +18,19 @@ void int_arr_write_element_after_end_off_by_one(int32_t x)
arr[10] = x;
~~~~~~~~^~~
event 1 (depth 0)
- |
- | int32_t arr[10];
- | ^~~
- | |
- | (1) capacity: 40 bytes
- |
- +--> 'int_arr_write_element_after_end_off_by_one': event 2 (depth 1)
- |
- | arr[10] = x;
- | ~~~~~~~~^~~
- | |
- | (2) ⚠️ out-of-bounds write from byte 40 till byte 43 but 'arr' ends at byte 40
- |
+ │
+ │ int32_t arr[10];
+ │ ^~~
+ │ |
+ │ (1) capacity: 40 bytes
+ │
+ └──> 'int_arr_write_element_after_end_off_by_one': event 2 (depth 1)
+ │
+ │ arr[10] = x;
+ │ ~~~~~~~~^~~
+ │ |
+ │ (2) ⚠️ out-of-bounds write from byte 40 till byte 43 but 'arr' ends at byte 40
+ │
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
@@ -18,19 +18,19 @@ void int_arr_write_element_after_end_off_by_one(int32_t x)
arr[10] = x;
~~~~~~~~^~~
event 1 (depth 0)
- |
- | int32_t arr[10];
- | ^~~
- | |
- | (1) capacity: 40 bytes
- |
- +--> 'int_arr_write_element_after_end_off_by_one': event 2 (depth 1)
- |
- | arr[10] = x;
- | ~~~~~~~~^~~
- | |
- | (2) out-of-bounds write from byte 40 till byte 43 but 'arr' ends at byte 40
- |
+ │
+ │ int32_t arr[10];
+ │ ^~~
+ │ |
+ │ (1) capacity: 40 bytes
+ │
+ └──> 'int_arr_write_element_after_end_off_by_one': event 2 (depth 1)
+ │
+ │ arr[10] = x;
+ │ ~~~~~~~~^~~
+ │ |
+ │ (2) out-of-bounds write from byte 40 till byte 43 but 'arr' ends at byte 40
+ │
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
@@ -125,6 +125,21 @@ ascii_theme::get_cppchar (enum cell_kind kind) const
case cell_kind::Y_ARROW_UP_TAIL:
case cell_kind::Y_ARROW_DOWN_TAIL:
return '|';
+
+ case cell_kind::INTERPROCEDURAL_PUSH_FRAME_LEFT:
+ return '+';
+ case cell_kind::INTERPROCEDURAL_PUSH_FRAME_MIDDLE:
+ return '-';
+ case cell_kind::INTERPROCEDURAL_PUSH_FRAME_RIGHT:
+ return '>';
+ case cell_kind::INTERPROCEDURAL_DEPTH_MARKER:
+ return '|';
+ case cell_kind::INTERPROCEDURAL_POP_FRAMES_LEFT:
+ return '<';
+ case cell_kind::INTERPROCEDURAL_POP_FRAMES_MIDDLE:
+ return '-';
+ case cell_kind::INTERPROCEDURAL_POP_FRAMES_RIGHT:
+ return '+';
}
}
@@ -180,5 +195,20 @@ unicode_theme::get_cppchar (enum cell_kind kind) const
case cell_kind::Y_ARROW_UP_TAIL:
case cell_kind::Y_ARROW_DOWN_TAIL:
return 0x2502; /* "│": U+2502: BOX DRAWINGS LIGHT VERTICAL */
+
+ case cell_kind::INTERPROCEDURAL_PUSH_FRAME_LEFT:
+ return 0x2514; /* "└": U+2514: BOX DRAWINGS LIGHT UP AND RIGHT */
+ case cell_kind::INTERPROCEDURAL_PUSH_FRAME_MIDDLE:
+ return 0x2500; /* "─": U+2500: BOX DRAWINGS LIGHT HORIZONTAL */
+ case cell_kind::INTERPROCEDURAL_PUSH_FRAME_RIGHT:
+ return '>';
+ case cell_kind::INTERPROCEDURAL_DEPTH_MARKER:
+ return 0x2502; /* "│": U+2502: BOX DRAWINGS LIGHT VERTICAL */
+ case cell_kind::INTERPROCEDURAL_POP_FRAMES_LEFT:
+ return '<';
+ case cell_kind::INTERPROCEDURAL_POP_FRAMES_MIDDLE:
+ return 0x2500; /* "─": U+2500: BOX DRAWINGS LIGHT HORIZONTAL */
+ case cell_kind::INTERPROCEDURAL_POP_FRAMES_RIGHT:
+ return 0x2518; /* "┘": U+2518: BOX DRAWINGS LIGHT UP AND LEFT. */
}
}
@@ -63,6 +63,16 @@ class theme
Y_ARROW_UP_TAIL,
Y_ARROW_DOWN_HEAD,
Y_ARROW_DOWN_TAIL,
+
+ /* The interprocedural depth indications shown in execution paths
+ with DPF_INLINE_EVENTS. */
+ INTERPROCEDURAL_PUSH_FRAME_LEFT, /* e.g. "+". */
+ INTERPROCEDURAL_PUSH_FRAME_MIDDLE, /* e.g. "-". */
+ INTERPROCEDURAL_PUSH_FRAME_RIGHT, /* e.g. ">". */
+ INTERPROCEDURAL_DEPTH_MARKER, /* e.g. "|". */
+ INTERPROCEDURAL_POP_FRAMES_LEFT, /* e.g. "<". */
+ INTERPROCEDURAL_POP_FRAMES_MIDDLE, /* e.g. "-". */
+ INTERPROCEDURAL_POP_FRAMES_RIGHT /* e.g. "+". */
};
virtual ~theme () = default;
@@ -437,6 +437,15 @@ public:
= colorize_start (pp_show_color (pp), line_color);
const char *end_line_color = colorize_stop (pp_show_color (pp));
+ text_art::ascii_theme fallback_theme;
+ text_art::theme *theme = dc->get_diagram_theme ();
+ if (!theme)
+ theme = &fallback_theme;
+
+ cppchar_t depth_marker_char = theme->get_cppchar
+ (text_art::theme::cell_kind::INTERPROCEDURAL_DEPTH_MARKER);
+ /* e.g. "|". */
+
const bool interprocedural_p = m_per_thread_summary.interprocedural_p ();
write_indent (pp, m_cur_indent);
@@ -446,11 +455,21 @@ public:
{
gcc_assert (interprocedural_p);
/* Show pushed stack frame(s). */
- const char *push_prefix = "+--> ";
+ cppchar_t left = theme->get_cppchar
+ (text_art::theme::cell_kind::INTERPROCEDURAL_PUSH_FRAME_LEFT);
+ cppchar_t middle = theme->get_cppchar
+ (text_art::theme::cell_kind::INTERPROCEDURAL_PUSH_FRAME_MIDDLE);
+ cppchar_t right = theme->get_cppchar
+ (text_art::theme::cell_kind::INTERPROCEDURAL_PUSH_FRAME_RIGHT);
+ /* e.g. "+--> ". */
pp_string (pp, start_line_color);
- pp_string (pp, push_prefix);
+ pp_unicode_character (pp, left);
+ pp_unicode_character (pp, middle);
+ pp_unicode_character (pp, middle);
+ pp_unicode_character (pp, right);
+ pp_space (pp);
pp_string (pp, end_line_color);
- m_cur_indent += strlen (push_prefix);
+ m_cur_indent += 5;
}
}
if (range->m_fndecl)
@@ -473,7 +492,7 @@ public:
{
write_indent (pp, m_cur_indent + per_frame_indent);
pp_string (pp, start_line_color);
- pp_string (pp, "|");
+ pp_unicode_character (pp, depth_marker_char);
pp_string (pp, end_line_color);
pp_newline (pp);
@@ -483,7 +502,7 @@ public:
pretty_printer tmp_pp;
write_indent (&tmp_pp, m_cur_indent + per_frame_indent);
pp_string (&tmp_pp, start_line_color);
- pp_string (&tmp_pp, "|");
+ pp_unicode_character (&tmp_pp, depth_marker_char);
pp_string (&tmp_pp, end_line_color);
prefix = xstrdup (pp_formatted_text (&tmp_pp));
}
@@ -494,7 +513,7 @@ public:
write_indent (pp, m_cur_indent + per_frame_indent);
pp_string (pp, start_line_color);
- pp_string (pp, "|");
+ pp_unicode_character (pp, depth_marker_char);
pp_string (pp, end_line_color);
pp_newline (pp);
}
@@ -510,9 +529,15 @@ public:
/* Show returning from stack frame(s), by printing
something like:
" |\n"
- " <------------ +\n"
+ " <-------------+\n"
" |\n". */
gcc_assert (interprocedural_p);
+ cppchar_t left = theme->get_cppchar
+ (text_art::theme::cell_kind::INTERPROCEDURAL_POP_FRAMES_LEFT);
+ cppchar_t middle = theme->get_cppchar
+ (text_art::theme::cell_kind::INTERPROCEDURAL_POP_FRAMES_MIDDLE);
+ cppchar_t right = theme->get_cppchar
+ (text_art::theme::cell_kind::INTERPROCEDURAL_POP_FRAMES_RIGHT);
int vbar_for_next_frame
= *m_vbar_column_for_depth.get (next_range->m_stack_depth);
@@ -520,18 +545,18 @@ public:
= vbar_for_next_frame - per_frame_indent;
write_indent (pp, vbar_for_next_frame);
pp_string (pp, start_line_color);
- pp_character (pp, '<');
+ pp_unicode_character (pp, left);
for (int i = indent_for_next_frame + per_frame_indent;
i < m_cur_indent + per_frame_indent - 1; i++)
- pp_character (pp, '-');
- pp_character (pp, '+');
+ pp_unicode_character (pp, middle);
+ pp_unicode_character (pp, right);
pp_string (pp, end_line_color);
pp_newline (pp);
m_cur_indent = indent_for_next_frame;
write_indent (pp, vbar_for_next_frame);
pp_string (pp, start_line_color);
- pp_character (pp, '|');
+ pp_unicode_character (pp, depth_marker_char);
pp_string (pp, end_line_color);
pp_newline (pp);
}
@@ -864,59 +889,119 @@ test_interprocedural_path_1 (pretty_printer *event_pp)
path_summary summary (path, false);
ASSERT_EQ (summary.get_num_ranges (), 9);
- test_diagnostic_context dc;
- print_path_summary_as_text (&summary, &dc, true);
- ASSERT_STREQ
- (" `test': events 1-2 (depth 0)\n"
- " |\n"
- " | (1): entering `test'\n"
- " | (2): calling `make_boxed_int'\n"
- " |\n"
- " +--> `make_boxed_int': events 3-4 (depth 1)\n"
- " |\n"
- " | (3): entering `make_boxed_int'\n"
- " | (4): calling `wrapped_malloc'\n"
- " |\n"
- " +--> `wrapped_malloc': events 5-6 (depth 2)\n"
- " |\n"
- " | (5): entering `wrapped_malloc'\n"
- " | (6): calling malloc\n"
- " |\n"
- " <-------------+\n"
- " |\n"
- " `test': events 7-8 (depth 0)\n"
- " |\n"
- " | (7): returning to `test'\n"
- " | (8): calling `free_boxed_int'\n"
- " |\n"
- " +--> `free_boxed_int': events 9-10 (depth 1)\n"
- " |\n"
- " | (9): entering `free_boxed_int'\n"
- " | (10): calling `wrapped_free'\n"
- " |\n"
- " +--> `wrapped_free': events 11-12 (depth 2)\n"
- " |\n"
- " | (11): entering `wrapped_free'\n"
- " | (12): calling free\n"
- " |\n"
- " <-------------+\n"
- " |\n"
- " `test': events 13-14 (depth 0)\n"
- " |\n"
- " | (13): returning to `test'\n"
- " | (14): calling `free_boxed_int'\n"
- " |\n"
- " +--> `free_boxed_int': events 15-16 (depth 1)\n"
- " |\n"
- " | (15): entering `free_boxed_int'\n"
- " | (16): calling `wrapped_free'\n"
- " |\n"
- " +--> `wrapped_free': events 17-18 (depth 2)\n"
- " |\n"
- " | (17): entering `wrapped_free'\n"
- " | (18): calling free\n"
- " |\n",
- pp_formatted_text (dc.printer));
+ {
+ test_diagnostic_context dc;
+ dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_ASCII);
+ print_path_summary_as_text (&summary, &dc, true);
+ ASSERT_STREQ
+ (" `test': events 1-2 (depth 0)\n"
+ " |\n"
+ " | (1): entering `test'\n"
+ " | (2): calling `make_boxed_int'\n"
+ " |\n"
+ " +--> `make_boxed_int': events 3-4 (depth 1)\n"
+ " |\n"
+ " | (3): entering `make_boxed_int'\n"
+ " | (4): calling `wrapped_malloc'\n"
+ " |\n"
+ " +--> `wrapped_malloc': events 5-6 (depth 2)\n"
+ " |\n"
+ " | (5): entering `wrapped_malloc'\n"
+ " | (6): calling malloc\n"
+ " |\n"
+ " <-------------+\n"
+ " |\n"
+ " `test': events 7-8 (depth 0)\n"
+ " |\n"
+ " | (7): returning to `test'\n"
+ " | (8): calling `free_boxed_int'\n"
+ " |\n"
+ " +--> `free_boxed_int': events 9-10 (depth 1)\n"
+ " |\n"
+ " | (9): entering `free_boxed_int'\n"
+ " | (10): calling `wrapped_free'\n"
+ " |\n"
+ " +--> `wrapped_free': events 11-12 (depth 2)\n"
+ " |\n"
+ " | (11): entering `wrapped_free'\n"
+ " | (12): calling free\n"
+ " |\n"
+ " <-------------+\n"
+ " |\n"
+ " `test': events 13-14 (depth 0)\n"
+ " |\n"
+ " | (13): returning to `test'\n"
+ " | (14): calling `free_boxed_int'\n"
+ " |\n"
+ " +--> `free_boxed_int': events 15-16 (depth 1)\n"
+ " |\n"
+ " | (15): entering `free_boxed_int'\n"
+ " | (16): calling `wrapped_free'\n"
+ " |\n"
+ " +--> `wrapped_free': events 17-18 (depth 2)\n"
+ " |\n"
+ " | (17): entering `wrapped_free'\n"
+ " | (18): calling free\n"
+ " |\n",
+ pp_formatted_text (dc.printer));
+ }
+ {
+ test_diagnostic_context dc;
+ dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_UNICODE);
+ print_path_summary_as_text (&summary, &dc, true);
+ ASSERT_STREQ
+ (" `test': events 1-2 (depth 0)\n"
+ " │\n"
+ " │ (1): entering `test'\n"
+ " │ (2): calling `make_boxed_int'\n"
+ " │\n"
+ " └──> `make_boxed_int': events 3-4 (depth 1)\n"
+ " │\n"
+ " │ (3): entering `make_boxed_int'\n"
+ " │ (4): calling `wrapped_malloc'\n"
+ " │\n"
+ " └──> `wrapped_malloc': events 5-6 (depth 2)\n"
+ " │\n"
+ " │ (5): entering `wrapped_malloc'\n"
+ " │ (6): calling malloc\n"
+ " │\n"
+ " <─────────────┘\n"
+ " │\n"
+ " `test': events 7-8 (depth 0)\n"
+ " │\n"
+ " │ (7): returning to `test'\n"
+ " │ (8): calling `free_boxed_int'\n"
+ " │\n"
+ " └──> `free_boxed_int': events 9-10 (depth 1)\n"
+ " │\n"
+ " │ (9): entering `free_boxed_int'\n"
+ " │ (10): calling `wrapped_free'\n"
+ " │\n"
+ " └──> `wrapped_free': events 11-12 (depth 2)\n"
+ " │\n"
+ " │ (11): entering `wrapped_free'\n"
+ " │ (12): calling free\n"
+ " │\n"
+ " <─────────────┘\n"
+ " │\n"
+ " `test': events 13-14 (depth 0)\n"
+ " │\n"
+ " │ (13): returning to `test'\n"
+ " │ (14): calling `free_boxed_int'\n"
+ " │\n"
+ " └──> `free_boxed_int': events 15-16 (depth 1)\n"
+ " │\n"
+ " │ (15): entering `free_boxed_int'\n"
+ " │ (16): calling `wrapped_free'\n"
+ " │\n"
+ " └──> `wrapped_free': events 17-18 (depth 2)\n"
+ " │\n"
+ " │ (17): entering `wrapped_free'\n"
+ " │ (18): calling free\n"
+ " │\n",
+ pp_formatted_text (dc.printer));
+ }
+
}
/* Example where we pop the stack to an intermediate frame, rather than the
@@ -946,35 +1031,70 @@ test_interprocedural_path_2 (pretty_printer *event_pp)
path_summary summary (path, false);
ASSERT_EQ (summary.get_num_ranges (), 5);
- test_diagnostic_context dc;
- print_path_summary_as_text (&summary, &dc, true);
- ASSERT_STREQ
- (" `foo': events 1-2 (depth 0)\n"
- " |\n"
- " | (1): entering `foo'\n"
- " | (2): calling `bar'\n"
- " |\n"
- " +--> `bar': events 3-4 (depth 1)\n"
- " |\n"
- " | (3): entering `bar'\n"
- " | (4): calling `baz'\n"
- " |\n"
- " +--> `baz': event 5 (depth 2)\n"
- " |\n"
- " | (5): entering `baz'\n"
- " |\n"
- " <------+\n"
- " |\n"
- " `bar': events 6-7 (depth 1)\n"
- " |\n"
- " | (6): returning to `bar'\n"
- " | (7): calling `baz'\n"
- " |\n"
- " +--> `baz': event 8 (depth 2)\n"
- " |\n"
- " | (8): entering `baz'\n"
- " |\n",
- pp_formatted_text (dc.printer));
+ {
+ test_diagnostic_context dc;
+ dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_ASCII);
+ print_path_summary_as_text (&summary, &dc, true);
+ ASSERT_STREQ
+ (" `foo': events 1-2 (depth 0)\n"
+ " |\n"
+ " | (1): entering `foo'\n"
+ " | (2): calling `bar'\n"
+ " |\n"
+ " +--> `bar': events 3-4 (depth 1)\n"
+ " |\n"
+ " | (3): entering `bar'\n"
+ " | (4): calling `baz'\n"
+ " |\n"
+ " +--> `baz': event 5 (depth 2)\n"
+ " |\n"
+ " | (5): entering `baz'\n"
+ " |\n"
+ " <------+\n"
+ " |\n"
+ " `bar': events 6-7 (depth 1)\n"
+ " |\n"
+ " | (6): returning to `bar'\n"
+ " | (7): calling `baz'\n"
+ " |\n"
+ " +--> `baz': event 8 (depth 2)\n"
+ " |\n"
+ " | (8): entering `baz'\n"
+ " |\n",
+ pp_formatted_text (dc.printer));
+ }
+ {
+ test_diagnostic_context dc;
+ dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_UNICODE);
+ print_path_summary_as_text (&summary, &dc, true);
+ ASSERT_STREQ
+ (" `foo': events 1-2 (depth 0)\n"
+ " │\n"
+ " │ (1): entering `foo'\n"
+ " │ (2): calling `bar'\n"
+ " │\n"
+ " └──> `bar': events 3-4 (depth 1)\n"
+ " │\n"
+ " │ (3): entering `bar'\n"
+ " │ (4): calling `baz'\n"
+ " │\n"
+ " └──> `baz': event 5 (depth 2)\n"
+ " │\n"
+ " │ (5): entering `baz'\n"
+ " │\n"
+ " <──────┘\n"
+ " │\n"
+ " `bar': events 6-7 (depth 1)\n"
+ " │\n"
+ " │ (6): returning to `bar'\n"
+ " │ (7): calling `baz'\n"
+ " │\n"
+ " └──> `baz': event 8 (depth 2)\n"
+ " │\n"
+ " │ (8): entering `baz'\n"
+ " │\n",
+ pp_formatted_text (dc.printer));
+ }
}
/* Verify that print_path_summary is sane in the face of a recursive
@@ -998,29 +1118,58 @@ test_recursion (pretty_printer *event_pp)
path_summary summary (path, false);
ASSERT_EQ (summary.get_num_ranges (), 4);
- test_diagnostic_context dc;
- print_path_summary_as_text (&summary, &dc, true);
- ASSERT_STREQ
- (" `factorial': events 1-2 (depth 0)\n"
- " |\n"
- " | (1): entering `factorial'\n"
- " | (2): calling `factorial'\n"
- " |\n"
- " +--> `factorial': events 3-4 (depth 1)\n"
- " |\n"
- " | (3): entering `factorial'\n"
- " | (4): calling `factorial'\n"
- " |\n"
- " +--> `factorial': events 5-6 (depth 2)\n"
- " |\n"
- " | (5): entering `factorial'\n"
- " | (6): calling `factorial'\n"
- " |\n"
- " +--> `factorial': event 7 (depth 3)\n"
- " |\n"
- " | (7): entering `factorial'\n"
- " |\n",
- pp_formatted_text (dc.printer));
+ {
+ test_diagnostic_context dc;
+ dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_ASCII);
+ print_path_summary_as_text (&summary, &dc, true);
+ ASSERT_STREQ
+ (" `factorial': events 1-2 (depth 0)\n"
+ " |\n"
+ " | (1): entering `factorial'\n"
+ " | (2): calling `factorial'\n"
+ " |\n"
+ " +--> `factorial': events 3-4 (depth 1)\n"
+ " |\n"
+ " | (3): entering `factorial'\n"
+ " | (4): calling `factorial'\n"
+ " |\n"
+ " +--> `factorial': events 5-6 (depth 2)\n"
+ " |\n"
+ " | (5): entering `factorial'\n"
+ " | (6): calling `factorial'\n"
+ " |\n"
+ " +--> `factorial': event 7 (depth 3)\n"
+ " |\n"
+ " | (7): entering `factorial'\n"
+ " |\n",
+ pp_formatted_text (dc.printer));
+ }
+ {
+ test_diagnostic_context dc;
+ dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_UNICODE);
+ print_path_summary_as_text (&summary, &dc, true);
+ ASSERT_STREQ
+ (" `factorial': events 1-2 (depth 0)\n"
+ " │\n"
+ " │ (1): entering `factorial'\n"
+ " │ (2): calling `factorial'\n"
+ " │\n"
+ " └──> `factorial': events 3-4 (depth 1)\n"
+ " │\n"
+ " │ (3): entering `factorial'\n"
+ " │ (4): calling `factorial'\n"
+ " │\n"
+ " └──> `factorial': events 5-6 (depth 2)\n"
+ " │\n"
+ " │ (5): entering `factorial'\n"
+ " │ (6): calling `factorial'\n"
+ " │\n"
+ " └──> `factorial': event 7 (depth 3)\n"
+ " │\n"
+ " │ (7): entering `factorial'\n"
+ " │\n",
+ pp_formatted_text (dc.printer));
+ }
}
/* Run all of the selftests within this file. */
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Successful run of analyzer integration tests on x86_64-pc-linux-gnu. Pushed to trunk as r15-535-ge656656e711949. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/out-of-bounds-diagram-1-emoji.c: Update expected output to use unicode for depth indication. * gcc.dg/analyzer/out-of-bounds-diagram-1-unicode.c: Likewise. gcc/ChangeLog: * text-art/theme.cc (ascii_theme::get_cppchar): Add cell_kind::INTERPROCEDURAL_*. (unicode_theme::get_cppchar): Likewise. * text-art/theme.h (theme::cell_kind): Likewise. * tree-diagnostic-path.cc: (thread_event_printer::print_swimlane_for_event_range): Use the above to get characters for indicating interprocedural stack depth activity, falling back to ascii. (selftest::test_interprocedural_path_1): Test with both ascii and unicode themes. (selftest::test_interprocedural_path_2): Likewise. (selftest::test_recursion): Likewise. Signed-off-by: David Malcolm <dmalcolm@redhat.com> --- .../analyzer/out-of-bounds-diagram-1-emoji.c | 26 +- .../out-of-bounds-diagram-1-unicode.c | 26 +- gcc/text-art/theme.cc | 30 ++ gcc/text-art/theme.h | 10 + gcc/tree-diagnostic-path.cc | 381 ++++++++++++------ 5 files changed, 331 insertions(+), 142 deletions(-)