From 369ba4e626584bfc24a991bac234ac30227e61ae Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 22 Mar 2019 09:17:45 -0400
Subject: [PATCH 136/217] FIXME: add -fdiagnostics-path-summary-format=; add
 inline event format

---
 gcc/common.opt                                     |  21 +-
 gcc/diagnostic-show-locus.c                        |   2 +
 gcc/diagnostic.c                                   |   2 +-
 gcc/diagnostic.h                                   |  18 +-
 gcc/opts.c                                         |   4 +-
 gcc/testsuite/gcc.dg/analyzer/analyzer.exp         |   2 +-
 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c       |   2 +-
 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-8.c       |   2 +-
 .../diagnostic-path-summary-format-default.c       | 140 +++++++++
 ...iagnostic-path-summary-format-event-summaries.c |  74 +++++
 .../diagnostic-path-summary-format-inline-events.c | 140 +++++++++
 .../plugin/diagnostic-path-summary-format-none.c   |  43 +++
 .../plugin/diagnostic-path-summary-format-simple.c |  66 +++++
 .../gcc.dg/plugin/diagnostic-test-paths-4.c        |  74 -----
 .../gcc.dg/plugin/diagnostic-test-paths-5.c        |  76 -----
 gcc/testsuite/gcc.dg/plugin/plugin.exp             |   7 +-
 gcc/toplev.c                                       |   4 +-
 gcc/tree-diagnostic.c                              | 314 +++++++++++++++------
 18 files changed, 740 insertions(+), 251 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-default.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-event-summaries.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-inline-events.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-none.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-simple.c
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-5.c

diff --git a/gcc/common.opt b/gcc/common.opt
index 99218d0..de97853 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1325,9 +1325,24 @@ fdiagnostics-show-metadata
 Common Var(flag_diagnostics_show_metadata) Init(1)
 FIXME; TODO: add to docs
 
-fdiagnostics-show-path-summary
-Common Var(flag_diagnostics_show_path_summary) Init(1)
-Show summary of interprocedural paths. (TODO: add to docs)
+fdiagnostics-path-summary-format=
+Common Joined RejectNegative Var(flag_diagnostics_path_summary_format) Enum(diagnostic_path_summary_format) Init(DPSF_INLINE_EVENTS)
+FIXME; TODO: docs
+
+Enum
+Name(diagnostic_path_summary_format) Type(int)
+
+EnumValue
+Enum(diagnostic_path_summary_format) String(none) Value(DPSF_NONE)
+
+EnumValue
+Enum(diagnostic_path_summary_format) String(simple) Value(DPSF_SIMPLE)
+
+EnumValue
+Enum(diagnostic_path_summary_format) String(event-summaries) Value(DPSF_EVENT_SUMMARIES)
+
+EnumValue
+Enum(diagnostic_path_summary_format) String(inline-events) Value(DPSF_INLINE_EVENTS)
 
 fdiagnostics-show-path-depths
 Common Var(flag_diagnostics_show_path_depths) Init(0)
diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index e49740d..bd7f3af 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -1031,6 +1031,8 @@ layout::print_gap_in_line_numbering ()
 {
   gcc_assert (m_show_line_numbers_p);
 
+  pp_emit_prefix (m_pp);
+
   for (int i = 0; i < m_linenum_width + 1; i++)
     pp_character (m_pp, '.');
 
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 51330b1..10511f8 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -179,7 +179,7 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
   for (i = 0; i < rich_location::STATICALLY_ALLOCATED_RANGES; i++)
     context->caret_chars[i] = '^';
   context->show_metadata = false;
-  context->show_path_summary = false;
+  context->path_summary_format = DPSF_NONE;
   context->show_path_depths = false;
   context->show_option_requested = false;
   context->abort_on_error = false;
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index ba9dfb2..2951177 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -35,6 +35,22 @@ enum diagnostics_output_format
   DIAGNOSTICS_OUTPUT_FORMAT_JSON
 };
 
+/* FIXME.  */
+enum diagnostic_path_summary_format
+{
+  /* FIXME.  */
+  DPSF_NONE,
+
+  /* FIXME.  */
+  DPSF_SIMPLE,
+
+  /* FIXME.  */
+  DPSF_EVENT_SUMMARIES,
+
+  /* FIXME.  */
+  DPSF_INLINE_EVENTS
+};
+
 /* A diagnostic is described by the MESSAGE to send, the FILE and LINE of
    its context and its KIND (ice, error, warning, note, ...)  See complete
    list in diagnostic.def.  */
@@ -134,7 +150,7 @@ struct diagnostic_context
   bool show_metadata;
 
   /* FIXME.  */
-  bool show_path_summary;
+  enum diagnostic_path_summary_format path_summary_format;
 
   /* FIXME.  */
   bool show_path_depths;
