From ca92c380dc3ada619feb3594a2d7a52650ade8bc Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 10 May 2017 13:29:11 -0400
Subject: [PATCH 04/14] FIXME: C++: initial implementation of AST capture

---
 gcc/Makefile.in                                    |   1 +
 gcc/ast.c                                          | 243 +++++++++++++++++++
 gcc/ast.def                                        |  56 +++++
 gcc/ast.h                                          |  80 +++++++
 gcc/c-family/c-common.c                            |   5 +-
 gcc/c-family/c-common.h                            |   6 +-
 gcc/c-family/c-format.c                            |  37 ++-
 gcc/c-family/c.opt                                 |   8 +
 gcc/c/c-typeck.c                                   |   2 +-
 gcc/cp/call.c                                      | 154 +++++++++---
 gcc/cp/class.c                                     |  22 +-
 gcc/cp/cp-tree.h                                   |  15 +-
 gcc/cp/decl.c                                      |  27 ++-
 gcc/cp/parser.c                                    | 266 +++++++++++++++++++--
 gcc/cp/parser.h                                    |   8 +
 gcc/cp/pt.c                                        |  50 +++-
 gcc/cp/semantics.c                                 |   7 +-
 gcc/cp/typeck.c                                    |   2 +-
 .../g++.dg/diagnostic/Wformat-security-fixit.C     |  13 +
 .../g++.dg/diagnostic/param-type-mismatch.C        | 151 ++++++++++++
 gcc/testsuite/g++.dg/warn/Wsuggest-override.C      |   6 +-
 21 files changed, 1067 insertions(+), 92 deletions(-)
 create mode 100644 gcc/ast.c
 create mode 100644 gcc/ast.def
 create mode 100644 gcc/ast.h
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/Wformat-security-fixit.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2411671..a21ad0d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1213,6 +1213,7 @@ OBJS = \
 	ggc-page.o \
 	alias.o \
 	alloc-pool.o \
+	ast.o \
 	auto-inc-dec.o \
 	auto-profile.o \
 	bb-reorder.o \
diff --git a/gcc/ast.c b/gcc/ast.c
new file mode 100644
index 0000000..07201ce
--- /dev/null
+++ b/gcc/ast.c
@@ -0,0 +1,243 @@
+/* Abstract syntax 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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "pretty-print.h"
+#include "diagnostic.h"
+#include "ast.h"
+
+typedef hash_map <tree, ast_node *> tree_to_ast_map_t;
+static tree_to_ast_map_t *tree_to_ast_map;
+
+static const char *ast_kind_to_name (enum ast_kind kind);
+
+/* FIXME.  */
+
+ast_node::ast_node (enum ast_kind kind, location_t start)
+: m_kind (kind), m_parent (NULL), m_children (),
+  m_start (start), m_finish (UNKNOWN_LOCATION), m_tree (NULL_TREE)
+{
+}
+
+/* FIXME.  */
+
+void
+ast_node::add_child (ast_node *child)
+{
+  m_children.safe_push (child);
+  child->m_parent = this;
+}
+
+/* FIXME.  */
+
+void
+ast_node::set_tree (tree t)
+{
+  m_tree = t;
+
+  /* Add to mapping.  */
+  if (!t)
+    return;
+
+  if (!tree_to_ast_map)
+    tree_to_ast_map = new tree_to_ast_map_t ();
+  tree_to_ast_map->put (t, this);
+}
+
+/* FIXME.  */
+
+void
+ast_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
+ast_node::dump (pretty_printer *pp, const char *prefix,
+		const ast_node *parent, bool is_last_child) const
+{
+  unsigned i;
+  ast_node *child;
+
+  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", ast_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:
+    pp_printf (pp, " tree: %p %qE", (void *)m_tree, m_tree);
+
+  /* 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));
+      diagnostic_show_locus (&dc, &richloc, DK_NOTE);
+    }
+
+  pp_newline (pp);
+  const char *new_prefix;
+  if (parent)
+    new_prefix = ACONCAT ((prefix, is_last_child ? "  " : "|  ", NULL));
+  else
+    new_prefix = prefix;
+  FOR_EACH_VEC_ELT (m_children, i, child)
+    {
+      bool is_last_child = (i == m_children.length () - 1);
+      child->dump (pp, new_prefix, this, is_last_child);
+    }
+}
+
+/* FIXME.  */
+
+const char *
+ast_node::get_name () const
+{
+  return ast_kind_to_name (m_kind);
+}
+
+/* FIXME.  */
+
+location_t
+ast_node::get_range () const
+{
+  return make_location (m_start, m_start, m_finish);
+}
+
+/* FIXME.  */
+
+ast_node *
+ast_node::get_first_child_of_kind (enum ast_kind kind) const
+{
+  int i;
+  ast_node *child;
+  FOR_EACH_VEC_ELT (m_children, i, child)
+    if (kind == child->m_kind)
+      return child;
+  return NULL;
+}
+
+void
+ast_node::get_children_of_kind (auto_vec<ast_node *> &out,
+				enum ast_kind kind) const
+{
+  int i;
+  ast_node *child;
+  FOR_EACH_VEC_ELT (m_children, i, child)
+    if (kind == child->m_kind)
+      out.safe_push (child);
+}
+
+/* FIXME.  */
+
+ast_node *
+ast_get_node_for_tree (tree t)
+{
+  if (!t)
+    return NULL;
+  if (!tree_to_ast_map)
+    return NULL;
+  ast_node **slot = tree_to_ast_map->get (t);
+  if (!slot)
+    return NULL;
+  return *slot;
+}
+
+/* FIXME.  */
+
+void
+ast_set_node_for_tree (tree t, ast_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 ast_node *, but an ast_node * references
+	 at most one tree node (e.g. template instantiations).  */
+      gcc_assert (tree_to_ast_map);
+      tree_to_ast_map->get_or_insert (t) = asnode;
+    }
+}
+
+
+static const char * const ast_kind_names[] = {
+#define DEF_AST_NODE(ENUM_NAME, PRETTY_NAME) PRETTY_NAME,
+#include "ast.def"
+#undef DEF_AST_NODE
+};
+
+static const char *
+ast_kind_to_name (enum ast_kind kind)
+{
+  return ast_kind_names[kind];
+}
diff --git a/gcc/ast.def b/gcc/ast.def
new file mode 100644
index 0000000..be6bd25
--- /dev/null
+++ b/gcc/ast.def
@@ -0,0 +1,56 @@
+/* Abstract syntax 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/>.  */
+
+// TODO: generate the pairs of data automatically (awk?)
+DEF_AST_NODE (AST_ASM_SPECIFICATION, "asm-specification")
+DEF_AST_NODE (AST_ASSIGNMENT_EXPRESSION, "assignment-expression")
+DEF_AST_NODE (AST_BLOCK_DECLARATION, "block-declaration")
+DEF_AST_NODE (AST_CLASS_HEAD, "class-head")
+DEF_AST_NODE (AST_CLASS_KEY, "class-key")
+DEF_AST_NODE (AST_CLASS_SPECIFIER, "class-specifier")
+DEF_AST_NODE (AST_DECLARATION, "declaration")
+DEF_AST_NODE (AST_DECLARATION_SEQ, "declaration-seq")
+DEF_AST_NODE (AST_DECLARATOR, "declarator")
+DEF_AST_NODE (AST_DECL_SPECIFIER_SEQ, "decl-specifier-seq")
+DEF_AST_NODE (AST_DIRECT_DECLARATOR, "direct-declarator")
+DEF_AST_NODE (AST_EXCEPTION_DECLARATION, "exception-declaration")
+DEF_AST_NODE (AST_EXPRESSION_LIST, "expression-list")
+DEF_AST_NODE (AST_FUNCTION_TRY_BLOCK, "function-try-block")
+DEF_AST_NODE (AST_HANDLER, "handler")
+DEF_AST_NODE (AST_HANDLER_SEQ, "handler-seq")
+DEF_AST_NODE (AST_IDENTIFIER, "identifier")
+DEF_AST_NODE (AST_ID_EXPRESSION, "id-expression")
+DEF_AST_NODE (AST_MEMBER_DECLARATION, "member-declaration")
+DEF_AST_NODE (AST_PARAMETER_DECLARATION, "parameter-declaration")
+DEF_AST_NODE (AST_PARAMETER_DECLARATION_CLAUSE, "parameter-declaration-clause")
+DEF_AST_NODE (AST_PARAMETER_DECLARATION_LIST, "parameter-declaration-list")
+DEF_AST_NODE (AST_POSTFIX_EXPRESSION, "postfix-expression")
+DEF_AST_NODE (AST_PRIMARY_EXPRESSION, "primary-expression")
+DEF_AST_NODE (AST_SIMPLE_DECLARATION, "simple-declaration")
+DEF_AST_NODE (AST_TEMPLATE_DECLARATION, "template-declaration")
+DEF_AST_NODE (AST_TEMPLATE_PARAMETER_LIST, "template-parameter-list")
+DEF_AST_NODE (AST_EXPLICIT_INSTANTIATION, "explicit-instantiation")
+DEF_AST_NODE (AST_EXPLICIT_SPECIALIZATION, "explicit-specialization")
+DEF_AST_NODE (AST_THROW_EXPRESSION, "throw-expression")
+DEF_AST_NODE (AST_TOKEN, "token")
+DEF_AST_NODE (AST_TRANSLATION_UNIT, "translation-unit")
+DEF_AST_NODE (AST_TRY_BLOCK, "try-block")
+DEF_AST_NODE (AST_TYPE_ID_LIST, "type-id-list")
+DEF_AST_NODE (AST_UNARY_EXPRESSION, "unary-expression")
+DEF_AST_NODE (AST_UNQUALIFIED_ID, "unqualified-id")
diff --git a/gcc/ast.h b/gcc/ast.h
new file mode 100644
index 0000000..8f65d0b
--- /dev/null
+++ b/gcc/ast.h
@@ -0,0 +1,80 @@
+/* Abstract syntax 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/>.  */
+
+#ifndef GCC_AST_H
+#define GCC_AST_H
+
+/* FIXME.  */
+
+enum ast_kind
+{
+#define DEF_AST_NODE(ENUM_NAME, PRETTY_NAME) ENUM_NAME,
+#include "ast.def"
+#undef DEF_AST_NODE
+};
+
+/* FIXME.  */
+
+class ast_node
+{
+public:
+  ast_node (enum ast_kind kind, location_t start);
+
+  /* Modification.  */
+  void add_child (ast_node *child);
+  void set_finish (location_t loc) { m_finish = loc; }
+  void set_tree (tree t);
+
+  /* Dumping.  */
+  void dump (FILE *) const;
+  void dump (pretty_printer *pp, const char *prefix,
+	     const ast_node *parent, bool is_last_child) const;
+
+  /* Accessors.  */
+  enum ast_kind get_kind () const { return m_kind; }
+  const char *get_name () const;
+  ast_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; }
+
+  ast_node *get_first_child_of_kind (enum ast_kind kind) const;
+  void get_children_of_kind (auto_vec<ast_node *> &out,
+			     enum ast_kind kind) const;
+
+private:
+  enum ast_kind m_kind;
+  ast_node *m_parent;
+  auto_vec <ast_node *> m_children;
+#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 ast_node *ast_get_node_for_tree (tree);
+extern void ast_set_node_for_tree (tree, ast_node *);
+
+#endif  /* GCC_AST_H  */
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 0884922..a74f333 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -5524,7 +5524,7 @@ attribute_fallthrough_p (tree attr)
    diagnostics.  Return true if -Wnonnull warning has been diagnosed.  */
 bool
 check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype,
