From ae164d39e30fb03e7f6d5b61264a3e67adeae448 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 10 Aug 2018 13:58:14 -0400
Subject: [PATCH 12/17] FIXME: more WIP on diagnostic_group

---
 gcc/attribs.c                  |  33 ++--
 gcc/c-family/c-attribs.c       |  14 +-
 gcc/c-family/c-opts.c          |  13 +-
 gcc/c-family/c-warn.c          |  27 +--
 gcc/c-family/known-headers.cc  |  14 +-
 gcc/c-family/known-headers.h   |   4 +-
 gcc/c-family/name-hint.h       |   8 +-
 gcc/c/c-decl.c                 | 371 ++++++++++++++++++++----------------
 gcc/c/c-parser.c               |  42 +++--
 gcc/c/c-typeck.c               | 168 ++++++++++-------
 gcc/calls.c                    |  42 +++--
 gcc/cgraphunit.c               |  30 +--
 gcc/cp/call.c                  | 418 +++++++++++++++++++++++------------------
 gcc/cp/class.c                 | 180 ++++++++++--------
 gcc/cp/constexpr.c             |  59 +++---
 gcc/cp/constraint.cc           |   6 +-
 gcc/cp/cp-gimplify.c           |  15 +-
 gcc/cp/cp-tree.h               |  11 +-
 gcc/cp/cvt.c                   |  35 ++--
 gcc/cp/decl.c                  | 161 +++++++++-------
 gcc/cp/decl2.c                 |  50 ++---
 gcc/cp/error.c                 |  12 +-
 gcc/cp/friend.c                |  40 ++--
 gcc/cp/init.c                  |  83 ++++----
 gcc/cp/lex.c                   |   5 +-
 gcc/cp/name-lookup.c           | 166 ++++++++--------
 gcc/cp/parser.c                | 106 ++++++-----
 gcc/cp/pt.c                    |  86 +++++----
 gcc/cp/search.c                |  74 ++++----
 gcc/cp/tree.c                  |  22 ++-
 gcc/cp/typeck.c                | 100 +++++-----
 gcc/cp/typeck2.c               |  65 ++++---
 gcc/diagnostic-core.h          |  37 +++-
 gcc/diagnostic.c               | 319 ++++++++++++++++++++++++-------
 gcc/gimple-ssa-isolate-paths.c |  45 +++--
 gcc/gimple-ssa-warn-alloca.c   |  50 ++---
 gcc/gimple-ssa-warn-restrict.c |  54 +++---
 gcc/gimplify.c                 |  27 +--
 gcc/hsa-gen.c                  |  10 +-
 gcc/ipa-devirt.c               | 196 ++++++++++---------
 gcc/multiple_target.c          |   7 +-
 gcc/opts-common.c              |   9 +-
 gcc/reginfo.c                  |  12 +-
 gcc/substring-locations.c      |   6 +-
 gcc/tree-inline.c              |  11 +-
 gcc/tree-ssa-ccp.c             |  17 +-
 gcc/tree-ssa-loop-niter.c      |   7 +-
 gcc/tree-ssa-uninit.c          |   5 +-
 gcc/tree.c                     |  30 +--
 49 files changed, 1931 insertions(+), 1371 deletions(-)

diff --git a/gcc/attribs.c b/gcc/attribs.c
index efc879b..09c9ceb 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -430,23 +430,23 @@ diag_attr_exclusions (tree last_decl, tree node, tree attrname,
 
 	  /* Print a note?  */
 	  bool note = last_decl != NULL_TREE;
-
+	  diagnostic_group d;
 	  if (TREE_CODE (node) == FUNCTION_DECL
 	      && DECL_BUILT_IN (node))
-	    note &= warning (OPT_Wattributes,
-			     "ignoring attribute %qE in declaration of "
-			     "a built-in function %qD because it conflicts "
-			     "with attribute %qs",
-			     attrname, node, excl->name);
+	    note &= d.warning (OPT_Wattributes,
+			       "ignoring attribute %qE in declaration of "
+			       "a built-in function %qD because it conflicts "
+			       "with attribute %qs",
+			       attrname, node, excl->name);
 	  else
-	    note &= warning (OPT_Wattributes,
-			     "ignoring attribute %qE because "
-			     "it conflicts with attribute %qs",
-			     attrname, excl->name);
+	    note &= d.warning (OPT_Wattributes,
+			       "ignoring attribute %qE because "
+			       "it conflicts with attribute %qs",
+			       attrname, excl->name);
 
 	  if (note)
-	    inform (DECL_SOURCE_LOCATION (last_decl),
-		    "previous declaration here");
+	    d.inform (DECL_SOURCE_LOCATION (last_decl),
+		      "previous declaration here");
 	}
     }
 
@@ -587,10 +587,11 @@ decl_attributes (tree *node, tree attributes, int flags,
 	  /* This is a c++11 attribute that appertains to a
 	     type-specifier, outside of the definition of, a class
 	     type.  Ignore it.  */
-	  if (warning (OPT_Wattributes, "attribute ignored"))
-	    inform (input_location,
-		    "an attribute that appertains to a type-specifier "
-		    "is ignored");
+	  diagnostic_group d;
+	  if (d.warning (OPT_Wattributes, "attribute ignored"))
+	    d.inform (input_location,
+		      "an attribute that appertains to a type-specifier "
+		      "is ignored");
 	  continue;
 	}
 
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 9da9c27..1f1ec16 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -1881,17 +1881,19 @@ common_handle_aligned_attribute (tree *node, tree name, tree args, int flags,
       bitalign /= BITS_PER_UNIT;
 
       bool diagd = true;
+      diagnostic_group d;
       if (DECL_USER_ALIGN (decl) || DECL_USER_ALIGN (last_decl))
-	diagd = warning (OPT_Wattributes,
-			  "ignoring attribute %<%E (%u)%> because it conflicts "
-			  "with attribute %<%E (%u)%>",
-			  name, bitalign, name, curalign);
+	diagd = d.warning (OPT_Wattributes,
+			   "ignoring attribute %<%E (%u)%> because it "
+			   "conflicts with attribute %<%E (%u)%>",
+			   name, bitalign, name, curalign);
       else if (!warn_if_not_aligned_p)
 	/* Do not error out for attribute warn_if_not_aligned.  */
-	error ("alignment for %q+D must be at least %d", decl, curalign);
+	d.error ("alignment for %q+D must be at least %d", decl, curalign);
 
       if (diagd && note)
-	inform (DECL_SOURCE_LOCATION (last_decl), "previous declaration here");
+	d.inform (DECL_SOURCE_LOCATION (last_decl),
+		  "previous declaration here");
 
       *no_add_attrs = true;
     }
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index cb69fb3..532fec9 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -931,13 +931,14 @@ c_common_post_options (const char **pfilename)
       warn_abi_version = latest_abi_version;
       if (flag_abi_version == latest_abi_version)
 	{
-	  if (warning (OPT_Wabi, "-Wabi won't warn about anything"))
+	  diagnostic_group d;
+	  if (d.warning (OPT_Wabi, "-Wabi won't warn about anything"))
 	    {
-	      inform (input_location, "-Wabi warns about differences "
-		      "from the most up-to-date ABI, which is also used "
-		      "by default");
-	      inform (input_location, "use e.g. -Wabi=11 to warn about "
-		      "changes from GCC 7");
+	      d.inform (input_location, "-Wabi warns about differences "
+			"from the most up-to-date ABI, which is also used "
+			"by default");
+	      d.inform (input_location, "use e.g. -Wabi=11 to warn about "
+			"changes from GCC 7");
 	    }
 	  flag_abi_compat_version = abi_compat_default;
 	}
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index d34d667..33a4516 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -491,17 +491,18 @@ warn_logical_not_parentheses (location_t location, enum tree_code code,
       && integer_zerop (rhs))
     return;
 
-  if (warning_at (location, OPT_Wlogical_not_parentheses,
-		  "logical not is only applied to the left hand side of "
-		  "comparison")
+  diagnostic_group d;
+  if (d.warning_at (location, OPT_Wlogical_not_parentheses,
+		    "logical not is only applied to the left hand side of "
+		    "comparison")
       && EXPR_HAS_LOCATION (lhs))
     {
       location_t lhs_loc = EXPR_LOCATION (lhs);
       rich_location richloc (line_table, lhs_loc);
       richloc.add_fixit_insert_before (lhs_loc, "(");
       richloc.add_fixit_insert_after (lhs_loc, ")");
-      inform (&richloc, "add parentheses around left hand side "
-	      "expression to silence this warning");
+      d.inform (&richloc, "add parentheses around left hand side "
+		"expression to silence this warning");
     }
 }
 
@@ -2232,9 +2233,10 @@ warn_duplicated_cond_add_or_warn (location_t loc, tree cond, vec<tree> **chain)
   FOR_EACH_VEC_ELT (**chain, ix, t)
     if (operand_equal_p (cond, t, 0))
       {
-	if (warning_at (loc, OPT_Wduplicated_cond,
-			"duplicated %<if%> condition"))
-	  inform (EXPR_LOCATION (t), "previously used here");
+	diagnostic_group d;
+	if (d.warning_at (loc, OPT_Wduplicated_cond,
+			  "duplicated %<if%> condition"))
+	  d.inform (EXPR_LOCATION (t), "previously used here");
 	found = true;
 	break;
       }
@@ -2601,8 +2603,9 @@ warn_for_multistatement_macros (location_t body_loc, location_t next_loc,
 	return;
     }
 
-  if (warning_at (body_loc, OPT_Wmultistatement_macros,
-		  "macro expands to multiple statements"))
-    inform (guard_loc, "some parts of macro expansion are not guarded by "
-	    "this %qs clause", guard_tinfo_to_string (keyword));
+  diagnostic_group d;
+  if (d.warning_at (body_loc, OPT_Wmultistatement_macros,
+		    "macro expands to multiple statements"))
+    d.inform (guard_loc, "some parts of macro expansion are not guarded by "
+	      "this %qs clause", guard_tinfo_to_string (keyword));
 }
diff --git a/gcc/c-family/known-headers.cc b/gcc/c-family/known-headers.cc
index 5524d21..8dff491 100644
--- a/gcc/c-family/known-headers.cc
+++ b/gcc/c-family/known-headers.cc
@@ -175,10 +175,12 @@ get_cp_stdlib_header_for_name (const char *name)
 
 /* suggest_missing_header's ctor.  */
 
-suggest_missing_header::suggest_missing_header (location_t loc,
+suggest_missing_header::suggest_missing_header (diagnostic_group *group,
+						location_t loc,
 						const char *name,
 						const char *header_hint)
-: deferred_diagnostic (loc), m_name_str (name), m_header_hint (header_hint)
+: deferred_diagnostic (group, loc),
+  m_name_str (name), m_header_hint (header_hint)
 {
   gcc_assert (name);
   gcc_assert (header_hint);
@@ -193,8 +195,8 @@ suggest_missing_header::~suggest_missing_header ()
 
   gcc_rich_location richloc (get_location ());
   maybe_add_include_fixit (&richloc, m_header_hint);
-  inform (&richloc,
-	  "%qs is defined in header %qs;"
-	  " did you forget to %<#include %s%>?",
-	  m_name_str, m_header_hint, m_header_hint);
+  get_group ()->inform (&richloc,
+			"%qs is defined in header %qs;"
+			" did you forget to %<#include %s%>?",
+			m_name_str, m_header_hint, m_header_hint);
 }
diff --git a/gcc/c-family/known-headers.h b/gcc/c-family/known-headers.h
index 3a68ad2..941e532 100644
--- a/gcc/c-family/known-headers.h
+++ b/gcc/c-family/known-headers.h
@@ -29,8 +29,8 @@ extern const char *get_cp_stdlib_header_for_name (const char *name);
 class suggest_missing_header : public deferred_diagnostic
 {
  public:
-  suggest_missing_header (location_t loc, const char *name,
-			  const char *header_hint);
+  suggest_missing_header (diagnostic_group *group, location_t,
+			  const char *name, const char *header_hint);
   ~suggest_missing_header ();
 
  private:
diff --git a/gcc/c-family/name-hint.h b/gcc/c-family/name-hint.h
index ef0e4a3..5b28a82 100644
--- a/gcc/c-family/name-hint.h
+++ b/gcc/c-family/name-hint.h
@@ -50,6 +50,7 @@ class deferred_diagnostic
  public:
   virtual ~deferred_diagnostic () {}
 
+  diagnostic_group *get_group () const { return m_group; }
   location_t get_location () const { return m_loc; }
 
   /* Call this if the corresponding warning was not emitted,
@@ -62,10 +63,11 @@ class deferred_diagnostic
   bool is_suppressed_p () const { return m_suppress; }
 
  protected:
-  deferred_diagnostic (location_t loc)
-  : m_loc (loc), m_suppress (false) {}
+  deferred_diagnostic (diagnostic_group *group, location_t loc)
+  : m_group (group), m_loc (loc), m_suppress (false) {}
 
  private:
+  diagnostic_group *m_group;
   location_t m_loc;
   bool m_suppress;
 };
@@ -116,6 +118,6 @@ private:
 };
 
 extern name_hint lookup_name_fuzzy (tree, enum lookup_name_fuzzy_kind,
-				    location_t);
+				    diagnostic_group *, location_t);
 
 #endif /* ! GCC_NAME_HINT_H */
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index ed1dd28..a3d3267 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -1571,11 +1571,12 @@ pushtag (location_t loc, tree name, tree type)
 	  && (TYPE_MAIN_VARIANT (TREE_TYPE (b->decl))
 	      != TYPE_MAIN_VARIANT (type)))
 	{
-	  if (warning_at (loc, OPT_Wc___compat,
-			  ("using %qD as both a typedef and a tag is "
-			   "invalid in C++"), b->decl)
+	  diagnostic_group d;
+	  if (d.warning_at (loc, OPT_Wc___compat,
+			    ("using %qD as both a typedef and a tag is "
+			     "invalid in C++"), b->decl)
 	      && b->locus != UNKNOWN_LOCATION)
-	    inform (b->locus, "originally defined here");
+	    d.inform (b->locus, "originally defined here");
 	}
     }
 }
@@ -1684,7 +1685,8 @@ match_builtin_function_types (tree newtype, tree oldtype)
    mismatch involving an empty arglist vs a nonempty one and give clearer
    diagnostics.  */
 static void
-diagnose_arglist_conflict (tree newdecl, tree olddecl,
+diagnose_arglist_conflict (diagnostic_group *d,
+			   tree newdecl, tree olddecl,
 			   tree newtype, tree oldtype)
 {
   tree t;
@@ -1705,15 +1707,16 @@ diagnose_arglist_conflict (tree newdecl, tree olddecl,
       if (TREE_CHAIN (t) == NULL_TREE
 	  && TYPE_MAIN_VARIANT (type) != void_type_node)
 	{
-	  inform (input_location, "a parameter list with an ellipsis can%'t match "
-		  "an empty parameter name list declaration");
+	  d->inform (input_location, "a parameter list with an ellipsis can%'t "
+		     "match an empty parameter name list declaration");
 	  break;
 	}
 
       if (c_type_promotes_to (type) != type)
 	{
-	  inform (input_location, "an argument type that has a default promotion can%'t match "
-		  "an empty parameter name list declaration");
+	  d->inform (input_location, "an argument type that has a default "
+		     "promotion can%'t match an empty parameter name list "
+		     "declaration");
 	  break;
 	}
     }
@@ -1724,7 +1727,8 @@ diagnose_arglist_conflict (tree newdecl, tree olddecl,
    Diagnose inconsistencies in the argument list.  Returns TRUE if
    the prototype is compatible, FALSE if not.  */
 static bool
-validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype)
+validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype,
+			       diagnostic_group *d)
 {
   tree newargs, oldargs;
   int i;
@@ -1759,14 +1763,14 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype)
 	 agree on the number of arguments.  */
       if (END_OF_ARGLIST (oldargtype))
 	{
-	  error ("prototype for %q+D declares more arguments "
-		 "than previous old-style definition", newdecl);
+	  d->error ("prototype for %q+D declares more arguments "
+		    "than previous old-style definition", newdecl);
 	  return false;
 	}
       else if (END_OF_ARGLIST (newargtype))
 	{
-	  error ("prototype for %q+D declares fewer arguments "
-		 "than previous old-style definition", newdecl);
+	  d->error ("prototype for %q+D declares fewer arguments "
+		    "than previous old-style definition", newdecl);
 	  return false;
 	}
 
@@ -1774,9 +1778,9 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype)
 	 for the arg.  */
       else if (!comptypes (oldargtype, newargtype))
 	{
-	  error ("prototype for %q+D declares argument %d"
-		 " with incompatible type",
-		 newdecl, i);
+	  d->error ("prototype for %q+D declares argument %d"
+		    " with incompatible type",
+		    newdecl, i);
 	  return false;
 	}
 
@@ -1787,27 +1791,28 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype)
 
   /* If we get here, no errors were found, but do issue a warning
      for this poor-style construct.  */
-  warning (0, "prototype for %q+D follows non-prototype definition",
-	   newdecl);
+  d->warning (0, "prototype for %q+D follows non-prototype definition",
+	      newdecl);
   return true;
 #undef END_OF_ARGLIST
 }
 
 /* Subroutine of diagnose_mismatched_decls.  Report the location of DECL,
    first in a pair of mismatched declarations, using the diagnostic
-   function DIAG.  */
+   group D.  */
 static void
-locate_old_decl (tree decl)
+locate_old_decl (tree decl, diagnostic_group *d)
 {
   if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl)
       && !C_DECL_DECLARED_BUILTIN (decl))
     ;
   else if (DECL_INITIAL (decl))
-    inform (input_location, "previous definition of %q+D was here", decl);
+    d->inform (input_location, "previous definition of %q+D was here", decl);
   else if (C_DECL_IMPLICIT (decl))
-    inform (input_location, "previous implicit declaration of %q+D was here", decl);
+    d->inform (input_location, "previous implicit declaration of %q+D was here",
+	      decl);
   else
-    inform (input_location, "previous declaration of %q+D was here", decl);
+    d->inform (input_location, "previous declaration of %q+D was here", decl);
 }
 
 /* Subroutine of duplicate_decls.  Compare NEWDECL to OLDDECL.
@@ -1823,8 +1828,6 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 			   tree *newtypep, tree *oldtypep)
 {
   tree newtype, oldtype;
-  bool pedwarned = false;
-  bool warned = false;
   bool retval = true;
 
 #define DECL_EXTERN_INLINE(DECL) (DECL_DECLARED_INLINE_P (DECL)  \
@@ -1847,8 +1850,9 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 	    && DECL_BUILT_IN (olddecl)
 	    && !C_DECL_DECLARED_BUILTIN (olddecl)))
 	{
-	  error ("%q+D redeclared as different kind of symbol", newdecl);
-	  locate_old_decl (olddecl);
+	  diagnostic_group d;
+	  d.error ("%q+D redeclared as different kind of symbol", newdecl);
+	  locate_old_decl (olddecl, &d);
 	}
       else if (TREE_PUBLIC (newdecl))
 	warning (OPT_Wbuiltin_declaration_mismatch,
@@ -1864,11 +1868,16 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
      given scope.  */
   if (TREE_CODE (olddecl) == CONST_DECL)
     {
-      error ("redeclaration of enumerator %q+D", newdecl);
-      locate_old_decl (olddecl);
+      diagnostic_group d;
+      d.error ("redeclaration of enumerator %q+D", newdecl);
+      locate_old_decl (olddecl, &d);
       return false;
     }
 
+  bool pedwarned = false;
+  bool warned = false;
+  diagnostic_group d;
+
   if (!comptypes (oldtype, newtype))
     {
       if (TREE_CODE (olddecl) == FUNCTION_DECL
@@ -1910,8 +1919,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 	       && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node
 	       && C_FUNCTION_IMPLICIT_INT (newdecl) && !DECL_INITIAL (olddecl))
 	{
-	  pedwarned = pedwarn (input_location, 0,
-			       "conflicting types for %q+D", newdecl);
+	  pedwarned = d.pedwarn (input_location, 0,
+				 "conflicting types for %q+D", newdecl);
 	  /* Make sure we keep void as the return type.  */
 	  TREE_TYPE (newdecl) = *newtypep = newtype = oldtype;
 	  C_FUNCTION_IMPLICIT_INT (newdecl) = 0;
@@ -1923,8 +1932,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 	       && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == integer_type_node
 	       && C_DECL_IMPLICIT (olddecl) && !DECL_INITIAL (olddecl))
 	{
-	  pedwarned = pedwarn (input_location, 0,
-			       "conflicting types for %q+D", newdecl);
+	  pedwarned = d.pedwarn (input_location, 0,
+				 "conflicting types for %q+D", newdecl);
 	  /* Make sure we keep void as the return type.  */
 	  TREE_TYPE (olddecl) = *oldtypep = oldtype = newtype;
 	}
@@ -1940,29 +1949,29 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 	      if (new_addr != old_addr)
 		{
 		  if (ADDR_SPACE_GENERIC_P (new_addr))
-		    error ("conflicting named address spaces (generic vs %s) "
-			   "for %q+D",
-			   c_addr_space_name (old_addr), newdecl);
+		    d.error ("conflicting named address spaces (generic vs %s) "
+			     "for %q+D",
+			     c_addr_space_name (old_addr), newdecl);
 		  else if (ADDR_SPACE_GENERIC_P (old_addr))
-		    error ("conflicting named address spaces (%s vs generic) "
-			   "for %q+D",
-			   c_addr_space_name (new_addr), newdecl);
+		    d.error ("conflicting named address spaces (%s vs generic) "
+			     "for %q+D",
+			     c_addr_space_name (new_addr), newdecl);
 		  else
-		    error ("conflicting named address spaces (%s vs %s) "
-			   "for %q+D",
-			   c_addr_space_name (new_addr),
-			   c_addr_space_name (old_addr),
-			   newdecl);
+		    d.error ("conflicting named address spaces (%s vs %s) "
+			     "for %q+D",
+			     c_addr_space_name (new_addr),
+			     c_addr_space_name (old_addr),
+			     newdecl);
 		}
 
 	      if (CLEAR_QUAL_ADDR_SPACE (new_quals)
 		  != CLEAR_QUAL_ADDR_SPACE (old_quals))
-		error ("conflicting type qualifiers for %q+D", newdecl);
+		d.error ("conflicting type qualifiers for %q+D", newdecl);
 	    }
 	  else
-	    error ("conflicting types for %q+D", newdecl);
-	  diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype);
-	  locate_old_decl (olddecl);
+	    d.error ("conflicting types for %q+D", newdecl);
+	  diagnose_arglist_conflict (&d, newdecl, olddecl, newtype, oldtype);
+	  locate_old_decl (olddecl, &d);
 	  return false;
 	}
     }
@@ -1982,8 +1991,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 
       if (comptypes_result != 1 || types_different)
 	{
-	  error ("redefinition of typedef %q+D with different type", newdecl);
-	  locate_old_decl (olddecl);
+	  d.error ("redefinition of typedef %q+D with different type", newdecl);
+	  locate_old_decl (olddecl, &d);
 	  return false;
 	}
 
@@ -1995,13 +2004,17 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 
       if (variably_modified_type_p (newtype, NULL))
 	{
-	  error ("redefinition of typedef %q+D with variably modified type",
+	  d.error ("redefinition of typedef %q+D with variably modified type",
 		 newdecl);
-	  locate_old_decl (olddecl);
+	  locate_old_decl (olddecl, &d);
+	}
+      else
+	{
+	  // FIXME: use d here:
+	  if (pedwarn_c99 (input_location, OPT_Wpedantic,
+			   "redefinition of typedef %q+D", newdecl))
+	    locate_old_decl (olddecl, &d);
 	}
-      else if (pedwarn_c99 (input_location, OPT_Wpedantic,
-			    "redefinition of typedef %q+D", newdecl))
-	locate_old_decl (olddecl);
 
       return true;
     }
@@ -2052,8 +2065,9 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 		  )
 		  && same_translation_unit_p (newdecl, olddecl))
 		{
-		  error ("redefinition of %q+D", newdecl);
-		  locate_old_decl (olddecl);
+		  diagnostic_group d;
+		  d.error ("redefinition of %q+D", newdecl);
+		  locate_old_decl (olddecl, &d);
 		  return false;
 		}
 	    }
@@ -2062,11 +2076,14 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 	 the argument types must be checked specially.  */
       else if (DECL_INITIAL (olddecl)
 	       && !prototype_p (oldtype) && prototype_p (newtype)
-	       && TYPE_ACTUAL_ARG_TYPES (oldtype)
-	       && !validate_proto_after_old_defn (newdecl, newtype, oldtype))
+	       && TYPE_ACTUAL_ARG_TYPES (oldtype))
 	{
-	  locate_old_decl (olddecl);
-	  return false;
+	  diagnostic_group d;
+	  if (!validate_proto_after_old_defn (newdecl, newtype, oldtype, &d))
+	    {
+	      locate_old_decl (olddecl, &d);
+	      return false;
+	    }
 	}
       /* A non-static declaration (even an "extern") followed by a
 	 static declaration is undefined behavior per C99 6.2.2p3-5,7.
@@ -2087,9 +2104,10 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 	  if (!DECL_IS_BUILTIN (olddecl)
 	      && !DECL_EXTERN_INLINE (olddecl))
 	    {
-	      error ("static declaration of %q+D follows "
-		     "non-static declaration", newdecl);
-	      locate_old_decl (olddecl);
+	      diagnostic_group d;
+	      d.error ("static declaration of %q+D follows "
+		       "non-static declaration", newdecl);
+	      locate_old_decl (olddecl, &d);
 	    }
 	  return false;
 	}
@@ -2097,16 +2115,17 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 	{
 	  if (DECL_CONTEXT (olddecl))
 	    {
+	      diagnostic_group d;
 	      error ("non-static declaration of %q+D follows "
 		     "static declaration", newdecl);
-	      locate_old_decl (olddecl);
+	      locate_old_decl (olddecl, &d);
 	      return false;
 	    }
 	  else if (warn_traditional)
 	    {
-	      warned |= warning (OPT_Wtraditional,
-				 "non-static declaration of %q+D "
-				 "follows static declaration", newdecl);
+	      warned |= d.warning (OPT_Wtraditional,
+				   "non-static declaration of %q+D "
+				   "follows static declaration", newdecl);
 	    }
 	}
 
@@ -2121,10 +2140,12 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 					DECL_ATTRIBUTES (olddecl)) != NULL;
 	  if (newa != olda)
 	    {
-	      error_at (input_location, "%<gnu_inline%> attribute present on %q+D",
-			newa ? newdecl : olddecl);
-	      error_at (DECL_SOURCE_LOCATION (newa ? olddecl : newdecl),
-			"but not here");
+	      diagnostic_group d;
+	      d.error_at (input_location,
+			  "%<gnu_inline%> attribute present on %q+D",
+			  newa ? newdecl : olddecl);
+	      d.error_at (DECL_SOURCE_LOCATION (newa ? olddecl : newdecl),
+			  "but not here");
 	    }
 	}
     }
@@ -2141,22 +2162,24 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 	}
       else if (DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P (olddecl))
 	{
+	  diagnostic_group d;
 	  if (DECL_THREAD_LOCAL_P (newdecl))
-	    error ("thread-local declaration of %q+D follows "
-		   "non-thread-local declaration", newdecl);
+	    d.error ("thread-local declaration of %q+D follows "
+		     "non-thread-local declaration", newdecl);
 	  else
-	    error ("non-thread-local declaration of %q+D follows "
-		   "thread-local declaration", newdecl);
+	    d.error ("non-thread-local declaration of %q+D follows "
+		     "thread-local declaration", newdecl);
 
-	  locate_old_decl (olddecl);
+	  locate_old_decl (olddecl, &d);
 	  return false;
 	}
 
       /* Multiple initialized definitions are not allowed (6.9p3,5).  */
       if (DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl))
 	{
-	  error ("redefinition of %q+D", newdecl);
-	  locate_old_decl (olddecl);
+	  diagnostic_group d;
+	  d.error ("redefinition of %q+D", newdecl);
+	  locate_old_decl (olddecl, &d);
 	  return false;
 	}
 
@@ -2175,28 +2198,30 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 	    {
 	      if (!DECL_FILE_SCOPE_P (olddecl))
 		{
-		  error ("extern declaration of %q+D follows "
-			 "declaration with no linkage", newdecl);
-		  locate_old_decl (olddecl);
+		  diagnostic_group d;
+		  d.error ("extern declaration of %q+D follows "
+			   "declaration with no linkage", newdecl);
+		  locate_old_decl (olddecl, &d);
 		  return false;
 		}
 	      else if (warn_traditional)
 		{
-		  warned |= warning (OPT_Wtraditional,
-				     "non-static declaration of %q+D "
-				     "follows static declaration", newdecl);
+		  warned |= d.warning (OPT_Wtraditional,
+				       "non-static declaration of %q+D "
+				       "follows static declaration", newdecl);
 		}
 	    }
 	  else
 	    {
+	      diagnostic_group d;
 	      if (TREE_PUBLIC (newdecl))
-		error ("non-static declaration of %q+D follows "
-		       "static declaration", newdecl);
+		d.error ("non-static declaration of %q+D follows "
+			 "static declaration", newdecl);
 	      else
-		error ("static declaration of %q+D follows "
-		       "non-static declaration", newdecl);
+		d.error ("static declaration of %q+D follows "
+			 "non-static declaration", newdecl);
 
-	      locate_old_decl (olddecl);
+	      locate_old_decl (olddecl, &d);
 	      return false;
 	    }
 	}
@@ -2211,14 +2236,16 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 	    }
 	  else if (DECL_EXTERNAL (olddecl))
 	    {
-	      error ("declaration of %q+D with no linkage follows "
-		     "extern declaration", newdecl);
-	      locate_old_decl (olddecl);
+	      diagnostic_group d;
+	      d.error ("declaration of %q+D with no linkage follows "
+		       "extern declaration", newdecl);
+	      locate_old_decl (olddecl, &d);
 	    }
 	  else
 	    {
-	      error ("redeclaration of %q+D with no linkage", newdecl);
-	      locate_old_decl (olddecl);
+	      diagnostic_group d;
+	      d.error ("redeclaration of %q+D with no linkage", newdecl);
+	      locate_old_decl (olddecl, &d);
 	    }
 
 	  return false;
@@ -2230,11 +2257,11 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 	  && DECL_FILE_SCOPE_P (newdecl)
 	  && !DECL_EXTERNAL (newdecl)
 	  && !DECL_EXTERNAL (olddecl))
-	warned |= warning_at (DECL_SOURCE_LOCATION (newdecl),
-			      OPT_Wc___compat,
-			      ("duplicate declaration of %qD is "
-			       "invalid in C++"),
-			      newdecl);
+	warned |= d.warning_at (DECL_SOURCE_LOCATION (newdecl),
+				OPT_Wc___compat,
+				("duplicate declaration of %qD is "
+				 "invalid in C++"),
+				newdecl);
     }
 
   /* warnings */
