C++ template type diff printing
authorDavid Malcolm <dmalcolm@redhat.com>
Tue, 30 May 2017 20:38:14 +0000 (20:38 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Tue, 30 May 2017 20:38:14 +0000 (20:38 +0000)
gcc/ChangeLog:
* diagnostic-color.c (color_dict): Add "type-diff".
(parse_gcc_colors): Update comment.
* doc/invoke.texi (Diagnostic Message Formatting Options): Add
-fdiagnostics-show-template-tree and -fno-elide-type.
(GCC_COLORS): Add type-diff to example.
(type-diff=): New.
(-fdiagnostics-show-template-tree): New.
(-fno-elide-type): New.
* pretty-print.c (pp_format): Pass quote and formatters[argno] to
the pp_format_decoder callback.  Call any m_format_postprocessor's
"handle" method.
(pretty_printer::pretty_printer): Initialize
m_format_postprocessor.
(pretty_printer::~pretty_printer): Delete any
m_format_postprocessor.
* pretty-print.h (printer_fn): Add bool and const char **
parameters.
(class format_postprocessor): New class.
(struct pretty_printer::format_decoder): Document the new
parameters.
(struct pretty_printer::m_format_postprocessor): New field.
* tree-diagnostic.c (default_tree_printer): Update for new
bool and const char ** params.
* tree-diagnostic.h (default_tree_printer): Likewise.

gcc/c/ChangeLog:
* c-objc-common.c (c_tree_printer): Gain bool and const char **
parameters.

gcc/c-family/ChangeLog:
* c-format.c (gcc_cxxdiag_char_table): Add 'H' and 'I' to
format_chars.
* c.opt (fdiagnostics-show-template-tree): New option.
(felide-type): New option.

gcc/cp/ChangeLog:
* call.c (perform_implicit_conversion_flags): Convert
"from %qT to %qT" to "from %qH to %qI" in diagnostic.
(print_conversion_rejection): Replace pairs of %qT with
%qH and %qI in various places.
(build_user_type_conversion_1): Likewise.
(build_integral_nontype_arg_conv): Likewise.
(build_conditional_expr_1): Likewise.
(convert_like_real): Likewise.
(convert_arg_to_ellipsis): Likewise.
(joust): Likewise.
(initialize_reference): Likewise.
* cvt.c (cp_convert_to_pointer): Likewise.
(cp_convert_to_pointer): Likewise.
(convert_to_reference): Likewise.
(ocp_convert): Likewise.
* error.c (cp_printer): Gain bool and const char ** parameters.
(struct deferred_printed_type): New struct.
(class cxx_format_postprocessor): New class.
(cxx_initialize_diagnostics): Wire up a cxx_format_postprocessor
to pp->m_format_postprocessor.
(comparable_template_types_p): New function.
(newline_and_indent): New function.
(arg_to_string): New function.
(print_nonequal_arg): New function.
(print_template_differences): New function.
(type_to_string_with_compare): New function.
(print_template_tree_comparison): New function.
(append_formatted_chunk): New function.
(add_quotes): New function.
(cxx_format_postprocessor::handle): New function.
(defer_phase_2_of_type_diff): New function.
(cp_printer): Add "quoted" and "buffer_ptr" params.  Implement
%H and %I.
* typeck.c (cp_build_binary_op): Replace pairs of %qT with
%qH and %qI in various places.
(convert_member_func_to_ptr): Likewise.
(build_reinterpret_cast_1): Likewise.
(convert_for_assignment): Likewise.
* typeck2.c (check_narrowing): Likewise.

gcc/fortran/ChangeLog:
* error.c (gfc_format_decoder): Update for new bool and
const char ** params.

gcc/testsuite/ChangeLog:
* g++.dg/plugin/plugin.exp (plugin_test_list): Add...
* g++.dg/plugin/show-template-tree-color-no-elide-type.C: New
test case.
* g++.dg/plugin/show-template-tree-color.C: New test case.
* g++.dg/plugin/show_template_tree_color_plugin.c: New plugin.
* g++.dg/template/show-template-tree-2.C: New test case.
* g++.dg/template/show-template-tree-3.C: New test case.
* g++.dg/template/show-template-tree-4.C: New test case.
* g++.dg/template/show-template-tree-no-elide-type.C: New test case.
* g++.dg/template/show-template-tree.C: New test case.

From-SVN: r248698

30 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-format.c
gcc/c-family/c.opt
gcc/c/ChangeLog
gcc/c/c-objc-common.c
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cvt.c
gcc/cp/error.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/diagnostic-color.c
gcc/doc/invoke.texi
gcc/fortran/ChangeLog
gcc/fortran/error.c
gcc/pretty-print.c
gcc/pretty-print.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/plugin/plugin.exp
gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-elide-type.C [new file with mode: 0644]
gcc/testsuite/g++.dg/plugin/show-template-tree-color.C [new file with mode: 0644]
gcc/testsuite/g++.dg/plugin/show_template_tree_color_plugin.c [new file with mode: 0644]
gcc/testsuite/g++.dg/template/show-template-tree-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/show-template-tree-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/show-template-tree-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/show-template-tree-no-elide-type.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/show-template-tree.C [new file with mode: 0644]
gcc/tree-diagnostic.c
gcc/tree-diagnostic.h

index 168e6734a305aac837ea92a0b1a1a0d861d13591..da2b93ff90021c436f2a58ca3931ceb8a7c1feca 100644 (file)
@@ -1,3 +1,30 @@
+2017-05-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * diagnostic-color.c (color_dict): Add "type-diff".
+       (parse_gcc_colors): Update comment.
+       * doc/invoke.texi (Diagnostic Message Formatting Options): Add
+       -fdiagnostics-show-template-tree and -fno-elide-type.
+       (GCC_COLORS): Add type-diff to example.
+       (type-diff=): New.
+       (-fdiagnostics-show-template-tree): New.
+       (-fno-elide-type): New.
+       * pretty-print.c (pp_format): Pass quote and formatters[argno] to
+       the pp_format_decoder callback.  Call any m_format_postprocessor's
+       "handle" method.
+       (pretty_printer::pretty_printer): Initialize
+       m_format_postprocessor.
+       (pretty_printer::~pretty_printer): Delete any
+       m_format_postprocessor.
+       * pretty-print.h (printer_fn): Add bool and const char **
+       parameters.
+       (class format_postprocessor): New class.
+       (struct pretty_printer::format_decoder): Document the new
+       parameters.
+       (struct pretty_printer::m_format_postprocessor): New field.
+       * tree-diagnostic.c (default_tree_printer): Update for new
+       bool and const char ** params.
+       * tree-diagnostic.h (default_tree_printer): Likewise.
+
 2017-05-30  Segher Boessenkool  <segher@kernel.crashing.org>
 
        * config/rs6000/predicates.md (cc_reg_not_micro_cr0_operand): Delete.
index 818d39ba8024f09a8b4befc6a50d217744e49d15..a077867c8da0fbb7866d727f87ccfaf807f0c430 100644 (file)
@@ -1,3 +1,10 @@
+2017-05-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * c-format.c (gcc_cxxdiag_char_table): Add 'H' and 'I' to
+       format_chars.
+       * c.opt (fdiagnostics-show-template-tree): New option.
+       (felide-type): New option.
+
 2017-05-25  Volker Reichelt  <v.reichelt@netcologne.de>
 
        * c.opt (Wcatch-value=): New C++ warning flag.
index a561d0e30e4fa878bdfa6a52d9b13e6f8e526035..faef267220d50ef38375459e7da3c7e6f886f41a 100644 (file)
@@ -771,7 +771,7 @@ static const format_char_info gcc_cxxdiag_char_table[] =
   /* Custom conversion specifiers.  */
 
   /* These will require a "tree" at runtime.  */
-  { "ADFSTVX",1,STD_C89,{ T89_T,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q+#",   "'",   NULL },
+  { "ADFHISTVX",1,STD_C89,{ T89_T,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q+#",   "'",   NULL },
   { "E", 1,STD_C89,{ T89_T,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q+#",   "",   NULL },
   { "K", 1, STD_C89,{ T89_T,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "",   "\"",   NULL },
   { "v", 0,STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q#",  "",   NULL },
index 648e0add9c64b45010d4206cf6304b8074695364..c3eca4acdeb199b6ad34008b717bfb7703a2ed9f 100644 (file)
@@ -1346,6 +1346,10 @@ fdefault-inline
 C++ ObjC++ Ignore
 Does nothing.  Preserved for backward compatibility.
 
+fdiagnostics-show-template-tree
+C++ ObjC++ Var(flag_diagnostics_show_template_tree) Init(0)
+Print hierarchical comparisons when template types are mismatched.
+
 fdirectives-only
 C ObjC C++ ObjC++
 Preprocess directives only.
@@ -1365,6 +1369,10 @@ Write all declarations as Ada code for the given file only.
 felide-constructors
 C++ ObjC++ Var(flag_elide_constructors) Init(1)
 
+felide-type
+C++ ObjC++ Var(flag_elide_type) Init(1)
+-fno-elide-type Do not elide common elements in template comparisons.
+
 fenforce-eh-specs
 C++ ObjC++ Var(flag_enforce_eh_specs) Init(1)
 Generate code to check exception specifications.
index d240298d4d8fd42f0efb5d4470a2d7919a412505..2fa398466b1b99b5a14cdccf96c2fa6a5785cfb6 100644 (file)
@@ -1,3 +1,8 @@
+2017-05-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * c-objc-common.c (c_tree_printer): Gain bool and const char **
+       parameters.
+
 2017-05-24  Martin Sebor  <msebor@redhat.com>
 
        PR c/80731
index 5e694887307d47e4cdb9da40bb921590b6a41784..05212b2cb8e4c9477daf2cd2f86e3205a66249e4 100644 (file)
@@ -28,7 +28,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-objc-common.h"
 
 static bool c_tree_printer (pretty_printer *, text_info *, const char *,
-                           int, bool, bool, bool);
+                           int, bool, bool, bool, bool, const char **);
 
 bool
 c_missing_noreturn_ok_p (tree decl)
@@ -75,7 +75,8 @@ c_objc_common_init (void)
    diagnostic machinery.  */
 static bool
 c_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
-               int precision, bool wide, bool set_locus, bool hash)
+               int precision, bool wide, bool set_locus, bool hash,
+               bool, const char **)
 {
   tree t = NULL_TREE;
   tree name;
index 3da2f979e4dc5f57c3ad3e9cd0576d381d490361..2dac6109392d6c849ed9f8bf29af9081cf97ec90 100644 (file)
@@ -1,3 +1,45 @@
+2017-05-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * call.c (perform_implicit_conversion_flags): Convert
+       "from %qT to %qT" to "from %qH to %qI" in diagnostic.
+       (print_conversion_rejection): Replace pairs of %qT with
+       %qH and %qI in various places.
+       (build_user_type_conversion_1): Likewise.
+       (build_integral_nontype_arg_conv): Likewise.
+       (build_conditional_expr_1): Likewise.
+       (convert_like_real): Likewise.
+       (convert_arg_to_ellipsis): Likewise.
+       (joust): Likewise.
+       (initialize_reference): Likewise.
+       * cvt.c (cp_convert_to_pointer): Likewise.
+       (cp_convert_to_pointer): Likewise.
+       (convert_to_reference): Likewise.
+       (ocp_convert): Likewise.
+       * error.c (cp_printer): Gain bool and const char ** parameters.
+       (struct deferred_printed_type): New struct.
+       (class cxx_format_postprocessor): New class.
+       (cxx_initialize_diagnostics): Wire up a cxx_format_postprocessor
+       to pp->m_format_postprocessor.
+       (comparable_template_types_p): New function.
+       (newline_and_indent): New function.
+       (arg_to_string): New function.
+       (print_nonequal_arg): New function.
+       (print_template_differences): New function.
+       (type_to_string_with_compare): New function.
+       (print_template_tree_comparison): New function.
+       (append_formatted_chunk): New function.
+       (add_quotes): New function.
+       (cxx_format_postprocessor::handle): New function.
+       (defer_phase_2_of_type_diff): New function.
+       (cp_printer): Add "quoted" and "buffer_ptr" params.  Implement
+       %H and %I.
+       * typeck.c (cp_build_binary_op): Replace pairs of %qT with
+       %qH and %qI in various places.
+       (convert_member_func_to_ptr): Likewise.
+       (build_reinterpret_cast_1): Likewise.
+       (convert_for_assignment): Likewise.
+       * typeck2.c (check_narrowing): Likewise.
+
 2017-05-30  Nathan Sidwell  <nathan@acm.org>
 
        Kill IDENTIFIER_NAMESPACE_BINDINGS
index c1fcd194b762a275e78af104b4fc2fb1b153862e..51260f07dfd142dcbc5b7a69330c0142335969dc 100644 (file)
@@ -3402,7 +3402,7 @@ print_conversion_rejection (location_t loc, struct conversion_info *info)
                from);
       else
        inform (loc, "  no known conversion for implicit "
-               "%<this%> parameter from %qT to %qT",
+               "%<this%> parameter from %qH to %qI",
                from, info->to_type);
     }
   else if (!TYPE_P (info->from))
@@ -3415,10 +3415,10 @@ print_conversion_rejection (location_t loc, struct conversion_info *info)
     }
   else if (info->n_arg == -2)
     /* Conversion of conversion function return value failed.  */
-    inform (loc, "  no known conversion from %qT to %qT",
+    inform (loc, "  no known conversion from %qH to %qI",
            from, info->to_type);
   else
-    inform (loc, "  no known conversion for argument %d from %qT to %qT",
+    inform (loc, "  no known conversion for argument %d from %qH to %qI",
            info->n_arg + 1, from, info->to_type);
 }
 
@@ -3925,7 +3925,7 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags,
     {
       if (complain & tf_error)
        {
-         error ("conversion from %qT to %qT is ambiguous",
+         error ("conversion from %qH to %qI is ambiguous",
                 fromtype, totype);
          print_z_candidates (location_of (expr), candidates);
        }
@@ -4052,7 +4052,7 @@ build_integral_nontype_arg_conv (tree type, tree expr, tsubst_flags_t complain)
          break;
 
        if (complain & tf_error)
-         error_at (loc, "conversion from %qT to %qT not considered for "
+         error_at (loc, "conversion from %qH to %qI not considered for "
                    "non-type template argument", t, type);
        /* fall through.  */
 
@@ -4818,14 +4818,14 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
          if (unsafe_conversion_p (loc, stype, arg2, NULL_TREE, false))
            {
              if (complain & tf_error)
-               error_at (loc, "conversion of scalar %qT to vector %qT "
+               error_at (loc, "conversion of scalar %qH to vector %qI "
                               "involves truncation", arg2_type, vtype);
              return error_mark_node;
            }
          if (unsafe_conversion_p (loc, stype, arg3, NULL_TREE, false))
            {
              if (complain & tf_error)
-               error_at (loc, "conversion of scalar %qT to vector %qT "
+               error_at (loc, "conversion of scalar %qH to vector %qI "
                               "involves truncation", arg3_type, vtype);
              return error_mark_node;
            }
@@ -5214,7 +5214,7 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
                                                             arg3_type);
       if (complain & tf_warning)
        do_warn_double_promotion (result_type, arg2_type, arg3_type,
-                                 "implicit conversion from %qT to %qT to "
+                                 "implicit conversion from %qH to %qI to "
                                  "match other result of conditional",
                                  loc);
 
@@ -6593,7 +6593,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
         from std::nullptr_t requires direct-initialization.  */
       if (NULLPTR_TYPE_P (TREE_TYPE (expr))
          && TREE_CODE (totype) == BOOLEAN_TYPE)
-       complained = permerror (loc, "converting to %qT from %qT requires "
+       complained = permerror (loc, "converting to %qH from %qI requires "
                                "direct-initialization",
                                totype, TREE_TYPE (expr));
 
@@ -6602,7 +6602,7 @@ 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 %qT to %qT", TREE_TYPE (expr),
+                                     "from %qH to %qI", TREE_TYPE (expr),
                                      totype);
              if (complained)
                print_z_candidate (loc, "candidate is:", t->cand);
@@ -6638,7 +6638,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
            break;
        }
       if (!complained)
-       complained = permerror (loc, "invalid conversion from %qT to %qT",
+       complained = permerror (loc, "invalid conversion from %qH to %qI",
                                TREE_TYPE (expr), totype);
       if (complained && fn)
        inform (DECL_SOURCE_LOCATION (fn),
@@ -6914,14 +6914,14 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
            tree extype = TREE_TYPE (expr);
            if (TYPE_REF_IS_RVALUE (ref_type)
                && lvalue_p (expr))
-             error_at (loc, "cannot bind rvalue reference of type %qT to "
-                        "lvalue of type %qT", totype, extype);
+             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 %qT to an rvalue of type %qT", totype, extype);
+                       "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 %qT to %qT "
+             error_at (loc, "binding reference of type %qH to %qI "
                        "discards qualifiers", totype, extype);
            else
              gcc_unreachable ();
@@ -7073,7 +7073,7 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain)
       if ((complain & tf_warning)
          && warn_double_promotion && !c_inhibit_evaluation_warnings)
        warning_at (loc, OPT_Wdouble_promotion,
-                   "implicit conversion from %qT to %qT when passing "
+                   "implicit conversion from %qH to %qI when passing "
                    "argument to function",
                    arg_type, double_type_node);
       arg = convert_to_real_nofold (double_type_node, arg);
@@ -9640,7 +9640,7 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
          if (! DECL_CONSTRUCTOR_P (w->fn))
            source = TREE_TYPE (source);
          if (warning (OPT_Wconversion, "choosing %qD over %qD", w->fn, l->fn)
-             && warning (OPT_Wconversion, "  for conversion from %qT to %qT",
+             && 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");
@@ -10096,7 +10096,7 @@ perform_implicit_conversion_flags (tree type, tree expr,
          else if (invalid_nonstatic_memfn_p (loc, expr, complain))
            /* We gave an error.  */;
          else
-           error_at (loc, "could not convert %qE from %qT to %qT", expr,
+           error_at (loc, "could not convert %qE from %qH to %qI", expr,
                      TREE_TYPE (expr), type);
        }
       expr = error_mark_node;
@@ -10412,11 +10412,11 @@ initialize_reference (tree type, tree expr,
                   && !TYPE_REF_IS_RVALUE (type)
                   && !lvalue_p (expr))
            error_at (loc, "invalid initialization of non-const reference of "
-                     "type %qT from an rvalue of type %qT",
+                     "type %qH from an rvalue of type %qI",
                      type, TREE_TYPE (expr));
          else
            error_at (loc, "invalid initialization of reference of type "
-                     "%qT from expression of type %qT", type,
+                     "%qH from expression of type %qI", type,
                      TREE_TYPE (expr));
        }
       return error_mark_node;
index a53c0b3751a25592fd3a346e114b238ed67a440c..e8a7ee29465d089dbd0dc979259c37e1a8691ba2 100644 (file)
@@ -86,7 +86,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold,
       if (!COMPLETE_TYPE_P (intype))
        {
          if (complain & tf_error)
-           error_at (loc, "can%'t convert from incomplete type %qT to %qT",
+           error_at (loc, "can%'t convert from incomplete type %qH to %qI",
                      intype, type);
          return error_mark_node;
        }
@@ -96,7 +96,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold,
        {
          if ((complain & tf_error)
              && rval == error_mark_node)
-           error_at (loc, "conversion of %qE from %qT to %qT is ambiguous",
+           error_at (loc, "conversion of %qE from %qH to %qI is ambiguous",
                      expr, intype, type);
          return rval;
        }
@@ -168,7 +168,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold,
       if (TYPE_PTRMEMFUNC_P (type))
        {
          if (complain & tf_error)
-           error_at (loc, "cannot convert %qE from type %qT to type %qT",
+           error_at (loc, "cannot convert %qE from type %qH to type %qI",
                      expr, intype, type);
          return error_mark_node;
        }
@@ -195,7 +195,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold,
            }
        }
       if (complain & tf_error)
-       error_at (loc, "cannot convert %qE from type %qT to type %qT",
+       error_at (loc, "cannot convert %qE from type %qH to type %qI",
                  expr, intype, type);
       return error_mark_node;
     }
@@ -221,7 +221,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold,
   else if (TYPE_PTRMEM_P (type) && INTEGRAL_CODE_P (form))
     {
       if (complain & tf_error)
-       error_at (loc, "invalid conversion from %qT to %qT", intype, type);
+       error_at (loc, "invalid conversion from %qH to %qI", intype, type);
       return error_mark_node;
     }
 
@@ -244,7 +244,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold,
     return instantiate_type (type, expr, complain);
 
   if (complain & tf_error)
-    error_at (loc, "cannot convert %qE from type %qT to type %qT",
+    error_at (loc, "cannot convert %qE from type %qH to type %qI",
              expr, intype, type);
   return error_mark_node;
 }
@@ -464,7 +464,7 @@ convert_to_reference (tree reftype, tree expr, int convtype,
            && !at_least_as_qualified_p (ttl, ttr))
          {
            if (complain & tf_error)
-             permerror (loc, "conversion from %qT to %qT discards qualifiers",
+             permerror (loc, "conversion from %qH to %qI discards qualifiers",
                         ttr, reftype);
            else
              return error_mark_node;
@@ -514,7 +514,7 @@ convert_to_reference (tree reftype, tree expr, int convtype,
     }
 
   if (complain & tf_error)
-    error_at (loc, "cannot convert type %qT to type %qT", intype, reftype);
+    error_at (loc, "cannot convert type %qH to type %qI", intype, reftype);
 
   return error_mark_node;
 }
@@ -907,7 +907,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
       if (invalid_nonstatic_memfn_p (loc, expr, complain))
        /* We displayed the error message.  */;
       else
-       error_at (loc, "conversion from %qT to non-scalar type %qT requested",
+       error_at (loc, "conversion from %qH to non-scalar type %qI requested",
                  TREE_TYPE (expr), type);
     }
   return error_mark_node;
index 8481e2d1e17338040f456c81e71e924ac7eb4741..ed67d14567be701c5e0d308e10cebd359af7d98a 100644 (file)
@@ -99,7 +99,50 @@ static void cp_diagnostic_starter (diagnostic_context *, diagnostic_info *);
 static void cp_print_error_function (diagnostic_context *, diagnostic_info *);
 
 static bool cp_printer (pretty_printer *, text_info *, const char *,
-                       int, bool, bool, bool);
+                       int, bool, bool, bool, bool, const char **);
+
+/* Struct for handling %H or %I, which require delaying printing the
+   type until a postprocessing stage.  */
+
+struct deferred_printed_type
+{
+  deferred_printed_type ()
+  : m_tree (NULL_TREE), m_buffer_ptr (NULL), m_verbose (false), m_quote (false)
+  {}
+
+  deferred_printed_type (tree type, const char **buffer_ptr, bool verbose,
+                        bool quote)
+  : m_tree (type), m_buffer_ptr (buffer_ptr), m_verbose (verbose),
+    m_quote (quote)
+  {
+    gcc_assert (type);
+    gcc_assert (buffer_ptr);
+  }
+
+  /* The tree is not GTY-marked: they are only non-NULL within a
+     call to pp_format.  */
+  tree m_tree;
+  const char **m_buffer_ptr;
+  bool m_verbose;
+  bool m_quote;
+};
+
+/* Subclass of format_postprocessor for the C++ frontend.
+   This handles the %H and %I formatting codes, printing them
+   in a postprocessing phase (since they affect each other).  */
+
+class cxx_format_postprocessor : public format_postprocessor
+{
+ public:
+  cxx_format_postprocessor ()
+  : m_type_a (), m_type_b ()
+  {}
+
+  void handle (pretty_printer *pp) FINAL OVERRIDE;
+
+  deferred_printed_type m_type_a;
+  deferred_printed_type m_type_b;
+};
 
 /* CONTEXT->printer is a basic pretty printer that was constructed
    presumably by diagnostic_initialize(), called early in the
@@ -123,6 +166,7 @@ cxx_initialize_diagnostics (diagnostic_context *context)
   diagnostic_starter (context) = cp_diagnostic_starter;
   /* diagnostic_finalizer is already c_diagnostic_finalizer.  */
   diagnostic_format_decoder (context) = cp_printer;
+  pp->m_format_postprocessor = new cxx_format_postprocessor ();
 }
 
 /* Dump a scope, if deemed necessary.  */
@@ -3563,6 +3607,388 @@ maybe_print_constexpr_context (diagnostic_context *context)
     }
 }
 \f
+
+/* 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);
+  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.  */
+  pp_printf (&tmp_pp, "%<%s%>", content);
+
+  return pp_ggc_formatted_text (&tmp_pp);
+}
+
+/* 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, they are printed normally,
+            and no difference tree is printed.  */
+         type_a_text = type_to_string (type_a.m_tree, type_a.m_verbose);
+         type_b_text = type_to_string (type_b.m_tree, type_b.m_verbose);
+       }
+
+      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.
@@ -3577,11 +4003,18 @@ maybe_print_constexpr_context (diagnostic_context *context)
    %S   substitution (template + args)
    %T   type.
    %V   cv-qualifier.
-   %X   exception-specification.  */
+   %X   exception-specification.
+   %H   type difference (from)
+   %I   type difference (to).  */
 static bool
 cp_printer (pretty_printer *pp, text_info *text, const char *spec,
-           int precision, bool wide, bool set_locus, bool verbose)
+           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))
@@ -3627,6 +4060,20 @@ cp_printer (pretty_printer *pp, text_info *text, const char *spec,
       percent_K_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;
+      }
+
     default:
       return false;
     }
index 6bf57bb3a0f8e10bf0e6086279123f1702da57f2..c657b3b9812ec34fd6989fed51a770bb15474e3a 100644 (file)
@@ -5040,7 +5040,7 @@ cp_build_binary_op (location_t location,
       result_type = cp_common_type (type0, type1);
       if (complain & tf_warning)
        do_warn_double_promotion (result_type, type0, type1,
-                                 "implicit conversion from %qT to %qT "
+                                 "implicit conversion from %qH to %qI "
                                  "to match other operand of binary "
                                  "expression",
                                  location);
@@ -7076,7 +7076,7 @@ convert_member_func_to_ptr (tree type, tree expr, tsubst_flags_t complain)
 
   if (pedantic || warn_pmf2ptr)
     pedwarn (input_location, pedantic ? OPT_Wpedantic : OPT_Wpmf_conversions,
-            "converting from %qT to %qT", intype, type);
+            "converting from %qH to %qI", intype, type);
 
   if (TREE_CODE (intype) == METHOD_TYPE)
     expr = build_addr_func (expr, complain);
@@ -7202,7 +7202,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
       if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
         {
           if (complain & tf_error)
-            permerror (input_location, "cast from %qT to %qT loses precision",
+            permerror (input_location, "cast from %qH to %qI loses precision",
                        intype, type);
           else
             return error_mark_node;
@@ -7242,7 +7242,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
          && COMPLETE_TYPE_P (TREE_TYPE (type))
          && COMPLETE_TYPE_P (TREE_TYPE (intype))
          && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (intype)))
-       warning (OPT_Wcast_align, "cast from %qT to %qT "
+       warning (OPT_Wcast_align, "cast from %qH to %qI "
                  "increases required alignment of target type", intype, type);
 
       /* We need to strip nops here, because the front end likes to
@@ -8569,33 +8569,33 @@ convert_for_assignment (tree type, tree rhs,
                    return r;
                }
              else if (fndecl)
-               error ("cannot convert %qT to %qT for argument %qP to %qD",
+               error ("cannot convert %qH to %qI for argument %qP to %qD",
                       rhstype, type, parmnum, fndecl);
              else
                switch (errtype)
                  {
                    case ICR_DEFAULT_ARGUMENT:
-                     error ("cannot convert %qT to %qT in default argument",
+                     error ("cannot convert %qH to %qI in default argument",
                             rhstype, type);
                      break;
                    case ICR_ARGPASS:
-                     error ("cannot convert %qT to %qT in argument passing",
+                     error ("cannot convert %qH to %qI in argument passing",
                             rhstype, type);
                      break;
                    case ICR_CONVERTING:
-                     error ("cannot convert %qT to %qT",
+                     error ("cannot convert %qH to %qI",
                             rhstype, type);
                      break;
                    case ICR_INIT:
-                     error ("cannot convert %qT to %qT in initialization",
+                     error ("cannot convert %qH to %qI in initialization",
                             rhstype, type);
                      break;
                    case ICR_RETURN:
-                     error ("cannot convert %qT to %qT in return",
+                     error ("cannot convert %qH to %qI in return",
                             rhstype, type);
                      break;
                    case ICR_ASSIGN:
-                     error ("cannot convert %qT to %qT in assignment",
+                     error ("cannot convert %qH to %qI in assignment",
                             rhstype, type);
                      break;
                    default:
index ff445ca6a0e6ee858adeace0a3684fd04f2d5d35..4623d6d9197e478129765cf28a964fa4235c430c 100644 (file)
@@ -955,7 +955,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
        {
          if (complain & tf_warning)
            warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
-                       "from %qT to %qT inside { } is ill-formed in C++11",
+                       "from %qH to %qI inside { } is ill-formed in C++11",
                        init, ftype, type);
          ok = true;
        }
@@ -966,7 +966,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
              if ((!almost_ok || pedantic)
                  && pedwarn (loc, OPT_Wnarrowing,
                              "narrowing conversion of %qE "
-                             "from %qT to %qT inside { }",
+                             "from %qH to %qI inside { }",
                              init, ftype, type)
                  && almost_ok)
                inform (loc, " the expression has a constant value but is not "
@@ -979,7 +979,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
          int savederrorcount = errorcount;
          global_dc->pedantic_errors = 1;
          pedwarn (loc, OPT_Wnarrowing,
-                  "narrowing conversion of %qE from %qT to %qT "
+                  "narrowing conversion of %qE from %qH to %qI "
                   "inside { }", init, ftype, type);
          if (errorcount == savederrorcount)
            ok = true;
index 8353fe016b77149d5c1164de5bba68a329213e76..6adb872146b698177f8d266f4fd7ad0b68eb413b 100644 (file)
@@ -174,6 +174,7 @@ static struct color_cap color_dict[] =
   { "diff-hunk", SGR_SEQ (COLOR_FG_CYAN), 9, false },
   { "diff-delete", SGR_SEQ (COLOR_FG_RED), 11, false },
   { "diff-insert", SGR_SEQ (COLOR_FG_GREEN), 11, false },
+  { "type-diff", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN), 9, false },
   { NULL, NULL, 0, false }
 };
 
@@ -204,8 +205,9 @@ colorize_stop (bool show_color)
 /* Parse GCC_COLORS.  The default would look like:
    GCC_COLORS='error=01;31:warning=01;35:note=01;36:\
    range1=32:range2=34:locus=01:quote=01:\
-   fixit-insert=32:fixit-delete=31'\
-   diff-filename=01:diff-hunk=32:diff-delete=31:diff-insert=32'
+   fixit-insert=32:fixit-delete=31:'\
+   diff-filename=01:diff-hunk=32:diff-delete=31:diff-insert=32:\
+   type-diff=01;32'
    No character escaping is needed or supported.  */
 static bool
 parse_gcc_colors (void)
index 612bd12a1bda24be5c266ad460ecfc86015fb455..20805df884d11a65da35a2922f2a24ca25c33335 100644 (file)
@@ -251,6 +251,7 @@ Objective-C and Objective-C++ Dialects}.
 -fdiagnostics-color=@r{[}auto@r{|}never@r{|}always@r{]}  @gol
 -fno-diagnostics-show-option  -fno-diagnostics-show-caret @gol
 -fdiagnostics-parseable-fixits  -fdiagnostics-generate-patch @gol
+-fdiagnostics-show-template-tree -fno-elide-type @gol
 -fno-show-column}
 
 @item Warning Options
@@ -3448,7 +3449,8 @@ The default @env{GCC_COLORS} is
 @smallexample
 error=01;31:warning=01;35:note=01;36:range1=32:range2=34:locus=01:\
 quote=01:fixit-insert=32:fixit-delete=31:\
-diff-filename=01:diff-hunk=32:diff-delete=31:diff-insert=32
+diff-filename=01:diff-hunk=32:diff-delete=31:diff-insert=32:\
+type-diff=01;32
 @end smallexample
 @noindent
 where @samp{01;31} is bold red, @samp{01;35} is bold magenta,
@@ -3512,6 +3514,11 @@ SGR substring for deleted lines within generated patches.
 @item diff-insert=
 @vindex diff-insert GCC_COLORS @r{capability}
 SGR substring for inserted lines within generated patches.
+
+@item type-diff=
+@vindex type-diff GCC_COLORS @r{capability}
+SGR substring for highlighting mismatching types within template
+arguments in the C++ frontend.
 @end table
 
 @item -fno-diagnostics-show-option
@@ -3584,6 +3591,47 @@ are printed.  For example:
 The diff may or may not be colorized, following the same rules
 as for diagnostics (see @option{-fdiagnostics-color}).
 
+@item -fdiagnostics-show-template-tree
+@opindex fdiagnostics-show-template-tree
+
+In the C++ frontend, when printing diagnostics showing mismatching
+template types, such as:
+
+@smallexample
+  could not convert 'std::map<int, std::vector<double> >()'
+    from 'map<[...],vector<double>>' to 'map<[...],vector<float>>
+@end smallexample
+
+the @option{-fdiagnostics-show-template-tree} flag enables printing a
+tree-like structure showing the common and differing parts of the types,
+such as:
+
+@smallexample
+  map<
+    [...],
+    vector<
+      [double != float]>>
+@end smallexample
+
+The parts that differ are highlighted with color (``double'' and
+``float'' in this case).
+
+@item -fno-elide-type
+@opindex fno-elide-type
+@opindex felide-type
+By default when the C++ frontend prints diagnostics showing mismatching
+template types, common parts of the types are printed as ``[...]'' to
+simplify the error message.  For example:
+
+@smallexample
+  could not convert 'std::map<int, std::vector<double> >()'
+    from 'map<[...],vector<double>>' to 'map<[...],vector<float>>
+@end smallexample
+
+Specifying the @option{-fno-elide-type} flag suppresses that behavior.
+This flag also affects the output of the
+@option{-fdiagnostics-show-template-tree} flag.
+
 @item -fno-show-column
 @opindex fno-show-column
 Do not print column numbers in diagnostics.  This may be necessary if
index 093c36c7e21a1b81c01a40c89cf0f2029430f49c..08c3ea7b17298e4fc705299406f34abd5259d554 100644 (file)
@@ -1,3 +1,8 @@
+2017-05-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * error.c (gfc_format_decoder): Update for new bool and
+       const char ** params.
+
 2017-05-29  Thomas Koenig  <tkoenig@gcc.gnu.org>
 
        PR fortran/37131
index eeb7a785c3d51aa332c3b421efafce662d471f04..3ad1cf9ff25c08960f528c609198cab5e9e13e8d 100644 (file)
@@ -917,7 +917,8 @@ gfc_notify_std (int std, const char *gmsgid, ...)
 */
 static bool
 gfc_format_decoder (pretty_printer *pp, text_info *text, const char *spec,
-                   int precision, bool wide, bool set_locus, bool hash)
+                   int precision, bool wide, bool set_locus, bool hash,
+                   bool quoted, const char **buffer_ptr)
 {
   switch (*spec)
     {
@@ -948,7 +949,7 @@ gfc_format_decoder (pretty_printer *pp, text_info *text, const char *spec,
         etc. diagnostics can use the FE printer while the FE is still
         active.  */
       return default_tree_printer (pp, text, spec, precision, wide,
-                                  set_locus, hash);
+                                  set_locus, hash, quoted, buffer_ptr);
     }
 }
 
index bcb1a70ac033b9f2dcd9c5d1bafd35a8d9930b6e..570dec77dc1b9df56bddb320c543ab2201c9798c 100644 (file)
@@ -677,7 +677,8 @@ pp_format (pretty_printer *pp, text_info *text)
 
            gcc_assert (pp_format_decoder (pp));
            ok = pp_format_decoder (pp) (pp, text, p,
-                                        precision, wide, plus, hash);
+                                        precision, wide, plus, hash, quote,
+                                        formatters[argno]);
            gcc_assert (ok);
          }
        }