-			  int nargs, tree *argarray)
+			  int nargs, tree *argarray, ast_node *args_asnode)
 {
   bool warned_p = false;
 
@@ -5538,7 +5538,8 @@ check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype,
   /* Check for errors in format strings.  */
 
   if (warn_format || warn_suggest_attribute_format)
-    check_function_format (TYPE_ATTRIBUTES (fntype), nargs, argarray);
+    check_function_format (TYPE_ATTRIBUTES (fntype), nargs, argarray,
+			   args_asnode);
 
   if (warn_format)
     check_function_sentinel (fntype, nargs, argarray);
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 138a0a6..7e359f6 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -26,6 +26,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "fold-const.h"
 
+class ast_node;
+
 /* In order for the format checking to accept the C frontend
    diagnostic framework extensions, you must include this file before
    diagnostic-core.h, not after.  The C front end formats are a subset of those
@@ -808,7 +810,7 @@ extern tree fname_decl (location_t, unsigned, tree);
 
 extern int check_user_alignment (const_tree, bool);
 extern bool check_function_arguments (location_t loc, const_tree, const_tree,
-				      int, tree *);
+				      int, tree *, ast_node *);
 extern void check_function_arguments_recurse (void (*)
 					      (void *, tree,
 					       unsigned HOST_WIDE_INT),
@@ -816,7 +818,7 @@ extern void check_function_arguments_recurse (void (*)
 					      unsigned HOST_WIDE_INT);
 extern bool check_builtin_function_arguments (location_t, vec<location_t>,
 					      tree, int, tree *);
-extern void check_function_format (tree, int, tree *);
+extern void check_function_format (tree, int, tree *, ast_node *);
 extern bool attribute_fallthrough_p (tree);
 extern tree handle_format_attribute (tree *, tree, tree, int, bool *);
 extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 400eb66..94ed739 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "substring-locations.h"
 #include "selftest.h"
 #include "builtins.h"
+#include "ast.h"
 
 /* Handle attributes associated with format checking.  */
 
@@ -977,7 +978,7 @@ format_flags (int format_num)
   gcc_unreachable ();
 }
 
-static void check_format_info (function_format_info *, tree);
+static void check_format_info (function_format_info *, tree, ast_node *);
 static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT);
 static void check_format_info_main (format_check_results *,
 				    function_format_info *, const char *,
@@ -1042,7 +1043,8 @@ decode_format_type (const char *s)
    attribute themselves.  */
 
 void
-check_function_format (tree attrs, int nargs, tree *argarray)
+check_function_format (tree attrs, int nargs, tree *argarray,
+		       ast_node *args_asnode)
 {
   tree a;
 
@@ -1063,7 +1065,7 @@ check_function_format (tree attrs, int nargs, tree *argarray)
 	      int i;
 	      for (i = nargs - 1; i >= 0; i--)
 		params = tree_cons (NULL_TREE, argarray[i], params);
-	      check_format_info (&info, params);
+	      check_format_info (&info, params, args_asnode);
 	    }
 
 	  /* Attempt to detect whether the current function might benefit
@@ -1366,7 +1368,8 @@ get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates)
    PARAMS is the list of argument values.  */
 
 static void
-check_format_info (function_format_info *info, tree params)
+check_format_info (function_format_info *info, tree params,
+		   ast_node *args_asnode)
 {
   format_check_context format_ctx;
   unsigned HOST_WIDE_INT arg_num;
@@ -1430,8 +1433,30 @@ check_format_info (function_format_info *info, tree params)
 	      ++arg_num;
 	    }
 	  if (params == 0 && warn_format_security)
-	    warning_at (loc, OPT_Wformat_security,
-			"format not a string literal and no format arguments");
+	    {
+	      location_t report_loc = loc;
+	      if (args_asnode)
+		{
+		  /* For C++, expect an expression-list, containing a token for
+		     the open paren, then various assignment-expression for the args.  */
+		  ast_node *first_param
+		    = args_asnode->get_first_child_of_kind (AST_ASSIGNMENT_EXPRESSION);
+		  if (first_param)
+		    report_loc = first_param->get_range ();
+		}
+	      rich_location richloc (line_table, report_loc);
+	      if (args_asnode)
+		{
+		  ast_node *open_paren
+		    = args_asnode->get_first_child_of_kind (AST_TOKEN);
+		  if (open_paren)
+		    richloc.add_fixit_insert_after (open_paren->get_finish (),
+						    "\"%s\", ");
+		}
+	      warning_at_rich_loc
+		(&richloc, OPT_Wformat_security,
+		 "format not a string literal and no format arguments");
+	    }
 	  else if (params == 0 && warn_format_nonliteral)
 	    warning_at (loc, OPT_Wformat_nonliteral,
 			"format not a string literal and no format arguments");
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 9ad2f6e..08b5655 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1204,6 +1204,10 @@ fcanonical-system-headers
 C ObjC C++ ObjC++
 Where shorter, use canonicalized paths to systems headers.
 
+fcapture-ast
+C++ ObjC++ Var(flag_capture_ast)
+Capture the AST.
+
 fcheck-pointer-bounds
 C ObjC C++ ObjC++ LTO Report Var(flag_check_pointer_bounds)
 Add Pointer Bounds Checker instrumentation.  fchkp-* flags are used to
@@ -1358,6 +1362,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-ast
+C++ ObjC++ Var(flag_dump_ast)
+Dump the AST.
+
 felide-constructors
 C++ ObjC++ Var(flag_elide_constructors) Init(1)
 
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 6f9909c..00a6577 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -3111,7 +3111,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
 
   /* Check that the arguments to the function are valid.  */
   bool warned_p = check_function_arguments (loc, fundecl, fntype,
-					    nargs, argarray);
+					    nargs, argarray, NULL);
 
   if (name != NULL_TREE
       && !strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10))
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index c15b8e4..afaa3b3 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "c-family/c-objc.h"
 #include "internal-fn.h"
