+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.
+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.
/* 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 },
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.
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.
+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
#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)
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;
+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
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))
}
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);
}
{
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);
}
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. */
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;
}
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);
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));
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);
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),
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 ();
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);
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");
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;
&& !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;
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;
}
{
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;
}
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;
}
}
}
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;
}
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;
}
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;
}
&& !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;
}
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;
}
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;
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
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. */
}
}
\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.
%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))
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;
}
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);
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);
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;
&& 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
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:
{
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;
}
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 "
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;
{ "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 }
};
/* 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)
-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
@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,
@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
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
+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
*/
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)
{
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);
}
}
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);
}
}
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;
indent_skip (),
wrapping (),
format_decoder (),
+ m_format_postprocessor (NULL),
emitted_prefix (),
need_newline (),
translate_identifiers (true),
pretty_printer::~pretty_printer ()
{
+ if (m_format_postprocessor)
+ delete m_format_postprocessor;
buffer->~output_buffer ();
XDELETE (buffer);
}
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
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;
+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
{ 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 {
--- /dev/null
+/* 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 "" } */
+}
--- /dev/null
+/* 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 "" } */
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+// 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> >());
+}
--- /dev/null
+/* 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 "" } */
+}
--- /dev/null
+// { 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 "" } */
+}
--- /dev/null
+// { 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 "" } */
+}
--- /dev/null
+// { 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 "" } */
+}
/* 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;
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 */