diff mbox series

c++: Module-specific error and tree dumping

Message ID 7d76f73b-9310-2573-682c-4296e4dd0424@acm.org
State New
Headers show
Series c++: Module-specific error and tree dumping | expand

Commit Message

Nathan Sidwell Dec. 9, 2020, 8:20 p.m. UTC
With modules, we need the ability to name 'foos' in different modules.
The idiom for that is a trailing '@modulename' suffix.	This adds that
to the error printing routines.	 I also	augment	the tree dumping
machinery to show module-specific metadata.

         gcc/cp/
         * error.c (dump_module_suffix): New.
         (dump_aggr_type, dump_simple_decl, dump_function_name): Call it.
         * ptree.c (cxx_print_decl): Print module information.
         * module.cc (module_name, get_importing_module): Stubs.

pushing to trunk

Comments

David Malcolm Dec. 9, 2020, 8:41 p.m. UTC | #1
On Wed, 2020-12-09 at 15:20 -0500, Nathan Sidwell wrote:
> With modules, we need the ability to name 'foos' in different
> modules.
> The idiom for that is a trailing '@modulename' suffix.

Out of curiosity, is this idiom shared with other compilers? (or in the
standard)

> 	This adds that
> to the error printing routines.	 I also	augment	the tree
> dumping
> machinery to show module-specific metadata.
> 
>          gcc/cp/
>          * error.c (dump_module_suffix): New.
>          (dump_aggr_type, dump_simple_decl, dump_function_name): Call
> it.
>          * ptree.c (cxx_print_decl): Print module information.
>          * module.cc (module_name, get_importing_module): Stubs.
> 
> pushing to trunk

Unless I'm misreading it, the patch you posted deletes about 2000 lines
from gcc/cp/error.c (lines 2599 onwards), deleting a whole bunch of
stuff.

Did you post the wrong patch?

Dave
Nathan Sidwell Dec. 9, 2020, 9:07 p.m. UTC | #2
On 12/9/20 3:41 PM, David Malcolm wrote:
> On Wed, 2020-12-09 at 15:20 -0500, Nathan Sidwell wrote:
>> With modules, we need the ability to name 'foos' in different
>> modules.
>> The idiom for that is a trailing '@modulename' suffix.
> 
> Out of curiosity, is this idiom shared with other compilers? (or in the
> standard)

The std says nothing.  I discussed it with clang guys, and probably with 
MSVC & EDG guys.  I've been using it consistently in papers to wg21. 
Can't recall exactly, it was one of the very early things.


> Unless I'm misreading it, the patch you posted deletes about 2000 lines
> from gcc/cp/error.c (lines 2599 onwards), deleting a whole bunch of
> stuff.
> 
> Did you post the wrong patch?

hm, wut?  Attached is the diff that was committed.   I think I must have 
generated the diff during a file write (via sshfs).

I think that's evidence I need to stop for the day :)

nathan
David Malcolm Dec. 9, 2020, 9:17 p.m. UTC | #3
On Wed, 2020-12-09 at 16:07 -0500, Nathan Sidwell wrote:
> On 12/9/20 3:41 PM, David Malcolm wrote:
> > On Wed, 2020-12-09 at 15:20 -0500, Nathan Sidwell wrote:
> > > With modules, we need the ability to name 'foos' in different
> > > modules.
> > > The idiom for that is a trailing '@modulename' suffix.
> > 
> > Out of curiosity, is this idiom shared with other compilers? (or in
> > the
> > standard)
> 
> The std says nothing.  I discussed it with clang guys, and probably
> with 
> MSVC & EDG guys.  I've been using it consistently in papers to wg21. 
> Can't recall exactly, it was one of the very early things.

Fair enough, thanks.


> > Unless I'm misreading it, the patch you posted deletes about 2000
> > lines
> > from gcc/cp/error.c (lines 2599 onwards), deleting a whole bunch of
> > stuff.
> > 
> > Did you post the wrong patch?
> 
> hm, wut?  Attached is the diff that was committed.

Thanks; that diff looks far more reasonable :)

Dave

>    I think I must have 
> generated the diff during a file write (via sshfs).
> 
> I think that's evidence I need to stop for the day :)
> 
> nathan
> 
>
diff mbox series

Patch

diff --git i/gcc/cp/error.c w/gcc/cp/error.c
index d11591d67a0..374d859fe1c 100644
--- i/gcc/cp/error.c
+++ w/gcc/cp/error.c
@@ -179,6 +179,38 @@  cxx_initialize_diagnostics (diagnostic_context *context)
   pp->m_format_postprocessor = new cxx_format_postprocessor ();
 }
 
+/* Dump an '@module' name suffix for DECL, if any.  */
+
+static void
+dump_module_suffix (cxx_pretty_printer *pp, tree decl)
+{
+  if (!modules_p ())
+    return;
+
+  if (!DECL_CONTEXT (decl))
+    return;
+
+  if (TREE_CODE (decl) != CONST_DECL
+      || !UNSCOPED_ENUM_P (DECL_CONTEXT (decl)))
+    {
+      if (!DECL_NAMESPACE_SCOPE_P (decl))
+	return;
+
+      if (TREE_CODE (decl) == NAMESPACE_DECL
+	  && !DECL_NAMESPACE_ALIAS (decl)
+	  && (TREE_PUBLIC (decl) || !TREE_PUBLIC (CP_DECL_CONTEXT (decl))))
+	return;
+    }
+
+  if (unsigned m = get_originating_module (decl))
+    if (const char *n = module_name (m, false))
+      {
+	pp_character (pp, '@');
+	pp->padding = pp_none;
+	pp_string (pp, n);
+      }
+}
+
 /* Dump a scope, if deemed necessary.  */
 
 static void
@@ -771,6 +803,8 @@  dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags)
   else
     pp_cxx_tree_identifier (pp, DECL_NAME (decl));
 
+  dump_module_suffix (pp, decl);
+
   if (tmplate)
     dump_template_parms (pp, TYPE_TEMPLATE_INFO (t),
 			 !CLASSTYPE_USE_TEMPLATE (t),
@@ -1077,6 +1111,9 @@  dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags)
     pp_string (pp, M_("<structured bindings>"));
   else
     pp_string (pp, M_("<anonymous>"));
+
+  dump_module_suffix (pp, t);
+
   if (flags & TFF_DECL_SPECIFIERS)
     dump_type_suffix (pp, type, flags);
 }
@@ -1894,6 +1931,8 @@  dump_function_name (cxx_pretty_printer *pp, tree t, int flags)
   else
     dump_decl (pp, name, flags);
 
