From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12903 invoked by alias); 9 May 2017 13:35:45 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 12837 invoked by uid 89); 9 May 2017 13:35:45 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-23.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_LAZY_DOMAIN_SECURITY,RP_MATCHES_RCVD,SPF_HELO_PASS,UNSUBSCRIBE_BODY autolearn=ham version=3.3.2 spammy=LINE X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 09 May 2017 13:35:37 +0000 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1AF23C05490A; Tue, 9 May 2017 13:35:39 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 1AF23C05490A Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=dmalcolm@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 1AF23C05490A Received: from c64.redhat.com (ovpn-112-30.phx2.redhat.com [10.3.112.30]) by smtp.corp.redhat.com (Postfix) with ESMTP id AE53DA2517; Tue, 9 May 2017 13:35:37 +0000 (UTC) From: David Malcolm To: Nathan Sidwell , gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [PATCH 1/2] (v2) C++ template type diff printing Date: Tue, 09 May 2017 13:39:00 -0000 Message-Id: <1494338830-7392-1-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1494262293.9106.218.camel@redhat.com> References: <1494262293.9106.218.camel@redhat.com> X-IsSubscribed: yes X-SW-Source: 2017-05/txt/msg00655.txt.bz2 Changes in v2: - pass "quote" as an extra bool argument to the pp_format_decoder callback, so that we can optionally quote the delayed chunks (with %qH and %qI) - use %qH and %qI rather than %H and %I. - use CLASS_TYPE_P. - use TYPE_P rather than EXPR_P in arg_to_string to handle non-type template arguments; added test cases for this - in type_to_string_with_compare, drop the "foo_a" and "foo_b" naming convention in favor of "foo" vs "foo_peer", since here we could be dealing with either %H or %I, either way around. Remove logic for returning NULL types, and clairy behavior for handling of mixtures of default and non-default args, adding test coverage for this. For example, given: template struct s {}; void takes_s (s<> ); then: takes_s (s<0, 2>()); is reported as: can't convert from 's<[...],2>' to 's<[...], 1>' highlighting the "2" and "1", rather than can't convert from 's<0,2>' to 's<>' since these are the arguments of interest. The template tree comparison for this case is printed as: s< [...] [2 != 1]> - renamed "defer_half_of_type_diff" to "defer_phase_2_of_type_diff", and rewrite to avoid a switch statement Would it make sense to rename "m_type_a"/"m_type_b" to "m_type_H"/m_type_I"? (we normally don't go for uppercase in fieldnames, but given the codes are case-sensitive, does it make sense here?) Successfully bootstrapped®rtested the combination of the two patches on x86_64-pc-linux-gnu. 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. * c-format.c (static): Likewise. gcc/c/ChangeLog: * c-objc-common.c (c_tree_printer): Gain bool and const char ** parameters. gcc/cp/ChangeLog: * call.c (perform_implicit_conversion_flags): Convert "from %qT to %qT" to "from %qH to %qI" in diagnostic. * error.c (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. (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. 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 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/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. --- gcc/c-family/c-format.c | 2 +- gcc/c-family/c.opt | 8 + gcc/c/c-objc-common.c | 5 +- gcc/cp/call.c | 2 +- gcc/cp/error.c | 438 ++++++++++++++++++++- gcc/diagnostic-color.c | 6 +- gcc/doc/invoke.texi | 50 ++- gcc/fortran/error.c | 5 +- gcc/pretty-print.c | 11 +- gcc/pretty-print.h | 20 +- gcc/testsuite/g++.dg/plugin/plugin.exp | 3 + .../show-template-tree-color-no-elide-type.C | 30 ++ .../g++.dg/plugin/show-template-tree-color.C | 30 ++ .../plugin/show_template_tree_color_plugin.c | 38 ++ .../g++.dg/template/show-template-tree-2.C | 118 ++++++ .../g++.dg/template/show-template-tree-3.C | 37 ++ .../g++.dg/template/show-template-tree-4.C | 95 +++++ .../template/show-template-tree-no-elide-type.C | 24 ++ gcc/testsuite/g++.dg/template/show-template-tree.C | 51 +++ gcc/tree-diagnostic.c | 3 +- gcc/tree-diagnostic.h | 2 +- 21 files changed, 961 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-elide-type.C create mode 100644 gcc/testsuite/g++.dg/plugin/show-template-tree-color.C create mode 100644 gcc/testsuite/g++.dg/plugin/show_template_tree_color_plugin.c create mode 100644 gcc/testsuite/g++.dg/template/show-template-tree-2.C create mode 100644 gcc/testsuite/g++.dg/template/show-template-tree-3.C create mode 100644 gcc/testsuite/g++.dg/template/show-template-tree-4.C create mode 100644 gcc/testsuite/g++.dg/template/show-template-tree-no-elide-type.C create mode 100644 gcc/testsuite/g++.dg/template/show-template-tree.C diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c index 400eb66..fd40359 100644 --- a/gcc/c-family/c-format.c +++ b/gcc/c-family/c-format.c @@ -754,7 +754,7 @@ static const format_char_info gcc_cxxdiag_char_table[] = /* Custom conversion specifiers. */ /* These will require a "tree" at runtime. */ - { "ADEFKSTVX",0,STD_C89,{ T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "", NULL }, + { "ADEFHIKSTVX",0,STD_C89,{ T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "", NULL }, { "v", 0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q#", "", NULL }, diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 9ad2f6e..4648e60 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1342,6 +1342,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. @@ -1361,6 +1365,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. diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c index 5e69488..05212b2 100644 --- a/gcc/c/c-objc-common.c +++ b/gcc/c/c-objc-common.c @@ -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; diff --git a/gcc/cp/call.c b/gcc/cp/call.c index c15b8e4..f1b6bf4 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -10099,7 +10099,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; diff --git a/gcc/cp/error.c b/gcc/cp/error.c index a83ecb2..ccd4bdc 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -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. */ @@ -3565,6 +3609,373 @@ maybe_print_constexpr_context (diagnostic_context *context) } } + +/* 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)"))); +} + +/* As type_to_string, but for a template, potentially colorizing/eliding + in comparison with PEER. + For example, if TYPE is map and PEER is map, + then the resulting string would be: + map<[...],double> + with type elision, and: + map + 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; + + tree tinfo = TYPE_TEMPLATE_INFO (type); + tree tinfo_peer = TYPE_TEMPLATE_INFO (peer); + + pp_printf (pp, "%s<", + IDENTIFIER_POINTER (DECL_NAME (TI_TEMPLATE (tinfo)))); + tree args = TI_ARGS (tinfo); + tree args_peer = TI_ARGS (tinfo_peer); + gcc_assert (TREE_CODE (args) == TREE_VEC); + gcc_assert (TREE_CODE (args_peer) == TREE_VEC); + int flags = 0; + int len = get_non_default_template_args_count (args, flags); + args = INNERMOST_TEMPLATE_ARGS (args); + int len_peer = get_non_default_template_args_count (args_peer, flags); + args_peer = INNERMOST_TEMPLATE_ARGS (args_peer); + /* 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, len_peer); + for (int idx = 0; idx < len_max; idx++) + { + tree arg = TREE_VEC_ELT (args, idx); + tree arg_peer = TREE_VEC_ELT (args_peer, idx); + if (arg == arg_peer) + { + if (flag_elide_type) + pp_string (pp, G_("[...]")); + else + pp_string (pp, arg_to_string (arg, verbose)); + } + else + { + if (comparable_template_types_p (arg, arg_peer)) + pp_string (pp, + type_to_string_with_compare (arg, arg_peer, verbose, + show_color)); + else + print_nonequal_arg (pp, arg, verbose); + } + if (idx + 1 < len_max) + pp_character (pp, ','); + } + pp_printf (pp, ">"); + 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> + + and + + vector> + + 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) +{ + tree tinfo_a = TYPE_TEMPLATE_INFO (type_a); + tree tinfo_b = TYPE_TEMPLATE_INFO (type_b); + + newline_and_indent (pp, indent); + 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); + 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); + 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++) + { + tree arg_a = TREE_VEC_ELT (args_a, idx); + tree arg_b = TREE_VEC_ELT (args_b, idx); + if (arg_a == arg_b) + { + 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 + { + if (comparable_template_types_p (arg_a, arg_b)) + print_template_tree_comparison (pp, arg_a, arg_b, verbose, + indent + 2); + else + { + 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, ']'); + } + } + if (idx + 1 < len_max) + pp_character (pp, ','); + } + pp_printf (pp, ">"); +} + +/* 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) + { + gcc_assert (m_type_a.m_tree); + gcc_assert (m_type_b.m_tree); + } + + 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_tree); + gcc_assert (type_a.m_buffer_ptr); + gcc_assert (type_b.m_tree); + 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' to 'map' + + 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. @@ -3579,11 +3990,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 (pp->m_format_postprocessor); + const char *result; tree t = NULL; #define next_tree (t = va_arg (*text->args_ptr, tree)) @@ -3629,6 +4047,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; } diff --git a/gcc/diagnostic-color.c b/gcc/diagnostic-color.c index 8353fe0..6adb872 100644 --- a/gcc/diagnostic-color.c +++ b/gcc/diagnostic-color.c @@ -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) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 65308c9..9966fa0 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 @@ -3442,7 +3443,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, @@ -3506,6 +3508,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 @@ -3578,6 +3585,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 >()' + from 'map<[...],vector>' to 'map<[...],vector> +@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 >()' + from 'map<[...],vector>' to 'map<[...],vector> +@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 diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c index 0312499..af72581 100644 --- a/gcc/fortran/error.c +++ b/gcc/fortran/error.c @@ -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); } } diff --git a/gcc/pretty-print.c b/gcc/pretty-print.c index bcb1a70..570dec7 100644 --- a/gcc/pretty-print.c +++ b/gcc/pretty-print.c @@ -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); } diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h index 2596678..40e56a3 100644 --- a/gcc/pretty-print.h +++ b/gcc/pretty-print.h @@ -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; diff --git a/gcc/testsuite/g++.dg/plugin/plugin.exp b/gcc/testsuite/g++.dg/plugin/plugin.exp index 6a0c1aa..94ebe93 100644 --- a/gcc/testsuite/g++.dg/plugin/plugin.exp +++ b/gcc/testsuite/g++.dg/plugin/plugin.exp @@ -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 index 0000000..cab0359 --- /dev/null +++ b/gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-elide-type.C @@ -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 struct vector {}; +template struct map {}; + +void fn_1(vector); +void fn_2(map); + +void test () +{ + fn_1 (vector ()); + /* { dg-begin-multiline-output "" } +could not convert 'vector()' from 'vector<double>' to 'vector<int>' + vector< + [double != int]> + { dg-end-multiline-output "" } */ + + fn_2 (map()); + /* { dg-begin-multiline-output "" } +could not convert 'map()' from 'map' to 'map' + map< + int, + [double != int]> + { 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 index 0000000..eb99a3e --- /dev/null +++ b/gcc/testsuite/g++.dg/plugin/show-template-tree-color.C @@ -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 struct vector {}; +template struct map {}; + +void fn_1(vector); +void fn_2(map); + +void test () +{ + fn_1 (vector ()); + /* { dg-begin-multiline-output "" } +could not convert 'vector()' from 'vector<double>' to 'vector<int>' + vector< + [double != int]> + { dg-end-multiline-output "" } */ + + fn_2 (map()); + /* { dg-begin-multiline-output "" } +could not convert 'map()' from 'map<[...],double>' to 'map<[...],int>' + map< + [...], + [double != int]> + { 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 index 0000000..af568bf --- /dev/null +++ b/gcc/testsuite/g++.dg/plugin/show_template_tree_color_plugin.c @@ -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 index 0000000..1cd3a06 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/show-template-tree-2.C @@ -0,0 +1,118 @@ +// Tests of -fdiagnostics-show-template-tree with variadic templates +// { dg-options "-fdiagnostics-show-template-tree -std=c++11" } + +template struct vector {}; +template struct map {}; +template struct var {}; + +void fn_0(var<>); +void fn_1(var); +void fn_2(var); +void fn_3(vector >); +void fn_4(vector >); +void fn_5(vector >); + +void test_fn_0 () +{ + fn_0 (var<> ()); + fn_0 (var ()); // { dg-error "could not convert .* from 'var' to 'var<>'" } + /* { dg-begin-multiline-output "" } + var< + [int != ]> + { dg-end-multiline-output "" } */ + fn_0 (var ()); // { dg-error "could not convert .* from 'var' to 'var<>'" } + /* { dg-begin-multiline-output "" } + var< + [int, int != ]> + { dg-end-multiline-output "" } */ + fn_0 (vector >()); // { dg-error "could not convert .* from 'vector >' to 'var<>'" } + fn_0 (vector >()); // { dg-error "could not convert .* from 'vector >' to 'var<>'" } +} + +void test_fn_1 () +{ + fn_1 (var<> ()); // { dg-error "could not convert .* from 'var<>' to 'var'" } + /* { dg-begin-multiline-output "" } + var< + [ != int]> + { dg-end-multiline-output "" } */ + fn_1 (var ()); + fn_1 (var ()); // { dg-error "could not convert .* from 'var' to 'var'" } + /* { dg-begin-multiline-output "" } + var< + [int, int != int]> + { dg-end-multiline-output "" } */ + fn_1 (vector >()); // { dg-error "could not convert .* from 'vector >' to 'var'" } + fn_1 (vector >()); // { dg-error "could not convert .* from 'vector >' to 'var'" } +} + +void test_fn_2 () +{ + fn_2 (var<> ()); // { dg-error "could not convert .* from 'var<>' to 'var'" } + /* { dg-begin-multiline-output "" } + var< + [ != int, int]> + { dg-end-multiline-output "" } */ + fn_2 (var ()); // { dg-error "could not convert .* from 'var' to 'var'" } + /* { dg-begin-multiline-output "" } + var< + [int != int, int]> + { dg-end-multiline-output "" } */ + fn_2 (var ()); + fn_2 (vector >()); // { dg-error "could not convert .* from 'vector >' to 'var'" } + fn_2 (vector >()); // { dg-error "could not convert .* from 'vector >' to 'var'" } +} + +void test_fn_3 () +{ + fn_3 (var<> ()); // { dg-error "could not convert .* from 'var<>' to 'vector >'" } + fn_3 (var ()); // { dg-error "could not convert .* from 'var' to 'vector >'" } + fn_3 (var ()); // { dg-error "could not convert .* from 'var' to 'vector >'" } + fn_3 (vector >()); + fn_3 (vector >()); // { dg-error "could not convert .* from 'vector>' to 'vector>'" } + /* { dg-begin-multiline-output "" } + vector< + var< + [int != ]>> + { dg-end-multiline-output "" } */ + fn_3 (vector >()); // { dg-error "could not convert .* from 'vector>' to 'vector>'" } + /* { 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 >'" } + fn_4 (var ()); // { dg-error "could not convert .* from 'var' to 'vector >'" } + fn_4 (var ()); // { dg-error "could not convert .* from 'var' to 'vector >'" } + fn_4 (vector >()); // { dg-error "could not convert .* from 'vector>' to 'vector>'" } + /* { dg-begin-multiline-output "" } + vector< + var< + [ != int]>> + { dg-end-multiline-output "" } */ + fn_4 (vector >()); + fn_4 (vector >()); // { dg-error "could not convert .* from 'vector>' to 'vector>'" } + /* { 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 >'" } + fn_5 (var ()); // { dg-error "could not convert .* from 'var' to 'vector >'" } + fn_5 (var ()); // { dg-error "could not convert .* from 'var' to 'vector >'" } + fn_5 (vector >()); // { dg-error "could not convert .* from 'vector>' to 'vector>'" } + /* { dg-begin-multiline-output "" } + vector< + var< + [int != int, int]>> + { dg-end-multiline-output "" } */ + fn_5 (vector >()); +} 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 index 0000000..0eda40b --- /dev/null +++ b/gcc/testsuite/g++.dg/template/show-template-tree-3.C @@ -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>' to 'vector>' + (albeit with differences nicely color-coded), we want to print: + from 'vector' to 'vector' + (again, with the "double" and "float" highlighted, though we can't test + for that in this case). */ + +// { dg-options "-fdiagnostics-show-template-tree" } + +#include +#include + +using std::vector; +using std::map; + +void takes_vf (vector v); +void takes_mivf (map > v); + +int test () +{ + takes_vf (vector ()); // { dg-error "could not convert '.*' from 'vector' to 'vector'" } + /* { dg-begin-multiline-output "" } + vector< + [double != float]> + { dg-end-multiline-output "" } */ + + takes_mivf (map > ()); // { dg-error "could not convert '.*' from 'map<.\\.\\.\\..,vector>' to 'map<.\\.\\.\\..,vector>'" } + /* { 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 index 0000000..953733b --- /dev/null +++ b/gcc/testsuite/g++.dg/template/show-template-tree-4.C @@ -0,0 +1,95 @@ +// { dg-options "-fdiagnostics-show-template-tree" } + +/* Example of default template args, and various kinds of mismatch. */ + +template +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 index 0000000..d4bfa81 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/show-template-tree-no-elide-type.C @@ -0,0 +1,24 @@ +// { dg-options "-fdiagnostics-show-template-tree -fno-elide-type" } + +template struct vector {}; +template struct map {}; + +void fn_1(vector); +void fn_2(map); +void fn_3(vector >); + +void test () +{ + fn_1 (vector ()); // { dg-error "could not convert .* from 'vector' to 'vector'" } + /* { dg-begin-multiline-output "" } + vector< + [double != int]> + { dg-end-multiline-output "" } */ + + fn_2 (map()); // { dg-error "could not convert .* from 'map' to 'map'" } + /* { 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 index 0000000..0b75098 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/show-template-tree.C @@ -0,0 +1,51 @@ +// { dg-options "-fdiagnostics-show-template-tree" } + +template struct vector {}; +template struct map {}; +template struct arr {}; + +void fn_1(vector); +void fn_2(map); +void fn_3(vector >); +void takes_arr_10 (arr<10>); + +void test () +{ + fn_1 (vector ()); + fn_1 (42); // { dg-error "could not convert '42' from 'int' to 'vector'" } + fn_1 (vector ()); // { dg-error "could not convert .* from 'vector' to 'vector'" } + /* { dg-begin-multiline-output "" } + vector< + [double != int]> + { dg-end-multiline-output "" } */ + fn_1 (map ()); // { dg-error "could not convert .* from 'map' to 'vector'" } + + fn_2 (map()); + fn_2 (map()); // { 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()); // { dg-error "could not convert .* from .map. to .map." } + /* { dg-begin-multiline-output "" } + map< + [double != int], + [double != int]> + { dg-end-multiline-output "" } */ + + fn_3 (vector >()); + fn_3 (vector >()); // { dg-error "could not convert .* from 'vector>' to 'vector>'" } + /* { 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 "" } */ +} diff --git a/gcc/tree-diagnostic.c b/gcc/tree-diagnostic.c index 4f211ed..ebce1a4 100644 --- a/gcc/tree-diagnostic.c +++ b/gcc/tree-diagnostic.c @@ -245,7 +245,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; diff --git a/gcc/tree-diagnostic.h b/gcc/tree-diagnostic.h index e95183f..85aa980 100644 --- a/gcc/tree-diagnostic.h +++ b/gcc/tree-diagnostic.h @@ -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 */ -- 1.8.5.3