diff --git a/gcc/opts.c b/gcc/opts.c
index ef14677..cb962e4 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2404,8 +2404,8 @@ common_handle_option (struct gcc_options *opts,
       dc->show_metadata = value;
       break;
 
-    case OPT_fdiagnostics_show_path_summary:
-      dc->show_path_summary = value;
+    case OPT_fdiagnostics_path_summary_format_:
+      dc->path_summary_format = (enum diagnostic_path_summary_format)value;
       break;
 
     case OPT_fdiagnostics_show_path_depths:
diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer.exp b/gcc/testsuite/gcc.dg/analyzer/analyzer.exp
index 9679256..4680d32 100644
--- a/gcc/testsuite/gcc.dg/analyzer/analyzer.exp
+++ b/gcc/testsuite/gcc.dg/analyzer/analyzer.exp
@@ -22,7 +22,7 @@ load_lib gcc-dg.exp
 # If a testcase doesn't have special options, use these.
 global DEFAULT_CFLAGS
 if ![info exists DEFAULT_CFLAGS] then {
-    set DEFAULT_CFLAGS " --analyzer -fno-diagnostics-show-path-summary"
+    set DEFAULT_CFLAGS " --analyzer -fdiagnostics-path-summary-format=none"
 }
 
 # Initialize `dg'.
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c
index a167534..55b77d2 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c
@@ -1,4 +1,4 @@
-/* { dg-options "--analyzer -fno-diagnostics-show-path-summary -fanalyzer-verbosity=1" } */
+/* { dg-options "--analyzer -fdiagnostics-path-summary-format=none -fanalyzer-verbosity=1" } */
 
 #include <stdlib.h>
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-8.c b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-8.c
index 0d82941..9f99287 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-8.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-8.c
@@ -1,6 +1,6 @@
 /* Example of a multilevel wrapper around malloc/free, with a double-free.  */
 
-/* { dg-options "--analyzer -fno-diagnostics-show-path-summary -fdump-analyzer-summaries -fanalyzer-checker=malloc" } */
+/* { dg-options "--analyzer -fdiagnostics-path-summary-format=none -fdump-analyzer-summaries -fanalyzer-checker=malloc" } */
 
 #include <stdlib.h>
 
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-default.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-default.c
new file mode 100644
index 0000000..d68f856
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-default.c
@@ -0,0 +1,140 @@
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+#include <stdlib.h>
+
+void *wrapped_malloc (size_t size)
+{
+  return malloc (size);
+}
+
+void wrapped_free (void *ptr)
+{
+  free (ptr); /* { dg-warning "double-free of 'ptr' \\\[CWE-415\\]" } */
+  /* { dg-begin-multiline-output "" }
+  'test': events 1-2
+     |
+     | {
+     | ^
+     | |
+     | (1) entering 'test'
+     |   boxed_int *obj = make_boxed_int (i);
+     |                    ~~~~~~~~~~~~~~~~~~
+     |                    |
+     |                    (2) calling 'make_boxed_int'
+     |
+     +--> 'make_boxed_int': events 3-4
+                  |
+                  | {
+                  | ^
+                  | |
+                  | (3) entering 'make_boxed_int'
+                  |   boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int));
+                  |                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                  |                                    |
+                  |                                    (4) calling 'wrapped_malloc'
+                  |
+                  +--> 'wrapped_malloc': events 5-6
+                               |
+                               | {
+                               | ^
+                               | |
+                               | (5) entering 'wrapped_malloc'
+                               |   return malloc (size);
+                               |          ~~~~~~~~~~~~~
+                               |          |
+                               |          (6) calling 'malloc'
+                               |
+     <-------------------------+
+     |
+  'test': event 7
+     |
+     |   free_boxed_int (obj);
+     |   ^~~~~~~~~~~~~~~~~~~~
+     |   |
+     |   (7) calling 'free_boxed_int'
+     |
+     +--> 'free_boxed_int': events 8-9
+                  |
+                  | {
+                  | ^
+                  | |
+                  | (8) entering 'free_boxed_int'
+                  |   wrapped_free (bi);
+                  |   ~~~~~~~~~~~~~~~~~
+                  |   |
+                  |   (9) calling 'wrapped_free'
+                  |
+                  +--> 'wrapped_free': events 10-11
+                              |
+                              | {
+                              | ^
+                              | |
+                              | (10) entering 'wrapped_free'
+                              |   free (ptr);
+                              |   ~~~~~~~~~~
+                              |   |
+                              |   (11) calling 'free'
+                              |
+     <------------------------+
+     |
+  'test': event 12
+     |
+     |   free_boxed_int (obj);
+     |   ^~~~~~~~~~~~~~~~~~~~
+     |   |
+     |   (12) calling 'free_boxed_int'
+     |
+     +--> 'free_boxed_int': events 13-14
+                  |
+                  | {
+                  | ^
+                  | |
+                  | (13) entering 'free_boxed_int'
+                  |   wrapped_free (bi);
+                  |   ~~~~~~~~~~~~~~~~~
+                  |   |
+                  |   (14) calling 'wrapped_free'
+                  |
+                  +--> 'wrapped_free': events 15-16
+                              |
+                              | {
+                              | ^
+                              | |
+                              | (15) entering 'wrapped_free'
+                              |   free (ptr);
+                              |   ~~~~~~~~~~
+                              |   |
+                              |   (16) calling 'free'
+                              |
+     { dg-end-multiline-output "" } */
+}
+
+typedef struct boxed_int
+{
+  int i;
+} boxed_int;
+
+boxed_int *
+make_boxed_int (int i)
+{
+  boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int));
+  result->i = i;
+  return result;
+}
+
+void
+free_boxed_int (boxed_int *bi)
+{
+  wrapped_free (bi);
+}
+
+void test (int i)
+{
+  boxed_int *obj = make_boxed_int (i);
+
+  free_boxed_int (obj);
+
+  free_boxed_int (obj);
+}
+
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-event-summaries.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-event-summaries.c
new file mode 100644
index 0000000..903c405
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-event-summaries.c
@@ -0,0 +1,74 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-path-summary-format=event-summaries" } */
+
+#include <stdlib.h>
+
+void *wrapped_malloc (size_t size)
+{
+  return malloc (size);
+}
+
+void wrapped_free (void *ptr)
+{
+  free (ptr); /* { dg-warning "double-free of 'ptr' \\\[CWE-415\\]" } */
+  /* { dg-begin-multiline-output "" }
+  'test': events 1-2
+     | (1): entering 'test'
+     | (2): calling 'make_boxed_int'
+     +--> 'make_boxed_int': events 3-4
+                  | (3): entering 'make_boxed_int'
+                  | (4): calling 'wrapped_malloc'
+                  +--> 'wrapped_malloc': events 5-6
+                               | (5): entering 'wrapped_malloc'
+                               | (6): calling 'malloc'
+     <-------------------------+
+     |
+  'test': event 7
+     | (7): calling 'free_boxed_int'
+     +--> 'free_boxed_int': events 8-9
+                  | (8): entering 'free_boxed_int'
+                  | (9): calling 'wrapped_free'
+                  +--> 'wrapped_free': events 10-11
+                              | (10): entering 'wrapped_free'
+                              | (11): calling 'free'
+     <------------------------+
+     |
+  'test': event 12
+     | (12): calling 'free_boxed_int'
+     +--> 'free_boxed_int': events 13-14
+                  | (13): entering 'free_boxed_int'
+                  | (14): calling 'wrapped_free'
+                  +--> 'wrapped_free': events 15-16
+                              | (15): entering 'wrapped_free'
+                              | (16): calling 'free'
+     { dg-end-multiline-output "" } */
+}
+
+typedef struct boxed_int
+{
+  int i;
+} boxed_int;
+
+boxed_int *
+make_boxed_int (int i)
+{
+  boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int));
+  result->i = i;
+  return result;
+}
+
+void
+free_boxed_int (boxed_int *bi)
+{
+  wrapped_free (bi);
+}
+
+void test (int i)
+{
+  boxed_int *obj = make_boxed_int (i);
+
+  free_boxed_int (obj);
+
+  free_boxed_int (obj);
+}
+
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-inline-events.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-inline-events.c
new file mode 100644
index 0000000..c111e11
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-inline-events.c
@@ -0,0 +1,140 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-path-summary-format=inline-events" } */
+
+#include <stdlib.h>
+
+void *wrapped_malloc (size_t size)
+{
+  return malloc (size);
+}
+
+void wrapped_free (void *ptr)
+{
+  free (ptr); /* { dg-warning "double-free of 'ptr' \\\[CWE-415\\]" } */
+  /* { dg-begin-multiline-output "" }
+  'test': events 1-2
+     |
+     | {
+     | ^
+     | |
+     | (1) entering 'test'
+     |   boxed_int *obj = make_boxed_int (i);
+     |                    ~~~~~~~~~~~~~~~~~~
+     |                    |
+     |                    (2) calling 'make_boxed_int'
+     |
+     +--> 'make_boxed_int': events 3-4
+                  |
+                  | {
+                  | ^
+                  | |
+                  | (3) entering 'make_boxed_int'
+                  |   boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int));
+                  |                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                  |                                    |
+                  |                                    (4) calling 'wrapped_malloc'
+                  |
+                  +--> 'wrapped_malloc': events 5-6
+                               |
+                               | {
+                               | ^
+                               | |
+                               | (5) entering 'wrapped_malloc'
+                               |   return malloc (size);
+                               |          ~~~~~~~~~~~~~
+                               |          |
+                               |          (6) calling 'malloc'
+                               |
+     <-------------------------+
+     |
+  'test': event 7
+     |
+     |   free_boxed_int (obj);
+     |   ^~~~~~~~~~~~~~~~~~~~
+     |   |
+     |   (7) calling 'free_boxed_int'
+     |
+     +--> 'free_boxed_int': events 8-9
+                  |
+                  | {
+                  | ^
+                  | |
+                  | (8) entering 'free_boxed_int'
+                  |   wrapped_free (bi);
+                  |   ~~~~~~~~~~~~~~~~~
+                  |   |
+                  |   (9) calling 'wrapped_free'
+                  |
+                  +--> 'wrapped_free': events 10-11
+                              |
+                              | {
+                              | ^
+                              | |
+                              | (10) entering 'wrapped_free'
+                              |   free (ptr);
+                              |   ~~~~~~~~~~
+                              |   |
+                              |   (11) calling 'free'
+                              |
+     <------------------------+
+     |
+  'test': event 12
+     |
+     |   free_boxed_int (obj);
+     |   ^~~~~~~~~~~~~~~~~~~~
+     |   |
+     |   (12) calling 'free_boxed_int'
+     |
+     +--> 'free_boxed_int': events 13-14
+                  |
+                  | {
+                  | ^
+                  | |
+                  | (13) entering 'free_boxed_int'
+                  |   wrapped_free (bi);
+                  |   ~~~~~~~~~~~~~~~~~
+                  |   |
+                  |   (14) calling 'wrapped_free'
+                  |
+                  +--> 'wrapped_free': events 15-16
+                              |
+                              | {
+                              | ^
+                              | |
+                              | (15) entering 'wrapped_free'
+                              |   free (ptr);
+                              |   ~~~~~~~~~~
+                              |   |
+                              |   (16) calling 'free'
+                              |
+     { dg-end-multiline-output "" } */
+}
+
+typedef struct boxed_int
+{
+  int i;
+} boxed_int;
+
+boxed_int *
+make_boxed_int (int i)
+{
+  boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int));
+  result->i = i;
+  return result;
+}
+
+void
+free_boxed_int (boxed_int *bi)
+{
+  wrapped_free (bi);
+}
+
+void test (int i)
+{
+  boxed_int *obj = make_boxed_int (i);
+
+  free_boxed_int (obj);
+
+  free_boxed_int (obj);
+}
+
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-none.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-none.c
new file mode 100644
index 0000000..2efdd74
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-none.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-path-summary-format=none" } */
+
+#include <stdlib.h>
+
+void *wrapped_malloc (size_t size)
+{
+  return malloc (size);
+}
+
+void wrapped_free (void *ptr)
+{
+  free (ptr); /* { dg-warning "double-free of 'ptr' \\\[CWE-415\\]" } */
+}
+
+typedef struct boxed_int
+{
+  int i;
+} boxed_int;
+
+boxed_int *
+make_boxed_int (int i)
+{
+  boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int));
+  result->i = i;
+  return result;
+}
+
+void
+free_boxed_int (boxed_int *bi)
+{
+  wrapped_free (bi);
+}
+
+void test (int i)
+{
+  boxed_int *obj = make_boxed_int (i);
+
+  free_boxed_int (obj);
+
+  free_boxed_int (obj);
+}
+
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-simple.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-simple.c
new file mode 100644
index 0000000..097eb55
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-path-summary-format-simple.c
@@ -0,0 +1,66 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-show-path-depths -fdiagnostics-path-summary-format=simple" } */
+
+#include <stdlib.h>
+
+void *wrapped_malloc (size_t size)
+{
+  return malloc (size);
+}
+
+void wrapped_free (void *ptr)
+{
+  free (ptr); /* { dg-warning "double-free of 'ptr' \\\[CWE-415\\]" } */
+  /* { dg-begin-multiline-output "" }
+  'test': events 1-2 (depth 0)
+     |
+     +--> 'make_boxed_int': events 3-4 (depth 1)
+                  |
+                  +--> 'wrapped_malloc': events 5-6 (depth 2)
+                               |
+     <-------------------------+
+     |
+  'test': event 7 (depth 0)
+     |
+     +--> 'free_boxed_int': events 8-9 (depth 1)
+                  |
+                  +--> 'wrapped_free': events 10-11 (depth 2)
+                              |
+     <------------------------+
+     |
+  'test': event 12 (depth 0)
+     |
+     +--> 'free_boxed_int': events 13-14 (depth 1)
+                  |
+                  +--> 'wrapped_free': events 15-16 (depth 2)
+     { dg-end-multiline-output "" } */
+}
+
+typedef struct boxed_int
+{
+  int i;
+} boxed_int;
+
+boxed_int *
+make_boxed_int (int i)
+{
+  boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int));
+  result->i = i;
+  return result;
+}
+
+void
+free_boxed_int (boxed_int *bi)
+{
+  wrapped_free (bi);
+}
+
+void test (int i)
+{
+  boxed_int *obj = make_boxed_int (i);
+
+  free_boxed_int (obj);
+
+  free_boxed_int (obj);
+}
+
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c
deleted file mode 100644
index b7f4c73..0000000
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "" } */
-
-#include <stdlib.h>
-
-void *wrapped_malloc (size_t size)
-{
-  return malloc (size);
-}
-
-void wrapped_free (void *ptr)
-{
-  free (ptr); /* { dg-warning "double-free of 'ptr' \\\[CWE-415\\]" } */
-  /* { dg-begin-multiline-output "" }
-  'test': events 1-2
-     | (1): entering 'test'
-     | (2): calling 'make_boxed_int'
-     +--> 'make_boxed_int': events 3-4
-                  | (3): entering 'make_boxed_int'
-                  | (4): calling 'wrapped_malloc'
-                  +--> 'wrapped_malloc': events 5-6
-                               | (5): entering 'wrapped_malloc'
-                               | (6): calling 'malloc'
-     <-------------------------+
-     |
-  'test': event 7
-     | (7): calling 'free_boxed_int'
-     +--> 'free_boxed_int': events 8-9
-                  | (8): entering 'free_boxed_int'
-                  | (9): calling 'wrapped_free'
-                  +--> 'wrapped_free': events 10-11
-                              | (10): entering 'wrapped_free'
-                              | (11): calling 'free'
-     <------------------------+
-     |
-  'test': event 12
-     | (12): calling 'free_boxed_int'
-     +--> 'free_boxed_int': events 13-14
-                  | (13): entering 'free_boxed_int'
-                  | (14): calling 'wrapped_free'
-                  +--> 'wrapped_free': events 15-16
-                              | (15): entering 'wrapped_free'
-                              | (16): calling 'free'
-     { dg-end-multiline-output "" } */
-}
-
-typedef struct boxed_int
-{
-  int i;
-} boxed_int;
-
-boxed_int *
-make_boxed_int (int i)
-{
-  boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int));
-  result->i = i;
-  return result;
-}
-
-void
-free_boxed_int (boxed_int *bi)
-{
-  wrapped_free (bi);
-}
-
-void test (int i)
-{
-  boxed_int *obj = make_boxed_int (i);
-
-  free_boxed_int (obj);
-
-  free_boxed_int (obj);
-}
-
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-5.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-5.c
deleted file mode 100644
index 0ccb90e..0000000
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-5.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/* As per diagnostics-test-paths-4.c, but with -fdiagnostics-show-path-depths.  */
-
-/* { dg-do compile } */
-/* { dg-options "-fdiagnostics-show-path-depths" } */
-
-#include <stdlib.h>
-
-void *wrapped_malloc (size_t size)
-{
-  return malloc (size);
-}
-
-void wrapped_free (void *ptr)
-{
-  free (ptr); /* { dg-warning "double-free of 'ptr' \\\[CWE-415\\]" } */
-  /* { dg-begin-multiline-output "" }
-  'test': events 1-2 (depth 0)
-     | (1): entering 'test'
-     | (2): calling 'make_boxed_int'
-     +--> 'make_boxed_int': events 3-4 (depth 1)
-                  | (3): entering 'make_boxed_int'
-                  | (4): calling 'wrapped_malloc'
-                  +--> 'wrapped_malloc': events 5-6 (depth 2)
-                               | (5): entering 'wrapped_malloc'
-                               | (6): calling 'malloc'
-     <-------------------------+
-     |
-  'test': event 7 (depth 0)
-     | (7): calling 'free_boxed_int'
-     +--> 'free_boxed_int': events 8-9 (depth 1)
-                  | (8): entering 'free_boxed_int'
-                  | (9): calling 'wrapped_free'
-                  +--> 'wrapped_free': events 10-11 (depth 2)
-                              | (10): entering 'wrapped_free'
-                              | (11): calling 'free'
-     <------------------------+
-     |
-  'test': event 12 (depth 0)
-     | (12): calling 'free_boxed_int'
-     +--> 'free_boxed_int': events 13-14 (depth 1)
-                  | (13): entering 'free_boxed_int'
-                  | (14): calling 'wrapped_free'
-                  +--> 'wrapped_free': events 15-16 (depth 2)
-                              | (15): entering 'wrapped_free'
-                              | (16): calling 'free'
-     { dg-end-multiline-output "" } */
-}
-
-typedef struct boxed_int
-{
-  int i;
-} boxed_int;
-
-boxed_int *
-make_boxed_int (int i)
-{
-  boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int));
-  result->i = i;
-  return result;
-}
-
-void
-free_boxed_int (boxed_int *bi)
-{
-  wrapped_free (bi);
-}
-
-void test (int i)
-{
-  boxed_int *obj = make_boxed_int (i);
-
-  free_boxed_int (obj);
-
-  free_boxed_int (obj);
-}
-
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index 71e3d22..60065e6 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -60,8 +60,11 @@ set plugin_test_list [list \
 	  diagnostic-test-paths-1.c \
 	  diagnostic-test-paths-2.c \
 	  diagnostic-test-paths-3.c \
-	  diagnostic-test-paths-4.c \
-	  diagnostic-test-paths-5.c } \
+	  diagnostic-path-summary-format-default.c \
+	  diagnostic-path-summary-format-none.c \
+	  diagnostic-path-summary-format-simple.c \
+	  diagnostic-path-summary-format-event-summaries.c \
+	  diagnostic-path-summary-format-inline-events.c } \
 ]
 
 foreach plugin_test $plugin_test_list {
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 4a0dc31..55d4bdb 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1121,8 +1121,8 @@ general_init (const char *argv0, bool init_signals)
     = global_options_init.x_flag_diagnostics_show_line_numbers;
   global_dc->show_metadata
     = global_options_init.x_flag_diagnostics_show_metadata;
-  global_dc->show_path_summary
-    = global_options_init.x_flag_diagnostics_show_path_summary;
+  global_dc->path_summary_format
+    = (enum diagnostic_path_summary_format)global_options_init.x_flag_diagnostics_path_summary_format;
   global_dc->show_path_depths
     = global_options_init.x_flag_diagnostics_show_path_depths;
   global_dc->show_option_requested
diff --git a/gcc/tree-diagnostic.c b/gcc/tree-diagnostic.c
index 91d83b0..1102cd8 100644
--- a/gcc/tree-diagnostic.c
+++ b/gcc/tree-diagnostic.c
@@ -339,6 +339,14 @@ class path_label : public range_label
   unsigned m_start_idx;
 };
 