@@ -696,6 +697,11 @@ pp_format (pretty_printer *pp, text_info *text)
     for (; argno < PP_NL_ARGMAX; argno++)
       gcc_assert (!formatters[argno]);
 
+  /* If the client supplied a postprocessing object, call its "handle"
+     hook here.  */
+  if (pp->m_format_postprocessor)
+    pp->m_format_postprocessor->handle (pp);
+
   /* Revert to normal obstack and wrapping mode.  */
   buffer->obstack = &buffer->formatted_obstack;
   buffer->line_length = 0;
@@ -847,6 +853,7 @@ pretty_printer::pretty_printer (const char *p, int l)
     indent_skip (),
     wrapping (),
     format_decoder (),
+    m_format_postprocessor (NULL),
     emitted_prefix (),
     need_newline (),
     translate_identifiers (true),
@@ -860,6 +867,8 @@ pretty_printer::pretty_printer (const char *p, int l)
 
 pretty_printer::~pretty_printer ()
 {
+  if (m_format_postprocessor)
+    delete m_format_postprocessor;
   buffer->~output_buffer ();
   XDELETE (buffer);
 }
index 25966787d05db4253ac90658ccc36817dbad81f0..40e56a35d93e7c7db0332dba203d28c432290d88 100644 (file)
@@ -180,11 +180,20 @@ struct pp_wrapping_mode_t
    A client-supplied formatter returns true if everything goes well,
    otherwise it returns false.  */
 typedef bool (*printer_fn) (pretty_printer *, text_info *, const char *,
-                           int, bool, bool, bool);
+                           int, bool, bool, bool, bool, const char **);
 
 /* Client supplied function used to decode formats.  */
 #define pp_format_decoder(PP) (PP)->format_decoder
 