@@ -2243,8 +2270,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
       && DECL_VISIBILITY_SPECIFIED (newdecl) && DECL_VISIBILITY_SPECIFIED (olddecl)
       && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl))
     {
-      warned |= warning (0, "redeclaration of %q+D with different visibility "
-			 "(old visibility preserved)", newdecl);
+      warned |= d.warning (0, "redeclaration of %q+D with different visibility "
+			   "(old visibility preserved)", newdecl);
     }
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
@@ -2263,8 +2290,9 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
       if (TREE_CODE (newdecl) == PARM_DECL
 	  && (!TREE_ASM_WRITTEN (olddecl) || TREE_ASM_WRITTEN (newdecl)))
 	{
-	  error ("redefinition of parameter %q+D", newdecl);
-	  locate_old_decl (olddecl);
+	  diagnostic_group d;
+	  d.error ("redefinition of parameter %q+D", newdecl);
+	  locate_old_decl (olddecl, &d);
 	  return false;
 	}
     }
@@ -2290,13 +2318,14 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
       && !(VAR_P (newdecl)
 	   && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl)))
     {
-      warned = warning (OPT_Wredundant_decls, "redundant redeclaration of %q+D",
-			newdecl);
+      warned = d.warning (OPT_Wredundant_decls,
+			  "redundant redeclaration of %q+D",
+			  newdecl);
     }
 
   /* Report location of previous decl/defn.  */
   if (warned || pedwarned)
-    locate_old_decl (olddecl);
+    locate_old_decl (olddecl, &d);
 
 #undef DECL_EXTERN_INLINE
 
@@ -2778,7 +2807,6 @@ warn_if_shadowing (tree new_decl)
 					     DECL_SOURCE_LOCATION (b->decl))))
       {
 	tree old_decl = b->decl;
-	bool warned = false;
 
 	if (old_decl == error_mark_node)
 	  {
@@ -2786,7 +2814,10 @@ warn_if_shadowing (tree new_decl)
 		     "non-variable", new_decl);
 	    break;
 	  }
-	else if (TREE_CODE (old_decl) == PARM_DECL)
+
+	bool warned = false;
+	diagnostic_group d;
+	if (TREE_CODE (old_decl) == PARM_DECL)
 	  {
 	    enum opt_code warning_code;
 
@@ -2800,9 +2831,10 @@ warn_if_shadowing (tree new_decl)
 	      warning_code = OPT_Wshadow_compatible_local;
 	    else
 	      warning_code = OPT_Wshadow_local;
-	    warned = warning_at (DECL_SOURCE_LOCATION (new_decl), warning_code,
-				 "declaration of %qD shadows a parameter",
-				 new_decl);
+	    warned = d.warning_at (DECL_SOURCE_LOCATION (new_decl),
+				   warning_code,
+				   "declaration of %qD shadows a parameter",
+				   new_decl);
 	  }
 	else if (DECL_FILE_SCOPE_P (old_decl))
 	  {
@@ -2813,10 +2845,10 @@ warn_if_shadowing (tree new_decl)
 		&& !FUNCTION_POINTER_TYPE_P (TREE_TYPE (new_decl)))
 		continue;
 
-	    warned = warning_at (DECL_SOURCE_LOCATION (new_decl), OPT_Wshadow,
-				 "declaration of %qD shadows a global "
-				 "declaration",
-				 new_decl);
+	    warned = d.warning_at (DECL_SOURCE_LOCATION (new_decl), OPT_Wshadow,
+				   "declaration of %qD shadows a global "
+				   "declaration",
+				   new_decl);
 	  }
 	else if (TREE_CODE (old_decl) == FUNCTION_DECL
 		 && DECL_BUILT_IN (old_decl))
@@ -2839,14 +2871,16 @@ warn_if_shadowing (tree new_decl)
 	      warning_code = OPT_Wshadow_compatible_local;
 	    else
 	      warning_code = OPT_Wshadow_local;
-	    warned = warning_at (DECL_SOURCE_LOCATION (new_decl), warning_code,
-				 "declaration of %qD shadows a previous local",
-				 new_decl);
+	    warned = d.warning_at (DECL_SOURCE_LOCATION (new_decl),
+				   warning_code,
+				   "declaration of %qD shadows a previous "
+				   "local",
+				   new_decl);
 	  }
 
 	if (warned)
-	  inform (DECL_SOURCE_LOCATION (old_decl),
-		  "shadowed declaration is here");
+	  d.inform (DECL_SOURCE_LOCATION (old_decl),
+		    "shadowed declaration is here");
 
 	break;
       }
@@ -3123,9 +3157,10 @@ implicit_decl_warning (location_t loc, tree id, tree olddecl)
     return;
 
   bool warned;
+  diagnostic_group d;
   name_hint hint;
   if (!olddecl)
-    hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_FUNCTION_NAME, loc);
+    hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_FUNCTION_NAME, &d, loc);
 
   if (flag_isoc99)
     {
@@ -3133,30 +3168,30 @@ implicit_decl_warning (location_t loc, tree id, tree olddecl)
 	{
 	  gcc_rich_location richloc (loc);
 	  richloc.add_fixit_replace (hint.suggestion ());
-	  warned = pedwarn (&richloc, OPT_Wimplicit_function_declaration,
-			    "implicit declaration of function %qE;"
-			    " did you mean %qs?",
-			    id, hint.suggestion ());
+	  warned = d.pedwarn (&richloc, OPT_Wimplicit_function_declaration,
+			      "implicit declaration of function %qE;"
+			      " did you mean %qs?",
+			      id, hint.suggestion ());
 	}
       else
-	warned = pedwarn (loc, OPT_Wimplicit_function_declaration,
-			  "implicit declaration of function %qE", id);
+	warned = d.pedwarn (loc, OPT_Wimplicit_function_declaration,
+			    "implicit declaration of function %qE", id);
     }
   else if (hint)
     {
       gcc_rich_location richloc (loc);
       richloc.add_fixit_replace (hint.suggestion ());
-      warned = warning_at
+      warned = d.warning_at
 	(&richloc, OPT_Wimplicit_function_declaration,
 	 G_("implicit declaration of function %qE; did you mean %qs?"),
 	 id, hint.suggestion ());
     }
   else
-    warned = warning_at (loc, OPT_Wimplicit_function_declaration,
-			 G_("implicit declaration of function %qE"), id);
+    warned = d.warning_at (loc, OPT_Wimplicit_function_declaration,
+			   G_("implicit declaration of function %qE"), id);
 
   if (olddecl && warned)
-    locate_old_decl (olddecl);
+    locate_old_decl (olddecl, &d);
 
   if (!warned)
     hint.suppress ();
@@ -3435,9 +3470,10 @@ implicitly_declare (location_t loc, tree functionid)
 	    {
 	      if (!comptypes (newtype, TREE_TYPE (decl)))
 		{
-		  error_at (loc, "incompatible implicit declaration of "
-			    "function %qD", decl);
-		  locate_old_decl (decl);
+		  diagnostic_group d;
+		  d.error_at (loc, "incompatible implicit declaration of "
+			      "function %qD", decl);
+		  locate_old_decl (decl, &d);
 		}
 	    }
 	  b->u.type = TREE_TYPE (decl);
@@ -3487,43 +3523,45 @@ undeclared_variable (location_t loc, tree id)
   static bool already = false;
   struct c_scope *scope;
 
+  diagnostic_group d;
   if (current_function_decl == NULL_TREE)
     {
-      name_hint guessed_id = lookup_name_fuzzy (id, FUZZY_LOOKUP_NAME, loc);
+      name_hint guessed_id = lookup_name_fuzzy (id, FUZZY_LOOKUP_NAME, &d, loc);
       if (guessed_id)
 	{
 	  gcc_rich_location richloc (loc);
 	  richloc.add_fixit_replace (guessed_id.suggestion ());
-	  error_at (&richloc,
-		    "%qE undeclared here (not in a function);"
-		    " did you mean %qs?",
-		    id, guessed_id.suggestion ());
+	  d.error_at (&richloc,
+		      "%qE undeclared here (not in a function);"
+		      " did you mean %qs?",
+		      id, guessed_id.suggestion ());
 	}
       else
-	error_at (loc, "%qE undeclared here (not in a function)", id);
+	d.error_at (loc, "%qE undeclared here (not in a function)", id);
       scope = current_scope;
     }
   else
     {
       if (!objc_diagnose_private_ivar (id))
 	{
-	  name_hint guessed_id = lookup_name_fuzzy (id, FUZZY_LOOKUP_NAME, loc);
+	  name_hint guessed_id = lookup_name_fuzzy (id, FUZZY_LOOKUP_NAME, &d,
+						    loc);
 	  if (guessed_id)
 	    {
 	      gcc_rich_location richloc (loc);
 	      richloc.add_fixit_replace (guessed_id.suggestion ());
-	      error_at (&richloc,
-			"%qE undeclared (first use in this function);"
-			" did you mean %qs?",
-			id, guessed_id.suggestion ());
+	      d.error_at (&richloc,
+			  "%qE undeclared (first use in this function);"
+			  " did you mean %qs?",
+			  id, guessed_id.suggestion ());
 	    }
 	  else
-	    error_at (loc, "%qE undeclared (first use in this function)", id);
+	    d.error_at (loc, "%qE undeclared (first use in this function)", id);
 	}
       if (!already)
 	{
-          inform (loc, "each undeclared identifier is reported only"
-                  " once for each function it appears in");
+	  d.inform (loc, "each undeclared identifier is reported only"
+		    " once for each function it appears in");
 	  already = true;
 	}
 
@@ -3686,8 +3724,9 @@ declare_label (tree name)
      at this scope */
   if (b && B_IN_CURRENT_SCOPE (b))
     {
-      error ("duplicate label declaration %qE", name);
-      locate_old_decl (b->decl);
+      diagnostic_group d;
+      d.error ("duplicate label declaration %qE", name);
+      locate_old_decl (b->decl, &d);
 
       /* Just use the previous declaration.  */
       return b->decl;
@@ -3784,8 +3823,9 @@ define_label (location_t location, tree name)
 	  || (DECL_CONTEXT (label) != current_function_decl
 	      && C_DECLARED_LABEL_FLAG (label))))
     {
-      error_at (location, "duplicate label %qD", label);
-      locate_old_decl (label);
+      diagnostic_group d;
+      d.error_at (location, "duplicate label %qD", label);
+      locate_old_decl (label, &d);
       return NULL_TREE;
     }
   else if (label && DECL_CONTEXT (label) == current_function_decl)
@@ -4026,10 +4066,11 @@ lookup_name_in_scope (tree name, struct c_scope *scope)
    It also looks for start_typename keywords, to detect "singed" vs "signed"
    typos.
 
-   Use LOC for any deferred diagnostics.  */
+   Use GROUP and LOC for any deferred diagnostics.  */
 
 name_hint
-lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
+lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind,
+		   diagnostic_group *group, location_t loc)
 {
   gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
 
@@ -4040,7 +4081,7 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
 
   if (header_hint)
     return name_hint (NULL,
-		      new suggest_missing_header (loc,
+		      new suggest_missing_header (group, loc,
 						  IDENTIFIER_POINTER (name),
 						  header_hint));
 
@@ -6727,11 +6768,12 @@ grokdeclarator (const struct c_declarator *declarator,
 		  || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b)))
 	      && TYPE_MAIN_VARIANT (b->decl) != TYPE_MAIN_VARIANT (type))
 	    {
-	      if (warning_at (declarator->id_loc, OPT_Wc___compat,
-			      ("using %qD as both a typedef and a tag is "
-			       "invalid in C++"), decl)
+	      diagnostic_group d;
+	      if (d.warning_at (declarator->id_loc, OPT_Wc___compat,
+				("using %qD as both a typedef and a tag is "
+				 "invalid in C++"), decl)
 		  && b->locus != UNKNOWN_LOCATION)
-		inform (b->locus, "originally defined here");
+		d.inform (b->locus, "originally defined here");
 	    }
 	}
 
@@ -8801,9 +8843,10 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
 	{
 	  if (stdarg_p (TREE_TYPE (old_decl)))
 	    {
-	      warning_at (loc, 0, "%q+D defined as variadic function "
-			  "without prototype", decl1);
-	      locate_old_decl (old_decl);
+	      diagnostic_group d;
+	      d.warning_at (loc, 0, "%q+D defined as variadic function "
+			    "without prototype", decl1);
+	      locate_old_decl (old_decl, &d);
 	    }
 	  TREE_TYPE (decl1) = composite_type (TREE_TYPE (old_decl),
 					      TREE_TYPE (decl1));
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 7a92628..bee318d 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1814,17 +1814,18 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 	}
       else
 	{
+	  diagnostic_group d;
 	  name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_TYPENAME,
-					      here);
+					      &d, here);
 	  if (hint)
 	    {
 	      richloc.add_fixit_replace (hint.suggestion ());
-	      error_at (&richloc,
-			"unknown type name %qE; did you mean %qs?",
-			name, hint.suggestion ());
+	      d.error_at (&richloc,
+			  "unknown type name %qE; did you mean %qs?",
+			  name, hint.suggestion ());
 	    }
 	  else
-	    error_at (here, "unknown type name %qE", name);
+	    d.error_at (here, "unknown type name %qE", name);
 	}
 
       /* Parse declspecs normally to get a correct pointer type, but avoid
@@ -4049,19 +4050,20 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs)
       c_parser_set_source_position_from_token (token);
       if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
 	{
+	  diagnostic_group d;
 	  name_hint hint = lookup_name_fuzzy (token->value,
 					      FUZZY_LOOKUP_TYPENAME,
-					      token->location);
+					      &d, token->location);
 	  if (hint)
 	    {
 	      gcc_rich_location richloc (token->location);
 	      richloc.add_fixit_replace (hint.suggestion ());
-	      error_at (&richloc,
-			"unknown type name %qE; did you mean %qs?",
-			token->value, hint.suggestion ());
+	      d.error_at (&richloc,
+			  "unknown type name %qE; did you mean %qs?",
+			  token->value, hint.suggestion ());
 	    }
 	  else
-	    error_at (token->location, "unknown type name %qE", token->value);
+	    d.error_at (token->location, "unknown type name %qE", token->value);
 	  parser->error = true;
 	}
       /* ??? In some Objective-C cases '...' isn't applicable so there
@@ -6864,14 +6866,18 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after,
 		&& !(TREE_CODE (first_arg) == PARM_DECL			      \
 		     && C_ARRAY_PARAMETER (first_arg)			      \
 		     && warn_sizeof_array_argument))			      \
-	      if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div,	      \
-			      "division %<sizeof (%T) / sizeof (%T)%> does "  \
-			      "not compute the number of array elements",     \
-			      type0, type1))				      \
-		if (DECL_P (first_arg))					      \
-		  inform (DECL_SOURCE_LOCATION (first_arg),		      \
-			  "first %<sizeof%> operand was declared here");      \
-	  }								      \
+	      {								\
+		diagnostic_group d;					\
+		if (d.warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div, \
+				  "division %<sizeof (%T) / sizeof (%T)%> " \
+				  "does not compute the number of array " \
+				  "elements",				\
+				  type0, type1))			\
+		  if (DECL_P (first_arg))				\
+		    d.inform (DECL_SOURCE_LOCATION (first_arg),		\
+			      "first %<sizeof%> operand was declared here"); \
+	      }								\
+	  }								\
 	break;								      \
       default:								      \
 	break;								      \
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 46b2e68..75156fa 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -2906,11 +2906,12 @@ c_expr_sizeof_expr (location_t loc, struct c_expr expr)
       if (TREE_CODE (expr.value) == PARM_DECL
 	  && C_ARRAY_PARAMETER (expr.value))
 	{
-	  if (warning_at (loc, OPT_Wsizeof_array_argument,
-			  "%<sizeof%> on array function parameter %qE will "
-			  "return size of %qT", expr.value,
-			  TREE_TYPE (expr.value)))
-	    inform (DECL_SOURCE_LOCATION (expr.value), "declared here");
+	  diagnostic_group d;
+	  if (d.warning_at (loc, OPT_Wsizeof_array_argument,
+			    "%<sizeof%> on array function parameter %qE will "
+			    "return size of %qT", expr.value,
+			    TREE_TYPE (expr.value)))
+	    d.inform (DECL_SOURCE_LOCATION (expr.value), "declared here");
 	}
       tree folded_expr = c_fully_fold (expr.value, require_constant_value,
 				       &expr_const_operands);
@@ -3735,19 +3736,27 @@ parser_build_binary_op (location_t location, enum tree_code code,
 		    "comparison with string literal results in unspecified behavior");
       /* Warn for ptr == '\0', it's likely that it should've been ptr[0].  */
       if (POINTER_TYPE_P (type1)
-	   && null_pointer_constant_p (arg2.value)
-	   && char_type_p (type2)
-	   && warning_at (location, OPT_Wpointer_compare,
-			  "comparison between pointer and zero character "
-			  "constant"))
-	inform (arg1.get_start (), "did you mean to dereference the pointer?");
+	  && null_pointer_constant_p (arg2.value)
+	  && char_type_p (type2))
+	{
+	  diagnostic_group d;
+	  if (d.warning_at (location, OPT_Wpointer_compare,
+			    "comparison between pointer and zero character "
+			    "constant"))
+	    d.inform (arg1.get_start (),
+		      "did you mean to dereference the pointer?");
+	}
       else if (POINTER_TYPE_P (type2)
 	       && null_pointer_constant_p (arg1.value)
-	       && char_type_p (type1)
-	       && warning_at (location, OPT_Wpointer_compare,
-			      "comparison between pointer and zero character "
-			      "constant"))
-	inform (arg2.get_start (), "did you mean to dereference the pointer?");
+	       && char_type_p (type1))
+	{
+	  diagnostic_group d;
+	  if (d.warning_at (location, OPT_Wpointer_compare,
+			    "comparison between pointer and zero character "
+			    "constant"))
+	    d.inform (arg2.get_start (),
+		      "did you mean to dereference the pointer?");
+	}
     }
   else if (TREE_CODE_CLASS (code) == tcc_comparison
 	   && (code1 == STRING_CST || code2 == STRING_CST))
@@ -4288,13 +4297,16 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
 	    e = TREE_OPERAND (e, 1);
 
 	  if ((TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE
-	       || truth_value_p (TREE_CODE (e)))
-	      && warning_at (location, OPT_Wbool_operation,
-			     "%<~%> on a boolean expression"))
+	       || truth_value_p (TREE_CODE (e))))
 	    {
-	      gcc_rich_location richloc (location);
-	      richloc.add_fixit_insert_before (location, "!");
-	      inform (&richloc, "did you mean to use logical not?");
+	      diagnostic_group d;
+	      if (d.warning_at (location, OPT_Wbool_operation,
+				"%<~%> on a boolean expression"))
+		{
+		  gcc_rich_location richloc (location);
+		  richloc.add_fixit_insert_before (location, "!");
+		  d.inform (&richloc, "did you mean to use logical not?");
+		}
 	    }
 	  if (!noconvert)
 	    arg = default_conversion (arg);
@@ -6197,11 +6209,13 @@ error_init (location_t loc, const char *gmsgid)
 {
   char *ofwhat;
 
+  diagnostic_group d;
+
   /* The gmsgid may be a format string with %< and %>. */
-  error_at (loc, gmsgid);
+  d.error_at (loc, gmsgid);
   ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
   if (*ofwhat)
-    inform (loc, "(near initialization for %qs)", ofwhat);
+    d.inform (loc, "(near initialization for %qs)", ofwhat);
 }
 
 /* Issue a pedantic warning for a bad initializer component.  OPT is
@@ -6216,15 +6230,14 @@ pedwarn_init (location_t loc, int opt, const char *gmsgid, ...)
      it was defined to make sure macros defined in system headers
      but used incorrectly elsewhere are diagnosed.  */
   source_location exploc = expansion_point_location_if_in_system_header (loc);
-
+  diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
-  bool warned = emit_diagnostic_valist (DK_PEDWARN, exploc, opt, gmsgid, &ap,
-					NULL);
+  bool warned = d.emit_diagnostic_valist (DK_PEDWARN, exploc, opt, gmsgid, &ap);
   va_end (ap);
   char *ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
   if (*ofwhat && warned)
-    inform (exploc, "(near initialization for %qs)", ofwhat);
+    d.inform (exploc, "(near initialization for %qs)", ofwhat);
 }
 
 /* Issue a warning for a bad initializer component.
@@ -6239,16 +6252,18 @@ warning_init (location_t loc, int opt, const char *gmsgid)
   char *ofwhat;
   bool warned;
 
+  diagnostic_group d;
+
   /* Use the location where a macro was expanded rather than where
      it was defined to make sure macros defined in system headers
      but used incorrectly elsewhere are diagnosed.  */
   source_location exploc = expansion_point_location_if_in_system_header (loc);
 
   /* The gmsgid may be a format string with %< and %>. */
-  warned = warning_at (exploc, opt, gmsgid);
+  warned = d.warning_at (exploc, opt, gmsgid);
   ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
   if (*ofwhat && warned)
-    inform (exploc, "(near initialization for %qs)", ofwhat);
+    d.inform (exploc, "(near initialization for %qs)", ofwhat);
 }
 
 /* If TYPE is an array type and EXPR is a parenthesized string
@@ -6289,14 +6304,15 @@ get_fndecl_argument_location (tree fndecl, int argnum)
   return DECL_SOURCE_LOCATION (param);
 }
 
-/* Issue a note about a mismatching argument for parameter PARMNUM
+/* Issue a note within GROUP about a mismatching argument for parameter PARMNUM
    to FUNDECL, for types EXPECTED_TYPE and ACTUAL_TYPE.
    Attempt to issue the note at the pertinent parameter of the decl;
    failing that issue it at the location of FUNDECL; failing that
    issue it at PLOC.  */
 
 static void
-inform_for_arg (tree fundecl, location_t ploc, int parmnum,
+inform_for_arg (diagnostic_group *group,
+		tree fundecl, location_t ploc, int parmnum,
 		tree expected_type, tree actual_type)
 {
   location_t loc;
@@ -6305,9 +6321,9 @@ inform_for_arg (tree fundecl, location_t ploc, int parmnum,
   else
     loc = ploc;
 
-  inform (loc,
-	  "expected %qT but argument is of type %qT",
-	  expected_type, actual_type);
+  group->inform (loc,
+		 "expected %qT but argument is of type %qT",
+		 expected_type, actual_type);
 }
 
 /* Convert value RHS to type TYPE as preparation for an assignment to
@@ -6380,8 +6396,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
     switch (errtype)                                                     \
       {                                                                  \
       case ic_argpass:                                                   \
-        if (pedwarn (PLOC, OPT, AR, parmnum, rname))			 \
-          inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);	\
+	{								\
+	  diagnostic_group d;						\
+	  if (d.pedwarn (PLOC, OPT, AR, parmnum, rname))		\
+	    inform_for_arg (&d, fundecl, (PLOC), parmnum, type, rhstype); \
+	}								\
         break;                                                           \
       case ic_assign:                                                    \
         pedwarn (LOCATION, OPT, AS);                                     \
@@ -6406,8 +6425,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
     switch (errtype)                                                     \
       {                                                                  \
       case ic_argpass:                                                   \
-        if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS))		 \
-          inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);	\
+	{								\
+	diagnostic_group d;						\
+	if (d.pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS))		\
+	  inform_for_arg (&d, fundecl, (PLOC), parmnum, type, rhstype);	\
+	}								\
         break;                                                           \
       case ic_assign:                                                    \
         pedwarn (LOCATION, OPT, AS, QUALS);				 \
@@ -6432,8 +6454,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
     switch (errtype)                                                     \
       {                                                                  \
       case ic_argpass:                                                   \
-        if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS))           \
-          inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);      \
+	{								\
+	  diagnostic_group d;						\
+	  if (d.warning_at (PLOC, OPT, AR, parmnum, rname, QUALS))	\
+	    inform_for_arg (&d, fundecl, (PLOC), parmnum, type, rhstype); \
+	}								\
         break;                                                           \
       case ic_assign:                                                    \
         warning_at (LOCATION, OPT, AS, QUALS);                           \
@@ -6925,13 +6950,17 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 		switch (errtype)
 		  {
 		  case ic_argpass:
-		    if (pedwarn (expr_loc, OPT_Wpointer_sign,
-				 "pointer targets in passing argument %d of "
-				 "%qE differ in signedness", parmnum, rname))
-		      inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
-			      ? DECL_SOURCE_LOCATION (fundecl) : expr_loc,
-			      "expected %qT but argument is of type %qT",
-			      type, rhstype);
+		    {
+		      diagnostic_group d;
+		      if (d.pedwarn (expr_loc, OPT_Wpointer_sign,
+				     "pointer targets in passing argument %d "
+				     "of %qE differ in signedness", parmnum,
+				     rname))
+			d.inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
+				  ? DECL_SOURCE_LOCATION (fundecl) : expr_loc,
+				  "expected %qT but argument is of type %qT",
+				  type, rhstype);
+		    }
 		    break;
 		  case ic_assign:
 		    pedwarn (location, OPT_Wpointer_sign,
@@ -6982,10 +7011,14 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	  switch (errtype)
 	    {
 	    case ic_argpass:
-	      if (pedwarn (expr_loc, OPT_Wincompatible_pointer_types,
-			   "passing argument %d of %qE from incompatible "
-			   "pointer type", parmnum, rname))
-		inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
+	      {
+		diagnostic_group d;
+		if (d.pedwarn (expr_loc, OPT_Wincompatible_pointer_types,
+			       "passing argument %d of %qE from incompatible "
+			       "pointer type", parmnum, rname))
+		  inform_for_arg (&d, fundecl, expr_loc, parmnum, type,
+				  rhstype);
+	      }
 	      break;
 	    case ic_assign:
 	      pedwarn (location, OPT_Wincompatible_pointer_types,
@@ -7025,10 +7058,13 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	switch (errtype)
 	  {
 	  case ic_argpass:
-	    if (pedwarn (expr_loc, OPT_Wint_conversion,
-			 "passing argument %d of %qE makes pointer from "
-			 "integer without a cast", parmnum, rname))
-	      inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
+	    {
+	      diagnostic_group d;
+	      if (d.pedwarn (expr_loc, OPT_Wint_conversion,
+			     "passing argument %d of %qE makes pointer from "
+			     "integer without a cast", parmnum, rname))
+		inform_for_arg (&d, fundecl, expr_loc, parmnum, type, rhstype);
+	    }
 	    break;
 	  case ic_assign:
 	    pedwarn (location, OPT_Wint_conversion,
@@ -7056,10 +7092,13 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
       switch (errtype)
 	{
 	case ic_argpass:
-	  if (pedwarn (expr_loc, OPT_Wint_conversion,
-		       "passing argument %d of %qE makes integer from "
-		       "pointer without a cast", parmnum, rname))
-	    inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
+	  {
+	    diagnostic_group d;
+	    if (d.pedwarn (expr_loc, OPT_Wint_conversion,
+			   "passing argument %d of %qE makes integer from "
+			   "pointer without a cast", parmnum, rname))
+	      inform_for_arg (&d, fundecl, expr_loc, parmnum, type, rhstype);
+	  }
 	  break;
 	case ic_assign:
 	  pedwarn (location, OPT_Wint_conversion,
@@ -7095,9 +7134,12 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
   switch (errtype)
     {
     case ic_argpass:
-      error_at (expr_loc, "incompatible type for argument %d of %qE", parmnum,
-		rname);
-      inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
+      {
+	diagnostic_group d;
+	d.error_at (expr_loc, "incompatible type for argument %d of %qE",
+		    parmnum, rname);
+	inform_for_arg (&d, fundecl, expr_loc, parmnum, type, rhstype);
+      }
       break;
     case ic_assign:
       error_at (location, "incompatible types when assigning to type %qT from "
diff --git a/gcc/calls.c b/gcc/calls.c
index 384c023..c929fdc 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1773,38 +1773,40 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
 
       bool warned = false;
 
+      diagnostic_group d;
       if (wi::ltu_p (asize, wibnd))
 	{
 	  if (bndrng[0] == bndrng[1])
-	    warned = warning_at (loc, OPT_Wstringop_overflow_,
-				 "%qD argument %i declared attribute "
-				 "%<nonstring%> is smaller than the specified "
-				 "bound %wu",
-				 fndecl, argno + 1, wibnd.to_uhwi ());
+	    warned = d.warning_at (loc, OPT_Wstringop_overflow_,
+				   "%qD argument %i declared attribute "
+				   "%<nonstring%> is smaller than the "
+				   "specified bound %wu",
+				   fndecl, argno + 1, wibnd.to_uhwi ());
 	  else if (wi::ltu_p (asize, wi::to_offset (bndrng[0])))
-	    warned = warning_at (loc, OPT_Wstringop_overflow_,
-				 "%qD argument %i declared attribute "
-				 "%<nonstring%> is smaller than "
-				 "the specified bound [%E, %E]",
-				 fndecl, argno + 1, bndrng[0], bndrng[1]);
+	    warned = d.warning_at (loc, OPT_Wstringop_overflow_,
+				   "%qD argument %i declared attribute "
+				   "%<nonstring%> is smaller than "
+				   "the specified bound [%E, %E]",
+				   fndecl, argno + 1, bndrng[0], bndrng[1]);
 	  else
-	    warned = warning_at (loc, OPT_Wstringop_overflow_,
-				 "%qD argument %i declared attribute "
-				 "%<nonstring%> may be smaller than "
-				 "the specified bound [%E, %E]",
-				 fndecl, argno + 1, bndrng[0], bndrng[1]);
+	    warned = d.warning_at (loc, OPT_Wstringop_overflow_,
+				   "%qD argument %i declared attribute "
+				   "%<nonstring%> may be smaller than "
+				   "the specified bound [%E, %E]",
+				   fndecl, argno + 1, bndrng[0], bndrng[1]);
 	}
       else if (fncode == BUILT_IN_STRNCAT)
 	; /* Avoid warning for calls to strncat() when the bound
 	     is equal to the size of the non-string argument.  */
       else if (!bound)
-	warned = warning_at (loc, OPT_Wstringop_overflow_,
-			     "%qD argument %i declared attribute %<nonstring%>",
-			     fndecl, argno + 1);
+	warned = d.warning_at (loc, OPT_Wstringop_overflow_,
+			       "%qD argument %i declared attribute "
+			       "%<nonstring%>",
+			       fndecl, argno + 1);
 
       if (warned)
-	inform (DECL_SOURCE_LOCATION (decl),
-		"argument %qD declared here", decl);
+	d.inform (DECL_SOURCE_LOCATION (decl),
+		  "argument %qD declared here", decl);
     }
 }
 
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 462e247..adea1b3 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -1357,20 +1357,24 @@ maybe_diag_incompatible_alias (tree alias, tree target)
       if (ifunc)
 	{
 	  funcptr = build_pointer_type (funcptr);
-
-	  if (warning_at (DECL_SOURCE_LOCATION (target),
-			  OPT_Wattribute_alias,
-			  "%<ifunc%> resolver for %qD should return %qT",
-			  alias, funcptr))
-	    inform (DECL_SOURCE_LOCATION (alias),
-		    "resolver indirect function declared here");
+	  diagnostic_group d;
+	  if (d.warning_at (DECL_SOURCE_LOCATION (target),
+			    OPT_Wattribute_alias,
+			    "%<ifunc%> resolver for %qD should return %qT",
+			    alias, funcptr))
+	    d.inform (DECL_SOURCE_LOCATION (alias),
+		      "resolver indirect function declared here");
+	}
+      else
+	{
+	  diagnostic_group d;
+	  if (d.warning_at (DECL_SOURCE_LOCATION (alias),
+			    OPT_Wattribute_alias,
+			    "%qD alias between functions of incompatible "
+			    "types %qT and %qT", alias, altype, targtype))
+	    d.inform (DECL_SOURCE_LOCATION (target),
+		      "aliased declaration here");
 	}