+static void
+print_event_range (pretty_printer *pp,
+		   const diagnostic_path *path,
+		   unsigned start_idx, unsigned end_idx,
+		   bool use_diagnostic);
+
+/* FIXME.  */
+
 static bool
 can_consolidate_events (const diagnostic_event &e1,
 			const diagnostic_event &e2)
@@ -476,10 +484,9 @@ print_fndecl (pretty_printer *pp, tree fndecl, bool quoted)
 static void
 print_path_summary (pretty_printer *pp,
 		    const interprocedural_path_summary& summary,
-		    const diagnostic_path *path, bool show_depths)
+		    const diagnostic_path *path, bool show_depths,
+		    enum diagnostic_path_summary_format summary_format)
 {
-  const bool show_events = (path != NULL);
-
   auto_vec<int> name_lengths;
 
   /* Populate name_lengths.  */
@@ -548,21 +555,64 @@ print_path_summary (pretty_printer *pp,
 
       int midpoint = name_lengths[i] / 2;
 
-      if (show_events)
+      switch (summary_format)
 	{
-	  for (int event_idx = range->m_start_idx;
-	       event_idx <= range->m_end_idx; event_idx++)
+	default:
+	case DPSF_NONE:
+	  gcc_unreachable ();
+
+	case DPSF_SIMPLE:
+	  break;
+	case DPSF_EVENT_SUMMARIES:
+	  {
+	    for (int event_idx = range->m_start_idx;
+		 event_idx <= range->m_end_idx; event_idx++)
+	      {
+		write_indent (pp, cur_indent + midpoint);
+		label_text event_desc = path->get_event (event_idx).get_desc ();
+		pp_string (pp, start_line_color);
+		pp_string (pp, "|");
+		pp_string (pp, end_line_color);
+		pp_printf (pp, " (%i): %s",
+			   event_idx + 1, event_desc.m_buffer);
+		event_desc.maybe_free ();
+		pp_newline (pp);
+	      }
+	  }
+	  break;
+	case DPSF_INLINE_EVENTS:
+	  {
+	    write_indent (pp, cur_indent + midpoint);
+	    pp_string (pp, start_line_color);
+	    pp_string (pp, "|");
+	    pp_string (pp, end_line_color);
+	    /* No newline here, as diagnostic_show_locus adds a leading
+	       newline.  */
+
+	    char *saved_prefix = pp_take_prefix (pp);
+	    char *prefix;
 	    {
-	      write_indent (pp, cur_indent + midpoint);
-	      label_text event_desc = path->get_event (event_idx).get_desc ();
-	      pp_string (pp, start_line_color);
-	      pp_string (pp, "|");
-	      pp_string (pp, end_line_color);
-	      pp_printf (pp, " (%i): %s",
-			 event_idx + 1, event_desc.m_buffer);
-	      event_desc.maybe_free ();
-	      pp_newline (pp);
+	      pretty_printer tmp_pp;
+	      write_indent (&tmp_pp, cur_indent + midpoint);
+	      pp_string (&tmp_pp, start_line_color);
+	      pp_string (&tmp_pp, "|");
+	      pp_string (&tmp_pp, end_line_color);
+	      prefix = xstrdup (pp_formatted_text (&tmp_pp));
 	    }
+	    pp_set_prefix (pp, prefix);
+	    pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
+	    print_event_range (pp, path,
+			       range->m_start_idx, range->m_end_idx,
+			       false);
+	    pp_set_prefix (pp, saved_prefix);
+
+	    write_indent (pp, cur_indent + midpoint);
+	    pp_string (pp, start_line_color);
+	    pp_string (pp, "|");
+	    pp_string (pp, end_line_color);
+	    pp_newline (pp);
+	  }
+	  break;
 	}
 
       if (i < summary.m_ranges.length () - 1)
@@ -570,7 +620,7 @@ print_path_summary (pretty_printer *pp,
 	  const interprocedural_path_summary::event_range *next_range
 	    = &summary.m_ranges[i + 1];
 
-	  if (!show_events)
+	  if (summary_format == DPSF_SIMPLE)
 	    {
 	      write_indent (pp, cur_indent + midpoint);
 	      pp_string (pp, start_line_color);
@@ -627,12 +677,93 @@ print_path_summary (pretty_printer *pp,
     }
   // TODO: maybe show state changes?
   // TODO: maybe show all events
-  // TODO: color
-
-  // TODO: DejaGnu test for this
   /* TODO: example of recursion in DejaGnu tests.  */
 }
 
+/* FIXME.
+   Print events, consolidating them into rich locations.  */
+
+static void
+print_event_range (pretty_printer *pp,
+		   const diagnostic_path *path,
+		   unsigned start_idx, unsigned end_idx,
+		   bool use_diagnostic)
+{
+  while (start_idx <= end_idx)
+    {
+      path_label label (path, start_idx);
+      const diagnostic_event &event = path->get_event (start_idx);
+      gcc_rich_location richloc (event.get_location (),
+				 use_diagnostic ? NULL : &label);
+      unsigned j;
+      for (j = start_idx + 1; j <= end_idx; j++)
+	{
+	  const diagnostic_event &other = path->get_event (j);
+	  // TODO: label, and slacken the constraint
+	  if (can_consolidate_events (event, other))
+	    if (richloc.add_location_if_nearby (other.get_location (),
+						false, &label))
+	      continue;
+	  break;
+	}
+
+#if 1
+      /* Hack up state so that diagnostic_report_current_function will announce
+	 function name changes.  */
+      tree saved_current_function_decl = current_function_decl;
+      location_t saved_input_location = input_location;
+      current_function_decl = event.get_fndecl ();
+      input_location = event.get_location ();
+#endif
+
+#if 0
+      /* Alternatively, part of lhd_print_error_function.  */
+      char *old_prefix = pp_take_prefix (pp);
+      const char *file = LOCATION_FILE (event->m_loc);
+      char *new_prefix = file ? file_name_as_prefix (context, file) : NULL;
+      tree fndecl = event->m_fndecl;
+      if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
+	pp_printf
+	  (pp, _("In member function %qs"),
+	   identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 2)));
+      else
+	pp_printf
+	  (pp, _("In function %qs"),
+	   identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 2)));
+      pp_newline_and_flush (pp);
+      pp->prefix = old_prefix;
+      free ((char*) new_prefix);
+#endif
+
+      if (use_diagnostic)
+	{
+	  label_text event_text (event.get_desc ());
+	  inform (&richloc, "(%i) %s", start_idx + 1, event_text.m_buffer);
+	  event_text.maybe_free ();
+	}
+      else
+	{
+	  diagnostic_context dc;
+	  memset (&dc, 0, sizeof (dc));
+	  dc.printer = pp;
+	  dc.show_caret = true;
+	  dc.show_labels_p = global_dc->show_labels_p;
+	  dc.show_line_numbers_p = global_dc->show_line_numbers_p;
+	  dc.min_margin_width = global_dc->min_margin_width;
+	  dc.caret_chars[0] = '^';
+	  diagnostic_set_caret_max_width (&dc, pp_line_cutoff (pp));
+	  diagnostic_show_locus (&dc, &richloc, DK_NOTE); // FIXME
+	}
+
+      start_idx = j;
+
+#if 1
+      current_function_decl = saved_current_function_decl;
+      input_location = saved_input_location;
+#endif
+    }
+}
+
 /* FIXME.  */
 // This needs to be in tree-diagnostic.c so we can hack up current_function_decl,
 // which is used by lhd_print_error_function etc.
