aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog42
-rw-r--r--gcc/cp/call.c40
-rw-r--r--gcc/cp/cvt.c18
-rw-r--r--gcc/cp/error.c453
-rw-r--r--gcc/cp/typeck.c22
-rw-r--r--gcc/cp/typeck2.c6
6 files changed, 535 insertions, 46 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3da2f97..2dac610 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,45 @@
+2017-05-30 David Malcolm <dmalcolm@redhat.com>
+
+ * call.c (perform_implicit_conversion_flags): Convert
+ "from %qT to %qT" to "from %qH to %qI" in diagnostic.
+ (print_conversion_rejection): Replace pairs of %qT with
+ %qH and %qI in various places.
+ (build_user_type_conversion_1): Likewise.
+ (build_integral_nontype_arg_conv): Likewise.
+ (build_conditional_expr_1): Likewise.
+ (convert_like_real): Likewise.
+ (convert_arg_to_ellipsis): Likewise.
+ (joust): Likewise.
+ (initialize_reference): Likewise.
+ * cvt.c (cp_convert_to_pointer): Likewise.
+ (cp_convert_to_pointer): Likewise.
+ (convert_to_reference): Likewise.
+ (ocp_convert): Likewise.
+ * error.c (cp_printer): Gain bool and const char ** parameters.
+ (struct deferred_printed_type): New struct.
+ (class cxx_format_postprocessor): New class.
+ (cxx_initialize_diagnostics): Wire up a cxx_format_postprocessor
+ to pp->m_format_postprocessor.
+ (comparable_template_types_p): New function.
+ (newline_and_indent): New function.
+ (arg_to_string): New function.
+ (print_nonequal_arg): New function.
+ (print_template_differences): New function.
+ (type_to_string_with_compare): New function.
+ (print_template_tree_comparison): New function.
+ (append_formatted_chunk): New function.
+ (add_quotes): New function.
+ (cxx_format_postprocessor::handle): New function.
+ (defer_phase_2_of_type_diff): New function.
+ (cp_printer): Add "quoted" and "buffer_ptr" params. Implement
+ %H and %I.
+ * typeck.c (cp_build_binary_op): Replace pairs of %qT with
+ %qH and %qI in various places.
+ (convert_member_func_to_ptr): Likewise.
+ (build_reinterpret_cast_1): Likewise.
+ (convert_for_assignment): Likewise.
+ * typeck2.c (check_narrowing): Likewise.
+
2017-05-30 Nathan Sidwell <nathan@acm.org>
Kill IDENTIFIER_NAMESPACE_BINDINGS
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index c1fcd19..51260f0 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -3402,7 +3402,7 @@ print_conversion_rejection (location_t loc, struct conversion_info *info)
from);
else
inform (loc, " no known conversion for implicit "
- "%<this%> parameter from %qT to %qT",
+ "%<this%> parameter from %qH to %qI",
from, info->to_type);
}
else if (!TYPE_P (info->from))
@@ -3415,10 +3415,10 @@ print_conversion_rejection (location_t loc, struct conversion_info *info)
}
else if (info->n_arg == -2)
/* Conversion of conversion function return value failed. */
- inform (loc, " no known conversion from %qT to %qT",
+ inform (loc, " no known conversion from %qH to %qI",
from, info->to_type);
else
- inform (loc, " no known conversion for argument %d from %qT to %qT",
+ inform (loc, " no known conversion for argument %d from %qH to %qI",
info->n_arg + 1, from, info->to_type);
}
@@ -3925,7 +3925,7 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags,
{
if (complain & tf_error)
{
- error ("conversion from %qT to %qT is ambiguous",
+ error ("conversion from %qH to %qI is ambiguous",
fromtype, totype);
print_z_candidates (location_of (expr), candidates);
}
@@ -4052,7 +4052,7 @@ build_integral_nontype_arg_conv (tree type, tree expr, tsubst_flags_t complain)
break;
if (complain & tf_error)
- error_at (loc, "conversion from %qT to %qT not considered for "
+ error_at (loc, "conversion from %qH to %qI not considered for "
"non-type template argument", t, type);
/* fall through. */
@@ -4818,14 +4818,14 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
if (unsafe_conversion_p (loc, stype, arg2, NULL_TREE, false))
{
if (complain & tf_error)
- error_at (loc, "conversion of scalar %qT to vector %qT "
+ error_at (loc, "conversion of scalar %qH to vector %qI "
"involves truncation", arg2_type, vtype);
return error_mark_node;
}
if (unsafe_conversion_p (loc, stype, arg3, NULL_TREE, false))
{
if (complain & tf_error)
- error_at (loc, "conversion of scalar %qT to vector %qT "
+ error_at (loc, "conversion of scalar %qH to vector %qI "
"involves truncation", arg3_type, vtype);
return error_mark_node;
}
@@ -5214,7 +5214,7 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
arg3_type);
if (complain & tf_warning)
do_warn_double_promotion (result_type, arg2_type, arg3_type,
- "implicit conversion from %qT to %qT to "
+ "implicit conversion from %qH to %qI to "
"match other result of conditional",
loc);
@@ -6593,7 +6593,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
from std::nullptr_t requires direct-initialization. */
if (NULLPTR_TYPE_P (TREE_TYPE (expr))
&& TREE_CODE (totype) == BOOLEAN_TYPE)
- complained = permerror (loc, "converting to %qT from %qT requires "
+ complained = permerror (loc, "converting to %qH from %qI requires "
"direct-initialization",
totype, TREE_TYPE (expr));
@@ -6602,7 +6602,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
if (t->kind == ck_user && t->cand->reason)
{
complained = permerror (loc, "invalid user-defined conversion "
- "from %qT to %qT", TREE_TYPE (expr),
+ "from %qH to %qI", TREE_TYPE (expr),
totype);
if (complained)
print_z_candidate (loc, "candidate is:", t->cand);
@@ -6638,7 +6638,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
break;
}
if (!complained)
- complained = permerror (loc, "invalid conversion from %qT to %qT",
+ complained = permerror (loc, "invalid conversion from %qH to %qI",
TREE_TYPE (expr), totype);
if (complained && fn)
inform (DECL_SOURCE_LOCATION (fn),
@@ -6914,14 +6914,14 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
tree extype = TREE_TYPE (expr);
if (TYPE_REF_IS_RVALUE (ref_type)
&& lvalue_p (expr))
- error_at (loc, "cannot bind rvalue reference of type %qT to "
- "lvalue of type %qT", totype, extype);
+ error_at (loc, "cannot bind rvalue reference of type %qH to "
+ "lvalue of type %qI", totype, extype);
else if (!TYPE_REF_IS_RVALUE (ref_type) && !lvalue_p (expr)
&& !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type)))
error_at (loc, "cannot bind non-const lvalue reference of "
- "type %qT to an rvalue of type %qT", totype, extype);
+ "type %qH to an rvalue of type %qI", totype, extype);
else if (!reference_compatible_p (TREE_TYPE (totype), extype))
- error_at (loc, "binding reference of type %qT to %qT "
+ error_at (loc, "binding reference of type %qH to %qI "
"discards qualifiers", totype, extype);
else
gcc_unreachable ();
@@ -7073,7 +7073,7 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain)
if ((complain & tf_warning)
&& warn_double_promotion && !c_inhibit_evaluation_warnings)
warning_at (loc, OPT_Wdouble_promotion,
- "implicit conversion from %qT to %qT when passing "
+ "implicit conversion from %qH to %qI when passing "
"argument to function",
arg_type, double_type_node);
arg = convert_to_real_nofold (double_type_node, arg);
@@ -9640,7 +9640,7 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
if (! DECL_CONSTRUCTOR_P (w->fn))
source = TREE_TYPE (source);
if (warning (OPT_Wconversion, "choosing %qD over %qD", w->fn, l->fn)
- && warning (OPT_Wconversion, " for conversion from %qT to %qT",
+ && warning (OPT_Wconversion, " for conversion from %qH to %qI",
source, w->second_conv->type))
{
inform (input_location, " because conversion sequence for the argument is better");
@@ -10096,7 +10096,7 @@ perform_implicit_conversion_flags (tree type, tree expr,
else if (invalid_nonstatic_memfn_p (loc, expr, complain))
/* We gave an error. */;
else
- error_at (loc, "could not convert %qE from %qT to %qT", expr,
+ error_at (loc, "could not convert %qE from %qH to %qI", expr,
TREE_TYPE (expr), type);
}
expr = error_mark_node;
@@ -10412,11 +10412,11 @@ initialize_reference (tree type, tree expr,
&& !TYPE_REF_IS_RVALUE (type)
&& !lvalue_p (expr))
error_at (loc, "invalid initialization of non-const reference of "
- "type %qT from an rvalue of type %qT",
+ "type %qH from an rvalue of type %qI",
type, TREE_TYPE (expr));
else
error_at (loc, "invalid initialization of reference of type "
- "%qT from expression of type %qT", type,
+ "%qH from expression of type %qI", type,
TREE_TYPE (expr));
}
return error_mark_node;
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index a53c0b3..e8a7ee2 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -86,7 +86,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold,
if (!COMPLETE_TYPE_P (intype))
{
if (complain & tf_error)
- error_at (loc, "can%'t convert from incomplete type %qT to %qT",
+ error_at (loc, "can%'t convert from incomplete type %qH to %qI",
intype, type);
return error_mark_node;
}
@@ -96,7 +96,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold,
{
if ((complain & tf_error)
&& rval == error_mark_node)
- error_at (loc, "conversion of %qE from %qT to %qT is ambiguous",
+ error_at (loc, "conversion of %qE from %qH to %qI is ambiguous",
expr, intype, type);
return rval;
}
@@ -168,7 +168,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold,
if (TYPE_PTRMEMFUNC_P (type))
{
if (complain & tf_error)
- error_at (loc, "cannot convert %qE from type %qT to type %qT",
+ error_at (loc, "cannot convert %qE from type %qH to type %qI",
expr, intype, type);
return error_mark_node;
}
@@ -195,7 +195,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold,
}
}
if (complain & tf_error)
- error_at (loc, "cannot convert %qE from type %qT to type %qT",
+ error_at (loc, "cannot convert %qE from type %qH to type %qI",
expr, intype, type);
return error_mark_node;
}
@@ -221,7 +221,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold,
else if (TYPE_PTRMEM_P (type) && INTEGRAL_CODE_P (form))
{
if (complain & tf_error)
- error_at (loc, "invalid conversion from %qT to %qT", intype, type);
+ error_at (loc, "invalid conversion from %qH to %qI", intype, type);
return error_mark_node;
}
@@ -244,7 +244,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold,
return instantiate_type (type, expr, complain);
if (complain & tf_error)
- error_at (loc, "cannot convert %qE from type %qT to type %qT",
+ error_at (loc, "cannot convert %qE from type %qH to type %qI",
expr, intype, type);
return error_mark_node;
}
@@ -464,7 +464,7 @@ convert_to_reference (tree reftype, tree expr, int convtype,
&& !at_least_as_qualified_p (ttl, ttr))
{
if (complain & tf_error)
- permerror (loc, "conversion from %qT to %qT discards qualifiers",
+ permerror (loc, "conversion from %qH to %qI discards qualifiers",
ttr, reftype);
else
return error_mark_node;
@@ -514,7 +514,7 @@ convert_to_reference (tree reftype, tree expr, int convtype,
}
if (complain & tf_error)
- error_at (loc, "cannot convert type %qT to type %qT", intype, reftype);
+ error_at (loc, "cannot convert type %qH to type %qI", intype, reftype);
return error_mark_node;
}
@@ -907,7 +907,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
if (invalid_nonstatic_memfn_p (loc, expr, complain))
/* We displayed the error message. */;
else
- error_at (loc, "conversion from %qT to non-scalar type %qT requested",
+ error_at (loc, "conversion from %qH to non-scalar type %qI requested",
TREE_TYPE (expr), type);
}
return error_mark_node;
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 8481e2d..ed67d14 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. */
@@ -3563,6 +3607,388 @@ 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)")));
+}
+
+/* Recursively print template TYPE_A to PP, as compared to template TYPE_B.
+
+ The types must satisfy comparable_template_types_p.
+
+ If INDENT is 0, then this is equivalent to type_to_string (TYPE_A), but
+ potentially colorizing/eliding in comparison with TYPE_B.
+
+ For example given types:
+ vector<map<int,double>>
+ and
+ vector<map<int,float>>
+ then the result on PP would be:
+ vector<map<[...],double>>
+ with type elision, and:
+ vector<map<int,double>>
+ without type elision.
+
+ In both cases the parts of TYPE that differ from PEER will be colorized
+ if pp_show_color (pp) is true. In the above example, this would be
+ "double".
+
+ If INDENT is non-zero, then the types are printed in a tree-like form
+ which shows both types. In the above example, the result on PP would be:
+
+ vector<
+ map<
+ [...],
+ [double != float]>>
+
+ and without type-elision would be:
+
+ vector<
+ map<
+ int,
+ [double != float]>>
+
+ As before, the differing parts of the types are colorized if
+ pp_show_color (pp) is true ("double" and "float" in this example).
+
+ Template arguments in which both types are using the default arguments
+ are not printed; if at least one of the two types is using a non-default
+ argument, then that argument is printed (or both arguments for the
+ tree-like print format). */
+
+static void
+print_template_differences (pretty_printer *pp, tree type_a, tree type_b,
+ bool verbose, int indent)
+{
+ if (indent)
+ newline_and_indent (pp, indent);
+
+ tree tinfo_a = TYPE_TEMPLATE_INFO (type_a);
+ tree tinfo_b = TYPE_TEMPLATE_INFO (type_b);
+
+ pp_printf (pp, "%s<",
+ IDENTIFIER_POINTER (DECL_NAME (TI_TEMPLATE (tinfo_a))));
+
+ tree args_a = TI_ARGS (tinfo_a);
+ tree args_b = TI_ARGS (tinfo_b);
+ gcc_assert (TREE_CODE (args_a) == TREE_VEC);
+ gcc_assert (TREE_CODE (args_b) == TREE_VEC);
+ int flags = 0;
+ int len_a = get_non_default_template_args_count (args_a, flags);
+ args_a = INNERMOST_TEMPLATE_ARGS (args_a);
+ int len_b = get_non_default_template_args_count (args_b, flags);
+ args_b = INNERMOST_TEMPLATE_ARGS (args_b);
+ /* Determine the maximum range of args for which non-default template args
+ were used; beyond this, only default args (if any) were used, and so
+ they will be equal from this point onwards.
+ One of the two peers might have used default arguments within this
+ range, but the other will be using non-default arguments, and so
+ it's more readable to print both within this range, to highlight
+ the differences. */
+ int len_max = MAX (len_a, len_b);
+ gcc_assert (TREE_CODE (args_a) == TREE_VEC);
+ gcc_assert (TREE_CODE (args_b) == TREE_VEC);
+ for (int idx = 0; idx < len_max; idx++)
+ {
+ if (idx)
+ pp_character (pp, ',');
+
+ tree arg_a = TREE_VEC_ELT (args_a, idx);
+ tree arg_b = TREE_VEC_ELT (args_b, idx);
+ if (arg_a == arg_b)
+ {
+ if (indent)
+ newline_and_indent (pp, indent + 2);
+ /* Can do elision here, printing "[...]". */
+ if (flag_elide_type)
+ pp_string (pp, G_("[...]"));
+ else
+ pp_string (pp, arg_to_string (arg_a, verbose));
+ }
+ else
+ {
+ int new_indent = indent ? indent + 2 : 0;
+ if (comparable_template_types_p (arg_a, arg_b))
+ print_template_differences (pp, arg_a, arg_b, verbose, new_indent);
+ else
+ if (indent)
+ {
+ newline_and_indent (pp, indent + 2);
+ pp_character (pp, '[');
+ print_nonequal_arg (pp, arg_a, verbose);
+ pp_string (pp, " != ");
+ print_nonequal_arg (pp, arg_b, verbose);
+ pp_character (pp, ']');
+ }
+ else
+ print_nonequal_arg (pp, arg_a, verbose);
+ }
+ }
+ pp_printf (pp, ">");
+}
+
+/* As type_to_string, but for a template, potentially colorizing/eliding
+ in comparison with PEER.
+ For example, if TYPE is map<int,double> and PEER is map<int,int>,
+ then the resulting string would be:
+ map<[...],double>
+ with type elision, and:
+ map<int,double>
+ without type elision.
+
+ In both cases the parts of TYPE that differ from PEER will be colorized
+ if SHOW_COLOR is true. In the above example, this would be "double".
+
+ Template arguments in which both types are using the default arguments
+ are not printed; if at least one of the two types is using a non-default
+ argument, then both arguments are printed.
+
+ The resulting string is in a GC-allocated buffer. */
+
+static const char *
+type_to_string_with_compare (tree type, tree peer, bool verbose,
+ bool show_color)
+{
+ pretty_printer inner_pp;
+ pretty_printer *pp = &inner_pp;
+ pp_show_color (pp) = show_color;
+
+ print_template_differences (pp, type, peer, verbose, 0);
+ return pp_ggc_formatted_text (pp);
+}
+
+/* Recursively print a tree-like comparison of TYPE_A and TYPE_B to PP,
+ indented by INDENT spaces.
+
+ For example given types:
+
+ vector<map<int,double>>
+
+ and
+
+ vector<map<double,float>>
+
+ the output with type elision would be:
+
+ vector<
+ map<
+ [...],
+ [double != float]>>
+
+ and without type-elision would be:
+
+ vector<
+ map<
+ int,
+ [double != float]>>
+
+ TYPE_A and TYPE_B must both be comparable template types
+ (as per comparable_template_types_p).
+
+ Template arguments in which both types are using the default arguments
+ are not printed; if at least one of the two types is using a non-default
+ argument, then both arguments are printed. */
+
+static void
+print_template_tree_comparison (pretty_printer *pp, tree type_a, tree type_b,
+ bool verbose, int indent)
+{
+ print_template_differences (pp, type_a, type_b, verbose, indent);
+}
+
+/* Subroutine for use in a format_postprocessor::handle
+ implementation. Adds a chunk to the end of
+ formatted output, so that it will be printed
+ by pp_output_formatted_text. */
+
+static void
+append_formatted_chunk (pretty_printer *pp, const char *content)
+{
+ output_buffer *buffer = pp_buffer (pp);
+ struct chunk_info *chunk_array = buffer->cur_chunk_array;
+ const char **args = chunk_array->args;
+
+ unsigned int chunk_idx;
+ for (chunk_idx = 0; args[chunk_idx]; chunk_idx++)
+ ;
+ args[chunk_idx++] = content;
+ args[chunk_idx] = NULL;
+}
+
+/* Create a copy of CONTENT, with quotes added, and,
+ potentially, with colorization.
+ No escaped is performed on CONTENT.
+ The result is in a GC-allocated buffer. */
+
+static const char *
+add_quotes (const char *content, bool show_color)
+{
+ pretty_printer tmp_pp;
+ pp_show_color (&tmp_pp) = show_color;
+
+ /* We have to use "%<%s%>" rather than "%qs" here in order to avoid
+ quoting colorization bytes within the results. */
+ pp_printf (&tmp_pp, "%<%s%>", content);
+
+ return pp_ggc_formatted_text (&tmp_pp);
+}
+
+/* If we had %H and %I, and hence deferred printing them,
+ print them now, storing the result into the chunk_info
+ for pp_format. Quote them if 'q' was provided.
+ Also print the difference in tree form, adding it as
+ an additional chunk. */
+
+void
+cxx_format_postprocessor::handle (pretty_printer *pp)
+{
+ /* If we have one of %H and %I, the other should have
+ been present. */
+ if (m_type_a.m_tree || m_type_b.m_tree)
+ {
+ /* Avoid reentrancy issues by working with a copy of
+ m_type_a and m_type_b, resetting them now. */
+ deferred_printed_type type_a = m_type_a;
+ deferred_printed_type type_b = m_type_b;
+ m_type_a = deferred_printed_type ();
+ m_type_b = deferred_printed_type ();
+
+ gcc_assert (type_a.m_buffer_ptr);
+ gcc_assert (type_b.m_buffer_ptr);
+
+ bool show_color = pp_show_color (pp);
+
+ const char *type_a_text;
+ const char *type_b_text;
+
+ if (comparable_template_types_p (type_a.m_tree, type_b.m_tree))
+ {
+ type_a_text
+ = type_to_string_with_compare (type_a.m_tree, type_b.m_tree,
+ type_a.m_verbose, show_color);
+ type_b_text
+ = type_to_string_with_compare (type_b.m_tree, type_a.m_tree,
+ type_b.m_verbose, show_color);
+
+ if (flag_diagnostics_show_template_tree)
+ {
+ pretty_printer inner_pp;
+ pp_show_color (&inner_pp) = pp_show_color (pp);
+ print_template_tree_comparison
+ (&inner_pp, type_a.m_tree, type_b.m_tree, type_a.m_verbose, 2);
+ append_formatted_chunk (pp, pp_ggc_formatted_text (&inner_pp));
+ }
+ }
+ else
+ {
+ /* If the types were not comparable, they are printed normally,
+ and no difference tree is printed. */
+ type_a_text = type_to_string (type_a.m_tree, type_a.m_verbose);
+ type_b_text = type_to_string (type_b.m_tree, type_b.m_verbose);
+ }
+
+ if (type_a.m_quote)
+ type_a_text = add_quotes (type_a_text, show_color);
+ *type_a.m_buffer_ptr = type_a_text;
+
+ if (type_b.m_quote)
+ type_b_text = add_quotes (type_b_text, show_color);
+ *type_b.m_buffer_ptr = type_b_text;
+ }
+}
+
+/* Subroutine for handling %H and %I, to support i18n of messages like:
+
+ error_at (loc, "could not convert %qE from %qH to %qI",
+ expr, type_a, type_b);
+
+ so that we can print things like:
+
+ could not convert 'foo' from 'map<int,double>' to 'map<int,int>'
+
+ and, with type-elision:
+
+ could not convert 'foo' from 'map<[...],double>' to 'map<[...],int>'
+
+ (with color-coding of the differences between the types).
+
+ The %H and %I format codes are peers: both must be present,
+ and they affect each other. Hence to handle them, we must
+ delay printing until we have both, deferring the printing to
+ pretty_printer's m_format_postprocessor hook.
+
+ This is called in phase 2 of pp_format, when it is accumulating
+ a series of formatted chunks. We stash the location of the chunk
+ we're meant to have written to, so that we can write to it in the
+ m_format_postprocessor hook.
+
+ We also need to stash whether a 'q' prefix was provided (the QUOTE
+ param) so that we can add the quotes when writing out the delayed
+ chunk. */
+
+static void
+defer_phase_2_of_type_diff (deferred_printed_type *deferred,
+ tree type, const char **buffer_ptr,
+ bool verbose, bool quote)
+{
+ gcc_assert (deferred->m_tree == NULL_TREE);
+ gcc_assert (deferred->m_buffer_ptr == NULL);
+ *deferred = deferred_printed_type (type, buffer_ptr, verbose, quote);
+}
+
+
/* Called from output_format -- during diagnostic message processing --
to handle C++ specific format specifier with the following meanings:
%A function argument-list.
@@ -3577,11 +4003,18 @@ maybe_print_constexpr_context (diagnostic_context *context)
%S substitution (template + args)
%T type.
%V cv-qualifier.
- %X exception-specification. */
+ %X exception-specification.
+ %H type difference (from)
+ %I type difference (to). */
static bool
cp_printer (pretty_printer *pp, text_info *text, const char *spec,
- int precision, bool wide, bool set_locus, bool verbose)
+ int precision, bool wide, bool set_locus, bool verbose,
+ bool quoted, const char **buffer_ptr)
{
+ gcc_assert (pp->m_format_postprocessor);
+ cxx_format_postprocessor *postprocessor
+ = static_cast <cxx_format_postprocessor *> (pp->m_format_postprocessor);
+
const char *result;
tree t = NULL;
#define next_tree (t = va_arg (*text->args_ptr, tree))
@@ -3627,6 +4060,20 @@ cp_printer (pretty_printer *pp, text_info *text, const char *spec,
percent_K_format (text);
return true;
+ case 'H':
+ {
+ defer_phase_2_of_type_diff (&postprocessor->m_type_a, next_tree,
+ buffer_ptr, verbose, quoted);
+ return true;
+ }
+
+ case 'I':
+ {
+ defer_phase_2_of_type_diff (&postprocessor->m_type_b, next_tree,
+ buffer_ptr, verbose, quoted);
+ return true;
+ }
+
default:
return false;
}
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 6bf57bb..c657b3b 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -5040,7 +5040,7 @@ cp_build_binary_op (location_t location,
result_type = cp_common_type (type0, type1);
if (complain & tf_warning)
do_warn_double_promotion (result_type, type0, type1,
- "implicit conversion from %qT to %qT "
+ "implicit conversion from %qH to %qI "
"to match other operand of binary "
"expression",
location);
@@ -7076,7 +7076,7 @@ convert_member_func_to_ptr (tree type, tree expr, tsubst_flags_t complain)
if (pedantic || warn_pmf2ptr)
pedwarn (input_location, pedantic ? OPT_Wpedantic : OPT_Wpmf_conversions,
- "converting from %qT to %qT", intype, type);
+ "converting from %qH to %qI", intype, type);
if (TREE_CODE (intype) == METHOD_TYPE)
expr = build_addr_func (expr, complain);
@@ -7202,7 +7202,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
{
if (complain & tf_error)
- permerror (input_location, "cast from %qT to %qT loses precision",
+ permerror (input_location, "cast from %qH to %qI loses precision",
intype, type);
else
return error_mark_node;
@@ -7242,7 +7242,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
&& COMPLETE_TYPE_P (TREE_TYPE (type))
&& COMPLETE_TYPE_P (TREE_TYPE (intype))
&& TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (intype)))
- warning (OPT_Wcast_align, "cast from %qT to %qT "
+ warning (OPT_Wcast_align, "cast from %qH to %qI "
"increases required alignment of target type", intype, type);
/* We need to strip nops here, because the front end likes to
@@ -8569,33 +8569,33 @@ convert_for_assignment (tree type, tree rhs,
return r;
}
else if (fndecl)
- error ("cannot convert %qT to %qT for argument %qP to %qD",
+ error ("cannot convert %qH to %qI for argument %qP to %qD",
rhstype, type, parmnum, fndecl);
else
switch (errtype)
{
case ICR_DEFAULT_ARGUMENT:
- error ("cannot convert %qT to %qT in default argument",
+ error ("cannot convert %qH to %qI in default argument",
rhstype, type);
break;
case ICR_ARGPASS:
- error ("cannot convert %qT to %qT in argument passing",
+ error ("cannot convert %qH to %qI in argument passing",
rhstype, type);
break;
case ICR_CONVERTING:
- error ("cannot convert %qT to %qT",
+ error ("cannot convert %qH to %qI",
rhstype, type);
break;
case ICR_INIT:
- error ("cannot convert %qT to %qT in initialization",
+ error ("cannot convert %qH to %qI in initialization",
rhstype, type);
break;
case ICR_RETURN:
- error ("cannot convert %qT to %qT in return",
+ error ("cannot convert %qH to %qI in return",
rhstype, type);
break;
case ICR_ASSIGN:
- error ("cannot convert %qT to %qT in assignment",
+ error ("cannot convert %qH to %qI in assignment",
rhstype, type);
break;
default:
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index ff445ca..4623d6d 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -955,7 +955,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
{
if (complain & tf_warning)
warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
- "from %qT to %qT inside { } is ill-formed in C++11",
+ "from %qH to %qI inside { } is ill-formed in C++11",
init, ftype, type);
ok = true;
}
@@ -966,7 +966,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
if ((!almost_ok || pedantic)
&& pedwarn (loc, OPT_Wnarrowing,
"narrowing conversion of %qE "
- "from %qT to %qT inside { }",
+ "from %qH to %qI inside { }",
init, ftype, type)
&& almost_ok)
inform (loc, " the expression has a constant value but is not "
@@ -979,7 +979,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
int savederrorcount = errorcount;
global_dc->pedantic_errors = 1;
pedwarn (loc, OPT_Wnarrowing,
- "narrowing conversion of %qE from %qT to %qT "
+ "narrowing conversion of %qE from %qH to %qI "
"inside { }", init, ftype, type);
if (errorcount == savederrorcount)
ok = true;