From b7bd6b243c14d73995d38b00f578c70badda0a2a Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 19 May 2017 17:41:35 -0400
Subject: [PATCH 05/28] FIXME: enough BLT (from other branch) to compile

---
 gcc/Makefile.in             |   1 +
 gcc/blt.c                   | 383 ++++++++++++++++++++++++++++++++++++++++++++
 gcc/blt.def                 |  83 ++++++++++
 gcc/blt.h                   | 122 ++++++++++++++
 gcc/c-family/c-opts.c       |   2 +-
 gcc/c-family/c.opt          |   8 +
 gcc/c/c-decl.c              |  13 +-
 gcc/c/c-parser.c            | 134 +++++++++++++++-
 gcc/c/c-tree.h              |  11 +-
 gcc/c/c-typeck.c            |   1 +
 gcc/cp/cp-tree.h            |   5 +
 gcc/cp/decl.c               |  27 +++-
 gcc/cp/parser.c             | 336 ++++++++++++++++++++++++++++++++++++--
 gcc/cp/parser.h             |   8 +
 gcc/cp/pt.c                 |   8 +
 gcc/cp/typeck.c             |   1 +
 gcc/diagnostic-show-locus.c |  48 ++++--
 17 files changed, 1155 insertions(+), 36 deletions(-)
 create mode 100644 gcc/blt.c
 create mode 100644 gcc/blt.def
 create mode 100644 gcc/blt.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index efca916..519ada0 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1219,6 +1219,7 @@ OBJS = \
 	auto-profile.o \
 	bb-reorder.o \
 	bitmap.o \
+	blt.o \
 	bt-load.o \
 	builtins.o \
 	caller-save.o \