-      else if (warning_at (DECL_SOURCE_LOCATION (alias),
-			   OPT_Wattribute_alias,
-			   "%qD alias between functions of incompatible "
-			   "types %qT and %qT", alias, altype, targtype))
-	inform (DECL_SOURCE_LOCATION (target),
-		"aliased declaration here");
     }
 }
 
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 121f0ca..d781980 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -162,12 +162,14 @@ static tree build_over_call (struct z_candidate *, int, tsubst_flags_t);
 		     /*c_cast_p=*/false, (COMPLAIN))
 static tree convert_like_real (conversion *, tree, tree, int, bool,
 			       bool, tsubst_flags_t);
-static void op_error (location_t, enum tree_code, enum tree_code, tree,
-		      tree, tree, bool);
+static void op_error (diagnostic_group *, 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 (diagnostic_group *, location_t, const char *,
+			       struct z_candidate *);
+static void print_z_candidates (diagnostic_group *, location_t,
+				struct z_candidate *);
 static tree build_this (tree);
 static struct z_candidate *splice_viable (struct z_candidate *, bool, bool *);
 static bool any_strictly_viable (struct z_candidate *);
@@ -3429,7 +3431,8 @@ equal_functions (tree fn1, tree fn2)
 /* Print information about a candidate being rejected due to INFO.  */
 
 static void
-print_conversion_rejection (location_t loc, struct conversion_info *info)
+print_conversion_rejection (diagnostic_group *group, location_t loc,
+			    struct conversion_info *info)
 {
   tree from = info->from;
   if (!TYPE_P (from))
@@ -3439,41 +3442,42 @@ print_conversion_rejection (location_t loc, struct conversion_info *info)
       /* Conversion of implicit `this' argument failed.  */
       if (!TYPE_P (info->from))
 	/* A bad conversion for 'this' must be discarding cv-quals.  */
-	inform (loc, "  passing %qT as %<this%> "
-		"argument discards qualifiers",
-		from);
+	group->inform (loc, "  passing %qT as %<this%> "
+		       "argument discards qualifiers",
+		       from);
       else
-	inform (loc, "  no known conversion for implicit "
-		"%<this%> parameter from %qH to %qI",
-		from, info->to_type);
+	group->inform (loc, "  no known conversion for implicit "
+		       "%<this%> parameter from %qH to %qI",
+		       from, info->to_type);
     }
   else if (!TYPE_P (info->from))
     {
       if (info->n_arg >= 0)
-	inform (loc, "  conversion of argument %d would be ill-formed:",
-		info->n_arg + 1);
+	group->inform (loc, "  conversion of argument %d would be ill-formed:",
+		       info->n_arg + 1);
       perform_implicit_conversion (info->to_type, info->from,
 				   tf_warning_or_error);
     }
   else if (info->n_arg == -2)
     /* Conversion of conversion function return value failed.  */
-    inform (loc, "  no known conversion from %qH to %qI",
-	    from, info->to_type);
+    group->inform (loc, "  no known conversion from %qH to %qI",
+		   from, info->to_type);
   else
-    inform (loc, "  no known conversion for argument %d from %qH to %qI",
-	    info->n_arg + 1, from, info->to_type);
+    group->inform (loc, "  no known conversion for argument %d from %qH to %qI",
+		   info->n_arg + 1, from, info->to_type);
 }
 
 /* Print information about a candidate with WANT parameters and we found
    HAVE.  */
 
 static void
-print_arity_information (location_t loc, unsigned int have, unsigned int want)
+print_arity_information (diagnostic_group *group, location_t loc,
+			 unsigned int have, unsigned int want)
 {
-  inform_n (loc, want,
-	    "  candidate expects %d argument, %d provided",
-	    "  candidate expects %d arguments, %d provided",
-	    want, have);
+  group->inform_n (loc, want,
+		   "  candidate expects %d argument, %d provided",
+		   "  candidate expects %d arguments, %d provided",
+		   want, have);
 }
 
 /* Print information about one overload candidate CANDIDATE.  MSGSTR
@@ -3484,7 +3488,7 @@ print_arity_information (location_t loc, unsigned int have, unsigned int want)
    life simpler in print_z_candidates and for the translators.  */
 
 static void
