From 41e8fa460398152b34054d1c63a984595168e330 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 14 Mar 2019 13:11:15 -0400
Subject: [PATCH 105/138] FIXME: abstract events; move desc to be a vfunc

---
 gcc/analyzer/engine.cc    | 184 +++++++++++++++++++++++++++++-----------------
 gcc/c-family/c-format.c   |   2 +-
 gcc/c/c-objc-common.c     |   4 +-
 gcc/cp/error.c            |   4 +-
 gcc/diagnostic-path.h     |  51 ++++++++++---
 gcc/diagnostic.c          |  15 ++--
 gcc/gcc-rich-location.c   |   2 +-
 gcc/gcc-rich-location.h   |   2 +-
 gcc/tree-diagnostic.c     |  48 +++++++-----
 libcpp/include/line-map.h |  22 +++++-
 10 files changed, 219 insertions(+), 115 deletions(-)

diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 8763ca1..0c28961 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -436,27 +436,34 @@ class checker_event : public diagnostic_event
 {
 public:
   checker_event (enum event_kind kind,
-		 location_t loc, tree fndecl, int depth,
-		 const char *desc)
-  : diagnostic_event (loc, fndecl, depth, desc),
-    m_kind (kind)
+		 location_t loc, tree fndecl, int depth)
+  : m_kind (kind), m_loc (loc), m_fndecl (fndecl), m_depth (depth)
   {
   }
 
+  location_t get_location () const FINAL OVERRIDE { return m_loc; }
+  tree get_fndecl () const FINAL OVERRIDE { return m_fndecl; }
+  int get_stack_depth () const FINAL OVERRIDE { return m_depth; }
+
   virtual checker_event *clone () const = 0;
 
   std::string to_str () const
   {
     std::string result ("\"");
-    result += m_desc;
+    label_text event_desc (get_desc ());
+    result += event_desc.m_buffer;
+    event_desc.maybe_free ();
     result += "\" (";
     result += event_kind_to_string (m_kind);
     result += ", depth ";
-    result += std::to_string (m_depth) + ")";
+    result += std::to_string (get_stack_depth ()) + ")";
     return result;
   }
 
   enum event_kind m_kind;
+  location_t m_loc;
+  tree m_fndecl;
+  int m_depth;
 };
 
 class debug_event : public checker_event
@@ -464,8 +471,18 @@ class debug_event : public checker_event
 public:
   debug_event (location_t loc, tree fndecl, int depth,
 	      const char *desc)
-  : checker_event (EK_DEBUG, loc, fndecl, depth, desc)
+  : checker_event (EK_DEBUG, loc, fndecl, depth),
+    m_desc (xstrdup (desc))
+  {
+  }
+  ~debug_event ()
+  {
+    free (m_desc);
+  }
+
+  label_text get_desc () const FINAL OVERRIDE
   {
+    return label_text::borrow (m_desc);
   }
 
   checker_event *clone () const FINAL OVERRIDE
@@ -473,21 +490,26 @@ public:
     return new debug_event (m_loc, m_fndecl, m_depth, m_desc);
   }
 
-  // FIXME
+private:
+  char *m_desc;
 };
 
 class function_entry_event : public checker_event
 {
 public:
-  function_entry_event (location_t loc, tree fndecl, int depth,
-		 const char *desc)
-  : checker_event (EK_FUNCTION_ENTRY, loc, fndecl, depth, desc)
+  function_entry_event (location_t loc, tree fndecl, int depth)
+  : checker_event (EK_FUNCTION_ENTRY, loc, fndecl, depth)
   {
   }
 
+  label_text get_desc () const FINAL OVERRIDE
+  {
+    return label_text::take (print ("entry to %qE", m_fndecl));
+  }
+
   checker_event *clone () const FINAL OVERRIDE
   {
-    return new function_entry_event (m_loc, m_fndecl, m_depth, m_desc);
+    return new function_entry_event (m_loc, m_fndecl, m_depth);
   }
 
   // FIXME
@@ -505,31 +527,28 @@ public:
 		      tree origin)
   : checker_event (EK_STATE_CHANGE,
 		   stmt->location, node->m_fun->decl,
-		   stack_depth,
-		   make_desc (var, sm, from, to, origin)),
+		   stack_depth),
     m_node (node), m_stmt (stmt), m_sm (sm),
     m_var (var), m_from (from), m_to (to),
     m_origin (origin)
   {
   }
 