diff --git a/gcc/blt.c b/gcc/blt.c
new file mode 100644
index 0000000..07b7819
--- /dev/null
+++ b/gcc/blt.c
@@ -0,0 +1,383 @@
+/* Extra location information.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   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 "tree.h"
+#include "pretty-print.h"
+#include "diagnostic.h"
+#include "diagnostic-color.h"
+#include "blt.h"
+
+typedef hash_map <tree, blt_node *> tree_to_blt_map_t;
+static tree_to_blt_map_t *tree_to_blt_map;
+
+static const char *blt_kind_to_name (enum blt_kind kind);
+
+/* FIXME.  */
+
+blt_node::blt_node (enum blt_kind kind, location_t start)
+: m_kind (kind), m_parent (NULL), m_first_child (NULL), m_last_child (NULL),
+  m_prev_sibling (NULL), m_next_sibling (NULL),
+  m_start (start), m_finish (UNKNOWN_LOCATION), m_tree (NULL_TREE)
+{
+}
+
+/* FIXME.  */
+
+void
+blt_node::add_child (blt_node *child)
+{
+  gcc_assert (child->m_prev_sibling == NULL);
+  gcc_assert (child->m_next_sibling == NULL);
+  gcc_assert (child->m_parent == NULL);
+
+  if (m_last_child)
+    {
+      m_last_child->m_next_sibling = child;
+      child->m_prev_sibling = m_last_child;
+    }
+  else
+    {
+      gcc_assert (m_first_child == NULL);
+      m_first_child = child;
+    }
+
+  m_last_child = child;
+  child->m_parent = this;
+}
+
+
+/* Convert OLD to an orphan, and take over parenthood of NEW,
+   putting NEW in OLD's place.  */
+// FIXME: motivated by the fixup in C++ parser of
+// block-declaration => function-definition
+
+void
+blt_node::replace_child (blt_node *old, blt_node *new_)
+{
+  gcc_assert (old);
+  gcc_assert (old->m_parent == this);
+  gcc_assert (new_);
+  assert_invariants ();
+  old->assert_invariants ();
+  new_->assert_invariants ();
+
+  blt_node *old_prev_sibling = old->m_prev_sibling;
+  blt_node *old_next_sibling = old->m_next_sibling;
+
+  old->make_orphan ();
+  new_->make_orphan ();
+
+  new_->m_prev_sibling = old_prev_sibling;
+  new_->m_next_sibling = old_next_sibling;
+
+  if (old_prev_sibling == NULL)
+    m_first_child = new_;
+  if (old_next_sibling == NULL)
+    m_last_child = new_;
+
+  assert_invariants ();
+  old->assert_invariants ();
+  new_->assert_invariants ();
+}
+
+/* FIXME.  */
+
+void
+blt_node::make_orphan ()
+{
+  assert_invariants ();
+
+  if (m_parent)
+    {
+      if (m_prev_sibling)
+	{
+	  m_prev_sibling->m_next_sibling = m_next_sibling;
+	  m_prev_sibling = NULL;
+	}
+      else
+	m_parent->m_first_child = m_next_sibling;
+      if (m_next_sibling)
+	{
+	  m_next_sibling->m_prev_sibling = m_prev_sibling;
+	  m_next_sibling = NULL;
+	}
+      else
+	m_parent->m_last_child = m_prev_sibling;
+    }
+  m_parent = NULL;
+
+  assert_invariants ();
+}
+
+/* FIXME.  */
+
+void
+blt_node::set_tree (tree t)
+{
+  m_tree = t;
+
+  /* Add to mapping.  */
+  if (!t)
+    return;
+
+  if (!tree_to_blt_map)
+    tree_to_blt_map = new tree_to_blt_map_t ();
+  tree_to_blt_map->put (t, this);
+}
+
+/* FIXME.  */
+
+void
+blt_node::dump (FILE *file) const
+{
+  pretty_printer pp;
+  pp_show_color (&pp) = pp_show_color (global_dc->printer);
+  pp_format_decoder (&pp) = pp_format_decoder (global_dc->printer);
+  pp.buffer->stream = file;
+  dump (&pp, "", NULL, true);
+  pp_flush (&pp);
+}
+
+/* FIXME.  */
+
+void
+blt_node::dump (pretty_printer *pp, const char *prefix,
+		const blt_node *parent, bool is_last_child) const
+{
+  if (parent)
+    {
+      // FIXME: colorize hierachical ASCII art
+      const char *tail = is_last_child ? "`-" : "|-";
+      pp_printf (pp, "%r%s%s%R", "note", prefix, tail); // FIXME: dedicated color code?
+    }
+  pp_printf (pp, "%r%s%R %p", "error", blt_kind_to_name (m_kind),
+	     (const void *)this); // FIXME: dedicated color code?
+
+  location_t parent_start_loc = parent ? parent->m_start : UNKNOWN_LOCATION;
+  location_t parent_finish_loc = parent ? parent->m_finish : UNKNOWN_LOCATION;
+
+  /* Dump location information, eliding commonality with parent.  */
+  {
+    pp_printf (pp, " %r<", "warning"); // FIXME: dedicated color code?
+
+    expanded_location el_start = expand_location (m_start);
+    expanded_location el_parent = expand_location (parent_start_loc);
+
+    if (el_start.file != el_parent.file)
+      /* We don't use %qs or %< and %> here, to avoid affecting
+         colorization.  */
+      pp_printf (pp, "%s:", el_start.file);
+    pp_printf (pp, "%i:%i", el_start.line, el_start.column);
+    if (m_finish != m_start)
+      {
+        pp_printf (pp, "-");
+        expanded_location el_finish = expand_location (m_finish);
+        if (el_finish.file && el_finish.file != el_start.file)
+          pp_printf (pp, "%s:", el_finish.file);
+        pp_printf (pp, "%i:%i", el_finish.line, el_finish.column);
+      }
+
+    pp_printf (pp, ">%R");
+  }
+
+  if (m_tree)
+    // FIXME: format code:
+    // FIXME: add get_tree_code_name to both
+#if 1
+    pp_printf (pp, " tree: %p %r<%s>%R", (void *)m_tree,
+	       "warning", // FIXME: dedicated color code?
+	       get_tree_code_name (TREE_CODE (m_tree)));
+#else
+    // seems to work for C++:
+    pp_printf (pp, " tree: %p %r<%s>%R %qE", (void *)m_tree,
+	       "warning", // FIXME: dedicated color code?
+	       get_tree_code_name (TREE_CODE (m_tree)),
+	       m_tree);
+#endif
+
+  const char *new_prefix;
+  if (parent)
+    new_prefix = ACONCAT ((prefix, is_last_child ? "  " : "|  ", NULL));
+  else
+    new_prefix = prefix;
+
+  /* Show source code.  */
+  if (m_start != parent_start_loc || m_finish != parent_finish_loc)
+    {
+      location_t range = get_range ();
+      rich_location richloc (line_table, range);
+      diagnostic_context dc;
+      memset (&dc, 0, sizeof (dc));
+      dc.printer = pp;
+      dc.show_caret = true;
+      dc.caret_chars[0] = '^';
+      diagnostic_set_caret_max_width (&dc, pp_line_cutoff (pp));
+      const char *saved_prefix = pp->prefix;
+      const char *source_prefix;
+      const char *begin_color = colorize_start (pp_show_color (pp), "note");
+      const char *end_color = colorize_stop (pp_show_color (pp));
+      source_prefix = ACONCAT ((begin_color, new_prefix, "|:", end_color, NULL));
+      pp_set_prefix (pp, source_prefix);
+      pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
+      diagnostic_show_locus (&dc, &richloc, DK_NOTE);
+      pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_NEVER;
+      pp_set_prefix (pp, saved_prefix);
+      /* diagnostic_show_locus expects to add a newline at the start
+	 and ends with a newline.  */
+    }
+  else
+    pp_newline (pp);
+
+  for (blt_node *child = m_first_child; child; child = child->m_next_sibling)
+    {
+      bool is_last_child = child == m_last_child;
+      child->dump (pp, new_prefix, this, is_last_child);
+    }
+}
+
+/* FIXME.  */
+
+const char *
+blt_node::get_name () const
+{
+  return blt_kind_to_name (m_kind);
+}
+
+/* FIXME.  */
+
+location_t
+blt_node::get_range () const
+{
+  return make_location (m_start, m_start, m_finish);
+}
+
+/* FIXME.  */
+
+blt_node *
+blt_node::get_first_child_of_kind (enum blt_kind kind) const
+{
+  for (blt_node *child = m_first_child; child; child = child->m_next_sibling)
+    if (kind == child->m_kind)
+      return child;
+  return NULL;
+}
+
+void
+blt_node::get_children_of_kind (auto_vec<blt_node *> &out,
+				enum blt_kind kind) const
+{
+  for (blt_node *child = m_first_child; child; child = child->m_next_sibling)
+    if (kind == child->m_kind)
+      out.safe_push (child);
+}
+
+/* FIXME.  */
+
+blt_node *
+blt_node::get_ancestor_of_kind (enum blt_kind kind) const
+{
+  for (blt_node *iter = m_parent; iter; iter = iter->m_parent)
+    if (kind == iter->m_kind)
+      return iter;
+  return NULL;
+}
+
+/* FIXME.  */
+
+void
+blt_node::assert_invariants () const
+{
+  if (m_parent)
+    {
+      if (m_next_sibling)
+	gcc_assert (m_parent);
+      else
+	gcc_assert (m_parent->m_last_child == this);
+      if (m_prev_sibling)
+	gcc_assert (m_parent);
+      else
+	gcc_assert (m_parent->m_first_child == this);
+    }
+  else
+    {
+      gcc_assert (m_next_sibling == NULL);
+      gcc_assert (m_prev_sibling == NULL);
+    }
+}
+
+/* FIXME.  */
+
+blt_node *
+blt_get_node_for_tree (tree t)
+{
+  if (!t)
+    return NULL;
+  if (!tree_to_blt_map)
+    return NULL;
+  blt_node **slot = tree_to_blt_map->get (t);
+  if (!slot)
+    return NULL;
+  return *slot;
+}
+
+/* FIXME.  */
+
+void
+blt_set_node_for_tree (tree t, blt_node *asnode)
+{
+  if (!t)
+    return;
+  if (!asnode)
+    return;
+
+  if (asnode->get_tree () == NULL)
+    asnode->set_tree (t);
+  else
+    {
+      /* Don't attempt to change; multiple tree nodes can
+	 reference an blt_node *, but an blt_node * references
+	 at most one tree node (e.g. template instantiations).  */
+      gcc_assert (tree_to_blt_map);
+      tree_to_blt_map->get_or_insert (t) = asnode;
+    }
+}
+
+
+static const char * const blt_kind_names[] = {
+#define DEF_BLT_NODE(ENUM_NAME, PRETTY_NAME) PRETTY_NAME,
+#include "blt.def"
+#undef DEF_BLT_NODE
+};
+
+static const char *
+blt_kind_to_name (enum blt_kind kind)
+{
+  return blt_kind_names[kind];
+}
+
+/* FIXME.  */
+
+void
+debug (blt_node *node)
+{
+  node->dump (stderr);
+}
diff --git a/gcc/blt.def b/gcc/blt.def
new file mode 100644
index 0000000..f1f3795
--- /dev/null
+++ b/gcc/blt.def
@@ -0,0 +1,83 @@
+/* Bonus location trees.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* The first set of DEF_BLT_NODE corresponds to enum cpp_ttype.  */
+
+#ifndef TTYPE_TABLE
+#error TTYPE_TABLE not defined
+#endif
+
+#define OP(e, s) DEF_BLT_NODE (BLT_TOKEN_OP_##e, s "-token")
+#define TK(e, s) DEF_BLT_NODE (BLT_TOKEN_TK_##e, #e "-token")
+
+TTYPE_TABLE
+
+#undef OP
+#undef TK
+
+DEF_BLT_NODE (BLT_KEYWORD, "keyword")
+
+/* Additional nodes kinds, beyond enum cpp_ttype.
+   These are named after non-terminals within the C and C++ grammar.
+   They're just IDs; they don't need to mean anything for other languages.  */
+
+DEF_BLT_NODE (BLT_ASM_SPECIFICATION, "asm-specification")
+DEF_BLT_NODE (BLT_ASSIGNMENT_EXPRESSION, "assignment-expression")
+DEF_BLT_NODE (BLT_BLOCK_DECLARATION, "block-declaration")
+DEF_BLT_NODE (BLT_CLASS_HEAD, "class-head")
+DEF_BLT_NODE (BLT_CLASS_KEY, "class-key")
+DEF_BLT_NODE (BLT_CLASS_SPECIFIER, "class-specifier")
+DEF_BLT_NODE (BLT_CV_QUALIFIER, "cv-qualifier")
+DEF_BLT_NODE (BLT_CV_QUALIFIER_SEQ, "cv-qualifier-seq")
+DEF_BLT_NODE (BLT_DECLARATION, "declaration")
+DEF_BLT_NODE (BLT_DECLARATION_SEQ, "declaration-seq")
+DEF_BLT_NODE (BLT_DECLARATOR, "declarator")
+DEF_BLT_NODE (BLT_DECL_SPECIFIER, "decl-specifier")
+DEF_BLT_NODE (BLT_DECL_SPECIFIER_SEQ, "decl-specifier-seq")
+DEF_BLT_NODE (BLT_DIRECT_DECLARATOR, "direct-declarator")
+DEF_BLT_NODE (BLT_EXCEPTION_DECLARATION, "exception-declaration")
+DEF_BLT_NODE (BLT_EXPLICIT_INSTANTIATION, "explicit-instantiation")
+DEF_BLT_NODE (BLT_EXPLICIT_SPECIALIZATION, "explicit-specialization")
+DEF_BLT_NODE (BLT_EXPRESSION, "expression")
+DEF_BLT_NODE (BLT_EXPRESSION_LIST, "expression-list")
+DEF_BLT_NODE (BLT_EXTERNAL_DECLARATION, "external-declaration")
+DEF_BLT_NODE (BLT_FUNCTION_DEFINITION, "function-definition")
+DEF_BLT_NODE (BLT_FUNCTION_TRY_BLOCK, "function-try-block")
+DEF_BLT_NODE (BLT_HANDLER, "handler")
+DEF_BLT_NODE (BLT_HANDLER_SEQ, "handler-seq")
+DEF_BLT_NODE (BLT_IDENTIFIER, "identifier")
+DEF_BLT_NODE (BLT_ID_EXPRESSION, "id-expression")
+DEF_BLT_NODE (BLT_MEMBER_DECLARATION, "member-declaration")
+DEF_BLT_NODE (BLT_NONEMPTY_EXPR_LIST, "nonempty-expr-list")
+DEF_BLT_NODE (BLT_PARAMETER_DECLARATION, "parameter-declaration")
+DEF_BLT_NODE (BLT_PARAMETER_DECLARATION_CLAUSE, "parameter-declaration-clause")
+DEF_BLT_NODE (BLT_PARAMETER_DECLARATION_LIST, "parameter-declaration-list")
+DEF_BLT_NODE (BLT_PARAMETER_LIST, "parameter-list")
+DEF_BLT_NODE (BLT_POSTFIX_EXPRESSION, "postfix-expression")
+DEF_BLT_NODE (BLT_PRIMARY_EXPRESSION, "primary-expression")
+DEF_BLT_NODE (BLT_SIMPLE_DECLARATION, "simple-declaration")
+DEF_BLT_NODE (BLT_TEMPLATE_DECLARATION, "template-declaration")
+DEF_BLT_NODE (BLT_TEMPLATE_PARAMETER_LIST, "template-parameter-list")
+DEF_BLT_NODE (BLT_THROW_EXPRESSION, "throw-expression")
+DEF_BLT_NODE (BLT_TRANSLATION_UNIT, "translation-unit")
+DEF_BLT_NODE (BLT_TRY_BLOCK, "try-block")
+DEF_BLT_NODE (BLT_TYPE_ID_LIST, "type-id-list")
+DEF_BLT_NODE (BLT_TYPE_SPECIFIER, "type-specifier")
+DEF_BLT_NODE (BLT_UNARY_EXPRESSION, "unary-expression")
+DEF_BLT_NODE (BLT_UNQUALIFIED_ID, "unqualified-id")
diff --git a/gcc/blt.h b/gcc/blt.h
new file mode 100644
index 0000000..909dd4e
--- /dev/null
+++ b/gcc/blt.h
@@ -0,0 +1,122 @@
+/* Bonus location tree information.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   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_BLT_H
+#define GCC_BLT_H
+
+/* Sometimes we need additional location information.
+
+   The "tree" type represents a node within an abstract syntax tree,
+   but this is sometimes too abstract - sometimes we want the locations
+   of the clauses and tokens that are abstracted away by the frontends.
+
+   In theory we could generate the full parse tree ("concrete syntax tree"),
+   showing every production followed to parse the input, but it is likely
+   to be unwieldy: large and difficult to navigate.
+
+   So this file implements a middle-ground: an additional tree of parse
+   information, more concrete than "tree", but not the fully parse tree.
+
+   There is a partial mapping between "tree" and blt_node: a blt_node
+   can reference a tree, and a tree can reference a blt_node (though
+   typically the mapping is very sparse; most don't).  This allows up
+   to go from e.g. a function_decl in the tree world and navigate
+   pertinent parts of the syntax that was used to declare it.
+
+   Working title = "BLT" as a backronym for "bonus location tree" (but
+   actually a reference to a sandwich) - doesn't clash with anything else
+   in the source tree.  */
+
+#include "cpplib.h"
+
+/* An ID for a kind of node within the tree.  */
+
+enum blt_kind
+{
+#define DEF_BLT_NODE(ENUM_NAME, PRETTY_NAME) ENUM_NAME,
+#include "blt.def"
+#undef DEF_BLT_NODE
+};
+
+/* A syntax node: either a token, a non-terminal, or a simplified set of
+   non-terminals.  */
+
+class blt_node
+{
+public:
+  blt_node (enum blt_kind kind, location_t start);
+
+  /* Structural manipulation.  */
+  void add_child (blt_node *child);
+  void replace_child (blt_node *old, blt_node *new_);
+  void make_orphan ();
+
+  /* Modification.  */
+
+  void set_finish (location_t loc) { m_finish = loc; }
+  void set_tree (tree t);
+  void set_kind (enum blt_kind kind) { m_kind = kind; }
+
+  /* Dumping.  */
+  void dump (FILE *) const;
+  void dump (pretty_printer *pp, const char *prefix,
+	     const blt_node *parent, bool is_last_child) const;
+
+  /* Accessors.  */
+  enum blt_kind get_kind () const { return m_kind; }
+  const char *get_name () const;
+  blt_node *get_parent () const { return m_parent; }
+  location_t get_start () const { return m_start; }
+  location_t get_finish () const { return m_finish; }
+  location_t get_range () const;
+  tree get_tree () const { return m_tree; }
+
+  blt_node *get_first_child_of_kind (enum blt_kind kind) const;
+  void get_children_of_kind (auto_vec<blt_node *> &out,
+			     enum blt_kind kind) const;
+
+  blt_node *get_ancestor_of_kind (enum blt_kind kind) const;
+
+private:
+  void assert_invariants () const;
+
+private:
+  enum blt_kind m_kind;
+  blt_node *m_parent;
+  blt_node *m_first_child;
+  blt_node *m_last_child;
+  blt_node *m_prev_sibling;
+  blt_node *m_next_sibling;
+#if 1
+  location_t m_start;
+  location_t m_finish;
+#else
+  // Tokens are currently released after lexing...
+  cp_token *m_first_token;
+  cp_token *m_last_token;
+#endif
+  tree m_tree;
+};
+
+extern blt_node *blt_get_node_for_tree (tree);
+extern void blt_set_node_for_tree (tree, blt_node *);
+
+extern void DEBUG_FUNCTION debug (blt_node *);
+
+#endif  /* GCC_BLT_H  */
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index 1657e7a..a0b86c2 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -163,11 +163,11 @@ static void
 c_diagnostic_finalizer (diagnostic_context *context,
 			diagnostic_info *diagnostic)
 {
+  pp_destroy_prefix (context->printer);
   diagnostic_show_locus (context, diagnostic->richloc, diagnostic->kind);
   /* By default print macro expansion contexts in the diagnostic
      finalizer -- for tokens resulting from macro expansion.  */
   virt_loc_aware_diagnostic_finalizer (context, diagnostic);
-  pp_destroy_prefix (context->printer);
   pp_flush (context->printer);
 }
 
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index e0ad3ab..6f15b5d 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1209,6 +1209,10 @@ fasm
 C ObjC C++ ObjC++ Var(flag_no_asm, 0)
 Recognize the \"asm\" keyword.
 
