diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 35f259da858..a2799b8d826 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1700,6 +1700,8 @@ OBJS = \
 	ubsan.o \
 	sanopt.o \
 	sancov.o \
+	selftest-diagnostic-path.o \
+	selftest-logical-location.o \
 	simple-diagnostic-path.o \
 	tree-call-cdce.o \
 	tree-cfg.o \
diff --git a/gcc/logical-location.h b/gcc/logical-location.h
index c3b72081135..bba21087786 100644
--- a/gcc/logical-location.h
+++ b/gcc/logical-location.h
@@ -21,6 +21,8 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_LOGICAL_LOCATION_H
 #define GCC_LOGICAL_LOCATION_H
 
+#include "label-text.h"
+
 /* An enum for discriminating between different kinds of logical location
    for a diagnostic.
 
@@ -46,7 +48,8 @@ enum logical_location_kind
    - "within function 'foo'", or
    - "within method 'bar'",
    but *without* requiring knowledge of trees
-   (see tree-logical-location.h for subclasses relating to trees).  */
+   (see tree-logical-location.h for concrete subclasses relating to trees,
+   and selftest-logical-location.h for a concrete subclass for selftests).  */
 
 class logical_location
 {
diff --git a/gcc/selftest-diagnostic-path.cc b/gcc/selftest-diagnostic-path.cc
new file mode 100644
index 00000000000..6d21f2e5599
--- /dev/null
+++ b/gcc/selftest-diagnostic-path.cc
@@ -0,0 +1,233 @@
+/* Concrete classes for selftests involving diagnostic paths.
+   Copyright (C) 2019-2024 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+#include "config.h"
+#define INCLUDE_VECTOR
+#include "system.h"
+#include "coretypes.h"
+#include "version.h"
+#include "demangle.h"
+#include "backtrace.h"
+#include "diagnostic.h"
+#include "selftest-diagnostic-path.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* class test_diagnostic_path : public diagnostic_path.  */
+
+test_diagnostic_path::test_diagnostic_path (pretty_printer *event_pp)
+: m_event_pp (event_pp)
+{
+  add_thread ("main");
+}
+
+/* Implementation of diagnostic_path::num_events vfunc for
+   test_diagnostic_path: simply get the number of events in the vec.  */
+
+unsigned
+test_diagnostic_path::num_events () const
+{
+  return m_events.length ();
+}
+
+/* Implementation of diagnostic_path::get_event vfunc for
+   test_diagnostic_path: simply return the event in the vec.  */
+
+const diagnostic_event &
+test_diagnostic_path::get_event (int idx) const
+{
+  return *m_events[idx];
+}
+
+unsigned
+test_diagnostic_path::num_threads () const
+{
+  return m_threads.length ();
+}
+
+const diagnostic_thread &
+test_diagnostic_path::get_thread (diagnostic_thread_id_t idx) const
+{
+  return *m_threads[idx];
+}
+
+bool
+test_diagnostic_path::same_function_p (int event_idx_a,
+				       int event_idx_b) const
+{
+  const char *name_a = m_events[event_idx_a]->get_function_name ();
+  const char *name_b = m_events[event_idx_b]->get_function_name ();
+
+  if (name_a && name_b)
+    return 0 == strcmp (name_a, name_b);
+  return name_a == name_b;
+}
+
+diagnostic_thread_id_t
+test_diagnostic_path::add_thread (const char *name)
+{
+  m_threads.safe_push (new test_diagnostic_thread (name));
+  return m_threads.length () - 1;
+}
+
+/* Add an event to this path at LOC within function FNDECL at
+   stack depth DEPTH.
+
+   Use m_context's printer to format FMT, as the text of the new
+   event.
+
+   Return the id of the new event.  */
+
+diagnostic_event_id_t
+test_diagnostic_path::add_event (location_t loc,
+				 const char *funcname,
+				 int depth,
+				 const char *fmt, ...)
+{
+  pretty_printer *pp = m_event_pp;
+  pp_clear_output_area (pp);
+
+  rich_location rich_loc (line_table, UNKNOWN_LOCATION);
+
+  va_list ap;
+
+  va_start (ap, fmt);
+
+  /* No localization is done on FMT.  */
+  text_info ti (fmt, &ap, 0, nullptr, &rich_loc);
+  pp_format (pp, &ti);
+  pp_output_formatted_text (pp);
+
+  va_end (ap);
+
+  test_diagnostic_event *new_event
+    = new test_diagnostic_event (loc, funcname, depth, pp_formatted_text (pp));
+  m_events.safe_push (new_event);
+
+  pp_clear_output_area (pp);
+
+  return diagnostic_event_id_t (m_events.length () - 1);
+}
+
+diagnostic_event_id_t
+test_diagnostic_path::add_thread_event (diagnostic_thread_id_t thread_id,
+					location_t loc,
+					const char *funcname,
+					int depth,
+					const char *fmt, ...)
+{
+  pretty_printer *pp = m_event_pp;
+  pp_clear_output_area (pp);
+
+  rich_location rich_loc (line_table, UNKNOWN_LOCATION);
+
+  va_list ap;
+
+  va_start (ap, fmt);
+
+  /* No localization is done on FMT.  */
+  text_info ti (fmt, &ap, 0, nullptr, &rich_loc);
+
+  pp_format (pp, &ti);
+  pp_output_formatted_text (pp);
+
+  va_end (ap);
+
+  test_diagnostic_event *new_event
+    = new test_diagnostic_event (loc, funcname, depth, pp_formatted_text (pp),
+				   thread_id);
+  m_events.safe_push (new_event);
+
+  pp_clear_output_area (pp);
+
+  return diagnostic_event_id_t (m_events.length () - 1);
+}
+
+/* Mark the most recent event on this path (which must exist) as being
+   connected to the next one to be added.  */
+
+void
+test_diagnostic_path::connect_to_next_event ()
+{
+  gcc_assert (m_events.length () > 0);
+  m_events[m_events.length () - 1]->connect_to_next_event ();
+}
+
+void
+test_diagnostic_path::add_entry (const char *callee_name,
+				 int stack_depth,
+				 diagnostic_thread_id_t thread_id)
+{
+  add_thread_event (thread_id, UNKNOWN_LOCATION, callee_name, stack_depth,
+		    "entering %qs", callee_name);
+}
+
+void
+test_diagnostic_path::add_return (const char *caller_name,
+				  int stack_depth,
+				  diagnostic_thread_id_t thread_id)
+{
+  add_thread_event (thread_id, UNKNOWN_LOCATION, caller_name, stack_depth,
+		    "returning to %qs", caller_name);
+}
+
+void
+test_diagnostic_path::add_call (const char *caller_name,
+				int caller_stack_depth,
+				const char *callee_name,
+				diagnostic_thread_id_t thread_id)
+{
+  add_thread_event (thread_id, UNKNOWN_LOCATION,
+		    caller_name, caller_stack_depth,
+		    "calling %qs", callee_name);
+  add_entry (callee_name, caller_stack_depth + 1, thread_id);
+}
+
+/* struct test_diagnostic_event.  */
+
+/* test_diagnostic_event's ctor.  */
+
+test_diagnostic_event::
+test_diagnostic_event (location_t loc,
+			 const char *funcname,
+			 int depth,
+			 const char *desc,
+			 diagnostic_thread_id_t thread_id)
+: m_loc (loc),
+  m_logical_loc (LOGICAL_LOCATION_KIND_FUNCTION, funcname),
+  m_depth (depth), m_desc (xstrdup (desc)),
+  m_connected_to_next_event (false),
+  m_thread_id (thread_id)
+{
+}
+
+/* test_diagnostic_event's dtor.  */
+
+test_diagnostic_event::~test_diagnostic_event ()
+{
+  free (m_desc);
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-diagnostic-path.h b/gcc/selftest-diagnostic-path.h
new file mode 100644
index 00000000000..51786a0f589
--- /dev/null
+++ b/gcc/selftest-diagnostic-path.h
@@ -0,0 +1,163 @@
+/* Concrete classes for selftests involving diagnostic paths.
+   Copyright (C) 2019-2024 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_SELFTEST_DIAGNOSTIC_PATH_H
+#define GCC_SELFTEST_DIAGNOSTIC_PATH_H
+
+#include "diagnostic-path.h"
+#include "selftest-logical-location.h"
+
+/* The selftest code should entirely disappear in a production
+   configuration, hence we guard all of it with #if CHECKING_P.  */
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Concrete subclasses of the abstract base classes
+   declared in diagnostic-path.h for use in selftests.
+
+   This code should have no dependency on "tree".  */
+
+/* An implementation of diagnostic_event.  */
+
+class test_diagnostic_event : public diagnostic_event
+{
+ public:
+  test_diagnostic_event (location_t loc, const char *funcname, int depth,
+			 const char *desc,
+			 diagnostic_thread_id_t thread_id = 0);
+  ~test_diagnostic_event ();
+
+  location_t get_location () const final override { return m_loc; }
+  int get_stack_depth () const final override { return m_depth; }
+  label_text get_desc (bool) const final override
+  {
+    return label_text::borrow (m_desc);
+  }
+  const logical_location *get_logical_location () const final override
+  {
+    if (m_logical_loc.get_name ())
+      return &m_logical_loc;
+    else
+      return nullptr;
+  }
+  meaning get_meaning () const final override
+  {
+    return meaning ();
+  }
+  bool connect_to_next_event_p () const final override
+  {
+    return m_connected_to_next_event;
+  }
+  diagnostic_thread_id_t get_thread_id () const final override
+  {
+    return m_thread_id;
+  }
+
+  void connect_to_next_event ()
+  {
+    m_connected_to_next_event = true;
+  }
+
+  const char *get_function_name () const
+  {
+    return m_logical_loc.get_name ();
+  }
+
+ private:
+  location_t m_loc;
+  test_logical_location m_logical_loc;
+  int m_depth;
+  char *m_desc; // has been formatted; doesn't get i18n-ed
+  bool m_connected_to_next_event;
+  diagnostic_thread_id_t m_thread_id;
+};
+
+/* A simple implementation of diagnostic_thread.  */
+
+class test_diagnostic_thread : public diagnostic_thread
+{
+public:
+  test_diagnostic_thread (const char *name) : m_name (name) {}
+  label_text get_name (bool) const final override
+  {
+    return label_text::borrow (m_name);
+  }
+
+private:
+  const char *m_name; // has been i18n-ed and formatted
+};
+
+/* A concrete subclass of diagnostic_path for implementing selftests
+   - a vector of test_diagnostic_event instances
+   - adds member functions for adding test event
+   - does no translation of its events
+   - has no dependency on "tree".  */
+
+class test_diagnostic_path : public diagnostic_path
+{
+ public:
+  test_diagnostic_path (pretty_printer *event_pp);
+
+  unsigned num_events () const final override;
+  const diagnostic_event & get_event (int idx) const final override;
+  unsigned num_threads () const final override;
+  const diagnostic_thread &
+  get_thread (diagnostic_thread_id_t) const final override;
+  bool
+  same_function_p (int event_idx_a,
+		   int event_idx_b) const final override;
+
+  diagnostic_thread_id_t add_thread (const char *name);
+
+  diagnostic_event_id_t add_event (location_t loc, const char *funcname, int depth,
+				   const char *fmt, ...)
+    ATTRIBUTE_GCC_DIAG(5,6);
+  diagnostic_event_id_t
+  add_thread_event (diagnostic_thread_id_t thread_id,
+		    location_t loc, const char *funcname, int depth,
+		    const char *fmt, ...)
+    ATTRIBUTE_GCC_DIAG(6,7);
+
+  void connect_to_next_event ();
+
+  void add_entry (const char *callee_name, int stack_depth,
+		  diagnostic_thread_id_t thread_id = 0);
+  void add_return (const char *caller_name, int stack_depth,
+		   diagnostic_thread_id_t thread_id = 0);
+  void add_call (const char *caller_name,
+		 int caller_stack_depth,
+		 const char *callee_name,
+		 diagnostic_thread_id_t thread_id = 0);
+
+ private:
+  auto_delete_vec<test_diagnostic_thread> m_threads;
+  auto_delete_vec<test_diagnostic_event> m_events;
+
+  /* (for use by add_event).  */
+  pretty_printer *m_event_pp;
+};
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
+
+#endif /* ! GCC_SELFTEST_DIAGNOSTIC_PATH_H */
diff --git a/gcc/selftest-logical-location.cc b/gcc/selftest-logical-location.cc
new file mode 100644
index 00000000000..8017672afa7
--- /dev/null
+++ b/gcc/selftest-logical-location.cc
@@ -0,0 +1,71 @@
+/* Concrete subclass of logical_location for use in selftests.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest-logical-location.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* class test_logical_location : public logical_location.  */
+
+test_logical_location::test_logical_location (enum logical_location_kind kind,
+					      const char *name)
+: m_kind (kind),
+  m_name (name)
+{
+}
+
+const char *
+test_logical_location::get_short_name () const
+{
+  return m_name;
+}
+
+const char *
+test_logical_location::get_name_with_scope () const
+{
+  return m_name;
+}
+
+const char *
+test_logical_location::get_internal_name () const
+{
+  return m_name;
+}
+
+enum logical_location_kind
+test_logical_location::get_kind () const
+{
+  return m_kind;
+}
+
+label_text
+test_logical_location::get_name_for_path_output () const
+{
+  return label_text::borrow (m_name);
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-logical-location.h b/gcc/selftest-logical-location.h
new file mode 100644
index 00000000000..819e111851e
--- /dev/null
+++ b/gcc/selftest-logical-location.h
@@ -0,0 +1,58 @@
+/* Concrete subclass of logical_location for use in selftests.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_SELFTEST_LOGICAL_LOCATION_H
+#define GCC_SELFTEST_LOGICAL_LOCATION_H
+
+#include "logical-location.h"
+
+/* The selftest code should entirely disappear in a production
+   configuration, hence we guard all of it with #if CHECKING_P.  */
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Concrete subclass of logical_location for use in selftests.  */
+
+class test_logical_location : public logical_location
+{
+public:
+  test_logical_location (enum logical_location_kind kind,
+			 const char *name);
+  virtual const char *get_short_name () const final override;
+  virtual const char *get_name_with_scope () const final override;
+  virtual const char *get_internal_name () const final override;
+  virtual enum logical_location_kind get_kind () const final override;
+  virtual label_text get_name_for_path_output () const final override;
+
+  const char *get_name () const { return m_name; }
+
+ private:
+  enum logical_location_kind m_kind;
+  const char *m_name;
+};
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
+
+
+#endif /* GCC_SELFTEST_LOGICAL_LOCATION_H.  */
diff --git a/gcc/tree-diagnostic-path.cc b/gcc/tree-diagnostic-path.cc
index 4287b90d5dd..39a85d33015 100644
--- a/gcc/tree-diagnostic-path.cc
+++ b/gcc/tree-diagnostic-path.cc
@@ -27,13 +27,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tree.h"
 #include "diagnostic.h"
-#include "tree-pretty-print.h"
-#include "gimple-pretty-print.h"
 #include "tree-diagnostic.h"
-#include "langhooks.h"
 #include "intl.h"
 #include "diagnostic-path.h"
-#include "simple-diagnostic-path.h"
 #include "json.h"
 #include "gcc-rich-location.h"
 #include "diagnostic-color.h"
@@ -41,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-label-effects.h"
 #include "selftest.h"
 #include "selftest-diagnostic.h"
+#include "selftest-diagnostic-path.h"
 #include "text-art/theme.h"
 
 /* Disable warnings about missing quoting in GCC diagnostics for the print
@@ -1013,38 +1010,6 @@ path_events_have_column_data_p (const diagnostic_path &path)
   return true;
 }
 
-/* A subclass of simple_diagnostic_path that adds member functions
-   for adding test events and suppresses translation of these events.  */
-
-class test_diagnostic_path : public simple_diagnostic_path
-{
- public:
-  test_diagnostic_path (pretty_printer *event_pp)
-  : simple_diagnostic_path (event_pp)
-  {
-    disable_event_localization ();
-  }
-
-  void add_entry (tree fndecl, int stack_depth)
-  {
-    add_event (UNKNOWN_LOCATION, fndecl, stack_depth,
-	       "entering %qE", fndecl);
-  }
-
-  void add_return (tree fndecl, int stack_depth)
-  {
-    add_event (UNKNOWN_LOCATION, fndecl, stack_depth,
-	       "returning to %qE", fndecl);
-  }
-
-  void add_call (tree caller, int caller_stack_depth, tree callee)
-  {
-    add_event (UNKNOWN_LOCATION, caller, caller_stack_depth,
-	       "calling %qE", callee);
-    add_entry (callee, caller_stack_depth + 1);
-  }
-};
-
 /* Verify that empty paths are handled gracefully.  */
 
 static void
@@ -1067,13 +1032,10 @@ test_empty_path (pretty_printer *event_pp)
 static void
 test_intraprocedural_path (pretty_printer *event_pp)
 {
-  tree fntype_void_void
-    = build_function_type_array (void_type_node, 0, NULL);
-  tree fndecl_foo = build_fn_decl ("foo", fntype_void_void);
-
   test_diagnostic_path path (event_pp);
-  path.add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "first %qs", "free");
-  path.add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "double %qs", "free");
+  const char *const funcname = "foo";
+  path.add_event (UNKNOWN_LOCATION, funcname, 0, "first %qs", "free");
+  path.add_event (UNKNOWN_LOCATION, funcname, 0, "double %qs", "free");
 
   ASSERT_FALSE (path.interprocedural_p ());
 
@@ -1093,33 +1055,20 @@ test_intraprocedural_path (pretty_printer *event_pp)
 static void
 test_interprocedural_path_1 (pretty_printer *event_pp)
 {
-  /* Build fndecls.  The types aren't quite right, but that
-     doesn't matter for the purposes of this test.  */
-  tree fntype_void_void
-    = build_function_type_array (void_type_node, 0, NULL);
-  tree fndecl_test = build_fn_decl ("test", fntype_void_void);
-  tree fndecl_make_boxed_int
-    = build_fn_decl ("make_boxed_int", fntype_void_void);
-  tree fndecl_wrapped_malloc
-    = build_fn_decl ("wrapped_malloc", fntype_void_void);
-  tree fndecl_free_boxed_int
-    = build_fn_decl ("free_boxed_int", fntype_void_void);
-  tree fndecl_wrapped_free
-    = build_fn_decl ("wrapped_free", fntype_void_void);
-
   test_diagnostic_path path (event_pp);
-  path.add_entry (fndecl_test, 0);
-  path.add_call (fndecl_test, 0, fndecl_make_boxed_int);
-  path.add_call (fndecl_make_boxed_int, 1, fndecl_wrapped_malloc);
-  path.add_event (UNKNOWN_LOCATION, fndecl_wrapped_malloc, 2, "calling malloc");
-  path.add_return (fndecl_test, 0);
-  path.add_call (fndecl_test, 0, fndecl_free_boxed_int);
-  path.add_call (fndecl_free_boxed_int, 1, fndecl_wrapped_free);
-  path.add_event (UNKNOWN_LOCATION, fndecl_wrapped_free, 2, "calling free");
-  path.add_return (fndecl_test, 0);
-  path.add_call (fndecl_test, 0, fndecl_free_boxed_int);
-  path.add_call (fndecl_free_boxed_int, 1, fndecl_wrapped_free);
-  path.add_event (UNKNOWN_LOCATION, fndecl_wrapped_free, 2, "calling free");
+  path.add_entry ("test", 0);
+  path.add_call ("test", 0, "make_boxed_int");
+  path.add_call ("make_boxed_int", 1, "wrapped_malloc");
+  path.add_event (UNKNOWN_LOCATION,
+		  "wrapped_malloc", 2, "calling malloc");
+  path.add_return ("test", 0);
+  path.add_call ("test", 0, "free_boxed_int");
+  path.add_call ("free_boxed_int", 1, "wrapped_free");
+  path.add_event (UNKNOWN_LOCATION, "wrapped_free", 2, "calling free");
+  path.add_return ("test", 0);
+  path.add_call ("test", 0, "free_boxed_int");
+  path.add_call ("free_boxed_int", 1, "wrapped_free");
+  path.add_event (UNKNOWN_LOCATION, "wrapped_free", 2, "calling free");
   ASSERT_EQ (path.num_events (), 18);
 
   ASSERT_TRUE (path.interprocedural_p ());
@@ -1248,20 +1197,12 @@ test_interprocedural_path_1 (pretty_printer *event_pp)
 static void
 test_interprocedural_path_2 (pretty_printer *event_pp)
 {
-  /* Build fndecls.  The types aren't quite right, but that
-     doesn't matter for the purposes of this test.  */
-  tree fntype_void_void
-    = build_function_type_array (void_type_node, 0, NULL);
-  tree fndecl_foo = build_fn_decl ("foo", fntype_void_void);
-  tree fndecl_bar = build_fn_decl ("bar", fntype_void_void);
-  tree fndecl_baz = build_fn_decl ("baz", fntype_void_void);
-
   test_diagnostic_path path (event_pp);
-  path.add_entry (fndecl_foo, 0);
-  path.add_call (fndecl_foo, 0, fndecl_bar);
-  path.add_call (fndecl_bar, 1, fndecl_baz);
-  path.add_return (fndecl_bar, 1);
-  path.add_call (fndecl_bar, 1, fndecl_baz);
+  path.add_entry ("foo", 0);
+  path.add_call ("foo", 0, "bar");
+  path.add_call ("bar", 1, "baz");
+  path.add_return ("bar", 1);
+  path.add_call ("bar", 1, "baz");
   ASSERT_EQ (path.num_events (), 8);
 
   ASSERT_TRUE (path.interprocedural_p ());
@@ -1341,14 +1282,10 @@ test_interprocedural_path_2 (pretty_printer *event_pp)
 static void
 test_recursion (pretty_printer *event_pp)
 {
-  tree fntype_void_void
-    = build_function_type_array (void_type_node, 0, NULL);
-  tree fndecl_factorial = build_fn_decl ("factorial", fntype_void_void);
-
  test_diagnostic_path path (event_pp);
-  path.add_entry (fndecl_factorial, 0);
+  path.add_entry ("factorial", 0);
   for (int depth = 0; depth < 3; depth++)
-    path.add_call (fndecl_factorial, depth, fndecl_factorial);
+    path.add_call ("factorial", depth, "factorial");
   ASSERT_EQ (path.num_events (), 7);
 
   ASSERT_TRUE (path.interprocedural_p ());
@@ -1485,14 +1422,14 @@ test_control_flow_1 (const line_table_case &case_,
   const location_t cfg_dest = t.get_line_and_column (5, 10);
 
   test_diagnostic_path path (event_pp);
-  path.add_event (conditional, NULL_TREE, 0,
+  path.add_event (conditional, nullptr, 0,
 		  "following %qs branch (when %qs is NULL)...",
 		  "false", "p");
   path.connect_to_next_event ();
 
-  path.add_event (cfg_dest, NULL_TREE, 0,
+  path.add_event (cfg_dest, nullptr, 0,
 		  "...to here");
-  path.add_event (cfg_dest, NULL_TREE, 0,
+  path.add_event (cfg_dest, nullptr, 0,
 		  "dereference of NULL %qs",
 		  "p");
 
@@ -1665,17 +1602,17 @@ test_control_flow_2 (const line_table_case &case_,
   const location_t loop_body_end = t.get_line_and_columns (5, 5, 9, 17);
 
   test_diagnostic_path path (event_pp);
-  path.add_event (iter_test, NULL_TREE, 0, "infinite loop here");
+  path.add_event (iter_test, nullptr, 0, "infinite loop here");
 
-  path.add_event (iter_test, NULL_TREE, 0, "looping from here...");
+  path.add_event (iter_test, nullptr, 0, "looping from here...");
   path.connect_to_next_event ();
 
-  path.add_event (loop_body_start, NULL_TREE, 0, "...to here");
+  path.add_event (loop_body_start, nullptr, 0, "...to here");
 
-  path.add_event (loop_body_end, NULL_TREE, 0, "looping back...");
+  path.add_event (loop_body_end, nullptr, 0, "looping back...");
   path.connect_to_next_event ();
 
-  path.add_event (iter_test, NULL_TREE, 0, "...to here");
+  path.add_event (iter_test, nullptr, 0, "...to here");
 
   if (!path_events_have_column_data_p (path))
     return;
@@ -1751,17 +1688,17 @@ test_control_flow_3 (const line_table_case &case_,
   const location_t iter_next = t.get_line_and_columns (3, 22, 24);
 
   test_diagnostic_path path (event_pp);
-  path.add_event (iter_test, NULL_TREE, 0, "infinite loop here");
+  path.add_event (iter_test, nullptr, 0, "infinite loop here");
 
-  path.add_event (iter_test, NULL_TREE, 0, "looping from here...");
+  path.add_event (iter_test, nullptr, 0, "looping from here...");
   path.connect_to_next_event ();
 
-  path.add_event (iter_next, NULL_TREE, 0, "...to here");
+  path.add_event (iter_next, nullptr, 0, "...to here");
 
-  path.add_event (iter_next, NULL_TREE, 0, "looping back...");
+  path.add_event (iter_next, nullptr, 0, "looping back...");
   path.connect_to_next_event ();
 
-  path.add_event (iter_test, NULL_TREE, 0, "...to here");
+  path.add_event (iter_test, nullptr, 0, "...to here");
 
   if (!path_events_have_column_data_p (path))
     return;
@@ -1816,10 +1753,10 @@ assert_cfg_edge_path_streq (const location &loc,
 			    const char *expected_str)
 {
   test_diagnostic_path path (event_pp);
-  path.add_event (src_loc, NULL_TREE, 0, "from here...");
+  path.add_event (src_loc, nullptr, 0, "from here...");
   path.connect_to_next_event ();
 
-  path.add_event (dst_loc, NULL_TREE, 0, "...to here");
+  path.add_event (dst_loc, nullptr, 0, "...to here");
 
   if (!path_events_have_column_data_p (path))
     return;
@@ -2120,27 +2057,27 @@ test_control_flow_5 (const line_table_case &case_,
 
   test_diagnostic_path path (event_pp);
   /* (1) */
-  path.add_event (t.get_line_and_column (1, 6), NULL_TREE, 0,
+  path.add_event (t.get_line_and_column (1, 6), nullptr, 0,
 		  "following %qs branch (when %qs is non-NULL)...",
 		  "false", "arr");
   path.connect_to_next_event ();
 
   /* (2) */
-  path.add_event (t.get_line_and_columns (4, 8, 10, 12), NULL_TREE, 0,
+  path.add_event (t.get_line_and_columns (4, 8, 10, 12), nullptr, 0,
 		  "...to here");
 
   /* (3) */
-  path.add_event (t.get_line_and_columns (4, 15, 17, 19), NULL_TREE, 0,
+  path.add_event (t.get_line_and_columns (4, 15, 17, 19), nullptr, 0,
 		  "following %qs branch (when %qs)...",
 		  "true", "i < n");
   path.connect_to_next_event ();
 
   /* (4) */
-  path.add_event (t.get_line_and_column (5, 13), NULL_TREE, 0,
+  path.add_event (t.get_line_and_column (5, 13), nullptr, 0,
 		  "...to here");
 
   /* (5) */
-  path.add_event (t.get_line_and_columns (5, 33, 58), NULL_TREE, 0,
+  path.add_event (t.get_line_and_columns (5, 33, 58), nullptr, 0,
 		  "allocated here");
 
   if (!path_events_have_column_data_p (path))
@@ -2208,27 +2145,27 @@ test_control_flow_6 (const line_table_case &case_,
 
   test_diagnostic_path path (event_pp);
   /* (1) */
-  path.add_event (t.get_line_and_columns (6, 25, 35), NULL_TREE, 0,
+  path.add_event (t.get_line_and_columns (6, 25, 35), nullptr, 0,
 		  "allocated here");
 
   /* (2) */
-  path.add_event (t.get_line_and_columns (8, 13, 14, 17), NULL_TREE, 0,
+  path.add_event (t.get_line_and_columns (8, 13, 14, 17), nullptr, 0,
 		  "following %qs branch (when %qs)...",
 		  "true", "i <= 254");
   path.connect_to_next_event ();
 
   /* (3) */
-  path.add_event (t.get_line_and_columns (9, 5, 15, 17), NULL_TREE, 0,
+  path.add_event (t.get_line_and_columns (9, 5, 15, 17), nullptr, 0,
 		  "...to here");
 
   /* (4) */
-  path.add_event (t.get_line_and_columns (8, 13, 14, 17), NULL_TREE, 0,
+  path.add_event (t.get_line_and_columns (8, 13, 14, 17), nullptr, 0,
 		  "following %qs branch (when %qs)...",
 		  "true", "i <= 254");
   path.connect_to_next_event ();
 
   /* (5) */
-  path.add_event (t.get_line_and_columns (9, 5, 15, 17), NULL_TREE, 0,
+  path.add_event (t.get_line_and_columns (9, 5, 15, 17), nullptr, 0,
 		  "...to here");
 
   if (!path_events_have_column_data_p (path))