-  static char *make_desc (tree var,
-			  const state_machine &sm,
-			  state_machine::state_t from,
-			  state_machine::state_t to,
-			  tree origin)
+  label_text get_desc () const FINAL OVERRIDE
   {
-    if (origin)
-      return print ("state of %qE: %qs -> %qs (origin: %qE)",
-		    var,
-		    sm.get_state_name (from),
-		    sm.get_state_name (to),
-		    origin);
+    if (m_origin)
+      return label_text::take
+	(print ("state of %qE: %qs -> %qs (origin: %qE)",
+		m_var,
+		m_sm.get_state_name (m_from),
+		m_sm.get_state_name (m_to),
+		m_origin));
     else
-      return print ("state of %qE: %qs -> %qs (origin: NULL)",
-		    var,
-		    sm.get_state_name (from),
-		    sm.get_state_name (to));
+      return label_text::take
+	(print ("state of %qE: %qs -> %qs (origin: NULL)",
+		m_var,
+		m_sm.get_state_name (m_from),
+		m_sm.get_state_name (m_to)));
   }
 
   checker_event *clone () const FINAL OVERRIDE
@@ -551,19 +570,51 @@ class edge_event : public checker_event
 {
 public:
   edge_event (const superedge *edge,
-	      location_t loc, tree fndecl, int depth, const char *desc)
+	      location_t loc, tree fndecl, int depth)
   : checker_event (EK_EDGE,
-		   loc, fndecl, depth, desc),
+		   loc, fndecl, depth),
     m_edge (edge)
   {
   }
 
+  label_text get_desc () const FINAL OVERRIDE
+  {
+    switch (m_edge->m_kind)
+      {
+      default:
+	gcc_unreachable ();
+      case SUPEREDGE_CFG_EDGE:
+	return label_text::take (// TODO: possibly a higher-level description?
+				 print ("taking edge SN:%i -> SN:%i",
+					m_edge->m_src->m_index,
+					m_edge->m_dest->m_index));
+      case SUPEREDGE_CALL:
+	{
+	  return label_text::take (print ("calling %qE from %qE",
+					  m_edge->m_dest->m_fun->decl,
+					  m_edge->m_src->m_fun->decl));
+	}
+
+      case SUPEREDGE_RETURN:
+	{
+	  return label_text::take (print ("returning to %qE from %qE",
+					  m_edge->m_dest->m_fun->decl,
+					  m_edge->m_src->m_fun->decl));
+	}
+
+      case SUPEREDGE_INTRAPROCEDURAL_CALL:
+	return label_text::take (// TODO: possibly a higher-level description?
+				 print ("taking edge SN:%i -> SN:%i",
+					m_edge->m_src->m_index,
+					m_edge->m_dest->m_index));
+      }
+  }
+
   checker_event *clone () const FINAL OVERRIDE
   {
-    return new edge_event (m_edge, m_loc, m_fndecl, m_depth, m_desc);
+    return new edge_event (m_edge, m_loc, m_fndecl, m_depth);
   }
 
-  // FIXME
   const superedge *m_edge;
 };
 
@@ -571,20 +622,27 @@ class call_summary : public checker_event
 {
 public:
   call_summary (const supernode *caller_node,
-		cgraph_edge *edge, int depth,
-		const char *desc)
+		cgraph_edge *edge, int depth)
   : checker_event (EK_CALL_SUMMARY,
 		   edge->call_stmt->location,
 		   caller_node->m_fun->decl,
-		   depth, desc),
+		   depth),
     m_caller_node (caller_node),
     m_edge (edge)
   {
   }
 
+  label_text get_desc () const FINAL OVERRIDE
+  {
+    return label_text::take (print
+			     ("call summary: call to %qD from %qD",
+			      m_edge->callee->get_fun ()->decl,
+			      m_caller_node->m_fun->decl));
+  }
+
   checker_event *clone () const FINAL OVERRIDE
   {
-    return new call_summary (m_caller_node, m_edge, m_depth, m_desc);
+    return new call_summary (m_caller_node, m_edge, m_depth);
   }
 
   // FIXME
@@ -608,17 +666,24 @@ class warning_event : public checker_event
 {
 public:
   warning_event (location_t loc, tree fndecl, int depth,
-		 const char *desc)
-  : checker_event (EK_WARNING, loc, fndecl, depth, desc)
+		 const char *msg)
+  : checker_event (EK_WARNING, loc, fndecl, depth),
+    m_msg (xstrdup (msg))
   {
   }