+#include "ast.h"
 
 /* The various kinds of conversion.  */
 
@@ -145,23 +146,27 @@ static int equal_functions (tree, tree);
 static int joust (struct z_candidate *, struct z_candidate *, bool,
 		  tsubst_flags_t);
 static int compare_ics (conversion *, conversion *);
-static tree build_over_call (struct z_candidate *, int, tsubst_flags_t);
+static tree build_over_call (struct z_candidate *, int, tsubst_flags_t,
+                             ast_node *args_asnode = NULL);
 #define convert_like(CONV, EXPR, COMPLAIN)			\
   convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0,		\
 		     /*issue_conversion_warnings=*/true,	\
 		     /*c_cast_p=*/false, (COMPLAIN))
-#define convert_like_with_context(CONV, EXPR, FN, ARGNO, COMPLAIN )	\
+#define convert_like_with_context(CONV, EXPR, FN, ARGNO, COMPLAIN, ASNODE)	\
   convert_like_real ((CONV), (EXPR), (FN), (ARGNO), 0,			\
 		     /*issue_conversion_warnings=*/true,		\
-		     /*c_cast_p=*/false, (COMPLAIN))
+		     /*c_cast_p=*/false, (COMPLAIN),                    \
+                     (ASNODE))
 static tree convert_like_real (conversion *, tree, tree, int, int, bool,
-			       bool, tsubst_flags_t);
+			       bool, tsubst_flags_t, ast_node * = NULL);
 static void op_error (location_t, enum tree_code, enum tree_code, tree,
 		      tree, tree, bool);
 static struct z_candidate *build_user_type_conversion_1 (tree, tree, int,
 							 tsubst_flags_t);
-static void print_z_candidate (location_t, const char *, struct z_candidate *);
-static void print_z_candidates (location_t, struct z_candidate *);
+static void print_z_candidate (location_t, const char *, struct z_candidate *,
+			       ast_node * = NULL);
+static void print_z_candidates (location_t, struct z_candidate *,
+				ast_node * = NULL);
 static tree build_this (tree);
 static struct z_candidate *splice_viable (struct z_candidate *, bool, bool *);
 static bool any_strictly_viable (struct z_candidate *);
@@ -3443,7 +3448,8 @@ print_arity_information (location_t loc, unsigned int have, unsigned int want)
 
 static void
 print_z_candidate (location_t loc, const char *msgstr,
-		   struct z_candidate *candidate)
+		   struct z_candidate *candidate,
+                   ast_node *args_asnode)
 {
   const char *msg = (msgstr == NULL
 		     ? ""
@@ -3532,7 +3538,7 @@ print_z_candidate (location_t loc, const char *msgstr,
 			       r->u.template_unification.return_type,
 			       r->u.template_unification.strict,
 			       r->u.template_unification.flags,
-			       true, false);
+			       true, false, args_asnode);
 	  break;
 	case rr_invalid_copy:
 	  inform (cloc,
@@ -3561,7 +3567,8 @@ print_z_candidate (location_t loc, const char *msgstr,
 }
 
 static void
-print_z_candidates (location_t loc, struct z_candidate *candidates)
+print_z_candidates (location_t loc, struct z_candidate *candidates,
+                    ast_node *args_asnode)
 {
   struct z_candidate *cand1;
   struct z_candidate **cand2;
@@ -3607,7 +3614,7 @@ print_z_candidates (location_t loc, struct z_candidate *candidates)
     }
 
   for (; candidates; candidates = candidates->next)
-    print_z_candidate (loc, "candidate:", candidates);
+    print_z_candidate (loc, "candidate:", candidates, args_asnode);
 }
 
 /* USER_SEQ is a user-defined conversion sequence, beginning with a
@@ -4164,7 +4171,8 @@ perform_overload_resolution (tree fn,
 
 static void
 print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
-			      struct z_candidate *candidates)
+			      struct z_candidate *candidates,
+                              ast_node *args_asnode)
 {
   tree targs = NULL_TREE;
   if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
@@ -4184,7 +4192,7 @@ print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
     error_at (loc, "call of overloaded %<%D(%A)%> is ambiguous",
 	      name, build_tree_list_vec (args));
   if (candidates)
-    print_z_candidates (loc, candidates);
+    print_z_candidates (loc, candidates, args_asnode);
 }
 
 /* Return an expression for a call to FN (a namespace-scope function,
@@ -4193,7 +4201,7 @@ print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
 
 tree
 build_new_function_call (tree fn, vec<tree, va_gc> **args, bool koenig_p, 
-			 tsubst_flags_t complain)
+			 tsubst_flags_t complain, ast_node *args_asnode)
 {
   struct z_candidate *candidates, *cand;
   bool any_viable_p;
@@ -4221,7 +4229,7 @@ build_new_function_call (tree fn, vec<tree, va_gc> **args, bool koenig_p,
       if (!fn)
 	{
 	  if (complain & tf_error)
-	    print_error_for_call_failure (orig_fn, *args, NULL);
+	    print_error_for_call_failure (orig_fn, *args, NULL, args_asnode);
 	  return error_mark_node;
 	}
     }
@@ -4243,7 +4251,7 @@ build_new_function_call (tree fn, vec<tree, va_gc> **args, bool koenig_p,
 	    return cp_build_function_call_vec (candidates->fn, args, complain);
 
 	  // Otherwise, emit notes for non-viable candidates.
-	  print_error_for_call_failure (fn, *args, candidates);
+	  print_error_for_call_failure (fn, *args, candidates, args_asnode);
 	}
       result = error_mark_node;
     }
@@ -4275,7 +4283,7 @@ build_new_function_call (tree fn, vec<tree, va_gc> **args, bool koenig_p,
           flags |= LOOKUP_EXPLICIT_TMPL_ARGS;
         }
 
-      result = build_over_call (cand, flags, complain);
+      result = build_over_call (cand, flags, complain, args_asnode);
     }
 
   /* Free all the conversions we allocated.  */
@@ -4356,7 +4364,7 @@ build_operator_new_call (tree fnname, vec<tree, va_gc> **args,
   if (!cand)
     {
       if (complain & tf_error)
-	print_error_for_call_failure (fns, *args, candidates);
+	print_error_for_call_failure (fns, *args, candidates, NULL);
       return error_mark_node;
     }
 
@@ -4526,7 +4534,7 @@ build_op_call_1 (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
 	{
 	  if (DECL_P (cand->fn))
 	    obj = convert_like_with_context (cand->convs[0], obj, cand->fn,
-					     -1, complain);
+					     -1, complain, NULL);
 	  else
 	    obj = convert_like (cand->convs[0], obj, complain);
 	  obj = convert_from_reference (obj);
@@ -6550,6 +6558,74 @@ maybe_print_user_conv_context (conversion *convs)
 	}
 }
 
+/* FIXME.  */
+
+static ast_node *
+get_ast_node_for_function_decl (tree fndecl)
+{
+  if (!flag_capture_ast)
+    return NULL;
+
+  ast_node *node = ast_get_node_for_tree (fndecl);
+  if (node)
+    return node;
+
+  tree template_decl = DECL_TI_TEMPLATE (fndecl);
+  if (template_decl)
+    {
+      node = ast_get_node_for_tree (template_decl);
+      if (node)
+        return node;
+    }
+
+  return NULL;
+}
+
+/* FIXME.  */
+
+static location_t
+get_fndecl_argument_location (tree fndecl, int argnum)
+{
+  location_t loc = DECL_SOURCE_LOCATION (fndecl);
+  ast_node *node = get_ast_node_for_function_decl (fndecl);
+  if (!node)
+    return loc;
+
+  /* For "member-declaration", expect the "direct-declarator" to be
+     inside a "declarator".  */
+  if (node->get_kind () == AST_MEMBER_DECLARATION)
+    {
+      node = node->get_first_child_of_kind (AST_DECLARATOR);
+      if (!node)
+        return loc;
+      node = node->get_first_child_of_kind (AST_DIRECT_DECLARATOR);
+      if (!node)
+        return loc;
+    }
+
+  if (node->get_kind () != AST_DIRECT_DECLARATOR)
+    return loc;
+
+  ast_node *pdc
+    = node->get_first_child_of_kind (AST_PARAMETER_DECLARATION_CLAUSE);
+  if (!pdc)
+    return loc;
+
+  ast_node *pdl = pdc->get_first_child_of_kind (AST_PARAMETER_DECLARATION_LIST);
+  if (!pdl)
+    return loc;
+
+  auto_vec<ast_node *> params;
+  pdl->get_children_of_kind (params, AST_PARAMETER_DECLARATION);
+
+  if (argnum >= (int)params.length ())
+    return loc;
+
+  ast_node *param = params[argnum];
+  return param->get_range ();
+}
+
+
 /* Perform the conversions in CONVS on the expression EXPR.  FN and
    ARGNUM are used for diagnostics.  ARGNUM is zero based, -1
    indicates the `this' argument of a method.  INNER is nonzero when
@@ -6563,12 +6639,17 @@ maybe_print_user_conv_context (conversion *convs)
 static tree
 convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 		   int inner, bool issue_conversion_warnings,
-		   bool c_cast_p, tsubst_flags_t complain)
+		   bool c_cast_p, tsubst_flags_t complain,
+                   ast_node *asnode)
 {
   tree totype = convs->type;
   diagnostic_t diag_kind;
   int flags;
-  location_t loc = EXPR_LOC_OR_LOC (expr, input_location);
+  location_t loc;
+  if (asnode)
+    loc = asnode->get_range ();
+  else
+    loc = EXPR_LOC_OR_LOC (expr, input_location);
 
   if (convs->bad_p && !(complain & tf_error))
     return error_mark_node;
@@ -6651,8 +6732,11 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	complained = permerror (loc, "invalid conversion from %qT to %qT",
 				TREE_TYPE (expr), totype);
       if (complained && fn)
-	inform (DECL_SOURCE_LOCATION (fn),
-		"  initializing argument %P of %qD", argnum, fn);
+        {
+          location_t decl_loc = get_fndecl_argument_location (fn, argnum);
+          inform (decl_loc,
+                  "  initializing argument %P of %qD", argnum, fn);
+        }
 
       return cp_convert (totype, expr, complain);
     }
@@ -7523,7 +7607,8 @@ unsafe_copy_elision_p (tree target, tree exp)
    bitmask of various LOOKUP_* flags which apply to the call itself.  */
 
 static tree
-build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
+build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain,
+                 ast_node *args_asnode)
 {
   tree fn = cand->fn;
   const vec<tree, va_gc> *args = cand->args;
@@ -7541,6 +7626,11 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
   tree *argarray;
   bool already_used = false;
 
+  auto_vec <ast_node *> argvec_asnode;
+  if (args_asnode)
+    args_asnode->get_children_of_kind (argvec_asnode,
+                                       AST_ASSIGNMENT_EXPRESSION);
+
   /* In a template, there is no need to perform all of the work that
      is normally done.  We are only interested in the type of the call
      expression, i.e., the return type of the function.  Any semantic
@@ -7773,6 +7863,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
       tree arg = (*args)[arg_index];
       bool conversion_warning = true;
 
+      ast_node *arg_asnode = NULL;
+      if (arg_index < argvec_asnode.length ())
+        arg_asnode = argvec_asnode[arg_index];
+
       conv = convs[i];
 
       /* If the argument is NULL and used to (implicitly) instantiate a
@@ -7843,7 +7937,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 	arg_complain &= ~tf_warning;
 
       val = convert_like_with_context (conv, arg, fn, i - is_method,
-				       arg_complain);
+				       arg_complain, arg_asnode);
       val = convert_for_arg_passing (type, val, arg_complain);
 	
       if (val == error_mark_node)
@@ -7914,7 +8008,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 	fargs[j] = maybe_constant_value (argarray[j]);
 
       warned_p = check_function_arguments (input_location, fn, TREE_TYPE (fn),
-					   nargs, fargs);
+					   nargs, fargs, args_asnode);
     }
 
   if (DECL_INHERITED_CTOR (fn))
@@ -8489,7 +8583,8 @@ name_as_c_string (tree name, tree type, bool *free_p)
 static tree
 build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 		         tree conversion_path, int flags,
-		         tree *fn_p, tsubst_flags_t complain)
+		         tree *fn_p, tsubst_flags_t complain,
+                         ast_node *args_asnode)
 {
   struct z_candidate *candidates = 0, *cand;
   tree explicit_targs = NULL_TREE;
@@ -8823,7 +8918,7 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 	      if (fn_p)
 		*fn_p = fn;
 	      /* Build the actual CALL_EXPR.  */
-	      call = build_over_call (cand, flags, complain);
+	      call = build_over_call (cand, flags, complain, args_asnode);
 	      /* In an expression of the form `a->f()' where `f' turns
 		 out to be a static member function, `a' is
 		 none-the-less evaluated.  */
@@ -8888,12 +8983,13 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 tree
 build_new_method_call (tree instance, tree fns, vec<tree, va_gc> **args,
 		       tree conversion_path, int flags,
-		       tree *fn_p, tsubst_flags_t complain)
+		       tree *fn_p, tsubst_flags_t complain,
+                       ast_node *args_asnode)
 {
   tree ret;
   bool subtime = timevar_cond_start (TV_OVERLOAD);
   ret = build_new_method_call_1 (instance, fns, args, conversion_path, flags,
-                                 fn_p, complain);
+                                 fn_p, complain, args_asnode);
   timevar_cond_stop (TV_OVERLOAD, subtime);
   return ret;
 }
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 2b039fe..21c3175 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dumpfile.h"
 #include "gimplify.h"
 #include "intl.h"