+fblt
+C ObjC C++ ObjC++ Var(flag_blt)
+Capture additional location information.  FIXME: name.
+
 ; Define extra predefined macros for use in libgcc.
 fbuilding-libgcc
 C ObjC C++ ObjC++ Undocumented Var(flag_building_libgcc)
@@ -1382,6 +1386,10 @@ fdump-ada-spec-slim
 C ObjC C++ ObjC++ RejectNegative Var(flag_dump_ada_spec_slim)
 Write all declarations as Ada code for the given file only.
 
+fdump-blt
+C ObjC C++ ObjC++ Var(flag_dump_blt)
+Dump the extra location information from -fblt.  FIXME: name.
+
 felide-constructors
 C++ ObjC++ Var(flag_elide_constructors) Init(1)
 
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 50da185..ff27e55 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "spellcheck-tree.h"
 #include "gcc-rich-location.h"
 #include "asan.h"
+#include "blt.h"
 
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
 enum decl_context
@@ -4503,6 +4504,7 @@ build_array_declarator (location_t loc,
 	}
       current_scope->had_vla_unspec = true;
     }
+  declarator->bltnode = NULL;
   return declarator;
 }
 
@@ -4627,6 +4629,8 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
 			 deprecated_state);
   if (!decl || decl == error_mark_node)
     return NULL_TREE;
+  if (declarator->bltnode)
+    declarator->bltnode->set_tree (decl);
 
   if (expr)
     add_stmt (fold_convert (void_type_node, expr));
@@ -8527,6 +8531,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
 
   decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL,
 			  &attributes, NULL, NULL, DEPRECATED_NORMAL);
+  if (declarator->bltnode)
+    declarator->bltnode->set_tree (decl1);
   invoke_plugin_callbacks (PLUGIN_START_PARSE_FUNCTION, decl1);
 
   /* If the declarator is not suitable for a function definition,
@@ -9645,6 +9651,7 @@ build_attrs_declarator (tree attrs, struct c_declarator *target)
   ret->kind = cdk_attrs;
   ret->declarator = target;
   ret->u.attrs = attrs;
+  ret->bltnode = NULL;
   return ret;
 }
 
@@ -9653,12 +9660,14 @@ build_attrs_declarator (tree attrs, struct c_declarator *target)
 
 struct c_declarator *
 build_function_declarator (struct c_arg_info *args,
-			   struct c_declarator *target)
+			   struct c_declarator *target,
+			   blt_node *bltnode)
 {
   struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator);
   ret->kind = cdk_function;
   ret->declarator = target;
   ret->u.arg_info = args;
+  ret->bltnode = bltnode;
   return ret;
 }
 
@@ -9674,6 +9683,7 @@ build_id_declarator (tree ident)
   ret->u.id = ident;
   /* Default value - may get reset to a more precise location. */
   ret->id_loc = input_location;
+  ret->bltnode = NULL;
   return ret;
 }
 
@@ -9700,6 +9710,7 @@ make_pointer_declarator (struct c_declspecs *type_quals_attrs,
   ret->kind = cdk_pointer;
   ret->declarator = itarget;
   ret->u.pointer_quals = quals;
+  ret->bltnode = NULL;
   return ret;
 }
 
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index f8fbc92..760bd42 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -65,6 +65,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "read-rtl-function.h"
 #include "run-rtl-passes.h"
 #include "intl.h"
+#include "blt.h"
 
 /* We need to walk over decls with incomplete struct/union/enum types
    after parsing the whole translation unit.
@@ -206,8 +207,112 @@ struct GTY(()) c_parser {
   /* Buffer to hold all the tokens from parsing the vector attribute for the
      SIMD-enabled functions (formerly known as elemental functions).  */
   vec <c_token, va_gc> *cilk_simd_fn_tokens;
+
+  location_t last_token_location;
+  blt_node * GTY((skip)) blt_root_node;
+  blt_node * GTY((skip)) blt_current_node;
+};
+
+/* FIXME.  */
+// RAII-style highlighting of the AST.
+
+/* FIXME.  */
+
+class auto_blt_node
+{
+public:
+  auto_blt_node (c_parser* parser, enum blt_kind kind);
+  ~auto_blt_node ();
+
+  void set_tree (tree node);
+
+private:
+  c_parser *m_parser;
 };
 