+  ~warning_event () { free (m_msg); }
+
+  label_text get_desc () const FINAL OVERRIDE
+  {
+    return label_text::borrow (m_msg);
+  }
 
   warning_event *clone () const FINAL OVERRIDE
   {
-    return new warning_event (m_loc, m_fndecl, m_depth, m_desc);
+    return new warning_event (m_loc, m_fndecl, m_depth, m_msg);
   }
 
-  // FIXME
+  char *m_msg;
 };
 
 /* FIXME.  */
@@ -640,7 +705,9 @@ public:
       {
 	if (i > 0)
 	  result += ", ";
-	result += std::string ("\"") + e->m_desc + std::string ("\"");
+	label_text event_desc (e->get_desc ());
+	result += std::string ("\"") + event_desc.m_buffer + std::string ("\"");
+	event_desc.maybe_free ();
       }
 
     return result + "]";
@@ -1030,8 +1097,7 @@ engine::add_events_for_node (checker_path *path, const supernode *node,
       path->add_event
 	(new function_entry_event (node->get_start_location (),
 				   node->m_fun->decl,
-				   stack_depth,
-				   print ("entry to %qE", node->m_fun->decl)));
+				   stack_depth));
     }
 }
 
@@ -1456,10 +1522,7 @@ engine::dfs_traverse (sm_instance sm_inst,
 				? last_stmt->location
 				: UNKNOWN_LOCATION),
 			       node->m_fun->decl,
-			       new_b.m_path.m_stack_depth,
-			       // TODO: possibly a higher-level description?
-			       print ("taking edge SN:%i -> SN:%i",
-				      node->m_index, succ->m_dest->m_index));
+			       new_b.m_path.m_stack_depth);
 	   new_b.m_path.add_event (event);
 	   
 	   sm_instance per_edge_new_sm_inst = sm_inst;
@@ -2007,10 +2070,7 @@ engine::follow_call (sm_instance sm_inst, backtrace b, path_state ps,
 	(new edge_event (sedge,
 			 edge->call_stmt->location,
 			 caller_node->m_fun->decl,
-			 b_in_callee.m_path.m_stack_depth,
-			 print ("calling %qE from %qE",
-				callee_node->m_fun->decl,
-				caller_node->m_fun->decl)));
+			 b_in_callee.m_path.m_stack_depth));
     }
   b_in_callee.m_path.m_stack_depth++;
 
@@ -2095,11 +2155,7 @@ engine::follow_call (sm_instance sm_inst, backtrace b, path_state ps,
 
     backtrace new_b (b);
     checker_event *event
-      = new call_summary (caller_node, edge,
-			  0,/*int depth,*/
-			  print ("call summary: call to %qD from %qD",
-				 edge->callee->get_fun ()->decl,
-				 caller_node->m_fun->decl));
+      = new call_summary (caller_node, edge, 0/*int depth,*/);
     new_b.m_path.add_event (event);
 
     sm_instance restored_sm
@@ -2342,10 +2398,7 @@ engine::expand_call_summary (const call_summary *summary_event,
   result->add_event (new edge_event (sedge_call,
 				     summary_event->m_loc,
 				     caller_node->m_fun->decl,
-				     caller_stack_depth,
-				     print ("calling %qE from %qE",
-					    callee_node->m_fun->decl,
-					    caller_node->m_fun->decl)));
+				     caller_stack_depth));
 
   // TODO: body of function
 
@@ -2452,9 +2505,7 @@ engine::expand_call_summary (const call_summary *summary_event,
 		checker_event *event
 		  = new edge_event (succ, node->get_end_location (),
 				    node->m_fun->decl,
-				    callee_stack_depth,
-				    print ("taking edge SN:%i -> SN:%i",
-					   node->m_index, succ->m_dest->m_index));
+				    callee_stack_depth);
 		result->add_event (event);
 	      }
 	    node = succ->m_dest;
@@ -2469,10 +2520,7 @@ engine::expand_call_summary (const call_summary *summary_event,
   result->add_event (new edge_event (sedge_return,
 				     summary_event->m_loc,
 				     caller_node->m_fun->decl,
-				     caller_stack_depth,
-				     print ("returning to %qE from %qE",
-					    caller_node->m_fun->decl,
-					    callee_node->m_fun->decl)));
+				     caller_stack_depth));
 
   result->maybe_log (get_logger (), "result");
 
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 327fa29..dd54f22 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -3631,7 +3631,7 @@ class range_label_for_format_type_mismatch
 
     char *result = concat (text.m_buffer, p, NULL);
     text.maybe_free ();