+#include "ast.h"
 
 /* The number of nested classes being processed.  If we are not in the
    scope of any class, this is zero.  */
@@ -3038,8 +3039,25 @@ check_for_override (tree decl, tree ctype)
       overrides_found = true;
       if (warn_override && !DECL_OVERRIDE_P (decl)
 	  && !DECL_DESTRUCTOR_P (decl))
-	warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wsuggest_override,
-		    "%qD can be marked override", decl);
+	{
+	  rich_location richloc (line_table, DECL_SOURCE_LOCATION (decl));
+	  /* Attempt to suggest adding " override" after the declarator
+	     (and before the semicolon).  */
+	  ast_node *asnode = ast_get_node_for_tree (decl);
+	  if (asnode)
+	    {
+	      /* Expect a member-declaration containing a
+		 decl-specifier-seq declarator token(;).
+		 We want the declarator.  */
+	      ast_node *declarator
+		= asnode->get_first_child_of_kind (AST_DECLARATOR);
+	      if (declarator)
+		richloc.add_fixit_insert_after (declarator->get_finish (),
+						" override");
+	    }
+	  warning_at_rich_loc (&richloc, OPT_Wsuggest_override,
+			       "%qD can be marked override", decl);
+	}
     }
 
   if (DECL_VIRTUAL_P (decl))
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 844f5ed..c4e7a8c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -40,6 +40,8 @@ c-common.h, not after.
 #include "c-family/c-common.h"
 #include "diagnostic.h"
 
+class ast_node;
+
 /* A tree node, together with a location, so that we can track locations
    (and ranges) during parsing.
 
@@ -5455,6 +5457,8 @@ struct cp_parameter_declarator {
   tree default_argument;
   /* True iff this is a template parameter pack.  */
   bool template_parameter_pack_p;
+  /* FIXME.  */
+  ast_node *asnode;
 };
 
 /* A declarator.  */
@@ -5530,6 +5534,7 @@ struct cp_declarator {
       bool rvalue_ref;
     } reference;
   } u;
+  ast_node *asnode;
 };
 
 /* A level of template instantiation.  */
@@ -5632,13 +5637,15 @@ extern tree extract_call_expr			(tree);
 extern tree build_user_type_conversion		(tree, tree, int,
 						 tsubst_flags_t);
 extern tree build_new_function_call		(tree, vec<tree, va_gc> **, bool, 
-						 tsubst_flags_t);
+						 tsubst_flags_t,
+						 ast_node * = NULL);
 extern tree build_operator_new_call		(tree, vec<tree, va_gc> **, tree *,
 						 tree *, tree, tree, tree *,
 						 tsubst_flags_t);
 extern tree build_new_method_call		(tree, tree, vec<tree, va_gc> **,
 						 tree, int, tree *,
-						 tsubst_flags_t);
+						 tsubst_flags_t,
+						 ast_node * = NULL);
 extern tree build_special_member_call		(tree, tree, vec<tree, va_gc> **,
 						 tree, int, tsubst_flags_t);
 extern tree build_new_op			(location_t, enum tree_code,
@@ -6184,7 +6191,7 @@ extern tree instantiate_template		(tree, tree, tsubst_flags_t);
 extern tree fn_type_unification			(tree, tree, tree,
 						 const tree *, unsigned int,
 						 tree, unification_kind_t, int,
-						 bool, bool);
+						 bool, bool, ast_node * = NULL);
 extern void mark_decl_instantiated		(tree, int);
 extern int more_specialized_fn			(tree, tree, int);
 extern void do_decl_instantiation		(tree, tree);