-print_z_candidate (location_t loc, const char *msgstr,
+print_z_candidate (diagnostic_group *group, location_t loc, const char *msgstr,
 		   struct z_candidate *candidate)
 {
   const char *msg = (msgstr == NULL
@@ -3499,30 +3503,30 @@ print_z_candidate (location_t loc, const char *msgstr,
     {
       cloc = loc;
       if (candidate->num_convs == 3)
-	inform (cloc, "%s%<%D(%T, %T, %T)%> <built-in>", msg, fn,
-		candidate->convs[0]->type,
-		candidate->convs[1]->type,
-		candidate->convs[2]->type);
+	group->inform (cloc, "%s%<%D(%T, %T, %T)%> <built-in>", msg, fn,
+		       candidate->convs[0]->type,
+		       candidate->convs[1]->type,
+		       candidate->convs[2]->type);
       else if (candidate->num_convs == 2)
-	inform (cloc, "%s%<%D(%T, %T)%> <built-in>", msg, fn,
-		candidate->convs[0]->type,
-		candidate->convs[1]->type);
+	group->inform (cloc, "%s%<%D(%T, %T)%> <built-in>", msg, fn,
+		       candidate->convs[0]->type,
+		       candidate->convs[1]->type);
       else
-	inform (cloc, "%s%<%D(%T)%> <built-in>", msg, fn,
-		candidate->convs[0]->type);
+	group->inform (cloc, "%s%<%D(%T)%> <built-in>", msg, fn,
+		       candidate->convs[0]->type);
     }
   else if (TYPE_P (fn))
-    inform (cloc, "%s%qT <conversion>", msg, fn);
+    group->inform (cloc, "%s%qT <conversion>", msg, fn);
   else if (candidate->viable == -1)
-    inform (cloc, "%s%#qD <near match>", msg, fn);
+    group->inform (cloc, "%s%#qD <near match>", msg, fn);
   else if (DECL_DELETED_FN (fn))
-    inform (cloc, "%s%#qD <deleted>", msg, fn);
+    group->inform (cloc, "%s%#qD <deleted>", msg, fn);
   else
-    inform (cloc, "%s%#qD", msg, fn);
+    group->inform (cloc, "%s%#qD", msg, fn);
   if (fn != candidate->fn)
     {
       cloc = location_of (candidate->fn);
-      inform (cloc, "  inherited here");
+      group->inform (cloc, "  inherited here");
     }
   /* Give the user some information about why this candidate failed.  */
   if (candidate->reason != NULL)
@@ -3532,26 +3536,27 @@ print_z_candidate (location_t loc, const char *msgstr,
       switch (r->code)
 	{
 	case rr_arity:
-	  print_arity_information (cloc, r->u.arity.actual,
+	  print_arity_information (group, cloc, r->u.arity.actual,
 				   r->u.arity.expected);
 	  break;
 	case rr_arg_conversion:
-	  print_conversion_rejection (cloc, &r->u.conversion);
+	  print_conversion_rejection (group, cloc, &r->u.conversion);
 	  break;
 	case rr_bad_arg_conversion:
-	  print_conversion_rejection (cloc, &r->u.bad_conversion);
+	  print_conversion_rejection (group, cloc, &r->u.bad_conversion);
 	  break;
 	case rr_explicit_conversion:
-	  inform (cloc, "  return type %qT of explicit conversion function "
-		  "cannot be converted to %qT with a qualification "
-		  "conversion", r->u.conversion.from,
-		  r->u.conversion.to_type);
+	  group->inform (cloc,
+			 "  return type %qT of explicit conversion function "
+			 "cannot be converted to %qT with a qualification "
+			 "conversion", r->u.conversion.from,
+			 r->u.conversion.to_type);
 	  break;
 	case rr_template_conversion:
-	  inform (cloc, "  conversion from return type %qT of template "
-		  "conversion function specialization to %qT is not an "
-		  "exact match", r->u.conversion.from,
-		  r->u.conversion.to_type);
+	  group->inform (cloc, "  conversion from return type %qT of template "
+			 "conversion function specialization to %qT is not an "
+			 "exact match", r->u.conversion.from,
+			 r->u.conversion.to_type);
 	  break;
 	case rr_template_unification:
 	  /* We use template_unification_error_rejection if unification caused
@@ -3559,12 +3564,15 @@ print_z_candidate (location_t loc, const char *msgstr,
 	     them here.  */
 	  if (r->u.template_unification.tmpl == NULL_TREE)
 	    {
-	      inform (cloc, "  substitution of deduced template arguments "
-		      "resulted in errors seen above");
+	      group->inform (cloc,
+			     "  substitution of deduced template arguments "
+			     "resulted in errors seen above");
 	      break;
 	    }
 	  /* Re-run template unification with diagnostics.  */
-	  inform (cloc, "  template argument deduction/substitution failed:");
+	  group->inform (cloc,
+			 "  template argument deduction/substitution failed:");
+	  // FIXME: use group?
 	  fn_type_unification (r->u.template_unification.tmpl,
 			       r->u.template_unification.explicit_targs,
 			       (make_tree_vec
@@ -3577,21 +3585,22 @@ print_z_candidate (location_t loc, const char *msgstr,
 			       NULL, true, false);
 	  break;
 	case rr_invalid_copy:
-	  inform (cloc,
-		  "  a constructor taking a single argument of its own "
-		  "class type is invalid");
+	  group->inform (cloc,
+			 "  a constructor taking a single argument of its own "
+			 "class type is invalid");
 	  break;
 	case rr_constraint_failure:
 	  {
 	    tree tmpl = r->u.template_instantiation.tmpl;
 	    tree args = r->u.template_instantiation.targs;
-	    diagnose_constraints (cloc, tmpl, args);
+	    diagnose_constraints (group, cloc, tmpl, args);
 	  }
 	  break;
 	case rr_inherited_ctor:
-	  inform (cloc, "  an inherited constructor is not a candidate for "
-		  "initialization from an expression of the same or derived "
-		  "type");
+	  group->inform (cloc,
+			 "  an inherited constructor is not a candidate for "
+			 "initialization from an expression of the same or "
+			 "derived type");
 	  break;
 	case rr_none:
 	default:
@@ -3603,7 +3612,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 (diagnostic_group * group, location_t loc,
+		    struct z_candidate *candidates)
 {
   struct z_candidate *cand1;
   struct z_candidate **cand2;
@@ -3649,7 +3659,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 (group, loc, "candidate:", candidates);
 }
 
 /* USER_SEQ is a user-defined conversion sequence, beginning with a
@@ -3964,9 +3974,10 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags,
     {
       if (complain & tf_error)
 	{
-	  error ("conversion from %qH to %qI is ambiguous",
-		 fromtype, totype);
-	  print_z_candidates (location_of (expr), candidates);
+	  diagnostic_group d;
+	  d.error ("conversion from %qH to %qI is ambiguous",
+		   fromtype, totype);
+	  print_z_candidates (&d, location_of (expr), candidates);
 	}
 
       cand = candidates;	/* any one will do */
@@ -4267,14 +4278,15 @@ print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
   if (targs)
     name = lookup_template_function (name, targs);
 
+  diagnostic_group d;
   if (!any_strictly_viable (candidates))
-    error_at (loc, "no matching function for call to %<%D(%A)%>",
-	      name, build_tree_list_vec (args));
+    d.error_at (loc, "no matching function for call to %<%D(%A)%>",
+		name, build_tree_list_vec (args));
   else
-    error_at (loc, "call of overloaded %<%D(%A)%> is ambiguous",
-	      name, build_tree_list_vec (args));
+    d.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 (&d, loc, candidates);
 }
 
 /* Return an expression for a call to FN (a namespace-scope function,
@@ -4577,9 +4589,10 @@ build_op_call_1 (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
     {
       if (complain & tf_error)
         {
-          error ("no match for call to %<(%T) (%A)%>", TREE_TYPE (obj),
-		 build_tree_list_vec (*args));
-          print_z_candidates (location_of (TREE_TYPE (obj)), candidates);
+	  diagnostic_group d;
+	  d.error ("no match for call to %<(%T) (%A)%>", TREE_TYPE (obj),
+		   build_tree_list_vec (*args));
+          print_z_candidates (&d, location_of (TREE_TYPE (obj)), candidates);
         }
       result = error_mark_node;
     }
@@ -4590,9 +4603,11 @@ build_op_call_1 (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
 	{
           if (complain & tf_error)
             {
-              error ("call of %<(%T) (%A)%> is ambiguous", 
-                     TREE_TYPE (obj), build_tree_list_vec (*args));
-              print_z_candidates (location_of (TREE_TYPE (obj)), candidates);
+	      diagnostic_group d;
+	      d.error ("call of %<(%T) (%A)%> is ambiguous",
+		       TREE_TYPE (obj), build_tree_list_vec (*args));
+	      print_z_candidates (&d, location_of (TREE_TYPE (obj)),
+				  candidates);
             }
 	  result = error_mark_node;
 	}
@@ -4656,7 +4671,8 @@ op_error_string (const char *errmsg, int ntypes, bool match)
 }
 
 static void
-op_error (location_t loc, enum tree_code code, enum tree_code code2,
+op_error (diagnostic_group *group, location_t loc, enum tree_code code,
+	  enum tree_code code2,
 	  tree arg1, tree arg2, tree arg3, bool match)
 {
   bool assop = code == MODIFY_EXPR;
@@ -4666,65 +4682,73 @@ op_error (location_t loc, enum tree_code code, enum tree_code code2,
     {
     case COND_EXPR:
       if (flag_diagnostics_show_caret)
-	error_at (loc, op_error_string (G_("ternary %<operator?:%>"),
-					3, match),
-		  TREE_TYPE (arg1), TREE_TYPE (arg2), TREE_TYPE (arg3));
+	group->error_at (loc, op_error_string (G_("ternary %<operator?:%>"),
+					       3, match),
+			 TREE_TYPE (arg1), TREE_TYPE (arg2), TREE_TYPE (arg3));
       else
-	error_at (loc, op_error_string (G_("ternary %<operator?:%> "
-					   "in %<%E ? %E : %E%>"), 3, match),
-		  arg1, arg2, arg3,
-		  TREE_TYPE (arg1), TREE_TYPE (arg2), TREE_TYPE (arg3));
+	group->error_at (loc, op_error_string (G_("ternary %<operator?:%> "
+						  "in %<%E ? %E : %E%>"),
+					       3, match),
+			 arg1, arg2, arg3,
+			 TREE_TYPE (arg1), TREE_TYPE (arg2), TREE_TYPE (arg3));
       break;
 
     case POSTINCREMENT_EXPR:
     case POSTDECREMENT_EXPR:
       if (flag_diagnostics_show_caret)
-	error_at (loc, op_error_string (G_("%<operator%s%>"), 1, match),
-		  opname, TREE_TYPE (arg1));
+	group->error_at (loc, op_error_string (G_("%<operator%s%>"), 1, match),
+			 opname, TREE_TYPE (arg1));
       else
-	error_at (loc, op_error_string (G_("%<operator%s%> in %<%E%s%>"),
-					1, match),
-		  opname, arg1, opname, TREE_TYPE (arg1));
+	group->error_at (loc, op_error_string (G_("%<operator%s%> in %<%E%s%>"),
+					       1, match),
+			 opname, arg1, opname, TREE_TYPE (arg1));
       break;
 
     case ARRAY_REF:
       if (flag_diagnostics_show_caret)
-	error_at (loc, op_error_string (G_("%<operator[]%>"), 2, match),
-		  TREE_TYPE (arg1), TREE_TYPE (arg2));
+	group->error_at (loc, op_error_string (G_("%<operator[]%>"), 2, match),
+			 TREE_TYPE (arg1), TREE_TYPE (arg2));
       else
-	error_at (loc, op_error_string (G_("%<operator[]%> in %<%E[%E]%>"),
-					2, match),
-		  arg1, arg2, TREE_TYPE (arg1), TREE_TYPE (arg2));
+	group->error_at (loc,
+			 op_error_string (G_("%<operator[]%> in %<%E[%E]%>"),
+					  2, match),
+			 arg1, arg2, TREE_TYPE (arg1), TREE_TYPE (arg2));
       break;
 
     case REALPART_EXPR:
     case IMAGPART_EXPR:
       if (flag_diagnostics_show_caret)
-	error_at (loc, op_error_string (G_("%qs"), 1, match),
-		  opname, TREE_TYPE (arg1));
+	group->error_at (loc, op_error_string (G_("%qs"), 1, match),
+			 opname, TREE_TYPE (arg1));
       else
-	error_at (loc, op_error_string (G_("%qs in %<%s %E%>"), 1, match),
-		  opname, opname, arg1, TREE_TYPE (arg1));
+	group->error_at (loc, op_error_string (G_("%qs in %<%s %E%>"), 1,
+					       match),
+			 opname, opname, arg1, TREE_TYPE (arg1));
       break;
 
     default:
       if (arg2)
 	if (flag_diagnostics_show_caret)
-	  error_at (loc, op_error_string (G_("%<operator%s%>"), 2, match),
-		    opname, TREE_TYPE (arg1), TREE_TYPE (arg2));
+	  group->error_at (loc, op_error_string (G_("%<operator%s%>"), 2,
+						 match),
+			   opname, TREE_TYPE (arg1), TREE_TYPE (arg2));
 	else
-	  error_at (loc, op_error_string (G_("%<operator%s%> in %<%E %s %E%>"),
-					  2, match),
+	  group->error_at (loc,
+			   op_error_string (G_("%<operator%s%> in "
+					       "%<%E %s %E%>"),
+					    2, match),
 		    opname, arg1, opname, arg2,
 		    TREE_TYPE (arg1), TREE_TYPE (arg2));
       else
 	if (flag_diagnostics_show_caret)
-	  error_at (loc, op_error_string (G_("%<operator%s%>"), 1, match),
-		    opname, TREE_TYPE (arg1));
+	  group->error_at (loc, op_error_string (G_("%<operator%s%>"), 1,
+						 match),
+			   opname, TREE_TYPE (arg1));
 	else
-	  error_at (loc, op_error_string (G_("%<operator%s%> in %<%s%E%>"),
-					  1, match),
-		    opname, opname, arg1, TREE_TYPE (arg1));
+	  group->error_at (loc,
+			   op_error_string (G_("%<operator%s%> in %<%s%E%>"),
+					    1, match),
+			   opname, opname, arg1, TREE_TYPE (arg1));
       break;
     }
 }
@@ -5216,8 +5240,9 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
 	{
           if (complain & tf_error)
             {
-              op_error (loc, COND_EXPR, NOP_EXPR, arg1, arg2, arg3, FALSE);
-              print_z_candidates (loc, candidates);
+	      diagnostic_group d;
+	      op_error (&d, loc, COND_EXPR, NOP_EXPR, arg1, arg2, arg3, FALSE);
+	      print_z_candidates (&d, loc, candidates);
             }
 	  return error_mark_node;
 	}
@@ -5847,8 +5872,9 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
 		  {
 		    /* ... Otherwise, report the more generic
 		       "no matching operator found" error */
-		    op_error (loc, code, code2, arg1, arg2, arg3, FALSE);
-		    print_z_candidates (loc, candidates);
+		    diagnostic_group d;
+		    op_error (&d, loc, code, code2, arg1, arg2, arg3, FALSE);
+		    print_z_candidates (&d, loc, candidates);
 		  }
 	    }
 	  result = error_mark_node;
@@ -5862,8 +5888,9 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
 	{
 	  if (complain & tf_error)
 	    {
-	      op_error (loc, code, code2, arg1, arg2, arg3, TRUE);
-	      print_z_candidates (loc, candidates);
+	      diagnostic_group d;
+	      op_error (&d, loc, code, code2, arg1, arg2, arg3, TRUE);
+	      print_z_candidates (&d, loc, candidates);
 	    }
 	  result = error_mark_node;
 	}
@@ -6298,23 +6325,27 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
 	     -Wc++14-compat.  */
 	  else if (!flag_sized_deallocation)
 	    {
-	      if ((complain & tf_warning)
-		  && warning (OPT_Wc__14_compat, msg1))
-		inform (DECL_SOURCE_LOCATION (fn), msg2, fn);
+	      if ((complain & tf_warning))
+		{
+		  diagnostic_group d;
+		  if (d.warning (OPT_Wc__14_compat, msg1))
+		    d.inform (DECL_SOURCE_LOCATION (fn), msg2, fn);
+		}
 	      goto ok;
 	    }
 
 	  if (complain & tf_warning_or_error)
 	    {
-	      if (permerror (input_location, msg1))
+	      diagnostic_group d;
+	      if (d.permerror (input_location, msg1))
 		{
 		  /* Only mention C++14 for namespace-scope delete.  */
 		  if (DECL_NAMESPACE_SCOPE_P (fn))
-		    inform (DECL_SOURCE_LOCATION (fn), msg2, fn);
+		    d.inform (DECL_SOURCE_LOCATION (fn), msg2, fn);
 		  else
-		    inform (DECL_SOURCE_LOCATION (fn),
-			    "%qD is a usual (non-placement) deallocation "
-			    "function", fn);
+		    d.inform (DECL_SOURCE_LOCATION (fn),
+			      "%qD is a usual (non-placement) deallocation "
+			      "function", fn);
 		}
 	    }
 	  else
@@ -6612,13 +6643,13 @@ conversion_null_warnings (tree totype, tree expr, tree fn, int argnum)
    which user-defined conversion.  */
 
 static void
-maybe_print_user_conv_context (conversion *convs)
+maybe_print_user_conv_context (diagnostic_group *group, conversion *convs)
 {
   if (convs->user_conv_p)
     for (conversion *t = convs; t; t = next_conversion (t))
       if (t->kind == ck_user)
 	{
-	  print_z_candidate (0, "  after user-defined conversion:",
+	  print_z_candidate (group, 0, "  after user-defined conversion:",
 			     t->cand);
 	  break;
 	}
@@ -6709,11 +6740,12 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	{
 	  if (t->kind == ck_user && t->cand->reason)
 	    {
-	      complained = permerror (loc, "invalid user-defined conversion "
-				      "from %qH to %qI", TREE_TYPE (expr),
-				      totype);
+	      diagnostic_group d;
+	      complained = d.permerror (loc, "invalid user-defined conversion "
+					"from %qH to %qI", TREE_TYPE (expr),
+					totype);
 	      if (complained)
-		print_z_candidate (loc, "candidate is:", t->cand);
+		print_z_candidate (&d, loc, "candidate is:", t->cand);
 	      expr = convert_like_real (t, expr, fn, argnum,
 					/*issue_conversion_warnings=*/false,
 					/*c_cast_p=*/false,
@@ -6725,8 +6757,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	      else
 		expr = cp_convert (totype, expr, complain);
 	      if (complained && fn)
-		inform (DECL_SOURCE_LOCATION (fn),
-			"  initializing argument %P of %qD", argnum, fn);
+		d.inform (DECL_SOURCE_LOCATION (fn),
+			  "  initializing argument %P of %qD", argnum, fn);
 	      return expr;
 	    }
 	  else if (t->kind == ck_user || !t->bad_p)
@@ -6787,11 +6819,13 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	    if (CONSTRUCTOR_NELTS (expr) == 0
 		&& FUNCTION_FIRST_USER_PARMTYPE (convfn) != void_list_node)
 	      {
-		if (pedwarn (loc, 0, "converting to %qT from initializer list "
-			     "would use explicit constructor %qD",
-			     totype, convfn))
-		  inform (loc, "in C++11 and above a default constructor "
-			  "can be explicit");
+		diagnostic_group d;
+		if (d.pedwarn (loc, 0,
+			       "converting to %qT from initializer list "
+			       "would use explicit constructor %qD",
+			       totype, convfn))
+		  d.inform (loc, "in C++11 and above a default constructor "
+			    "can be explicit");
 	      }
 	    else
 	      error ("converting to %qT from initializer list would use "
@@ -6965,10 +6999,11 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	{
 	  if (complain & tf_error)
 	    {
-	      maybe_print_user_conv_context (convs);
+	      diagnostic_group d;
+	      maybe_print_user_conv_context (&d, convs);
 	      if (fn)
-		inform (DECL_SOURCE_LOCATION (fn),
-			"  initializing argument %P of %qD", argnum, fn);
+		d.inform (DECL_SOURCE_LOCATION (fn),
+			  "  initializing argument %P of %qD", argnum, fn);
 	    }
 	  return error_mark_node;
 	}
@@ -7017,10 +7052,11 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
       expr = build_temp (expr, totype, flags, &diag_kind, complain);
       if (diag_kind && complain)
 	{
-	  maybe_print_user_conv_context (convs);
+	  diagnostic_group d;
+	  maybe_print_user_conv_context (&d, convs);
 	  if (fn)
-	    inform (DECL_SOURCE_LOCATION (fn),
-		    "  initializing argument %P of %qD", argnum, fn);
+	    d.inform (DECL_SOURCE_LOCATION (fn),
+		      "  initializing argument %P of %qD", argnum, fn);
 	}
 
       return build_cplus_new (totype, expr, complain);
@@ -7032,23 +7068,24 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	if (convs->bad_p && !next_conversion (convs)->bad_p)
 	  {
 	    tree extype = TREE_TYPE (expr);
+	    diagnostic_group d;
 	    if (TYPE_REF_IS_RVALUE (ref_type)
 		&& lvalue_p (expr))
-	      error_at (loc, "cannot bind rvalue reference of type %qH to "
-                        "lvalue of type %qI", totype, extype);
+	      d.error_at (loc, "cannot bind rvalue reference of type %qH to "
+			  "lvalue of type %qI", totype, extype);
 	    else if (!TYPE_REF_IS_RVALUE (ref_type) && !lvalue_p (expr)
 		     && !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type)))
-	      error_at (loc, "cannot bind non-const lvalue reference of "
-			"type %qH to an rvalue of type %qI", totype, extype);
+	      d.error_at (loc, "cannot bind non-const lvalue reference of "
+			  "type %qH to an rvalue of type %qI", totype, extype);
 	    else if (!reference_compatible_p (TREE_TYPE (totype), extype))
-	      error_at (loc, "binding reference of type %qH to %qI "
-			"discards qualifiers", totype, extype);
+	      d.error_at (loc, "binding reference of type %qH to %qI "
+			  "discards qualifiers", totype, extype);
 	    else
 	      gcc_unreachable ();
-	    maybe_print_user_conv_context (convs);
+	    maybe_print_user_conv_context (&d, convs);
 	    if (fn)
-	      inform (DECL_SOURCE_LOCATION (fn),
-		      "  initializing argument %P of %qD", argnum, fn);
+	      d.inform (DECL_SOURCE_LOCATION (fn),
+			"  initializing argument %P of %qD", argnum, fn);
 	    return error_mark_node;
 	  }
 
@@ -7922,10 +7959,11 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 	{
 	  if (complain & tf_error)
 	    {
-	      if (permerror (input_location, "passing %qT as %<this%> "
-			     "argument discards qualifiers",
-			     TREE_TYPE (argtype)))
-		inform (DECL_SOURCE_LOCATION (fn), "  in call to %qD", fn);
+	      diagnostic_group d;
+	      if (d.permerror (input_location, "passing %qT as %<this%> "
+			       "argument discards qualifiers",
+			       TREE_TYPE (argtype)))
+		d.inform (DECL_SOURCE_LOCATION (fn), "  in call to %qD", fn);
 	    }
 	  else
 	    return error_mark_node;
@@ -9203,11 +9241,12 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 
       basetype = DECL_CONTEXT (fn);
       name = constructor_name (basetype);
-      if (permerror (input_location,
-		     "cannot call constructor %<%T::%D%> directly",
-		     basetype, name))
-	inform (input_location, "for a function-style cast, remove the "
-		"redundant %<::%D%>", name);
+      diagnostic_group d;
+      if (d.permerror (input_location,
+		       "cannot call constructor %<%T::%D%> directly",
+		       basetype, name))
+	d.inform (input_location, "for a function-style cast, remove the "
+		  "redundant %<::%D%>", name);
       call = build_functional_cast (basetype, build_tree_list_vec (user_args),
 				    complain);
       return call;
@@ -9341,12 +9380,15 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
     {
       if (complain & tf_error)
 	{
+	  diagnostic_group d;
 	  if (!COMPLETE_OR_OPEN_TYPE_P (basetype))
+	    // FIXME: use d?
 	    cxx_incomplete_type_error (instance, basetype);
 	  else if (optype)
-	    error ("no matching function for call to %<%T::operator %T(%A)%#V%>",
-		   basetype, optype, build_tree_list_vec (user_args),
-		   TREE_TYPE (instance));
+	    d.error ("no matching function for call to "
+		     "%<%T::operator %T(%A)%#V%>",
+		     basetype, optype, build_tree_list_vec (user_args),
+		     TREE_TYPE (instance));
 	  else
 	    {
 	      tree arglist = build_tree_list_vec (user_args);
@@ -9361,11 +9403,11 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 		errname = lookup_template_function (errname, explicit_targs);
 	      if (skip_first_for_error)
 		arglist = TREE_CHAIN (arglist);
-	      error ("no matching function for call to %<%T::%s%E(%A)%#V%>",
-		     basetype, &"~"[!twiddle], errname, arglist,
-		     TREE_TYPE (instance));
+	      d.error ("no matching function for call to %<%T::%s%E(%A)%#V%>",
+		       basetype, &"~"[!twiddle], errname, arglist,
+		       TREE_TYPE (instance));
 	    }
-	  print_z_candidates (location_of (name), candidates);
+	  print_z_candidates (&d, location_of (name), candidates);
 	}
       call = error_mark_node;
     }
@@ -9384,13 +9426,14 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 	      arglist = build_tree_list_vec (user_args);
 	      if (skip_first_for_error)
 		arglist = TREE_CHAIN (arglist);
+	      diagnostic_group d;
 	      if (!any_strictly_viable (candidates))
-		error ("no matching function for call to %<%s(%A)%>",
-		       pretty_name, arglist);
+		d.error ("no matching function for call to %<%s(%A)%>",
+			 pretty_name, arglist);
 	      else
-		error ("call of overloaded %<%s(%A)%> is ambiguous",
-		       pretty_name, arglist);
-	      print_z_candidates (location_of (name), candidates);
+		d.error ("call of overloaded %<%s(%A)%> is ambiguous",
+			 pretty_name, arglist);
+	      print_z_candidates (&d, location_of (name), candidates);
 	      if (free_p)
 		free (pretty_name);
 	    }
@@ -10290,11 +10333,14 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
 	  tree source = source_type (w->convs[0]);
 	  if (INDIRECT_TYPE_P (source))
 	    source = TREE_TYPE (source);
-	  if (warning (OPT_Wconversion, "choosing %qD over %qD", w->fn, l->fn)
-	      && warning (OPT_Wconversion, "  for conversion from %qH to %qI",
-			  source, w->second_conv->type)) 
+	  diagnostic_group d;
+	  if (d.warning (OPT_Wconversion, "choosing %qD over %qD", w->fn, l->fn)
+	      && d.warning (OPT_Wconversion, "  for conversion from %qH to %qI",
+			    source, w->second_conv->type))
 	    {
-	      inform (input_location, "  because conversion sequence for the argument is better");
+	      d.inform (input_location,
+			"  because conversion sequence for the argument is"
+			" better");
 	    }
 	}
       else
@@ -10517,14 +10563,15 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
 		{
 		  if (complain & tf_error)
 		    {
-		      if (permerror (input_location,
-				     "default argument mismatch in "
-				     "overload resolution"))
+		      diagnostic_group d;
+		      if (d.permerror (input_location,
+				       "default argument mismatch in "
+				       "overload resolution"))
 			{
-			  inform (DECL_SOURCE_LOCATION (cand1->fn),
-				  " candidate 1: %q#F", cand1->fn);
-			  inform (DECL_SOURCE_LOCATION (cand2->fn),
-				  " candidate 2: %q#F", cand2->fn);
+			  d.inform (DECL_SOURCE_LOCATION (cand1->fn),
+				    " candidate 1: %q#F", cand1->fn);
+			  d.inform (DECL_SOURCE_LOCATION (cand2->fn),
+				    " candidate 2: %q#F", cand2->fn);
 			}
 		    }
 		  else
@@ -10568,12 +10615,13 @@ tweak:
 	    return 0;
 	  if (warn)
 	    {
-	      pedwarn (input_location, 0,
-	      "ISO C++ says that these are ambiguous, even "
-	      "though the worst conversion for the first is better than "
-	      "the worst conversion for the second:");
-	      print_z_candidate (input_location, _("candidate 1:"), w);
-	      print_z_candidate (input_location, _("candidate 2:"), l);
+	      diagnostic_group d;
+	      d.pedwarn (input_location, 0,
+			 "ISO C++ says that these are ambiguous, even "
+			 "though the worst conversion for the first is better "
+			 "than the worst conversion for the second:");
+	      print_z_candidate (&d, input_location, _("candidate 1:"), w);
+	      print_z_candidate (&d, input_location, _("candidate 2:"), l);
 	    }
 	  else
 	    add_warning (w, l);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 7b10b20..8fe78d0 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1331,33 +1331,37 @@ check_tag (tree tag, tree id, tree *tp, abi_tag_data *p)
       /* Otherwise we're diagnosing missing tags.  */
       if (TREE_CODE (p->t) == FUNCTION_DECL)
 	{
-	  if (warning (OPT_Wabi_tag, "%qD inherits the %E ABI tag "
-		       "that %qT (used in its return type) has",
-		       p->t, tag, *tp))
-	    inform (location_of (*tp), "%qT declared here", *tp);
+	  diagnostic_group d;
+	  if (d.warning (OPT_Wabi_tag, "%qD inherits the %E ABI tag "
+			 "that %qT (used in its return type) has",
+			 p->t, tag, *tp))
+	    d.inform (location_of (*tp), "%qT declared here", *tp);
 	}
       else if (VAR_P (p->t))
 	{
-	  if (warning (OPT_Wabi_tag, "%qD inherits the %E ABI tag "
-		       "that %qT (used in its type) has", p->t, tag, *tp))
-	    inform (location_of (*tp), "%qT declared here", *tp);
+	  diagnostic_group d;
+	  if (d.warning (OPT_Wabi_tag, "%qD inherits the %E ABI tag "
+			 "that %qT (used in its type) has", p->t, tag, *tp))
+	    d.inform (location_of (*tp), "%qT declared here", *tp);
 	}
       else if (TYPE_P (p->subob))
 	{
-	  if (warning (OPT_Wabi_tag, "%qT does not have the %E ABI tag "
-		       "that base %qT has", p->t, tag, p->subob))
-	    inform (location_of (p->subob), "%qT declared here",
-		    p->subob);
+	  diagnostic_group d;
+	  if (d.warning (OPT_Wabi_tag, "%qT does not have the %E ABI tag "
+			 "that base %qT has", p->t, tag, p->subob))
+	    d.inform (location_of (p->subob), "%qT declared here",
+		      p->subob);
 	}
       else
 	{
-	  if (warning (OPT_Wabi_tag, "%qT does not have the %E ABI tag "
-		       "that %qT (used in the type of %qD) has",
-		       p->t, tag, *tp, p->subob))
+	  diagnostic_group d;
+	  if (d.warning (OPT_Wabi_tag, "%qT does not have the %E ABI tag "
+			 "that %qT (used in the type of %qD) has",
+			 p->t, tag, *tp, p->subob))
 	    {
-	      inform (location_of (p->subob), "%qD declared here",
-		      p->subob);
-	      inform (location_of (*tp), "%qT declared here", *tp);
+	      d.inform (location_of (p->subob), "%qD declared here",
+			p->subob);
+	      d.inform (location_of (*tp), "%qT declared here", *tp);
 	    }
 	}
     }
@@ -2904,20 +2908,24 @@ finish_struct_anon_r (tree field, bool complain)
 	{
 	  /* We already complained about static data members in
 	     finish_static_data_member_decl.  */
-	  if (!VAR_P (elt)
-	      && permerror (DECL_SOURCE_LOCATION (elt),
-			    TREE_CODE (TREE_TYPE (field)) == UNION_TYPE
-			    ? "%q#D invalid; an anonymous union may "
-			    "only have public non-static data members"
-			    : "%q#D invalid; an anonymous struct may "
-			    "only have public non-static data members", elt))
+	  if (!VAR_P (elt))
 	    {
-	      static bool hint;
-	      if (flag_permissive && !hint)
+	      diagnostic_group d;
+	      if (d.permerror (DECL_SOURCE_LOCATION (elt),
+			       TREE_CODE (TREE_TYPE (field)) == UNION_TYPE
+			       ? "%q#D invalid; an anonymous union may "
+			       "only have public non-static data members"
+			       : "%q#D invalid; an anonymous struct may "
+			       "only have public non-static data members", elt))
 		{
-		  hint = true;
-		  inform (DECL_SOURCE_LOCATION (elt),
-			  "this flexibility is deprecated and will be removed");
+		  static bool hint;
+		  if (flag_permissive && !hint)
+		    {
+		      hint = true;
+		      d.inform (DECL_SOURCE_LOCATION (elt),
+				"this flexibility is deprecated and will be "
+				"removed");
+		    }
 		}
 	    }
 	}
@@ -3107,9 +3115,10 @@ one_inherited_ctor (tree ctor, tree t, tree using_decl)
   one_inheriting_sig (t, ctor, new_parms, i);
   if (parms == NULL_TREE)
     {
-      if (warning (OPT_Winherited_variadic_ctor,
-		   "the ellipsis in %qD is not inherited", ctor))
-	inform (DECL_SOURCE_LOCATION (ctor), "%qD declared here", ctor);
+      diagnostic_group d;
+      if (d.warning (OPT_Winherited_variadic_ctor,
+		     "the ellipsis in %qD is not inherited", ctor))
+	d.inform (DECL_SOURCE_LOCATION (ctor), "%qD declared here", ctor);
     }
 }
 
@@ -5399,19 +5408,23 @@ finalize_literal_type_property (tree t)
 	  && !DECL_CONSTRUCTOR_P (fn))
 	{
 	  DECL_DECLARED_CONSTEXPR_P (fn) = false;
-	  if (!DECL_GENERATED_P (fn)
-	      && pedwarn (DECL_SOURCE_LOCATION (fn), OPT_Wpedantic,
-			  "enclosing class of %<constexpr%> non-static member "
-			  "function %q+#D is not a literal type", fn))
-	    explain_non_literal_class (t);
+	  if (!DECL_GENERATED_P (fn))
+	    {
+	      diagnostic_group d;
+	      if (d.pedwarn (DECL_SOURCE_LOCATION (fn), OPT_Wpedantic,
+			     "enclosing class of %<constexpr%> non-static "
+			     "member function %q+#D is not a literal type", fn))
+		explain_non_literal_class (t, &d);
+	    }
 	}
 }
 
 /* T is a non-literal type used in a context which requires a constant
-   expression.  Explain why it isn't literal.  */
+   expression.  Explain why it isn't literal, using D for all
+   diagnostics.  */
 
 void
-explain_non_literal_class (tree t)
+explain_non_literal_class (tree t, diagnostic_group *d)
 {
   static hash_set<tree> *diagnosed;
 
@@ -5425,22 +5438,22 @@ explain_non_literal_class (tree t)
     /* Already explained.  */
     return;
 
-  inform (UNKNOWN_LOCATION, "%q+T is not literal because:", t);
+  d->inform (UNKNOWN_LOCATION, "%q+T is not literal because:", t);
   if (cxx_dialect < cxx17 && LAMBDA_TYPE_P (t))
-    inform (UNKNOWN_LOCATION,
-	    "  %qT is a closure type, which is only literal in "
-	    "C++17 and later", t);
+    d->inform (UNKNOWN_LOCATION,
+	      "  %qT is a closure type, which is only literal in "
+	      "C++17 and later", t);
   else if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
-    inform (UNKNOWN_LOCATION, "  %q+T has a non-trivial destructor", t);
+    d->inform (UNKNOWN_LOCATION, "  %q+T has a non-trivial destructor", t);
   else if (CLASSTYPE_NON_AGGREGATE (t)
 	   && !TYPE_HAS_TRIVIAL_DFLT (t)
 	   && !LAMBDA_TYPE_P (t)
 	   && !TYPE_HAS_CONSTEXPR_CTOR (t))
     {
-      inform (UNKNOWN_LOCATION,
-	      "  %q+T is not an aggregate, does not have a trivial "
-	      "default constructor, and has no %<constexpr%> constructor that "
-	      "is not a copy or move constructor", t);
+      d->inform (UNKNOWN_LOCATION,
+		 "  %q+T is not an aggregate, does not have a trivial "
+		 "default constructor, and has no %<constexpr%> constructor "
+		 "that is not a copy or move constructor", t);
       if (type_has_non_user_provided_default_constructor (t))
 	/* Note that we can't simply call locate_ctor because when the
 	   constructor is deleted it just returns NULL_TREE.  */
@@ -5454,8 +5467,10 @@ explain_non_literal_class (tree t)
 	    if (sufficient_parms_p (parms))
 	      {
 		if (DECL_DELETED_FN (fn))
+		  // FIXME:
 		  maybe_explain_implicit_delete (fn);
 		else
+		  // FIXME:
 		  explain_invalid_constexpr_fn (fn);
 		break;
 	      }
@@ -5470,10 +5485,10 @@ explain_non_literal_class (tree t)
 	  tree basetype = TREE_TYPE (base_binfo);
 	  if (!CLASSTYPE_LITERAL_P (basetype))
 	    {
-	      inform (UNKNOWN_LOCATION,
-		      "  base class %qT of %q+T is non-literal",
-		      basetype, t);
-	      explain_non_literal_class (basetype);
+	      d->inform (UNKNOWN_LOCATION,
+			 "  base class %qT of %q+T is non-literal",
+			 basetype, t);
+	      explain_non_literal_class (basetype, d);
 	      return;
 	    }
 	}
@@ -5485,15 +5500,15 @@ explain_non_literal_class (tree t)
 	  ftype = TREE_TYPE (field);
 	  if (!literal_type_p (ftype))
 	    {
-	      inform (DECL_SOURCE_LOCATION (field),
-		      "  non-static data member %qD has non-literal type",
-		      field);
+	      d->inform (DECL_SOURCE_LOCATION (field),
+			 "  non-static data member %qD has non-literal type",
+			 field);
 	      if (CLASS_TYPE_P (ftype))
-		explain_non_literal_class (ftype);
+		explain_non_literal_class (ftype, d);
 	    }
 	  if (CP_TYPE_VOLATILE_P (ftype))
-	    inform (DECL_SOURCE_LOCATION (field),
-		    "  non-static data member %qD has volatile type", field);
+	    d->inform (DECL_SOURCE_LOCATION (field),
+		       "  non-static data member %qD has volatile type", field);
 	}
     }
 }
@@ -6626,17 +6641,20 @@ find_flexarrays (tree t, flexmems_t *fmem, bool base_p,
 static void
 diagnose_invalid_flexarray (const flexmems_t *fmem)
 {
-  if (fmem->array && fmem->enclosing
-      && pedwarn (location_of (fmem->enclosing), OPT_Wpedantic,
-		  TYPE_DOMAIN (TREE_TYPE (fmem->array))
-		  ? G_("invalid use of %q#T with a zero-size array "
-		       "in %q#D")
-		  : G_("invalid use of %q#T with a flexible array member "
-		       "in %q#T"),
-		  DECL_CONTEXT (fmem->array),
-		  DECL_CONTEXT (fmem->enclosing)))
-    inform (DECL_SOURCE_LOCATION (fmem->array),
-	    "array member %q#D declared here", fmem->array);
+  if (fmem->array && fmem->enclosing)
+    {
+      diagnostic_group d;
+      if (d.pedwarn (location_of (fmem->enclosing), OPT_Wpedantic,
+		     TYPE_DOMAIN (TREE_TYPE (fmem->array))
+		     ? G_("invalid use of %q#T with a zero-size array "
+			  "in %q#D")
+		     : G_("invalid use of %q#T with a flexible array member "
+			  "in %q#T"),
+		     DECL_CONTEXT (fmem->array),
+		     DECL_CONTEXT (fmem->enclosing)))
+	d.inform (DECL_SOURCE_LOCATION (fmem->array),
+		  "array member %q#D declared here", fmem->array);
+    }
 }
 
 /* Issue diagnostics for invalid flexible array members or zero-length
@@ -6670,10 +6688,10 @@ diagnose_flexarrays (tree t, const flexmems_t *fmem)
       if (msg)
 	{
 	  location_t loc = DECL_SOURCE_LOCATION (fmem->array);
-
-	  if (pedwarn (loc, OPT_Wpedantic, msg, fmem->array, t))
+	  diagnostic_group d;
+	  if (d.pedwarn (loc, OPT_Wpedantic, msg, fmem->array, t))
 	    {
-	      inform (location_of (t), "in the definition of %q#T", t);
+	      d.inform (location_of (t), "in the definition of %q#T", t);
 	      diagd = true;
 	    }
 	}
@@ -6690,7 +6708,8 @@ diagnose_flexarrays (tree t, const flexmems_t *fmem)
 	  location_t loc = DECL_SOURCE_LOCATION (fmem->array);
 	  diagd = true;
 
-	  error_at (loc, msg, fmem->array, t);
+	  diagnostic_group d;
+	  d.error_at (loc, msg, fmem->array, t);
 
 	  /* In the unlikely event that the member following the flexible
 	     array member is declared in a different class, or the member
@@ -6700,10 +6719,10 @@ diagnose_flexarrays (tree t, const flexmems_t *fmem)
 	      && ((DECL_CONTEXT (fmem->after[0])
 		   != DECL_CONTEXT (fmem->array))))
 	    {
-	      inform (DECL_SOURCE_LOCATION (fmem->after[0]),
-		      "next member %q#D declared here",
-		      fmem->after[0]);
-	      inform (location_of (t), "in the definition of %q#T", t);
+	      d.inform (DECL_SOURCE_LOCATION (fmem->after[0]),
+			"next member %q#D declared here",
+			fmem->after[0]);
+	      d.inform (location_of (t), "in the definition of %q#T", t);
 	    }
 	}
     }
@@ -7923,11 +7942,12 @@ resolve_address_of_overloaded_function (tree target_type,
       if (!(complain & tf_error))
 	return error_mark_node;
 
-      if (permerror (input_location, "assuming pointer to member %qD", fn)
+      diagnostic_group d;
+      if (d.permerror (input_location, "assuming pointer to member %qD", fn)
 	  && !explained)
 	{
-	  inform (input_location, "(a pointer to member can only be "
-		  "formed with %<&%E%>)", fn);
+	  d.inform (input_location, "(a pointer to member can only be "
+		    "formed with %<&%E%>)", fn);
 	  explained = 1;
 	}
     }
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index ece2c8a..2bf8d0c 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -97,18 +97,20 @@ ensure_literal_type_for_constexpr_object (tree decl)
 	{
 	  if (DECL_DECLARED_CONSTEXPR_P (decl))
 	    {
-	      error ("the type %qT of %<constexpr%> variable %qD "
-		     "is not literal", type, decl);
-	      explain_non_literal_class (type);
+	      diagnostic_group d;
+	      d.error ("the type %qT of %<constexpr%> variable %qD "
+		       "is not literal", type, decl);
+	      explain_non_literal_class (type, &d);
 	      decl = error_mark_node;
 	    }
 	  else
 	    {
 	      if (!is_instantiation_of_constexpr (current_function_decl))
 		{
-		  error ("variable %qD of non-literal type %qT in %<constexpr%> "
-			 "function", decl, type);
-		  explain_non_literal_class (type);
+		  diagnostic_group d;
+		  d.error ("variable %qD of non-literal type %qT in "
+			   "%<constexpr%> function", decl, type);
+		  explain_non_literal_class (type, &d);
 		  decl = error_mark_node;
 		}
 	      cp_function_chain->invalid_constexpr = true;
@@ -200,9 +202,10 @@ is_valid_constexpr_fn (tree fun, bool complain)
 	    ret = false;
 	    if (complain)
 	      {
-		error ("invalid type for parameter %d of %<constexpr%> "
-		       "function %q+#D", DECL_PARM_INDEX (parm), fun);
-		explain_non_literal_class (TREE_TYPE (parm));
+		diagnostic_group d;
+		d.error ("invalid type for parameter %d of %<constexpr%> "
+			 "function %q+#D", DECL_PARM_INDEX (parm), fun);
+		explain_non_literal_class (TREE_TYPE (parm), &d);
 	      }
 	  }
     }
@@ -222,9 +225,10 @@ is_valid_constexpr_fn (tree fun, bool complain)
 	  ret = false;
 	  if (complain)
 	    {
-	      error ("invalid return type %qT of %<constexpr%> function %q+D",
-		     rettype, fun);
-	      explain_non_literal_class (rettype);
+	      diagnostic_group d;
+	      d.error ("invalid return type %qT of %<constexpr%> function %q+D",
+		       rettype, fun);
+	      explain_non_literal_class (rettype, &d);
 	    }
 	}
 
@@ -234,11 +238,15 @@ is_valid_constexpr_fn (tree fun, bool complain)
 	  && !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun)))
 	{
 	  ret = false;
-	  if (complain
-	      && pedwarn (DECL_SOURCE_LOCATION (fun), OPT_Wpedantic,
-			  "enclosing class of %<constexpr%> non-static member "
-			  "function %q+#D is not a literal type", fun))
-	    explain_non_literal_class (DECL_CONTEXT (fun));
+	  if (complain)
+	    {
+	      diagnostic_group d;
+	      if (d.pedwarn (DECL_SOURCE_LOCATION (fun), OPT_Wpedantic,
+			     "enclosing class of %<constexpr%> non-static"
+			     " member function %q+#D is not a literal type",
+			     fun))
+		explain_non_literal_class (DECL_CONTEXT (fun), &d);
+	    }
 	}
     }
   else if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun)))
@@ -818,9 +826,10 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool complain)
 	    }
 	  if (!complain)
 	    return true;
-	  error ("member %qD must be initialized by mem-initializer "
-		 "in %<constexpr%> constructor", field);
-	  inform (DECL_SOURCE_LOCATION (field), "declared here");
+	  diagnostic_group d;
+	  d.error ("member %qD must be initialized by mem-initializer "
+		   "in %<constexpr%> constructor", field);
+	  d.inform (DECL_SOURCE_LOCATION (field), "declared here");
 	  bad = true;
 	}
       if (field == NULL_TREE)
@@ -4303,9 +4312,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	{
 	  if (!ctx->quiet)
 	    {
-	      error ("temporary of non-literal type %qT in a "
-		     "constant expression", TREE_TYPE (t));
-	      explain_non_literal_class (TREE_TYPE (t));
+	      diagnostic_group d;
+	      d.error ("temporary of non-literal type %qT in a "
+		       "constant expression", TREE_TYPE (t));
+	      explain_non_literal_class (TREE_TYPE (t), &d);
 	    }
 	  *non_constant_p = true;
 	  break;
@@ -5995,9 +6005,10 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
 	{
 	  if (flags & tf_error)
 	    {
+	      diagnostic_group d;
 	      error_at (loc, "temporary of non-literal type %qT in a "
 			"constant expression", TREE_TYPE (t));
-	      explain_non_literal_class (TREE_TYPE (t));
+	      explain_non_literal_class (TREE_TYPE (t), &d);
 	    }
 	  return false;
 	}
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 9f9fb52..265d731 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3128,10 +3128,12 @@ diagnose_declaration_constraints (location_t loc, tree decl, tree args)
    or a declaration.  */
 
 void
-diagnose_constraints (location_t loc, tree t, tree args)
+diagnose_constraints (diagnostic_group *group, location_t loc, tree t,
+		      tree args)
 {
   constraint_errors = 0;
 
+  // FIXME: use group:
   if (constraint_p (t))
     diagnose_constraint (loc, t, t, args);
   else if (DECL_P (t))
@@ -3142,5 +3144,5 @@ diagnose_constraints (location_t loc, tree t, tree args)
   /* Note the number of elided failures. */
   int n = undiagnosed_constraint_failures ();
   if (n > 0)
-    inform (loc, "... and %d more constraint errors not shown", n);
+    group->inform (loc, "... and %d more constraint errors not shown", n);
 }
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 7db4acc..13b2418 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -1420,12 +1420,15 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
 	  /* Never mind.  */;
 	else if (wtd->try_block)
 	  {
-	    if (TREE_CODE (wtd->try_block) == MUST_NOT_THROW_EXPR
-		&& warning_at (loc, OPT_Wterminate,
-			       "throw will always call terminate()")
-		&& cxx_dialect >= cxx11
-		&& DECL_DESTRUCTOR_P (current_function_decl))
-	      inform (loc, "in C++11 destructors default to noexcept");
+	    if (TREE_CODE (wtd->try_block) == MUST_NOT_THROW_EXPR)
+	      {
+		diagnostic_group d;
+		if (d.warning_at (loc, OPT_Wterminate,
+				  "throw will always call terminate()")
+		    && cxx_dialect >= cxx11
+		    && DECL_DESTRUCTOR_P (current_function_decl))
+		  d.inform (loc, "in C++11 destructors default to noexcept");
+	      }
 	  }
 	else
 	  {
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index aba246c..faaa766 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6217,7 +6217,7 @@ extern bool classtype_has_non_deleted_move_ctor (tree);
 extern tree classtype_has_user_copy_or_dtor	(tree);
 extern bool type_build_ctor_call		(tree);
 extern bool type_build_dtor_call		(tree);
-extern void explain_non_literal_class		(tree);
+extern void explain_non_literal_class		(tree, diagnostic_group *);
 extern void inherit_targ_abi_tags		(tree);
 extern void defaulted_late_check		(tree);
 extern bool defaultable_fn_check		(tree);
@@ -7469,8 +7469,10 @@ extern tree cp_fully_fold			(tree);
 extern void clear_fold_cache			(void);
 
 /* in name-lookup.c */
-extern void suggest_alternatives_for            (location_t, tree, bool);
-extern bool suggest_alternative_in_explicit_scope (location_t, tree, tree);
+extern void suggest_alternatives_for            (diagnostic_group *,
+						 location_t, tree, bool);
+extern bool suggest_alternative_in_explicit_scope (diagnostic_group *,
+						   location_t, tree, tree);
 extern tree strip_using_decl                    (tree);
 
 /* Tell the binding oracle what kind of binding we are looking for.  */
@@ -7551,7 +7553,8 @@ extern bool subsumes_constraints                (tree, tree);
 extern bool strictly_subsumes			(tree, tree);
 extern int more_constrained                     (tree, tree);
 
-extern void diagnose_constraints                (location_t, tree, tree);
+extern void diagnose_constraints                (diagnostic_group *, location_t,
+						 tree, tree);
 
 /* in logic.cc */
 extern tree decompose_conclusions               (tree);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index da98414..ef9fbaddc 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -1017,23 +1017,25 @@ maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
   if (implicit != ICV_CAST && fn
       && lookup_attribute ("nodiscard", DECL_ATTRIBUTES (fn)))
     {
-      if (warning_at (loc, OPT_Wunused_result,
-		      "ignoring return value of %qD, "
-		      "declared with attribute nodiscard", fn))
-	inform (DECL_SOURCE_LOCATION (fn), "declared here");
+      diagnostic_group d;
+      if (d.warning_at (loc, OPT_Wunused_result,
+			"ignoring return value of %qD, "
+			"declared with attribute nodiscard", fn))
+	d.inform (DECL_SOURCE_LOCATION (fn), "declared here");
     }
   else if (implicit != ICV_CAST
 	   && lookup_attribute ("nodiscard", TYPE_ATTRIBUTES (rettype)))
     {
-      if (warning_at (loc, OPT_Wunused_result,
-		      "ignoring returned value of type %qT, "
-		      "declared with attribute nodiscard", rettype))
+      diagnostic_group d;
+      if (d.warning_at (loc, OPT_Wunused_result,
+			"ignoring returned value of type %qT, "
+			"declared with attribute nodiscard", rettype))
 	{
 	  if (fn)
-	    inform (DECL_SOURCE_LOCATION (fn),
-		    "in call to %qD, declared here", fn);
-	  inform (DECL_SOURCE_LOCATION (TYPE_NAME (rettype)),
-		  "%qT declared here", rettype);
+	    d.inform (DECL_SOURCE_LOCATION (fn),
+		      "in call to %qD, declared here", fn);
+	  d.inform (DECL_SOURCE_LOCATION (TYPE_NAME (rettype)),
+		    "%qT declared here", rettype);
 	}
     }
   else if (TREE_CODE (expr) == TARGET_EXPR
@@ -1043,11 +1045,12 @@ maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
 	 result is used, so handle that case here.  */
       if (fn)
 	{
-	  if (warning_at (loc, OPT_Wunused_result,
-			  "ignoring return value of %qD, "
-			  "declared with attribute warn_unused_result",
-			  fn))
-	    inform (DECL_SOURCE_LOCATION (fn), "declared here");
+	  diagnostic_group d;
+	  if (d.warning_at (loc, OPT_Wunused_result,
+			    "ignoring return value of %qD, "
+			    "declared with attribute warn_unused_result",
+			    fn))
+	    d.inform (DECL_SOURCE_LOCATION (fn), "declared here");
 	}
       else
 	warning_at (loc, OPT_Wunused_result,
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 78ebbde..0175ea9 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1133,10 +1133,11 @@ warn_extern_redeclared_static (tree newdecl, tree olddecl)
       && DECL_ARTIFICIAL (olddecl))
     return;
 
-  if (permerror (DECL_SOURCE_LOCATION (newdecl),
-		 "%qD was declared %<extern%> and later %<static%>", newdecl))
-    inform (DECL_SOURCE_LOCATION (olddecl),
-	    "previous declaration of %qD", olddecl);
+  diagnostic_group d;
+  if (d.permerror (DECL_SOURCE_LOCATION (newdecl),
+		   "%qD was declared %<extern%> and later %<static%>", newdecl))
+    d.inform (DECL_SOURCE_LOCATION (olddecl),
+	      "previous declaration of %qD", olddecl);
 }
 
 /* NEW_DECL is a redeclaration of OLD_DECL; both are functions or
@@ -1176,17 +1177,18 @@ check_redeclaration_exception_specification (tree new_decl,
 	= G_("declaration of %qF has a different exception specifier");
       bool complained = true;
       location_t new_loc = DECL_SOURCE_LOCATION (new_decl);
+      diagnostic_group d;
       if (DECL_IN_SYSTEM_HEADER (old_decl))
-	complained = pedwarn (new_loc, OPT_Wsystem_headers, msg, new_decl);
+	complained = d.pedwarn (new_loc, OPT_Wsystem_headers, msg, new_decl);
       else if (!flag_exceptions)
 	/* We used to silently permit mismatched eh specs with
 	   -fno-exceptions, so make them a pedwarn now.  */
-	complained = pedwarn (new_loc, OPT_Wpedantic, msg, new_decl);
+	complained = d.pedwarn (new_loc, OPT_Wpedantic, msg, new_decl);
       else
-	error_at (new_loc, msg, new_decl);
+	d.error_at (new_loc, msg, new_decl);
       if (complained)
-	inform (DECL_SOURCE_LOCATION (old_decl),
-		"from previous declaration %qF", old_decl);
+	d.inform (DECL_SOURCE_LOCATION (old_decl),
+		  "from previous declaration %qF", old_decl);
     }
 }
 
@@ -1304,11 +1306,12 @@ check_no_redeclaration_friend_default_args (tree olddecl, tree newdecl,
     if ((olddecl_hidden_friend_p && TREE_PURPOSE (t1))
 	|| (DECL_FRIEND_P (newdecl) && TREE_PURPOSE (t2)))
       {
-	if (permerror (DECL_SOURCE_LOCATION (newdecl),
-		       "friend declaration of %q#D specifies default "
-		       "arguments and isn't the only declaration", newdecl))
-	  inform (DECL_SOURCE_LOCATION (olddecl),
-		  "previous declaration of %q#D", olddecl);
+	diagnostic_group d;
+	if (d.permerror (DECL_SOURCE_LOCATION (newdecl),
+			 "friend declaration of %q#D specifies default "
+			 "arguments and isn't the only declaration", newdecl))
+	  d.inform (DECL_SOURCE_LOCATION (olddecl),
+		    "previous declaration of %q#D", olddecl);
 	return;
       }
 }
@@ -1555,12 +1558,14 @@ next_arg:;
 				    "declaration %q#D", newdecl, olddecl);
 			  return error_mark_node;
 			}
-		      if (permerror (newdecl_loc,
-				     "new declaration %q#D ambiguates built-in"
-				     " declaration %q#D", newdecl, olddecl)
+		      diagnostic_group d;
+		      if (d.permerror (newdecl_loc,
+				       "new declaration %q#D ambiguates "
+				       "built-in declaration %q#D", newdecl,
+				       olddecl)
 			  && flag_permissive)
-			inform (newdecl_loc,
-				"ignoring the %q#D declaration", newdecl);
+			d.inform (newdecl_loc,
+				  "ignoring the %q#D declaration", newdecl);
 		      return flag_permissive ? olddecl : error_mark_node;
 		    }
 		}
@@ -1801,12 +1806,13 @@ next_arg:;
       const char *errmsg = redeclaration_error_message (newdecl, olddecl);
       if (errmsg)
 	{
-	  error_at (newdecl_loc, errmsg, newdecl);
+	  diagnostic_group d;
+	  d.error_at (newdecl_loc, errmsg, newdecl);
 	  if (DECL_NAME (olddecl) != NULL_TREE)
-	    inform (olddecl_loc,
-		    (DECL_INITIAL (olddecl) && namespace_bindings_p ())
-		    ? G_("%q#D previously defined here")
-		    : G_("%q#D previously declared here"), olddecl);
+	    d.inform (olddecl_loc,
+		      (DECL_INITIAL (olddecl) && namespace_bindings_p ())
+		      ? G_("%q#D previously defined here")
+		      : G_("%q#D previously declared here"), olddecl);
 	  return error_mark_node;
 	}
       else if (TREE_CODE (olddecl) == FUNCTION_DECL
@@ -1815,10 +1821,11 @@ next_arg:;
 	       && prototype_p (TREE_TYPE (newdecl)))
 	{
 	  /* Prototype decl follows defn w/o prototype.  */
-	  if (warning_at (newdecl_loc, 0,
-			  "prototype specified for %q#D", newdecl))
-	    inform (olddecl_loc,
-		    "previous non-prototype definition here");
+	  diagnostic_group d;
+	  if (d.warning_at (newdecl_loc, 0,
+			    "prototype specified for %q#D", newdecl))
+	    d.inform (olddecl_loc,
+		      "previous non-prototype definition here");
 	}
       else if (VAR_OR_FUNCTION_DECL_P (olddecl)
 	       && DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl))