-    return label_text (result, true);
+    return label_text::take (result);
   }
 
  private:
diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c
index 21ca7e6..1509902 100644
--- a/gcc/c/c-objc-common.c
+++ b/gcc/c/c-objc-common.c
@@ -221,12 +221,12 @@ label_text
 range_label_for_type_mismatch::get_text (unsigned /*range_idx*/) const
 {
   if (m_labelled_type == NULL_TREE)
-    return label_text (NULL, false);
+    return label_text::borrow (NULL);
 
   c_pretty_printer cpp;
   bool quoted = false;
   print_type (&cpp, m_labelled_type, &quoted);
-  return label_text (xstrdup (pp_formatted_text (&cpp)), true);
+  return label_text::take (xstrdup (pp_formatted_text (&cpp)));
 }
 
 
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 3c9df67..b868c99 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -4340,7 +4340,7 @@ label_text
 range_label_for_type_mismatch::get_text (unsigned /*range_idx*/) const
 {
   if (m_labelled_type == NULL_TREE)
-    return label_text (NULL, false);
+    return label_text::borrow (NULL);
 
   const bool verbose = false;
   const bool show_color = false;
@@ -4355,5 +4355,5 @@ range_label_for_type_mismatch::get_text (unsigned /*range_idx*/) const
 
   /* Both of the above return GC-allocated buffers, so the caller mustn't
      free them.  */
-  return label_text (const_cast <char *> (result), false);
+  return label_text::borrow (result);
 }
diff --git a/gcc/diagnostic-path.h b/gcc/diagnostic-path.h
index 65ffc94..d0d4fce 100644
--- a/gcc/diagnostic-path.h
+++ b/gcc/diagnostic-path.h
@@ -55,24 +55,25 @@ along with GCC; see the file COPYING3.  If not see
     function; more complicated examples (such as interprocedural paths)
     might be printed as multiple notes.  */
 
+/* Abstract base classes, describing events within a path, and the paths
+   themselves.  */
+
 /* One event within a diagnostic_path.  */
 
-struct diagnostic_event
+class diagnostic_event
 {
  public:
-  diagnostic_event (location_t loc, tree fndecl, int depth, const char *desc);
-  virtual ~diagnostic_event ();
+  virtual ~diagnostic_event () {}
 
-  location_t m_loc;
-  /* TODO: generalize this to a "backtrace", so that consumers can
-     decipher interprocedural sequences of events:  */
-  tree m_fndecl;
+  virtual location_t get_location () const = 0;
+
+  virtual tree get_fndecl () const = 0;
 
   /* Stack depth, so that consumers can visualizes the interprocedural
      calls, returns, and frame nesting.  */
-  int m_depth;
+  virtual int get_stack_depth () const = 0;
 
-  char *m_desc; // has been i18n-ed and formatted
+  virtual label_text get_desc () const = 0;
 };
 
 /* Abstract base class for getting at a sequence of events.  */
@@ -81,12 +82,38 @@ class diagnostic_path
 {
  public:
   virtual ~diagnostic_path () {}
-
   virtual unsigned num_events () const = 0;
   virtual const diagnostic_event & get_event (int idx) const = 0;
 };
 
-/* Concrete subclass: a simple vector of events.  */
+/* Concrete subclasses.  */
+
+/* A simple implementation of diagnostic_event.  */
+
+class simple_diagnostic_event : public diagnostic_event
+{
+ public:
+  simple_diagnostic_event (location_t loc, tree fndecl, int depth,
+			   const char *desc);
+  ~simple_diagnostic_event ();
+
+  location_t get_location () const FINAL OVERRIDE { return m_loc; }
+  tree get_fndecl () const FINAL OVERRIDE { return m_fndecl; }
+  int get_stack_depth () const FINAL OVERRIDE { return m_depth; }
+  label_text get_desc () const FINAL OVERRIDE
+  {
+    return label_text::borrow (m_desc);
+  }
+
+ private:
+  location_t m_loc;
+  tree m_fndecl;
+  int m_depth;
+  char *m_desc; // has been i18n-ed and formatted
+};
+
+/* A simple implementation of diagnostic_path, as a vector of
+   simple_diagnostic_event instances.  */
 
 class simple_diagnostic_path : public diagnostic_path
 {
@@ -100,7 +127,7 @@ class simple_diagnostic_path : public diagnostic_path
     ATTRIBUTE_GCC_DIAG(5,6);
 
  private:
-  auto_delete_vec<diagnostic_event> m_events;
+  auto_delete_vec<simple_diagnostic_event> m_events;
 };
 
 // FIXME:
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 12cb3f1..9b49a4e 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -1269,6 +1269,7 @@ diagnostic_n_impl (rich_location *richloc, const diagnostic_metadata *metadata,
   diagnostic_set_info_translated (&diagnostic, text, ap, richloc, kind);
   if (kind == DK_WARNING)
     diagnostic.option_index = opt;
+  diagnostic.metadata = metadata;
   return diagnostic_report_diagnostic (global_dc, &diagnostic);
 }
 