@@ -6467,7 +6474,7 @@ bool empty_expr_stmt_p				(tree);
 extern cp_expr perform_koenig_lookup		(cp_expr, vec<tree, va_gc> *,
 						 tsubst_flags_t);
 extern tree finish_call_expr			(tree, vec<tree, va_gc> **, bool,
-						 bool, tsubst_flags_t);
+						 bool, tsubst_flags_t, ast_node * = NULL);
 extern tree lookup_and_finish_template_variable (tree, tree, tsubst_flags_t = tf_warning_or_error);
 extern tree finish_template_variable		(tree, tsubst_flags_t = tf_warning_or_error);
 extern cp_expr finish_increment_expr		(cp_expr, enum tree_code);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 4f06572..d46a631 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cilk.h"
 #include "builtins.h"
 #include "gimplify.h"
+#include "ast.h"
 
 /* Possible cases of bad specifiers type used by bad_specifiers. */
 enum bad_spec_place {
@@ -9940,12 +9941,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;
@@ -12419,6 +12420,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 0622fb0..80bdc58 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 "ast.h"
 
 
 /* The lexer.  */
@@ -1348,6 +1349,114 @@ cp_token_cache_new (cp_token *first, cp_token *last)
   return cache;
 }
 
+
+
+/* FIXME.  */
+// RAII-style highlighting of the AST.
+
+/* FIXME.  */
+
+class auto_ast_node
+{
+public:
+  auto_ast_node (cp_parser* parser, enum ast_kind kind,
+                 cp_expr *expr_ptr = NULL);
+  ~auto_ast_node ();
+
+  void set_tree (tree node);
+
+private:
+  cp_parser *m_parser;
+  cp_expr *m_expr_ptr;
+};
+
+/* FIXME.  */
+
+#define AST_NODE(PARSER, KIND) \
+  auto_ast_node tmp_ast_node ((PARSER), (KIND))
+
+#define AST_NODE_WITH_RETURN(PARSER, KIND, ADDR_OF_CP_EXPR) \
+  auto_ast_node tmp_ast_node ((PARSER), (KIND), (ADDR_OF_CP_EXPR))
+
+#define CURRENT_AST_NODE (parser->ast_current_node)
+
+#define AST_ADD_NEXT_TOKEN(PARSER) \
+  add_next_token (PARSER)
+
+#define AST_SET_TREE(TREE_NODE) \
+  tmp_ast_node.set_tree (TREE_NODE);
+
+static void
+add_next_token (cp_parser *parser)
+{
+  if (!flag_capture_ast)
+    return;
+
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+  ast_node *parent = parser->ast_current_node;
+  ast_node *node = new ast_node (AST_TOKEN, token->location);
+  parent->add_child (node);
+  // FIXME: get a meaningful string for the token
+  node->set_finish (token->location);
+}
+
+/* FIXME.  */
+
+auto_ast_node::auto_ast_node (cp_parser *parser, enum ast_kind kind,
+                              cp_expr *expr_ptr)
+: m_parser (parser), m_expr_ptr (expr_ptr)
+{
+  if (!flag_capture_ast)
+    return;
+
+  cp_token *first_token = cp_lexer_peek_token (parser->lexer);
+  ast_node *parent = parser->ast_current_node;
+  ast_node *node = new ast_node (kind, first_token->location);
+  parser->ast_current_node = node;
+  if (parent)
+    parent->add_child (node);
+  else
+    parser->ast_root_node = node;
+}
+
+/* FIXME.  */
+
+auto_ast_node::~auto_ast_node ()
+{
+  if (!flag_capture_ast)
+    return;
+
+  ast_node *node = m_parser->ast_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 ());
+
+  m_parser->ast_current_node = node->get_parent ();
+}
+
+void
+auto_ast_node::set_tree (tree tree_node)
+{
+  if (!flag_capture_ast)
+    return;
+
+  ast_node *node = m_parser->ast_current_node;
+  node->set_tree (tree_node);
+}
+
+
 /* Diagnose if #pragma omp declare simd isn't followed immediately
    by function declaration or definition.  */
 
@@ -1456,6 +1565,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 +1801,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,
+                           ast_node *asnode = NULL)
 {
   cp_parameter_declarator *parameter;
 
@@ -1705,6 +1816,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;
 }
@@ -2051,7 +2163,8 @@ static tree cp_parser_postfix_open_square_expression
 static tree cp_parser_postfix_dot_deref_expression
   (cp_parser *, enum cpp_ttype, cp_expr, bool, cp_id_kind *, location_t);
 static vec<tree, va_gc> *cp_parser_parenthesized_expression_list
-  (cp_parser *, int, bool, bool, bool *, location_t * = NULL);
+  (cp_parser *, int, bool, bool, bool *, location_t * = NULL,
+   ast_node ** = NULL);
 /* Values for the second parameter of cp_parser_parenthesized_expression_list.  */
 enum { non_attr = 0, normal_attr = 1, id_attr = 2 };
 static void cp_parser_pseudo_destructor_name
@@ -3846,6 +3959,10 @@ cp_parser_identifier (cp_parser* parser)
 {
   cp_token *token;
 
+  AST_NODE (parser, AST_IDENTIFIER);
+  if (0)
+    AST_ADD_NEXT_TOKEN (parser);
+
   /* Look for the identifier.  */
   token = cp_parser_require (parser, CPP_NAME, RT_NAME);
   /* Return the value.  */
@@ -4351,19 +4468,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);
-    }
+  {
+    AST_NODE (parser, AST_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))
@@ -4767,6 +4888,8 @@ cp_parser_primary_expression (cp_parser *parser,
 			      bool decltype_p,
 			      cp_id_kind *idk)
 {
+  AST_NODE (parser, AST_PRIMARY_EXPRESSION);
+
   cp_token *token = NULL;
 
   /* Assume the primary expression is not an id-expression.  */
@@ -5397,6 +5520,8 @@ cp_parser_id_expression (cp_parser *parser,
 			 bool declarator_p,
 			 bool optional_p)
 {
+  AST_NODE (parser, AST_ID_EXPRESSION);
+
   bool global_scope_p;
   bool nested_name_specifier_p;
 
@@ -5531,6 +5656,8 @@ cp_parser_unqualified_id (cp_parser* parser,
 			  bool declarator_p,
 			  bool optional_p)
 {
+  AST_NODE (parser, AST_UNQUALIFIED_ID);
+
   cp_token *token;
 
   /* Peek at the next token.  */
@@ -6394,6 +6521,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
   bool is_member_access = false;
   int saved_in_statement = -1;
 
+  AST_NODE_WITH_RETURN (parser, AST_POSTFIX_EXPRESSION, &postfix_expression);
+
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
   loc = token->location;
@@ -6413,6 +6542,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;
 
+        AST_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.  */
@@ -6499,6 +6630,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.  */
+        AST_ADD_NEXT_TOKEN (parser);
 	cp_lexer_consume_token (parser->lexer);
 	/* Look for the `(' token.  */
 	cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
@@ -6835,6 +6967,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 	    bool saved_non_integral_constant_expression_p = false;
 	    tsubst_flags_t complain = complain_flags (decltype_p);
 	    vec<tree, va_gc> *args;
+            ast_node *args_asnode;
 	    location_t close_paren_loc = UNKNOWN_LOCATION;
 
             is_member_access = false;
@@ -6855,7 +6988,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 		    (parser, non_attr,
 		     /*cast_p=*/false, /*allow_expansion_p=*/true,
 		     /*non_constant_p=*/NULL,
-		     /*close_paren_loc=*/&close_paren_loc));
+		     /*close_paren_loc=*/&close_paren_loc,
+                     &args_asnode));
 	    if (is_builtin_constant_p)
 	      {
 		parser->integral_constant_expression_p
@@ -6966,14 +7100,15 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 			 ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL
 			 : LOOKUP_NORMAL),
 			/*fn_p=*/NULL,