+/* Base class for an optional client-supplied object for doing additional
+   processing between stages 2 and 3 of formatted printing.  */
+class format_postprocessor
+{
+ public:
+  virtual ~format_postprocessor () {}
+  virtual void handle (pretty_printer *) = 0;
+};
+
 /* TRUE if a newline character needs to be added before further
    formatting.  */
 #define pp_needs_newline(PP)  (PP)->need_newline
@@ -239,9 +248,16 @@ struct pretty_printer
      If the BUFFER needs additional characters from the format string, it
      should advance the TEXT->format_spec as it goes.  When FORMAT_DECODER
      returns, TEXT->format_spec should point to the last character processed.
-  */
+     The QUOTE and BUFFER_PTR are passed in, to allow for deferring-handling
+     of format codes (e.g. %H and %I in the C++ frontend).  */
   printer_fn format_decoder;
 
+  /* If non-NULL, this is called by pp_format once after all format codes
+     have been processed, to allow for client-specific postprocessing.
+     This is used by the C++ frontend for handling the %H and %I
+     format codes (which interract with each other).  */
+  format_postprocessor *m_format_postprocessor;
+
   /* Nonzero if current PREFIX was emitted at least once.  */
   bool emitted_prefix;
 
index ee302e4b455914959b61a3f74ba19c5c20d876a7..8fbbfcece6bfaa92a9eb3ea0c32b0bca6c180159 100644 (file)
@@ -1,3 +1,16 @@
+2017-05-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * g++.dg/plugin/plugin.exp (plugin_test_list): Add...
+       * g++.dg/plugin/show-template-tree-color-no-elide-type.C: New
+       test case.
+       * g++.dg/plugin/show-template-tree-color.C: New test case.
+       * g++.dg/plugin/show_template_tree_color_plugin.c: New plugin.
+       * g++.dg/template/show-template-tree-2.C: New test case.
+       * g++.dg/template/show-template-tree-3.C: New test case.
+       * g++.dg/template/show-template-tree-4.C: New test case.
+       * g++.dg/template/show-template-tree-no-elide-type.C: New test case.
+       * g++.dg/template/show-template-tree.C: New test case.
+
 2017-05-30  Segher Boessenkool  <segher@kernel.crashing.org>
 
        * gcc.target/powerpc/shift-dot.c: Delete -mgen-cell-microcode from