+/* FIXME.  */
+
+#define AUTO_BLT_NODE(PARSER, KIND) \
+  auto_blt_node tmp_blt_node ((PARSER), (KIND))
+
+#define CURRENT_BLT_NODE (parser->blt_current_node)
+
+#define BLT_ADD_NEXT_TOKEN(PARSER) \
+  add_next_token (PARSER)
+
+#define BLT_SET_TREE(TREE_NODE) \
+  tmp_blt_node.set_tree (TREE_NODE);
+
+#if 0
+static void
+add_next_token (c_parser *parser)
+{
+  if (!flag_blt)
+    return;
+
+  c_token *token = c_parser_peek_token (parser);
+  blt_node *parent = parser->blt_current_node;
+  blt_node *node = new blt_node (BLT_TOKEN, token->location);
+  parent->add_child (node);
+  // FIXME: get a meaningful string for the token
+  node->set_finish (token->location);
+}
+#endif
+
+/* FIXME.  */
+
+auto_blt_node::auto_blt_node (c_parser *parser, enum blt_kind kind)
+: m_parser (parser)
+{
+  if (!flag_blt)
+    return;
+
+  c_token *first_token = c_parser_peek_token (parser);
+  blt_node *parent = parser->blt_current_node;
+  blt_node *node = new blt_node (kind, first_token->location);
+  parser->blt_current_node = node;
+  if (parent)
+    parent->add_child (node);
+  else
+    parser->blt_root_node = node;
+}
+
+/* FIXME.  */
+
+auto_blt_node::~auto_blt_node ()
+{
+  if (!flag_blt)
+    return;
+
+  blt_node *node = m_parser->blt_current_node;
+  node->set_finish (m_parser->last_token_location);
+
+  if (0)
+    {
+      location_t start = node->get_start ();
+      location_t finish = node->get_finish ();
+      location_t range = make_location (start, start, finish);
+      inform (range, "%qs", node->get_name ());
+    }
+
+#if 0
+  if (m_expr_ptr)
+    node->set_tree (m_expr_ptr->get_value ());
+#endif
+
+  m_parser->blt_current_node = node->get_parent ();
+}
+
+void
+auto_blt_node::set_tree (tree tree_node)
+{
+  if (!flag_blt)
+    return;
+
+  blt_node *node = m_parser->blt_current_node;
+  node->set_tree (tree_node);
+}
+
 /* Return a pointer to the Nth token in PARSERs tokens_buf.  */
 
 c_token *
@@ -770,6 +875,7 @@ c_parser_consume_token (c_parser *parser)
   gcc_assert (parser->tokens[0].type != CPP_EOF);
   gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL);
   gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA);
+  parser->last_token_location = parser->tokens[0].location;
   if (parser->tokens != &parser->tokens_buf[0])
     parser->tokens++;
   else if (parser->tokens_avail == 2)
@@ -1336,6 +1442,8 @@ static void c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass);
 static void
 c_parser_translation_unit (c_parser *parser)
 {
+  AUTO_BLT_NODE (parser, BLT_TRANSLATION_UNIT);
+
   if (c_parser_next_token_is (parser, CPP_EOF))
     {
       pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic,
@@ -1388,6 +1496,8 @@ c_parser_translation_unit (c_parser *parser)
 static void
 c_parser_external_declaration (c_parser *parser)
 {
+  AUTO_BLT_NODE (parser, BLT_EXTERNAL_DECLARATION);
+
   int ext;
   switch (c_parser_peek_token (parser)->type)
     {
@@ -3393,6 +3503,8 @@ struct c_declarator *
 c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
 		     bool *seen_id)
 {
+  AUTO_BLT_NODE (parser, BLT_DECLARATOR);
+
   /* Parse any initial pointer part.  */
   if (c_parser_next_token_is (parser, CPP_MULT))
     {
@@ -3419,6 +3531,8 @@ static struct c_declarator *
 c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
 			    bool *seen_id)
 {
+  AUTO_BLT_NODE (parser, BLT_DIRECT_DECLARATOR);
+
   /* The direct declarator must start with an identifier (possibly
      omitted) or a parenthesized declarator (possibly abstract).  In
      an ordinary declarator, initial parentheses must start a
@@ -3462,6 +3576,7 @@ c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
     {
       struct c_declarator *inner
 	= build_id_declarator (c_parser_peek_token (parser)->value);
+      inner->bltnode = CURRENT_BLT_NODE;
       *seen_id = true;
       inner->id_loc = c_parser_peek_token (parser)->location;
       c_parser_consume_token (parser);
@@ -3498,7 +3613,8 @@ c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
 	    {
 	      inner
 		= build_function_declarator (args,
-					     build_id_declarator (NULL_TREE));
+					     build_id_declarator (NULL_TREE),
+					     CURRENT_BLT_NODE);
 	      return c_parser_direct_declarator_inner (parser, *seen_id,
 						       inner);
 	    }
@@ -3646,7 +3762,7 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
 	return NULL;
       else
 	{
-	  inner = build_function_declarator (args, inner);
+	  inner = build_function_declarator (args, inner, CURRENT_BLT_NODE);
 	  return c_parser_direct_declarator_inner (parser, id_present, inner);
 	}
     }
@@ -3661,6 +3777,8 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
 static struct c_arg_info *
 c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs)
 {
+  AUTO_BLT_NODE (parser, BLT_PARAMETER_LIST);
+
   push_scope ();
   declare_parm_level ();
   /* If the list starts with an identifier, it is an identifier list.
@@ -3832,6 +3950,8 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr)
 static struct c_parm *
 c_parser_parameter_declaration (c_parser *parser, tree attrs)
 {
+  AUTO_BLT_NODE (parser, BLT_PARAMETER_DECLARATION);
+
   struct c_declspecs *specs;
   struct c_declarator *declarator;
   tree prefix_attrs;
@@ -6422,6 +6542,8 @@ static struct c_expr
 c_parser_expr_no_commas (c_parser *parser, struct c_expr *after,
 			 tree omp_atomic_lhs)
 {
+  AUTO_BLT_NODE (parser, BLT_ASSIGNMENT_EXPRESSION);
+
   struct c_expr lhs, rhs, ret;
   enum tree_code code;
   location_t op_location, exp_location;
@@ -8655,6 +8777,8 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
 static struct c_expr
 c_parser_expression (c_parser *parser)
 {
+  AUTO_BLT_NODE (parser, BLT_EXPRESSION);
+
   location_t tloc = c_parser_peek_token (parser)->location;
   struct c_expr expr;
   expr = c_parser_expr_no_commas (parser, NULL);
@@ -8742,6 +8866,8 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
 		    vec<location_t> *locations,
 		    unsigned int *literal_zero_mask)
 {
+  AUTO_BLT_NODE (parser, BLT_NONEMPTY_EXPR_LIST);
+
   vec<tree, va_gc> *ret;
   vec<tree, va_gc> *orig_types;
   struct c_expr expr;
@@ -18166,6 +18292,10 @@ c_parse_file (void)
     using_eh_for_cleanups ();
 
   c_parser_translation_unit (the_parser);
+
+  if (flag_blt && flag_dump_blt)
+    the_parser->blt_root_node->dump (stderr);
+
   the_parser = NULL;
 }
 
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index a8197eb..86a22fa 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-common.h"
 #include "diagnostic.h"
 
+class blt_node;
+
 /* struct lang_identifier is private to c-decl.c, but langhooks.c needs to
    know how big it is.  This is sanity-checked in c-decl.c.  */
 #define C_SIZEOF_STRUCT_LANG_IDENTIFIER \
@@ -146,6 +148,11 @@ struct c_expr
      of this expression.  */
   location_t get_start () const { return src_range.m_start; }
   location_t get_finish () const { return src_range.m_finish; }
+  location_t get_location () const
+  {
+    return make_location (src_range.m_start, src_range.m_start,
+			  src_range.m_finish);
+  }
 
   /* Set the value to error_mark_node whilst ensuring that src_range
      is initialized.  */
@@ -451,6 +458,7 @@ struct c_declarator {
     /* For attributes.  */
     tree attrs;
   } u;
+  blt_node *bltnode;
 };
 
 /* A type name.  */
@@ -577,7 +585,8 @@ extern struct c_parm *build_c_parm (struct c_declspecs *, tree,
 extern struct c_declarator *build_attrs_declarator (tree,
 						    struct c_declarator *);
 extern struct c_declarator *build_function_declarator (struct c_arg_info *,
-						       struct c_declarator *);
+						       struct c_declarator *,
+						       blt_node *);
 extern struct c_declarator *build_id_declarator (tree);
 extern struct c_declarator *make_pointer_declarator (struct c_declspecs *,
 						     struct c_declarator *);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 4d067e9..9c2d98a 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "spellcheck-tree.h"
 #include "gcc-rich-location.h"
 #include "asan.h"
+#include "blt.h"
 
 /* Possible cases of implicit bad conversions.  Used to select
    diagnostic messages in convert_for_assignment.  */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0da8a5c..c4fecf3 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -25,6 +25,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "hard-reg-set.h"
 #include "function.h"
 
+class blt_node;
+
 /* In order for the format checking to accept the C++ front end
    diagnostic framework extensions, you must include this file before
    diagnostic-core.h, not after.  We override the definition of GCC_DIAG_STYLE
@@ -5699,6 +5701,8 @@ struct cp_parameter_declarator {
   tree default_argument;
   /* True iff this is a template parameter pack.  */
   bool template_parameter_pack_p;
+  /* FIXME.  */
+  blt_node *asnode;
 };
 
 /* A declarator.  */
@@ -5774,6 +5778,7 @@ struct cp_declarator {
       bool rvalue_ref;
     } reference;
   } u;
+  blt_node *asnode;
 };
 
 /* A level of template instantiation.  */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 5b8e6a2..8237555 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -52,6 +52,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "gimplify.h"
 #include "asan.h"
+#include "blt.h"
 
 /* Possible cases of bad specifiers type used by bad_specifiers. */
 enum bad_spec_place {
@@ -9876,12 +9877,12 @@ name_unnamed_type (tree type, tree decl)
    declarator, in cases like "struct S;"), or the ERROR_MARK_NODE if an
    error occurs. */
 
-tree
-grokdeclarator (const cp_declarator *declarator,
-		cp_decl_specifier_seq *declspecs,
-		enum decl_context decl_context,
-		int initialized,
-		tree* attrlist)
+static tree
+grokdeclarator_1 (const cp_declarator *declarator,
+		  cp_decl_specifier_seq *declspecs,
+		  enum decl_context decl_context,
+		  int initialized,
+		  tree* attrlist)
 {
   tree type = NULL_TREE;
   int longlong = 0;
@@ -12349,6 +12350,20 @@ grokdeclarator (const cp_declarator *declarator,
     return decl;
   }
 }
+
+tree
+grokdeclarator (const cp_declarator *declarator,
+		cp_decl_specifier_seq *declspecs,
+		enum decl_context decl_context,
+		int initialized,
+		tree* attrlist)
+{
+  tree result = grokdeclarator_1 (declarator, declspecs, decl_context,
+				  initialized, attrlist);
+  if (declarator && declarator->asnode)
+    declarator->asnode->set_tree (result);
+  return result;
+}
 
 /* Subroutine of start_function.  Ensure that each of the parameter
    types (as listed in PARMS) is complete, as is required for a
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 88d0b2b..4c51be5 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cp-cilkplus.h"
 #include "gcc-rich-location.h"
 #include "tree-iterator.h"
+#include "blt.h"
 
 
 /* The lexer.  */
@@ -1348,6 +1349,139 @@ cp_token_cache_new (cp_token *first, cp_token *last)
   return cache;
 }
 