@@ -645,7 +776,7 @@ tree_print_diagnostic_path (diagnostic_context *context,
 
   /* Attempt to show intraprocedural summary.  */
   if (path->interprocedural_p ()
-      && context->show_path_summary)
+      && context->path_summary_format != DPSF_NONE)
     {
       inform (UNKNOWN_LOCATION, "summary of interprocedural path");
 
@@ -654,7 +785,8 @@ tree_print_diagnostic_path (diagnostic_context *context,
       char *saved_prefix = pp_take_prefix (context->printer);
       pp_set_prefix (context->printer, NULL);
       print_path_summary (context->printer,
-			  summary, path, context->show_path_depths);
+			  summary, path, context->show_path_depths,
+			  context->path_summary_format);
       pp_flush (context->printer);
       pp_set_prefix (context->printer, saved_prefix);
     }
@@ -662,63 +794,9 @@ tree_print_diagnostic_path (diagnostic_context *context,
   /* TODO: options for different printing approaches.  */
   if (context->show_caret && context->show_line_numbers_p)
     {
-      /* Try consolidating events into rich locations.  */
-      unsigned start_idx = 0;
-      while (start_idx < num_events)
-	{
-	  path_label label (path, start_idx);
-	  const diagnostic_event &event = path->get_event (start_idx);
-	  gcc_rich_location richloc (event.get_location ());
-	  unsigned j;
-	  for (j = start_idx + 1; j < path->num_events (); j++)
-	    {
-	      const diagnostic_event &other = path->get_event (j);
-	      // TODO: label, and slacken the constraint
-	      if (can_consolidate_events (event, other))
-		if (richloc.add_location_if_nearby (other.get_location (),
-						    false, &label))
-		  continue;
-	      break;
-	    }
-
-#if 1
-	  /* Hack up state so that diagnostic_report_current_function will announce
-	     function name changes.  */
-	  tree saved_current_function_decl = current_function_decl;
-	  location_t saved_input_location = input_location;
-	  current_function_decl = event.get_fndecl ();
-	  input_location = event.get_location ();
-#endif
-
-#if 0
-	  /* Alternatively, part of lhd_print_error_function.  */
-	  char *old_prefix = pp_take_prefix (context->printer);
-	  const char *file = LOCATION_FILE (event->m_loc);
-	  char *new_prefix = file ? file_name_as_prefix (context, file) : NULL;
-	  tree fndecl = event->m_fndecl;
-	  if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
-	    pp_printf
-	      (context->printer, _("In member function %qs"),
-	       identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 2)));
-	  else
-	    pp_printf
-	      (context->printer, _("In function %qs"),
-	       identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 2)));
-	  pp_newline_and_flush (context->printer);
-	  context->printer->prefix = old_prefix;
-	  free ((char*) new_prefix);
-#endif
-
-	  label_text event_text (event.get_desc ());
-	  inform (&richloc, "(%i) %s", start_idx + 1, event_text.m_buffer);
-	  event_text.maybe_free ();
-	  start_idx = j;
-
-#if 1
-	  current_function_decl = saved_current_function_decl;
-	  input_location = saved_input_location;
-#endif
-	}
+      if (num_events > 0)
+	print_event_range (context->printer, path, 0, num_events - 1,
+			   true);
     }
   else
     {
@@ -822,7 +900,8 @@ test_empty_path (pretty_printer *event_pp)
   ASSERT_EQ (summary.m_ranges.length (), 0);
 
   pretty_printer pp;
-  print_path_summary (&pp, summary, &path, true);
+  print_path_summary (&pp, summary, &path, true,
+		      DPSF_INLINE_EVENTS);
   ASSERT_STREQ ("",
 		pp_formatted_text (&pp));
 }