index 6a0c1aa504ca389ffcf3fc7993e65ca21b36ff64..94ebe933798b9c0debcc371c41df23b628e72ff3 100644 (file)
@@ -65,6 +65,9 @@ set plugin_test_list [list \
     { def_plugin.c def-plugin-test.C } \
     { ../../gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c \
          diagnostic-test-expressions-1.C } \
+    { show_template_tree_color_plugin.c \
+         show-template-tree-color.C \
+         show-template-tree-color-no-elide-type.C } \
 ]
 
 foreach plugin_test $plugin_test_list {
diff --git a/gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-elide-type.C b/gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-elide-type.C
new file mode 100644 (file)
index 0000000..cab0359
--- /dev/null
@@ -0,0 +1,30 @@
+/* Verify colorization of the output of -fdiagnostics-show-template-tree,
+   and within the %H and %I format codes.
+   Doing so requires a plugin; see the comments in the plugin for the
+   rationale.  */
+
+// { dg-options "-fdiagnostics-show-template-tree -fdiagnostics-color=always -fno-elide-type" }
+
+template<typename> struct vector {};
+template<typename, typename> struct map {};
+
+void fn_1(vector<int>);
+void fn_2(map<int, int>);
+
+void test ()
+{
+  fn_1 (vector<double> ());
+  /* { dg-begin-multiline-output "" }
+could not convert '\e[01m\e[Kvector<double>()\e[m\e[K' from '\e[01m\e[Kvector<\e[01;32m\e[Kdouble\e[m\e[K>\e[m\e[K' to '\e[01m\e[Kvector<\e[01;32m\e[Kint\e[m\e[K>\e[m\e[K'
+  vector<
+    [\e[01;32m\e[Kdouble\e[m\e[K != \e[01;32m\e[Kint\e[m\e[K]>
+     { dg-end-multiline-output "" } */
+
+  fn_2 (map<int, double>());
+  /* { dg-begin-multiline-output "" }
+could not convert '\e[01m\e[Kmap<int, double>()\e[m\e[K' from '\e[01m\e[Kmap<int,\e[01;32m\e[Kdouble\e[m\e[K>\e[m\e[K' to '\e[01m\e[Kmap<int,\e[01;32m\e[Kint\e[m\e[K>\e[m\e[K'
+  map<
+    int,
+    [\e[01;32m\e[Kdouble\e[m\e[K != \e[01;32m\e[Kint\e[m\e[K]>
+     { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/plugin/show-template-tree-color.C b/gcc/testsuite/g++.dg/plugin/show-template-tree-color.C
new file mode 100644 (file)
index 0000000..eb99a3e
--- /dev/null
@@ -0,0 +1,30 @@
+/* Verify colorization of the output of -fdiagnostics-show-template-tree,
+   and within the %H and %I format codes.
+   Doing so requires a plugin; see the comments in the plugin for the
+   rationale.  */
+
+// { dg-options "-fdiagnostics-show-template-tree -fdiagnostics-color=always" }
+
+template<typename> struct vector {};
+template<typename, typename> struct map {};
+
+void fn_1(vector<int>);
+void fn_2(map<int, int>);
+
+void test ()
+{
+  fn_1 (vector<double> ());
+  /* { dg-begin-multiline-output "" }
+could not convert '\e[01m\e[Kvector<double>()\e[m\e[K' from '\e[01m\e[Kvector<\e[01;32m\e[Kdouble\e[m\e[K>\e[m\e[K' to '\e[01m\e[Kvector<\e[01;32m\e[Kint\e[m\e[K>\e[m\e[K'
+  vector<
+    [\e[01;32m\e[Kdouble\e[m\e[K != \e[01;32m\e[Kint\e[m\e[K]>
+     { dg-end-multiline-output "" } */
+
+  fn_2 (map<int, double>());
+  /* { dg-begin-multiline-output "" }
+could not convert '\e[01m\e[Kmap<int, double>()\e[m\e[K' from '\e[01m\e[Kmap<[...],\e[01;32m\e[Kdouble\e[m\e[K>\e[m\e[K' to '\e[01m\e[Kmap<[...],\e[01;32m\e[Kint\e[m\e[K>\e[m\e[K'
+  map<
+    [...],
+    [\e[01;32m\e[Kdouble\e[m\e[K != \e[01;32m\e[Kint\e[m\e[K]>
+     { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/plugin/show_template_tree_color_plugin.c b/gcc/testsuite/g++.dg/plugin/show_template_tree_color_plugin.c
new file mode 100644 (file)
index 0000000..af568bf
--- /dev/null
@@ -0,0 +1,38 @@
+/* We want to verify the colorized output of cxx_format_postprocessor,
+   but turning on colorization for everything confuses "dg-error" etc.
+   The color codes in the generated messages would also need escaping
+   for use within dg-error.
+
+   Hence the simplest approach is to provide a custom diagnostic_starter_fn,
+   which does nothing.
+
+   The resulting messages lack the "FILENAME:LINE:COL: error: " prefix
+   and can thus be tested using dg-begin/end-multiline-output.  */
+
+/* { dg-options "-O" } */
+
+#include "gcc-plugin.h"
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "plugin-version.h"
+#include "diagnostic.h"
+
+int plugin_is_GPL_compatible;
+
+void
+noop_starter_fn (diagnostic_context *, diagnostic_info *)
+{
+}
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+            struct plugin_gcc_version *version)
+{
+  if (!plugin_default_version_check (version, &gcc_version))
+    return 1;
+
+  diagnostic_starter (global_dc) = noop_starter_fn;
+
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/template/show-template-tree-2.C b/gcc/testsuite/g++.dg/template/show-template-tree-2.C
new file mode 100644 (file)
index 0000000..1cd3a06
--- /dev/null
@@ -0,0 +1,118 @@
+// Tests of -fdiagnostics-show-template-tree with variadic templates
+// { dg-options "-fdiagnostics-show-template-tree -std=c++11" }
+
+template<typename> struct vector {};
+template<typename, typename> struct map {};
+template<typename ... Types> struct var {};
+
+void fn_0(var<>);
+void fn_1(var<int>);
+void fn_2(var<int, int>);
+void fn_3(vector<var<> >);
+void fn_4(vector<var<int> >);
+void fn_5(vector<var<int, int> >);
+
+void test_fn_0 ()
+{
+  fn_0 (var<> ());
+  fn_0 (var<int> ()); // { dg-error "could not convert .* from 'var<int>' to 'var<>'" }
+  /* { dg-begin-multiline-output "" }
+  var<
+    [int != ]>
+     { dg-end-multiline-output "" } */
+  fn_0 (var<int, int> ()); // { dg-error "could not convert .* from 'var<int, int>' to 'var<>'" }
+  /* { dg-begin-multiline-output "" }
+  var<
+    [int, int != ]>
+     { dg-end-multiline-output "" } */
+  fn_0 (vector<var<int> >()); // { dg-error "could not convert .* from 'vector<var<int> >' to 'var<>'" }
+  fn_0 (vector<var<int, int> >());  // { dg-error "could not convert .* from 'vector<var<int, int> >' to 'var<>'" }
+}
+
+void test_fn_1 ()
+{
+  fn_1 (var<> ()); // { dg-error "could not convert .* from 'var<>' to 'var<int>'" }
+  /* { dg-begin-multiline-output "" }
+  var<
+    [ != int]>
+     { dg-end-multiline-output "" } */
+  fn_1 (var<int> ());
+  fn_1 (var<int, int> ()); // { dg-error "could not convert .* from 'var<int, int>' to 'var<int>'" }
+  /* { dg-begin-multiline-output "" }
+  var<
+    [int, int != int]>
+     { dg-end-multiline-output "" } */
+  fn_1 (vector<var<int> >()); // { dg-error "could not convert .* from 'vector<var<int> >' to 'var<int>'" }
+  fn_1 (vector<var<int, int> >()); // { dg-error "could not convert .* from 'vector<var<int, int> >' to 'var<int>'" }
+}
+
+void test_fn_2 ()
+{
+  fn_2 (var<> ()); // { dg-error "could not convert .* from 'var<>' to 'var<int, int>'" }
+  /* { dg-begin-multiline-output "" }
+  var<
+    [ != int, int]>
+     { dg-end-multiline-output "" } */
+  fn_2 (var<int> ()); // { dg-error "could not convert .* from 'var<int>' to 'var<int, int>'" }
+  /* { dg-begin-multiline-output "" }
+  var<
+    [int != int, int]>
+     { dg-end-multiline-output "" } */
+  fn_2 (var<int, int> ());
+  fn_2 (vector<var<int> >()); // { dg-error "could not convert .* from 'vector<var<int> >' to 'var<int, int>'" }
+  fn_2 (vector<var<int, int> >()); // { dg-error "could not convert .* from 'vector<var<int, int> >' to 'var<int, int>'" }
+}
+
+void test_fn_3 ()
+{
+  fn_3 (var<> ()); // { dg-error "could not convert .* from 'var<>' to 'vector<var<> >'" }
+  fn_3 (var<int> ()); // { dg-error "could not convert .* from 'var<int>' to 'vector<var<> >'" }
+  fn_3 (var<int, int> ()); // { dg-error "could not convert .* from 'var<int, int>' to 'vector<var<> >'" }
+  fn_3 (vector<var<> >());
+  fn_3 (vector<var<int> >());  // { dg-error "could not convert .* from 'vector<var<int>>' to 'vector<var<>>'" }
+  /* { dg-begin-multiline-output "" }
+  vector<
+    var<
+      [int != ]>>
+     { dg-end-multiline-output "" } */
+  fn_3 (vector<var<int, int> >()); // { dg-error "could not convert .* from 'vector<var<int, int>>' to 'vector<var<>>'" }
+  /* { dg-begin-multiline-output "" }
+  vector<
+    var<
+      [int, int != ]>>
+     { dg-end-multiline-output "" } */
+}
+
+void test_fn_4 ()
+{
+  fn_4 (var<> ()); // { dg-error "could not convert .* from 'var<>' to 'vector<var<int> >'" }
+  fn_4 (var<int> ()); // { dg-error "could not convert .* from 'var<int>' to 'vector<var<int> >'" }
+  fn_4 (var<int, int> ()); // { dg-error "could not convert .* from 'var<int, int>' to 'vector<var<int> >'" }
+  fn_4 (vector<var<> >()); // { dg-error "could not convert .* from 'vector<var<>>' to 'vector<var<int>>'" }
+  /* { dg-begin-multiline-output "" }
+  vector<
+    var<
+      [ != int]>>
+     { dg-end-multiline-output "" } */
+  fn_4 (vector<var<int> >()); 
+  fn_4 (vector<var<int, int> >()); // { dg-error "could not convert .* from 'vector<var<int, int>>' to 'vector<var<int>>'" }
+  /* { dg-begin-multiline-output "" }
+  vector<
+    var<
+      [int, int != int]>>
+     { dg-end-multiline-output "" } */
+}
+
+void test_fn_5 ()
+{
+  fn_5 (var<> ()); // { dg-error "could not convert .* from 'var<>' to 'vector<var<int, int> >'" }
+  fn_5 (var<int> ());  // { dg-error "could not convert .* from 'var<int>' to 'vector<var<int, int> >'" }
+  fn_5 (var<int, int> ());  // { dg-error "could not convert .* from 'var<int, int>' to 'vector<var<int, int> >'" }
+  fn_5 (vector<var<int> >());  // { dg-error "could not convert .* from 'vector<var<int>>' to 'vector<var<int, int>>'" }
+  /* { dg-begin-multiline-output "" }
+  vector<
+    var<
+      [int != int, int]>>
+     { dg-end-multiline-output "" } */
+  fn_5 (vector<var<int, int> >());
+}
diff --git a/gcc/testsuite/g++.dg/template/show-template-tree-3.C b/gcc/testsuite/g++.dg/template/show-template-tree-3.C
new file mode 100644 (file)
index 0000000..0eda40b
--- /dev/null
@@ -0,0 +1,37 @@
+/* End-to-end test of -fdiagnostics-show-template-tree and -felide-type
+   using the STL.
+   In particular, ensure that we don't print the default arguments e.g.
+   rather than printing
+     from 'vector<double,allocator<double>>' to 'vector<float,allocator<float>>'
+   (albeit with differences nicely color-coded), we want to print:
+     from 'vector<double>' to 'vector<float>'
+   (again, with the "double" and "float" highlighted, though we can't test
+   for that in this case).  */
+
+// { dg-options "-fdiagnostics-show-template-tree" }
+
+#include <map>
+#include <vector>
+
+using std::vector;
+using std::map;
+
+void takes_vf (vector<float> v);
+void takes_mivf (map<int, vector<float> > v);
+
+int test ()
+{
+  takes_vf (vector<double> ()); // { dg-error "could not convert '.*' from 'vector<double>' to 'vector<float>'" }
+  /* { dg-begin-multiline-output "" }
+  vector<
+    [double != float]>
+     { dg-end-multiline-output "" } */
+
+  takes_mivf (map<int, vector<double> > ()); // { dg-error "could not convert '.*' from 'map<.\\.\\.\\..,vector<double>>' to 'map<.\\.\\.\\..,vector<float>>'" }
+  /* { dg-begin-multiline-output "" }
+  map<
+    [...],
+    vector<
+      [double != float]>>
+     { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/template/show-template-tree-4.C b/gcc/testsuite/g++.dg/template/show-template-tree-4.C
new file mode 100644 (file)
index 0000000..953733b
--- /dev/null
@@ -0,0 +1,95 @@
+// { dg-options "-fdiagnostics-show-template-tree" }
+
+/* Example of default template args, and various kinds of mismatch.  */
+
+template <int = 0, int = 1, int = 2>
+struct s {};
+
+void takes_s (s<> );
+void takes_s013 (s<0, 1, 3> );
+void takes_s321 (s<3, 2, 1> );
+
+void test ()
+{
+  takes_s (s<>());
+  takes_s (s<0, 1>());
+  takes_s (s<0, 1, 2>());
+  takes_s (s<0, 2>()); // { dg-error "could not convert '.*' from 's<.\\.\\.\\..,2>' to 's<.\\.\\.\\..,1>'" }
+  /* { dg-begin-multiline-output "" }
+  s<
+    [...],
+    [2 != 1]>
+     { dg-end-multiline-output "" } */
+
+  takes_s (s<1>()); // { dg-error "could not convert '.*' from 's<1>' to 's<0>'" }
+  /* { dg-begin-multiline-output "" }
+  s<
+    [1 != 0]>
+     { dg-end-multiline-output "" } */
+
+  takes_s (s<0, 1, 3>()); // { dg-error "could not convert '.*' from 's<.\\.\\.\\..,.\\.\\.\\..,3>' to 's<.\\.\\.\\..,.\\.\\.\\..,2>'" }
+  /* { dg-begin-multiline-output "" }
+  s<
+    [...],
+    [...],
+    [3 != 2]>
+     { dg-end-multiline-output "" } */
+
+  takes_s (s<3, 2, 0>()); // { dg-error "could not convert '.*' from 's<3,2,0>' to 's<0,1,2>'" }
+  /* { dg-begin-multiline-output "" }
+  s<
+    [3 != 0],
+    [2 != 1],
+    [0 != 2]>
+     { dg-end-multiline-output "" } */
+
+  takes_s (s<3, 2, 1>()); // { dg-error "could not convert '.*' from 's<3,2,1>' to 's<0,1,2>'" }
+  /* { dg-begin-multiline-output "" }
+  s<
+    [3 != 0],
+    [2 != 1],
+    [1 != 2]>
+     { dg-end-multiline-output "" } */
+
+  takes_s013 (s<0, 1, 2>()); // { dg-error "could not convert '.*' from 's<.\\.\\.\\..,.\\.\\.\\..,2>' to 's<.\\.\\.\\..,.\\.\\.\\..,3>'" }
+  /* { dg-begin-multiline-output "" }
+  s<
+    [...],
+    [...],
+    [2 != 3]>
+     { dg-end-multiline-output "" } */
+
+  takes_s321 (s<>());        // { dg-error "could not convert '.*' from 's<0,1,2>' to 's<3,2,1>'" }
+  /* { dg-begin-multiline-output "" }
+  s<
+    [0 != 3],
+    [1 != 2],
+    [2 != 1]>
+     { dg-end-multiline-output "" } */
+
+  takes_s321 (s<0, 1, 3>()); // { dg-error "could not convert '.*' from 's<0,1,3>' to 's<3,2,1>'" }
+  /* { dg-begin-multiline-output "" }
+  s<
+    [0 != 3],
+    [1 != 2],
+    [3 != 1]>
+     { dg-end-multiline-output "" } */
+
+  takes_s321 (s<3, 2, 0>()); // { dg-error "could not convert '.*' from 's<.\\.\\.\\..,.\\.\\.\\..,0>' to 's<.\\.\\.\\..,.\\.\\.\\..,1>'" }
+  /* { dg-begin-multiline-output "" }
+  s<
+    [...],
+    [...],
+    [0 != 1]>
+     { dg-end-multiline-output "" } */
+
+  takes_s321 (s<3, 2, 1>());
+
+  takes_s321 (s<1, 2, 3>()); // { dg-error "could not convert '.*' from 's<1,.\\.\\.\\..,3>' to 's<3,.\\.\\.\\..,1>'" }
+  /* { dg-begin-multiline-output "" }
+  s<
+    [1 != 3],
+    [...],
+    [3 != 1]>
+     { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/template/show-template-tree-no-elide-type.C b/gcc/testsuite/g++.dg/template/show-template-tree-no-elide-type.C
new file mode 100644 (file)
index 0000000..d4bfa81
--- /dev/null
@@ -0,0 +1,24 @@
+// { dg-options "-fdiagnostics-show-template-tree -fno-elide-type" }
+
+template<typename> struct vector {};
+template<typename, typename> struct map {};
+
+void fn_1(vector<int>);
+void fn_2(map<int, int>);
+void fn_3(vector<map<int, float> >);
+
+void test ()
+{
+  fn_1 (vector<double> ()); // { dg-error "could not convert .* from 'vector<double>' to 'vector<int>'" }
+  /* { dg-begin-multiline-output "" }
+  vector<
+    [double != int]>
+     { dg-end-multiline-output "" } */
+
+  fn_2 (map<int, double>());  // { dg-error "could not convert .* from 'map<int,double>' to 'map<int,int>'" }
+  /* { dg-begin-multiline-output "" }
+  map<
+    int,
+    [double != int]>
+     { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/template/show-template-tree.C b/gcc/testsuite/g++.dg/template/show-template-tree.C
new file mode 100644 (file)
index 0000000..0b75098
--- /dev/null
@@ -0,0 +1,51 @@
+// { dg-options "-fdiagnostics-show-template-tree" }
+
+template<typename> struct vector {};
+template<typename, typename> struct map {};
+template<int> struct arr {};
+
+void fn_1(vector<int>);
+void fn_2(map<int, int>);
+void fn_3(vector<map<int, float> >);
+void takes_arr_10 (arr<10>);
+
+void test ()
+{
+  fn_1 (vector<int> ());
+  fn_1 (42); // { dg-error "could not convert '42' from 'int' to 'vector<int>'" }
+  fn_1 (vector<double> ()); // { dg-error "could not convert .* from 'vector<double>' to 'vector<int>'" }
+  /* { dg-begin-multiline-output "" }
+  vector<
+    [double != int]>
+     { dg-end-multiline-output "" } */
+  fn_1 (map<int, int> ()); // { dg-error "could not convert .* from 'map<int, int>' to 'vector<int>'" }
+
+  fn_2 (map<int, int>());
+  fn_2 (map<int, double>());  // { dg-error "could not convert .* from 'map<.\\.\\.\\..,double>. to .map<.\\.\\.\\..,int>'" }
+  /* { dg-begin-multiline-output "" }
+  map<
+    [...],
+    [double != int]>
+     { dg-end-multiline-output "" } */
+  fn_2 (map<double, double>());  // { dg-error "could not convert .* from .map<double,double>. to .map<int,int>." }
+  /* { dg-begin-multiline-output "" }
+  map<
+    [double != int],
+    [double != int]>
+     { dg-end-multiline-output "" } */
+
+  fn_3 (vector<map<int, float> >());
+  fn_3 (vector<map<int, double> >());  // { dg-error "could not convert .* from 'vector<map<.\\.\\.\\..,double>>' to 'vector<map<.\\.\\.\\..,float>>'" }
+  /* { dg-begin-multiline-output "" }
+  vector<
+    map<
+      [...],
+      [double != float]>>
+     { dg-end-multiline-output "" } */
+
+  takes_arr_10 (arr<5>()); // { dg-error "could not convert '.*' from 'arr<5>' to 'arr<10>'" }
+  /* { dg-begin-multiline-output "" }
+  arr<
+    [5 != 10]>
+     { dg-end-multiline-output "" } */
+}
index 1009c78ab3cf1a48b221f10475b60db6aea7d5cf..52b7e7f0bb4420b24a317b613596fa7f3407aef6 100644 (file)
@@ -244,7 +244,8 @@ virt_loc_aware_diagnostic_finalizer (diagnostic_context *context,
 /* Default tree printer.   Handles declarations only.  */
 bool
 default_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
-                     int precision, bool wide, bool set_locus, bool hash)
+                     int precision, bool wide, bool set_locus, bool hash,
+                     bool, const char **)
 {
   tree t;
 
index e95183f92f7e260a401047b04e2a06111bbcad84..85aa980aeb97d9702e7e873f5a2b426138f55149 100644 (file)
@@ -55,6 +55,6 @@ void virt_loc_aware_diagnostic_finalizer (diagnostic_context *,
 
 void tree_diagnostics_defaults (diagnostic_context *context);
 bool default_tree_printer (pretty_printer *, text_info *, const char *,
-                          int, bool, bool, bool);
+                          int, bool, bool, bool, bool, const char **);
 
 #endif /* ! GCC_TREE_DIAGNOSTIC_H */