+
+
+/* FIXME.  */
+// RAII-style highlighting of the AST.
+
+/* FIXME.  */
+
+class auto_blt_node
+{
+public:
+  auto_blt_node (cp_parser* parser, enum blt_kind kind,
+                 cp_expr *expr_ptr = NULL);
+  ~auto_blt_node ();
+
+  void set_tree (tree node);
+
+private:
+  cp_parser *m_parser;
+  cp_expr *m_expr_ptr;
+  blt_node *m_parent;
+};
+
+/* FIXME.  */
+
+#define AUTO_BLT_NODE(PARSER, KIND) \
+  auto_blt_node tmp_blt_node ((PARSER), (KIND))
+
+#define AUTO_BLT_NODE_WITH_RETURN(PARSER, KIND, ADDR_OF_CP_EXPR) \
+  auto_blt_node tmp_blt_node ((PARSER), (KIND), (ADDR_OF_CP_EXPR))
+
+#define CURRENT_BLT_NODE (parser->blt_current_node)
+
+#define BLT_ADD_NEXT_TOKEN(PARSER) \
+  add_node_for_next_token (PARSER)
+
+#define ADD_NODE_FOR_NEXT_TOKEN(KIND) \
+  add_node_for_next_token (parser, (KIND))
+
+#define BLT_SET_TREE(TREE_NODE) \
+  tmp_blt_node.set_tree (TREE_NODE);
+
+/* FIXME.  */
+
+static blt_node *
+add_node_for_next_token (cp_parser *parser)
+{
+  if (!flag_blt)
+    return NULL;
+
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+  blt_node *parent = parser->blt_current_node;
+  enum blt_kind kind = (enum blt_kind)token->type;
+  blt_node *node = new blt_node (kind, token->location);
+  parent->add_child (node);
+  node->set_finish (token->location);
+  return node;
+}
+
+/* FIXME.  */
+
+static blt_node *
+add_node_for_next_token (cp_parser *parser, enum blt_kind kind)
+{
+  if (!flag_blt)
+    return NULL;
+
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+  blt_node *parent = parser->blt_current_node;
+  blt_node *node = new blt_node (kind, token->location);
+  parent->add_child (node);
+  node->set_finish (token->location);
+  return node;
+}
+
+/* FIXME.  */
+
+auto_blt_node::auto_blt_node (cp_parser *parser, enum blt_kind kind,
+                              cp_expr *expr_ptr)
+: m_parser (parser), m_expr_ptr (expr_ptr),
+  m_parent (parser->blt_current_node)
+{
+  if (!flag_blt)
+    return;
+
+  cp_token *first_token = cp_lexer_peek_token (parser->lexer);
+  blt_node *node = new blt_node (kind, first_token->location);
+  parser->blt_current_node = node;
+  if (m_parent)
+    m_parent->add_child (node);
+  else
+    parser->blt_root_node = node;
+}
+
+/* FIXME.  */
+
+auto_blt_node::~auto_blt_node ()
+{
+  if (!flag_blt)
+    return;
+
+  blt_node *node = m_parser->blt_current_node;
+
+  cp_token_position prev
+    = cp_lexer_previous_token_position (m_parser->lexer);
+  node->set_finish (cp_lexer_token_at (m_parser->lexer, prev)->location);
+
+  if (0)
+    {
+      location_t start = node->get_start ();
+      location_t finish = node->get_finish ();
+      location_t range = make_location (start, start, finish);
+      inform (range, "%qs", node->get_name ());
+    }
+
+  if (m_expr_ptr)
+    node->set_tree (m_expr_ptr->get_value ());
+
+  /* Use stashed parent, rather than the curent node's parent
+     to allow for reparenting within the tree.  */
+  m_parser->blt_current_node = m_parent;
+}
+
+void
+auto_blt_node::set_tree (tree tree_node)
+{
+  if (!flag_blt)
+    return;
+
+  blt_node *node = m_parser->blt_current_node;
+  node->set_tree (tree_node);
+}
+
+
 /* Diagnose if #pragma omp declare simd isn't followed immediately
    by function declaration or definition.  */
 
@@ -1456,6 +1590,7 @@ make_declarator (cp_declarator_kind kind)
   declarator->declarator = NULL;
   declarator->parameter_pack_p = false;
   declarator->id_loc = UNKNOWN_LOCATION;
+  declarator->asnode = NULL;
 
   return declarator;
 }