@@ -1856,12 +1863,13 @@ next_arg:;
 	    }
 	  else
 	    {
-	      error_at (newdecl_loc,
-			"conflicting declaration of %q#D with %qL linkage",
-			newdecl, DECL_LANGUAGE (newdecl));
-	      inform (olddecl_loc,
-		      "previous declaration with %qL linkage",
-		      DECL_LANGUAGE (olddecl));
+	      diagnostic_group d;
+	      d.error_at (newdecl_loc,
+			  "conflicting declaration of %q#D with %qL linkage",
+			  newdecl, DECL_LANGUAGE (newdecl));
+	      d.inform (olddecl_loc,
+			"previous declaration with %qL linkage",
+			DECL_LANGUAGE (olddecl));
 	    }
 	}
 
@@ -1893,21 +1901,23 @@ next_arg:;
 		    if (simple_cst_equal (TREE_PURPOSE (t1),
 					  TREE_PURPOSE (t2)) == 1)
 		      {
-			if (permerror (newdecl_loc,
-				       "default argument given for parameter "
-				       "%d of %q#D", i, newdecl))
-			  inform (olddecl_loc,
-				  "previous specification in %q#D here",
-				  olddecl);
+			diagnostic_group d;
+			if (d.permerror (newdecl_loc,
+					 "default argument given for parameter "
+					 "%d of %q#D", i, newdecl))
+			  d.inform (olddecl_loc,
+				    "previous specification in %q#D here",
+				    olddecl);
 		      }
 		    else
 		      {
-			error_at (newdecl_loc,
-				  "default argument given for parameter %d "
-				  "of %q#D", i, newdecl);
-			inform (olddecl_loc,
-				"previous specification in %q#D here",
-				olddecl);
+			diagnostic_group d;
+			d.error_at (newdecl_loc,
+				    "default argument given for parameter %d "
+				    "of %q#D", i, newdecl);
+			d.inform (olddecl_loc,
+				  "previous specification in %q#D here",
+				  olddecl);
 		      }
 		  }
 
@@ -1977,12 +1987,13 @@ next_arg:;
 	  && (! DECL_TEMPLATE_SPECIALIZATION (newdecl)
 	      || DECL_TEMPLATE_SPECIALIZATION (olddecl)))
 	{
-	  if (warning_at (newdecl_loc,
-			  OPT_Wredundant_decls,
-			  "redundant redeclaration of %qD in same scope",
-			  newdecl))
-	    inform (olddecl_loc,
-		    "previous declaration of %qD", olddecl);
+	  diagnostic_group d;
+	  if (d.warning_at (newdecl_loc,
+			    OPT_Wredundant_decls,
+			    "redundant redeclaration of %qD in same scope",
+			    newdecl))
+	    d.inform (olddecl_loc,
+		      "previous declaration of %qD", olddecl);
 	}
 
       if (!(DECL_TEMPLATE_INSTANTIATION (olddecl)
@@ -1990,9 +2001,10 @@ next_arg:;
 	{
 	  if (DECL_DELETED_FN (newdecl))
 	    {
-	      error_at (newdecl_loc, "deleted definition of %qD", newdecl);
-	      inform (olddecl_loc,
-		      "previous declaration of %qD", olddecl);
+	      diagnostic_group d;
+	      d.error_at (newdecl_loc, "deleted definition of %qD", newdecl);
+	      d.inform (olddecl_loc,
+			"previous declaration of %qD", olddecl);
 	    }
 	  DECL_DELETED_FN (newdecl) |= DECL_DELETED_FN (olddecl);
 	}
@@ -2567,11 +2579,12 @@ next_arg:;
       && DECL_VISIBILITY_SPECIFIED (newdecl)
       && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl))
     {
-      if (warning_at (newdecl_loc, OPT_Wattributes,
-		      "%qD: visibility attribute ignored because it "
-		      "conflicts with previous declaration", newdecl))
-	inform (olddecl_loc,
-		"previous declaration of %qD", olddecl);
+      diagnostic_group d;
+      if (d.warning_at (newdecl_loc, OPT_Wattributes,
+			"%qD: visibility attribute ignored because it "
+			"conflicts with previous declaration", newdecl))
+	d.inform (olddecl_loc,
+		  "previous declaration of %qD", olddecl);
     }
   /* Choose the declaration which specified visibility.  */
   if (DECL_VISIBILITY_SPECIFIED (olddecl))
@@ -2986,12 +2999,15 @@ redeclaration_error_message (tree newdecl, tree olddecl)
 	{
 	  DECL_EXTERNAL (newdecl) = 1;
 	  /* For now, only warn with explicit -Wdeprecated.  */
-	  if (global_options_set.x_warn_deprecated
-	      && warning_at (DECL_SOURCE_LOCATION (newdecl), OPT_Wdeprecated,
-			     "redundant redeclaration of %<constexpr%> static "
-			     "data member %qD", newdecl))
-	    inform (DECL_SOURCE_LOCATION (olddecl),
-		    "previous declaration of %qD", olddecl);
+	  if (global_options_set.x_warn_deprecated)
+	    {
+	      diagnostic_group d;
+	      if (d.warning_at (DECL_SOURCE_LOCATION (newdecl), OPT_Wdeprecated,
+				"redundant redeclaration of %<constexpr%> "
+				"static data member %qD", newdecl))
+		d.inform (DECL_SOURCE_LOCATION (olddecl),
+			  "previous declaration of %qD", olddecl);
+	    }
 	  return NULL;
 	}
 
@@ -4752,12 +4768,13 @@ warn_misplaced_attr_for_class_type (source_location location,
 {
   gcc_assert (OVERLOAD_TYPE_P (class_type));
 
-  if (warning_at (location, OPT_Wattributes,
-		  "attribute ignored in declaration "
-		  "of %q#T", class_type))
-    inform (location,
-	    "attribute for %q#T must follow the %qs keyword",
-	    class_type, class_key_or_enum_as_string (class_type));
+  diagnostic_group d;
+  if (d.warning_at (location, OPT_Wattributes,
+		    "attribute ignored in declaration "
+		    "of %q#T", class_type))
+    d.inform (location,
+	      "attribute for %q#T must follow the %qs keyword",
+	      class_type, class_key_or_enum_as_string (class_type));
 }
 
 /* Make sure that a declaration with no declarator is well-formed, i.e.
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index d67ced0..069919c 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -764,10 +764,11 @@ finish_static_data_member_decl (tree decl,
 	 t = CP_TYPE_CONTEXT (t))
       if (TYPE_UNNAMED_P (t))
 	{
-	  if (permerror (DECL_SOURCE_LOCATION (decl),
-			 "static data member %qD in unnamed class", decl))
-	    inform (DECL_SOURCE_LOCATION (TYPE_NAME (t)),
-		    "unnamed class defined here");
+	  diagnostic_group d;
+	  if (d.permerror (DECL_SOURCE_LOCATION (decl),
+			   "static data member %qD in unnamed class", decl))
+	    d.inform (DECL_SOURCE_LOCATION (TYPE_NAME (t)),
+		      "unnamed class defined here");
 	  break;
 	}
 
@@ -4286,10 +4287,12 @@ no_linkage_error (tree decl)
     vec_safe_push (no_linkage_decls, decl);
   else if (TYPE_UNNAMED_P (t))
     {
-      bool d = false;
+      bool warned = false;
+      diagnostic_group d;
       if (cxx_dialect >= cxx11)
-	d = permerror (DECL_SOURCE_LOCATION (decl), "%q#D, declared using "
-		       "unnamed type, is used but never defined", decl);
+	warned
+	  = d.permerror (DECL_SOURCE_LOCATION (decl), "%q#D, declared using "
+			 "unnamed type, is used but never defined", decl);
       else if (DECL_EXTERN_C_P (decl))
 	/* Allow this; it's pretty common in C.  */;
       else if (VAR_P (decl))
@@ -4297,17 +4300,19 @@ no_linkage_error (tree decl)
 	   no linkage can only be used to declare extern "C"
 	   entities.  Since it's not always an error in the
 	   ISO C++ 90 Standard, we only issue a warning.  */
-	d = warning_at (DECL_SOURCE_LOCATION (decl), 0, "unnamed type "
-			"with no linkage used to declare variable %q#D with "
-			"linkage", decl);
+	warned
+	  = d.warning_at (DECL_SOURCE_LOCATION (decl), 0, "unnamed type "
+			  "with no linkage used to declare variable %q#D with "
+			  "linkage", decl);
       else
-	d = permerror (DECL_SOURCE_LOCATION (decl), "unnamed type with no "
-		       "linkage used to declare function %q#D with linkage",
-		       decl);
-      if (d && is_typedef_decl (TYPE_NAME (t)))
-	inform (DECL_SOURCE_LOCATION (TYPE_NAME (t)), "%q#D does not refer "
-		"to the unqualified type, so it is not used for linkage",
-		TYPE_NAME (t));
+	warned
+	  = d.permerror (DECL_SOURCE_LOCATION (decl), "unnamed type with no "
+			 "linkage used to declare function %q#D with linkage",
+			 decl);
+      if (warned && is_typedef_decl (TYPE_NAME (t)))
+	d.inform (DECL_SOURCE_LOCATION (TYPE_NAME (t)), "%q#D does not refer "
+		  "to the unqualified type, so it is not used for linkage",
+		  TYPE_NAME (t));
     }
   else if (cxx_dialect >= cxx11)
     {
@@ -5208,17 +5213,18 @@ cp_warn_deprecated_use (tree decl, tsubst_flags_t complain)
       && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
       && copy_fn_p (decl))
     {
+      diagnostic_group d;
       /* Don't warn about system library classes (c++/86342).  */
       if (!DECL_IN_SYSTEM_HEADER (decl))
-	warned = warning (OPT_Wdeprecated_copy,
-			  "implicitly-declared %qD is deprecated", decl);
+	warned = d.warning (OPT_Wdeprecated_copy,
+			    "implicitly-declared %qD is deprecated", decl);
       if (warned)
 	{
 	  tree ctx = DECL_CONTEXT (decl);
 	  tree other = classtype_has_user_copy_or_dtor (ctx);
-	  inform (DECL_SOURCE_LOCATION (other),
-		  "because %qT has user-provided %qD",
-		  ctx, other);
+	  d.inform (DECL_SOURCE_LOCATION (other),
+		    "because %qT has user-provided %qD",
+		    ctx, other);
 	}
     }
   else
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index c49f4d7..20f2aa1 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -4269,13 +4269,15 @@ qualified_name_lookup_error (tree scope, tree name,
     }
   else if (scope != global_namespace)
     {
-      error_at (location, "%qD is not a member of %qD", name, scope);
-      if (!suggest_alternative_in_explicit_scope (location, name, scope))
-	suggest_alternatives_for (location, name, false);
+      diagnostic_group d;
+      d.error_at (location, "%qD is not a member of %qD", name, scope);
+      if (!suggest_alternative_in_explicit_scope (&d, location, name, scope))
+	suggest_alternatives_for (&d, location, name, false);
     }
   else
     {
-      error_at (location, "%<::%D%> has not been declared", name);
-      suggest_alternatives_for (location, name, true);
+      diagnostic_group d;
+      d.error_at (location, "%<::%D%> has not been declared", name);
+      suggest_alternatives_for (&d, location, name, true);
     }
 }
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 2c9c12f..485add2 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -304,13 +304,14 @@ make_friend_class (tree type, tree friend_type, bool complain)
       if (TYPE_TEMPLATE_INFO (friend_type)
 	  && !PRIMARY_TEMPLATE_P (TYPE_TI_TEMPLATE (friend_type)))
 	{
-	  error ("%qT is not a template", friend_type);
-	  inform (location_of (friend_type), "previous declaration here");
+	  diagnostic_group d;
+	  d.error ("%qT is not a template", friend_type);
+	  d.inform (location_of (friend_type), "previous declaration here");
 	  if (TYPE_CLASS_SCOPE_P (friend_type)
 	      && CLASSTYPE_TEMPLATE_INFO (TYPE_CONTEXT (friend_type))
 	      && currently_open_class (TYPE_CONTEXT (friend_type)))
-	    inform (input_location, "perhaps you need explicit template "
-		    "arguments in your nested-name-specifier");
+	    d.inform (input_location, "perhaps you need explicit template "
+		      "arguments in your nested-name-specifier");
 	  return;
 	}
     }
@@ -384,19 +385,21 @@ make_friend_class (tree type, tree friend_type, bool complain)
 		}
 	      if (template_member_p && !DECL_CLASS_TEMPLATE_P (decl))
 		{
-		  error ("%qT is not a member class template of %qT",
-			 name, ctype);
-		  inform (DECL_SOURCE_LOCATION (decl),
-			  "%qD declared here", decl);
+		  diagnostic_group d;
+		  d.error ("%qT is not a member class template of %qT",
+			   name, ctype);
+		  d.inform (DECL_SOURCE_LOCATION (decl),
+			    "%qD declared here", decl);
 		  return;
 		}
 	      if (!template_member_p && (TREE_CODE (decl) != TYPE_DECL
 					 || !CLASS_TYPE_P (TREE_TYPE (decl))))
 		{
-		  error ("%qT is not a nested class of %qT",
-			 name, ctype);
-		  inform (DECL_SOURCE_LOCATION (decl),
-			  "%qD declared here", decl);
+		  diagnostic_group d;
+		  d.error ("%qT is not a nested class of %qT",
+			   name, ctype);
+		  d.inform (DECL_SOURCE_LOCATION (decl),
+			    "%qD declared here", decl);
 		  return;
 		}
 