+  dump_module_suffix (pp, t);
+
   if (DECL_TEMPLATE_INFO (t)
       && !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (t)
       && (TREE_CODE (DECL_TI_TEMPLATE (t)) != TEMPLATE_DECL
@@ -2560,2047 +2599,4 @@  dump_expr (cxx_pretty_printer *pp, tree t, int flags)
 	      pp_cxx_left_paren (pp);
 	      pp_cxx_left_paren (pp);
 	      dump_type (pp, TREE_TYPE (t), flags);
-	      pp_cxx_right_paren (pp);
-	      pp_character (pp, '0');
-	      pp_cxx_right_paren (pp);
-	      break;
-	    }
-	  else if (tree_fits_shwi_p (idx))
-	    {
-	      tree virtuals;
-	      unsigned HOST_WIDE_INT n;
-
-	      t = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (t)));
-	      t = TYPE_METHOD_BASETYPE (t);
-	      virtuals = BINFO_VIRTUALS (TYPE_BINFO (TYPE_MAIN_VARIANT (t)));
-
-	      n = tree_to_shwi (idx);
-
-	      /* Map vtable index back one, to allow for the null pointer to
-		 member.  */
-	      --n;
-
-	      while (n > 0 && virtuals)
-		{
-		  --n;
-		  virtuals = TREE_CHAIN (virtuals);
-		}
-	      if (virtuals)
-		{
-		  dump_expr (pp, BV_FN (virtuals),
-			     flags | TFF_EXPR_IN_PARENS);
-		  break;
-		}
-	    }
-	}
-      if (TREE_TYPE (t) && LAMBDA_TYPE_P (TREE_TYPE (t)))
-	pp_string (pp, "<lambda closure object>");
-      if (TREE_TYPE (t) && EMPTY_CONSTRUCTOR_P (t))
-	{
-	  dump_type (pp, TREE_TYPE (t), 0);
-	  pp_cxx_left_paren (pp);
-	  pp_cxx_right_paren (pp);
-	}
-      else
-	{
-	  if (!BRACE_ENCLOSED_INITIALIZER_P (t))
-	    dump_type (pp, TREE_TYPE (t), 0);
-	  pp_cxx_left_brace (pp);
-	  dump_expr_init_vec (pp, CONSTRUCTOR_ELTS (t), flags);
-	  pp_cxx_right_brace (pp);
-	}
-
-      break;
-
-    case OFFSET_REF:
-      {
-	tree ob = TREE_OPERAND (t, 0);
-	if (is_dummy_object (ob))
-	  {
-	    t = TREE_OPERAND (t, 1);
-	    if (TREE_CODE (t) == FUNCTION_DECL)
-	      /* A::f */
-	      dump_expr (pp, t, flags | TFF_EXPR_IN_PARENS);
-	    else if (BASELINK_P (t))
-	      dump_expr (pp, OVL_FIRST (BASELINK_FUNCTIONS (t)),
-			 flags | TFF_EXPR_IN_PARENS);
-	    else
-	      dump_decl (pp, t, flags);
-	  }
-	else
-	  {
-	    if (INDIRECT_REF_P (ob))
-	      {
-		dump_expr (pp, TREE_OPERAND (ob, 0), flags | TFF_EXPR_IN_PARENS);
-		pp_cxx_arrow (pp);
-		pp_cxx_star (pp);
-	      }
-	    else
-	      {
-		dump_expr (pp, ob, flags | TFF_EXPR_IN_PARENS);
-		pp_cxx_dot (pp);
-		pp_cxx_star (pp);
-	      }
-	    dump_expr (pp, TREE_OPERAND (t, 1), flags | TFF_EXPR_IN_PARENS);
-	  }
-	break;
-      }
-
-    case TEMPLATE_PARM_INDEX:
-      dump_decl (pp, TEMPLATE_PARM_DECL (t), flags & ~TFF_DECL_SPECIFIERS);
-      break;
-
-    case CAST_EXPR:
-      if (TREE_OPERAND (t, 0) == NULL_TREE
-	  || TREE_CHAIN (TREE_OPERAND (t, 0)))
-	{
-	  dump_type (pp, TREE_TYPE (t), flags);
-	  pp_cxx_left_paren (pp);
-	  dump_expr_list (pp, TREE_OPERAND (t, 0), flags);
-	  pp_cxx_right_paren (pp);
-	}
-      else
-	{
-	  pp_cxx_left_paren (pp);
-	  dump_type (pp, TREE_TYPE (t), flags);
-	  pp_cxx_right_paren (pp);
-	  pp_cxx_left_paren (pp);
-	  dump_expr_list (pp, TREE_OPERAND (t, 0), flags);
-	  pp_cxx_right_paren (pp);
-	}
-      break;
-
-    case STATIC_CAST_EXPR:
-      pp_cxx_ws_string (pp, "static_cast");
-      goto cast;
-    case REINTERPRET_CAST_EXPR:
-      pp_cxx_ws_string (pp, "reinterpret_cast");
-      goto cast;
-    case CONST_CAST_EXPR:
-      pp_cxx_ws_string (pp, "const_cast");
-      goto cast;
-    case DYNAMIC_CAST_EXPR:
-      pp_cxx_ws_string (pp, "dynamic_cast");
-    cast:
-      pp_cxx_begin_template_argument_list (pp);
-      dump_type (pp, TREE_TYPE (t), flags);
-      pp_cxx_end_template_argument_list (pp);
-      pp_cxx_left_paren (pp);
-      dump_expr (pp, TREE_OPERAND (t, 0), flags);
-      pp_cxx_right_paren (pp);
-      break;
-
-    case ARROW_EXPR:
-      dump_expr (pp, TREE_OPERAND (t, 0), flags);
-      pp_cxx_arrow (pp);
-      break;
-
-    case SIZEOF_EXPR:
-    case ALIGNOF_EXPR:
-      if (TREE_CODE (t) == SIZEOF_EXPR)
-	pp_cxx_ws_string (pp, "sizeof");
-      else
-	{
-	  gcc_assert (TREE_CODE (t) == ALIGNOF_EXPR);
-	  pp_cxx_ws_string (pp, "__alignof__");
-	}
-      op = TREE_OPERAND (t, 0);
-      if (PACK_EXPANSION_P (op))
-	{
-	  pp_string (pp, "...");
-	  op = PACK_EXPANSION_PATTERN (op);
-	}
-      pp_cxx_whitespace (pp);
-      pp_cxx_left_paren (pp);
-      if (TREE_CODE (t) == SIZEOF_EXPR && SIZEOF_EXPR_TYPE_P (t))
-	dump_type (pp, TREE_TYPE (op), flags);
-      else if (TYPE_P (TREE_OPERAND (t, 0)))
-	dump_type (pp, op, flags);
-      else
-	dump_expr (pp, op, flags);
-      pp_cxx_right_paren (pp);
-      break;
-
-    case AT_ENCODE_EXPR:
-      pp_cxx_ws_string (pp, "@encode");
-      pp_cxx_whitespace (pp);
-      pp_cxx_left_paren (pp);
-      dump_type (pp, TREE_OPERAND (t, 0), flags);
-      pp_cxx_right_paren (pp);
-      break;
-
-    case NOEXCEPT_EXPR:
-      pp_cxx_ws_string (pp, "noexcept");
-      pp_cxx_whitespace (pp);
-      pp_cxx_left_paren (pp);
-      dump_expr (pp, TREE_OPERAND (t, 0), flags);
-      pp_cxx_right_paren (pp);
-      break;
-
-    case REALPART_EXPR:
-    case IMAGPART_EXPR:
-      pp_cxx_ws_string (pp, OVL_OP_INFO (false, TREE_CODE (t))->name);
-      pp_cxx_whitespace (pp);
-      dump_expr (pp, TREE_OPERAND (t, 0), flags);
-      break;
-
-    case DEFERRED_PARSE:
-      pp_string (pp, M_("<unparsed>"));
-      break;
-
-    case TRY_CATCH_EXPR:
-    case CLEANUP_POINT_EXPR:
-      dump_expr (pp, TREE_OPERAND (t, 0), flags);
-      break;
-
-    case PSEUDO_DTOR_EXPR:
-      dump_expr (pp, TREE_OPERAND (t, 0), flags);
-      pp_cxx_dot (pp);
-      if (TREE_OPERAND (t, 1))
-	{
-	  dump_type (pp, TREE_OPERAND (t, 1), flags);
-	  pp_cxx_colon_colon (pp);
-	}
-      pp_cxx_complement (pp);
-      dump_type (pp, TREE_OPERAND (t, 2), flags);
-      break;
-
-    case TEMPLATE_ID_EXPR:
-      dump_decl (pp, t, flags);
-      break;
-
-    case BIND_EXPR:
-    case STMT_EXPR:
-    case EXPR_STMT:
-    case STATEMENT_LIST:
-      /* We don't yet have a way of dumping statements in a
-	 human-readable format.  */
-      pp_string (pp, "({...})");
-      break;
-
-    case LOOP_EXPR:
-      pp_string (pp, "while (1) { ");
-      dump_expr (pp, TREE_OPERAND (t, 0), flags & ~TFF_EXPR_IN_PARENS);
-      pp_cxx_right_brace (pp);
-      break;
-
-    case EXIT_EXPR:
-      pp_string (pp, "if (");
-      dump_expr (pp, TREE_OPERAND (t, 0), flags & ~TFF_EXPR_IN_PARENS);
-      pp_string (pp, ") break; ");
-      break;
-
-    case BASELINK:
-      dump_expr (pp, BASELINK_FUNCTIONS (t), flags & ~TFF_EXPR_IN_PARENS);
-      break;
-
-    case EMPTY_CLASS_EXPR:
-      dump_type (pp, TREE_TYPE (t), flags);
-      pp_cxx_left_paren (pp);
-      pp_cxx_right_paren (pp);
-      break;
-
-    case NON_DEPENDENT_EXPR:
-      dump_expr (pp, TREE_OPERAND (t, 0), flags);
-      break;
-
-    case ARGUMENT_PACK_SELECT:
-      dump_template_argument (pp, ARGUMENT_PACK_SELECT_FROM_PACK (t), flags);
-      break;
-
-    case RECORD_TYPE:
-    case UNION_TYPE:
-    case ENUMERAL_TYPE:
-    case REAL_TYPE:
-    case VOID_TYPE:
-    case OPAQUE_TYPE:
-    case BOOLEAN_TYPE:
-    case INTEGER_TYPE:
-    case COMPLEX_TYPE:
-    case VECTOR_TYPE:
-    case DECLTYPE_TYPE:
-      pp_type_specifier_seq (pp, t);
-      break;
-
-    case TYPENAME_TYPE:
-      /* We get here when we want to print a dependent type as an
-         id-expression, without any disambiguator decoration.  */
-      pp->id_expression (t);
-      break;
-
-    case TEMPLATE_TYPE_PARM:
-    case TEMPLATE_TEMPLATE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
-      dump_type (pp, t, flags);
-      break;
-
-    case TRAIT_EXPR:
-      pp_cxx_trait_expression (pp, t);
-      break;
-
-    case VA_ARG_EXPR:
-      pp_cxx_va_arg_expression (pp, t);
-      break;
-
-    case OFFSETOF_EXPR:
-      pp_cxx_offsetof_expression (pp, t);
-      break;
-
-    case ADDRESSOF_EXPR:
-      pp_cxx_addressof_expression (pp, t);
-      break;
-
-    case SCOPE_REF:
-      dump_decl (pp, t, flags);
-      break;
-
-    case EXPR_PACK_EXPANSION:
-    case UNARY_LEFT_FOLD_EXPR:
-    case UNARY_RIGHT_FOLD_EXPR:
-    case BINARY_LEFT_FOLD_EXPR:
-    case BINARY_RIGHT_FOLD_EXPR:
-    case TYPEID_EXPR:
-    case MEMBER_REF:
-    case DOTSTAR_EXPR:
-    case NEW_EXPR:
-    case VEC_NEW_EXPR:
-    case DELETE_EXPR:
-    case VEC_DELETE_EXPR:
-    case MODOP_EXPR:
-    case ABS_EXPR:
-    case ABSU_EXPR:
-    case CONJ_EXPR:
-    case VECTOR_CST:
-    case FIXED_CST:
-    case UNORDERED_EXPR:
-    case ORDERED_EXPR:
-    case UNLT_EXPR:
-    case UNLE_EXPR:
-    case UNGT_EXPR:
-    case UNGE_EXPR:
-    case UNEQ_EXPR:
-    case LTGT_EXPR:
-    case COMPLEX_EXPR:
-    case BIT_FIELD_REF:
-    case FIX_TRUNC_EXPR:
-    case FLOAT_EXPR:
-      pp->expression (t);
-      break;
-
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case TRUTH_XOR_EXPR:
-      if (flags & TFF_EXPR_IN_PARENS)
-	pp_cxx_left_paren (pp);
-      pp->expression (t);
-      if (flags & TFF_EXPR_IN_PARENS)
-	pp_cxx_right_paren (pp);
-      break;
-
-    case OBJ_TYPE_REF:
-      dump_expr (pp, resolve_virtual_fun_from_obj_type_ref (t), flags);
-      break;
-
-    case LAMBDA_EXPR:
-      pp_string (pp, M_("<lambda>"));
-      break;
-
-    case PAREN_EXPR:
-      pp_cxx_left_paren (pp);
-      dump_expr (pp, TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
-      pp_cxx_right_paren (pp);
-      break;
-
-    case REQUIRES_EXPR:
-      pp_cxx_requires_expr (cxx_pp, t);
-      break;
-
-    case SIMPLE_REQ:
-      pp_cxx_simple_requirement (cxx_pp, t);
-      break;
-
-    case TYPE_REQ:
-      pp_cxx_type_requirement (cxx_pp, t);
-      break;
-
-    case COMPOUND_REQ:
-      pp_cxx_compound_requirement (cxx_pp, t);
-      break;
-
-    case NESTED_REQ:
-      pp_cxx_nested_requirement (cxx_pp, t);
-      break;
-
-    case ATOMIC_CONSTR:
-    case CHECK_CONSTR:
-    case CONJ_CONSTR:
-    case DISJ_CONSTR:
-      {
-        pp_cxx_constraint (cxx_pp, t);
-        break;
-      }
-
-    case PLACEHOLDER_EXPR:
-      pp_string (pp, M_("*this"));
-      break;
-
-    case TREE_LIST:
-      dump_expr_list (pp, t, flags);
-      break;
-
-      /*  This list is incomplete, but should suffice for now.
-	  It is very important that `sorry' does not call
-	  `report_error_function'.  That could cause an infinite loop.  */
-    default:
-      pp_unsupported_tree (pp, t);
-      /* Fall through.  */
-    case ERROR_MARK:
-      pp_string (pp, M_("<expression error>"));
-      break;
-    }
-}
-
-static void
-dump_binary_op (cxx_pretty_printer *pp, const char *opstring, tree t,
-                int flags)
-{
-  pp_cxx_left_paren (pp);
-  dump_expr (pp, TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
-  pp_cxx_whitespace (pp);
-  if (opstring)
-    pp_cxx_ws_string (pp, opstring);
-  else
-    pp_string (pp, M_("<unknown operator>"));
-  pp_cxx_whitespace (pp);
-  tree op1 = TREE_OPERAND (t, 1);
-  if (TREE_CODE (t) == POINTER_PLUS_EXPR
-      && TREE_CODE (op1) == INTEGER_CST
-      && tree_int_cst_sign_bit (op1))
-    /* A pointer minus an integer is represented internally as plus a very
-       large number, don't expose that to users.  */
-    op1 = convert (ssizetype, op1);
-  dump_expr (pp, op1, flags | TFF_EXPR_IN_PARENS);
-  pp_cxx_right_paren (pp);
-}
-
-static void
-dump_unary_op (cxx_pretty_printer *pp, const char *opstring, tree t, int flags)
-{
-  if (flags & TFF_EXPR_IN_PARENS)
-    pp_cxx_left_paren (pp);
-  pp_cxx_ws_string (pp, opstring);
-  dump_expr (pp, TREE_OPERAND (t, 0), flags & ~TFF_EXPR_IN_PARENS);
-  if (flags & TFF_EXPR_IN_PARENS)
-    pp_cxx_right_paren (pp);
-}
-
-static void
-reinit_cxx_pp (void)
-{
-  pp_clear_output_area (cxx_pp);
-  cxx_pp->padding = pp_none;
-  pp_indentation (cxx_pp) = 0;
-  pp_needs_newline (cxx_pp) = false;
-  cxx_pp->enclosing_scope = current_function_decl;
-}
-
-/* Same as pp_formatted_text, except the return string is a separate
-   copy and has a GGC storage duration, e.g. an indefinite lifetime.  */
-
-inline const char *
-pp_ggc_formatted_text (pretty_printer *pp)
-{
-  return ggc_strdup (pp_formatted_text (pp));
-}
-
-/* Exported interface to stringifying types, exprs and decls under TFF_*
-   control.  */
-
-const char *
-type_as_string (tree typ, int flags)
-{
-  reinit_cxx_pp ();
-  pp_translate_identifiers (cxx_pp) = false;
-  dump_type (cxx_pp, typ, flags);
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-const char *
-type_as_string_translate (tree typ, int flags)
-{
-  reinit_cxx_pp ();
-  dump_type (cxx_pp, typ, flags);
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-const char *
-expr_as_string (tree decl, int flags)
-{
-  reinit_cxx_pp ();
-  pp_translate_identifiers (cxx_pp) = false;
-  dump_expr (cxx_pp, decl, flags);
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-/* Wrap decl_as_string with options appropriate for dwarf.  */
-
-const char *
-decl_as_dwarf_string (tree decl, int flags)
-{
-  const char *name;
-  /* Curiously, reinit_cxx_pp doesn't reset the flags field, so setting the flag
-     here will be adequate to get the desired behavior.  */
-  cxx_pp->flags |= pp_c_flag_gnu_v3;
-  name = decl_as_string (decl, flags);
-  /* Subsequent calls to the pretty printer shouldn't use this style.  */
-  cxx_pp->flags &= ~pp_c_flag_gnu_v3;
-  return name;
-}
-
-const char *
-decl_as_string (tree decl, int flags)
-{
-  reinit_cxx_pp ();
-  pp_translate_identifiers (cxx_pp) = false;
-  dump_decl (cxx_pp, decl, flags);
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-const char *
-decl_as_string_translate (tree decl, int flags)
-{
-  reinit_cxx_pp ();
-  dump_decl (cxx_pp, decl, flags);
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-/* Wrap lang_decl_name with options appropriate for dwarf.  */
-
-const char *
-lang_decl_dwarf_name (tree decl, int v, bool translate)
-{
-  const char *name;
-  /* Curiously, reinit_cxx_pp doesn't reset the flags field, so setting the flag
-     here will be adequate to get the desired behavior.  */
-  cxx_pp->flags |= pp_c_flag_gnu_v3;
-  name = lang_decl_name (decl, v, translate);
-  /* Subsequent calls to the pretty printer shouldn't use this style.  */
-  cxx_pp->flags &= ~pp_c_flag_gnu_v3;
-  return name;
-}
-
-/* Generate the three forms of printable names for cxx_printable_name.  */
-
-const char *
-lang_decl_name (tree decl, int v, bool translate)
-{
-  if (v >= 2)
-    return (translate
-	    ? decl_as_string_translate (decl, TFF_DECL_SPECIFIERS)
-	    : decl_as_string (decl, TFF_DECL_SPECIFIERS));
-
-  reinit_cxx_pp ();
-  pp_translate_identifiers (cxx_pp) = translate;
-  if (v == 1
-      && (DECL_CLASS_SCOPE_P (decl)
-	  || (DECL_NAMESPACE_SCOPE_P (decl)
-	      && CP_DECL_CONTEXT (decl) != global_namespace)))
-    {
-      dump_type (cxx_pp, CP_DECL_CONTEXT (decl), TFF_PLAIN_IDENTIFIER);
-      pp_cxx_colon_colon (cxx_pp);
-    }
-
-  if (TREE_CODE (decl) == FUNCTION_DECL)
-    dump_function_name (cxx_pp, decl, TFF_PLAIN_IDENTIFIER);
-  else if ((DECL_NAME (decl) == NULL_TREE)
-           && TREE_CODE (decl) == NAMESPACE_DECL)
-    dump_decl (cxx_pp, decl, TFF_PLAIN_IDENTIFIER | TFF_UNQUALIFIED_NAME);
-  else
-    dump_decl (cxx_pp, DECL_NAME (decl), TFF_PLAIN_IDENTIFIER);
-
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-/* Return the location of a tree passed to %+ formats.  */
-
-location_t
-location_of (tree t)
-{
-  if (TYPE_P (t))
-    {
-      t = TYPE_MAIN_DECL (t);
-      if (t == NULL_TREE)
-	return input_location;
-    }
-  else if (TREE_CODE (t) == OVERLOAD)
-    t = OVL_FIRST (t);
-
-  if (DECL_P (t))
-    return DECL_SOURCE_LOCATION (t);
-  if (TREE_CODE (t) == DEFERRED_PARSE)
-    return defparse_location (t);
-  return cp_expr_loc_or_input_loc (t);
-}
-
-/* Now the interfaces from error et al to dump_type et al. Each takes an
-   on/off VERBOSE flag and supply the appropriate TFF_ flags to a dump_
-   function.  */
-
-static const char *
-decl_to_string (tree decl, int verbose)
-{
-  int flags = 0;
-
-  if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == RECORD_TYPE
-      || TREE_CODE (decl) == UNION_TYPE || TREE_CODE (decl) == ENUMERAL_TYPE)
-    flags = TFF_CLASS_KEY_OR_ENUM;
-  if (verbose)
-    flags |= TFF_DECL_SPECIFIERS;
-  else if (TREE_CODE (decl) == FUNCTION_DECL)
-    flags |= TFF_DECL_SPECIFIERS | TFF_RETURN_TYPE;
-  flags |= TFF_TEMPLATE_HEADER;
-
-  reinit_cxx_pp ();
-  dump_decl (cxx_pp, decl, flags);
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-const char *
-expr_to_string (tree decl)
-{
-  reinit_cxx_pp ();
-  dump_expr (cxx_pp, decl, 0);
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-static const char *
-fndecl_to_string (tree fndecl, int verbose)
-{
-  int flags;
-
-  flags = TFF_EXCEPTION_SPECIFICATION | TFF_DECL_SPECIFIERS
-    | TFF_TEMPLATE_HEADER;
-  if (verbose)
-    flags |= TFF_FUNCTION_DEFAULT_ARGUMENTS;
-  reinit_cxx_pp ();
-  dump_decl (cxx_pp, fndecl, flags);
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-
-static const char *
-code_to_string (enum tree_code c)
-{
-  return get_tree_code_name (c);
-}
-
-const char *
-language_to_string (enum languages c)
-{
-  switch (c)
-    {
-    case lang_c:
-      return "C";
-
-    case lang_cplusplus:
-      return "C++";
-
-    default:
-      gcc_unreachable ();
-    }
-  return NULL;
-}
-
-/* Return the proper printed version of a parameter to a C++ function.  */
-
-static const char *
-parm_to_string (int p)
-{
-  reinit_cxx_pp ();
-  if (p < 0)
-    pp_string (cxx_pp, "'this'");
-  else
-    pp_decimal_int (cxx_pp, p + 1);
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-static const char *
-op_to_string (bool assop, enum tree_code p)
-{
-  tree id = ovl_op_identifier (assop, p);
-  return id ? IDENTIFIER_POINTER (id) : M_("<unknown>");
-}
-
-/* Return a GC-allocated representation of type TYP, with verbosity VERBOSE.
-
-   If QUOTE is non-NULL and if *QUOTE is true, then quotes are added to the
-   string in appropriate places, and *QUOTE is written to with false
-   to suppress pp_format's trailing close quote so that e.g.
-     foo_typedef {aka underlying_foo} {enum}
-   can be printed by "%qT" as:
-     `foo_typedef' {aka `underlying_foo'} {enum}
-   rather than:
-     `foo_typedef {aka underlying_foo} {enum}'
-   When adding such quotes, if POSTPROCESSED is true (for handling %H and %I)
-   then a leading open quote will be added, whereas if POSTPROCESSED is false
-   (for handling %T) then any leading quote has already been added by
-   pp_format, or is not needed due to QUOTE being NULL (for template arguments
-   within %H and %I).
-
-   SHOW_COLOR is used to determine the colorization of any quotes that
-   are added.  */
-
-static const char *
-type_to_string (tree typ, int verbose, bool postprocessed, bool *quote,
-		bool show_color)
-{
-  int flags = 0;
-  if (verbose)
-    flags |= TFF_CLASS_KEY_OR_ENUM;
-  flags |= TFF_TEMPLATE_HEADER;
-
-  reinit_cxx_pp ();
-
-  if (postprocessed && quote && *quote)
-    pp_begin_quote (cxx_pp, show_color);
-
-  struct obstack *ob = pp_buffer (cxx_pp)->obstack;
-  int type_start, type_len;
-  type_start = obstack_object_size (ob);
-
-  dump_type (cxx_pp, typ, flags);
-
-  /* Remember the end of the initial dump.  */
-  type_len = obstack_object_size (ob) - type_start;
-
-  /* If we're printing a type that involves typedefs, also print the
-     stripped version.  But sometimes the stripped version looks
-     exactly the same, so we don't want it after all.  To avoid printing
-     it in that case, we play ugly obstack games.  */
-  if (typ && TYPE_P (typ) && typ != TYPE_CANONICAL (typ)
-      && !uses_template_parms (typ))
-    {
-      int aka_start, aka_len; char *p;
-      tree aka = strip_typedefs (typ, NULL, STF_USER_VISIBLE);
-      if (quote && *quote)
-	pp_end_quote (cxx_pp, show_color);
-      pp_string (cxx_pp, " {aka");
-      pp_cxx_whitespace (cxx_pp);
-      if (quote && *quote)
-	pp_begin_quote (cxx_pp, show_color);
-      /* And remember the start of the aka dump.  */
-      aka_start = obstack_object_size (ob);
-      dump_type (cxx_pp, aka, flags);
-      aka_len = obstack_object_size (ob) - aka_start;
-      if (quote && *quote)
-	pp_end_quote (cxx_pp, show_color);
-      pp_right_brace (cxx_pp);
-      p = (char*)obstack_base (ob);
-      /* If they are identical, cut off the aka by unwinding the obstack.  */
-      if (type_len == aka_len
-	  && memcmp (p + type_start, p+aka_start, type_len) == 0)
-	{
-	  /* We can't add a '\0' here, since we may be adding a closing quote
-	     below, and it would be hidden by the '\0'.
-	     Instead, manually unwind the current object within the obstack
-	     so that the insertion point is at the end of the type, before
-	     the "' {aka".  */
-	  int delta = type_start + type_len - obstack_object_size (ob);
-	  gcc_assert (delta <= 0);
-	  obstack_blank_fast (ob, delta);
-	}
-      else
-	if (quote)
-	  /* No further closing quotes are needed.  */
-	  *quote = false;
-    }
-
-  if (quote && *quote)
-    {
-      pp_end_quote (cxx_pp, show_color);
-      *quote = false;
-    }
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-static const char *
-args_to_string (tree p, int verbose)
-{
-  int flags = 0;
-  if (verbose)
-    flags |= TFF_CLASS_KEY_OR_ENUM;
-
-  if (p == NULL_TREE)
-    return "";
-
-  if (TYPE_P (TREE_VALUE (p)))
-    return type_as_string_translate (p, flags);
-
-  reinit_cxx_pp ();
-  for (; p; p = TREE_CHAIN (p))
-    {
-      if (null_node_p (TREE_VALUE (p)))
-	pp_cxx_ws_string (cxx_pp, "NULL");
-      else
-	dump_type (cxx_pp, error_type (TREE_VALUE (p)), flags);
-      if (TREE_CHAIN (p))
-	pp_separate_with_comma (cxx_pp);
-    }
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-/* Pretty-print a deduction substitution (from deduction_tsubst_fntype).  P
-   is a TREE_LIST with purpose the TEMPLATE_DECL, value the template
-   arguments.  */
-
-static const char *
-subst_to_string (tree p)
-{
-  tree decl = TREE_PURPOSE (p);
-  tree targs = TREE_VALUE (p);
-  tree tparms = DECL_TEMPLATE_PARMS (decl);
-  int flags = (TFF_DECL_SPECIFIERS|TFF_TEMPLATE_HEADER
-	       |TFF_NO_TEMPLATE_BINDINGS);
-
-  if (p == NULL_TREE)
-    return "";
-
-  reinit_cxx_pp ();
-  dump_template_decl (cxx_pp, TREE_PURPOSE (p), flags);
-  dump_substitution (cxx_pp, NULL, tparms, targs, /*flags=*/0);
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-static const char *
-cv_to_string (tree p, int v)
-{
-  reinit_cxx_pp ();
-  cxx_pp->padding = v ? pp_before : pp_none;
-  pp_cxx_cv_qualifier_seq (cxx_pp, p);
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-static const char *
-eh_spec_to_string (tree p, int /*v*/)
-{
-  int flags = 0;
-  reinit_cxx_pp ();
-  dump_exception_spec (cxx_pp, p, flags);
-  return pp_ggc_formatted_text (cxx_pp);
-}
-
-/* Langhook for print_error_function.  */
-void
-cxx_print_error_function (diagnostic_context *context, const char *file,
-			  diagnostic_info *diagnostic)
-{
-  char *prefix;
-  if (file)
-    prefix = xstrdup (file);
-  else
-    prefix = NULL;
-  lhd_print_error_function (context, file, diagnostic);
-  pp_set_prefix (context->printer, prefix);
-  maybe_print_instantiation_context (context);
-}
-
-static void
-cp_diagnostic_starter (diagnostic_context *context,
-		       diagnostic_info *diagnostic)
-{
-  diagnostic_report_current_module (context, diagnostic_location (diagnostic));
-  cp_print_error_function (context, diagnostic);
-  maybe_print_instantiation_context (context);
-  maybe_print_constexpr_context (context);
-  maybe_print_constraint_context (context);
-  pp_set_prefix (context->printer, diagnostic_build_prefix (context,
-								 diagnostic));
-}
-
-/* Print current function onto BUFFER, in the process of reporting
-   a diagnostic message.  Called from cp_diagnostic_starter.  */
-static void
-cp_print_error_function (diagnostic_context *context,
-			 diagnostic_info *diagnostic)
-{
-  /* If we are in an instantiation context, current_function_decl is likely
-     to be wrong, so just rely on print_instantiation_full_context.  */
-  if (current_instantiation ())
-    return;
-  /* The above is true for constraint satisfaction also.  */
-  if (current_failed_constraint)
-    return;
-  if (diagnostic_last_function_changed (context, diagnostic))
-    {
-      char *old_prefix = pp_take_prefix (context->printer);
-      const char *file = LOCATION_FILE (diagnostic_location (diagnostic));
-      tree abstract_origin = diagnostic_abstract_origin (diagnostic);
-      char *new_prefix = (file && abstract_origin == NULL)
-			 ? file_name_as_prefix (context, file) : NULL;
-
-      pp_set_prefix (context->printer, new_prefix);
-
-      if (current_function_decl == NULL)
-	pp_string (context->printer, _("At global scope:"));
-      else
-	{
-	  tree fndecl, ao;
-
-	  if (abstract_origin)
-	    {
-	      ao = BLOCK_ABSTRACT_ORIGIN (abstract_origin);
-	      gcc_assert (TREE_CODE (ao) == FUNCTION_DECL);
-	      fndecl = ao;
-	    }
-	  else
-	    fndecl = current_function_decl;
-
-	  pp_printf (context->printer, function_category (fndecl),
-		     cxx_printable_name_translate (fndecl, 2));
-
-	  while (abstract_origin)
-	    {
-	      location_t *locus;
-	      tree block = abstract_origin;
-
-	      locus = &BLOCK_SOURCE_LOCATION (block);
-	      fndecl = NULL;
-	      block = BLOCK_SUPERCONTEXT (block);
-	      while (block && TREE_CODE (block) == BLOCK
-		     && BLOCK_ABSTRACT_ORIGIN (block))
-		{
-		  ao = BLOCK_ABSTRACT_ORIGIN (block);
-		  if (TREE_CODE (ao) == FUNCTION_DECL)
-		    {
-		      fndecl = ao;
-		      break;
-		    }
-		  else if (TREE_CODE (ao) != BLOCK)
-		    break;
-
-		  block = BLOCK_SUPERCONTEXT (block);
-		}
-	      if (fndecl)
-		abstract_origin = block;
-	      else
-		{
-		  while (block && TREE_CODE (block) == BLOCK)
-		    block = BLOCK_SUPERCONTEXT (block);
-
-		  if (block && TREE_CODE (block) == FUNCTION_DECL)
-		    fndecl = block;
-		  abstract_origin = NULL;
-		}
-	      if (fndecl)
-		{
-		  expanded_location s = expand_location (*locus);
-		  pp_character (context->printer, ',');
-		  pp_newline (context->printer);
-		  if (s.file != NULL)
-		    {
-		      if (context->show_column && s.column != 0)
-			pp_printf (context->printer,
-				   _("    inlined from %qs at %r%s:%d:%d%R"),
-				   cxx_printable_name_translate (fndecl, 2),
-				   "locus", s.file, s.line, s.column);
-		      else
-			pp_printf (context->printer,
-				   _("    inlined from %qs at %r%s:%d%R"),
-				   cxx_printable_name_translate (fndecl, 2),
-				   "locus", s.file, s.line);
-
-		    }
-		  else
-		    pp_printf (context->printer, _("    inlined from %qs"),
-			       cxx_printable_name_translate (fndecl, 2));
-		}
-	    }
-	  pp_character (context->printer, ':');
-	}
-      pp_newline (context->printer);
-
-      diagnostic_set_last_function (context, diagnostic);
-      pp_destroy_prefix (context->printer);
-      context->printer->prefix = old_prefix;
-    }
-}
-
-/* Returns a description of FUNCTION using standard terminology.  The
-   result is a format string of the form "In CATEGORY %qs".  */
-static const char *
-function_category (tree fn)
-{
-  /* We can get called from the middle-end for diagnostics of function
-     clones.  Make sure we have language specific information before
-     dereferencing it.  */
-  if (DECL_LANG_SPECIFIC (STRIP_TEMPLATE (fn))
-      && DECL_FUNCTION_MEMBER_P (fn))
-    {
-      if (DECL_STATIC_FUNCTION_P (fn))
-	return _("In static member function %qs");
-      else if (DECL_COPY_CONSTRUCTOR_P (fn))
-	return _("In copy constructor %qs");
-      else if (DECL_CONSTRUCTOR_P (fn))
-	return _("In constructor %qs");
-      else if (DECL_DESTRUCTOR_P (fn))
-	return _("In destructor %qs");
-      else if (LAMBDA_FUNCTION_P (fn))
-	return _("In lambda function");
-      else
-	return _("In member function %qs");
-    }
-  else
-    return _("In function %qs");
-}
-
-/* Disable warnings about missing quoting in GCC diagnostics for
-   the pp_verbatim calls.  Their format strings deliberately don't
-   follow GCC diagnostic conventions.  */
-#if __GNUC__ >= 10
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wformat-diag"
-#endif
-
-/* Report the full context of a current template instantiation,
-   onto BUFFER.  */
-static void
-print_instantiation_full_context (diagnostic_context *context)
-{
-  struct tinst_level *p = current_instantiation ();
-  location_t location = input_location;
-
-  if (p)
-    {
-      pp_verbatim (context->printer,
-		   p->list_p ()
-		   ? _("%s: In substitution of %qS:\n")
-		   : _("%s: In instantiation of %q#D:\n"),
-		   LOCATION_FILE (location),
-		   p->get_node ());
-
-      location = p->locus;
-      p = p->next;
-    }
-
-  print_instantiation_partial_context (context, p, location);
-}
-
-/* Helper function of print_instantiation_partial_context() that
-   prints a single line of instantiation context.  */
-
-static void
-print_instantiation_partial_context_line (diagnostic_context *context,
-					  struct tinst_level *t,
-					  location_t loc, bool recursive_p)
-{
-  if (loc == UNKNOWN_LOCATION)
-    return;
-
-  expanded_location xloc = expand_location (loc);
-
-  if (context->show_column)
-    pp_verbatim (context->printer, _("%r%s:%d:%d:%R   "),
-		 "locus", xloc.file, xloc.line, xloc.column);
-  else
-    pp_verbatim (context->printer, _("%r%s:%d:%R   "),
-		 "locus", xloc.file, xloc.line);
-
-  if (t != NULL)
-    {
-      if (t->list_p ())
-	pp_verbatim (context->printer,
-		     recursive_p
-		     ? _("recursively required by substitution of %qS\n")
-		     : _("required by substitution of %qS\n"),
-		     t->get_node ());
-      else
-	pp_verbatim (context->printer,
-		     recursive_p
-		     ? _("recursively required from %q#D\n")
-		     : _("required from %q#D\n"),
-		     t->get_node ());
-    }
-  else
-    {
-      pp_verbatim (context->printer,
-		   recursive_p
-		   ? _("recursively required from here\n")
-		   : _("required from here\n"));
-    }
-}
-
-/* Same as print_instantiation_full_context but less verbose.  */
-
-static void
-print_instantiation_partial_context (diagnostic_context *context,
-				     struct tinst_level *t0, location_t loc)
-{
-  struct tinst_level *t;
-  int n_total = 0;
-  int n;
-  location_t prev_loc = loc;
-
-  for (t = t0; t != NULL; t = t->next)
-    if (prev_loc != t->locus)
-      {
-	prev_loc = t->locus;
-	n_total++;
-      }
-
-  t = t0;
-
-  if (template_backtrace_limit
-      && n_total > template_backtrace_limit) 
-    {
-      int skip = n_total - template_backtrace_limit;
-      int head = template_backtrace_limit / 2;
-
-      /* Avoid skipping just 1.  If so, skip 2.  */
-      if (skip == 1)
-       {
-         skip = 2;
-         head = (template_backtrace_limit - 1) / 2;
-       }
-     
-      for (n = 0; n < head; n++)
-	{
-	  gcc_assert (t != NULL);
-	  if (loc != t->locus)
-	    print_instantiation_partial_context_line (context, t, loc,
-						      /*recursive_p=*/false);
-	  loc = t->locus;
-	  t = t->next;
-	}
-      if (t != NULL && skip > 0)
-	{
-	  expanded_location xloc;
-	  xloc = expand_location (loc);
-	  if (context->show_column)
-	    pp_verbatim (context->printer,
-			 _("%r%s:%d:%d:%R   [ skipping %d instantiation "
-			   "contexts, use -ftemplate-backtrace-limit=0 to "
-			   "disable ]\n"),
-			 "locus", xloc.file, xloc.line, xloc.column, skip);
-	  else
-	    pp_verbatim (context->printer,
-			 _("%r%s:%d:%R   [ skipping %d instantiation "
-			   "contexts, use -ftemplate-backtrace-limit=0 to "
-			   "disable ]\n"),
-			 "locus", xloc.file, xloc.line, skip);
-	  
-	  do {
-	    loc = t->locus;
-	    t = t->next;
-	  } while (t != NULL && --skip > 0);
-	}
-    }
-  
-  while (t != NULL)
-    {
-      while (t->next != NULL && t->locus == t->next->locus)
-	{
-	  loc = t->locus;
-	  t = t->next;
-	}
-      print_instantiation_partial_context_line (context, t, loc,
-						t->locus == loc);
-      loc = t->locus;
-      t = t->next;
-    }
-  print_instantiation_partial_context_line (context, NULL, loc,
-					    /*recursive_p=*/false);
-}
-
-/* Called from cp_thing to print the template context for an error.  */
-static void
-maybe_print_instantiation_context (diagnostic_context *context)
-{
-  if (!problematic_instantiation_changed () || current_instantiation () == 0)
-    return;
-
-  record_last_problematic_instantiation ();
-  print_instantiation_full_context (context);
-}
-
-/* Report what constexpr call(s) we're trying to expand, if any.  */
-
-void
-maybe_print_constexpr_context (diagnostic_context *context)
-{
-  vec<tree> call_stack = cx_error_context ();
-  unsigned ix;
-  tree t;
-
-  FOR_EACH_VEC_ELT (call_stack, ix, t)
-    {
-      expanded_location xloc = expand_location (EXPR_LOCATION (t));
-      const char *s = expr_as_string (t, 0);
-      if (context->show_column)
-	pp_verbatim (context->printer,
-		     _("%r%s:%d:%d:%R   in %<constexpr%> expansion of %qs"),
-		     "locus", xloc.file, xloc.line, xloc.column, s);
-      else
-	pp_verbatim (context->printer,
-		     _("%r%s:%d:%R   in %<constexpr%> expansion of %qs"),
-		     "locus", xloc.file, xloc.line, s);
-      pp_newline (context->printer);
-    }
-}
-
-
-static void
-print_location (diagnostic_context *context, location_t loc)
-{
-  expanded_location xloc = expand_location (loc);
-  if (context->show_column)
-    pp_verbatim (context->printer, _("%r%s:%d:%d:%R   "),
-                 "locus", xloc.file, xloc.line, xloc.column);
-  else
-    pp_verbatim (context->printer, _("%r%s:%d:%R   "),
-                 "locus", xloc.file, xloc.line);
-}
-
-static void
-print_constrained_decl_info (diagnostic_context *context, tree decl)
-{
-  print_location (context, DECL_SOURCE_LOCATION (decl));
-  pp_verbatim (context->printer, "required by the constraints of %q#D\n", decl);
-}
-
-static void
-print_concept_check_info (diagnostic_context *context, tree expr, tree map, tree args)
-{
-  gcc_assert (concept_check_p (expr));
-
-  tree id = unpack_concept_check (expr);
-  tree tmpl = TREE_OPERAND (id, 0);
-  if (OVL_P (tmpl))
-    tmpl = OVL_FIRST (tmpl);
-
-  print_location (context, DECL_SOURCE_LOCATION (tmpl));
-
-  cxx_pretty_printer *pp = (cxx_pretty_printer *)context->printer;
-  pp_verbatim (pp, "required for the satisfaction of %qE", expr);
-  if (map && map != error_mark_node)
-    {
-      tree subst_map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE);
-      pp_cxx_parameter_mapping (pp, (subst_map != error_mark_node
-				     ? subst_map : map));
-    }
-  pp_newline (pp);
-}
-
-/* Diagnose the entry point into the satisfaction error. Returns the next
-   context, if any.  */
-
-static tree
-print_constraint_context_head (diagnostic_context *context, tree cxt, tree args)
-{
-  tree src = TREE_VALUE (cxt);
-  if (!src)
-    {
-      print_location (context, input_location);
-      pp_verbatim (context->printer, "required for constraint satisfaction\n");
-      return NULL_TREE;
-    }
-  if (DECL_P (src))
-    {
-      print_constrained_decl_info (context, src);
-      return NULL_TREE;
-    }
-  else
-    {
-      print_concept_check_info (context, src, TREE_PURPOSE (cxt), args);
-      return TREE_CHAIN (cxt);
-    }
-}
-
-static void
-print_requires_expression_info (diagnostic_context *context, tree constr, tree args)
-{
-
-  tree expr = ATOMIC_CONSTR_EXPR (constr);
-  tree map = ATOMIC_CONSTR_MAP (constr);
-  map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE);
-  if (map == error_mark_node)
-    return;
-
-  print_location (context, cp_expr_loc_or_input_loc (expr));
-  pp_verbatim (context->printer, "in requirements ");
-
-  tree parms = TREE_OPERAND (expr, 0);
-  if (parms)
-    pp_verbatim (context->printer, "with ");
-  while (parms)
-    {
-      pp_verbatim (context->printer, "%q#D", parms);
-      if (TREE_CHAIN (parms))
-        pp_separate_with_comma ((cxx_pretty_printer *)context->printer);
-      parms = TREE_CHAIN (parms);
-    }
-  pp_cxx_parameter_mapping ((cxx_pretty_printer *)context->printer, map);
-
-  pp_verbatim (context->printer, "\n");
-}
-
-void
-maybe_print_single_constraint_context (diagnostic_context *context, tree failed)
-{
-  if (!failed)
-    return;
-
-  tree constr = TREE_VALUE (failed);
-  if (!constr || constr == error_mark_node)
-    return;
-  tree cxt = CONSTR_CONTEXT (constr);
-  if (!cxt)
-    return;
-  tree args = TREE_PURPOSE (failed);
-
-  /* Print the stack of requirements.  */
-  cxt = print_constraint_context_head (context, cxt, args);
-  while (cxt && !DECL_P (TREE_VALUE (cxt)))
-    {
-      tree expr = TREE_VALUE (cxt);
-      tree map = TREE_PURPOSE (cxt);
-      print_concept_check_info (context, expr, map, args);
-      cxt = TREE_CHAIN (cxt);
-    }
-
-  /* For certain constraints, we can provide additional context.  */
-  if (TREE_CODE (constr) == ATOMIC_CONSTR
-      && TREE_CODE (ATOMIC_CONSTR_EXPR (constr)) == REQUIRES_EXPR)
-    print_requires_expression_info (context, constr, args);
-}
-
-void
-maybe_print_constraint_context (diagnostic_context *context)
-{
-  if (!current_failed_constraint)
-    return;
-
-  tree cur = current_failed_constraint;
-
-  /* Recursively print nested contexts.  */
-  current_failed_constraint = TREE_CHAIN (current_failed_constraint);
-  if (current_failed_constraint)
-    maybe_print_constraint_context (context);
-
-  /* Print this context.  */
-  maybe_print_single_constraint_context (context, cur);
-}
-
-/* Return true iff TYPE_A and TYPE_B are template types that are
-   meaningful to compare.  */
-
-static bool
-comparable_template_types_p (tree type_a, tree type_b)
-{
-  if (!CLASS_TYPE_P (type_a))
-    return false;
-  if (!CLASS_TYPE_P (type_b))
-    return false;
-
-  tree tinfo_a = TYPE_TEMPLATE_INFO (type_a);
-  tree tinfo_b = TYPE_TEMPLATE_INFO (type_b);
-  if (!tinfo_a || !tinfo_b)
-    return false;
-
-  return TI_TEMPLATE (tinfo_a) == TI_TEMPLATE (tinfo_b);
-}
-
-/* Start a new line indented by SPC spaces on PP.  */
-
-static void
-newline_and_indent (pretty_printer *pp, int spc)
-{
-  pp_newline (pp);
-  for (int i = 0; i < spc; i++)
-    pp_space (pp);
-}
-
-/* Generate a GC-allocated string for ARG, an expression or type.  */
-
-static const char *
-arg_to_string (tree arg, bool verbose)
-{
-  if (TYPE_P (arg))
-    return type_to_string (arg, verbose, true, NULL, false);
-  else
-    return expr_to_string (arg);
-}
-
-/* Subroutine to type_to_string_with_compare and
-   print_template_tree_comparison.
-
-   Print a representation of ARG (an expression or type) to PP,
-   colorizing it as "type-diff" if PP->show_color.  */
-
-static void
-print_nonequal_arg (pretty_printer *pp, tree arg, bool verbose)
-{
-  pp_printf (pp, "%r%s%R",
-	     "type-diff",
-	     (arg
-	      ? arg_to_string (arg, verbose)
-	      : G_("(no argument)")));
-}
-
-/* Recursively print template TYPE_A to PP, as compared to template TYPE_B.
-
-   The types must satisfy comparable_template_types_p.
-
-   If INDENT is 0, then this is equivalent to type_to_string (TYPE_A), but
-   potentially colorizing/eliding in comparison with TYPE_B.
-
-   For example given types:
-     vector<map<int,double>>
-   and
-     vector<map<int,float>>
-   then the result on PP would be:
-     vector<map<[...],double>>
-   with type elision, and:
-     vector<map<int,double>>
-   without type elision.
-
-   In both cases the parts of TYPE that differ from PEER will be colorized
-   if pp_show_color (pp) is true.  In the above example, this would be
-   "double".
-
-   If INDENT is non-zero, then the types are printed in a tree-like form
-   which shows both types.  In the above example, the result on PP would be:
-
-     vector<
-       map<
-         [...],
-         [double != float]>>
-
-   and without type-elision would be:
-
-     vector<
-       map<
-         int,
-         [double != float]>>
-
-   As before, the differing parts of the types are colorized if
-   pp_show_color (pp) is true ("double" and "float" in this example).
-
-   Template arguments in which both types are using the default arguments
-   are not printed; if at least one of the two types is using a non-default
-   argument, then that argument is printed (or both arguments for the
-   tree-like print format).  */
-
-static void
-print_template_differences (pretty_printer *pp, tree type_a, tree type_b,
-			    bool verbose, int indent)
-{
-  if (indent)
-    newline_and_indent (pp, indent);
-
-  tree tinfo_a = TYPE_TEMPLATE_INFO (type_a);
-  tree tinfo_b = TYPE_TEMPLATE_INFO (type_b);
-
-  pp_printf (pp, "%s<",
-	     IDENTIFIER_POINTER (DECL_NAME (TI_TEMPLATE (tinfo_a))));
-
-  tree args_a = TI_ARGS (tinfo_a);
-  tree args_b = TI_ARGS (tinfo_b);
-  gcc_assert (TREE_CODE (args_a) == TREE_VEC);
-  gcc_assert (TREE_CODE (args_b) == TREE_VEC);
-  int flags = 0;
-  int len_a = get_non_default_template_args_count (args_a, flags);
-  args_a = INNERMOST_TEMPLATE_ARGS (args_a);
-  int len_b = get_non_default_template_args_count (args_b, flags);
-  args_b = INNERMOST_TEMPLATE_ARGS (args_b);
-  /* Determine the maximum range of args for which non-default template args
-     were used; beyond this, only default args (if any) were used, and so
-     they will be equal from this point onwards.
-     One of the two peers might have used default arguments within this
-     range, but the other will be using non-default arguments, and so
-     it's more readable to print both within this range, to highlight
-     the differences.  */
-  int len_max = MAX (len_a, len_b);
-  gcc_assert (TREE_CODE (args_a) == TREE_VEC);
-  gcc_assert (TREE_CODE (args_b) == TREE_VEC);
-  for (int idx = 0; idx < len_max; idx++)
-    {
-      if (idx)
-	pp_character (pp, ',');
-
-      tree arg_a = TREE_VEC_ELT (args_a, idx);
-      tree arg_b = TREE_VEC_ELT (args_b, idx);
-      if (arg_a == arg_b)
-	{
-	  if (indent)
-	    newline_and_indent (pp, indent + 2);
-	  /* Can do elision here, printing "[...]".  */
-	  if (flag_elide_type)
-	    pp_string (pp, G_("[...]"));
-	  else
-	    pp_string (pp, arg_to_string (arg_a, verbose));
-	}
-      else
-	{
-	  int new_indent = indent ? indent + 2 : 0;
-	  if (comparable_template_types_p (arg_a, arg_b))
-	    print_template_differences (pp, arg_a, arg_b, verbose, new_indent);
-	  else
-	    if (indent)
-	      {
-		newline_and_indent (pp, indent + 2);
-		pp_character (pp, '[');
-		print_nonequal_arg (pp, arg_a, verbose);
-		pp_string (pp, " != ");
-		print_nonequal_arg (pp, arg_b, verbose);
-		pp_character (pp, ']');
-	      }
-	    else
-	      print_nonequal_arg (pp, arg_a, verbose);
-	}
-    }
-  pp_printf (pp, ">");
-}
-
-/* As type_to_string, but for a template, potentially colorizing/eliding
-   in comparison with PEER.
-   For example, if TYPE is map<int,double> and PEER is map<int,int>,
-   then the resulting string would be:
-     map<[...],double>
-   with type elision, and:
-     map<int,double>
-   without type elision.
-
-   In both cases the parts of TYPE that differ from PEER will be colorized
-   if SHOW_COLOR is true.  In the above example, this would be "double".
-
-   Template arguments in which both types are using the default arguments
-   are not printed; if at least one of the two types is using a non-default
-   argument, then both arguments are printed.
-
-   The resulting string is in a GC-allocated buffer.  */
-
-static const char *
-type_to_string_with_compare (tree type, tree peer, bool verbose,
-			     bool show_color)
-{
-  pretty_printer inner_pp;
-  pretty_printer *pp = &inner_pp;
-  pp_show_color (pp) = show_color;
-
-  print_template_differences (pp, type, peer, verbose, 0);
-  return pp_ggc_formatted_text (pp);
-}
-
-/* Recursively print a tree-like comparison of TYPE_A and TYPE_B to PP,
-   indented by INDENT spaces.
-
-   For example given types:
-
-     vector<map<int,double>>
-
-   and
-
-     vector<map<double,float>>
-
-   the output with type elision would be:
-
-     vector<
-       map<
-         [...],
-         [double != float]>>
-
-   and without type-elision would be:
-
-     vector<
-       map<
-         int,
-         [double != float]>>
-
-   TYPE_A and TYPE_B must both be comparable template types
-   (as per comparable_template_types_p).
-
-   Template arguments in which both types are using the default arguments
-   are not printed; if at least one of the two types is using a non-default
-   argument, then both arguments are printed.  */
-
-static void
-print_template_tree_comparison (pretty_printer *pp, tree type_a, tree type_b,
-				bool verbose, int indent)
-{
-  print_template_differences (pp, type_a, type_b, verbose, indent);
-}
-
-/* Subroutine for use in a format_postprocessor::handle
-   implementation.  Adds a chunk to the end of
-   formatted output, so that it will be printed
-   by pp_output_formatted_text.  */
-
-static void
-append_formatted_chunk (pretty_printer *pp, const char *content)
-{
-  output_buffer *buffer = pp_buffer (pp);
-  struct chunk_info *chunk_array = buffer->cur_chunk_array;
-  const char **args = chunk_array->args;
-
-  unsigned int chunk_idx;
-  for (chunk_idx = 0; args[chunk_idx]; chunk_idx++)
-    ;
-  args[chunk_idx++] = content;
-  args[chunk_idx] = NULL;
-}
-
-/* Create a copy of CONTENT, with quotes added, and,
-   potentially, with colorization.
-   No escaped is performed on CONTENT.
-   The result is in a GC-allocated buffer. */
-
-static const char *
-add_quotes (const char *content, bool show_color)
-{
-  pretty_printer tmp_pp;
-  pp_show_color (&tmp_pp) = show_color;
-
-  /* We have to use "%<%s%>" rather than "%qs" here in order to avoid
-     quoting colorization bytes within the results and using either
-     pp_quote or pp_begin_quote doesn't work the same.  */
-  pp_printf (&tmp_pp, "%<%s%>", content);
-
-  return pp_ggc_formatted_text (&tmp_pp);
-}
-
-#if __GNUC__ >= 10
-#  pragma GCC diagnostic pop
-#endif
-
-/* If we had %H and %I, and hence deferred printing them,
-   print them now, storing the result into the chunk_info
-   for pp_format.  Quote them if 'q' was provided.
-   Also print the difference in tree form, adding it as
-   an additional chunk.  */
-
-void
-cxx_format_postprocessor::handle (pretty_printer *pp)
-{
-  /* If we have one of %H and %I, the other should have
-     been present.  */
-  if (m_type_a.m_tree || m_type_b.m_tree)
-    {
-      /* Avoid reentrancy issues by working with a copy of
-	 m_type_a and m_type_b, resetting them now.  */
-      deferred_printed_type type_a = m_type_a;
-      deferred_printed_type type_b = m_type_b;
-      m_type_a = deferred_printed_type ();
-      m_type_b = deferred_printed_type ();
-
-      gcc_assert (type_a.m_buffer_ptr);
-      gcc_assert (type_b.m_buffer_ptr);
-
-      bool show_color = pp_show_color (pp);
-
-      const char *type_a_text;
-      const char *type_b_text;
-
-      if (comparable_template_types_p (type_a.m_tree, type_b.m_tree))
-	{
-	  type_a_text
-	    = type_to_string_with_compare (type_a.m_tree, type_b.m_tree,
-					   type_a.m_verbose, show_color);
-	  type_b_text
-	    = type_to_string_with_compare (type_b.m_tree, type_a.m_tree,
-					   type_b.m_verbose, show_color);
-
-	  if (flag_diagnostics_show_template_tree)
-	    {
-	      pretty_printer inner_pp;
-	      pp_show_color (&inner_pp) = pp_show_color (pp);
-	      print_template_tree_comparison
-		(&inner_pp, type_a.m_tree, type_b.m_tree, type_a.m_verbose, 2);
-	      append_formatted_chunk (pp, pp_ggc_formatted_text (&inner_pp));
-	    }
-	}
-      else
-	{
-	  /* If the types were not comparable (or if only one of %H/%I was
-	     provided), they are printed normally, and no difference tree
-	     is printed.  */
-	  type_a_text = type_to_string (type_a.m_tree, type_a.m_verbose,
-					true, &type_a.m_quote, show_color);
-	  type_b_text = type_to_string (type_b.m_tree, type_b.m_verbose,
-					true, &type_b.m_quote, show_color);
-	}
-
-      if (type_a.m_quote)
-	type_a_text = add_quotes (type_a_text, show_color);
-      *type_a.m_buffer_ptr = type_a_text;
-
-       if (type_b.m_quote)
-	type_b_text = add_quotes (type_b_text, show_color);
-      *type_b.m_buffer_ptr = type_b_text;
-   }
-}
-
-/* Subroutine for handling %H and %I, to support i18n of messages like:
-
-    error_at (loc, "could not convert %qE from %qH to %qI",
-	       expr, type_a, type_b);
-
-   so that we can print things like:
-
-     could not convert 'foo' from 'map<int,double>' to 'map<int,int>'
-
-   and, with type-elision:
-
-     could not convert 'foo' from 'map<[...],double>' to 'map<[...],int>'
-
-   (with color-coding of the differences between the types).
-
-   The %H and %I format codes are peers: both must be present,
-   and they affect each other.  Hence to handle them, we must
-   delay printing until we have both, deferring the printing to
-   pretty_printer's m_format_postprocessor hook.
-
-   This is called in phase 2 of pp_format, when it is accumulating
-   a series of formatted chunks.  We stash the location of the chunk
-   we're meant to have written to, so that we can write to it in the
-   m_format_postprocessor hook.
-
-   We also need to stash whether a 'q' prefix was provided (the QUOTE
-   param)  so that we can add the quotes when writing out the delayed
-   chunk.  */
-
-static void
-defer_phase_2_of_type_diff (deferred_printed_type *deferred,
-			    tree type, const char **buffer_ptr,
-			    bool verbose, bool quote)
-{
-  gcc_assert (deferred->m_tree == NULL_TREE);
-  gcc_assert (deferred->m_buffer_ptr == NULL);
-  *deferred = deferred_printed_type (type, buffer_ptr, verbose, quote);
-}
-
-
-/* Called from output_format -- during diagnostic message processing --
-   to handle C++ specific format specifier with the following meanings:
-   %A   function argument-list.
-   %C	tree code.
-   %D   declaration.
-   %E   expression.
-   %F   function declaration.
-   %G   gcall *
-   %H   type difference (from).
-   %I   type difference (to).
-   %K   tree
-   %L	language as used in extern "lang".
-   %O	binary operator.
-   %P   function parameter whose position is indicated by an integer.
-   %Q	assignment operator.
-   %S   substitution (template + args)
-   %T   type.
-   %V   cv-qualifier.
-   %X   exception-specification.  */
-static bool
-cp_printer (pretty_printer *pp, text_info *text, const char *spec,
-	    int precision, bool wide, bool set_locus, bool verbose,
-	    bool *quoted, const char **buffer_ptr)
-{
-  gcc_assert (pp->m_format_postprocessor);
-  cxx_format_postprocessor *postprocessor
-    = static_cast <cxx_format_postprocessor *> (pp->m_format_postprocessor);
-
-  const char *result;
-  tree t = NULL;
-#define next_tree    (t = va_arg (*text->args_ptr, tree))
-#define next_tcode   ((enum tree_code) va_arg (*text->args_ptr, int))
-#define next_lang    ((enum languages) va_arg (*text->args_ptr, int))
-#define next_int     va_arg (*text->args_ptr, int)
-
-  if (precision != 0 || wide)
-    return false;
-
-  switch (*spec)
-    {
-    case 'A': result = args_to_string (next_tree, verbose);	break;
-    case 'C': result = code_to_string (next_tcode);		break;
-    case 'D':
-      {
-	tree temp = next_tree;
-	if (VAR_P (temp)
-	    && DECL_HAS_DEBUG_EXPR_P (temp))
-	  {
-	    temp = DECL_DEBUG_EXPR (temp);
-	    if (!DECL_P (temp))
-	      {
-		result = expr_to_string (temp);
-		break;
-	      }
-	  }
-	result = decl_to_string (temp, verbose);
-      }
-      break;
-    case 'E': result = expr_to_string (next_tree);		break;
-    case 'F': result = fndecl_to_string (next_tree, verbose);	break;
-    case 'G':
-      percent_G_format (text);
-      return true;
-    case 'H':
-      defer_phase_2_of_type_diff (&postprocessor->m_type_a, next_tree,
-				  buffer_ptr, verbose, *quoted);
-      return true;
-    case 'I':
-      defer_phase_2_of_type_diff (&postprocessor->m_type_b, next_tree,
-				  buffer_ptr, verbose, *quoted);
-      return true;
-    case 'K':
-      t = va_arg (*text->args_ptr, tree);
-      percent_K_format (text, EXPR_LOCATION (t), TREE_BLOCK (t));
-      return true;
-    case 'L': result = language_to_string (next_lang);		break;
-    case 'O': result = op_to_string (false, next_tcode);	break;
-    case 'P': result = parm_to_string (next_int);		break;
-    case 'Q': result = op_to_string (true, next_tcode);		break;
-    case 'S': result = subst_to_string (next_tree);		break;
-    case 'T':
-      {
-	result = type_to_string (next_tree, verbose, false, quoted,
-				 pp_show_color (pp));
-      }
-      break;
-    case 'V': result = cv_to_string (next_tree, verbose);	break;
-    case 'X': result = eh_spec_to_string (next_tree, verbose);  break;
-
-    default:
-      return false;
-    }
-
-  pp_string (pp, result);
-  if (set_locus && t != NULL)
-    text->set_location (0, location_of (t), SHOW_RANGE_WITH_CARET);
-  return true;
-#undef next_tree
-#undef next_tcode
-#undef next_lang
-#undef next_int
-}
-
-/* Warn about the use of C++0x features when appropriate.  */
-void
-maybe_warn_cpp0x (cpp0x_warn_str str)
-{
-  if (cxx_dialect == cxx98)
-    switch (str)
-      {
-      case CPP0X_INITIALIZER_LISTS:
-	pedwarn (input_location, 0, 
-		 "extended initializer lists "
-		 "only available with %<-std=c++11%> or %<-std=gnu++11%>");
-	break;
-      case CPP0X_EXPLICIT_CONVERSION:
-	pedwarn (input_location, 0,
-		 "explicit conversion operators "
-		 "only available with %<-std=c++11%> or %<-std=gnu++11%>");
-	break;
-      case CPP0X_VARIADIC_TEMPLATES:
-	pedwarn (input_location, 0,
-		 "variadic templates "
-		 "only available with %<-std=c++11%> or %<-std=gnu++11%>");
-	break;
-      case CPP0X_LAMBDA_EXPR:
-	pedwarn (input_location, 0,
-		 "lambda expressions "
-		  "only available with %<-std=c++11%> or %<-std=gnu++11%>");
-	break;
-      case CPP0X_AUTO:
-	pedwarn (input_location, 0,
-		 "C++11 auto only available with %<-std=c++11%> or "
-		 "%<-std=gnu++11%>");
-	break;
-      case CPP0X_SCOPED_ENUMS:
-	pedwarn (input_location, 0,
-		 "scoped enums only available with %<-std=c++11%> or "
-		 "%<-std=gnu++11%>");
-	break;
-      case CPP0X_DEFAULTED_DELETED:
-	pedwarn (input_location, 0,
-		 "defaulted and deleted functions "
-		 "only available with %<-std=c++11%> or %<-std=gnu++11%>");
-	break;
-      case CPP0X_INLINE_NAMESPACES:
-	pedwarn (input_location, OPT_Wpedantic,
-		 "inline namespaces "
-		 "only available with %<-std=c++11%> or %<-std=gnu++11%>");
-	break;
-      case CPP0X_OVERRIDE_CONTROLS:
-	pedwarn (input_location, 0,
-		 "override controls (override/final) "
-		 "only available with %<-std=c++11%> or %<-std=gnu++11%>");
-        break;
-      case CPP0X_NSDMI:
-	pedwarn (input_location, 0,
-		 "non-static data member initializers "
-		 "only available with %<-std=c++11%> or %<-std=gnu++11%>");
-        break;
-      case CPP0X_USER_DEFINED_LITERALS:
-	pedwarn (input_location, 0,
-		 "user-defined literals "
-		 "only available with %<-std=c++11%> or %<-std=gnu++11%>");
-	break;
-      case CPP0X_DELEGATING_CTORS:
-	pedwarn (input_location, 0,
-		 "delegating constructors "
-		 "only available with %<-std=c++11%> or %<-std=gnu++11%>");
-        break;
-      case CPP0X_INHERITING_CTORS:
-	pedwarn (input_location, 0,
-		 "inheriting constructors "
-		 "only available with %<-std=c++11%> or %<-std=gnu++11%>");
-        break;
-      case CPP0X_ATTRIBUTES:
-	pedwarn (input_location, 0,
-		 "c++11 attributes "
-		 "only available with %<-std=c++11%> or %<-std=gnu++11%>");
-	break;
-      case CPP0X_REF_QUALIFIER:
-	pedwarn (input_location, 0,
-		 "ref-qualifiers "
-		 "only available with %<-std=c++11%> or %<-std=gnu++11%>");
-	break;
-      default:
-	gcc_unreachable ();
-      }
-}
-
-/* Warn about the use of variadic templates when appropriate.  */
-void
-maybe_warn_variadic_templates (void)
-{
-  maybe_warn_cpp0x (CPP0X_VARIADIC_TEMPLATES);
-}
-
-
-/* Issue an ISO C++98 pedantic warning at LOCATION, conditional on
-   option OPT with text GMSGID.  Use this function to report
-   diagnostics for constructs that are invalid C++98, but valid
-   C++0x.  */
-bool
-pedwarn_cxx98 (location_t location, int opt, const char *gmsgid, ...)
-{
-  diagnostic_info diagnostic;
-  va_list ap;
-  bool ret;
-  rich_location richloc (line_table, location);
-
-  va_start (ap, gmsgid);
-  diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
-		       (cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING);
-  diagnostic.option_index = opt;
-  ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
-  va_end (ap);
-  return ret;
-}
-
-/* Issue a diagnostic that NAME cannot be found in SCOPE.  DECL is what
-   we found when we tried to do the lookup.  LOCATION is the location of
-   the NAME identifier.  */
-
-void
-qualified_name_lookup_error (tree scope, tree name,
-			     tree decl, location_t location)
-{
-  if (scope == error_mark_node)
-    ; /* We already complained.  */
-  else if (TYPE_P (scope))
-    {
-      if (!COMPLETE_TYPE_P (scope))
-	error_at (location, "incomplete type %qT used in nested name specifier",
-		  scope);
-      else if (TREE_CODE (decl) == TREE_LIST)
-	{
-	  error_at (location, "reference to %<%T::%D%> is ambiguous",
-		    scope, name);
-	  print_candidates (decl);
-	}
-      else
-	{
-	  name_hint hint;
-	  if (SCOPED_ENUM_P (scope) && TREE_CODE (name) == IDENTIFIER_NODE)
-	    hint = suggest_alternative_in_scoped_enum (name, scope);
-	  if (const char *suggestion = hint.suggestion ())
-	    {
-	      gcc_rich_location richloc (location);
-	      richloc.add_fixit_replace (suggestion);
-	      error_at (&richloc,
-			"%qD is not a member of %qT; did you mean %qs?",
-			name, scope, suggestion);
-	    }
-	  else
-	    error_at (location, "%qD is not a member of %qT", name, scope);
-	}
-    }
-  else if (scope != global_namespace)
-    {
-      auto_diagnostic_group d;
-      bool emit_fixit = true;
-      name_hint hint
-	= suggest_alternative_in_explicit_scope (location, name, scope);
-      if (!hint)
-	{
-	  hint = suggest_alternatives_in_other_namespaces (location, name);
-	  /* "location" is just the location of the name, not of the explicit
-	     scope, and it's not easy to get at the latter, so we can't issue
-	     fix-it hints for the suggestion.  */
-	  emit_fixit = false;
-	}
-      if (const char *suggestion = hint.suggestion ())
-	{
-	  gcc_rich_location richloc (location);
-	  if (emit_fixit)
-	    richloc.add_fixit_replace (suggestion);
-	  error_at (&richloc, "%qD is not a member of %qD; did you mean %qs?",
-		    name, scope, suggestion);
-	}
-      else
-	error_at (location, "%qD is not a member of %qD", name, scope);
-    }
-  else
-    {
-      auto_diagnostic_group d;
-      name_hint hint = suggest_alternatives_for (location, name, true);
-      if (const char *suggestion = hint.suggestion ())
-	{
-	  gcc_rich_location richloc (location);
-	  richloc.add_fixit_replace (suggestion);
-	  error_at (&richloc,
-		    "%<::%D%> has not been declared; did you mean %qs?",
-		    name, suggestion);
-	}
-      else
-	error_at (location, "%<::%D%> has not been declared", name);
-    }
-}
-
-/* C++-specific implementation of range_label::get_text () vfunc for
-   range_label_for_type_mismatch.
-
-   Compare with print_template_differences above.  */
-
-label_text
-range_label_for_type_mismatch::get_text (unsigned /*range_idx*/) const
-{
-  if (m_labelled_type == NULL_TREE)
-    return label_text::borrow (NULL);
-
-  const bool verbose = false;
-  const bool show_color = false;
-
-  const char *result;
-  if (m_other_type
-      && comparable_template_types_p (m_labelled_type, m_other_type))
-    result = type_to_string_with_compare (m_labelled_type, m_other_type,
-					  verbose, show_color);
-  else
-    result = type_to_string (m_labelled_type, verbose, true, NULL, show_color);
-
-  /* Both of the above return GC-allocated buffers, so the caller mustn't
-     free them.  */
-  return label_text::borrow (result);
-}
+	      pp_cxx_righ
\ No newline at end of file
diff --git i/gcc/cp/module.cc w/gcc/cp/module.cc
index 3587dfcc925..176286cdd91 100644
--- i/gcc/cp/module.cc
+++ w/gcc/cp/module.cc
@@ -74,6 +74,11 @@  get_module (tree, module_state *, bool)
   return nullptr;
 }
 
+const char *
+module_name (unsigned, bool)
+{
+  return nullptr;
+}
 
 void
 mangle_module (int, bool)
@@ -102,6 +107,12 @@  get_originating_module (tree, bool)
   return 0;
 }
 
+unsigned
+get_importing_module (tree, bool)
+{
+  return 0;
+}
+
 bool
 module_may_redeclare (tree)
 {
diff --git i/gcc/cp/ptree.c w/gcc/cp/ptree.c
index f8d22082ba7..1e9fdf82e86 100644
--- i/gcc/cp/ptree.c
+++ w/gcc/cp/ptree.c
@@ -59,6 +59,42 @@  cxx_print_decl (FILE *file, tree node, int indent)
 
   bool need_indent = true;
 
+  if (TREE_CODE (node) == FUNCTION_DECL
+      || TREE_CODE (node) == VAR_DECL
+      || TREE_CODE (node) == TYPE_DECL
+      || TREE_CODE (node) == TEMPLATE_DECL
+      || TREE_CODE (node) == CONCEPT_DECL
+      || TREE_CODE (node) == NAMESPACE_DECL)
+    {
+      unsigned m = 0;
+      if (DECL_LANG_SPECIFIC (node) && DECL_MODULE_IMPORT_P (node))
+	m = get_importing_module (node, true);
+
+      if (const char *name = m == ~0u ? "" : module_name (m, true))
+	{
+	  if (need_indent)
+	    indent_to (file, indent + 3);
+	  fprintf (file, " module %d:%s", m, name);
+	  need_indent = false;
+	}
+
+      if (DECL_LANG_SPECIFIC (node) && DECL_MODULE_PURVIEW_P (node))
+	{
+	  if (need_indent)
+	    indent_to (file, indent + 3);
+	  fprintf (file, " purview");
+	  need_indent = false;
+	}
+    }
+
+  if (DECL_MODULE_EXPORT_P (node))
+    {
+      if (need_indent)
+	indent_to (file, indent + 3);
+      fprintf (file, " exported");
+      need_indent = false;
+    }
+
   if (DECL_EXTERNAL (node) && DECL_NOT_REALLY_EXTERN (node))
     {
       if (need_indent)