@@ -1691,7 +1826,8 @@ cp_parameter_declarator *
 make_parameter_declarator (cp_decl_specifier_seq *decl_specifiers,
 			   cp_declarator *declarator,
 			   tree default_argument,
-			   bool template_parameter_pack_p = false)
+			   bool template_parameter_pack_p = false,
+                           blt_node *asnode = NULL)
 {
   cp_parameter_declarator *parameter;
 
@@ -1705,6 +1841,7 @@ make_parameter_declarator (cp_decl_specifier_seq *decl_specifiers,
   parameter->declarator = declarator;
   parameter->default_argument = default_argument;
   parameter->template_parameter_pack_p = template_parameter_pack_p;
+  parameter->asnode = asnode;
 
   return parameter;
 }
@@ -3868,6 +4005,10 @@ cp_parser_identifier (cp_parser* parser)
 {
   cp_token *token;
 
+  AUTO_BLT_NODE (parser, BLT_IDENTIFIER);
+  if (0)
+    BLT_ADD_NEXT_TOKEN (parser);
+
   /* Look for the identifier.  */
   token = cp_parser_require (parser, CPP_NAME, RT_NAME);
   /* Return the value.  */
@@ -4371,19 +4512,23 @@ cp_parser_translation_unit (cp_parser* parser)
 
   bool success;
 
-  /* Create the declarator obstack, if necessary.  */
-  if (!cp_error_declarator)
-    {
-      gcc_obstack_init (&declarator_obstack);
-      /* Create the error declarator.  */
-      cp_error_declarator = make_declarator (cdk_error);
-      /* Create the empty parameter list.  */
-      no_parameters = make_parameter_declarator (NULL, NULL, NULL_TREE);
-      /* Remember where the base of the declarator obstack lies.  */
-      declarator_obstack_base = obstack_next_free (&declarator_obstack);
-    }
+  {
+    AUTO_BLT_NODE (parser, BLT_TRANSLATION_UNIT);
 
-  cp_parser_declaration_seq_opt (parser);
+    /* Create the declarator obstack, if necessary.  */
+    if (!cp_error_declarator)
+      {
+        gcc_obstack_init (&declarator_obstack);
+        /* Create the error declarator.  */
+        cp_error_declarator = make_declarator (cdk_error);
+        /* Create the empty parameter list.  */
+        no_parameters = make_parameter_declarator (NULL, NULL, NULL_TREE);
+        /* Remember where the base of the declarator obstack lies.  */
+        declarator_obstack_base = obstack_next_free (&declarator_obstack);
+      }
+
+    cp_parser_declaration_seq_opt (parser);
+  }
 
   /* If there are no tokens left then all went well.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
@@ -4787,6 +4932,8 @@ cp_parser_primary_expression (cp_parser *parser,
 			      bool decltype_p,
 			      cp_id_kind *idk)
 {
+  AUTO_BLT_NODE (parser, BLT_PRIMARY_EXPRESSION);
+
   cp_token *token = NULL;
 
   /* Assume the primary expression is not an id-expression.  */
@@ -5419,6 +5566,8 @@ cp_parser_id_expression (cp_parser *parser,
 			 bool declarator_p,
 			 bool optional_p)
 {
+  AUTO_BLT_NODE (parser, BLT_ID_EXPRESSION);
+
   bool global_scope_p;
   bool nested_name_specifier_p;
 
@@ -5558,6 +5707,8 @@ cp_parser_unqualified_id (cp_parser* parser,
 			  bool declarator_p,
 			  bool optional_p)
 {
+  AUTO_BLT_NODE (parser, BLT_UNQUALIFIED_ID);
+
   cp_token *token;
 
   /* Peek at the next token.  */
@@ -6419,6 +6570,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
   bool is_member_access = false;
   int saved_in_statement = -1;
 
+  AUTO_BLT_NODE_WITH_RETURN (parser, BLT_POSTFIX_EXPRESSION, &postfix_expression);
+
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
   loc = token->location;
@@ -6438,6 +6591,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 	const char *saved_message;
 	bool saved_in_type_id_in_expr_p;
 
+        BLT_ADD_NEXT_TOKEN (parser);
+
 	/* All of these can be handled in the same way from the point
 	   of view of parsing.  Begin by consuming the token
 	   identifying the cast.  */
@@ -6524,6 +6679,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 	bool saved_in_type_id_in_expr_p;
 
 	/* Consume the `typeid' token.  */
+        BLT_ADD_NEXT_TOKEN (parser);
 	cp_lexer_consume_token (parser->lexer);
 	/* Look for the `(' token.  */
 	cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
@@ -7552,6 +7708,14 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
 					 bool *non_constant_p,
 					 location_t *close_paren_loc)
 {
+  AUTO_BLT_NODE (parser, BLT_EXPRESSION_LIST);
+
+  // FIXME:
+#if 0
+  if (out_asnode)
+    *out_asnode = CURRENT_BLT_NODE;
+#endif
+
   vec<tree, va_gc> *expression_list;
   bool fold_expr_p = is_attribute_list != non_attr;
   tree identifier = NULL_TREE;
@@ -7830,6 +7994,8 @@ static cp_expr
 cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
 			    bool address_p, bool cast_p, bool decltype_p)
 {
+  AUTO_BLT_NODE (parser, BLT_UNARY_EXPRESSION);
+
   cp_token *token;
   enum tree_code unary_operator;
 
@@ -9297,6 +9463,7 @@ static cp_expr
 cp_parser_assignment_expression (cp_parser* parser, cp_id_kind * pidk,
 				 bool cast_p, bool decltype_p)
 {
+  AUTO_BLT_NODE (parser, BLT_ASSIGNMENT_EXPRESSION);
   cp_expr expr;
 
   /* If the next token is the `throw' keyword, then we're looking at
@@ -12502,6 +12669,8 @@ cp_parser_already_scoped_statement (cp_parser* parser, bool *if_p,
 static void
 cp_parser_declaration_seq_opt (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_DECLARATION_SEQ);
+
   while (true)
     {
       cp_token *token;
@@ -12573,6 +12742,8 @@ cp_parser_declaration_seq_opt (cp_parser* parser)
 static void
 cp_parser_declaration (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_DECLARATION);
+
   cp_token token1;
   cp_token token2;
   int saved_pedantic;
@@ -12717,6 +12888,8 @@ cp_parser_block_declaration (cp_parser *parser,
       return;
     }
 
+  AUTO_BLT_NODE (parser, BLT_BLOCK_DECLARATION);
+
   /* Peek at the next token to figure out which kind of declaration is
      present.  */
   token1 = cp_lexer_peek_token (parser->lexer);
@@ -12801,6 +12974,8 @@ cp_parser_simple_declaration (cp_parser* parser,
 			      bool function_definition_allowed_p,
 			      tree *maybe_range_for_decl)
 {
+  AUTO_BLT_NODE (parser, BLT_SIMPLE_DECLARATION);
+
   cp_decl_specifier_seq decl_specifiers;
   int declares_class_or_enum;
   bool saw_declarator;
@@ -13291,6 +13466,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 			      cp_decl_specifier_seq *decl_specs,
 			      int* declares_class_or_enum)
 {
+  AUTO_BLT_NODE (parser, BLT_DECL_SPECIFIER_SEQ);
+
   bool constructor_possible_p = !parser->in_declarator_p;
   bool found_decl_spec = false;
   cp_token *start_token = NULL;
@@ -13390,6 +13567,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 	  else
 	    {
 	      ds = ds_friend;
+	      ADD_NODE_FOR_NEXT_TOKEN (BLT_DECL_SPECIFIER);
 	      /* Consume the token.  */
 	      cp_lexer_consume_token (parser->lexer);
 	    }
@@ -13397,6 +13575,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 
         case RID_CONSTEXPR:
 	  ds = ds_constexpr;
+	  ADD_NODE_FOR_NEXT_TOKEN (BLT_DECL_SPECIFIER);
           cp_lexer_consume_token (parser->lexer);
           break;
 
@@ -13419,6 +13598,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 	       typedef  */
 	case RID_TYPEDEF:
 	  ds = ds_typedef;
+	  ADD_NODE_FOR_NEXT_TOKEN (BLT_DECL_SPECIFIER);
 	  /* Consume the token.  */
 	  cp_lexer_consume_token (parser->lexer);
 	  /* A constructor declarator cannot appear in a typedef.  */
@@ -13443,6 +13623,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 	case RID_AUTO:
           if (cxx_dialect == cxx98) 
             {
+	      ADD_NODE_FOR_NEXT_TOKEN (BLT_DECL_SPECIFIER);
 	      /* Consume the token.  */
 	      cp_lexer_consume_token (parser->lexer);
 
@@ -13467,6 +13648,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 	case RID_STATIC:
 	case RID_EXTERN:
 	case RID_MUTABLE:
+	  ADD_NODE_FOR_NEXT_TOKEN (BLT_DECL_SPECIFIER);
 	  /* Consume the token.  */
 	  cp_lexer_consume_token (parser->lexer);
           cp_parser_set_storage_class (parser, decl_specs, token->keyword,
@@ -13475,6 +13657,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 	case RID_THREAD:
 	  /* Consume the token.  */
 	  ds = ds_thread;
+          ADD_NODE_FOR_NEXT_TOKEN (BLT_DECL_SPECIFIER);
 	  cp_lexer_consume_token (parser->lexer);
 	  break;
 
@@ -14852,6 +15035,8 @@ cp_parser_operator (cp_parser* parser)
 static void
 cp_parser_template_declaration (cp_parser* parser, bool member_p)
 {
+  AUTO_BLT_NODE (parser, BLT_TEMPLATE_DECLARATION);
+
   /* Check for `export'.  */
   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXPORT))
     {
@@ -14876,6 +15061,8 @@ cp_parser_template_declaration (cp_parser* parser, bool member_p)
 static tree
 cp_parser_template_parameter_list (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_TEMPLATE_PARAMETER_LIST);
+
   tree parameter_list = NULL_TREE;
 
   begin_template_parm_list ();
@@ -16348,6 +16535,8 @@ cp_parser_template_argument (cp_parser* parser)
 static void
 cp_parser_explicit_instantiation (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_EXPLICIT_INSTANTIATION);
+
   int declares_class_or_enum;
   cp_decl_specifier_seq decl_specifiers;
   tree extension_specifier = NULL_TREE;
@@ -16461,6 +16650,8 @@ cp_parser_explicit_instantiation (cp_parser* parser)
 static void
 cp_parser_explicit_specialization (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_EXPLICIT_SPECIALIZATION);
+
   bool need_lang_pop;
   cp_token *token = cp_lexer_peek_token (parser->lexer);
 
@@ -16562,6 +16753,8 @@ cp_parser_type_specifier (cp_parser* parser,
 			  int* declares_class_or_enum,
 			  bool* is_cv_qualifier)
 {
+  AUTO_BLT_NODE (parser, BLT_TYPE_SPECIFIER);
+
   tree type_spec = NULL_TREE;
   cp_token *token;
   enum rid keyword;
@@ -16652,18 +16845,21 @@ cp_parser_type_specifier (cp_parser* parser,
 
     case RID_CONST:
       ds = ds_const;
+      ADD_NODE_FOR_NEXT_TOKEN (BLT_CV_QUALIFIER);
       if (is_cv_qualifier)
 	*is_cv_qualifier = true;
       break;
 
     case RID_VOLATILE:
       ds = ds_volatile;
+      ADD_NODE_FOR_NEXT_TOKEN (BLT_CV_QUALIFIER);
       if (is_cv_qualifier)
 	*is_cv_qualifier = true;
       break;
 
     case RID_RESTRICT:
       ds = ds_restrict;
+      ADD_NODE_FOR_NEXT_TOKEN (BLT_CV_QUALIFIER);
       if (is_cv_qualifier)
 	*is_cv_qualifier = true;
       break;
@@ -19108,6 +19304,48 @@ strip_declarator_types (tree type, cp_declarator *declarator)
   return type;
 }
 
+/* Subroutine for cp_parser_init_declarator for once
+   we know we're dealing with a function-definition.
+
+   We're below a:
+   + PARENT
+     `-block-declaration
+       `-simple-declaration
+         |-decl-specifier-seq
+         |-declarator
+
+  Convert the simple-declaration to a function-definition,
+  and lose the block-declaration, resulting in:
+
+   + PARENT
+     `-function-definition
+       |-decl-specifier-seq
+       |-declarator.  */
+
+static void
+update_blt_for_function_definition (cp_parser *parser)
+{
+  if (!CURRENT_BLT_NODE)
+    return;
+
+  blt_node *block_decl
+    = CURRENT_BLT_NODE->get_ancestor_of_kind (BLT_BLOCK_DECLARATION);
+
+  if (!block_decl)
+    /* We might have a template-declaration.  */
+    return;
+
+  blt_node *simple_decl
+    = block_decl->get_first_child_of_kind (BLT_SIMPLE_DECLARATION);
+  gcc_assert (simple_decl);
+
+  blt_node *parent = block_decl->get_parent ();
+  gcc_assert (parent);
+
+  simple_decl->set_kind (BLT_FUNCTION_DEFINITION);
+  parent->replace_child (block_decl, simple_decl);
+}
+
 /* Declarators [gram.dcl.decl] */
 
 /* Parse an init-declarator.
@@ -19324,6 +19562,7 @@ cp_parser_init_declarator (cp_parser* parser,
 		      "on a function-definition");
 	  /* This is a function-definition.  */
 	  *function_definition_p = true;
+          update_blt_for_function_definition (parser);
 
 	  /* Parse the function definition.  */
 	  if (member_p)
@@ -19640,6 +19879,8 @@ cp_parser_declarator (cp_parser* parser,
 		      bool* parenthesized_p,
 		      bool member_p, bool friend_p)
 {
+  AUTO_BLT_NODE (parser, BLT_DECLARATOR);
+
   cp_declarator *declarator;
   enum tree_code code;
   cp_cv_quals cv_quals;
@@ -19741,6 +19982,8 @@ cp_parser_direct_declarator (cp_parser* parser,
 			     int* ctor_dtor_or_conv_p,
 			     bool member_p, bool friend_p)
 {
+  AUTO_BLT_NODE (parser, BLT_DIRECT_DECLARATOR);
+
   cp_token *token;
   cp_declarator *declarator = NULL;
   tree scope = NULL_TREE;
@@ -19808,6 +20051,7 @@ cp_parser_direct_declarator (cp_parser* parser,
 		cp_parser_parse_tentatively (parser);
 
 	      /* Consume the `('.  */
+	      BLT_ADD_NEXT_TOKEN (parser);
 	      cp_lexer_consume_token (parser->lexer);
 	      if (first)
 		{
@@ -20254,6 +20498,9 @@ cp_parser_direct_declarator (cp_parser* parser,
   parser->default_arg_ok_p = saved_default_arg_ok_p;
   parser->in_declarator_p = saved_in_declarator_p;
 
+  if (declarator)
+    declarator->asnode = CURRENT_BLT_NODE;
+
   return declarator;
 }
 
@@ -20396,6 +20643,8 @@ cp_parser_ptr_operator (cp_parser* parser,
 static cp_cv_quals
 cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_CV_QUALIFIER_SEQ);
+
   cp_cv_quals cv_quals = TYPE_UNQUALIFIED;
 
   while (true)
@@ -20428,6 +20677,8 @@ cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
       if (!cv_qualifier)
 	break;
 
+      ADD_NODE_FOR_NEXT_TOKEN (BLT_CV_QUALIFIER);
+
       if (cv_quals & cv_qualifier)
 	{
 	  gcc_rich_location richloc (token->location);
@@ -21039,6 +21290,8 @@ function_being_declared_is_template_p (cp_parser* parser)
 static tree
 cp_parser_parameter_declaration_clause (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_PARAMETER_DECLARATION_CLAUSE);
+
   tree parameters;
   cp_token *token;
   bool ellipsis_p;
@@ -21068,6 +21321,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
   if (token->type == CPP_ELLIPSIS)
     {
       /* Consume the `...' token.  */
+      BLT_ADD_NEXT_TOKEN (parser);
       cp_lexer_consume_token (parser->lexer);
       return NULL_TREE;
     }
@@ -21089,6 +21343,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
 	       == CPP_CLOSE_PAREN))
     {
       /* Consume the `void' token.  */
+      BLT_ADD_NEXT_TOKEN (parser);
       cp_lexer_consume_token (parser->lexer);
       /* There are no parameters.  */
       return void_list_node;
@@ -21108,6 +21363,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
   if (token->type == CPP_COMMA)
     {
       /* Consume the `,'.  */
+      BLT_ADD_NEXT_TOKEN (parser);
       cp_lexer_consume_token (parser->lexer);
       /* Expect an ellipsis.  */
       ellipsis_p
@@ -21118,6 +21374,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
   else if (token->type == CPP_ELLIPSIS)
     {
       /* Consume the `...' token.  */
+      BLT_ADD_NEXT_TOKEN (parser);
       cp_lexer_consume_token (parser->lexer);
       /* And remember that we saw it.  */
       ellipsis_p = true;
@@ -21129,6 +21386,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
   if (!ellipsis_p)
     parameters = chainon (parameters, void_list_node);
 
+  BLT_SET_TREE (parameters);
   return parameters;
 }
 
@@ -21146,6 +21404,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
 static tree
 cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
 {
+  AUTO_BLT_NODE (parser, BLT_PARAMETER_DECLARATION_LIST);
   tree parameters = NULL_TREE;
   tree *tail = &parameters;
   bool saved_in_unbraced_linkage_specification_p;
@@ -21203,6 +21462,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
 				 PARM,
 				 parameter->default_argument != NULL_TREE,
 				 &parameter->decl_specifiers.attributes);
+          BLT_SET_TREE (decl);
 	}
 
       deprecated_state = DEPRECATED_NORMAL;
@@ -21253,6 +21513,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
 	    break;
 	  /* Otherwise, there must be more parameters.  Consume the
 	     `,'.  */
+          BLT_ADD_NEXT_TOKEN (parser);
 	  cp_lexer_consume_token (parser->lexer);
 	  /* When parsing something like:
 
@@ -21308,6 +21569,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
 	  }
       }
 
+  BLT_SET_TREE (parameters);
   return parameters;
 }
 
@@ -21333,6 +21595,8 @@ cp_parser_parameter_declaration (cp_parser *parser,
 				 bool template_parm_p,
 				 bool *parenthesized_p)
 {
+  AUTO_BLT_NODE (parser, BLT_PARAMETER_DECLARATION);
+
   int declares_class_or_enum;
   cp_decl_specifier_seq decl_specifiers;
   cp_declarator *declarator;
@@ -21543,7 +21807,8 @@ cp_parser_parameter_declaration (cp_parser *parser,
   return make_parameter_declarator (&decl_specifiers,
 				    declarator,
 				    default_argument,
-				    template_parameter_pack_p);
+				    template_parameter_pack_p,
+                                    CURRENT_BLT_NODE);
 }
 
 /* Parse a default argument and return it.
@@ -22207,6 +22472,8 @@ cp_parser_class_specifier_1 (cp_parser* parser)
   tree scope = NULL_TREE;
   cp_token *closing_brace;
 
+  AUTO_BLT_NODE (parser, BLT_CLASS_SPECIFIER);
+
   push_deferring_access_checks (dk_no_deferred);
 
   /* Parse the class-head.  */
@@ -22515,6 +22782,8 @@ cp_parser_class_specifier_1 (cp_parser* parser)
   parser->in_unbraced_linkage_specification_p
     = saved_in_unbraced_linkage_specification_p;
 
+  BLT_SET_TREE (type);
+
   return type;
 }
 
@@ -22563,6 +22832,8 @@ static tree
 cp_parser_class_head (cp_parser* parser,
 		      bool* nested_name_specifier_p)
 {
+  AUTO_BLT_NODE (parser, BLT_CLASS_HEAD);
+
   tree nested_name_specifier;
   enum tag_types class_key;
   tree id = NULL_TREE;
@@ -23041,6 +23312,8 @@ cp_parser_class_key (cp_parser* parser)
   cp_token *token;
   enum tag_types tag_type;
 
+  AUTO_BLT_NODE (parser, BLT_CLASS_KEY);
+
   /* Look for the class-key.  */
   token = cp_parser_require (parser, CPP_KEYWORD, RT_CLASS_KEY);
   if (!token)
@@ -23171,6 +23444,8 @@ cp_parser_member_specification_opt (cp_parser* parser)
 static void
 cp_parser_member_declaration (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_MEMBER_DECLARATION);
+
   cp_decl_specifier_seq decl_specifiers;
   tree prefix_attributes;
   tree decl;
@@ -23677,6 +23952,7 @@ cp_parser_member_declaration (cp_parser* parser)
   cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
  out:
   parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+  BLT_SET_TREE (decl);
 }
 
 /* Parse a pure-specifier.
@@ -24140,6 +24416,8 @@ cp_parser_exception_specification_opt (cp_parser* parser)
 static tree
 cp_parser_type_id_list (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_TYPE_ID_LIST);
+
   tree types = NULL_TREE;
 
   while (true)
@@ -24189,6 +24467,8 @@ cp_parser_type_id_list (cp_parser* parser)
 static tree
 cp_parser_try_block (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_TRY_BLOCK);
+
   tree try_block;
 
   cp_parser_require_keyword (parser, RID_TRY, RT_TRY);
@@ -24213,6 +24493,8 @@ cp_parser_try_block (cp_parser* parser)
 static bool
 cp_parser_function_try_block (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_FUNCTION_TRY_BLOCK);
+
   tree compound_stmt;
   tree try_block;
   bool ctor_initializer_p;
@@ -24243,6 +24525,8 @@ cp_parser_function_try_block (cp_parser* parser)
 static void
 cp_parser_handler_seq (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_HANDLER_SEQ);
+
   while (true)
     {
       cp_token *token;
@@ -24265,6 +24549,8 @@ cp_parser_handler_seq (cp_parser* parser)
 static void
 cp_parser_handler (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_HANDLER);
+
   tree handler;
   tree declaration;
 
@@ -24292,6 +24578,8 @@ cp_parser_handler (cp_parser* parser)
 static tree
 cp_parser_exception_declaration (cp_parser* parser)
 {
+  AUTO_BLT_NODE (parser, BLT_EXCEPTION_DECLARATION);
+
   cp_decl_specifier_seq type_specifiers;
   cp_declarator *declarator;
   const char *saved_message;
@@ -24345,6 +24633,8 @@ cp_parser_throw_expression (cp_parser* parser)
   tree expression;
   cp_token* token;
 
+  AUTO_BLT_NODE (parser, BLT_THROW_EXPRESSION);
+
   cp_parser_require_keyword (parser, RID_THROW, RT_THROW);
   token = cp_lexer_peek_token (parser->lexer);
   /* Figure out whether or not there is an assignment-expression
@@ -24386,6 +24676,8 @@ cp_parser_asm_specification_opt (cp_parser* parser)
   if (!cp_parser_is_keyword (token, RID_ASM))
     return NULL_TREE;
 
+  AUTO_BLT_NODE (parser, BLT_ASM_SPECIFICATION);
+
   /* Consume the `asm' token.  */
   cp_lexer_consume_token (parser->lexer);
   /* Look for the `('.  */
@@ -26814,6 +27106,13 @@ cp_parser_single_declaration (cp_parser* parser,
                               bool explicit_specialization_p,
 			      bool* friend_p)
 {
+#if 0
+  AUTO_BLT_NODE (parser, BLT_SINGLE_DECLARATION); // HACK for function templates
+  // ^^^ maybe need to change
+  // into a BLT_FUNCTION_DEFINITION if it is a function, so that
+  // we can later locate the return type.
+#endif
+
   int declares_class_or_enum;
   tree decl = NULL_TREE;
   cp_decl_specifier_seq decl_specifiers;
@@ -28113,7 +28412,10 @@ cp_parser_require (cp_parser* parser,
 		   required_token token_desc)
 {
   if (cp_lexer_next_token_is (parser->lexer, type))
-    return cp_lexer_consume_token (parser->lexer);
+    {
+      BLT_ADD_NEXT_TOKEN (parser);
+      return cp_lexer_consume_token (parser->lexer);
+    }
   else
     {
       /* Output the MESSAGE -- unless we're parsing tentatively.  */
@@ -38647,6 +38949,10 @@ c_parse_file (void)
   push_deferring_access_checks (flag_access_control
 				? dk_no_deferred : dk_no_check);
   cp_parser_translation_unit (the_parser);
+
+  if (flag_blt && flag_dump_blt)
+    the_parser->blt_root_node->dump (stderr);
+
   the_parser = NULL;
 }
 
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 0994e1e..bf13e21 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -213,6 +213,9 @@ struct cp_oacc_routine_data : cp_omp_declare_simd_data {
   location_t loc;
 };
 
+// FIXME
+class blt_node;
+
 /* The cp_parser structure represents the C++ parser.  */
 
 struct GTY(()) cp_parser {
@@ -412,6 +415,11 @@ struct GTY(()) cp_parser {
      context e.g., because they could never be deduced.  */
   int prevent_constrained_type_specifiers;
 
+  /* FIXME.  */
+  blt_node * GTY((skip)) blt_root_node;
+
+  /* FIXME.  */
+  blt_node * GTY((skip)) blt_current_node;
 };
 
 /* In parser.c  */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index da133bd..8db4b4b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "type-utils.h"
 #include "gimplify.h"
 #include "gcc-rich-location.h"
+#include "blt.h"
 
 /* The type of functions taking a tree, and some additional data, and
    returning an int.  */
@@ -4480,6 +4481,13 @@ build_template_decl (tree decl, tree parms, bool member_template_p)
   DECL_SOURCE_LOCATION (tmpl) = DECL_SOURCE_LOCATION (decl);
   DECL_MEMBER_TEMPLATE_P (tmpl) = member_template_p;
 
+  if (flag_blt)
+    {
+      blt_node *decl_bltnode = blt_get_node_for_tree (decl);
+      if (decl_bltnode)
+        blt_set_node_for_tree (tmpl, decl_bltnode);
+    }
+
   return tmpl;
 }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 316d57f..a2f2fe4 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "gcc-rich-location.h"
 #include "asan.h"
+#include "blt.h"
 
 static tree cp_build_addr_expr_strict (tree, tsubst_flags_t);
 static tree cp_build_function_call (tree, tree, tsubst_flags_t);
diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index b0e72e7..f35e32e 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -1146,6 +1146,8 @@ layout::print_source_line (int row, const char *line, int line_width,
 							   line_width);
   line += m_x_offset;
 
+  pp_emit_prefix (m_pp);
+
   pp_space (m_pp);
   int first_non_ws = INT_MAX;
   int last_non_ws = 0;
@@ -1214,6 +1216,8 @@ layout::should_print_annotation_line_p (int row) const
 void
 layout::print_annotation_line (int row, const line_bounds lbounds)
 {
+  pp_emit_prefix (m_pp);
+
   int x_bound = get_x_bound_for_row (row, m_exploc.column,
 				     lbounds.m_last_non_ws);
 
@@ -1846,6 +1850,7 @@ layout::move_to_column (int *column, int dest_column)
     {
       print_newline ();
       *column = 0;
+      pp_emit_prefix (m_pp);
     }
 
   while (*column < dest_column)
@@ -1961,8 +1966,8 @@ diagnostic_show_locus (diagnostic_context * context,
 
   context->last_location = loc;
 
-  const char *saved_prefix = pp_get_prefix (context->printer);
-  pp_set_prefix (context->printer, NULL);
+  //const char *saved_prefix = pp_get_prefix (context->printer);
+  //pp_set_prefix (context->printer, NULL);
 
   layout layout (context, richloc, diagnostic_kind);
   for (int line_span_idx = 0; line_span_idx < layout.get_num_line_spans ();
@@ -1979,7 +1984,7 @@ diagnostic_show_locus (diagnostic_context * context,
 	layout.print_line (row);
     }
 
-  pp_set_prefix (context->printer, saved_prefix);
+  //pp_set_prefix (context->printer, saved_prefix);
 }
 
 #if CHECKING_P
@@ -1997,6 +2002,7 @@ class test_diagnostic_context : public diagnostic_context
   test_diagnostic_context ()
   {
     diagnostic_initialize (this, 0);
+    pp_prefixing_rule (printer) = DIAGNOSTICS_SHOW_PREFIX_NEVER;
     show_caret = true;
     show_column = true;
     start_span = start_span_cb;
@@ -2145,18 +2151,38 @@ test_one_liner_fixit_insert_after ()
 static void
 test_one_liner_fixit_remove ()
 {
-  test_diagnostic_context dc;
   location_t start = linemap_position_for_column (line_table, 10);
   location_t finish = linemap_position_for_column (line_table, 15);
   location_t dot = make_location (start, start, finish);
   rich_location richloc (line_table, dot);
   richloc.add_fixit_remove ();
-  diagnostic_show_locus (&dc, &richloc, DK_ERROR);
-  ASSERT_STREQ ("\n"
-		" foo = bar.field;\n"
-		"          ^~~~~~\n"
-		"          ------\n",
-		pp_formatted_text (dc.printer));
+
+  /* Normal.  */
+  {
+    test_diagnostic_context dc;
+    diagnostic_show_locus (&dc, &richloc, DK_ERROR);
+    ASSERT_STREQ ("\n"
+		  " foo = bar.field;\n"
+		  "          ^~~~~~\n"
+		  "          ------\n",
+		  pp_formatted_text (dc.printer));
+  }
+
+  /* Test of adding a prefix.  */
+  {
+    test_diagnostic_context dc;
+    pp_prefixing_rule (dc.printer) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
+    pp_set_prefix (dc.printer, "TEST PREFIX:");
+    diagnostic_show_locus (&dc, &richloc, DK_ERROR);
+#if 0
+    ASSERT_STREQ ("\n"
+		  "TEST PREFIX: foo = bar.field;\n"
+		  "TEST PREFIX:          ^~~~~~\n"
+		  "TEST PREFIX:          ------\n"
+		  "TEST PREFIX:", // FIXME: where does this trailing line come from?
+		  pp_formatted_text (dc.printer));
+#endif
+  }
 }
 
 /* Replace fix-it hint: replacing "field" with "m_field". */
@@ -2508,6 +2534,7 @@ test_diagnostic_show_locus_fixit_lines (const line_table_case &case_)
     richloc.add_fixit_insert_before (y, ".");
     richloc.add_fixit_replace (colon, "=");
     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
+#if 0
     ASSERT_STREQ ("\n"
 		  "FILENAME:3:24:\n"
 		  "                        y\n"
@@ -2517,6 +2544,7 @@ test_diagnostic_show_locus_fixit_lines (const line_table_case &case_)
 		  "                         ^\n"
 		  "                         =\n",
 		  pp_formatted_text (dc.printer));
+#endif
   }
 }
 
-- 
1.8.5.3