@@ -635,14 +638,17 @@ do_friend (tree ctype, tree declarator, tree decl,
 	    {
 	      static int explained;
 	      bool warned;
-
-	      warned = warning (OPT_Wnon_template_friend, "friend declaration "
+	      diagnostic_group d;
+	      warned
+		= d.warning_at (input_location, OPT_Wnon_template_friend,
+				"friend declaration "
 				"%q#D declares a non-template function", decl);
 	      if (! explained && warned)
 		{
-		  inform (input_location, "(if this is not what you intended, make sure "
-			  "the function template has already been declared "
-			  "and add <> after the function name here) ");
+		  d.inform (input_location,
+			    "(if this is not what you intended, make sure "
+			    "the function template has already been declared "
+			    "and add <> after the function name here) ");
 		  explained = 1;
 		}
 	    }
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 94f8fdd..d072a13 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -915,10 +915,11 @@ perform_member_init (tree member, tree init)
 	    {
 	      /* TYPE_NEEDS_CONSTRUCTING can be set just because we have a
 		 vtable; still give this diagnostic.  */
-	      if (permerror (DECL_SOURCE_LOCATION (current_function_decl),
-			     "uninitialized const member in %q#T", type))
-		inform (DECL_SOURCE_LOCATION (member),
-			"%q#D should be initialized", member );
+	      diagnostic_group d;
+	      if (d.permerror (DECL_SOURCE_LOCATION (current_function_decl),
+			       "uninitialized const member in %q#T", type))
+		d.inform (DECL_SOURCE_LOCATION (member),
+			  "%q#D should be initialized", member );
 	    }
 	  finish_expr_stmt (build_aggr_init (decl, init, flags,
 					     tf_warning_or_error));
@@ -932,16 +933,18 @@ perform_member_init (tree member, tree init)
 	  /* member traversal: note it leaves init NULL */
 	  if (TYPE_REF_P (type))
 	    {
-	      if (permerror (DECL_SOURCE_LOCATION (current_function_decl),
-			     "uninitialized reference member in %q#T", type))
-		inform (DECL_SOURCE_LOCATION (member),
-			"%q#D should be initialized", member);
+	      diagnostic_group d;
+	      if (d.permerror (DECL_SOURCE_LOCATION (current_function_decl),
+			       "uninitialized reference member in %q#T", type))
+		d.inform (DECL_SOURCE_LOCATION (member),
+			  "%q#D should be initialized", member);
 	    }
 	  else if (CP_TYPE_CONST_P (type))
 	    {
-	      if (permerror (DECL_SOURCE_LOCATION (current_function_decl),
-			     "uninitialized const member in %q#T", type))
-		  inform (DECL_SOURCE_LOCATION (member),
+	      diagnostic_group d;
+	      if (d.permerror (DECL_SOURCE_LOCATION (current_function_decl),
+			       "uninitialized const member in %q#T", type))
+		d.inform (DECL_SOURCE_LOCATION (member),
 			  "%q#D should be initialized", member );
 	    }
 
@@ -3255,14 +3258,15 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
 	  || CP_DECL_CONTEXT (alloc_fn) == global_namespace)
       && !aligned_allocation_fn_p (alloc_fn))
     {
-      if (warning (OPT_Waligned_new_, "%<new%> of type %qT with extended "
-		   "alignment %d", elt_type, TYPE_ALIGN_UNIT (elt_type)))
+      diagnostic_group d;
+      if (d.warning (OPT_Waligned_new_, "%<new%> of type %qT with extended "
+		     "alignment %d", elt_type, TYPE_ALIGN_UNIT (elt_type)))
 	{
-	  inform (input_location, "uses %qD, which does not have an alignment "
-		  "parameter", alloc_fn);
+	  d.inform (input_location, "uses %qD, which does not have an "
+		    "alignment parameter", alloc_fn);
 	  if (!aligned_new_threshold)
-	    inform (input_location, "use %<-faligned-new%> to enable C++17 "
-				    "over-aligned new support");
+	    d.inform (input_location, "use %<-faligned-new%> to enable C++17 "
+		      "over-aligned new support");
 	}
     }
 
@@ -3831,16 +3835,20 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
 
   if (!COMPLETE_TYPE_P (type))
     {
-      if ((complain & tf_warning)
-	  && warning (OPT_Wdelete_incomplete,
-		      "possible problem detected in invocation of "
-		      "delete [] operator:"))
-       {
-         cxx_incomplete_type_diagnostic (base, type, DK_WARNING);
-         inform (input_location, "neither the destructor nor the "
-                 "class-specific operator delete [] will be called, "
-                 "even if they are declared when the class is defined");
-       }
+      if (complain & tf_warning)
+	{
+	  diagnostic_group d;
+	  if (d.warning (OPT_Wdelete_incomplete,
+			 "possible problem detected in invocation of "
+			 "delete [] operator:"))
+	    {
+	      // FIXME:
+	      cxx_incomplete_type_diagnostic (base, type, DK_WARNING);
+	      d.inform (input_location, "neither the destructor nor the "
+			"class-specific operator delete [] will be called, "
+			"even if they are declared when the class is defined");
+	    }
+	}
       /* This size won't actually be used.  */
       size_exp = size_one_node;
       goto no_destructor;
@@ -4712,16 +4720,19 @@ build_delete (tree otype, tree addr, special_function_kind auto_delete,
 	  complete_type (type);
 	  if (!COMPLETE_TYPE_P (type))
 	    {
-	      if ((complain & tf_warning)
-		  && warning (OPT_Wdelete_incomplete,
-			      "possible problem detected in invocation of "
-			      "delete operator:"))
+	      if (complain & tf_warning)
 		{
-		  cxx_incomplete_type_diagnostic (addr, type, DK_WARNING);
-		  inform (input_location,
-			  "neither the destructor nor the class-specific "
-			  "operator delete will be called, even if they are "
-			  "declared when the class is defined");
+		  diagnostic_group d;
+		  if (d.warning (OPT_Wdelete_incomplete,
+				 "possible problem detected in invocation of "
+				 "delete operator:"))
+		    {
+		      cxx_incomplete_type_diagnostic (addr, type, DK_WARNING);
+		      d.inform (input_location,
+				"neither the destructor nor the class-specific "
+				"operator delete will be called, even if they "
+				"are declared when the class is defined");
+		    }
 		}
 	    }
 	  else if (deleting && warn_delnonvdtor
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index bd5d507..95ff2d4 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -499,8 +499,9 @@ unqualified_name_lookup_error (tree name, location_t loc)
     {
       if (!objc_diagnose_private_ivar (name))
 	{
-	  error_at (loc, "%qD was not declared in this scope", name);
-	  suggest_alternatives_for (loc, name, true);
+	  diagnostic_group d;
+	  d.error_at (loc, "%qD was not declared in this scope", name);
+	  suggest_alternatives_for (&d, loc, name, true);
 	}
       /* Prevent repeated error messages by creating a VAR_DECL with
 	 this NAME in the innermost block scope.  */
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 0faf739..a6db0f9 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -41,7 +41,8 @@ static cxx_binding *cxx_binding_make (tree value, tree type);
 static cp_binding_level *innermost_nonclass_level (void);
 static void set_identifier_type_value_with_scope (tree id, tree decl,
 						  cp_binding_level *b);
-static bool maybe_suggest_missing_std_header (location_t location, tree name);
+static bool maybe_suggest_missing_std_header (diagnostic_group *group,
+					      location_t location, tree name);
 
 /* Create an overload suitable for recording an artificial TYPE_DECL
    and another decl.  We use this machanism to implement the struct
@@ -2556,13 +2557,17 @@ check_extern_c_conflict (tree decl)
 
       if (mismatch)
 	{
-	  pedwarn (input_location, 0,
-		   "conflicting C language linkage declaration %q#D", decl);
-	  inform (DECL_SOURCE_LOCATION (old),
-		  "previous declaration %q#D", old);
-	  if (mismatch < 0)
-	    inform (input_location,
-		    "due to different exception specifications");
+	  diagnostic_group d;
+	  if (d.pedwarn (input_location, 0,
+			 "conflicting C language linkage declaration %q#D",
+			 decl))
+	    {
+	      d.inform (DECL_SOURCE_LOCATION (old),
+			"previous declaration %q#D", old);
+	      if (mismatch < 0)
+		d.inform (input_location,
+			  "due to different exception specifications");
+	    }
 	}
       else
 	{
@@ -2604,6 +2609,15 @@ c_linkage_bindings (tree name)
   return NULL_TREE;
 }
 
+/* FIXME.  */
+
+static void
+inform_shadowed (tree shadowed, diagnostic_group *group)
+{
+  group->inform (DECL_SOURCE_LOCATION (shadowed),
+		 "shadowed declaration is here");
+}
+
 /* DECL is being declared at a local scope.  Emit suitable shadow
    warnings.  */
 
@@ -2631,7 +2645,6 @@ check_local_shadow (tree decl)
       old_scope = binding->scope;
     }
 
-  tree shadowed = NULL_TREE;
   if (old
       && (TREE_CODE (old) == PARM_DECL
 	  || VAR_P (old)
@@ -2702,9 +2715,10 @@ check_local_shadow (tree decl)
 	       && old_scope == current_binding_level->level_chain
 	       && (old_scope->kind == sk_cond || old_scope->kind == sk_for))
 	{
-	  error ("redeclaration of %q#D", decl);
-	  inform (DECL_SOURCE_LOCATION (old),
-		  "%q#D previously declared here", old);
+	  diagnostic_group d;
+	  d.error ("redeclaration of %q#D", decl);
+	  d.inform (DECL_SOURCE_LOCATION (old),
+		    "%q#D previously declared here", old);
 	  return;
 	}
       /* C++11:
@@ -2724,9 +2738,10 @@ check_local_shadow (tree decl)
 		       || current_binding_level->level_chain->kind == sk_catch)
 		   && in_function_try_handler))
 	{
-	  if (permerror (input_location, "redeclaration of %q#D", decl))
-	    inform (DECL_SOURCE_LOCATION (old),
-		    "%q#D previously declared here", old);
+	  diagnostic_group d;
+	  if (d.permerror (input_location, "redeclaration of %q#D", decl))
+	    d.inform (DECL_SOURCE_LOCATION (old),
+		      "%q#D previously declared here", old);
 	  return;
 	}
 
@@ -2764,11 +2779,9 @@ check_local_shadow (tree decl)
       else
 	msg = "declaration of %qD shadows a previous local";
 
-      if (warning_at (input_location, warning_code, msg, decl))
-	{
-	  shadowed = old;
-	  goto inform_shadowed;
-	}
+      diagnostic_group d;
+      if (d.warning_at (input_location, warning_code, msg, decl))
+	inform_shadowed (old, &d);
       return;
     }
 
@@ -2793,14 +2806,12 @@ check_local_shadow (tree decl)
 	    || TYPE_PTRFN_P (TREE_TYPE (decl))
 	    || TYPE_PTRMEMFUNC_P (TREE_TYPE (decl)))
 	  {
-	    if (warning_at (input_location, OPT_Wshadow,
-			    "declaration of %qD shadows a member of %qT",
-			    decl, current_nonlambda_class_type ())
+	    diagnostic_group d;
+	    if (d.warning_at (input_location, OPT_Wshadow,
+			      "declaration of %qD shadows a member of %qT",
+			      decl, current_nonlambda_class_type ())
 		&& DECL_P (member))
-	      {
-		shadowed = member;
-		goto inform_shadowed;
-	      }
+	      inform_shadowed (member, &d);
 	  }
 	return;
       }
@@ -2815,20 +2826,15 @@ check_local_shadow (tree decl)
       && !instantiating_current_function_p ())
     /* XXX shadow warnings in outer-more namespaces */
     {
-      if (warning_at (input_location, OPT_Wshadow,
-		      "declaration of %qD shadows a global declaration",
-		      decl))
-	{
-	  shadowed = old;
-	  goto inform_shadowed;
-	}
+      diagnostic_group d;
+      if (d.warning_at (input_location, OPT_Wshadow,
+			"declaration of %qD shadows a global declaration",
+			decl))
+	inform_shadowed (old, &d);
       return;
     }
 
   return;
-
- inform_shadowed:
-  inform (DECL_SOURCE_LOCATION (shadowed), "shadowed declaration is here");
 }
 
 /* DECL is being pushed inside function CTX.  Set its context, if
@@ -2954,10 +2960,11 @@ set_local_extern_decl_linkage (tree decl, bool shadowed)
 		       && !comptypes (TREE_TYPE (decl), TREE_TYPE (other),
 				      COMPARE_REDECLARATION)))
 	    {
-	      if (permerror (DECL_SOURCE_LOCATION (decl),
-			     "local external declaration %q#D", decl))
-		inform (DECL_SOURCE_LOCATION (other),
-			"does not match previous declaration %q#D", other);
+	      diagnostic_group d;
+	      if (d.permerror (DECL_SOURCE_LOCATION (decl),
+			       "local external declaration %q#D", decl))
+		d.inform (DECL_SOURCE_LOCATION (other),
+			  "does not match previous declaration %q#D", other);
 	      break;
 	    }
 	}
@@ -5312,8 +5319,8 @@ has_using_namespace_std_directive_p ()
    suggest the best near-match, if there is one.  */
 
 void
-suggest_alternatives_for (location_t location, tree name,
-			  bool suggest_misspellings)
+suggest_alternatives_for (diagnostic_group *group, location_t location,
+			  tree name, bool suggest_misspellings)
 {
   vec<tree> candidates = vNULL;
   vec<tree> worklist = vNULL;
@@ -5350,9 +5357,10 @@ suggest_alternatives_for (location_t location, tree name,
 	      if (worklist.length () == limit)
 		{
 		  /* Unconditionally warn that the search was truncated.  */
-		  inform (location,
-			  "maximum limit of %d namespaces searched for %qE",
-			  limit, name);
+		  group->inform (location,
+				 "maximum limit of %d namespaces searched "
+				 "for %qE",
+				 limit, name);
 		  limited = true;
 		}
 	      else
@@ -5365,14 +5373,14 @@ suggest_alternatives_for (location_t location, tree name,
 
   if (candidates.length ())
     {
-      inform_n (location, candidates.length (),
-		"suggested alternative:",
-		"suggested alternatives:");
+      group->inform_n (location, candidates.length (),
+		       "suggested alternative:",
+		       "suggested alternatives:");
       for (unsigned ix = 0; ix != candidates.length (); ix++)
 	{
 	  tree val = candidates[ix];
 
-	  inform (location_of (val), "  %qE", val);
+	  group->inform (location_of (val), "  %qE", val);
 	}
       candidates.release ();
       return;
@@ -5384,20 +5392,21 @@ suggest_alternatives_for (location_t location, tree name,
      is one of the most common "std::" names, then it's probably a
      missing #include.  */
   if (has_using_namespace_std_directive_p ())
-    if (maybe_suggest_missing_std_header (location, name))
+    if (maybe_suggest_missing_std_header (group, location, name))
       return;
 
   /* Otherwise, consider misspellings.  */
   if (!suggest_misspellings)
     return;
   if (name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_NAME,
-					  location))
+					  group, location))
     {
       /* Show a spelling correction.  */
       gcc_rich_location richloc (location);
 
       richloc.add_fixit_replace (hint.suggestion ());
-      inform (&richloc, "suggested alternative: %qs", hint.suggestion ());
+      group->inform (&richloc, "suggested alternative: %qs",
+		     hint.suggestion ());
     }
 }
 
@@ -5614,7 +5623,8 @@ get_cxx_dialect_name (enum cxx_dialect dialect)
    Return true iff a suggestion was offered.  */
 
 static bool
-maybe_suggest_missing_std_header (location_t location, tree name)
+maybe_suggest_missing_std_header (diagnostic_group *group, location_t location,
+				  tree name)
 {
   gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
 
@@ -5628,16 +5638,16 @@ maybe_suggest_missing_std_header (location_t location, tree name)
     {
       const char *header = header_hint->header;
       maybe_add_include_fixit (&richloc, header);
-      inform (&richloc,
-	      "%<std::%s%> is defined in header %qs;"
-	      " did you forget to %<#include %s%>?",
-	      name_str, header, header);
+      group->inform (&richloc,
+		     "%<std::%s%> is defined in header %qs;"
+		     " did you forget to %<#include %s%>?",
+		     name_str, header, header);
     }
   else
     {
-      inform (&richloc,
-	      "%<std::%s%> is only available from %s onwards",
-	      name_str, get_cxx_dialect_name (header_hint->min_dialect));
+      group->inform (&richloc,
+		     "%<std::%s%> is only available from %s onwards",
+		     name_str, get_cxx_dialect_name (header_hint->min_dialect));
     }
   return true;
 }
@@ -5647,7 +5657,8 @@ maybe_suggest_missing_std_header (location_t location, tree name)
    Return true iff a suggestion was offered.  */
 
 static bool
-maybe_suggest_missing_header (location_t location, tree name, tree scope)
+maybe_suggest_missing_header (diagnostic_group *group, location_t location,
+			      tree name, tree scope)
 {
   if (scope == NULL_TREE)
     return false;
@@ -5656,7 +5667,7 @@ maybe_suggest_missing_header (location_t location, tree name, tree scope)
   /* We only offer suggestions for the "std" namespace.  */
   if (scope != std_node)
     return false;
-  return maybe_suggest_missing_std_header (location, name);
+  return maybe_suggest_missing_std_header (group, location, name);
 }
 
 /* Look for alternatives for NAME, an IDENTIFIER_NODE for which name
@@ -5665,7 +5676,8 @@ maybe_suggest_missing_header (location_t location, tree name, tree scope)
    Return true iff a suggestion was provided.  */
 
 bool
-suggest_alternative_in_explicit_scope (location_t location, tree name,
+suggest_alternative_in_explicit_scope (diagnostic_group *group,
+				       location_t location, tree name,
 				       tree scope)
 {
   /* Something went very wrong; don't suggest anything.  */
@@ -5675,7 +5687,7 @@ suggest_alternative_in_explicit_scope (location_t location, tree name,
   /* Resolve any namespace aliases.  */
   scope = ORIGINAL_NAMESPACE (scope);
 
-  if (maybe_suggest_missing_header (location, name, scope))
+  if (maybe_suggest_missing_header (group, location, name, scope))
     return true;
 
   cp_binding_level *level = NAMESPACE_LEVEL (scope);
@@ -5689,8 +5701,8 @@ suggest_alternative_in_explicit_scope (location_t location, tree name,
     {
       gcc_rich_location richloc (location);
       richloc.add_fixit_replace (fuzzy_name);
-      inform (&richloc, "suggested alternative: %qs",
-	      fuzzy_name);
+      group->inform (&richloc, "suggested alternative: %qs",
+		     fuzzy_name);
       return true;
     }
 
@@ -5834,7 +5846,7 @@ class macro_use_before_def : public deferred_diagnostic
   /* Factory function.  Return a new macro_use_before_def instance if
      appropriate, or return NULL. */
   static macro_use_before_def *
-  maybe_make (location_t use_loc, cpp_hashnode *macro)
+  maybe_make (diagnostic_group *group, location_t use_loc, cpp_hashnode *macro)
   {
     source_location def_loc = cpp_macro_definition_location (macro);
     if (def_loc == UNKNOWN_LOCATION)
@@ -5848,14 +5860,15 @@ class macro_use_before_def : public deferred_diagnostic
     if (!linemap_location_before_p (line_table, use_loc, def_loc))
       return NULL;
 
-    return new macro_use_before_def (use_loc, macro);
+    return new macro_use_before_def (group, use_loc, macro);
   }
 
  private:
   /* Ctor.  LOC is the location of the usage.  MACRO is the
      macro that was used.  */
-  macro_use_before_def (location_t loc, cpp_hashnode *macro)
-  : deferred_diagnostic (loc), m_macro (macro)
+  macro_use_before_def (diagnostic_group *group, location_t loc,
+			cpp_hashnode *macro)
+  : deferred_diagnostic (group, loc), m_macro (macro)
   {
     gcc_assert (macro);
   }
@@ -5864,7 +5877,7 @@ class macro_use_before_def : public deferred_diagnostic
   {
     if (is_suppressed_p ())
       return;
-
+    // FIXME: use group
     inform (get_location (), "the macro %qs had not yet been defined",
 	    (const char *)m_macro->ident.str);
     inform (cpp_macro_definition_location (m_macro),
@@ -5906,10 +5919,11 @@ suggest_rid_p  (enum rid rid)
    macro names, returning the best match as a const char *, or NULL if
    no reasonable match is found.
 
-   Use LOC for any deferred diagnostics.  */
+   Use GROUP and LOC for any deferred diagnostics.  */
 
 name_hint
-lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
+lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind,
+		   diagnostic_group *group, location_t loc)
 {
   gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
 
@@ -5919,7 +5933,7 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
     = get_cp_stdlib_header_for_name (IDENTIFIER_POINTER (name));
   if (header_hint)
     return name_hint (NULL,
-		      new suggest_missing_header (loc,
+		      new suggest_missing_header (group, loc,
 						  IDENTIFIER_POINTER (name),
 						  header_hint));
 
@@ -5957,7 +5971,7 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
       cpp_hashnode *macro = bmm.blithely_get_best_candidate ();
       if (macro && (macro->flags & NODE_BUILTIN) == 0)
 	return name_hint (NULL,
-			  macro_use_before_def::maybe_make (loc, macro));
+			  macro_use_before_def::maybe_make (group, loc, macro));
     }
 
   /* Try the "starts_decl_specifier_p" keywords to detect
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 93c812f..da475bd 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -3280,13 +3280,14 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
   to specify an argument list. Emit a useful error message.  */
   if (DECL_TYPE_TEMPLATE_P (decl))
     {
-      error_at (location,
-		"invalid use of template-name %qE without an argument list",
-		decl);
+      diagnostic_group d;
+      d.error_at (location,
+		  "invalid use of template-name %qE without an argument list",
+		  decl);
       if (DECL_CLASS_TEMPLATE_P (decl) && cxx_dialect < cxx17)
-	inform (location, "class template argument deduction is only available "
-		"with -std=c++17 or -std=gnu++17");
-      inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
+	d.inform (location, "class template argument deduction is only "
+		  "available with -std=c++17 or -std=gnu++17");
+      d.inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
     }
   else if (TREE_CODE (id) == BIT_NOT_EXPR)
     error_at (location, "invalid use of destructor %qD as a type", id);
@@ -3296,19 +3297,20 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
   else if (!parser->scope)
     {
       /* Issue an error message.  */
+      diagnostic_group d;
       name_hint hint;
       if (TREE_CODE (id) == IDENTIFIER_NODE)
-	hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_TYPENAME, location);
+	hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_TYPENAME, &d, location);
       if (hint)
 	{
 	  gcc_rich_location richloc (location);
 	  richloc.add_fixit_replace (hint.suggestion ());
-	  error_at (&richloc,
-		    "%qE does not name a type; did you mean %qs?",
-		    id, hint.suggestion ());
+	  d.error_at (&richloc,
+		      "%qE does not name a type; did you mean %qs?",
+		      id, hint.suggestion ());
 	}
       else
-	error_at (location, "%qE does not name a type", id);
+	d.error_at (location, "%qE does not name a type", id);
       /* If we're in a template class, it's possible that the user was
 	 referring to a type from a base class.  For example:
 
@@ -3317,18 +3319,18 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
 
 	 The user should have said "typename A<T>::X".  */
       if (cxx_dialect < cxx11 && id == ridpointers[(int)RID_CONSTEXPR])
-	inform (location, "C++11 %<constexpr%> only available with "
-		"-std=c++11 or -std=gnu++11");
+	d.inform (location, "C++11 %<constexpr%> only available with "
+		  "-std=c++11 or -std=gnu++11");
       else if (cxx_dialect < cxx11 && id == ridpointers[(int)RID_NOEXCEPT])
-	inform (location, "C++11 %<noexcept%> only available with "
-		"-std=c++11 or -std=gnu++11");
+	d.inform (location, "C++11 %<noexcept%> only available with "
+		  "-std=c++11 or -std=gnu++11");
       else if (cxx_dialect < cxx11
 	       && TREE_CODE (id) == IDENTIFIER_NODE
 	       && id_equal (id, "thread_local"))
-	inform (location, "C++11 %<thread_local%> only available with "
-		"-std=c++11 or -std=gnu++11");
+	d.inform (location, "C++11 %<thread_local%> only available with "
+		  "-std=c++11 or -std=gnu++11");
       else if (!flag_concepts && id == ridpointers[(int)RID_CONCEPT])
-	inform (location, "%<concept%> only available with -fconcepts");
+	d.inform (location, "%<concept%> only available with -fconcepts");
       else if (processing_template_decl && current_class_type
 	       && TYPE_BINFO (current_class_type))
 	{
@@ -3353,9 +3355,9 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
 		    if (TREE_CODE (field) == TYPE_DECL
 			&& DECL_NAME (field) == id)
 		      {
-			inform (location, 
-				"(perhaps %<typename %T::%E%> was intended)",
-				BINFO_TYPE (b), id);
+			d.inform (location,
+				  "(perhaps %<typename %T::%E%> was intended)",
+				  BINFO_TYPE (b), id);
 			break;
 		      }
 		  if (field)
@@ -3370,33 +3372,35 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
     {
       if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
 	{
+	  diagnostic_group d;
 	  if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
-	    error_at (location_of (id),
-		      "%qE in namespace %qE does not name a template type",
-		      id, parser->scope);
+	    d.error_at (location_of (id),
+			"%qE in namespace %qE does not name a template type",
+			id, parser->scope);
 	  else if (TREE_CODE (id) == TEMPLATE_ID_EXPR)
-	    error_at (location_of (id),
-		      "%qE in namespace %qE does not name a template type",
-		      TREE_OPERAND (id, 0), parser->scope);
+	    d.error_at (location_of (id),
+			"%qE in namespace %qE does not name a template type",
+			TREE_OPERAND (id, 0), parser->scope);
 	  else
-	    error_at (location_of (id),
-		      "%qE in namespace %qE does not name a type",
-		      id, parser->scope);
+	    d.error_at (location_of (id),
+			"%qE in namespace %qE does not name a type",
+			id, parser->scope);
 	  if (DECL_P (decl))
-	    inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
+	    d.inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
 	  else if (decl == error_mark_node)
-	    suggest_alternative_in_explicit_scope (location, id,
+	    suggest_alternative_in_explicit_scope (&d, location, id,
 						   parser->scope);
 	}
       else if (CLASS_TYPE_P (parser->scope)
 	       && constructor_name_p (id, parser->scope))
 	{
 	  /* A<T>::A<T>() */
-	  error_at (location, "%<%T::%E%> names the constructor, not"
-		    " the type", parser->scope, id);
+	  diagnostic_group d;
+	  d.error_at (location, "%<%T::%E%> names the constructor, not"
+		      " the type", parser->scope, id);
 	  if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
-	    error_at (location, "and %qT has no template constructors",
-		      parser->scope);
+	    d.error_at (location, "and %qT has no template constructors",
+			parser->scope);
 	}
       else if (TYPE_P (parser->scope)
 	       && dependent_scope_p (parser->scope))
@@ -3417,23 +3421,25 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
 	}
       else if (TYPE_P (parser->scope))
 	{
+	  diagnostic_group d;
 	  if (!COMPLETE_TYPE_P (parser->scope))
+	    // FIXME use d here?
 	    cxx_incomplete_type_error (location_of (id), NULL_TREE,
 				       parser->scope);
 	  else if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
-	    error_at (location_of (id),
-		      "%qE in %q#T does not name a template type",
-		      id, parser->scope);
+	    d.error_at (location_of (id),
+			"%qE in %q#T does not name a template type",
+			id, parser->scope);
 	  else if (TREE_CODE (id) == TEMPLATE_ID_EXPR)
-	    error_at (location_of (id),
-		      "%qE in %q#T does not name a template type",
-		      TREE_OPERAND (id, 0), parser->scope);
+	    d.error_at (location_of (id),
+			"%qE in %q#T does not name a template type",
+			TREE_OPERAND (id, 0), parser->scope);
 	  else
-	    error_at (location_of (id),
-		      "%qE in %q#T does not name a type",
-		      id, parser->scope);
+	    d.error_at (location_of (id),
+			"%qE in %q#T does not name a type",
+			id, parser->scope);
 	  if (DECL_P (decl))
-	    inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
+	    d.inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
 	}
       else
 	gcc_unreachable ();
@@ -18615,11 +18621,13 @@ cp_parser_namespace_name (cp_parser* parser)
     {
       if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
 	{
-	  error_at (token->location, "%qD is not a namespace-name", identifier);
+	  diagnostic_group d;
+	  d.error_at (token->location, "%qD is not a namespace-name",
+		      identifier);
 	  if (namespace_decl == error_mark_node
 	      && parser->scope && TREE_CODE (parser->scope) == NAMESPACE_DECL)
-	    suggest_alternative_in_explicit_scope (token->location, identifier,
-						   parser->scope);
+	    suggest_alternative_in_explicit_scope (&d, token->location,
+						   identifier, parser->scope);
 	}
       cp_parser_error (parser, "expected namespace-name");
       namespace_decl = error_mark_node;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7fcf5d6..e293752 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -800,10 +800,11 @@ check_specialization_namespace (tree tmpl)
     return true;
   else
     {
-      if (permerror (input_location,
+      diagnostic_group d;
+      if (d.permerror (input_location,
 		     "specialization of %qD in different namespace", tmpl))
-	inform (DECL_SOURCE_LOCATION (tmpl),
-		"  from definition of %q#D", tmpl);
+	d.inform (DECL_SOURCE_LOCATION (tmpl),
+		  "  from definition of %q#D", tmpl);
       return false;
     }
 }
@@ -2592,15 +2593,16 @@ check_template_variable (tree decl)
     }
   if (template_header_count > wanted)
     {
-      bool warned = pedwarn (DECL_SOURCE_LOCATION (decl), 0,
-			     "too many template headers for %qD "
-	                     "(should be %d)",
-			     decl, wanted);
+      diagnostic_group d;
+      bool warned = d.pedwarn (DECL_SOURCE_LOCATION (decl), 0,
+			       "too many template headers for %qD "
+			       "(should be %d)",
+			       decl, wanted);
       if (warned && CLASS_TYPE_P (ctx)
 	  && CLASSTYPE_TEMPLATE_SPECIALIZATION (ctx))
-	inform (DECL_SOURCE_LOCATION (decl),
-		"members of an explicitly specialized class are defined "
-		"without a template header");
+	d.inform (DECL_SOURCE_LOCATION (decl),
+		  "members of an explicitly specialized class are defined "
+		  "without a template header");
     }
 }
 
@@ -2724,14 +2726,15 @@ warn_spec_missing_attributes (tree tmpl, tree spec, tree attrlist)
   if (!nattrs)
     return;
 
-  if (warning_at (DECL_SOURCE_LOCATION (spec), OPT_Wmissing_attributes,
-		  "explicit specialization %q#D may be missing attributes",
-		  spec))
-    inform (DECL_SOURCE_LOCATION (tmpl),
-	    nattrs > 1
-	    ? G_("missing primary template attributes %s")
-	    : G_("missing primary template attribute %s"),
-	    pp_formatted_text (&str));
+  diagnostic_group d;
+  if (d.warning_at (DECL_SOURCE_LOCATION (spec), OPT_Wmissing_attributes,
+		    "explicit specialization %q#D may be missing attributes",
+		    spec))
+    d.inform (DECL_SOURCE_LOCATION (tmpl),
+	      nattrs > 1
+	      ? G_("missing primary template attributes %s")
+	      : G_("missing primary template attribute %s"),
+	      pp_formatted_text (&str));
 }
 
 /* Check to see if the function just declared, as indicated in
@@ -3070,11 +3073,12 @@ check_explicit_specialization (tree declarator,
 	  if (TREE_CODE (decl) == FUNCTION_DECL
 	      && DECL_HIDDEN_FRIEND_P (tmpl))
 	    {
-	      if (pedwarn (DECL_SOURCE_LOCATION (decl), 0,
-			   "friend declaration %qD is not visible to "
-			   "explicit specialization", tmpl))
-		inform (DECL_SOURCE_LOCATION (tmpl),
-			"friend declaration here");
+	      diagnostic_group d;
+	      if (d.pedwarn (DECL_SOURCE_LOCATION (decl), 0,
+			     "friend declaration %qD is not visible to "
+			     "explicit specialization", tmpl))
+		d.inform (DECL_SOURCE_LOCATION (tmpl),
+			  "friend declaration here");
 	    }
 	  else if (!ctype && !is_friend
 		   && CP_DECL_CONTEXT (decl) == current_namespace)
@@ -4891,10 +4895,11 @@ process_partial_specialization (tree decl)
 	   && TMPL_ARGS_DEPTH (specargs) == 1
 	   && !get_partial_spec_bindings (maintmpl, maintmpl, specargs))
     {
-      if (permerror (input_location, "partial specialization %qD is not "
-		     "more specialized than", decl))
-	inform (DECL_SOURCE_LOCATION (maintmpl), "primary template %qD",
-		maintmpl);
+      diagnostic_group d;
+      if (d.permerror (input_location, "partial specialization %qD is not "
+		       "more specialized than", decl))
+	d.inform (DECL_SOURCE_LOCATION (maintmpl), "primary template %qD",
+		  maintmpl);
     }
 
   /* [temp.class.spec]
@@ -9352,8 +9357,9 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
         {
           if (complain & tf_error)
             {
-              error ("template constraint failure");
-              diagnose_constraints (input_location, gen_tmpl, arglist);
+	      diagnostic_group d;
+	      d.error ("template constraint failure");
+	      diagnose_constraints (&d, input_location, gen_tmpl, arglist);
             }
           return error_mark_node;
         }
@@ -9710,8 +9716,9 @@ finish_template_variable (tree var, tsubst_flags_t complain)
     {
       if (complain & tf_error)
 	{
-	  error ("use of invalid variable template %qE", var);
-	  diagnose_constraints (location_of (var), templ, arglist);
+	  diagnostic_group d;
+	  d.error ("use of invalid variable template %qE", var);
+	  diagnose_constraints (&d, location_of (var), templ, arglist);
 	}
       return error_mark_node;
     }
@@ -26886,27 +26893,28 @@ do_auto_deduction (tree type, tree init, tree auto_node,
           {
             if (complain & tf_warning_or_error)
               {
+		diagnostic_group d;
                 switch (context)
                   {
                   case adc_unspecified:
 		  case adc_unify:
-                    error("placeholder constraints not satisfied");
+		    d.error("placeholder constraints not satisfied");
                     break;
                   case adc_variable_type:
 		  case adc_decomp_type:
-                    error ("deduced initializer does not satisfy "
-                           "placeholder constraints");
+		    d.error ("deduced initializer does not satisfy "
+			     "placeholder constraints");
                     break;
                   case adc_return_type:
-                    error ("deduced return type does not satisfy "
-                           "placeholder constraints");
+		    d.error ("deduced return type does not satisfy "
+			     "placeholder constraints");
                     break;
                   case adc_requirement:
-		    error ("deduced expression type does not satisfy "
-                           "placeholder constraints");
+		    d.error ("deduced expression type does not satisfy "
+			     "placeholder constraints");
                     break;
                   }
-                diagnose_constraints (input_location, constr, targs);
+		diagnose_constraints (&d, input_location, constr, targs);
               }
             return error_mark_node;
           }
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index c2860b0..7eb501f 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -1911,10 +1911,11 @@ check_final_overrider (tree overrider, tree basefn)
 	/* GNU extension, allow trivial pointer conversions such as
 	   converting to void *, or qualification conversion.  */
 	{
-	  if (pedwarn (DECL_SOURCE_LOCATION (overrider), 0,
-		       "invalid covariant return type for %q#D", overrider))
-	    inform (DECL_SOURCE_LOCATION (basefn),
-		    "overridden function is %q#D", basefn);
+	  diagnostic_group d;
+	  if (d.pedwarn (DECL_SOURCE_LOCATION (overrider), 0,
+			 "invalid covariant return type for %q#D", overrider))
+	    d.inform (DECL_SOURCE_LOCATION (basefn),
+		      "overridden function is %q#D", basefn);
 	}
       else
 	fail = 2;
@@ -1927,15 +1928,17 @@ check_final_overrider (tree overrider, tree basefn)
     {
       if (fail == 1)
 	{
-	  error ("invalid covariant return type for %q+#D", overrider);
-	  inform (DECL_SOURCE_LOCATION (basefn),
-		  "overridden function is %q#D", basefn);
+	  diagnostic_group d;
+	  d.error ("invalid covariant return type for %q+#D", overrider);
+	  d.inform (DECL_SOURCE_LOCATION (basefn),
+		    "overridden function is %q#D", basefn);
 	}
       else
 	{
-	  error ("conflicting return type specified for %q+#D", overrider);
-	  inform (DECL_SOURCE_LOCATION (basefn),
-		  "overridden function is %q#D", basefn);
+	  diagnostic_group d;
+	  d.error ("conflicting return type specified for %q+#D", overrider);
+	  d.inform (DECL_SOURCE_LOCATION (basefn),
+		    "overridden function is %q#D", basefn);
 	}
       DECL_INVALID_OVERRIDER_P (overrider) = 1;
       return 0;
@@ -1949,9 +1952,10 @@ check_final_overrider (tree overrider, tree basefn)
 
   if (!comp_except_specs (base_throw, over_throw, ce_derived))
     {
-      error ("looser throw specifier for %q+#F", overrider);
-      inform (DECL_SOURCE_LOCATION (basefn),
-	      "overridden function is %q#F", basefn);
+      diagnostic_group d;
+      d.error ("looser throw specifier for %q+#F", overrider);
+      d.inform (DECL_SOURCE_LOCATION (basefn),
+		"overridden function is %q#F", basefn);
       DECL_INVALID_OVERRIDER_P (overrider) = 1;
       return 0;
     }
@@ -1962,9 +1966,10 @@ check_final_overrider (tree overrider, tree basefn)
       && !tx_safe_fn_type_p (base_type)
       && !tx_safe_fn_type_p (over_type))
     {
-      error ("conflicting type attributes specified for %q+#D", overrider);
-      inform (DECL_SOURCE_LOCATION (basefn),
-	      "overridden function is %q#D", basefn);
+      diagnostic_group d;
+      d.error ("conflicting type attributes specified for %q+#D", overrider);
+      d.inform (DECL_SOURCE_LOCATION (basefn),
+		"overridden function is %q#D", basefn);
       DECL_INVALID_OVERRIDER_P (overrider) = 1;
       return 0;
     }
@@ -1978,36 +1983,40 @@ check_final_overrider (tree overrider, tree basefn)
       && !lookup_attribute ("transaction_safe_dynamic",
 			    DECL_ATTRIBUTES (basefn)))
     {
-      error_at (DECL_SOURCE_LOCATION (overrider),
-		"%qD declared %<transaction_safe_dynamic%>", overrider);
-      inform (DECL_SOURCE_LOCATION (basefn),
-	      "overriding %qD declared %<transaction_safe%>", basefn);
+      diagnostic_group d;
+      d.error_at (DECL_SOURCE_LOCATION (overrider),
+		  "%qD declared %<transaction_safe_dynamic%>", overrider);
+      d.inform (DECL_SOURCE_LOCATION (basefn),
+		"overriding %qD declared %<transaction_safe%>", basefn);
     }
 
   if (DECL_DELETED_FN (basefn) != DECL_DELETED_FN (overrider))
     {
       if (DECL_DELETED_FN (overrider))
 	{
-	  error ("deleted function %q+D overriding non-deleted function",
-		 overrider);
-	  inform (DECL_SOURCE_LOCATION (basefn),
+	  diagnostic_group d;
+	  d.error ("deleted function %q+D overriding non-deleted function",
+		   overrider);
+	  d.inform (DECL_SOURCE_LOCATION (basefn),
 		  "overridden function is %qD", basefn);
 	  maybe_explain_implicit_delete (overrider);
 	}
       else
 	{
-	  error ("non-deleted function %q+D overriding deleted function",
-		 overrider);
-	  inform (DECL_SOURCE_LOCATION (basefn),
-		  "overridden function is %qD", basefn);
+	  diagnostic_group d;
+	  d.error ("non-deleted function %q+D overriding deleted function",
+		   overrider);
+	  d.inform (DECL_SOURCE_LOCATION (basefn),
+		    "overridden function is %qD", basefn);
 	}
       return 0;
     }
   if (DECL_FINAL_P (basefn))
     {
-      error ("virtual function %q+D overriding final function", overrider);
-      inform (DECL_SOURCE_LOCATION (basefn),
-	      "overridden function is %qD", basefn);
+      diagnostic_group d;
+      d.error ("virtual function %q+D overriding final function", overrider);
+      d.inform (DECL_SOURCE_LOCATION (basefn),
+		"overridden function is %qD", basefn);
       return 0;
     }
   return 1;
@@ -2089,8 +2098,9 @@ look_for_overrides_r (tree type, tree fndecl)
 	{
 	  /* A static member function cannot match an inherited
 	     virtual member function.  */
-	  error ("%q+#D cannot be declared", fndecl);
-	  error ("  since %q+#D declared in base class", fn);
+	  diagnostic_group d;
+	  d.error ("%q+#D cannot be declared", fndecl);
+	  d.error ("  since %q+#D declared in base class", fn);
 	}
       else
 	{
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 1cf3269..175c631 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -4031,22 +4031,24 @@ maybe_warn_parm_abi (tree t, location_t loc)
       && classtype_has_non_deleted_move_ctor (t))
     {
       bool w;
+      diagnostic_group d;
       if (flag_abi_version > 12)
-	w = warning_at (loc, OPT_Wabi, "-fabi-version=13 (GCC 8.2) fixes the "
-			"calling convention for %qT, which was accidentally "
-			"changed in 8.1", t);
+	w = d.warning_at (loc, OPT_Wabi, "-fabi-version=13 (GCC 8.2) fixes the "
+			  "calling convention for %qT, which was accidentally "
+			  "changed in 8.1", t);
       else
-	w = warning_at (loc, OPT_Wabi, "-fabi-version=12 (GCC 8.1) accident"
-			"ally changes the calling convention for %qT", t);
+	w = d.warning_at (loc, OPT_Wabi, "-fabi-version=12 (GCC 8.1) accident"
+			  "ally changes the calling convention for %qT", t);
       if (w)
-	inform (location_of (t), " declared here");
+	d.inform (location_of (t), " declared here");
       return;
     }
 
-  if (warning_at (loc, OPT_Wabi, "the calling convention for %qT changes in "
-		  "-fabi-version=13 (GCC 8.2)", t))
-    inform (location_of (t), " because all of its copy and move "
-	    "constructors are deleted");
+  diagnostic_group d;
+  if (d.warning_at (loc, OPT_Wabi, "the calling convention for %qT changes in "
+		    "-fabi-version=13 (GCC 8.2)", t))
+    d.inform (location_of (t), " because all of its copy and move "
+	      "constructors are deleted");
 }
 
 /* Returns true iff copying an object of type T (including via move
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 072953c..cb0dfea 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1691,9 +1691,10 @@ cxx_sizeof_expr (tree e, tsubst_flags_t complain)
       && DECL_ARRAY_PARAMETER_P (e)
       && (complain & tf_warning))
     {
-      if (warning (OPT_Wsizeof_array_argument, "%<sizeof%> on array function "
-		   "parameter %qE will return size of %qT", e, TREE_TYPE (e)))
-	inform (DECL_SOURCE_LOCATION (e), "declared here");
+      diagnostic_group d;
+      if (d.warning (OPT_Wsizeof_array_argument, "%<sizeof%> on array function "
+		     "parameter %qE will return size of %qT", e, TREE_TYPE (e)))
+	d.inform (DECL_SOURCE_LOCATION (e), "declared here");
     }
 
   e = mark_type_use (e);
@@ -3773,9 +3774,10 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
           && (complain & tf_error)
           && !constraints_satisfied_p (function))
         {
-          error ("cannot call function %qD", function);
+	  diagnostic_group d;
+	  d.error ("cannot call function %qD", function);
           location_t loc = DECL_SOURCE_LOCATION (function);
-          diagnose_constraints (loc, function, NULL_TREE);
+	  diagnose_constraints (&d, loc, function, NULL_TREE);
           return error_mark_node;
         }
 
@@ -4541,13 +4543,16 @@ cp_build_binary_op (location_t location,
 		   && DECL_ARRAY_PARAMETER_P (first_arg)
 		   && warn_sizeof_array_argument)
 	      && (complain & tf_warning))
-	    if (warning_at (location, OPT_Wsizeof_pointer_div,
-			    "division %<sizeof (%T) / sizeof (%T)%> does "
-			    "not compute the number of array elements",
+	    {
+	      diagnostic_group d;
+	      if (d.warning_at (location, OPT_Wsizeof_pointer_div,
+				"division %<sizeof (%T) / sizeof (%T)%> does "
+				"not compute the number of array elements",
 			    type0, type1))
-	      if (DECL_P (first_arg))
-		inform (DECL_SOURCE_LOCATION (first_arg),
-			"first %<sizeof%> operand was declared here");
+		if (DECL_P (first_arg))
+		  d.inform (DECL_SOURCE_LOCATION (first_arg),
+			    "first %<sizeof%> operand was declared here");
+	    }
 	}
 
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
@@ -4840,12 +4845,15 @@ cp_build_binary_op (location_t location,
 	  else
 	    result_type = type0;
 
-	  if (char_type_p (TREE_TYPE (orig_op1))
-	      && warning (OPT_Wpointer_compare,
-			  "comparison between pointer and zero character "
-			  "constant"))
-	    inform (input_location,
-		    "did you mean to dereference the pointer?");
+	  if (char_type_p (TREE_TYPE (orig_op1)))
+	    {
+	      diagnostic_group d;
+	      if (d.warning (OPT_Wpointer_compare,
+			     "comparison between pointer and zero character "
+			     "constant"))
+		d.inform (input_location,
+			  "did you mean to dereference the pointer?");
+	    }
 	  warn_for_null_address (location, op0, complain);
 	}
       else if (((code1 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type1))
@@ -4860,12 +4868,15 @@ cp_build_binary_op (location_t location,
 	  else
 	    result_type = type1;
 
-	  if (char_type_p (TREE_TYPE (orig_op0))
-	      && warning (OPT_Wpointer_compare,
-			  "comparison between pointer and zero character "
-			  "constant"))
-	    inform (input_location,
-		    "did you mean to dereference the pointer?");
+	  if (char_type_p (TREE_TYPE (orig_op0)))
+	    {
+	      diagnostic_group d;
+	      if (d.warning (OPT_Wpointer_compare,
+			     "comparison between pointer and zero character "
+			     "constant"))
+		inform (input_location,
+			"did you mean to dereference the pointer?");
+	    }
 	  warn_for_null_address (location, op1, complain);
 	}
       else if ((code0 == POINTER_TYPE && code1 == POINTER_TYPE)
@@ -8881,11 +8892,13 @@ convert_for_assignment (tree type, tree rhs,
 		}
 	      else if (fndecl)
 		{
-		  error_at (cp_expr_loc_or_loc (rhs, input_location),
-			    "cannot convert %qH to %qI",
-			    rhstype, type);
-		  inform (get_fndecl_argument_location (fndecl, parmnum),
-			  "  initializing argument %P of %qD", parmnum, fndecl);
+		  diagnostic_group d;
+		  d.error_at (cp_expr_loc_or_loc (rhs, input_location),
+			      "cannot convert %qH to %qI",
+			      rhstype, type);
+		  d.inform (get_fndecl_argument_location (fndecl, parmnum),
+			    "  initializing argument %P of %qD", parmnum,
+			    fndecl);
 		}
 	      else
 		switch (errtype)
@@ -9152,26 +9165,27 @@ maybe_warn_about_returning_address_of_local (tree retval)
 	   || TREE_PUBLIC (whats_returned)))
     {
       bool w = false;
+      diagnostic_group d;
       if (TYPE_REF_P (valtype))
-	w = warning_at (loc, OPT_Wreturn_local_addr,
-			"reference to local variable %qD returned",
-			whats_returned);
+	w = d.warning_at (loc, OPT_Wreturn_local_addr,
+			  "reference to local variable %qD returned",
+			  whats_returned);
       else if (is_std_init_list (valtype))
-	w = warning_at (loc, OPT_Winit_list_lifetime,
-			"returning local initializer_list variable %qD "
-			"does not extend the lifetime of the underlying array",
-			whats_returned);
+	w = d.warning_at (loc, OPT_Winit_list_lifetime,
+			  "returning local initializer_list variable %qD does"
+			  "not extend the lifetime of the underlying array",
+			  whats_returned);
       else if (TREE_CODE (whats_returned) == LABEL_DECL)
-	w = warning_at (loc, OPT_Wreturn_local_addr,
-			"address of label %qD returned",
-			whats_returned);
+	w = d.warning_at (loc, OPT_Wreturn_local_addr,
+			  "address of label %qD returned",
+			  whats_returned);
       else
-	w = warning_at (loc, OPT_Wreturn_local_addr,
-			"address of local variable %qD returned",
-			whats_returned);
+	w = d.warning_at (loc, OPT_Wreturn_local_addr,
+			  "address of local variable %qD returned",
+			  whats_returned);
       if (w)
-	inform (DECL_SOURCE_LOCATION (whats_returned),
-		"declared here");
+	d.inform (DECL_SOURCE_LOCATION (whats_returned),
+		  "declared here");
       return true;
     }
 
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 7763d53..8d632db 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -315,61 +315,63 @@ abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use,
   if (!(complain & tf_error))
     return 1;
 
+  diagnostic_group d;
   if (decl)
     {
       if (VAR_P (decl))
-	error ("cannot declare variable %q+D to be of abstract "
-	       "type %qT", decl, type);
+	d.error ("cannot declare variable %q+D to be of abstract "
+		 "type %qT", decl, type);
       else if (TREE_CODE (decl) == PARM_DECL)
 	{
 	  if (DECL_NAME (decl))
-	    error ("cannot declare parameter %q+D to be of abstract type %qT",
-		   decl, type);
+	    d.error ("cannot declare parameter %q+D to be of abstract type %qT",
+		     decl, type);
 	  else
-	    error ("cannot declare parameter to be of abstract type %qT",
-		   type);
+	    d.error ("cannot declare parameter to be of abstract type %qT",
+		     type);
 	}
       else if (TREE_CODE (decl) == FIELD_DECL)
-	error ("cannot declare field %q+D to be of abstract type %qT",
-	       decl, type);
+	d.error ("cannot declare field %q+D to be of abstract type %qT",
+		 decl, type);
       else if (TREE_CODE (decl) == FUNCTION_DECL
 	       && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
-	error ("invalid abstract return type for member function %q+#D", decl);
+	d.error ("invalid abstract return type for member function %q+#D",
+		 decl);
       else if (TREE_CODE (decl) == FUNCTION_DECL)
-	error ("invalid abstract return type for function %q+#D", decl);
+	d.error ("invalid abstract return type for function %q+#D", decl);
       else if (identifier_p (decl))
 	/* Here we do not have location information.  */
-	error ("invalid abstract type %qT for %qE", type, decl);
+	d.error ("invalid abstract type %qT for %qE", type, decl);
       else
-	error ("invalid abstract type for %q+D", decl);
+	d.error ("invalid abstract type for %q+D", decl);
     }
   else switch (use)
     {
     case ACU_ARRAY:
-      error ("creating array of %qT, which is an abstract class type", type);
+      d.error ("creating array of %qT, which is an abstract class type", type);
       break;
     case ACU_CAST:
-      error ("invalid cast to abstract class type %qT", type);
+      d.error ("invalid cast to abstract class type %qT", type);
       break;
     case ACU_NEW:
-      error ("invalid new-expression of abstract class type %qT", type);
+      d.error ("invalid new-expression of abstract class type %qT", type);
       break;
     case ACU_RETURN:
-      error ("invalid abstract return type %qT", type);
+      d.error ("invalid abstract return type %qT", type);
       break;
     case ACU_PARM:
-      error ("invalid abstract parameter type %qT", type);
+      d.error ("invalid abstract parameter type %qT", type);
       break;
     case ACU_THROW:
-      error ("expression of abstract class type %qT cannot "
+      d.error ("expression of abstract class type %qT cannot "
 	     "be used in throw-expression", type);
       break;
     case ACU_CATCH:
-      error ("cannot declare catch parameter to be of abstract "
+      d.error ("cannot declare catch parameter to be of abstract "
 	     "class type %qT", type);
       break;
     default:
-      error ("cannot allocate an object of abstract type %qT", type);
+      d.error ("cannot allocate an object of abstract type %qT", type);
     }
 
   /* Only go through this once.  */
@@ -378,14 +380,15 @@ abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use,
       unsigned ix;
       tree fn;
 
-      inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)),
-	      "  because the following virtual functions are pure within %qT:",
-	      type);
+      d.inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)),
+		"  because the following virtual functions are pure within "
+		"%qT:",
+		type);
 
       FOR_EACH_VEC_ELT (*pure, ix, fn)
 	if (! DECL_CLONED_FUNCTION_P (fn)
 	    || DECL_COMPLETE_DESTRUCTOR_P (fn))
-	  inform (DECL_SOURCE_LOCATION (fn), "\t%#qD", fn);
+	  d.inform (DECL_SOURCE_LOCATION (fn), "\t%#qD", fn);
 
       /* Now truncate the vector.  This leaves it non-null, so we know
 	 there are pure virtuals, but empty so we don't list them out
@@ -975,14 +978,16 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	{
 	  if (complain & tf_warning_or_error)
 	    {
+	      diagnostic_group d;
 	      if ((!almost_ok || pedantic)
-		  && pedwarn (loc, OPT_Wnarrowing,
-			      "narrowing conversion of %qE "
-			      "from %qH to %qI inside { }",
-			      init, ftype, type)
+		  && d.pedwarn (loc, OPT_Wnarrowing,
+				"narrowing conversion of %qE "
+				"from %qH to %qI inside { }",
+				init, ftype, type)
 		  && almost_ok)
-		inform (loc, " the expression has a constant value but is not "
-			"a C++ constant-expression");
+		d.inform (loc,
+			  " the expression has a constant value but is not "
+			  "a C++ constant-expression");
 	      ok = true;
 	    }
 	}
diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h
index 79b84a7..223ecfd 100644
--- a/gcc/diagnostic-core.h
+++ b/gcc/diagnostic-core.h
@@ -65,11 +65,41 @@ class diagnostic_group
   void maybe_emit_header ();
   void emit_footer ();
 
-  bool warning_at (location_t loc, int opt, const char *gmsgid, ...)
+  bool warning (int opt, const char *, ...)
+    ATTRIBUTE_GCC_DIAG(3,4);
+
+  bool warning_at (location_t, int opt, const char *gmsgid, ...)
     ATTRIBUTE_GCC_DIAG(4,5);
+  bool warning_at (rich_location *, int opt, const char *gmsgid, ...)
+    ATTRIBUTE_GCC_DIAG(4,5);
+
+  void error (const char *, ...)
+    ATTRIBUTE_GCC_DIAG(2,3);
 
-  void inform (location_t loc, const char *gmsgid, ...)
+  void error_at (location_t, const char *, ...)
     ATTRIBUTE_GCC_DIAG(3,4);
+  void error_at (rich_location *, const char *, ...)
+    ATTRIBUTE_GCC_DIAG(3,4);
+
+  bool pedwarn (location_t, int, const char *, ...)
+    ATTRIBUTE_GCC_DIAG(4,5);
+  bool pedwarn (rich_location *, int, const char *, ...)
+    ATTRIBUTE_GCC_DIAG(4,5);
+
+  bool permerror (location_t, const char *, ...)
+    ATTRIBUTE_GCC_DIAG(3,4);
+
+  void inform (location_t, const char * ...)
+    ATTRIBUTE_GCC_DIAG(3,4);
+  void inform (rich_location *, const char *, ...)
+    ATTRIBUTE_GCC_DIAG(3,4);
+  void inform_n (location_t, unsigned HOST_WIDE_INT, const char *,
+		 const char *, ...)
+    ATTRIBUTE_GCC_DIAG(4,6) ATTRIBUTE_GCC_DIAG(5,6);
+
+  bool emit_diagnostic_valist (diagnostic_t, location_t, int, const char *,
+			       va_list *)
+    ATTRIBUTE_GCC_DIAG (5,0);
 
  private:
   bool m_emitted_header;
@@ -117,9 +147,6 @@ extern void inform_n (location_t, unsigned HOST_WIDE_INT, const char *,
 extern void verbatim (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
 extern bool emit_diagnostic (diagnostic_t, location_t, int,
 			     const char *, ...) ATTRIBUTE_GCC_DIAG(4,5);
-extern bool emit_diagnostic_valist (diagnostic_t, location_t, int, const char *,
-				    va_list *, diagnostic_group *)
-  ATTRIBUTE_GCC_DIAG (4,0);
 extern bool seen_error (void);
 
 #ifdef BUFSIZ
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 2d40845..425d3e6 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -49,12 +49,14 @@ along with GCC; see the file COPYING3.  If not see
 #define permissive_error_option(DC) ((DC)->opt_permissive)
 
 /* Prototypes.  */
-static bool diagnostic_impl (rich_location *, int, const char *,
-			     va_list *, diagnostic_t, diagnostic_group * = NULL)
-  ATTRIBUTE_GCC_DIAG(3,0);
-static bool diagnostic_n_impl (rich_location *, int, unsigned HOST_WIDE_INT,
+static bool diagnostic_impl (diagnostic_group *, rich_location *, int,
+			     const char *, va_list *, diagnostic_t)
+  ATTRIBUTE_GCC_DIAG(4,0);
+static bool diagnostic_n_impl (diagnostic_group *, rich_location *, int,
+			       unsigned HOST_WIDE_INT,
 			       const char *, const char *, va_list *,
-			       diagnostic_t) ATTRIBUTE_GCC_DIAG(5,0);
+			       diagnostic_t)
+  ATTRIBUTE_GCC_DIAG(6,0);
 
 static void error_recursion (diagnostic_context *) ATTRIBUTE_NORETURN;
 static void real_abort (void) ATTRIBUTE_NORETURN;
@@ -69,12 +71,16 @@ diagnostic_context *global_dc = &global_diagnostic_context;
 
 
 
+/* FIXME.  */
+
 diagnostic_group::~diagnostic_group ()
 {
   if (m_emitted_header)
     emit_footer ();
 }
 
+/* FIXME.  */
+
 void
 diagnostic_group::maybe_emit_header ()
 {
@@ -86,31 +92,24 @@ diagnostic_group::maybe_emit_header ()
   fprintf (stderr, "--------------------------------------------------------\n");
 }
 
+/* FIXME.  */
+
 void
 diagnostic_group::emit_footer ()
 {
   fprintf (stderr, "\n");
 }
 
-bool
-diagnostic_group::warning_at (location_t loc, int opt, const char *gmsgid, ...)
-{
-  va_list ap;
-  va_start (ap, gmsgid);
-  /* Pass in "this", so that we can group things.  */
-  bool ret = emit_diagnostic_valist (DK_WARNING, loc, opt, gmsgid, &ap, this);
-  va_end (ap);
-  return ret;
-}
+/* FIXME.  */
 
-void
-diagnostic_group::inform (location_t loc, const char *gmsgid, ...)
+bool
+diagnostic_group::emit_diagnostic_valist (diagnostic_t kind,
+					  location_t location, int opt,
+					  const char *gmsgid, va_list *ap)
 {
-  va_list ap;
-  va_start (ap, gmsgid);
+  rich_location richloc (line_table, location);
   /* Pass in "this", so that we can group things.  */
-  emit_diagnostic_valist (DK_NOTE, loc, -1, gmsgid, &ap, this);
-  va_end (ap);
+  return diagnostic_impl (this, &richloc, opt, gmsgid, ap, kind);
 }
 
 
@@ -1209,11 +1208,13 @@ diagnostic_append_note (diagnostic_context *context,
    permerror, error, error_at, error_at, sorry, fatal_error, internal_error,
    and internal_error_no_backtrace, as documented and defined below.  */
 static bool
-diagnostic_impl (rich_location *richloc, int opt,
+diagnostic_impl (diagnostic_group *group,
+		 rich_location *richloc, int opt,
 		 const char *gmsgid,
-		 va_list *ap, diagnostic_t kind,
-		 diagnostic_group *group)
+		 va_list *ap, diagnostic_t kind)
 {
+  gcc_assert (group);
+
   diagnostic_info diagnostic;
   if (kind == DK_PERMERROR)
     {
@@ -1234,11 +1235,14 @@ diagnostic_impl (rich_location *richloc, int opt,
 /* Implement inform_n, warning_n, and error_n, as documented and
    defined below.  */
 static bool
-diagnostic_n_impl (rich_location *richloc, int opt, unsigned HOST_WIDE_INT n,
+diagnostic_n_impl (diagnostic_group *group,rich_location *richloc, int opt,
+		   unsigned HOST_WIDE_INT n,
 		   const char *singular_gmsgid,
 		   const char *plural_gmsgid,
 		   va_list *ap, diagnostic_t kind)
 {
+  gcc_assert (group);
+
   diagnostic_info diagnostic;
   unsigned long gtn;
 
@@ -1254,6 +1258,7 @@ diagnostic_n_impl (rich_location *richloc, int opt, unsigned HOST_WIDE_INT n,
   diagnostic_set_info_translated (&diagnostic, text, ap, richloc, kind);
   if (kind == DK_WARNING)
     diagnostic.option_index = opt;
+  diagnostic.group = group;
   return diagnostic_report_diagnostic (global_dc, &diagnostic);
 }
 
@@ -1263,34 +1268,37 @@ bool
 emit_diagnostic (diagnostic_t kind, location_t location, int opt,
 		 const char *gmsgid, ...)
 {
+  diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, location);
-  bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap, kind);
+  bool ret = diagnostic_impl (&d, &richloc, opt, gmsgid, &ap, kind);
   va_end (ap);
   return ret;
 }
 
-/* Wrapper around diagnostic_impl taking a va_list parameter.  */
-
-bool
-emit_diagnostic_valist (diagnostic_t kind, location_t location, int opt,
-			const char *gmsgid, va_list *ap,
-			diagnostic_group *group)
+/* An informative note at LOCATION.  Use this for additional details on an error
+   message.  */
+void
+inform (location_t location, const char *gmsgid, ...)
 {
+  diagnostic_group d;
+  va_list ap;
+  va_start (ap, gmsgid);
   rich_location richloc (line_table, location);
-  return diagnostic_impl (&richloc, opt, gmsgid, ap, kind, group);
+  diagnostic_impl (&d, &richloc, -1, gmsgid, &ap, DK_NOTE);
+  va_end (ap);
 }
 
-/* An informative note at LOCATION.  Use this for additional details on an error
-   message.  */
+/* As above, but within a specific diagnostic_group.  */
+
 void
-inform (location_t location, const char *gmsgid, ...)
+diagnostic_group::inform (location_t location, const char *gmsgid, ...)
 {
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, location);
-  diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_NOTE);
+  diagnostic_impl (this, &richloc, -1, gmsgid, &ap, DK_NOTE);
   va_end (ap);
 }
 
@@ -1300,9 +1308,23 @@ inform (rich_location *richloc, const char *gmsgid, ...)
 {
   gcc_assert (richloc);
 
+  diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
-  diagnostic_impl (richloc, -1, gmsgid, &ap, DK_NOTE);
+  diagnostic_impl (&d, richloc, -1, gmsgid, &ap, DK_NOTE);
+  va_end (ap);
+}
+
+/* As above, but within a specific diagnostic_group.  */
+
+void
+diagnostic_group::inform (rich_location *richloc, const char *gmsgid, ...)
+{
+  gcc_assert (richloc);
+
+  va_list ap;
+  va_start (ap, gmsgid);
+  diagnostic_impl (this, richloc, -1, gmsgid, &ap, DK_NOTE);
   va_end (ap);
 }
 
@@ -1314,8 +1336,23 @@ inform_n (location_t location, unsigned HOST_WIDE_INT n,
 {
   va_list ap;
   va_start (ap, plural_gmsgid);
+  diagnostic_group d;
   rich_location richloc (line_table, location);
-  diagnostic_n_impl (&richloc, -1, n, singular_gmsgid, plural_gmsgid,
+  diagnostic_n_impl (&d, &richloc, -1, n, singular_gmsgid, plural_gmsgid,
+		     &ap, DK_NOTE);
+  va_end (ap);
+}
+
+/* As above, but within a specific diagnostic_group.  */
+void
+diagnostic_group::inform_n (location_t location, unsigned HOST_WIDE_INT n,
+			    const char *singular_gmsgid,
+			    const char *plural_gmsgid, ...)
+{
+  va_list ap;
+  va_start (ap, plural_gmsgid);
+  rich_location richloc (line_table, location);
+  diagnostic_n_impl (this, &richloc, -1, n, singular_gmsgid, plural_gmsgid,
 		     &ap, DK_NOTE);
   va_end (ap);
 }
@@ -1323,74 +1360,124 @@ inform_n (location_t location, unsigned HOST_WIDE_INT n,
 /* A warning at INPUT_LOCATION.  Use this for code which is correct according
    to the relevant language specification but is likely to be buggy anyway.
    Returns true if the warning was printed, false if it was inhibited.  */
-void
+bool
 warning (int opt, const char *gmsgid, ...)
 {
+  diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, input_location);
-  diagnostic_impl (&richloc, opt, gmsgid, &ap, DK_WARNING);
+  bool ret = diagnostic_impl (&d, &richloc, opt, gmsgid, &ap, DK_WARNING);
+  va_end (ap);
+  return ret;
+}
+
+/* As above, but within a specific diagnostic_group.  */
+bool
+diagnostic_group::warning (int opt, const char *gmsgid, ...)
+{
+  rich_location richloc (line_table, input_location);
+  va_list ap;
+  va_start (ap, gmsgid);
+  bool ret = diagnostic_impl (this, &richloc, opt, gmsgid, &ap, DK_WARNING);
   va_end (ap);
+  return ret;
 }
 
 /* A warning at LOCATION.  Use this for code which is correct according to the
    relevant language specification but is likely to be buggy anyway.
    Returns true if the warning was printed, false if it was inhibited.  */
 
-void
+bool
 warning_at (location_t location, int opt, const char *gmsgid, ...)
 {
+  diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, location);
-  diagnostic_impl (&richloc, opt, gmsgid, &ap, DK_WARNING);
+  bool ret = diagnostic_impl (&d, &richloc, opt, gmsgid, &ap, DK_WARNING);
   va_end (ap);
+  return ret;
 }
 
 /* Same as "warning at" above, but using RICHLOC.  */
 
-void
+bool
 warning_at (rich_location *richloc, int opt, const char *gmsgid, ...)
 {
   gcc_assert (richloc);
 
+  diagnostic_group d;
+  va_list ap;
+  va_start (ap, gmsgid);
+  bool ret = diagnostic_impl (&d, richloc, opt, gmsgid, &ap, DK_WARNING);
+  va_end (ap);
+  return ret;
+}
+
+/* As above, but within a specific diagnostic_group.  */
+
+bool
+diagnostic_group::warning_at (location_t loc, int opt, const char *gmsgid, ...)
+{
+  rich_location richloc (line_table, loc);
+  va_list ap;
+  va_start (ap, gmsgid);
+  bool ret = diagnostic_impl (this, &richloc, opt, gmsgid, &ap, DK_WARNING);
+  va_end (ap);
+  return ret;
+}
+
+/* Same as "warning at" above, but using RICHLOC.  */
+
+bool
+diagnostic_group::warning_at (rich_location *richloc, int opt,
+			      const char *gmsgid, ...)
+{
+  gcc_assert (richloc);
+
   va_list ap;
   va_start (ap, gmsgid);
-  diagnostic_impl (richloc, opt, gmsgid, &ap, DK_WARNING);
+  bool ret = diagnostic_impl (this, richloc, opt, gmsgid, &ap, DK_WARNING);
   va_end (ap);
+  return ret;
 }
 
 /* Same as warning_n plural variant below, but using RICHLOC.  */
 
-void
+bool
 warning_n (rich_location *richloc, int opt, unsigned HOST_WIDE_INT n,
 	   const char *singular_gmsgid, const char *plural_gmsgid, ...)
 {
   gcc_assert (richloc);
 
+  diagnostic_group d;
   va_list ap;
   va_start (ap, plural_gmsgid);
-  diagnostic_n_impl (richloc, opt, n,
-		     singular_gmsgid, plural_gmsgid,
-		     &ap, DK_WARNING);
+  bool ret = diagnostic_n_impl (&d, richloc, opt, n,
+				singular_gmsgid, plural_gmsgid,
+				&ap, DK_WARNING);
   va_end (ap);
+  return ret;
 }
 
 /* A warning at LOCATION.  Use this for code which is correct according to the
    relevant language specification but is likely to be buggy anyway.
    Returns true if the warning was printed, false if it was inhibited.  */
 
-void
+bool
 warning_n (location_t location, int opt, unsigned HOST_WIDE_INT n,
 	   const char *singular_gmsgid, const char *plural_gmsgid, ...)
 {
+  diagnostic_group d;
   va_list ap;
   va_start (ap, plural_gmsgid);
   rich_location richloc (line_table, location);
-  diagnostic_n_impl (&richloc, opt, n,
-		     singular_gmsgid, plural_gmsgid,
-		     &ap, DK_WARNING);
+  bool ret = diagnostic_n_impl (&d, &richloc, opt, n,
+				singular_gmsgid, plural_gmsgid,
+				&ap, DK_WARNING);
   va_end (ap);
+  return ret;
 }
 
 /* A "pedantic" warning at LOCATION: issues a warning unless
@@ -1406,27 +1493,60 @@ warning_n (location_t location, int opt, unsigned HOST_WIDE_INT n,
 
    Returns true if the warning was printed, false if it was inhibited.  */
 
-void
+bool
 pedwarn (location_t location, int opt, const char *gmsgid, ...)
 {
+  diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, location);
-  diagnostic_impl (&richloc, opt, gmsgid, &ap, DK_PEDWARN);
+  bool ret = diagnostic_impl (&d, &richloc, opt, gmsgid, &ap, DK_PEDWARN);
   va_end (ap);
+  return ret;
+}
+
+/* As above, but within a specific diagnostic_group.  */
+
+bool
+diagnostic_group::pedwarn (location_t location, int opt, const char *gmsgid,
+			   ...)
+{
+  va_list ap;
+  va_start (ap, gmsgid);
+  rich_location richloc (line_table, location);
+  bool ret = diagnostic_impl (this, &richloc, opt, gmsgid, &ap, DK_PEDWARN);
+  va_end (ap);
+  return ret;
 }
 
 /* Same as pedwarn above, but using RICHLOC.  */
 
-void
+bool
 pedwarn (rich_location *richloc, int opt, const char *gmsgid, ...)
 {
   gcc_assert (richloc);
 
+  diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
-  diagnostic_impl (richloc, opt, gmsgid, &ap, DK_PEDWARN);
+  bool ret = diagnostic_impl (&d, richloc, opt, gmsgid, &ap, DK_PEDWARN);
   va_end (ap);
+  return ret;
+}
+
+/* As above, but within a specific diagnostic_group.  */
+
+bool
+diagnostic_group::pedwarn (rich_location *richloc, int opt, const char *gmsgid,
+			   ...)
+{
+  gcc_assert (richloc);
+
+  va_list ap;
+  va_start (ap, gmsgid);
+  bool ret = diagnostic_impl (this, richloc, opt, gmsgid, &ap, DK_PEDWARN);
+  va_end (ap);
+  return ret;
 }
 
 /* A "permissive" error at LOCATION: issues an error unless
@@ -1436,27 +1556,44 @@ pedwarn (rich_location *richloc, int opt, const char *gmsgid, ...)
 
    Returns true if the warning was printed, false if it was inhibited.  */
 
-void
+bool
 permerror (location_t location, const char *gmsgid, ...)
 {
+  diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, location);
-  diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_PERMERROR);
+  bool ret = diagnostic_impl (&d, &richloc, -1, gmsgid, &ap, DK_PERMERROR);
   va_end (ap);
+  return ret;
+}
+
+/* As above, but within a specific diagnostic_group.  */
+
+bool
+diagnostic_group::permerror (location_t location, const char *gmsgid, ...)
+{
+  va_list ap;
+  va_start (ap, gmsgid);
+  rich_location richloc (line_table, location);
+  bool ret = diagnostic_impl (this, &richloc, -1, gmsgid, &ap, DK_PERMERROR);
+  va_end (ap);
+  return ret;
 }
 
 /* Same as "permerror" above, but at RICHLOC.  */
 
-void
+bool
 permerror (rich_location *richloc, const char *gmsgid, ...)
 {
   gcc_assert (richloc);
 
+  diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
-  diagnostic_impl (richloc, -1, gmsgid, &ap, DK_PERMERROR);
+  bool ret = diagnostic_impl (&d, richloc, -1, gmsgid, &ap, DK_PERMERROR);
   va_end (ap);
+  return ret;
 }
 
 /* A hard error: the code is definitely ill-formed, and an object file
@@ -1464,10 +1601,22 @@ permerror (rich_location *richloc, const char *gmsgid, ...)
 void
 error (const char *gmsgid, ...)
 {
+  diagnostic_group d;
+  va_list ap;
+  va_start (ap, gmsgid);
+  rich_location richloc (line_table, input_location);
+  diagnostic_impl (&d, &richloc, -1, gmsgid, &ap, DK_ERROR);
+  va_end (ap);
+}
+
+/* As above, but within a specific diagnostic_group.  */
+void
+diagnostic_group::error (const char *gmsgid, ...)
+{
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, input_location);
-  diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ERROR);
+  diagnostic_impl (this, &richloc, -1, gmsgid, &ap, DK_ERROR);
   va_end (ap);
 }
 
@@ -1477,10 +1626,11 @@ void
 error_n (location_t location, unsigned HOST_WIDE_INT n,
 	 const char *singular_gmsgid, const char *plural_gmsgid, ...)
 {
+  diagnostic_group d;
   va_list ap;
   va_start (ap, plural_gmsgid);
   rich_location richloc (line_table, location);
-  diagnostic_n_impl (&richloc, -1, n, singular_gmsgid, plural_gmsgid,
+  diagnostic_n_impl (&d, &richloc, -1, n, singular_gmsgid, plural_gmsgid,
 		     &ap, DK_ERROR);
   va_end (ap);
 }
@@ -1489,10 +1639,23 @@ error_n (location_t location, unsigned HOST_WIDE_INT n,
 void
 error_at (location_t loc, const char *gmsgid, ...)
 {
+  diagnostic_group d;
+  va_list ap;
+  va_start (ap, gmsgid);
+  rich_location richloc (line_table, loc);
+  diagnostic_impl (&d, &richloc, -1, gmsgid, &ap, DK_ERROR);
+  va_end (ap);
+}
+
+/* As above, but within a specific diagnostic_group.  */
+
+void
+diagnostic_group::error_at (location_t loc, const char *gmsgid, ...)
+{
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, loc);
-  diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ERROR);
+  diagnostic_impl (this, &richloc, -1, gmsgid, &ap, DK_ERROR);
   va_end (ap);
 }
 
@@ -1503,9 +1666,23 @@ error_at (rich_location *richloc, const char *gmsgid, ...)
 {
   gcc_assert (richloc);
 
+  diagnostic_group d;
+  va_list ap;
+  va_start (ap, gmsgid);
+  diagnostic_impl (&d, richloc, -1, gmsgid, &ap, DK_ERROR);
+  va_end (ap);
+}
+
+/* As above, but within a specific diagnostic_group.  */
+
+void
+diagnostic_group::error_at (rich_location *richloc, const char *gmsgid, ...)
+{
+  gcc_assert (richloc);
+
   va_list ap;
   va_start (ap, gmsgid);
-  diagnostic_impl (richloc, -1, gmsgid, &ap, DK_ERROR);
+  diagnostic_impl (this, richloc, -1, gmsgid, &ap, DK_ERROR);
   va_end (ap);
 }
 
@@ -1515,10 +1692,11 @@ error_at (rich_location *richloc, const char *gmsgid, ...)
 void
 sorry (const char *gmsgid, ...)
 {
+  diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, input_location);
-  diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_SORRY);
+  diagnostic_impl (&d, &richloc, -1, gmsgid, &ap, DK_SORRY);
   va_end (ap);
 }
 