@@ -847,19 +926,33 @@ test_intraprocedural_path (pretty_printer *event_pp)
 
   {
     pretty_printer pp;
-    print_path_summary (&pp, summary, NULL, true);
+    print_path_summary (&pp, summary, &path, true,
+			DPSF_SIMPLE);
     ASSERT_STREQ ("  `foo': events 1-2 (depth 0)\n",
 		  pp_formatted_text (&pp));
   }
 
   {
     pretty_printer pp;
-    print_path_summary (&pp, summary, &path, true);
+    print_path_summary (&pp, summary, &path, true,
+			DPSF_EVENT_SUMMARIES);
     ASSERT_STREQ ("  `foo': events 1-2 (depth 0)\n"
 		  "    | (1): first `free'\n"
 		  "    | (2): double `free'\n",
 		  pp_formatted_text (&pp));
   }
+
+  {
+    pretty_printer pp;
+    print_path_summary (&pp, summary, &path, true,
+			DPSF_INLINE_EVENTS);
+#if 0
+    ASSERT_STREQ ("  `foo': events 1-2 (depth 0)\n"
+		  "    | (1): first `free'\n"
+		  "    | (2): double `free'\n",
+		  pp_formatted_text (&pp));
+#endif
+  }
 }
 
 /* FIXME.  */