@@ -1827,8 +1828,8 @@ simple_diagnostic_path::add_event (location_t loc, tree fndecl, int depth, const
 
   va_end (ap);
 
-  diagnostic_event *new_event
-    = new diagnostic_event (loc, fndecl, depth, pp_formatted_text (pp));
+  simple_diagnostic_event *new_event
+    = new simple_diagnostic_event (loc, fndecl, depth, pp_formatted_text (pp));
   m_events.safe_push (new_event);
 #if 0
   fprintf (stderr, "DBG: added to path %p: %s\n", this, new_event->m_desc);
@@ -1837,15 +1838,17 @@ simple_diagnostic_path::add_event (location_t loc, tree fndecl, int depth, const
   pp_clear_output_area (pp);
 }
 
-/* struct diagnostic_event.  */
+/* struct simple_diagnostic_event.  */
 
-diagnostic_event::diagnostic_event (location_t loc, tree fndecl, int depth,
-				    const char *desc)
+simple_diagnostic_event::simple_diagnostic_event (location_t loc,
+						  tree fndecl,
+						  int depth,
+						  const char *desc)
 : m_loc (loc), m_fndecl (fndecl), m_depth (depth), m_desc (xstrdup (desc))
 {
 }
 
-diagnostic_event::~diagnostic_event ()
+simple_diagnostic_event::~simple_diagnostic_event ()
 {
   free (m_desc);
 }
diff --git a/gcc/gcc-rich-location.c b/gcc/gcc-rich-location.c
index 82d4f52..071463e 100644
--- a/gcc/gcc-rich-location.c
+++ b/gcc/gcc-rich-location.c
@@ -196,7 +196,7 @@ maybe_range_label_for_tree_type_mismatch::get_text (unsigned range_idx) const
 {
   if (m_expr == NULL_TREE
       || !EXPR_P (m_expr))
-    return label_text (NULL, false);
+    return label_text::borrow (NULL);
   tree expr_type = TREE_TYPE (m_expr);
 
   tree other_type = NULL_TREE;
diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h
index fee4af7..b4d47d4 100644
--- a/gcc/gcc-rich-location.h
+++ b/gcc/gcc-rich-location.h
@@ -113,7 +113,7 @@ class text_range_label : public range_label
 
   label_text get_text (unsigned /*range_idx*/) const FINAL OVERRIDE
   {
-    return label_text (const_cast <char *> (m_text), false);
+    return label_text::borrow (m_text);
   }
 
  private:
diff --git a/gcc/tree-diagnostic.c b/gcc/tree-diagnostic.c
index af7db2c..36dedf5 100644
--- a/gcc/tree-diagnostic.c
+++ b/gcc/tree-diagnostic.c
@@ -324,8 +324,12 @@ class path_label : public range_label
     unsigned event_idx = m_start_idx + range_idx;
     const diagnostic_event &event = m_path->get_event (event_idx);
 
-    return label_text (xasprintf ("(%i) %s", event_idx + 1, event.m_desc),
-		       true);
+    label_text event_text (event.get_desc ());
+    label_text result
+      = label_text::take (xasprintf ("(%i) %s", event_idx + 1,
+				     event_text.m_buffer));
+    event_text.maybe_free ();
+    return result;
   }
 
  private:
@@ -339,7 +343,7 @@ can_consolidate_events (const diagnostic_event &e1,
 {
   // FIXME: might want to simply group them by function, and also
   // split whenever there's a backward jump?
-  if (e1.m_fndecl != e2.m_fndecl)
+  if (e1.get_fndecl () != e2.get_fndecl ())
     return false;
 
 #if 0
@@ -350,10 +354,10 @@ can_consolidate_events (const diagnostic_event &e1,
 
   /* Neither can be macro-based.  */
   if (linemap_location_from_macro_expansion_p (line_table,
-					       e1.m_loc))
+					       e1.get_location ()))
     return false;
   if (linemap_location_from_macro_expansion_p (line_table,
-					       e2.m_loc))
+					       e2.get_location ()))
     return false;
 
   // TODO:
@@ -381,15 +385,15 @@ tree_print_diagnostic_path (diagnostic_context *context,
 	{
 	  path_label label (path, start_idx);
 	  const diagnostic_event &event = path->get_event (start_idx);
-	  gcc_rich_location richloc (event.m_loc);
+	  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.m_loc, false,
-						    &label))
+		if (richloc.add_location_if_nearby (other.get_location (),
+						    false, &label))
 		  continue;
 	      break;
 	    }
@@ -399,8 +403,8 @@ tree_print_diagnostic_path (diagnostic_context *context,
 	     function name changes.  */
 	  tree saved_current_function_decl = current_function_decl;
 	  location_t saved_input_location = input_location;
-	  current_function_decl = event.m_fndecl;
-	  input_location = event.m_loc;
+	  current_function_decl = event.get_fndecl ();
+	  input_location = event.get_location ();
 #endif
 
 #if 0
@@ -422,7 +426,9 @@ tree_print_diagnostic_path (diagnostic_context *context,
 	  free ((char*) new_prefix);
 #endif
 
-	  inform (&richloc, "(%i) %s", start_idx + 1, event.m_desc);
+	  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
@@ -437,7 +443,10 @@ tree_print_diagnostic_path (diagnostic_context *context,
       for (unsigned i = 0; i < path->num_events (); i++)
 	{
 	  const diagnostic_event &event = path->get_event (i);
-	  inform (event.m_loc, "(%i) %s", i + 1, event.m_desc);
+	  label_text event_text (event.get_desc ());
+	  inform (event.get_location (),
+		  "(%i) %s", i + 1, event_text.m_buffer);
+	  event_text.maybe_free ();
 	}
     }
 }
@@ -455,16 +464,19 @@ tree_make_json_for_path (diagnostic_context *, const diagnostic_path *path)
       const diagnostic_event &event = path->get_event (i);
 
       json::object *event_obj = new json::object ();
-      if (event.m_loc)
-	event_obj->set ("location", json_from_expanded_location (event.m_loc));
-      event_obj->set ("description", new json::string (event.m_desc));
-      if (event.m_fndecl)
+      if (event.get_location ())
+	event_obj->set ("location",
+			json_from_expanded_location (event.get_location ()));
+      label_text event_text (event.get_desc ());
+      event_obj->set ("description", new json::string (event_text.m_buffer));
+      event_text.maybe_free ();
+      if (tree fndecl = event.get_fndecl ())
 	{
 	  const char *function
-	    = identifier_to_locale (lang_hooks.decl_printable_name (event.m_fndecl, 2));
+	    = identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 2));
 	  event_obj->set ("function", new json::string (function));
 	}
-      event_obj->set ("depth", new json::number (event.m_depth));
+      event_obj->set ("depth", new json::number (event.get_stack_depth ()));
       path_array->append (event_obj);
     }
   return path_array;
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index 8ca4cf3..6b23db3 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -1793,18 +1793,32 @@ struct label_text
   : m_buffer (NULL), m_caller_owned (false)
   {}
 
-  label_text (char *buffer, bool caller_owned)
-  : m_buffer (buffer), m_caller_owned (caller_owned)
-  {}
-
   void maybe_free ()
   {
     if (m_caller_owned)
       free (m_buffer);
   }
 
+  /* Create a label_text instance that borrows BUFFER from a
+     longer-lived owner.  */
+  static label_text borrow (const char *buffer)
+  {
+    return label_text (const_cast <char *> (buffer), false);
+  }
+
+  /* Create a label_text instance that takes ownership of BUFFER.  */
+  static label_text take (char *buffer)
+  {
+    return label_text (buffer, true);
+  }
+
   char *m_buffer;
   bool m_caller_owned;
+
+private:
+  label_text (char *buffer, bool owned)
+  : m_buffer (buffer), m_caller_owned (owned)
+  {}
 };
 
 /* Abstract base class for labelling a range within a rich_location
-- 
1.8.5.3