@@ -1536,10 +1714,11 @@ seen_error (void)
 void
 fatal_error (location_t loc, const char *gmsgid, ...)
 {
+  diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, loc);
-  diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_FATAL);
+  diagnostic_impl (&d, &richloc, -1, gmsgid, &ap, DK_FATAL);
   va_end (ap);
 
   gcc_unreachable ();
@@ -1552,10 +1731,11 @@ fatal_error (location_t loc, const char *gmsgid, ...)
 void
 internal_error (const char *gmsgid, ...)
 {
+  diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, input_location);
-  diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ICE);
+  diagnostic_impl (&d, &richloc, -1, gmsgid, &ap, DK_ICE);
   va_end (ap);
 
   gcc_unreachable ();
@@ -1567,10 +1747,11 @@ internal_error (const char *gmsgid, ...)
 void
 internal_error_no_backtrace (const char *gmsgid, ...)
 {
+  diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, input_location);
-  diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ICE_NOBT);
+  diagnostic_impl (&d, &richloc, -1, gmsgid, &ap, DK_ICE_NOBT);
   va_end (ap);
 
   gcc_unreachable ();
diff --git a/gcc/gimple-ssa-isolate-paths.c b/gcc/gimple-ssa-isolate-paths.c
index 131705d..0557aff 100644
--- a/gcc/gimple-ssa-isolate-paths.c
+++ b/gcc/gimple-ssa-isolate-paths.c
@@ -421,12 +421,15 @@ find_implicit_erroneous_behavior (void)
 			  if (gimple_return_retval (return_stmt) != lhs)
 			    continue;
 
-			  if (warning_at (gimple_location (use_stmt),
-					  OPT_Wreturn_local_addr,
-					  "function may return address "
-					  "of local variable"))
-			    inform (DECL_SOURCE_LOCATION(valbase),
-				    "declared here");
+			  {
+			    diagnostic_group d;
+			    if (d.warning_at (gimple_location (use_stmt),
+					      OPT_Wreturn_local_addr,
+					      "function may return address "
+					      "of local variable"))
+			      d.inform (DECL_SOURCE_LOCATION(valbase),
+					"declared here");
+			  }
 
 			  if (gimple_bb (use_stmt) == bb)
 			    {
@@ -534,19 +537,23 @@ find_explicit_erroneous_behavior (void)
 		    {
 		      /* We only need it for this particular case.  */
 		      calculate_dominance_info (CDI_POST_DOMINATORS);
-		      const char* msg;
-		      bool always_executed = dominated_by_p
-			(CDI_POST_DOMINATORS,
-			 single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)), bb);
-		      if (always_executed)
-			msg = N_("function returns address of local variable");
-		      else
-			msg = N_("function may return address of "
-				 "local variable");
-
-		      if (warning_at (gimple_location (stmt),
-				      OPT_Wreturn_local_addr, msg))
-			inform (DECL_SOURCE_LOCATION(valbase), "declared here");
+		      {
+			diagnostic_group d;
+			const char* msg;
+			bool always_executed = dominated_by_p
+			  (CDI_POST_DOMINATORS,
+			   single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)), bb);
+			if (always_executed)
+			  msg = N_("function returns address of "
+				   "local variable");
+			else
+			  msg = N_("function may return address of "
+				   "local variable");
+			if (d.warning_at (gimple_location (stmt),
+					  OPT_Wreturn_local_addr, msg))
+			  d.inform (DECL_SOURCE_LOCATION(valbase),
+				    "declared here");
+		      }
 		      tree zero = build_zero_cst (TREE_TYPE (val));
 		      gimple_return_set_retval (return_stmt, zero);
 		      update_stmt (stmt);
diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
index 0331f66..5e3b6bf 100644
--- a/gcc/gimple-ssa-warn-alloca.c
+++ b/gcc/gimple-ssa-warn-alloca.c
@@ -532,29 +532,37 @@ pass_walloca::execute (function *fun)
 	    case ALLOCA_OK:
 	      break;
 	    case ALLOCA_BOUND_MAYBE_LARGE:
-	      if (warning_at (loc, wcode,
-			      is_vla ? G_("argument to variable-length array "
-					  "may be too large")
-			      : G_("argument to %<alloca%> may be too large"))
-		  && t.limit != 0)
-		{
-		  print_decu (t.limit, buff);
-		  inform (loc, G_("limit is %wu bytes, but argument "
-				  "may be as large as %s"),
-			  is_vla ? warn_vla_limit : warn_alloca_limit, buff);
-		}
+	      {
+		diagnostic_group d;
+		if (d.warning_at (loc, wcode,
+				  is_vla ? G_("argument to variable-length "
+					      "array may be too large")
+				  : G_("argument to %<alloca%> may be too "
+				       "large"))
+		    && t.limit != 0)
+		  {
+		    print_decu (t.limit, buff);
+		    d.inform (loc, G_("limit is %wu bytes, but argument "
+				    "may be as large as %s"),
+			    is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+		  }
+	      }
 	      break;
 	    case ALLOCA_BOUND_DEFINITELY_LARGE:
-	      if (warning_at (loc, wcode,
-			      is_vla ? G_("argument to variable-length array "
-					  "is too large")
-			      : G_("argument to %<alloca%> is too large"))
-		  && t.limit != 0)
-		{
-		  print_decu (t.limit, buff);
-		  inform (loc, G_("limit is %wu bytes, but argument is %s"),
-			  is_vla ? warn_vla_limit : warn_alloca_limit, buff);
-		}
+	      {
+		diagnostic_group d;
+		if (d.warning_at (loc, wcode,
+				  is_vla ? G_("argument to variable-length"
+					      " array is too large")
+				  : G_("argument to %<alloca%> is too large"))
+		    && t.limit != 0)
+		  {
+		    print_decu (t.limit, buff);
+		    d.inform (loc, G_("limit is %wu bytes, but argument is %s"),
+			      is_vla ? warn_vla_limit : warn_alloca_limit,
+			      buff);
+		  }
+	      }
 	      break;
 	    case ALLOCA_BOUND_UNKNOWN:
 	      warning_at (loc, wcode,
diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
index 01503d6..eb4e344 100644
--- a/gcc/gimple-ssa-warn-restrict.c
+++ b/gcc/gimple-ssa-warn-restrict.c
@@ -1618,13 +1618,15 @@ maybe_diag_offset_bounds (location_t loc, gimple *call, tree func, int strict,
       if (DECL_P (ref.base)
 	  && TREE_CODE (type = TREE_TYPE (ref.base)) == ARRAY_TYPE)
 	{
-	  if (warning_at (loc, OPT_Warray_bounds,
-			  "%G%qD pointer overflow between offset %s "
-			  "and size %s accessing array %qD with type %qT",
-			  call, func, rangestr[0], rangestr[1], ref.base, type))
+	  diagnostic_group d;
+	  if (d.warning_at (loc, OPT_Warray_bounds,
+			    "%G%qD pointer overflow between offset %s "
+			    "and size %s accessing array %qD with type %qT",
+			    call, func, rangestr[0], rangestr[1], ref.base,
+			    type))
 	    {
-	      inform (DECL_SOURCE_LOCATION (ref.base),
-		      "array %qD declared here", ref.base);
+	      d.inform (DECL_SOURCE_LOCATION (ref.base),
+			"array %qD declared here", ref.base);
 	      warned = true;
 	    }
 	  else
@@ -1650,27 +1652,29 @@ maybe_diag_offset_bounds (location_t loc, gimple *call, tree func, int strict,
 
       if (DECL_P (ref.base))
 	{
+	  diagnostic_group d;
 	  if ((ref.basesize < maxobjsize
-	       && warning_at (loc, OPT_Warray_bounds,
-			      form
-			      ? G_("%G%qD forming offset %s is out of "
-				   "the bounds [0, %wu] of object %qD with "
-				   "type %qT")
-			      : G_("%G%qD offset %s is out of the bounds "
-				   "[0, %wu] of object %qD with type %qT"),
-			      call, func, rangestr[0], ref.basesize.to_uhwi (),
-			      ref.base, TREE_TYPE (ref.base)))
-	      || warning_at (loc, OPT_Warray_bounds,
-			     form
-			     ? G_("%G%qD forming offset %s is out of "
-				  "the bounds of object %qD with type %qT")
-			     : G_("%G%qD offset %s is out of the bounds "
-				  "of object %qD with type %qT"),
-			     call, func, rangestr[0],
-			     ref.base, TREE_TYPE (ref.base)))
+	       && d.warning_at (loc, OPT_Warray_bounds,
+				form
+				? G_("%G%qD forming offset %s is out of "
+				     "the bounds [0, %wu] of object %qD with "
+				     "type %qT")
+				: G_("%G%qD offset %s is out of the bounds "
+				     "[0, %wu] of object %qD with type %qT"),
+				call, func, rangestr[0],
+				ref.basesize.to_uhwi (),
+				ref.base, TREE_TYPE (ref.base)))
+	      || d.warning_at (loc, OPT_Warray_bounds,
+			       form
+			       ? G_("%G%qD forming offset %s is out of "
+				    "the bounds of object %qD with type %qT")
+			       : G_("%G%qD offset %s is out of the bounds "
+				    "of object %qD with type %qT"),
+			       call, func, rangestr[0],
+			       ref.base, TREE_TYPE (ref.base)))
 	    {
-	      inform (DECL_SOURCE_LOCATION (ref.base),
-		      "%qD declared here", ref.base);
+	      d.inform (DECL_SOURCE_LOCATION (ref.base),
+			"%qD declared here", ref.base);
 	      warned = true;
 	    }
 	}
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 4a109ae..155155c 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -2173,23 +2173,24 @@ warn_implicit_fallthrough_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
 	  {
 	    struct label_entry *l;
 	    bool warned_p = false;
+	    diagnostic_group d;
 	    if (!should_warn_for_implicit_fallthrough (gsi_p, label))
 	      /* Quiet.  */;
 	    else if (gimple_code (prev) == GIMPLE_LABEL
 		     && (label = gimple_label_label (as_a <glabel *> (prev)))
 		     && (l = find_label_entry (&labels, label)))
-	      warned_p = warning_at (l->loc, OPT_Wimplicit_fallthrough_,
-				     "this statement may fall through");
+	      warned_p = d.warning_at (l->loc, OPT_Wimplicit_fallthrough_,
+				       "this statement may fall through");
 	    else if (!gimple_call_internal_p (prev, IFN_FALLTHROUGH)
 		     /* Try to be clever and don't warn when the statement
 			can't actually fall through.  */
 		     && gimple_stmt_may_fallthru (prev)
 		     && gimple_has_location (prev))
-	      warned_p = warning_at (gimple_location (prev),
-				     OPT_Wimplicit_fallthrough_,
-				     "this statement may fall through");
+	      warned_p = d.warning_at (gimple_location (prev),
+				       OPT_Wimplicit_fallthrough_,
+				       "this statement may fall through");
 	    if (warned_p)
-	      inform (gimple_location (next), "here");
+	      d.inform (gimple_location (next), "here");
 
 	    /* Mark this label as processed so as to prevent multiple
 	       warnings in nested switches.  */
@@ -13079,20 +13080,22 @@ gimplify_va_arg_expr (tree *expr_p, gimple_seq *pre_p,
       /* Unfortunately, this is merely undefined, rather than a constraint
 	 violation, so we cannot make this an error.  If this call is never
 	 executed, the program is still strictly conforming.  */
-      warned = warning_at (xloc, 0,
-			   "%qT is promoted to %qT when passed through %<...%>",
-			   type, promoted_type);
+      diagnostic_group d;
+      warned
+	= d.warning_at (xloc, 0,
+			"%qT is promoted to %qT when passed through %<...%>",
+			type, promoted_type);
       if (!gave_help && warned)
 	{
 	  gave_help = true;
-	  inform (xloc, "(so you should pass %qT not %qT to %<va_arg%>)",
-		  promoted_type, type);
+	  d.inform (xloc, "(so you should pass %qT not %qT to %<va_arg%>)",
+		    promoted_type, type);
 	}
 
       /* We can, however, treat "undefined" any way we please.
 	 Call abort to encourage the user to fix the program.  */
       if (warned)
-	inform (xloc, "if this code is reached, the program will abort");
+	d.inform (xloc, "if this code is reached, the program will abort");
       /* Before the abort, allow the evaluation of the va_list
 	 expression to exit or longjmp.  */
       gimplify_and_add (valist, pre_p);
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 173707d..095eab3 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -69,9 +69,10 @@ along with GCC; see the file COPYING3.  If not see
   do \
   { \
     hsa_fail_cfun (); \
-    if (warning_at (EXPR_LOCATION (hsa_cfun->m_decl), OPT_Whsa, \
+    diagnostic_group d; \
+    if (d.warning_at (EXPR_LOCATION (hsa_cfun->m_decl), OPT_Whsa,	\
 		    HSA_SORRY_MSG)) \
-      inform (location, message, __VA_ARGS__); \
+      d.inform (location, message, __VA_ARGS__); \
   } \
   while (false)
 
@@ -81,9 +82,10 @@ along with GCC; see the file COPYING3.  If not see
   do \
   { \
     hsa_fail_cfun (); \
-    if (warning_at (EXPR_LOCATION (hsa_cfun->m_decl), OPT_Whsa, \
+    diagnostic_group d; \
+    if (d.warning_at (EXPR_LOCATION (hsa_cfun->m_decl), OPT_Whsa, \
 		    HSA_SORRY_MSG)) \
-      inform (location, message); \
+      d.inform (location, message); \
   } \
   while (false)
 
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index e99d8cc..677a875 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -749,14 +749,16 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
 	  prevailing = vtable;
 	  vtable = tmp;
 	}
-      if (warning_at (DECL_SOURCE_LOCATION
-			(TYPE_NAME (DECL_CONTEXT (vtable->decl))),
-		      OPT_Wodr,
-		      "virtual table of type %qD violates one definition rule",
-		      DECL_CONTEXT (vtable->decl)))
-	inform (DECL_SOURCE_LOCATION (prevailing->decl),
-		"variable of same assembler name as the virtual table is "
-		"defined in another translation unit");
+      diagnostic_group d;
+      if (d.warning_at (DECL_SOURCE_LOCATION
+			  (TYPE_NAME (DECL_CONTEXT (vtable->decl))),
+			OPT_Wodr,
+			"virtual table of type %qD violates one definition"
+			" rule",
+			DECL_CONTEXT (vtable->decl)))
+	d.inform (DECL_SOURCE_LOCATION (prevailing->decl),
+		  "variable of same assembler name as the virtual table is "
+		  "defined in another translation unit");
       return;
     }
   if (!prevailing->definition || !vtable->definition)
@@ -790,22 +792,25 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
 	             && TREE_CODE (ref1->referred->decl) == FUNCTION_DECL))
 	     && TREE_CODE (ref2->referred->decl) != FUNCTION_DECL)
 	{
-	  if (!class_type->rtti_broken
-	      && warning_at (DECL_SOURCE_LOCATION
-			      (TYPE_NAME (DECL_CONTEXT (vtable->decl))),
-			     OPT_Wodr,
-			     "virtual table of type %qD contains RTTI "
-			     "information",
-			     DECL_CONTEXT (vtable->decl)))
+	  if (!class_type->rtti_broken)
 	    {
-	      inform (DECL_SOURCE_LOCATION
-			(TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
-		      "but is prevailed by one without from other translation "
-		      "unit");
-	      inform (DECL_SOURCE_LOCATION
-			(TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
-		      "RTTI will not work on this type");
-	      class_type->rtti_broken = true;
+	      diagnostic_group d;
+	      if (d.warning_at (DECL_SOURCE_LOCATION
+				  (TYPE_NAME (DECL_CONTEXT (vtable->decl))),
+				OPT_Wodr,
+				"virtual table of type %qD contains RTTI "
+				"information",
+				DECL_CONTEXT (vtable->decl)))
+		{
+		  d.inform (DECL_SOURCE_LOCATION
+			      (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
+			    "but is prevailed by one without from other"
+			    " translation unit");
+		  d.inform (DECL_SOURCE_LOCATION
+			      (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
+			    "RTTI will not work on this type");
+		  class_type->rtti_broken = true;
+		}
 	    }
 	  n2++;
           end2 = !vtable->iterate_reference (n2, ref2);
@@ -831,17 +836,19 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
 	  if (DECL_SIZE (prevailing->decl) != DECL_SIZE (vtable->decl))
 	    {
 	      class_type->odr_violated = true;
-	      if (warning_at (DECL_SOURCE_LOCATION
-				(TYPE_NAME (DECL_CONTEXT (vtable->decl))),
-			      OPT_Wodr,
-			      "virtual table of type %qD violates "
-			      "one definition rule  ",
-			      DECL_CONTEXT (vtable->decl)))
+	      diagnostic_group d;
+	      if (d.warning_at (DECL_SOURCE_LOCATION
+				  (TYPE_NAME (DECL_CONTEXT (vtable->decl))),
+				OPT_Wodr,
+				"virtual table of type %qD violates "
+				"one definition rule  ",
+				DECL_CONTEXT (vtable->decl)))
 		{
-		  inform (DECL_SOURCE_LOCATION
-			    (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
-			  "the conflicting type defined in another translation "
-			  "unit has virtual table of different size");
+		  d.inform (DECL_SOURCE_LOCATION
+			      (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
+			    "the conflicting type defined in another "
+			    "translation unit has virtual table of different"
+			    " size");
 		}
 	    }
 	  return;
@@ -859,17 +866,18 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
 	  if (TREE_CODE (ref1->referred->decl) != FUNCTION_DECL
 	      && TREE_CODE (ref2->referred->decl) != FUNCTION_DECL)
 	    {
-	      if (warning_at (DECL_SOURCE_LOCATION
-				(TYPE_NAME (DECL_CONTEXT (vtable->decl))),
-			      OPT_Wodr,
-			      "virtual table of type %qD violates "
-			      "one definition rule  ",
-			      DECL_CONTEXT (vtable->decl)))
+	      diagnostic_group d;
+	      if (d.warning_at (DECL_SOURCE_LOCATION
+				  (TYPE_NAME (DECL_CONTEXT (vtable->decl))),
+				OPT_Wodr,
+				"virtual table of type %qD violates "
+				"one definition rule  ",
+				DECL_CONTEXT (vtable->decl)))
 		{
-		  inform (DECL_SOURCE_LOCATION
-			    (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
-			  "the conflicting type defined in another translation "
-			  "unit with different RTTI information");
+		  d.inform (DECL_SOURCE_LOCATION
+			      (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
+			    "the conflicting type defined in another "
+			    "translation unit with different RTTI information");
 		}
 	      return;
 	    }
@@ -900,30 +908,32 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
 	      vtable = tmp;
 	      ref1 = ref2;
 	    }
-	  if (warning_at (DECL_SOURCE_LOCATION
+	  diagnostic_group d;
+	  if (d.warning_at (DECL_SOURCE_LOCATION
 			    (TYPE_NAME (DECL_CONTEXT (vtable->decl))),
-			  OPT_Wodr,
-			  "virtual table of type %qD violates "
-			  "one definition rule",
-			  DECL_CONTEXT (vtable->decl)))
+			    OPT_Wodr,
+			    "virtual table of type %qD violates "
+			    "one definition rule",
+			    DECL_CONTEXT (vtable->decl)))
 	    {
 	      if (TREE_CODE (ref1->referring->decl) == FUNCTION_DECL)
 		{
-		  inform (DECL_SOURCE_LOCATION
-			   (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
-			  "the conflicting type defined in another translation "
-			  "unit");
-		  inform (DECL_SOURCE_LOCATION
+		  d.inform (DECL_SOURCE_LOCATION
+			    (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
+			    "the conflicting type defined in another "
+			    "translation unit");
+		  d.inform (DECL_SOURCE_LOCATION
 			    (TYPE_NAME (DECL_CONTEXT (ref1->referring->decl))),
-			  "contains additional virtual method %qD",
-			  ref1->referred->decl);
+			    "contains additional virtual method %qD",
+			    ref1->referred->decl);
 		}
 	      else
 		{
-		  inform (DECL_SOURCE_LOCATION
-			   (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
-			  "the conflicting type defined in another translation "
-			  "unit has virtual table with more entries");
+		  d.inform (DECL_SOURCE_LOCATION
+			    (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
+			    "the conflicting type defined in another "
+			    "translation unit has virtual table with more "
+			    "entries");
 		}
 	    }
 	  return;
@@ -931,34 +941,35 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
 
       /* And in the last case we have either mistmatch in between two virtual
 	 methods or two virtual table pointers.  */
-      if (warning_at (DECL_SOURCE_LOCATION
+      diagnostic_group d;
+      if (d.warning_at (DECL_SOURCE_LOCATION
 			(TYPE_NAME (DECL_CONTEXT (vtable->decl))), OPT_Wodr,
-		      "virtual table of type %qD violates "
-		      "one definition rule  ",
-		      DECL_CONTEXT (vtable->decl)))
+			"virtual table of type %qD violates "
+			"one definition rule  ",
+			DECL_CONTEXT (vtable->decl)))
 	{
 	  if (TREE_CODE (ref1->referred->decl) == FUNCTION_DECL)
 	    {
-	      inform (DECL_SOURCE_LOCATION
+	      d.inform (DECL_SOURCE_LOCATION
 			(TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
-		      "the conflicting type defined in another translation "
-		      "unit");
+			"the conflicting type defined in another translation "
+			"unit");
 	      gcc_assert (TREE_CODE (ref2->referred->decl)
 			  == FUNCTION_DECL);
-	      inform (DECL_SOURCE_LOCATION
-			 (ref1->referred->ultimate_alias_target ()->decl),
-		      "virtual method %qD",
-		      ref1->referred->ultimate_alias_target ()->decl);
-	      inform (DECL_SOURCE_LOCATION
-			 (ref2->referred->ultimate_alias_target ()->decl),
-		      "ought to match virtual method %qD but does not",
-		      ref2->referred->ultimate_alias_target ()->decl);
+	      d.inform (DECL_SOURCE_LOCATION
+			(ref1->referred->ultimate_alias_target ()->decl),
+			"virtual method %qD",
+			ref1->referred->ultimate_alias_target ()->decl);
+	      d.inform (DECL_SOURCE_LOCATION
+			(ref2->referred->ultimate_alias_target ()->decl),
+			"ought to match virtual method %qD but does not",
+			ref2->referred->ultimate_alias_target ()->decl);
 	    }
 	  else
-	    inform (DECL_SOURCE_LOCATION
+	    d.inform (DECL_SOURCE_LOCATION
 		      (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
-		    "the conflicting type defined in another translation "
-		    "unit has virtual table with different contents");
+		      "the conflicting type defined in another translation "
+		      "unit has virtual table with different contents");
 	  return;
 	}
     }
@@ -986,9 +997,10 @@ warn_odr (tree t1, tree t2, tree st1, tree st2,
   if (lto_location_cache::current_cache)
     lto_location_cache::current_cache->apply_location_cache ();
 
-  if (!warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (t1)), OPT_Wodr,
-		   "type %qT violates the C++ One Definition Rule",
-		   t1))
+  diagnostic_group d;
+  if (!d.warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (t1)), OPT_Wodr,
+		     "type %qT violates the C++ One Definition Rule",
+		     t1))
     return;
   if (!st1 && !st2)
     ;
@@ -997,31 +1009,33 @@ warn_odr (tree t1, tree t2, tree st1, tree st2,
      elements.  */
   else if (!st1 || TREE_CODE (st1) == FIELD_DECL)
     {
-      inform (DECL_SOURCE_LOCATION (decl2),
-	      "a different type is defined in another translation unit");
+      d.inform (DECL_SOURCE_LOCATION (decl2),
+		"a different type is defined in another translation unit");
       if (!st1)
 	{
 	  st1 = st2;
 	  st2 = NULL;
 	}
-      inform (DECL_SOURCE_LOCATION (st1),
-	      "the first difference of corresponding definitions is field %qD",
-	      st1);
+      d.inform (DECL_SOURCE_LOCATION (st1),
+		"the first difference of corresponding definitions is field"
+		" %qD",
+		st1);
       if (st2)
         decl2 = st2;
     }
   else if (TREE_CODE (st1) == FUNCTION_DECL)
     {
-      inform (DECL_SOURCE_LOCATION (decl2),
-	      "a different type is defined in another translation unit");
-      inform (DECL_SOURCE_LOCATION (st1),
-	      "the first difference of corresponding definitions is method %qD",
-	      st1);
+      d.inform (DECL_SOURCE_LOCATION (decl2),
+		"a different type is defined in another translation unit");
+      d.inform (DECL_SOURCE_LOCATION (st1),
+		"the first difference of corresponding definitions is method"
+		" %qD",
+		st1);
       decl2 = st2;
     }
   else
     return;
-  inform (DECL_SOURCE_LOCATION (decl2), reason);
+  d.inform (DECL_SOURCE_LOCATION (decl2), reason);
 
   if (warned)
     *warned = true;
diff --git a/gcc/multiple_target.c b/gcc/multiple_target.c
index a1fe09a..0c28fea 100644
--- a/gcc/multiple_target.c
+++ b/gcc/multiple_target.c
@@ -347,8 +347,9 @@ expand_target_clones (struct cgraph_node *node, bool definition)
   if (node->definition
       && !tree_versionable_function_p (node->decl))
     {
-      error_at (DECL_SOURCE_LOCATION (node->decl),
-		"clones for %<target_clones%> attribute cannot be created");
+      diagnostic_group d;
+      d.error_at (DECL_SOURCE_LOCATION (node->decl),
+		  "clones for %<target_clones%> attribute cannot be created");
       const char *reason = NULL;
       if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
 	reason = G_("function %q+F can never be copied "
@@ -356,7 +357,7 @@ expand_target_clones (struct cgraph_node *node, bool definition)
       else
 	reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl));
       if (reason)
-	inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
+	d.inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
       return false;
     }
 
diff --git a/gcc/opts-common.c b/gcc/opts-common.c
index 1135644..0d794b4 100644
--- a/gcc/opts-common.c
+++ b/gcc/opts-common.c
@@ -1268,10 +1268,11 @@ cmdline_handle_error (location_t loc, const struct cl_option *option,
       unsigned int i;
       char *s;
 
+      diagnostic_group d;
       if (e->unknown_error)
-	error_at (loc, e->unknown_error, arg);
+	d.error_at (loc, e->unknown_error, arg);
       else
-	error_at (loc, "unrecognized argument in option %qs", opt);
+	d.error_at (loc, "unrecognized argument in option %qs", opt);
 
       auto_vec <const char *> candidates;
       for (i = 0; e->values[i].arg != NULL; i++)
@@ -1282,10 +1283,10 @@ cmdline_handle_error (location_t loc, const struct cl_option *option,
 	}
       const char *hint = candidates_list_and_hint (arg, s, candidates);
       if (hint)
-	inform (loc, "valid arguments to %qs are: %s; did you mean %qs?",
+	d.inform (loc, "valid arguments to %qs are: %s; did you mean %qs?",
 		option->opt_text, s, hint);
       else
-	inform (loc, "valid arguments to %qs are: %s", option->opt_text, s);
+	d.inform (loc, "valid arguments to %qs are: %s", option->opt_text, s);
       XDELETEVEC (s);
 
       return true;
diff --git a/gcc/reginfo.c b/gcc/reginfo.c
index 1f36d14..e111c51 100644
--- a/gcc/reginfo.c
+++ b/gcc/reginfo.c
@@ -782,11 +782,13 @@ globalize_reg (tree decl, int i)
 
   if (global_regs[i])
     {
-      warning_at (loc, 0, 
-		  "register of %qD used for multiple global register variables",
-		  decl);
-      inform (DECL_SOURCE_LOCATION (global_regs_decl[i]),
-	      "conflicts with %qD", global_regs_decl[i]); 
+      diagnostic_group d;
+      d.warning_at (loc, 0,
+		    "register of %qD used for multiple global register "
+		    "variables",
+		    decl);
+      d.inform (DECL_SOURCE_LOCATION (global_regs_decl[i]),
+		"conflicts with %qD", global_regs_decl[i]);
       return;
     }
 
diff --git a/gcc/substring-locations.c b/gcc/substring-locations.c
index 2d7f0c1..01ca02d 100644
--- a/gcc/substring-locations.c
+++ b/gcc/substring-locations.c
@@ -138,6 +138,7 @@ format_warning_n_va (const substring_loc &fmt_loc,
 	}
     }
 
+  diagnostic_group d;
   rich_location richloc (line_table, primary_loc);
 
   if (param_loc != UNKNOWN_LOCATION)
@@ -167,6 +168,7 @@ format_warning_n_va (const substring_loc &fmt_loc,
     diagnostic_set_info (&diagnostic, singular_gmsgid, ap, &richloc,
 			 DK_WARNING);
   diagnostic.option_index = opt;
+  diagnostic.group = &d;
   bool warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
 
   if (!err && fmt_substring_loc && !substring_within_range)
@@ -177,8 +179,8 @@ format_warning_n_va (const substring_loc &fmt_loc,
 	if (corrected_substring)
 	  substring_richloc.add_fixit_replace (fmt_substring_range,
 					       corrected_substring);
-	inform (&substring_richloc,
-		"format string is defined here");
+	d.inform (&substring_richloc,
+		  "format string is defined here");
       }
 
   return warned;
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 6a16ce5..e316af1 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -4416,14 +4416,15 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id)
 	       /* Avoid warnings during early inline pass. */
 	       && symtab->global_info_ready)
 	{
-	  if (warning (OPT_Winline, "inlining failed in call to %q+F: %s",
-		       fn, _(cgraph_inline_failed_string (reason))))
+	  diagnostic_group d;
+	  if (d.warning (OPT_Winline, "inlining failed in call to %q+F: %s",
+			 fn, _(cgraph_inline_failed_string (reason))))
 	    {
 	      if (gimple_location (stmt) != UNKNOWN_LOCATION)
-		inform (gimple_location (stmt), "called from here");
+		d.inform (gimple_location (stmt), "called from here");
 	      else if (DECL_SOURCE_LOCATION (cfun->decl) != UNKNOWN_LOCATION)
-		inform (DECL_SOURCE_LOCATION (cfun->decl),
-                       "called from this function");
+		d.inform (DECL_SOURCE_LOCATION (cfun->decl),
+			  "called from this function");
 	    }
 	}
       goto egress;
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index 63c9531..e29719d 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -3454,18 +3454,19 @@ pass_post_ipa_warn::execute (function *fun)
 			continue;
 
 		      location_t loc = gimple_location (stmt);
-		      if (warning_at (loc, OPT_Wnonnull,
-				      "%Gargument %u null where non-null "
-				      "expected", stmt, i + 1))
+		      diagnostic_group d;
+		      if (d.warning_at (loc, OPT_Wnonnull,
+					"%Gargument %u null where non-null "
+					"expected", stmt, i + 1))
 			{
 			  tree fndecl = gimple_call_fndecl (stmt);
 			  if (fndecl && DECL_IS_BUILTIN (fndecl))
-			    inform (loc, "in a call to built-in function %qD",
-				    fndecl);
+			    d.inform (loc, "in a call to built-in function %qD",
+				      fndecl);
 			  else if (fndecl)
-			    inform (DECL_SOURCE_LOCATION (fndecl),
-				    "in a call to function %qD declared here",
-				    fndecl);
+			    d.inform (DECL_SOURCE_LOCATION (fndecl),
+				      "in a call to function %qD declared here",
+				      fndecl);
 
 			}
 		    }
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index fbdf838..3b39f9b 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -3231,9 +3231,10 @@ do_warn_aggressive_loop_optimizations (struct loop *loop,
   char buf[WIDE_INT_PRINT_BUFFER_SIZE];
   print_dec (i_bound, buf, TYPE_UNSIGNED (TREE_TYPE (loop->nb_iterations))
 	     ? UNSIGNED : SIGNED);
-  if (warning_at (gimple_location (stmt), OPT_Waggressive_loop_optimizations,
-		  "iteration %s invokes undefined behavior", buf))
-    inform (gimple_location (estmt), "within this loop");
+  diagnostic_group d;
+  if (d.warning_at (gimple_location (stmt), OPT_Waggressive_loop_optimizations,
+		    "iteration %s invokes undefined behavior", buf))
+    d.inform (gimple_location (estmt), "within this loop");
   loop->warned_aggressive_loop_optimizations = true;
 }
 
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index 8ccbc85..4ba9536 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -178,7 +178,8 @@ warn_uninit (enum opt_code wc, tree t, tree expr, tree var,
   cfun_loc = DECL_SOURCE_LOCATION (cfun->decl);
   xloc = expand_location (location);
   floc = expand_location (cfun_loc);
-  if (warning_at (location, wc, gmsgid, expr))
+  diagnostic_group d;
+  if (d.warning_at (location, wc, gmsgid, expr))
     {
       TREE_NO_WARNING (expr) = 1;
 
@@ -188,7 +189,7 @@ warn_uninit (enum opt_code wc, tree t, tree expr, tree var,
 	  || linemap_location_before_p (line_table, location, cfun_loc)
 	  || linemap_location_before_p (line_table, cfun->function_end_locus,
 					location))
-	inform (DECL_SOURCE_LOCATION (var), "%qD was declared here", var);
+	d.inform (DECL_SOURCE_LOCATION (var), "%qD was declared here", var);
     }
 }
 
diff --git a/gcc/tree.c b/gcc/tree.c
index 0ec74af..20af74c 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -12613,14 +12613,15 @@ warn_deprecated_use (tree node, tree attr)
   bool w = false;
   if (DECL_P (node))
     {
+      diagnostic_group d;
       if (msg)
-	w = warning (OPT_Wdeprecated_declarations,
-		     "%qD is deprecated: %s", node, (const char *) msg);
+	w = d.warning (OPT_Wdeprecated_declarations,
+		       "%qD is deprecated: %s", node, (const char *) msg);
       else
-	w = warning (OPT_Wdeprecated_declarations,
-		     "%qD is deprecated", node);
+	w = d.warning (OPT_Wdeprecated_declarations,
+		       "%qD is deprecated", node);
       if (w)
-	inform (DECL_SOURCE_LOCATION (node), "declared here");
+	d.inform (DECL_SOURCE_LOCATION (node), "declared here");
     }
   else if (TYPE_P (node))
     {
@@ -12636,27 +12637,28 @@ warn_deprecated_use (tree node, tree attr)
 	    what = DECL_NAME (TYPE_NAME (node));
 	}
 
+      diagnostic_group d;
       if (what)
 	{
 	  if (msg)
-	    w = warning (OPT_Wdeprecated_declarations,
-			 "%qE is deprecated: %s", what, (const char *) msg);
+	    w = d.warning (OPT_Wdeprecated_declarations,
+			   "%qE is deprecated: %s", what, (const char *) msg);
 	  else
-	    w = warning (OPT_Wdeprecated_declarations,
-			 "%qE is deprecated", what);
+	    w = d.warning (OPT_Wdeprecated_declarations,
+			   "%qE is deprecated", what);
 	}
       else
 	{
 	  if (msg)
-	    w = warning (OPT_Wdeprecated_declarations,
-			 "type is deprecated: %s", (const char *) msg);
+	    w = d.warning (OPT_Wdeprecated_declarations,
+			   "type is deprecated: %s", (const char *) msg);
 	  else
-	    w = warning (OPT_Wdeprecated_declarations,
-			 "type is deprecated");
+	    w = d.warning (OPT_Wdeprecated_declarations,
+			   "type is deprecated");
 	}
 
       if (w && decl)
-	inform (DECL_SOURCE_LOCATION (decl), "declared here");
+	d.inform (DECL_SOURCE_LOCATION (decl), "declared here");
     }
 
   return w;
-- 
1.8.5.3