-			complain));
+			complain, args_asnode));
 		  }
 		else
 		  postfix_expression
 		    = finish_call_expr (postfix_expression, &args,
 					/*disallow_virtual=*/false,
 					/*koenig_p=*/false,
-					complain);
+					complain,
+                                        args_asnode);
 	      }
 	    else if (TREE_CODE (postfix_expression) == OFFSET_REF
 		     || TREE_CODE (postfix_expression) == MEMBER_REF
@@ -6988,14 +7123,16 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 		= finish_call_expr (postfix_expression, &args,
 				    /*disallow_virtual=*/true,
 				    koenig_p,
-				    complain);
+				    complain,
+                                    args_asnode);
 	    else
 	      /* All other function calls.  */
 	      postfix_expression
 		= finish_call_expr (postfix_expression, &args,
 				    /*disallow_virtual=*/false,
 				    koenig_p,
-				    complain);
+				    complain,
+                                    args_asnode);
 
 	    if (close_paren_loc != UNKNOWN_LOCATION)
 	      {
@@ -7511,8 +7648,14 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
 					 bool cast_p,
                                          bool allow_expansion_p,
 					 bool *non_constant_p,
-					 location_t *close_paren_loc)
+					 location_t *close_paren_loc,
+                                         ast_node **out_asnode)
 {
+  AST_NODE (parser, AST_EXPRESSION_LIST);
+
+  if (out_asnode)
+    *out_asnode = CURRENT_AST_NODE;
+
   vec<tree, va_gc> *expression_list;
   bool fold_expr_p = is_attribute_list != non_attr;
   tree identifier = NULL_TREE;
@@ -7791,6 +7934,8 @@ static cp_expr
 cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
 			    bool address_p, bool cast_p, bool decltype_p)
 {
+  AST_NODE (parser, AST_UNARY_EXPRESSION);
+
   cp_token *token;
   enum tree_code unary_operator;
 
@@ -9170,6 +9315,7 @@ static cp_expr
 cp_parser_assignment_expression (cp_parser* parser, cp_id_kind * pidk,
 				 bool cast_p, bool decltype_p)
 {
+  AST_NODE (parser, AST_ASSIGNMENT_EXPRESSION);
   cp_expr expr;
 
   /* If the next token is the `throw' keyword, then we're looking at
@@ -12343,6 +12489,8 @@ cp_parser_already_scoped_statement (cp_parser* parser, bool *if_p,
 static void
 cp_parser_declaration_seq_opt (cp_parser* parser)
 {
+  AST_NODE (parser, AST_DECLARATION_SEQ);
+
   while (true)
     {
       cp_token *token;
@@ -12414,6 +12562,8 @@ cp_parser_declaration_seq_opt (cp_parser* parser)
 static void
 cp_parser_declaration (cp_parser* parser)
 {
+  AST_NODE (parser, AST_DECLARATION);
+
   cp_token token1;
   cp_token token2;
   int saved_pedantic;
@@ -12558,6 +12708,8 @@ cp_parser_block_declaration (cp_parser *parser,
       return;
     }
 
+  AST_NODE (parser, AST_BLOCK_DECLARATION);
+
   /* Peek at the next token to figure out which kind of declaration is
      present.  */
   token1 = cp_lexer_peek_token (parser->lexer);
@@ -12642,6 +12794,8 @@ cp_parser_simple_declaration (cp_parser* parser,
 			      bool function_definition_allowed_p,
 			      tree *maybe_range_for_decl)
 {
+  AST_NODE (parser, AST_SIMPLE_DECLARATION);
+
   cp_decl_specifier_seq decl_specifiers;
   int declares_class_or_enum;
   bool saw_declarator;
@@ -13122,6 +13276,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 			      cp_decl_specifier_seq *decl_specs,
 			      int* declares_class_or_enum)
 {
+  AST_NODE (parser, AST_DECL_SPECIFIER_SEQ);
+
   bool constructor_possible_p = !parser->in_declarator_p;
   bool found_decl_spec = false;
   cp_token *start_token = NULL;
@@ -14678,6 +14834,8 @@ cp_parser_operator (cp_parser* parser)
 static void
 cp_parser_template_declaration (cp_parser* parser, bool member_p)
 {
+  AST_NODE (parser, AST_TEMPLATE_DECLARATION);
+
   /* Check for `export'.  */
   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXPORT))
     {
@@ -14702,6 +14860,8 @@ cp_parser_template_declaration (cp_parser* parser, bool member_p)
 static tree
 cp_parser_template_parameter_list (cp_parser* parser)
 {
+  AST_NODE (parser, AST_TEMPLATE_PARAMETER_LIST);
+
   tree parameter_list = NULL_TREE;
 
   begin_template_parm_list ();
@@ -16169,6 +16329,8 @@ cp_parser_template_argument (cp_parser* parser)
 static void
 cp_parser_explicit_instantiation (cp_parser* parser)
 {
+  AST_NODE (parser, AST_EXPLICIT_INSTANTIATION);
+
   int declares_class_or_enum;
   cp_decl_specifier_seq decl_specifiers;
   tree extension_specifier = NULL_TREE;
@@ -16282,6 +16444,8 @@ cp_parser_explicit_instantiation (cp_parser* parser)
 static void
 cp_parser_explicit_specialization (cp_parser* parser)
 {
+  AST_NODE (parser, AST_EXPLICIT_SPECIALIZATION);
+
   bool need_lang_pop;
   cp_token *token = cp_lexer_peek_token (parser->lexer);
 
@@ -19481,6 +19645,8 @@ cp_parser_declarator (cp_parser* parser,
 		      bool* parenthesized_p,
 		      bool member_p, bool friend_p)
 {
+  AST_NODE (parser, AST_DECLARATOR);
+
   cp_declarator *declarator;
   enum tree_code code;
   cp_cv_quals cv_quals;
@@ -19582,6 +19748,8 @@ cp_parser_direct_declarator (cp_parser* parser,
 			     int* ctor_dtor_or_conv_p,
 			     bool member_p, bool friend_p)
 {
+  AST_NODE (parser, AST_DIRECT_DECLARATOR);
+
   cp_token *token;
   cp_declarator *declarator = NULL;
   tree scope = NULL_TREE;
@@ -19649,6 +19817,7 @@ cp_parser_direct_declarator (cp_parser* parser,
 		cp_parser_parse_tentatively (parser);
 
 	      /* Consume the `('.  */
+	      AST_ADD_NEXT_TOKEN (parser);
 	      cp_lexer_consume_token (parser->lexer);
 	      if (first)
 		{
@@ -20111,6 +20280,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_AST_NODE;
+
   return declarator;
 }
 
@@ -20896,6 +21068,8 @@ function_being_declared_is_template_p (cp_parser* parser)
 static tree
 cp_parser_parameter_declaration_clause (cp_parser* parser)
 {
+  AST_NODE (parser, AST_PARAMETER_DECLARATION_CLAUSE);
+
   tree parameters;
   cp_token *token;
   bool ellipsis_p;
@@ -20925,6 +21099,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
   if (token->type == CPP_ELLIPSIS)
     {
       /* Consume the `...' token.  */
+      AST_ADD_NEXT_TOKEN (parser);
       cp_lexer_consume_token (parser->lexer);
       return NULL_TREE;
     }
@@ -20946,6 +21121,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
 	       == CPP_CLOSE_PAREN))
     {
       /* Consume the `void' token.  */
+      AST_ADD_NEXT_TOKEN (parser);
       cp_lexer_consume_token (parser->lexer);
       /* There are no parameters.  */
       return void_list_node;
@@ -20965,6 +21141,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
   if (token->type == CPP_COMMA)
     {
       /* Consume the `,'.  */
+      AST_ADD_NEXT_TOKEN (parser);
       cp_lexer_consume_token (parser->lexer);
       /* Expect an ellipsis.  */
       ellipsis_p
@@ -20975,6 +21152,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
   else if (token->type == CPP_ELLIPSIS)
     {
       /* Consume the `...' token.  */
+      AST_ADD_NEXT_TOKEN (parser);
       cp_lexer_consume_token (parser->lexer);
       /* And remember that we saw it.  */
       ellipsis_p = true;
@@ -20986,6 +21164,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
   if (!ellipsis_p)
     parameters = chainon (parameters, void_list_node);
 
+  AST_SET_TREE (parameters);
   return parameters;
 }
 
@@ -21003,6 +21182,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
 static tree
 cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
 {
+  AST_NODE (parser, AST_PARAMETER_DECLARATION_LIST);
   tree parameters = NULL_TREE;
   tree *tail = &parameters;
   bool saved_in_unbraced_linkage_specification_p;
@@ -21060,6 +21240,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
 				 PARM,
 				 parameter->default_argument != NULL_TREE,
 				 &parameter->decl_specifiers.attributes);
+          AST_SET_TREE (decl);
 	}
 
       deprecated_state = DEPRECATED_NORMAL;
@@ -21110,6 +21291,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
 	    break;
 	  /* Otherwise, there must be more parameters.  Consume the
 	     `,'.  */
+          AST_ADD_NEXT_TOKEN (parser);
 	  cp_lexer_consume_token (parser->lexer);
 	  /* When parsing something like:
 
@@ -21165,6 +21347,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
 	  }
       }
 
+  AST_SET_TREE (parameters);
   return parameters;
 }
 
@@ -21190,6 +21373,8 @@ cp_parser_parameter_declaration (cp_parser *parser,
 				 bool template_parm_p,
 				 bool *parenthesized_p)
 {
+  AST_NODE (parser, AST_PARAMETER_DECLARATION);
+
   int declares_class_or_enum;
   cp_decl_specifier_seq decl_specifiers;
   cp_declarator *declarator;
@@ -21400,7 +21585,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_AST_NODE);
 }
 
 /* Parse a default argument and return it.
@@ -22064,6 +22250,8 @@ cp_parser_class_specifier_1 (cp_parser* parser)
   tree scope = NULL_TREE;
   cp_token *closing_brace;
 
+  AST_NODE (parser, AST_CLASS_SPECIFIER);
+
   push_deferring_access_checks (dk_no_deferred);
 
   /* Parse the class-head.  */
@@ -22372,6 +22560,8 @@ cp_parser_class_specifier_1 (cp_parser* parser)
   parser->in_unbraced_linkage_specification_p
     = saved_in_unbraced_linkage_specification_p;
 
+  AST_SET_TREE (type);
+
   return type;
 }
 
@@ -22420,6 +22610,8 @@ static tree
 cp_parser_class_head (cp_parser* parser,
 		      bool* nested_name_specifier_p)
 {
+  AST_NODE (parser, AST_CLASS_HEAD);
+
   tree nested_name_specifier;
   enum tag_types class_key;
   tree id = NULL_TREE;
@@ -22887,6 +23079,8 @@ cp_parser_class_key (cp_parser* parser)
   cp_token *token;
   enum tag_types tag_type;
 
+  AST_NODE (parser, AST_CLASS_KEY);
+
   /* Look for the class-key.  */
   token = cp_parser_require (parser, CPP_KEYWORD, RT_CLASS_KEY);
   if (!token)
@@ -23017,9 +23211,11 @@ cp_parser_member_specification_opt (cp_parser* parser)
 static void
 cp_parser_member_declaration (cp_parser* parser)
 {
+  AST_NODE (parser, AST_MEMBER_DECLARATION);
+
   cp_decl_specifier_seq decl_specifiers;
   tree prefix_attributes;
-  tree decl;
+  tree decl = NULL_TREE;
   int declares_class_or_enum;
   bool friend_p;
   cp_token *token = NULL;
@@ -23523,6 +23719,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;
+  AST_SET_TREE (decl);
 }
 
 /* Parse a pure-specifier.
@@ -23986,6 +24183,8 @@ cp_parser_exception_specification_opt (cp_parser* parser)
 static tree
 cp_parser_type_id_list (cp_parser* parser)
 {
+  AST_NODE (parser, AST_TYPE_ID_LIST);
+
   tree types = NULL_TREE;
 
   while (true)
@@ -24035,6 +24234,8 @@ cp_parser_type_id_list (cp_parser* parser)
 static tree
 cp_parser_try_block (cp_parser* parser)
 {
+  AST_NODE (parser, AST_TRY_BLOCK);
+
   tree try_block;
 
   cp_parser_require_keyword (parser, RID_TRY, RT_TRY);
@@ -24059,6 +24260,8 @@ cp_parser_try_block (cp_parser* parser)
 static bool
 cp_parser_function_try_block (cp_parser* parser)
 {
+  AST_NODE (parser, AST_FUNCTION_TRY_BLOCK);
+
   tree compound_stmt;
   tree try_block;
   bool ctor_initializer_p;
@@ -24089,6 +24292,8 @@ cp_parser_function_try_block (cp_parser* parser)
 static void
 cp_parser_handler_seq (cp_parser* parser)
 {
+  AST_NODE (parser, AST_HANDLER_SEQ);
+
   while (true)
     {
       cp_token *token;
@@ -24111,6 +24316,8 @@ cp_parser_handler_seq (cp_parser* parser)
 static void
 cp_parser_handler (cp_parser* parser)
 {
+  AST_NODE (parser, AST_HANDLER);
+
   tree handler;
   tree declaration;
 
@@ -24138,6 +24345,8 @@ cp_parser_handler (cp_parser* parser)
 static tree
 cp_parser_exception_declaration (cp_parser* parser)
 {
+  AST_NODE (parser, AST_EXCEPTION_DECLARATION);
+
   cp_decl_specifier_seq type_specifiers;
   cp_declarator *declarator;
   const char *saved_message;
@@ -24191,6 +24400,8 @@ cp_parser_throw_expression (cp_parser* parser)
   tree expression;
   cp_token* token;
 
+  AST_NODE (parser, AST_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
@@ -24232,6 +24443,8 @@ cp_parser_asm_specification_opt (cp_parser* parser)
   if (!cp_parser_is_keyword (token, RID_ASM))
     return NULL_TREE;
 
+  AST_NODE (parser, AST_ASM_SPECIFICATION);
+
   /* Consume the `asm' token.  */
   cp_lexer_consume_token (parser->lexer);
   /* Look for the `('.  */
@@ -27957,7 +28170,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);
+    {
+      AST_ADD_NEXT_TOKEN (parser);
+      return cp_lexer_consume_token (parser->lexer);
+    }
   else
     {
       /* Output the MESSAGE -- unless we're parsing tentatively.  */
@@ -38483,6 +38699,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_capture_ast && flag_dump_ast)
+    the_parser->ast_root_node->dump (stderr);
+
   the_parser = NULL;
 }
 
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 0994e1e..d7e37af 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 ast_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.  */
+  ast_node *ast_root_node;
+
+  /* FIXME.  */
+  ast_node *ast_current_node;
 };
 
 /* In parser.c  */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 1567e2b..9c8b6e0 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "type-utils.h"
 #include "gimplify.h"
+#include "ast.h"
 
 /* The type of functions taking a tree, and some additional data, and
    returning an int.  */
@@ -154,7 +155,7 @@ static int maybe_adjust_types_for_deduction (unification_kind_t, tree*, tree*,
 static int type_unification_real (tree, tree, tree, const tree *,
 				  unsigned int, int, unification_kind_t, int,
 				  vec<deferred_access_check, va_gc> **,
-				  bool);
+				  bool, ast_node * = NULL);
 static void note_template_header (int);
 static tree convert_nontype_argument_function (tree, tree, tsubst_flags_t);
 static tree convert_nontype_argument (tree, tree, tsubst_flags_t);
@@ -4433,6 +4434,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_capture_ast)
+    {
+      ast_node *decl_asnode = ast_get_node_for_tree (decl);
+      if (decl_asnode)
+        ast_set_node_for_tree (tmpl, decl_asnode);
+    }
+
   return tmpl;
 }
 
@@ -6251,12 +6259,19 @@ unify_too_few_arguments (bool explain_p, int have, int wanted,
 
 static int
 unify_arg_conversion (bool explain_p, tree to_type,
-		      tree from_type, tree arg)
+		      tree from_type, tree arg,
+                      ast_node *argnode)
 {
   if (explain_p)
-    inform (EXPR_LOC_OR_LOC (arg, input_location),
-	    "  cannot convert %qE (type %qT) to type %qT",
-	    arg, from_type, to_type);
+    {
+      location_t loc;
+      if (argnode)
+        loc = argnode->get_range ();
+      else
+        loc = EXPR_LOC_OR_LOC (arg, input_location);
+      inform (loc, "  cannot convert %qE (type %qT) to type %qT",
+              arg, from_type, to_type);
+    }
   return 1;
 }
 
@@ -18339,7 +18354,8 @@ fn_type_unification (tree fn,
 		     unification_kind_t strict,
 		     int flags,
 		     bool explain_p,
-		     bool decltype_p)
+		     bool decltype_p,
+                     ast_node *args_asnode)
 {
   tree parms;
   tree fntype;
@@ -18548,7 +18564,8 @@ fn_type_unification (tree fn,
 
   ok = !type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn),
 			       full_targs, parms, args, nargs, /*subr=*/0,
-			       strict, flags, &checks, explain_p);
+			       strict, flags, &checks, explain_p,
+                               args_asnode);
   if (!explain_p)
     pop_tinst_level ();
   if (!ok)
@@ -18784,7 +18801,8 @@ maybe_adjust_types_for_deduction (unification_kind_t strict,
 
 static int
 check_non_deducible_conversion (tree parm, tree arg, int strict,
-				int flags, bool explain_p)
+				int flags, bool explain_p,
+                                ast_node *arg_asnode)
 {
   tree type;
 
@@ -18813,7 +18831,7 @@ check_non_deducible_conversion (tree parm, tree arg, int strict,
   if (strict == DEDUCE_EXACT)
     return unify_type_mismatch (explain_p, parm, arg);
   else
-    return unify_arg_conversion (explain_p, parm, type, arg);
+    return unify_arg_conversion (explain_p, parm, type, arg, arg_asnode);
 }
 
 static bool uses_deducible_template_parms (tree type);
@@ -19110,7 +19128,8 @@ type_unification_real (tree tparms,
 		       unification_kind_t strict,
 		       int flags,
 		       vec<deferred_access_check, va_gc> **checks,
-		       bool explain_p)
+		       bool explain_p,
+                       ast_node *args_asnode)
 {
   tree parm, arg;
   int i;
@@ -19299,6 +19318,11 @@ type_unification_real (tree tparms,
 
       /* DR 1391: All parameters have args, now check non-dependent parms for
 	 convertibility.  */
+      // FIXME: merge into the clause below (requires reindentation)
+      auto_vec <ast_node *> argvec_asnodes;
+      if (saw_undeduced < 2 && args_asnode)
+        args_asnode->get_children_of_kind (argvec_asnodes,
+					   AST_ASSIGNMENT_EXPRESSION);
       if (saw_undeduced < 2)
 	for (ia = 0, parms = xparms, args = xargs, nargs = xnargs;
 	     parms && parms != void_list_node && ia < nargs; )
@@ -19323,12 +19347,16 @@ type_unification_real (tree tparms,
 	      continue;
 
 	    arg = args[ia];
+            ast_node *arg_asnode = NULL;
+            if (ia < argvec_asnodes.length ())
+              arg_asnode = argvec_asnodes[ia];
 	    ++ia;
 
 	    if (uses_template_parms (parm))
 	      continue;
+
 	    if (check_non_deducible_conversion (parm, arg, strict, flags,
-						explain_p))
+						explain_p, arg_asnode))
 	      return 1;
 	  }
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 4db2462..f09e606 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2279,7 +2279,7 @@ perform_koenig_lookup (cp_expr fn, vec<tree, va_gc> *args,
 
 tree
 finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
-		  bool koenig_p, tsubst_flags_t complain)
+		  bool koenig_p, tsubst_flags_t complain, ast_node *args_asnode)
 {
   tree result;
   tree orig_fn;
@@ -2395,7 +2395,7 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
 				       ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL
 				       : LOOKUP_NORMAL),
 				      /*fn_p=*/NULL,
-				      complain);
+				      complain, args_asnode);
     }
   else if (is_overloaded_fn (fn))
     {
@@ -2438,7 +2438,8 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
 	    }
 
 	  /* A call to a namespace-scope function.  */
