diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 42 | ||||
-rw-r--r-- | gcc/cp/call.c | 40 | ||||
-rw-r--r-- | gcc/cp/cvt.c | 18 | ||||
-rw-r--r-- | gcc/cp/error.c | 453 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 22 | ||||
-rw-r--r-- | gcc/cp/typeck2.c | 6 |
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; |