@@ -903,7 +996,8 @@ test_interprocedural_path_1 (pretty_printer *event_pp)
 
   {
     pretty_printer pp;
-    print_path_summary (&pp, summary, NULL, true);
+    print_path_summary (&pp, summary, &path, true,
+			DPSF_SIMPLE);
     ASSERT_STREQ
       ("  `test': events 1-2 (depth 0)\n"
        "     |\n"
@@ -934,7 +1028,48 @@ test_interprocedural_path_1 (pretty_printer *event_pp)
      the interprocedural stuff is much clearer, given the picture.  */
   {
     pretty_printer pp;
-    print_path_summary (&pp, summary, &path, true);
+    print_path_summary (&pp, summary, &path, true,
+			DPSF_EVENT_SUMMARIES);
+    ASSERT_STREQ
+      ("  `test': events 1-2 (depth 0)\n"
+       "     | (1): entering `test'\n"
+       "     | (2): calling `make_boxed_int'\n"
+       "     +--> `make_boxed_int': events 3-4 (depth 1)\n"
+       "                  | (3): entering `make_boxed_int'\n"
+       "                  | (4): calling `wrapped_malloc'\n"
+       "                  +--> `wrapped_malloc': events 5-6 (depth 2)\n"
+       "                               | (5): entering `wrapped_malloc'\n"
+       "                               | (6): calling malloc\n"
+       "     <-------------------------+\n"
+       "     |\n"
+       "  `test': events 7-8 (depth 0)\n"
+       "     | (7): returning to `test'\n"
+       "     | (8): calling `free_boxed_int'\n"
+       "     +--> `free_boxed_int': events 9-10 (depth 1)\n"
+       "                  | (9): entering `free_boxed_int'\n"
+       "                  | (10): calling `wrapped_free'\n"
+       "                  +--> `wrapped_free': events 11-12 (depth 2)\n"
+       "                              | (11): entering `wrapped_free'\n"
+       "                              | (12): calling free\n"
+       "     <------------------------+\n"
+       "     |\n"
+       "  `test': events 13-14 (depth 0)\n"
+       "     | (13): returning to `test'\n"
+       "     | (14): calling `free_boxed_int'\n"
+       "     +--> `free_boxed_int': events 15-16 (depth 1)\n"
+       "                  | (15): entering `free_boxed_int'\n"
+       "                  | (16): calling `wrapped_free'\n"
+       "                  +--> `wrapped_free': events 17-18 (depth 2)\n"
+       "                              | (17): entering `wrapped_free'\n"
+       "                              | (18): calling free\n",
+       pp_formatted_text (&pp));
+  }
+
+  {
+    pretty_printer pp;
+    print_path_summary (&pp, summary, &path, true,
+			DPSF_INLINE_EVENTS);
+#if 0
     ASSERT_STREQ
       ("  `test': events 1-2 (depth 0)\n"
        "     | (1): entering `test'\n"
@@ -968,6 +1103,7 @@ test_interprocedural_path_1 (pretty_printer *event_pp)
        "                              | (17): entering `wrapped_free'\n"
        "                              | (18): calling free\n",
        pp_formatted_text (&pp));
+#endif
   }
 }
 
@@ -1000,7 +1136,8 @@ test_interprocedural_path_2 (pretty_printer *event_pp)
 
   {
     pretty_printer pp;
-    print_path_summary (&pp, summary, NULL, true);
+    print_path_summary (&pp, summary, &path, true,
+			DPSF_SIMPLE);
     ASSERT_STREQ
       ("  `foo': events 1-2 (depth 0)\n"
        "    |\n"
@@ -1018,7 +1155,8 @@ test_interprocedural_path_2 (pretty_printer *event_pp)
 
   {
     pretty_printer pp;
-    print_path_summary (&pp, summary, &path, true);
+    print_path_summary (&pp, summary, &path, true,
+			DPSF_EVENT_SUMMARIES);
     ASSERT_STREQ
       ("  `foo': events 1-2 (depth 0)\n"
        "    | (1): entering `foo'\n"
@@ -1060,7 +1198,8 @@ test_recursion (pretty_printer *event_pp)
 
   {
     pretty_printer pp;
-    print_path_summary (&pp, summary, NULL, true);
+    print_path_summary (&pp, summary, &path, true,
+			DPSF_SIMPLE);
     ASSERT_STREQ
       ("  `factorial': events 1-2 (depth 0)\n"
        "       |\n"
@@ -1074,7 +1213,8 @@ test_recursion (pretty_printer *event_pp)
 
   {
     pretty_printer pp;
-    print_path_summary (&pp, summary, &path, true);
+    print_path_summary (&pp, summary, &path, true,
+			DPSF_EVENT_SUMMARIES);
     ASSERT_STREQ
       ("  `factorial': events 1-2 (depth 0)\n"
        "       | (1): entering `factorial'\n"
-- 
1.8.5.3