-	  result = build_new_function_call (fn, args, koenig_p, complain);
+	  result = build_new_function_call (fn, args, koenig_p, complain,
+					    args_asnode);
 	}
     }
   else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 7aee0d6..ced08c7 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -3667,7 +3667,7 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
   /* Check for errors in format strings and inappropriately
      null parameters.  */
   bool warned_p = check_function_arguments (input_location, fndecl, fntype,
-					    nargs, argarray);
+					    nargs, argarray, NULL);
 
   ret = build_cxx_call (function, nargs, argarray, complain);
 
diff --git a/gcc/testsuite/g++.dg/diagnostic/Wformat-security-fixit.C b/gcc/testsuite/g++.dg/diagnostic/Wformat-security-fixit.C
new file mode 100644
index 0000000..dd53721
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/Wformat-security-fixit.C
@@ -0,0 +1,13 @@
+// { dg-options "-Wformat -Wformat-security -fdiagnostics-show-caret -fcapture-ast" }
+
+#include <stdio.h>
+
+void test (const char *msg)
+{
+  printf (msg); // { dg-warning "format not a string literal and no format arguments" }
+  /* { dg-begin-multiline-output "" }
+   printf (msg);
+           ^~~
+           "%s", 
+     { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
new file mode 100644
index 0000000..86a025c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
@@ -0,0 +1,151 @@
+// { dg-options "-fdiagnostics-show-caret -fcapture-ast" }
+
+/* decl, with argname.  */
+
+extern int callee_1 (int one, const char *two, float three); // { dg-message "initializing argument 2 of 'int callee_1\\(int, const char\\*, float\\)'" }
+/* { dg-begin-multiline-output "" }
+ extern int callee_1 (int one, const char *two, float three);
+                               ^~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+int test_1 (int first, int second, float third)
+{
+  return callee_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return callee_1 (first, second, third);
+                           ^~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* decl, without argname.  */
+
+extern int callee_2 (int, const char *, float); // { dg-message "initializing argument 2 of 'int callee_2\\(int, const char\\*, float\\)'" }
+/* { dg-begin-multiline-output "" }
+ extern int callee_2 (int, const char *, float);
+                           ^~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+int test_2 (int first, int second, float third)
+{
+  return callee_2 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return callee_2 (first, second, third);
+                           ^~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* defn, with argname.  */
+
+static int callee_3 (int one, const char *two, float three) // { dg-message "initializing argument 2 of 'int callee_3\\(int, const char\\*, float\\)'" }
+/* { dg-begin-multiline-output "" }
+ static int callee_3 (int one, const char *two, float three)
+                               ^~~~~~~~~~~~~~~
+     { dg-end-multiline-output "" } */
+{
+  return callee_2 (one, two, three);
+}
+
+int test_3 (int first, int second, float third)
+{
+  return callee_3 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return callee_3 (first, second, third);
+                           ^~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* static member, with argname.  */
+
+struct s4 { static int member_1 (int one, const char *two, float three); };
+/* { dg-begin-multiline-output "" }
+ struct s4 { static int member_1 (int one, const char *two, float three); };
+                                           ^~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+int test_4 (int first, int second, float third)
+{
+  return s4::member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return s4::member_1 (first, second, third);
+                               ^~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* non-static member, with argname.  */
+
+struct s5 { int member_1 (int one, const char *two, float three); };
+/* { dg-begin-multiline-output "" }
+ struct s5 { int member_1 (int one, const char *two, float three); };
+                                    ^~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+int test_5 (int first, int second, float third)
+{
+  s5 inst;
+  return inst.member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return inst.member_1 (first, second, third);
+                                ^~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* Template function.  */
+
+template <typename T>
+int test_6 (int one, T two, float three);
+/* { dg-begin-multiline-output "" }
+ int test_6 (int one, T two, float three);
+     ^~~~~~
+   { dg-end-multiline-output "" } */
+
+int test_6 (int first, int second, float third)
+{
+  return test_6 <const char *> (first, second, third); // { dg-error "no matching function" }
+  /* { dg-begin-multiline-output "" }
+   return test_6 <const char *> (first, second, third);
+                                                     ^
+     { dg-end-multiline-output "" } */
+  /* { dg-begin-multiline-output "" }
+   return test_6 <const char *> (first, second, third);
+                                        ^~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* Template class, static function.  */
+
+template <typename T>
+struct s7 { static int member_1 (int one, T two, float three); };
+/* { dg-begin-multiline-output "" }
+ struct s7 { static int member_1 (int one, T two, float three); };
+                                           ^~~~~
+   { dg-end-multiline-output "" } */
+
+int test_7 (int first, int second, float third)
+{
+  return s7 <const char *>::member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return s7 <const char *>::member_1 (first, second, third);
+                                              ^~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* Template class, non-static function.  */
+
+template <typename T>
+struct s8 { int member_1 (int one, T two, float three); };
+/* { dg-begin-multiline-output "" }
+ struct s8 { int member_1 (int one, T two, float three); };
+                                    ^~~~~
+   { dg-end-multiline-output "" } */
+
+int test_8 (int first, int second, float third)
+{
+  s8 <const char *> inst;
+  return inst.member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return inst.member_1 (first, second, third);
+                                ^~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+// TODO: template callsite
diff --git a/gcc/testsuite/g++.dg/warn/Wsuggest-override.C b/gcc/testsuite/g++.dg/warn/Wsuggest-override.C
index 8d567b2..7d4c311 100644
--- a/gcc/testsuite/g++.dg/warn/Wsuggest-override.C
+++ b/gcc/testsuite/g++.dg/warn/Wsuggest-override.C
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-options "-std=c++11 -Wsuggest-override -fdiagnostics-show-caret" }
+// { dg-options "-std=c++11 -Wsuggest-override -fdiagnostics-show-caret -fcapture-ast" }
 struct A
 {
 	A();
@@ -19,6 +19,7 @@ struct B : A
 /* { dg-begin-multiline-output "" }
   virtual void f();
                ^
+                   override
    { dg-end-multiline-output "" } */
 virtual int bar() override;
 int c();
@@ -26,6 +27,7 @@ operator int();
 virtual operator float(); // { dg-warning "can be marked override" }
 /* { dg-begin-multiline-output "" }
  virtual operator float();
-         ^~~~~~~~
+         ^~~~~~~~~~~~~~
+                          override
    { dg-end-multiline-output "" } */
 };
-- 
1.8.5.3

