[committed] diagnostics: add labeling of source ranges
Eric Gallager
egall@gwmail.gwu.edu
Wed Aug 15 23:50:00 GMT 2018
On 8/15/18, David Malcolm <dmalcolm@redhat.com> wrote:
> This patch adds the ability to label source ranges within a rich_location,
> to be printed by diagnostic_show_locus.
>
> For example:
>
> pr69554-1.c:11:18: error: invalid operands to binary + (have 'const char *'
> and 'const char *')
> 11 | return (p + 1) + (q + 1);
> | ~~~~~~~ ^ ~~~~~~~
> | | |
> | | const char *
> | const char *
>
> The patch implements labels for various type mismatch errors in the C and
> C++ frontends, and in -Wformat. I implemented it wherever accurate
> location
> information was guaranteed (there are other places that could benefit, but
> we need better location information in those places).
>
> The labels can be disabled via -fno-diagnostics-show-labels.
>
> Similarly:
>
> param-type-mismatch.C: In function 'int test_1(int, int, float)':
> param-type-mismatch.C:11:27: error: invalid conversion from 'int' to 'const
> char*' [-fpermissive]
> 11 | return callee_1 (first, second, third);
> | ^~~~~~
> | |
> | int
To me this seems more like it's saying "second" SHOULD be of type int,
rather than "second" IS of type int.
> param-type-mismatch.C:7:43: note: initializing argument 2 of 'int
> callee_1(int, const char*, float)'
> 7 | extern int callee_1 (int one, const char *two, float three);
> | ~~~~~~~~~~~~^~~
>
...but I guess that confusion would get quickly cleared up when
looking at the note that goes with it.
> where the first "error" describing the bad argument gets a label
> describing the type inline (since it's non-obvious from "second").
> The "note" describing the type of the param of the callee *doesn't*
> get a label, since that information is explicit there in the
> source ("const char *two").
>
> The idea is that in any diagnostic where two aspects of the source aren't
> in sync it ought to be easier for the user if we directly show them the
> mismatching aspects inline (e.g. types).
>
> As well as type mismatch errors, perhaps labels could also be used for
> buffer overflow warnings, for describing the capacity of the destination
> buffer vs the size of what's being written:
>
> sprintf (buf, "filename: %s\n", file);
> ^~~ ~~~~~~~~~~~^~~
> | |
> capacity: 32 10 + strlen(file) + 2
>
> or somesuch. Another idea might be for macro expansion warnings:
>
> warning: repeated side effects in macro expansion...
> x = MIN (p++, q++);
> ~~~~^~~~~~~~~~
> note: ...expanded here as
> #define MIN(X,Y) (X<Y?X:Y)
> ^~~ ~ ~ ~ ~ ~ ~
> | | | | | |
> | | | | | q++
> | | | | p++
> | | | q++
> | q++ p++
> p++
>
This would be a good thing to warn about separately from the addition
of labels to things; I just checked (with gcc 8) and code like that
currently gets no warnings regardless of the discussion of labels.
> The patch removes some logic from multiline.exp which special-cased
> lines ending with a '|' character (thus complicating testing of this
> patch). I believe that this was a vestige from experiments I did to
> support strippng dg directives from the output; it was present in the
> earliest version of multiline.exp I posted:
> "[RFC, stage1] Richer source location information for gcc 6 (location
> ranges etc)"
> https://gcc.gnu.org/ml/gcc-patches/2015-03/msg00837.html
> and I believe was neved used.
>
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
>
> I manually verified that "make selftest-valgrind" and
> "make selftest-c++-valgrind" are clean.
>
> Committed to trunk as r263564.
>
> gcc/c-family/ChangeLog:
> * c-format.c: Include "selftest-diagnostic.h" and
> "gcc-rich-location.h".
> (format_warning_at_char): Pass NULL for new label params of
> format_warning_va.
> (class indirection_suffix): New class.
> (class range_label_for_format_type_mismatch): New class.
> (format_type_warning): Move logic for generating "*" suffix to
> class indirection_suffix. Create "fmt_label" and "param_label"
> to show their types, and pass them to the
> format_warning_at_substring calls.
> (selftest::test_type_mismatch_range_labels): New test.
> (selftest::c_format_c_tests): Call it.
>
> gcc/c/ChangeLog:
> * c-objc-common.c: Include "gcc-rich-location.h".
> (c_tree_printer): Move implemenation of '%T' to...
> (print_type): ...this new function.
> (range_label_for_type_mismatch::get_text): New function.
> * c-typeck.c (convert_for_assignment): Add type labels to the rhs
> range for the various ic_argpass cases.
> (class maybe_range_label_for_tree_type_mismatch): New class.
> (build_binary_op): Use it when calling binary_op_error.
>
> gcc/cp/ChangeLog:
> * call.c: Include "gcc-rich-location.h".
> (convert_like_real): Add range label for "invalid conversion"
> diagnostic.
> (perform_implicit_conversion_flags): Add type label to the
> "could not convert" error.
> * error.c: Include "gcc-rich-location.h".
> (range_label_for_type_mismatch::get_text): New function.
> * typeck.c (convert_for_assignment): Add type label to
> the "cannot convert" error if a location is available.
>
> gcc/ChangeLog:
> * common.opt (fdiagnostics-show-labels): New option.
> * diagnostic-show-locus.c (class layout_range): Add field
> "m_label".
> (class layout): Add field "m_show_labels_p".
> (layout_range::layout_range): Add param "label" and use it to
> initialize m_label.
> (make_range): Pass in NULL for new "label" param of layout_range's
> ctor.
> (layout::layout): Initialize m_show_labels_p.
> (layout::maybe_add_location_range): Pass in loc_range->m_label
> when constructing layout_range instances.
> (struct line_label): New struct.
> (layout::print_any_labels): New member function.
> (layout::print_line): Call it if label-printing is enabled.
> (selftest::test_one_liner_labels): New test.
> (selftest::test_diagnostic_show_locus_one_liner): Call it.
> * diagnostic.c (diagnostic_initialize): Initialize
> context->show_labels_p.
> * diagnostic.h (struct diagnostic_context): Add field
> "show_labels_p".
> * doc/invoke.texi (Diagnostic Message Formatting Options): Add
> -fno-diagnostics-show-labels.
> * dwarf2out.c (gen_producer_string): Add
> OPT_fdiagnostics_show_labels to the ignored options.
> * gcc-rich-location.c (gcc_rich_location::add_expr): Add "label"
> param.
> (gcc_rich_location::maybe_add_expr): Likewise.
> * gcc-rich-location.h (gcc_rich_location::gcc_rich_location): Add
> label" param, defaulting to NULL.
> (gcc_rich_location::add_expr): Add "label" param.
> (gcc_rich_location::maybe_add_expr): Likewise.
> (class text_range_label): New class.
> (class range_label_for_type_mismatch): New class.
> * gimple-ssa-sprintf.c (fmtwarn): Pass NULL for new label params
> of format_warning_va.
> (fmtwarn_n): Likewise for new params of format_warning_n_va.
> * lto-wrapper.c (merge_and_complain): Add
> OPT_fdiagnostics_show_labels to the "pick one setting" options.
> (append_compiler_options): Likewise to the dropped options.
> (append_diag_options): Likewise to the passed-on options.
> * opts.c (common_handle_option): Handle the new option.
> * selftest-diagnostic.c
> (test_diagnostic_context::test_diagnostic_context): Enable
> show_labels_p.
> * substring-locations.c: Include "gcc-rich-location.h".
> (format_warning_n_va): Add "fmt_label" and "param_label" params
> and use them as appropriate.
> (format_warning_va): Add "fmt_label" and "param_label" params,
> passing them on to format_warning_n_va.
> (format_warning_at_substring): Likewise.
> (format_warning_at_substring_n): Likewise.
> * substring-locations.h (format_warning_va): Add "fmt_label" and
> "param_label" params.
> (format_warning_n_va): Likewise.
> (format_warning_at_substring): Likewise.
> (format_warning_at_substring_n): Likewise.
> * toplev.c (general_init): Initialize global_dc->show_labels_p.
>
> gcc/testsuite/ChangeLog:
> * g++.dg/diagnostic/aka3.C: New test.
> * g++.dg/diagnostic/param-type-mismatch-2.C: Update expected
> output to show range labels.
> * g++.dg/diagnostic/param-type-mismatch.C: Likewise.
> * g++.dg/plugin/plugin.exp (plugin_test_list): Add...
> * g++.dg/plugin/show-template-tree-color-labels.C: New test.
> * gcc.dg/bad-binary-ops.c: Update expected output to show range
> labels. Add an "aka" example.
> * gcc.dg/cpp/pr66415-1.c: Update expected output to show range
> labels.
> * gcc.dg/format/diagnostic-ranges.c: Likewise.
> * gcc.dg/format/pr72858.c: Likewise.
> * gcc.dg/format/pr78498.c: Likewise.
> * gcc.dg/param-type-mismatch.c: Add "-Wpointer-sign" to options.
> Update expected output to show range labels. Add examples of
> -Wincompatible-pointer-types and -Wpointer-sign for parameters.
> * gcc.dg/plugin/diagnostic-test-show-locus-bw-line-numbers.c:
> Update expected output to show range labels.
> * gcc.dg/plugin/diagnostic-test-show-locus-bw.c: Likewise.
> (test_very_wide_line): Adjust so that label is at left-clipping
> boundary.
> (test_very_wide_line_2): New test.
> * gcc.dg/plugin/diagnostic-test-show-locus-color-line-numbers.c:
> Update expected output to show range labels.
> * gcc.dg/plugin/diagnostic-test-show-locus-color.c: Likewise.
> * gcc.dg/plugin/diagnostic-test-show-locus-no-labels.c: New test.
> * gcc.dg/plugin/diagnostic_plugin_show_trees.c (show_tree): Update
> for new param to gcc_rich_location::add_expr.
> * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c (add_range):
> Add "label" param.
> (test_show_locus): Add examples of labels to various tests. Tweak
> the "very wide_line" test case and duplicate it, to cover the
> boundary values for clipping of labels against the left-margin.
> * gcc.dg/plugin/plugin.exp (plugin_test_list): Add
> diagnostic-test-show-locus-no-labels.c.
> * gcc.dg/pr69554-1.c: Update expected output to show range labels.
> Update line numbers of dg-locus directives.
> * gcc.dg/pr69627.c: Update expected output to show range labels.
> * lib/multiline.exp (proc _build_multiline_regex): Remove
> special-case handling of lines with trailing '|'.
>
> libcpp/ChangeLog:
> * include/line-map.h (struct location_range): Add "m_label" field.
> (class rich_location): Add description of labels to leading
> comment.
> (rich_location::rich_location): Add "label" param, defaulting to
> NULL.
> (rich_location::add_range): Likewise.
> (struct label_text): New struct.
> (class range_label): New abstract base class.
> * line-map.c (rich_location::rich_location): Add "label" param;
> use it.
> (rich_location::add_range): Likewise.
> ---
> gcc/c-family/c-format.c | 179 +++++++++--
> gcc/c/c-objc-common.c | 124 +++++---
> gcc/c/c-typeck.c | 108 +++++--
> gcc/common.opt | 4 +
> gcc/cp/call.c | 18 +-
> gcc/cp/error.c | 28 ++
> gcc/cp/typeck.c | 11 +-
> gcc/diagnostic-show-locus.c | 346
> ++++++++++++++++++++-
> gcc/diagnostic.c | 1 +
> gcc/diagnostic.h | 3 +
> gcc/doc/invoke.texi | 19 +-
> gcc/dwarf2out.c | 1 +
> gcc/gcc-rich-location.c | 14 +-
> gcc/gcc-rich-location.h | 71 ++++-
> gcc/gimple-ssa-sprintf.c | 7 +-
> gcc/lto-wrapper.c | 3 +
> gcc/opts.c | 4 +
> gcc/selftest-diagnostic.c | 1 +
> gcc/substring-locations.c | 53 +++-
> gcc/substring-locations.h | 16 +-
> gcc/testsuite/g++.dg/diagnostic/aka3.C | 25 ++
> .../g++.dg/diagnostic/param-type-mismatch-2.C | 6 +
> .../g++.dg/diagnostic/param-type-mismatch.C | 20 ++
> gcc/testsuite/g++.dg/plugin/plugin.exp | 1 +
> .../plugin/show-template-tree-color-labels.C | 38 +++
> gcc/testsuite/gcc.dg/bad-binary-ops.c | 26 ++
> gcc/testsuite/gcc.dg/cpp/pr66415-1.c | 2 +
> gcc/testsuite/gcc.dg/format/diagnostic-ranges.c | 55 ++++
> gcc/testsuite/gcc.dg/format/pr72858.c | 108 +++++++
> gcc/testsuite/gcc.dg/format/pr78498.c | 2 +
> gcc/testsuite/gcc.dg/param-type-mismatch.c | 56 +++-
> .../diagnostic-test-show-locus-bw-line-numbers.c | 14 +-
> .../gcc.dg/plugin/diagnostic-test-show-locus-bw.c | 72 ++++-
> ...diagnostic-test-show-locus-color-line-numbers.c | 2 +
> .../plugin/diagnostic-test-show-locus-color.c | 15 +-
> .../plugin/diagnostic-test-show-locus-no-labels.c | 27 ++
> .../gcc.dg/plugin/diagnostic_plugin_show_trees.c | 2 +-
> .../plugin/diagnostic_plugin_test_show_locus.c | 51 ++-
> gcc/testsuite/gcc.dg/plugin/plugin.exp | 1 +
> gcc/testsuite/gcc.dg/pr69554-1.c | 29 +-
> gcc/testsuite/gcc.dg/pr69627.c | 4 +
> gcc/testsuite/lib/multiline.exp | 20 --
> gcc/toplev.c | 2 +
> libcpp/include/line-map.h | 78 ++++-
> libcpp/line-map.c | 9 +-
> 45 files changed, 1482 insertions(+), 194 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/diagnostic/aka3.C
> create mode 100644
> gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C
> create mode 100644
> gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-no-labels.c
>
> diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
> index dc0e756..5a04f05 100644
> --- a/gcc/c-family/c-format.c
> +++ b/gcc/c-family/c-format.c
> @@ -32,8 +32,10 @@ along with GCC; see the file COPYING3. If not see
> #include "diagnostic.h"
> #include "substring-locations.h"
> #include "selftest.h"
> +#include "selftest-diagnostic.h"
> #include "builtins.h"
> #include "attribs.h"
> +#include "gcc-rich-location.h"
>
> /* Handle attributes associated with format checking. */
>
> @@ -97,8 +99,8 @@ format_warning_at_char (location_t fmt_string_loc, tree
> format_string_cst,
>
> substring_loc fmt_loc (fmt_string_loc, string_type, char_idx, char_idx,
> char_idx);
> - bool warned = format_warning_va (fmt_loc, UNKNOWN_LOCATION, NULL, opt,
> - gmsgid, &ap);
> + bool warned = format_warning_va (fmt_loc, NULL, UNKNOWN_LOCATION, NULL,
> + NULL, opt, gmsgid, &ap);
> va_end (ap);
>
> return warned;
> @@ -3510,6 +3512,82 @@ get_corrected_substring (const substring_loc
> &fmt_loc,
> return result;
> }
>
> +/* Helper class for adding zero or more trailing '*' to types.
> +
> + The format type and name exclude any '*' for pointers, so those
> + must be formatted manually. For all the types we currently have,
> + this is adequate, but formats taking pointers to functions or
> + arrays would require the full type to be built up in order to
> + print it with %T. */
> +
> +class indirection_suffix
> +{
> + public:
> + indirection_suffix (int pointer_count) : m_pointer_count (pointer_count)
> {}
> +
> + /* Determine the size of the buffer (including NUL-terminator). */
> +
> + size_t get_buffer_size () const
> + {
> + return m_pointer_count + 2;
> + }
> +
> + /* Write the '*' to DST and add a NUL-terminator. */
> +
> + void fill_buffer (char *dst) const
> + {
> + if (m_pointer_count == 0)
> + dst[0] = 0;
> + else if (c_dialect_cxx ())
> + {
> + memset (dst, '*', m_pointer_count);
> + dst[m_pointer_count] = 0;
> + }
> + else
> + {
> + dst[0] = ' ';
> + memset (dst + 1, '*', m_pointer_count);
> + dst[m_pointer_count + 1] = 0;
> + }
> + }
> +
> + private:
> + int m_pointer_count;
> +};
> +
> +/* Subclass of range_label for labelling the range in the format string
> + with the type in question, adding trailing '*' for pointer_count. */
> +
> +class range_label_for_format_type_mismatch
> + : public range_label_for_type_mismatch
> +{
> + public:
> + range_label_for_format_type_mismatch (tree labelled_type, tree
> other_type,
> + int pointer_count)
> + : range_label_for_type_mismatch (labelled_type, other_type),
> + m_pointer_count (pointer_count)
> + {
> + }
> +
> + label_text get_text () const FINAL OVERRIDE
> + {
> + label_text text = range_label_for_type_mismatch::get_text ();
> + if (text.m_buffer == NULL)
> + return text;
> +
> + indirection_suffix suffix (m_pointer_count);
> + char *p = (char *) alloca (suffix.get_buffer_size ());
> + suffix.fill_buffer (p);
> +
> + char *result = concat (text.m_buffer, p, NULL);
> + text.maybe_free ();
> + return label_text (result, true);
> + }
> +
> + private:
> + int m_pointer_count;
> +};
> +
> /* Give a warning about a format argument of different type from that
> expected.
> The range of the diagnostic is taken from WHOLE_FMT_LOC; the caret
> location
> is based on the location of the char at TYPE->offset_loc.
> @@ -3558,7 +3636,6 @@ format_type_warning (const substring_loc
> &whole_fmt_loc,
> int pointer_count = type->pointer_count;
> int arg_num = type->arg_num;
>
> - char *p;
> /* If ARG_TYPE is a typedef with a misleading name (for example,
> size_t but not the standard size_t expected by printf %zu), avoid
> printing the typedef name. */
> @@ -3570,25 +3647,10 @@ format_type_warning (const substring_loc
> &whole_fmt_loc,
> && !strcmp (wanted_type_name,
> lang_hooks.decl_printable_name (TYPE_NAME (arg_type), 2)))
> arg_type = TYPE_MAIN_VARIANT (arg_type);
> - /* The format type and name exclude any '*' for pointers, so those
> - must be formatted manually. For all the types we currently have,
> - this is adequate, but formats taking pointers to functions or
> - arrays would require the full type to be built up in order to
> - print it with %T. */
> - p = (char *) alloca (pointer_count + 2);
> - if (pointer_count == 0)
> - p[0] = 0;
> - else if (c_dialect_cxx ())
> - {
> - memset (p, '*', pointer_count);
> - p[pointer_count] = 0;
> - }
> - else
> - {
> - p[0] = ' ';
> - memset (p + 1, '*', pointer_count);
> - p[pointer_count + 1] = 0;
> - }
> +
> + indirection_suffix suffix (pointer_count);
> + char *p = (char *) alloca (suffix.get_buffer_size ());
> + suffix.fill_buffer (p);
>
> /* WHOLE_FMT_LOC has the caret at the end of the range.
> Set the caret to be at the offset from TYPE. Subtract one
> @@ -3596,6 +3658,10 @@ format_type_warning (const substring_loc
> &whole_fmt_loc,
> substring_loc fmt_loc (whole_fmt_loc);
> fmt_loc.set_caret_index (type->offset_loc - 1);
>
> + range_label_for_format_type_mismatch fmt_label (wanted_type, arg_type,
> + pointer_count);
> + range_label_for_type_mismatch param_label (arg_type, wanted_type);
> +
> /* Get a string for use as a replacement fix-it hint for the range in
> fmt_loc, or NULL. */
> char *corrected_substring
> @@ -3606,7 +3672,7 @@ format_type_warning (const substring_loc
> &whole_fmt_loc,
> {
> if (arg_type)
> format_warning_at_substring
> - (fmt_loc, param_loc,
> + (fmt_loc, &fmt_label, param_loc, ¶m_label,
> corrected_substring, OPT_Wformat_,
> "%s %<%s%.*s%> expects argument of type %<%s%s%>, "
> "but argument %d has type %qT",
> @@ -3616,7 +3682,7 @@ format_type_warning (const substring_loc
> &whole_fmt_loc,
> wanted_type_name, p, arg_num, arg_type);
> else
> format_warning_at_substring
> - (fmt_loc, param_loc,
> + (fmt_loc, &fmt_label, param_loc, ¶m_label,
> corrected_substring, OPT_Wformat_,
> "%s %<%s%.*s%> expects a matching %<%s%s%> argument",
> gettext (kind_descriptions[kind]),
> @@ -3627,7 +3693,7 @@ format_type_warning (const substring_loc
> &whole_fmt_loc,
> {
> if (arg_type)
> format_warning_at_substring
> - (fmt_loc, param_loc,
> + (fmt_loc, &fmt_label, param_loc, ¶m_label,
> corrected_substring, OPT_Wformat_,
> "%s %<%s%.*s%> expects argument of type %<%T%s%>, "
> "but argument %d has type %qT",
> @@ -3637,7 +3703,7 @@ format_type_warning (const substring_loc
> &whole_fmt_loc,
> wanted_type, p, arg_num, arg_type);
> else
> format_warning_at_substring
> - (fmt_loc, param_loc,
> + (fmt_loc, &fmt_label, param_loc, ¶m_label,
> corrected_substring, OPT_Wformat_,
> "%s %<%s%.*s%> expects a matching %<%T%s%> argument",
> gettext (kind_descriptions[kind]),
> @@ -4217,6 +4283,66 @@ test_get_format_for_type_scanf ()
>
> #undef ASSERT_FORMAT_FOR_TYPE_STREQ
>
> +/* Exercise the type-printing label code, to give some coverage
> + under "make selftest-valgrind" (in particular, to ensure that
> + the label-printing machinery doesn't leak). */
> +
> +static void
> +test_type_mismatch_range_labels ()
> +{
> + /* Create a tempfile and write some text to it.
> + ....................0000000001 11111111 12 22222222
> + ....................1234567890 12345678 90 12345678. */
> + const char *content = " printf (\"msg: %i\\n\", msg);\n";
> + temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
> + line_table_test ltt;
> +
> + linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
> +
> + location_t c17 = linemap_position_for_column (line_table, 17);
> + ASSERT_EQ (LOCATION_COLUMN (c17), 17);
> + location_t c18 = linemap_position_for_column (line_table, 18);
> + location_t c24 = linemap_position_for_column (line_table, 24);
> + location_t c26 = linemap_position_for_column (line_table, 26);
> +
> + /* Don't attempt to run the tests if column data might be unavailable.
> */
> + if (c26 > LINE_MAP_MAX_LOCATION_WITH_COLS)
> + return;
> +
> + location_t fmt = make_location (c18, c17, c18);
> + ASSERT_EQ (LOCATION_COLUMN (fmt), 18);
> +
> + location_t param = make_location (c24, c24, c26);
> + ASSERT_EQ (LOCATION_COLUMN (param), 24);
> +
> + range_label_for_format_type_mismatch fmt_label (char_type_node,
> + integer_type_node, 1);
> + range_label_for_type_mismatch param_label (integer_type_node,
> + char_type_node);
> + gcc_rich_location richloc (fmt, &fmt_label);
> + richloc.add_range (param, false, ¶m_label);
> +
> + test_diagnostic_context dc;
> + diagnostic_show_locus (&dc, &richloc, DK_ERROR);
> + if (c_dialect_cxx ())
> + /* "char*", without a space. */
> + ASSERT_STREQ ("\n"
> + " printf (\"msg: %i\\n\", msg);\n"
> + " ~^ ~~~\n"
> + " | |\n"
> + " char* int\n",
> + pp_formatted_text (dc.printer));
> + else
> + /* "char *", with a space. */
> + ASSERT_STREQ ("\n"
> + " printf (\"msg: %i\\n\", msg);\n"
> + " ~^ ~~~\n"
> + " | |\n"
> + " | int\n"
> + " char *\n",
> + pp_formatted_text (dc.printer));
> +}
> +
> /* Run all of the selftests within this file. */
>
> void
> @@ -4225,6 +4351,7 @@ c_format_c_tests ()
> test_get_modifier_for_format_len ();
> test_get_format_for_type_printf ();
> test_get_format_for_type_scanf ();
> + test_type_mismatch_range_labels ();
> }
>
> } // namespace selftest
> diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c
> index ddbd60c..238af19 100644
> --- a/gcc/c/c-objc-common.c
> +++ b/gcc/c/c-objc-common.c
> @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see
> #include "gimple-pretty-print.h"
> #include "langhooks.h"
> #include "c-objc-common.h"
> +#include "gcc-rich-location.h"
>
> static bool c_tree_printer (pretty_printer *, text_info *, const char *,
> int, bool, bool, bool, bool *, const char **);
> @@ -61,6 +62,60 @@ c_objc_common_init (void)
> return c_common_init ();
> }
>
> +/* Print T to CPP. */
> +
> +static void
> +print_type (c_pretty_printer *cpp, tree t, bool *quoted)
> +{
> + gcc_assert (TYPE_P (t));
> + struct obstack *ob = pp_buffer (cpp)->obstack;
> + char *p = (char *) obstack_base (ob);
> + /* Remember the end of the initial dump. */
> + int len = obstack_object_size (ob);
> +
> + tree name = TYPE_NAME (t);
> + if (name && TREE_CODE (name) == TYPE_DECL && DECL_NAME (name))
> + pp_identifier (cpp, lang_hooks.decl_printable_name (name, 2));
> + else
> + cpp->type_id (t);
> +
> + /* If we're printing a type that involves typedefs, also print the
> + stripped version. But sometimes the stripped version looks
> + exactly the same, so we don't want it after all. To avoid
> + printing it in that case, we play ugly obstack games. */
> + if (TYPE_CANONICAL (t) && t != TYPE_CANONICAL (t))
> + {
> + c_pretty_printer cpp2;
> + /* Print the stripped version into a temporary printer. */
> + cpp2.type_id (TYPE_CANONICAL (t));
> + struct obstack *ob2 = cpp2.buffer->obstack;
> + /* Get the stripped version from the temporary printer. */
> + const char *aka = (char *) obstack_base (ob2);
> + int aka_len = obstack_object_size (ob2);
> + int type1_len = obstack_object_size (ob) - len;
> +
> + /* If they are identical, bail out. */
> + if (aka_len == type1_len && memcmp (p + len, aka, aka_len) == 0)
> + return;
> +
> + /* They're not, print the stripped version now. */
> + if (*quoted)
> + pp_end_quote (cpp, pp_show_color (cpp));
> + pp_c_whitespace (cpp);
> + pp_left_brace (cpp);
> + pp_c_ws_string (cpp, _("aka"));
> + pp_c_whitespace (cpp);
> + if (*quoted)
> + pp_begin_quote (cpp, pp_show_color (cpp));
> + cpp->type_id (TYPE_CANONICAL (t));
> + if (*quoted)
> + pp_end_quote (cpp, pp_show_color (cpp));
> + pp_right_brace (cpp);
> + /* No further closing quotes are needed. */
> + *quoted = false;
> + }
> +}
> +
> /* Called during diagnostic message formatting process to print a
> source-level entity onto BUFFER. The meaning of the format specifiers
> is as follows:
> @@ -82,7 +137,6 @@ c_tree_printer (pretty_printer *pp, text_info *text,
> const char *spec,
> bool *quoted, const char **)
> {
> tree t = NULL_TREE;
> - tree name;
> // FIXME: the next cast should be a dynamic_cast, when it is permitted.
> c_pretty_printer *cpp = (c_pretty_printer *) pp;
> pp->padding = pp_none;
> @@ -133,56 +187,8 @@ c_tree_printer (pretty_printer *pp, text_info *text,
> const char *spec,
> break;
>
> case 'T':
> - {
> - gcc_assert (TYPE_P (t));
> - struct obstack *ob = pp_buffer (cpp)->obstack;
> - char *p = (char *) obstack_base (ob);
> - /* Remember the end of the initial dump. */
> - int len = obstack_object_size (ob);
> -
> - name = TYPE_NAME (t);
> - if (name && TREE_CODE (name) == TYPE_DECL && DECL_NAME (name))
> - pp_identifier (cpp, lang_hooks.decl_printable_name (name, 2));
> - else
> - cpp->type_id (t);
> -
> - /* If we're printing a type that involves typedefs, also print the
> - stripped version. But sometimes the stripped version looks
> - exactly the same, so we don't want it after all. To avoid
> - printing it in that case, we play ugly obstack games. */
> - if (TYPE_CANONICAL (t) && t != TYPE_CANONICAL (t))
> - {
> - c_pretty_printer cpp2;
> - /* Print the stripped version into a temporary printer. */
> - cpp2.type_id (TYPE_CANONICAL (t));
> - struct obstack *ob2 = cpp2.buffer->obstack;
> - /* Get the stripped version from the temporary printer. */
> - const char *aka = (char *) obstack_base (ob2);
> - int aka_len = obstack_object_size (ob2);
> - int type1_len = obstack_object_size (ob) - len;
> -
> - /* If they are identical, bail out. */
> - if (aka_len == type1_len && memcmp (p + len, aka, aka_len) == 0)
> - return true;
> -
> - /* They're not, print the stripped version now. */
> - if (*quoted)
> - pp_end_quote (pp, pp_show_color (pp));
> - pp_c_whitespace (cpp);
> - pp_left_brace (cpp);
> - pp_c_ws_string (cpp, _("aka"));
> - pp_c_whitespace (cpp);
> - if (*quoted)
> - pp_begin_quote (pp, pp_show_color (pp));
> - cpp->type_id (TYPE_CANONICAL (t));
> - if (*quoted)
> - pp_end_quote (pp, pp_show_color (pp));
> - pp_right_brace (cpp);
> - /* No further closing quotes are needed. */
> - *quoted = false;
> - }
> - return true;
> - }
> + print_type (cpp, t, quoted);
> + return true;
>
> case 'E':
> if (TREE_CODE (t) == IDENTIFIER_NODE)
> @@ -207,6 +213,22 @@ c_tree_printer (pretty_printer *pp, text_info *text,
> const char *spec,
> return true;
> }
>
> +/* C-specific implementation of range_label::get_text () vfunc for
> + range_label_for_type_mismatch. */
> +
> +label_text
> +range_label_for_type_mismatch::get_text () const
> +{
> + if (m_labelled_type == NULL_TREE)
> + return label_text (NULL, false);
> +
> + c_pretty_printer cpp;
> + bool quoted = false;
> + print_type (&cpp, m_labelled_type, "ed);
> + return label_text (xstrdup (pp_formatted_text (&cpp)), true);
> +}
> +
> +
> /* In C and ObjC, all decls have "C" linkage. */
> bool
> has_c_linkage (const_tree decl ATTRIBUTE_UNUSED)
> diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
> index 2e9338e..726ea83 100644
> --- a/gcc/c/c-typeck.c
> +++ b/gcc/c/c-typeck.c
> @@ -6924,13 +6924,15 @@ convert_for_assignment (location_t location,
> location_t expr_loc, tree type,
> switch (errtype)
> {
> case ic_argpass:
> - if (pedwarn (expr_loc, OPT_Wpointer_sign,
> - "pointer targets in passing argument %d of "
> - "%qE differ in signedness", parmnum, rname))
> - inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
> - ? DECL_SOURCE_LOCATION (fundecl) : expr_loc,
> - "expected %qT but argument is of type %qT",
> - type, rhstype);
> + {
> + range_label_for_type_mismatch rhs_label (rhstype, type);
> + gcc_rich_location richloc (expr_loc, &rhs_label);
> + if (pedwarn (&richloc, OPT_Wpointer_sign,
> + "pointer targets in passing argument %d of "
> + "%qE differ in signedness", parmnum, rname))
> + inform_for_arg (fundecl, expr_loc, parmnum, type,
> + rhstype);
> + }
> break;
> case ic_assign:
> pedwarn (location, OPT_Wpointer_sign,
> @@ -6981,10 +6983,14 @@ convert_for_assignment (location_t location,
> location_t expr_loc, tree type,
> switch (errtype)
> {
> case ic_argpass:
> - if (pedwarn (expr_loc, OPT_Wincompatible_pointer_types,
> - "passing argument %d of %qE from incompatible "
> - "pointer type", parmnum, rname))
> - inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
> + {
> + range_label_for_type_mismatch rhs_label (rhstype, type);
> + gcc_rich_location richloc (expr_loc, &rhs_label);
> + if (pedwarn (&richloc, OPT_Wincompatible_pointer_types,
> + "passing argument %d of %qE from incompatible "
> + "pointer type", parmnum, rname))
> + inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
> + }
> break;
> case ic_assign:
> pedwarn (location, OPT_Wincompatible_pointer_types,
> @@ -7024,10 +7030,14 @@ convert_for_assignment (location_t location,
> location_t expr_loc, tree type,
> switch (errtype)
> {
> case ic_argpass:
> - if (pedwarn (expr_loc, OPT_Wint_conversion,
> - "passing argument %d of %qE makes pointer from "
> - "integer without a cast", parmnum, rname))
> - inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
> + {
> + range_label_for_type_mismatch rhs_label (rhstype, type);
> + gcc_rich_location richloc (expr_loc, &rhs_label);
> + if (pedwarn (&richloc, OPT_Wint_conversion,
> + "passing argument %d of %qE makes pointer from "
> + "integer without a cast", parmnum, rname))
> + inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
> + }
> break;
> case ic_assign:
> pedwarn (location, OPT_Wint_conversion,
> @@ -7055,10 +7065,14 @@ convert_for_assignment (location_t location,
> location_t expr_loc, tree type,
> switch (errtype)
> {
> case ic_argpass:
> - if (pedwarn (expr_loc, OPT_Wint_conversion,
> - "passing argument %d of %qE makes integer from "
> - "pointer without a cast", parmnum, rname))
> - inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
> + {
> + range_label_for_type_mismatch rhs_label (rhstype, type);
> + gcc_rich_location richloc (expr_loc, &rhs_label);
> + if (pedwarn (&richloc, OPT_Wint_conversion,
> + "passing argument %d of %qE makes integer from "
> + "pointer without a cast", parmnum, rname))
> + inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
> + }
> break;
> case ic_assign:
> pedwarn (location, OPT_Wint_conversion,
> @@ -7094,9 +7108,13 @@ convert_for_assignment (location_t location,
> location_t expr_loc, tree type,
> switch (errtype)
> {
> case ic_argpass:
> - error_at (expr_loc, "incompatible type for argument %d of %qE",
> parmnum,
> - rname);
> - inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
> + {
> + range_label_for_type_mismatch rhs_label (rhstype, type);
> + gcc_rich_location richloc (expr_loc, &rhs_label);
> + error_at (&richloc, "incompatible type for argument %d of %qE", parmnum,
> + rname);
> + inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
> + }
> break;
> case ic_assign:
> error_at (location, "incompatible types when assigning to type %qT
> from "
> @@ -10992,6 +11010,38 @@ build_vec_cmp (tree_code code, tree type,
> return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
> }
>
> +/* Subclass of range_label for labelling the type of EXPR when reporting
> + a type mismatch between EXPR and OTHER_EXPR.
> + Either or both of EXPR and OTHER_EXPR could be NULL. */
> +
> +class maybe_range_label_for_tree_type_mismatch : public range_label
> +{
> + public:
> + maybe_range_label_for_tree_type_mismatch (tree expr, tree other_expr)
> + : m_expr (expr), m_other_expr (other_expr)
> + {
> + }
> +
> + label_text get_text () const FINAL OVERRIDE
> + {
> + if (m_expr == NULL_TREE
> + || !EXPR_P (m_expr))
> + return label_text (NULL, false);
> + tree expr_type = TREE_TYPE (m_expr);
> +
> + tree other_type = NULL_TREE;
> + if (m_other_expr && EXPR_P (m_other_expr))
> + other_type = TREE_TYPE (m_other_expr);
> +
> + range_label_for_type_mismatch inner (expr_type, other_type);
> + return inner.get_text ();
> + }
> +
> + private:
> + tree m_expr;
> + tree m_other_expr;
> +};
> +
> /* Build a binary-operation expression without default conversions.
> CODE is the kind of expression to build.
> LOCATION is the operator's location.
> @@ -11864,8 +11914,11 @@ build_binary_op (location_t location, enum
> tree_code code,
> || !vector_types_compatible_elements_p (type0, type1)))
> {
> gcc_rich_location richloc (location);
> - richloc.maybe_add_expr (orig_op0);
> - richloc.maybe_add_expr (orig_op1);
> + maybe_range_label_for_tree_type_mismatch
> + label_for_op0 (orig_op0, orig_op1),
> + label_for_op1 (orig_op1, orig_op0);
> + richloc.maybe_add_expr (orig_op0, &label_for_op0);
> + richloc.maybe_add_expr (orig_op1, &label_for_op1);
> binary_op_error (&richloc, code, type0, type1);
> return error_mark_node;
> }
> @@ -12106,8 +12159,11 @@ build_binary_op (location_t location, enum
> tree_code code,
> if (!result_type)
> {
> gcc_rich_location richloc (location);
> - richloc.maybe_add_expr (orig_op0);
> - richloc.maybe_add_expr (orig_op1);
> + maybe_range_label_for_tree_type_mismatch
> + label_for_op0 (orig_op0, orig_op1),
> + label_for_op1 (orig_op1, orig_op0);
> + richloc.maybe_add_expr (orig_op0, &label_for_op0);
> + richloc.maybe_add_expr (orig_op1, &label_for_op1);
> binary_op_error (&richloc, code, TREE_TYPE (op0), TREE_TYPE (op1));
> return error_mark_node;
> }
> diff --git a/gcc/common.opt b/gcc/common.opt
> index b2f2215..507291f 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1233,6 +1233,10 @@ fdiagnostics-show-caret
> Common Var(flag_diagnostics_show_caret) Init(1)
> Show the source line with a caret indicating the column.
>
> +fdiagnostics-show-labels
> +Common Var(flag_diagnostics_show_labels) Init(1)
> +Show labels annotating ranges of source code when showing source
> +
> fdiagnostics-show-line-numbers
> Common Var(flag_diagnostics_show_line_numbers) Init(1)
> Show line numbers in the left margin when showing source
> diff --git a/gcc/cp/call.c b/gcc/cp/call.c
> index 62654a9..16bb6bf 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see
> #include "internal-fn.h"
> #include "stringpool.h"
> #include "attribs.h"
> +#include "gcc-rich-location.h"
>
> /* The various kinds of conversion. */
>
> @@ -6748,8 +6749,13 @@ convert_like_real (conversion *convs, tree expr, tree
> fn, int argnum,
> break;
> }
> if (!complained)
> - complained = permerror (loc, "invalid conversion from %qH to %qI",
> - TREE_TYPE (expr), totype);
> + {
> + range_label_for_type_mismatch label (TREE_TYPE (expr), totype);
> + gcc_rich_location richloc (loc, &label);
> + complained = permerror (&richloc,
> + "invalid conversion from %qH to %qI",
> + TREE_TYPE (expr), totype);
> + }
> if (complained && fn)
> inform (get_fndecl_argument_location (fn, argnum),
> " initializing argument %P of %qD", argnum, fn);
> @@ -10755,8 +10761,12 @@ 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 %qH to %qI", expr,
> - TREE_TYPE (expr), type);
> + {
> + range_label_for_type_mismatch label (TREE_TYPE (expr), type);
> + gcc_rich_location rich_loc (loc, &label);
> + error_at (&rich_loc, "could not convert %qE from %qH to %qI",
> + expr, TREE_TYPE (expr), type);
> + }
> }
> expr = error_mark_node;
> }
> diff --git a/gcc/cp/error.c b/gcc/cp/error.c
> index c49f4d7..355a5e8 100644
> --- a/gcc/cp/error.c
> +++ b/gcc/cp/error.c
> @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
> #include "c-family/c-objc.h"
> #include "ubsan.h"
> #include "internal-fn.h"
> +#include "gcc-rich-location.h"
>
> #define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',')
> #define pp_separate_with_semicolon(PP) pp_cxx_separate_with (PP, ';')
> @@ -4279,3 +4280,30 @@ qualified_name_lookup_error (tree scope, tree name,
> suggest_alternatives_for (location, name, true);
> }
> }
> +
> +/* C++-specific implementation of range_label::get_text () vfunc for
> + range_label_for_type_mismatch.
> +
> + Compare with print_template_differences above. */
> +
> +label_text
> +range_label_for_type_mismatch::get_text () const
> +{
> + if (m_labelled_type == NULL_TREE)
> + return label_text (NULL, false);
> +
> + const bool verbose = false;
> + const bool show_color = false;
> +
> + const char *result;
> + if (m_other_type
> + && comparable_template_types_p (m_labelled_type, m_other_type))
> + result = type_to_string_with_compare (m_labelled_type, m_other_type,
> + verbose, show_color);
> + else
> + result = type_to_string (m_labelled_type, verbose, true, NULL,
> show_color);
> +
> + /* Both of the above return GC-allocated buffers, so the caller mustn't
> + free them. */
> + return label_text (const_cast <char *> (result), false);
> +}
> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
> index 1335da5..64b3d58 100644
> --- a/gcc/cp/typeck.c
> +++ b/gcc/cp/typeck.c
> @@ -8805,7 +8805,16 @@ convert_for_assignment (tree type, tree rhs,
> }
> else if (fndecl)
> {
> - error_at (cp_expr_loc_or_loc (rhs, input_location),
> + location_t loc = cp_expr_location (rhs);
> + range_label_for_type_mismatch rhs_label (rhstype, type);
> + range_label *label = &rhs_label;
> + if (loc == UNKNOWN_LOCATION)
> + {
> + loc = input_location;
> + label = NULL;
> + }
> + gcc_rich_location richloc (loc, label);
> + error_at (&richloc,
> "cannot convert %qH to %qI",
> rhstype, type);
> inform (get_fndecl_argument_location (fndecl, parmnum),
> diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
> index 238c689..c9edaab 100644
> --- a/gcc/diagnostic-show-locus.c
> +++ b/gcc/diagnostic-show-locus.c
> @@ -127,7 +127,8 @@ class layout_range
> layout_range (const expanded_location *start_exploc,
> const expanded_location *finish_exploc,
> bool show_caret_p,
> - const expanded_location *caret_exploc);
> + const expanded_location *caret_exploc,
> + const range_label *label);
>
> bool contains_point (linenum_type row, int column) const;
> bool intersects_line_p (linenum_type row) const;
> @@ -136,6 +137,7 @@ class layout_range
> layout_point m_finish;
> bool m_show_caret_p;
> layout_point m_caret;
> + const range_label *m_label;
> };
>
> /* A struct for use by layout::print_source_line for telling
> @@ -253,6 +255,7 @@ class layout
> bool should_print_annotation_line_p (linenum_type row) const;
> void start_annotation_line () const;
> void print_annotation_line (linenum_type row, const line_bounds
> lbounds);
> + void print_any_labels (linenum_type row);
> void print_trailing_fixits (linenum_type row);
>
> bool annotation_line_showed_range_p (linenum_type line, int
> start_column,
> @@ -287,6 +290,7 @@ class layout
> expanded_location m_exploc;
> colorizer m_colorizer;
> bool m_colorize_source_p;
> + bool m_show_labels_p;
> bool m_show_line_numbers_p;
> auto_vec <layout_range> m_layout_ranges;
> auto_vec <const fixit_hint *> m_fixit_hints;
> @@ -408,11 +412,13 @@ colorizer::get_color_by_name (const char *name)
> layout_range::layout_range (const expanded_location *start_exploc,
> const expanded_location *finish_exploc,
> bool show_caret_p,
> - const expanded_location *caret_exploc)
> + const expanded_location *caret_exploc,
> + const range_label *label)
> : m_start (*start_exploc),
> m_finish (*finish_exploc),
> m_show_caret_p (show_caret_p),
> - m_caret (*caret_exploc)
> + m_caret (*caret_exploc),
> + m_label (label)
> {
> }
>
> @@ -539,7 +545,7 @@ make_range (int start_line, int start_col, int end_line,
> int end_col)
> const expanded_location finish_exploc
> = {"test.c", end_line, end_col, NULL, false};
> return layout_range (&start_exploc, &finish_exploc, false,
> - &start_exploc);
> + &start_exploc, NULL);
> }
>
> /* Selftests for layout_range::contains_point and
> @@ -879,6 +885,7 @@ layout::layout (diagnostic_context * context,
> m_exploc (richloc->get_expanded_location (0)),
> m_colorizer (context, diagnostic_kind),
> m_colorize_source_p (context->colorize_source_p),
> + m_show_labels_p (context->show_labels_p),
> m_show_line_numbers_p (context->show_line_numbers_p),
> m_layout_ranges (richloc->get_num_locations ()),
> m_fixit_hints (richloc->get_num_fixit_hints ()),
> @@ -989,7 +996,8 @@ layout::maybe_add_location_range (const location_range
> *loc_range,
>
> /* Everything is now known to be in the correct source file,
> but it may require further sanitization. */
> - layout_range ri (&start, &finish, loc_range->m_show_caret_p, &caret);
> + layout_range ri (&start, &finish, loc_range->m_show_caret_p, &caret,
> + loc_range->m_label);
>
> /* If we have a range that finishes before it starts (perhaps
> from something built via macro expansion), printing the
> @@ -1379,6 +1387,180 @@ layout::print_annotation_line (linenum_type row,
> const line_bounds lbounds)
> print_newline ();
> }
>
> +/* Implementation detail of layout::print_any_labels.
> +
> + A label within the given row of source. */
> +
> +struct line_label
> +{
> + line_label (int state_idx, int column, label_text text)
> + : m_state_idx (state_idx), m_column (column),
> + m_text (text), m_length (strlen (text.m_buffer)),
> + m_label_line (0)
> + {}
> +
> + /* Sorting is primarily by column, then by state index. */
> + static int comparator (const void *p1, const void *p2)
> + {
> + const line_label *ll1 = (const line_label *)p1;
> + const line_label *ll2 = (const line_label *)p2;
> + int column_cmp = compare (ll1->m_column, ll2->m_column);
> + if (column_cmp)
> + return column_cmp;
> + return compare (ll1->m_state_idx, ll2->m_state_idx);
> + }
> +
> + int m_state_idx;
> + int m_column;
> + label_text m_text;
> + size_t m_length;
> + int m_label_line;
> +};
> +
> +/* Print any labels in this row. */
> +void
> +layout::print_any_labels (linenum_type row)
> +{
> + int i;
> + auto_vec<line_label> labels;
> +
> + /* Gather the labels that are to be printed into "labels". */
> + {
> + layout_range *range;
> + FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
> + {
> + /* Most ranges don't have labels, so reject this first. */
> + if (range->m_label == NULL)
> + continue;
> +
> + /* The range's caret must be on this line. */
> + if (range->m_caret.m_line != row)
> + continue;
> +
> + /* Reject labels that aren't fully visible due to clipping
> + by m_x_offset. */
> + if (range->m_caret.m_column <= m_x_offset)
> + continue;
> +
> + label_text text;
> + text = range->m_label->get_text ();
> +
> + /* Allow for labels that return NULL from their get_text
> + implementation (so e.g. such labels can control their own
> + visibility). */
> + if (text.m_buffer == NULL)
> + continue;
> +
> + labels.safe_push (line_label (i, range->m_caret.m_column, text));
> + }
> + }
> +
> + /* Bail out if there are no labels on this row. */
> + if (labels.length () == 0)
> + return;
> +
> + /* Sort them. */
> + labels.qsort(line_label::comparator);
> +
> + /* Figure out how many "label lines" we need, and which
> + one each label is printed in.
> +
> + For example, if the labels aren't too densely packed,
> + we can fit them on the same line, giving two "label lines":
> +
> + foo + bar
> + ~~~ ~~~
> + | | : label line 0
> + l0 l1 : label line 1
> +
> + If they would touch each other or overlap, then we need
> + additional "label lines":
> +
> + foo + bar
> + ~~~ ~~~
> + | | : label line 0
> + | label 1 : label line 1
> + label 0 : label line 2
> +
> + Place the final label on label line 1, and work backwards, adding
> + label lines as needed.
> +
> + If multiple labels are at the same place, put them on separate
> + label lines:
> +
> + foo + bar
> + ^ : label line 0
> + | : label line 1
> + label 1 : label line 2
> + label 0 : label line 3. */
> +
> + int max_label_line = 1;
> + {
> + int next_column = INT_MAX;
> + line_label *label;
> + FOR_EACH_VEC_ELT_REVERSE (labels, i, label)
> + {
> + /* Would this label "touch" or overlap the next label? */
> + if (label->m_column + label->m_length >= (size_t)next_column)
> + max_label_line++;
> +
> + label->m_label_line = max_label_line;
> + next_column = label->m_column;
> + }
> + }
> +
> + /* Print the "label lines". For each label within the line, print
> + either a vertical bar ('|') for the labels that are lower down, or
> the
> + labels themselves once we've reached their line. */
> + {
> + /* Keep track of in which column we last printed a vertical bar.
> + This allows us to suppress duplicate vertical bars for the case
> + where multiple labels are on one column. */
> + int last_vbar = 0;
> + for (int label_line = 0; label_line <= max_label_line; label_line++)
> + {
> + start_annotation_line ();
> + pp_space (m_pp);
> + int column = 1 + m_x_offset;
> + line_label *label;
> + FOR_EACH_VEC_ELT (labels, i, label)
> + {
> + if (label_line > label->m_label_line)
> + /* We've printed all the labels for this label line. */
> + break;
> +
> + if (label_line == label->m_label_line)
> + {
> + gcc_assert (column <= label->m_column);
> + move_to_column (&column, label->m_column, true);
> + m_colorizer.set_range (label->m_state_idx);
> + pp_string (m_pp, label->m_text.m_buffer);
> + m_colorizer.set_normal_text ();
> + column += label->m_length;
> + }
> + else if (label->m_column != last_vbar)
> + {
> + gcc_assert (column <= label->m_column);
> + move_to_column (&column, label->m_column, true);
> + m_colorizer.set_range (label->m_state_idx);
> + pp_character (m_pp, '|');
> + m_colorizer.set_normal_text ();
> + last_vbar = column;
> + column++;
> + }
> + }
> + print_newline ();
> + }
> + }
> +
> + /* Clean up. */
> + {
> + line_label *label;
> + FOR_EACH_VEC_ELT (labels, i, label)
> + label->m_text.maybe_free ();
> + }
> +}
> +
> /* If there are any fixit hints inserting new lines before source line
> ROW,
> print them.
>
> @@ -2023,6 +2205,8 @@ layout::print_line (linenum_type row)
> print_source_line (row, line.get_buffer (), line.length (), &lbounds);
> if (should_print_annotation_line_p (row))
> print_annotation_line (row, lbounds);
> + if (m_show_labels_p)
> + print_any_labels (row);
> print_trailing_fixits (row);
> }
>
> @@ -2429,6 +2613,157 @@ test_one_liner_many_fixits_2 ()
> pp_formatted_text (dc.printer));
> }
>
> +/* Test of labeling the ranges within a rich_location. */
> +
> +static void
> +test_one_liner_labels ()
> +{
> + location_t foo
> + = make_location (linemap_position_for_column (line_table, 1),
> + linemap_position_for_column (line_table, 1),
> + linemap_position_for_column (line_table, 3));
> + location_t bar
> + = make_location (linemap_position_for_column (line_table, 7),
> + linemap_position_for_column (line_table, 7),
> + linemap_position_for_column (line_table, 9));
> + location_t field
> + = make_location (linemap_position_for_column (line_table, 11),
> + linemap_position_for_column (line_table, 11),
> + linemap_position_for_column (line_table, 15));
> +
> + /* Example where all the labels fit on one line. */
> + {
> + text_range_label label0 ("0");
> + text_range_label label1 ("1");
> + text_range_label label2 ("2");
> + gcc_rich_location richloc (foo, &label0);
> + richloc.add_range (bar, false, &label1);
> + richloc.add_range (field, false, &label2);
> +
> + {
> + test_diagnostic_context dc;
> + diagnostic_show_locus (&dc, &richloc, DK_ERROR);
> + ASSERT_STREQ ("\n"
> + " foo = bar.field;\n"
> + " ^~~ ~~~ ~~~~~\n"
> + " | | |\n"
> + " 0 1 2\n",
> + pp_formatted_text (dc.printer));
> + }
> +
> + /* Verify that we can disable label-printing. */
> + {
> + test_diagnostic_context dc;
> + dc.show_labels_p = false;
> + diagnostic_show_locus (&dc, &richloc, DK_ERROR);
> + ASSERT_STREQ ("\n"
> + " foo = bar.field;\n"
> + " ^~~ ~~~ ~~~~~\n",
> + pp_formatted_text (dc.printer));
> + }
> + }
> +
> + /* Example where the labels need extra lines. */
> + {
> + text_range_label label0 ("label 0");
> + text_range_label label1 ("label 1");
> + text_range_label label2 ("label 2");
> + gcc_rich_location richloc (foo, &label0);
> + richloc.add_range (bar, false, &label1);
> + richloc.add_range (field, false, &label2);
> +
> + test_diagnostic_context dc;
> + diagnostic_show_locus (&dc, &richloc, DK_ERROR);
> + ASSERT_STREQ ("\n"
> + " foo = bar.field;\n"
> + " ^~~ ~~~ ~~~~~\n"
> + " | | |\n"
> + " | | label 2\n"
> + " | label 1\n"
> + " label 0\n",
> + pp_formatted_text (dc.printer));
> + }
> +
> + /* Example of boundary conditions: label 0 and 1 have just enough
> clearance,
> + but label 1 just touches label 2. */
> + {
> + text_range_label label0 ("aaaaa");
> + text_range_label label1 ("bbbb");
> + text_range_label label2 ("c");
> + gcc_rich_location richloc (foo, &label0);
> + richloc.add_range (bar, false, &label1);
> + richloc.add_range (field, false, &label2);
> +
> + test_diagnostic_context dc;
> + diagnostic_show_locus (&dc, &richloc, DK_ERROR);
> + ASSERT_STREQ ("\n"
> + " foo = bar.field;\n"
> + " ^~~ ~~~ ~~~~~\n"
> + " | | |\n"
> + " | | c\n"
> + " aaaaa bbbb\n",
> + pp_formatted_text (dc.printer));
> + }
> +
> + /* Example of out-of-order ranges (thus requiring a sort). */
> + {
> + text_range_label label0 ("0");
> + text_range_label label1 ("1");
> + text_range_label label2 ("2");
> + gcc_rich_location richloc (field, &label0);
> + richloc.add_range (bar, false, &label1);
> + richloc.add_range (foo, false, &label2);
> +
> + test_diagnostic_context dc;
> + diagnostic_show_locus (&dc, &richloc, DK_ERROR);
> + ASSERT_STREQ ("\n"
> + " foo = bar.field;\n"
> + " ~~~ ~~~ ^~~~~\n"
> + " | | |\n"
> + " 2 1 0\n",
> + pp_formatted_text (dc.printer));
> + }
> +
> + /* Ensure we don't ICE if multiple ranges with labels are on
> + the same point. */
> + {
> + text_range_label label0 ("label 0");
> + text_range_label label1 ("label 1");
> + text_range_label label2 ("label 2");
> + gcc_rich_location richloc (bar, &label0);
> + richloc.add_range (bar, false, &label1);
> + richloc.add_range (bar, false, &label2);
> +
> + test_diagnostic_context dc;
> + diagnostic_show_locus (&dc, &richloc, DK_ERROR);
> + ASSERT_STREQ ("\n"
> + " foo = bar.field;\n"
> + " ^~~\n"
> + " |\n"
> + " label 2\n"
> + " label 1\n"
> + " label 0\n",
> + pp_formatted_text (dc.printer));
> + }
> +
> + /* Verify that a NULL result from range_label::get_text is
> + handled gracefully. */
> + {
> + text_range_label label (NULL);
> + gcc_rich_location richloc (bar, &label);
> +
> + test_diagnostic_context dc;
> + diagnostic_show_locus (&dc, &richloc, DK_ERROR);
> + ASSERT_STREQ ("\n"
> + " foo = bar.field;\n"
> + " ^~~\n",
> + pp_formatted_text (dc.printer));
> + }
> +
> + /* TODO: example of formatted printing (needs to be in
> + gcc-rich-location.c due to Makefile.in issues). */
> +}
> +
> /* Run the various one-liner tests. */
>
> static void
> @@ -2465,6 +2800,7 @@ test_diagnostic_show_locus_one_liner (const
> line_table_case &case_)
> test_one_liner_fixit_validation_adhoc_locations ();
> test_one_liner_many_fixits_1 ();
> test_one_liner_many_fixits_2 ();
> + test_one_liner_labels ();
> }
>
> /* Verify that gcc_rich_location::add_location_if_nearby works. */
> diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
> index e9d93d5..59477ce 100644
> --- a/gcc/diagnostic.c
> +++ b/gcc/diagnostic.c
> @@ -175,6 +175,7 @@ diagnostic_initialize (diagnostic_context *context, int
> n_opts)
> context->lock = 0;
> context->inhibit_notes_p = false;
> context->colorize_source_p = false;
> + context->show_labels_p = false;
> context->show_line_numbers_p = false;
> context->show_ruler_p = false;
> context->parseable_fixits_p = false;
> diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
> index 744aec1..fe3130b 100644
> --- a/gcc/diagnostic.h
> +++ b/gcc/diagnostic.h
> @@ -204,6 +204,9 @@ struct diagnostic_context
> a token, which would look strange). */
> bool colorize_source_p;
>
> + /* When printing source code, should labelled ranges be printed? */
> + bool show_labels_p;
> +
> /* When printing source code, should there be a left-hand margin
> showing line numbers? */
> bool show_line_numbers_p;
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index d7fd0e1..586af17 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -267,7 +267,7 @@ Objective-C and Objective-C++ Dialects}.
> -fdiagnostics-show-location=@r{[}once@r{|}every-line@r{]} @gol
> -fdiagnostics-color=@r{[}auto@r{|}never@r{|}always@r{]} @gol
> -fno-diagnostics-show-option -fno-diagnostics-show-caret @gol
> --fno-diagnostics-show-line-numbers @gol
> +-fno-diagnostics-show-labels -fno-diagnostics-show-line-numbers @gol
> -fdiagnostics-parseable-fixits -fdiagnostics-generate-patch @gol
> -fdiagnostics-show-template-tree -fno-elide-type @gol
> -fno-show-column}
> @@ -3711,6 +3711,23 @@ the @option{-fmessage-length=n} option is given.
> When the output is done
> to the terminal, the width is limited to the width given by the
> @env{COLUMNS} environment variable or, if not set, to the terminal width.
>
> +@item -fno-diagnostics-show-labels
> +@opindex fno-diagnostics-show-labels
> +@opindex fdiagnostics-show-labels
> +By default, when printing source code (via
> @option{-fdiagnostics-show-caret}),
> +diagnostics can label ranges of source code with pertinent information,
> such
> +as the types of expressions:
> +
> +@smallexample
> + printf ("foo %s bar", long_i + long_j);
> + ~^ ~~~~~~~~~~~~~~~
> + | |
> + char * long int
> +@end smallexample
> +
> +This option suppresses the printing of these labels (in the example above,
> +the vertical bars and the ``char *'' and ``long int'' text).
> +
> @item -fno-diagnostics-show-line-numbers
> @opindex fno-diagnostics-show-line-numbers
> @opindex fdiagnostics-show-line-numbers
> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
> index 9ed4730..5a74131 100644
> --- a/gcc/dwarf2out.c
> +++ b/gcc/dwarf2out.c
> @@ -24247,6 +24247,7 @@ gen_producer_string (void)
> case OPT_fdiagnostics_show_location_:
> case OPT_fdiagnostics_show_option:
> case OPT_fdiagnostics_show_caret:
> + case OPT_fdiagnostics_show_labels:
> case OPT_fdiagnostics_show_line_numbers:
> case OPT_fdiagnostics_color_:
> case OPT_fverbose_asm:
> diff --git a/gcc/gcc-rich-location.c b/gcc/gcc-rich-location.c
> index 0a0adf9..2576c73 100644
> --- a/gcc/gcc-rich-location.c
> +++ b/gcc/gcc-rich-location.c
> @@ -38,24 +38,26 @@ along with GCC; see the file COPYING3. If not see
> #include "cpplib.h"
> #include "diagnostic.h"
>
> -/* Add a range to the rich_location, covering expression EXPR. */
> +/* Add a range to the rich_location, covering expression EXPR,
> + using LABEL if non-NULL. */
>
> void
> -gcc_rich_location::add_expr (tree expr)
> +gcc_rich_location::add_expr (tree expr, range_label *label)
> {
> gcc_assert (expr);
>
> if (CAN_HAVE_RANGE_P (expr))
> - add_range (EXPR_LOCATION (expr), false);
> + add_range (EXPR_LOCATION (expr), false, label);
> }
>
> -/* If T is an expression, add a range for it to the rich_location. */
> +/* If T is an expression, add a range for it to the rich_location,
> + using LABEL if non-NULL. */
>
> void
> -gcc_rich_location::maybe_add_expr (tree t)
> +gcc_rich_location::maybe_add_expr (tree t, range_label *label)
> {
> if (EXPR_P (t))
> - add_expr (t);
> + add_expr (t, label);
> }
>
> /* Add a fixit hint suggesting replacing the range at MISSPELLED_TOKEN_LOC
> diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h
> index 9c705c8..dc11ee8 100644
> --- a/gcc/gcc-rich-location.h
> +++ b/gcc/gcc-rich-location.h
> @@ -28,15 +28,17 @@ class gcc_rich_location : public rich_location
> /* Constructors. */
>
> /* Constructing from a location. */
> - gcc_rich_location (source_location loc) :
> - rich_location (line_table, loc) {}
> + gcc_rich_location (source_location loc, const range_label *label = NULL)
> + : rich_location (line_table, loc, label)
> + {
> + }
>
> /* Methods for adding ranges via gcc entities. */
> void
> - add_expr (tree expr);
> + add_expr (tree expr, range_label *label);
>
> void
> - maybe_add_expr (tree t);
> + maybe_add_expr (tree t, range_label *label);
>
> void add_fixit_misspelled_id (location_t misspelled_token_loc,
> tree hint_id);
> @@ -99,4 +101,65 @@ class gcc_rich_location : public rich_location
> location_t indent);
> };
>
> +/* Concrete subclass of libcpp's range_label.
> + Simple implementation using a string literal. */
> +
> +class text_range_label : public range_label
> +{
> + public:
> + text_range_label (const char *text) : m_text (text) {}
> +
> + label_text get_text () const FINAL OVERRIDE
> + {
> + return label_text (const_cast <char *> (m_text), false);
> + }
> +
> + private:
> + const char *m_text;
> +};
> +
> +/* Concrete subclass of libcpp's range_label for use in
> + diagnostics involving mismatched types.
> +
> + Each frontend that uses this should supply its own implementation.
> +
> + Generate a label describing LABELLED_TYPE. The frontend may use
> + OTHER_TYPE where appropriate for highlighting the differences between
> + the two types (analogous to C++'s use of %H and %I with
> + template types).
> +
> + Either or both of LABELLED_TYPE and OTHER_TYPE may be NULL_TREE.
> + If LABELLED_TYPE is NULL_TREE, then there is no label.
> +
> + For example, this rich_location could use two instances of
> + range_label_for_type_mismatch:
> +
> + printf ("arg0: %i arg1: %s arg2: %i",
> + ^~
> + |
> + const char *
> + 100, 101, 102);
> + ~~~
> + |
> + int
> +
> + (a) the label for "%s" with LABELLED_TYPE for "const char*" and
> + (b) the label for "101" with LABELLED TYPE for "int"
> + where each one uses the other's type as OTHER_TYPE. */
> +
> +class range_label_for_type_mismatch : public range_label
> +{
> + public:
> + range_label_for_type_mismatch (tree labelled_type, tree other_type)
> + : m_labelled_type (labelled_type), m_other_type (other_type)
> + {
> + }
> +
> + label_text get_text () const OVERRIDE;
> +
> + protected:
> + tree m_labelled_type;
> + tree m_other_type;
> +};
> +
> #endif /* GCC_RICH_LOCATION_H */
> diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
> index c652c55..5213e17 100644
> --- a/gcc/gimple-ssa-sprintf.c
> +++ b/gcc/gimple-ssa-sprintf.c
> @@ -601,8 +601,8 @@ fmtwarn (const substring_loc &fmt_loc, location_t
> param_loc,
> {
> va_list ap;
> va_start (ap, gmsgid);
> - bool warned = format_warning_va (fmt_loc, param_loc,
> corrected_substring,
> - opt, gmsgid, &ap);
> + bool warned = format_warning_va (fmt_loc, NULL, param_loc, NULL,
> + corrected_substring, opt, gmsgid, &ap);
> va_end (ap);
>
> return warned;
> @@ -616,7 +616,8 @@ fmtwarn_n (const substring_loc &fmt_loc, location_t
> param_loc,
> {
> va_list ap;
> va_start (ap, plural_gmsgid);
> - bool warned = format_warning_n_va (fmt_loc, param_loc,
> corrected_substring,
> + bool warned = format_warning_n_va (fmt_loc, NULL, param_loc, NULL,
> + corrected_substring,
> opt, n, singular_gmsgid, plural_gmsgid,
> &ap);
> va_end (ap);
> diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
> index 39d9f08..d446786 100644
> --- a/gcc/lto-wrapper.c
> +++ b/gcc/lto-wrapper.c
> @@ -255,6 +255,7 @@ merge_and_complain (struct cl_decoded_option
> **decoded_options,
>
> /* Fallthru. */
> case OPT_fdiagnostics_show_caret:
> + case OPT_fdiagnostics_show_labels:
> case OPT_fdiagnostics_show_line_numbers:
> case OPT_fdiagnostics_show_option:
> case OPT_fdiagnostics_show_location_:
> @@ -537,6 +538,7 @@ append_compiler_options (obstack *argv_obstack, struct
> cl_decoded_option *opts,
> switch (option->opt_index)
> {
> case OPT_fdiagnostics_show_caret:
> + case OPT_fdiagnostics_show_labels:
> case OPT_fdiagnostics_show_line_numbers:
> case OPT_fdiagnostics_show_option:
> case OPT_fdiagnostics_show_location_:
> @@ -584,6 +586,7 @@ append_diag_options (obstack *argv_obstack, struct
> cl_decoded_option *opts,
> {
> case OPT_fdiagnostics_color_:
> case OPT_fdiagnostics_show_caret:
> + case OPT_fdiagnostics_show_labels:
> case OPT_fdiagnostics_show_line_numbers:
> case OPT_fdiagnostics_show_option:
> case OPT_fdiagnostics_show_location_:
> diff --git a/gcc/opts.c b/gcc/opts.c
> index 4153263..a5c9ed9 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -2175,6 +2175,10 @@ common_handle_option (struct gcc_options *opts,
> dc->show_caret = value;
> break;
>
> + case OPT_fdiagnostics_show_labels:
> + dc->show_labels_p = value;
> + break;
> +
> case OPT_fdiagnostics_show_line_numbers:
> dc->show_line_numbers_p = value;
> break;
> diff --git a/gcc/selftest-diagnostic.c b/gcc/selftest-diagnostic.c
> index 837488b..f3c255e 100644
> --- a/gcc/selftest-diagnostic.c
> +++ b/gcc/selftest-diagnostic.c
> @@ -37,6 +37,7 @@ test_diagnostic_context::test_diagnostic_context ()
> {
> diagnostic_initialize (this, 0);
> show_caret = true;
> + show_labels_p = true;
> show_column = true;
> start_span = start_span_cb;
> }
> diff --git a/gcc/substring-locations.c b/gcc/substring-locations.c
> index 2d7f0c1..82f2f45 100644
> --- a/gcc/substring-locations.c
> +++ b/gcc/substring-locations.c
> @@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see
> #include "tree.h"
> #include "langhooks.h"
> #include "substring-locations.h"
> +#include "gcc-rich-location.h"
>
> /* Emit a warning governed by option OPT, using SINGULAR_GMSGID as the
> format string (or if PLURAL_GMSGID is different from SINGULAR_GMSGID,
> @@ -89,6 +90,27 @@ along with GCC; see the file COPYING3. If not see
> printf(fmt, msg);
> ^~~ ~~~
>
> + If non-NULL, then FMT_LABEL will be used to label the location within
> the
> + string for cases 1 and 2; if non-NULL, then PARAM_LABEL will be used to
> label
> + the parameter. For example with case 1:
> +
> + test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
> + printf ("foo %s bar", long_i + long_j);
> + ~^ ~~~~~~~~~~~~~~~
> + |
> + int
> +
> + and with case 2:
> +
> + test.c:90:10: warning: problem with '%i' here [-Wformat=]
> + printf("hello " INT_FMT " world", msg);
> + ^~~~~~~~~~~~~~~~~~~~~~~~~
> + test.c:19: note: format string is defined here
> + #define INT_FMT "%i"
> + ~^
> + |
> + int
> +
> If CORRECTED_SUBSTRING is non-NULL, use it for cases 1 and 2 to provide
> a fix-it hint, suggesting that it should replace the text within the
> substring range. For example:
> @@ -102,7 +124,9 @@ along with GCC; see the file COPYING3. If not see
>
> bool
> format_warning_n_va (const substring_loc &fmt_loc,
> + const range_label *fmt_label,
> location_t param_loc,
> + const range_label *param_label,
> const char *corrected_substring,
> int opt, unsigned HOST_WIDE_INT n,
> const char *singular_gmsgid,
> @@ -138,10 +162,15 @@ format_warning_n_va (const substring_loc &fmt_loc,
> }
> }
>
> - rich_location richloc (line_table, primary_loc);
> + /* Only use fmt_label in the initial warning for case 1. */
> + const range_label *primary_label = NULL;
> + if (substring_within_range)
> + primary_label = fmt_label;
> +
> + gcc_rich_location richloc (primary_loc, primary_label);
>
> if (param_loc != UNKNOWN_LOCATION)
> - richloc.add_range (param_loc, false);
> + richloc.add_range (param_loc, false, param_label);
>
> if (!err && corrected_substring && substring_within_range)
> richloc.add_fixit_replace (fmt_substring_range, corrected_substring);
> @@ -173,7 +202,9 @@ format_warning_n_va (const substring_loc &fmt_loc,
> /* Case 2. */
> if (warned)
> {
> - rich_location substring_richloc (line_table, fmt_substring_loc);
> + /* Use fmt_label in the note for case 2. */
> + rich_location substring_richloc (line_table, fmt_substring_loc,
> + fmt_label);
> if (corrected_substring)
> substring_richloc.add_fixit_replace (fmt_substring_range,
> corrected_substring);
> @@ -188,11 +219,14 @@ format_warning_n_va (const substring_loc &fmt_loc,
>
> bool
> format_warning_va (const substring_loc &fmt_loc,
> + const range_label *fmt_label,
> location_t param_loc,
> + const range_label *param_label,
> const char *corrected_substring,
> int opt, const char *gmsgid, va_list *ap)
> {
> - return format_warning_n_va (fmt_loc, param_loc, corrected_substring,
> opt,
> + return format_warning_n_va (fmt_loc, fmt_label, param_loc, param_label,
> + corrected_substring, opt,
> 0, gmsgid, gmsgid, ap);
> }
>
> @@ -200,14 +234,16 @@ format_warning_va (const substring_loc &fmt_loc,
>
> bool
> format_warning_at_substring (const substring_loc &fmt_loc,
> + const range_label *fmt_label,
> location_t param_loc,
> + const range_label *param_label,
> const char *corrected_substring,
> int opt, const char *gmsgid, ...)
> {
> va_list ap;
> va_start (ap, gmsgid);
> - bool warned = format_warning_va (fmt_loc, param_loc,
> corrected_substring,
> - opt, gmsgid, &ap);
> + bool warned = format_warning_va (fmt_loc, fmt_label, param_loc,
> param_label,
> + corrected_substring, opt, gmsgid, &ap);
> va_end (ap);
>
> return warned;
> @@ -217,7 +253,9 @@ format_warning_at_substring (const substring_loc
> &fmt_loc,
>
> bool
> format_warning_at_substring_n (const substring_loc &fmt_loc,
> + const range_label *fmt_label,
> location_t param_loc,
> + const range_label *param_label,
> const char *corrected_substring,
> int opt, unsigned HOST_WIDE_INT n,
> const char *singular_gmsgid,
> @@ -225,7 +263,8 @@ format_warning_at_substring_n (const substring_loc
> &fmt_loc,
> {
> va_list ap;
> va_start (ap, plural_gmsgid);
> - bool warned = format_warning_n_va (fmt_loc, param_loc,
> corrected_substring,
> + bool warned = format_warning_n_va (fmt_loc, fmt_label, param_loc,
> param_label,
> + corrected_substring,
> opt, n, singular_gmsgid, plural_gmsgid,
> &ap);
> va_end (ap);
> diff --git a/gcc/substring-locations.h b/gcc/substring-locations.h
> index fca6fd3..919fdf0 100644
> --- a/gcc/substring-locations.h
> +++ b/gcc/substring-locations.h
> @@ -77,32 +77,40 @@ class substring_loc
> /* Functions for emitting a warning about a format string. */
>
> extern bool format_warning_va (const substring_loc &fmt_loc,
> + const range_label *fmt_label,
> location_t param_loc,
> + const range_label *param_label,
> const char *corrected_substring,
> int opt, const char *gmsgid, va_list *ap)
> - ATTRIBUTE_GCC_DIAG (5, 0);
> + ATTRIBUTE_GCC_DIAG (7, 0);
>
> extern bool format_warning_n_va (const substring_loc &fmt_loc,
> + const range_label *fmt_label,
> location_t param_loc,
> + const range_label *param_label,
> const char *corrected_substring,
> int opt, unsigned HOST_WIDE_INT n,
> const char *singular_gmsgid,
> const char *plural_gmsgid, va_list *ap)
> - ATTRIBUTE_GCC_DIAG (6, 0) ATTRIBUTE_GCC_DIAG (7, 0);
> + ATTRIBUTE_GCC_DIAG (8, 0) ATTRIBUTE_GCC_DIAG (9, 0);
>
> extern bool format_warning_at_substring (const substring_loc &fmt_loc,
> + const range_label *fmt_label,
> location_t param_loc,
> + const range_label *param_label,
> const char *corrected_substring,
> int opt, const char *gmsgid, ...)
> - ATTRIBUTE_GCC_DIAG (5, 6);
> + ATTRIBUTE_GCC_DIAG (7, 8);
>
> extern bool format_warning_at_substring_n (const substring_loc &fmt_loc,
> + const range_label *fmt_label,
> location_t param_loc,
> + const range_label *param_label,
> const char *corrected_substring,
> int opt, unsigned HOST_WIDE_INT n,
> const char *singular_gmsgid,
> const char *plural_gmsgid, ...)
> - ATTRIBUTE_GCC_DIAG (6, 8) ATTRIBUTE_GCC_DIAG (7, 8);
> + ATTRIBUTE_GCC_DIAG (8, 10) ATTRIBUTE_GCC_DIAG (9, 10);
>
> /* Implementation detail, for use when implementing
> LANG_HOOKS_GET_SUBSTRING_LOCATION. */
> diff --git a/gcc/testsuite/g++.dg/diagnostic/aka3.C
> b/gcc/testsuite/g++.dg/diagnostic/aka3.C
> new file mode 100644
> index 0000000..1eb4fb2
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/diagnostic/aka3.C
> @@ -0,0 +1,25 @@
> +/* Verify the "aka" descriptions for typedefs are correctly
> + quoted and shown within labels. */
> +
> +/* { dg-options "-fdiagnostics-show-caret" } */
> +
> +typedef struct s1 t1;
> +typedef struct s2 {int i;} t2;
> +
> +int foo(t1 *);
> +
> +void test_1 () {
> + t2 pos;
> +
> + foo (&pos); // { dg-error "cannot convert 't2\\*' {aka 's2\\*'} to
> 't1\\*' {aka 's1\\*'}" }
> + /* { dg-begin-multiline-output "" }
> + foo (&pos);
> + ^~~~
> + |
> + t2* {aka s2*}
> + { dg-end-multiline-output "" } */
> + /* { dg-begin-multiline-output "" }
> + int foo(t1 *);
> + ^~~~
> + { dg-end-multiline-output "" } */
> +}
> diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
> b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
> index c3b6f00..8cf2dab 100644
> --- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
> +++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
> @@ -12,6 +12,8 @@ int test_1 (int first, const char *second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_1 (first, second, third);
> ^~~~~~
> + |
> + const char*
> { dg-end-multiline-output "" } */
> // { dg-message "initializing argument 2 of 'int callee_1\\(int, const
> char\\*\\*, float\\)'" "" { target *-*-* } callee_1 }
> /* { dg-begin-multiline-output "" }
> @@ -30,6 +32,8 @@ int test_2 (int first, const char *second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_2 (first, second, third);
> ^~~~~~
> + |
> + const char*
> { dg-end-multiline-output "" } */
> // { dg-message "initializing argument 2 of 'int callee_2\\(int, const
> char\\*\\*, float\\)'" "" { target *-*-* } callee_2 }
> /* { dg-begin-multiline-output "" }
> @@ -51,6 +55,8 @@ int test_3 (int first, const char *second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_3 (first, second, third);
> ^~~~~~
> + |
> + const char*
> { dg-end-multiline-output "" } */
> // { dg-message "initializing argument 2 of 'int callee_3\\(int, const
> char\\*\\*, float\\)'" "" { target *-*-* } callee_3 }
> /* { dg-begin-multiline-output "" }
> diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
> b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
> index 5fcde0b..50bbd4a 100644
> --- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
> +++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
> @@ -12,6 +12,8 @@ int test_1 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_1 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> // { dg-message "initializing argument 2 of 'int callee_1\\(int, const
> char\\*, float\\)'" "" { target *-*-* } callee_1 }
> /* { dg-begin-multiline-output "" }
> @@ -30,6 +32,8 @@ int test_2 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_2 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> // { dg-message "initializing argument 2 of 'int callee_2\\(int, const
> char\\*, float\\)'" "" { target *-*-* } callee_2 }
> /* { dg-begin-multiline-output "" }
> @@ -51,6 +55,8 @@ int test_3 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_3 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> // { dg-message "initializing argument 2 of 'int callee_3\\(int, const
> char\\*, float\\)'" "" { target *-*-* } callee_3 }
> /* { dg-begin-multiline-output "" }
> @@ -69,6 +75,8 @@ int test_4 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return s4::member_1 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> /* { dg-begin-multiline-output "" }
> struct s4 { static int member_1 (int one, const char *two, float three);
> };
> @@ -87,6 +95,8 @@ int test_5 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return inst.member_1 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> /* { dg-begin-multiline-output "" }
> struct s5 { int member_1 (int one, const char *two, float three); };
> @@ -104,6 +114,8 @@ int test_6 (int first, int second, float third, s6
> *ptr)
> /* { dg-begin-multiline-output "" }
> return ptr->member_1 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> /* { dg-begin-multiline-output "" }
> struct s6 { int member_1 (int one, const char *two, float three); };
> @@ -144,6 +156,8 @@ int test_8 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return s8 <const char *>::member_1 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> /* { dg-begin-multiline-output "" }
> struct s8 { static int member_1 (int one, T two, float three); };
> @@ -163,6 +177,8 @@ int test_9 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return inst.member_1 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> /* { dg-begin-multiline-output "" }
> struct s9 { int member_1 (int one, T two, float three); };
> @@ -180,6 +196,8 @@ int test_10 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_10 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> // { dg-message "initializing argument 2 of 'int callee_10\\(int, int
> \\(\\*\\)\\(int, int\\), float\\)'" "" { target *-*-* } callee_10 }
> /* { dg-begin-multiline-output "" }
> @@ -198,6 +216,8 @@ int test_11 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_11 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> // { dg-message "initializing argument 2 of 'int callee_11\\(int, int
> \\(\\*\\)\\(int, int\\), float\\)'" "" { target *-*-* } callee_11 }
> /* { dg-begin-multiline-output "" }
> diff --git a/gcc/testsuite/g++.dg/plugin/plugin.exp
> b/gcc/testsuite/g++.dg/plugin/plugin.exp
> index 451c4a9..d9f54ab 100644
> --- a/gcc/testsuite/g++.dg/plugin/plugin.exp
> +++ b/gcc/testsuite/g++.dg/plugin/plugin.exp
> @@ -69,6 +69,7 @@ set plugin_test_list [list \
> diagnostic-test-inlining-1.C } \
> { show_template_tree_color_plugin.c \
> show-template-tree-color.C \
> + show-template-tree-color-labels.C \
> show-template-tree-color-no-elide-type.C } \
> { comment_plugin.c comments-1.C } \
> ]
> diff --git a/gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C
> b/gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C
> new file mode 100644
> index 0000000..462e1bd
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C
> @@ -0,0 +1,38 @@
> +/* Verify colorization of the labels in diagnostic-show-locus.c
> + for template comparisons.
> + Doing so requires a plugin; see the comments in the plugin for the
> + rationale. */
> +
> +// { dg-options "-fdiagnostics-color=always -fdiagnostics-show-caret" }
> +
> +template<typename> struct vector {};
> +template<typename, typename> struct map {};
> +
> +void fn_1(vector<int>);
> +void fn_2(map<int, int>);
> +
> +void test_1 (vector<double> vec)
> +{
> + fn_1 (vec);
> + /* { dg-begin-multiline-output "" }
> +could not convert ' [01m [Kvec [m [K' from ' [01m [Kvector< [01;32m
> [Kdouble [m [K> [m [K' to ' [01m [Kvector< [01;32m [Kint [m [K> [m [K'
> + fn_1 ( [01;31m [Kvec [m [K);
> + [01;31m [K^~~ [m [K
> + [01;31m [K| [m [K
> + [01;31m [Kvector<double> [m [K
> + { dg-end-multiline-output "" } */
> + // TODO: we don't yet highlight the mismatching part with color
> +}
> +
> +void test_2 (const map<int, double> &m)
> +{
> + fn_2 (m);
> + /* { dg-begin-multiline-output "" }
> +could not convert ' [01m [Km [m [K' from ' [01m [Kmap<[...], [01;32m
> [Kdouble [m [K> [m [K' to ' [01m [Kmap<[...], [01;32m [Kint [m [K> [m [K'
> + fn_2 ( [01;31m [Km [m [K);
> + [01;31m [K^ [m [K
> + [01;31m [K| [m [K
> + [01;31m [Kmap<[...],double> [m [K
> + { dg-end-multiline-output "" } */
> + // TODO: we don't yet highlight the mismatching part with color
> +}
> diff --git a/gcc/testsuite/gcc.dg/bad-binary-ops.c
> b/gcc/testsuite/gcc.dg/bad-binary-ops.c
> index e1da4d6..46c158e 100644
> --- a/gcc/testsuite/gcc.dg/bad-binary-ops.c
> +++ b/gcc/testsuite/gcc.dg/bad-binary-ops.c
> @@ -13,6 +13,8 @@ void test_1 ()
> { dg-begin-multiline-output "" }
> myvec[1]/ptr;
> ~~~~~~~~^
> + |
> + __m128
> { dg-end-multiline-output "" } */
>
>
> @@ -31,8 +33,12 @@ int test_2 (void)
> /* { dg-begin-multiline-output "" }
> return (some_function ()
> ~~~~~~~~~~~~~~~~
> + |
> + struct s
> + some_other_function ());
> ^ ~~~~~~~~~~~~~~~~~~~~~~
> + |
> + struct t
> { dg-end-multiline-output "" } */
> }
>
> @@ -46,3 +52,23 @@ int test_3 (struct s param_s, struct t param_t)
> { dg-end-multiline-output "" } */
> /* TODO: ideally we'd underline both params here. */
> }
> +
> +typedef struct s S;
> +typedef struct t T;
> +
> +extern S callee_4a (void);
> +extern T callee_4b (void);
> +
> +int test_4 (void)
> +{
> + return callee_4a () + callee_4b (); /* { dg-error "invalid operands to
> binary \+" } */
> +
> +/* { dg-begin-multiline-output "" }
> + return callee_4a () + callee_4b ();
> + ~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
> + | |
> + | T {aka struct t}
> + S {aka struct s}
> + { dg-end-multiline-output "" } */
> +}
> +
> diff --git a/gcc/testsuite/gcc.dg/cpp/pr66415-1.c
> b/gcc/testsuite/gcc.dg/cpp/pr66415-1.c
> index 515252c..cc4e417 100644
> --- a/gcc/testsuite/gcc.dg/cpp/pr66415-1.c
> +++ b/gcc/testsuite/gcc.dg/cpp/pr66415-1.c
> @@ -11,6 +11,8 @@ fn1 (void)
> /* { dg-begin-multiline-output "" }
> __builtin_printf
> ("xxxxxxxxxxxxxxxxx%dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
> ~^
> + |
> + int
> { dg-end-multiline-output "" } */
>
> }
> diff --git a/gcc/testsuite/gcc.dg/format/diagnostic-ranges.c
> b/gcc/testsuite/gcc.dg/format/diagnostic-ranges.c
> index e56e159..84535f0 100644
> --- a/gcc/testsuite/gcc.dg/format/diagnostic-ranges.c
> +++ b/gcc/testsuite/gcc.dg/format/diagnostic-ranges.c
> @@ -11,6 +11,8 @@ void test_mismatching_types (const char *msg)
> /* { dg-begin-multiline-output "" }
> printf("hello %i", msg);
> ~^ ~~~
> + | |
> + int const char *
> %s
> { dg-end-multiline-output "" } */
>
> @@ -19,6 +21,9 @@ void test_mismatching_types (const char *msg)
> /* { dg-begin-multiline-output "" }
> printf("hello %s", 42);
> ~^ ~~
> + | |
> + | int
> + char *
> %d
> { dg-end-multiline-output "" } */
>
> @@ -26,6 +31,8 @@ void test_mismatching_types (const char *msg)
> /* { dg-begin-multiline-output "" }
> printf("hello %i", (long)0);
> ~^ ~~~~~~~
> + | |
> + int long int
> %li
> { dg-end-multiline-output "" } */
> }
> @@ -37,9 +44,13 @@ void test_multiple_arguments (void)
> /* { dg-begin-multiline-output "" }
> printf ("arg0: %i arg1: %s arg 2: %i",
> ~^
> + |
> + char *
> %d
> 100, 101, 102);
> ~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> }
>
> @@ -50,9 +61,13 @@ void test_multiple_arguments_2 (int i, int j)
> /* { dg-begin-multiline-output "" }
> printf ("arg0: %i arg1: %s arg 2: %i",
> ~^
> + |
> + char *
> %d
> 100, i + j, 102);
> ~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> }
>
> @@ -72,6 +87,8 @@ void multiline_format_string (void) {
> ~~
> "d"
> ~^
> + |
> + int
> { dg-end-multiline-output "" } */
> }
>
> @@ -84,6 +101,8 @@ void test_hex (const char *msg)
> /* { dg-begin-multiline-output "" }
> printf("hello \x25\x69", msg);
> ~~~~^~~~ ~~~
> + | |
> + int const char *
> \x25s
> { dg-end-multiline-output "" } */
> }
> @@ -97,6 +116,8 @@ void test_oct (const char *msg)
> /* { dg-begin-multiline-output "" }
> printf("hello \045\151", msg);
> ~~~~^~~~ ~~~
> + | |
> + int const char *
> \045s
> { dg-end-multiline-output "" } */
> }
> @@ -112,11 +133,15 @@ void test_multiple (const char *msg)
> ^~~~~~~~
> msg);
> ~~~
> + |
> + const char *
> { dg-end-multiline-output "" } */
>
> /* { dg-begin-multiline-output "" }
> printf("prefix" "\x25" "\151" "suffix",
> ~~~~~~~~^~~~
> + |
> + int
> \x25" "s
> { dg-end-multiline-output "" } */
> }
> @@ -127,6 +152,8 @@ void test_u8 (const char *msg)
> /* { dg-begin-multiline-output "" }
> printf(u8"hello %i", msg);
> ~^ ~~~
> + | |
> + int const char *
> %s
> { dg-end-multiline-output "" } */
> }
> @@ -137,6 +164,8 @@ void test_param (long long_i, long long_j)
> /* { dg-begin-multiline-output "" }
> printf ("foo %s bar", long_i + long_j);
> ~^ ~~~~~~~~~~~~~~~
> + | |
> + char * long int
> %ld
> { dg-end-multiline-output "" } */
> }
> @@ -147,6 +176,8 @@ void test_field_width_specifier (long l, int i1, int
> i2)
> /* { dg-begin-multiline-output "" }
> printf (" %*.*d ", l, i1, i2);
> ~^~~~ ~
> + | |
> + int long int
> { dg-end-multiline-output "" } */
> }
>
> @@ -158,12 +189,16 @@ void test_field_width_specifier_2 (char *d, long foo,
> long bar)
> /* { dg-begin-multiline-output "" }
> __builtin_sprintf (d, " %*ld ", foo, foo);
> ~^~~ ~~~
> + | |
> + int long int
> { dg-end-multiline-output "" } */
>
> __builtin_sprintf (d, " %*ld ", foo + bar, foo); /* { dg-warning "28:
> field width specifier '\\*' expects argument of type 'int', but argument 3
> has type 'long int'" } */
> /* { dg-begin-multiline-output "" }
> __builtin_sprintf (d, " %*ld ", foo + bar, foo);
> ~^~~ ~~~~~~~~~
> + | |
> + int long int
> { dg-end-multiline-output "" } */
> }
>
> @@ -173,12 +208,16 @@ void test_field_precision_specifier (char *d, long
> foo, long bar)
> /* { dg-begin-multiline-output "" }
> __builtin_sprintf (d, " %.*ld ", foo, foo);
> ~~^~~ ~~~
> + | |
> + int long int
> { dg-end-multiline-output "" } */
>
> __builtin_sprintf (d, " %.*ld ", foo + bar, foo); /* { dg-warning "29:
> field precision specifier '\\.\\*' expects argument of type 'int', but
> argument 3 has type 'long int'" } */
> /* { dg-begin-multiline-output "" }
> __builtin_sprintf (d, " %.*ld ", foo + bar, foo);
> ~~^~~ ~~~~~~~~~
> + | |
> + int long int
> { dg-end-multiline-output "" } */
> }
>
> @@ -241,10 +280,14 @@ void test_macro (const char *msg)
> /* { dg-begin-multiline-output "" }
> printf("hello " INT_FMT " world", msg);
> ^~~~~~~~ ~~~
> + |
> + const char *
> { dg-end-multiline-output "" } */
> /* { dg-begin-multiline-output "" }
> #define INT_FMT "%i"
> ~^
> + |
> + int
> %s
> { dg-end-multiline-output "" } */
> #undef INT_FMT
> @@ -257,10 +300,14 @@ void test_macro_2 (const char *msg)
> /* { dg-begin-multiline-output "" }
> printf("hello %" PRIu32 " world", msg);
> ^~~~~~~~~ ~~~
> + |
> + const char *
> { dg-end-multiline-output "" } */
> /* { dg-begin-multiline-output "" }
> #define PRIu32 "u"
> ^
> + |
> + unsigned int
> { dg-end-multiline-output "" } */
> #undef PRIu32
> }
> @@ -295,6 +342,8 @@ void test_macro_4 (const char *msg)
> /* { dg-begin-multiline-output "" }
> #define FMT_STRING "hello %i world"
> ~^
> + |
> + int
> %s
> { dg-end-multiline-output "" } */
> #undef FMT_STRING
> @@ -307,10 +356,14 @@ void test_non_contiguous_strings (void)
> /* { dg-begin-multiline-output "" }
> __builtin_printf(" %" "d ", 0.5);
> ^~~~ ~~~
> + |
> + double
> { dg-end-multiline-output "" } */
> /* { dg-begin-multiline-output "" }
> __builtin_printf(" %" "d ", 0.5);
> ~~~~^
> + |
> + int
> %" "f
> { dg-end-multiline-output "" } */
> }
> @@ -324,5 +377,7 @@ void test_const_arrays (void)
> /* { dg-begin-multiline-output "" }
> __builtin_printf(a, 0.5);
> ^ ~~~
> + |
> + double
> { dg-end-multiline-output "" } */
> }
> diff --git a/gcc/testsuite/gcc.dg/format/pr72858.c
> b/gcc/testsuite/gcc.dg/format/pr72858.c
> index b8c5829..7726094 100644
> --- a/gcc/testsuite/gcc.dg/format/pr72858.c
> +++ b/gcc/testsuite/gcc.dg/format/pr72858.c
> @@ -28,12 +28,18 @@ test_x (char *d,
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8x ", lexpr);
> ~~~^ ~~~~~
> + | |
> + | long int
> + unsigned int
> %-8lx
> { dg-end-multiline-output "" } */
> sprintf (d, " %-8x ", ulexpr); /* { dg-warning "20: format '%x' expects
> argument of type 'unsigned int', but argument 3 has type 'long unsigned
> int'" } */
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8x ", ulexpr);
> ~~~^ ~~~~~~
> + | |
> + | long unsigned int
> + unsigned int
> %-8lx
> { dg-end-multiline-output "" } */
>
> @@ -41,12 +47,18 @@ test_x (char *d,
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8x ", llexpr);
> ~~~^ ~~~~~~
> + | |
> + | long long int
> + unsigned int
> %-8llx
> { dg-end-multiline-output "" } */
> sprintf (d, " %-8x ", ullexpr); /* { dg-warning "20: format '%x' expects
> argument of type 'unsigned int', but argument 3 has type 'long long unsigned
> int'" } */
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8x ", ullexpr);
> ~~~^ ~~~~~~~
> + | |
> + | long long unsigned int
> + unsigned int
> %-8llx
> { dg-end-multiline-output "" } */
>
> @@ -56,18 +68,27 @@ test_x (char *d,
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8x ", fexpr);
> ~~~^ ~~~~~
> + | |
> + | double
> + unsigned int
> %-8f
> { dg-end-multiline-output "" } */
> sprintf (d, " %-8x ", dexpr); /* { dg-warning "20: format '%x' expects
> argument of type 'unsigned int', but argument 3 has type 'double'" } */
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8x ", dexpr);
> ~~~^ ~~~~~
> + | |
> + | double
> + unsigned int
> %-8f
> { dg-end-multiline-output "" } */
> sprintf (d, " %-8x ", ldexpr); /* { dg-warning "20: format '%x' expects
> argument of type 'unsigned int', but argument 3 has type 'long double'" }
> */
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8x ", ldexpr);
> ~~~^ ~~~~~~
> + | |
> + | long double
> + unsigned int
> %-8Lf
> { dg-end-multiline-output "" } */
>
> @@ -76,6 +97,9 @@ test_x (char *d,
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8x ", ptr);
> ~~~^ ~~~
> + | |
> + | void *
> + unsigned int
> %-8p
> { dg-end-multiline-output "" } */
>
> @@ -86,6 +110,9 @@ test_x (char *d,
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8x ", s);
> ~~~^ ~
> + | |
> + | struct s
> + unsigned int
> { dg-end-multiline-output "" } */
> }
>
> @@ -105,12 +132,18 @@ test_lx (char *d,
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8lx ", iexpr);
> ~~~~^ ~~~~~
> + | |
> + | int
> + long unsigned int
> %-8x
> { dg-end-multiline-output "" } */
> sprintf (d, " %-8lx ", uiexpr); /* { dg-warning "21: format '%lx' expects
> argument of type 'long unsigned int', but argument 3 has type 'unsigned
> int'" } */
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8lx ", uiexpr);
> ~~~~^ ~~~~~~
> + | |
> + | unsigned int
> + long unsigned int
> %-8x
> { dg-end-multiline-output "" } */
>
> @@ -121,12 +154,18 @@ test_lx (char *d,
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8lx ", llexpr);
> ~~~~^ ~~~~~~
> + | |
> + | long long int
> + long unsigned int
> %-8llx
> { dg-end-multiline-output "" } */
> sprintf (d, " %-8lx ", ullexpr); /* { dg-warning "21: format '%lx'
> expects argument of type 'long unsigned int', but argument 3 has type 'long
> long unsigned int'" } */
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8lx ", ullexpr);
> ~~~~^ ~~~~~~~
> + | |
> + | long long unsigned int
> + long unsigned int
> %-8llx
> { dg-end-multiline-output "" } */
>
> @@ -136,18 +175,27 @@ test_lx (char *d,
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8lx ", fexpr);
> ~~~~^ ~~~~~
> + | |
> + | double
> + long unsigned int
> %-8f
> { dg-end-multiline-output "" } */
> sprintf (d, " %-8lx ", dexpr); /* { dg-warning "21: format '%lx' expects
> argument of type 'long unsigned int', but argument 3 has type 'double'" }
> */
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8lx ", dexpr);
> ~~~~^ ~~~~~
> + | |
> + | double
> + long unsigned int
> %-8f
> { dg-end-multiline-output "" } */
> sprintf (d, " %-8lx ", ldexpr); /* { dg-warning "21: format '%lx' expects
> argument of type 'long unsigned int', but argument 3 has type 'long double'"
> } */
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8lx ", ldexpr);
> ~~~~^ ~~~~~~
> + | |
> + | long double
> + long unsigned int
> %-8Lf
> { dg-end-multiline-output "" } */
> }
> @@ -170,12 +218,18 @@ test_o (char *d,
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8o ", lexpr);
> ~~~^ ~~~~~
> + | |
> + | long int
> + unsigned int
> %-8lo
> { dg-end-multiline-output "" } */
> sprintf (d, " %-8o ", ulexpr); /* { dg-warning "20: format '%o' expects
> argument of type 'unsigned int', but argument 3 has type 'long unsigned
> int'" } */
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8o ", ulexpr);
> ~~~^ ~~~~~~
> + | |
> + | long unsigned int
> + unsigned int
> %-8lo
> { dg-end-multiline-output "" } */
>
> @@ -183,12 +237,18 @@ test_o (char *d,
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8o ", llexpr);
> ~~~^ ~~~~~~
> + | |
> + | long long int
> + unsigned int
> %-8llo
> { dg-end-multiline-output "" } */
> sprintf (d, " %-8o ", ullexpr); /* { dg-warning "20: format '%o' expects
> argument of type 'unsigned int', but argument 3 has type 'long long unsigned
> int'" } */
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8o ", ullexpr);
> ~~~^ ~~~~~~~
> + | |
> + | long long unsigned int
> + unsigned int
> %-8llo
> { dg-end-multiline-output "" } */
> }
> @@ -208,12 +268,18 @@ test_lo (char *d,
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8lo ", iexpr);
> ~~~~^ ~~~~~
> + | |
> + | int
> + long unsigned int
> %-8o
> { dg-end-multiline-output "" } */
> sprintf (d, " %-8lo ", uiexpr); /* { dg-warning "21: format '%lo' expects
> argument of type 'long unsigned int', but argument 3 has type 'unsigned
> int'" } */
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8lo ", uiexpr);
> ~~~~^ ~~~~~~
> + | |
> + | unsigned int
> + long unsigned int
> %-8o
> { dg-end-multiline-output "" } */
>
> @@ -224,12 +290,18 @@ test_lo (char *d,
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8lo ", llexpr);
> ~~~~^ ~~~~~~
> + | |
> + | long long int
> + long unsigned int
> %-8llo
> { dg-end-multiline-output "" } */
> sprintf (d, " %-8lo ", ullexpr); /* { dg-warning "21: format '%lo'
> expects argument of type 'long unsigned int', but argument 3 has type 'long
> long unsigned int'" } */
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8lo ", ullexpr);
> ~~~~^ ~~~~~~~
> + | |
> + | long long unsigned int
> + long unsigned int
> %-8llo
> { dg-end-multiline-output "" } */
> }
> @@ -246,6 +318,9 @@ test_e (char *d, int iexpr, float fexpr, double dexpr,
> long double ldexpr)
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8e ", iexpr);
> ~~~^ ~~~~~
> + | |
> + | int
> + double
> %-8d
> { dg-end-multiline-output "" } */
>
> @@ -257,6 +332,9 @@ test_e (char *d, int iexpr, float fexpr, double dexpr,
> long double ldexpr)
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8e ", ldexpr);
> ~~~^ ~~~~~~
> + | |
> + | long double
> + double
> %-8Le
> { dg-end-multiline-output "" } */
> }
> @@ -273,6 +351,9 @@ test_Le (char *d, int iexpr, float fexpr, double dexpr,
> long double ldexpr)
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8Le ", iexpr);
> ~~~~^ ~~~~~
> + | |
> + | int
> + long double
> %-8d
> { dg-end-multiline-output "" } */
>
> @@ -282,6 +363,9 @@ test_Le (char *d, int iexpr, float fexpr, double dexpr,
> long double ldexpr)
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8Le ", fexpr);
> ~~~~^ ~~~~~
> + | |
> + | double
> + long double
> %-8e
> { dg-end-multiline-output "" } */
>
> @@ -289,6 +373,9 @@ test_Le (char *d, int iexpr, float fexpr, double dexpr,
> long double ldexpr)
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8Le ", dexpr);
> ~~~~^ ~~~~~
> + | |
> + | double
> + long double
> %-8e
> { dg-end-multiline-output "" } */
>
> @@ -307,6 +394,9 @@ test_E (char *d, int iexpr, float fexpr, double dexpr,
> long double ldexpr)
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8E ", iexpr);
> ~~~^ ~~~~~
> + | |
> + | int
> + double
> %-8d
> { dg-end-multiline-output "" } */
>
> @@ -318,6 +408,9 @@ test_E (char *d, int iexpr, float fexpr, double dexpr,
> long double ldexpr)
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8E ", ldexpr);
> ~~~^ ~~~~~~
> + | |
> + | long double
> + double
> %-8LE
> { dg-end-multiline-output "" } */
> }
> @@ -334,6 +427,9 @@ test_LE (char *d, int iexpr, float fexpr, double dexpr,
> long double ldexpr)
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8LE ", iexpr);
> ~~~~^ ~~~~~
> + | |
> + | int
> + long double
> %-8d
> { dg-end-multiline-output "" } */
>
> @@ -341,6 +437,9 @@ test_LE (char *d, int iexpr, float fexpr, double dexpr,
> long double ldexpr)
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8LE ", fexpr);
> ~~~~^ ~~~~~
> + | |
> + | double
> + long double
> %-8E
> { dg-end-multiline-output "" } */
>
> @@ -348,6 +447,9 @@ test_LE (char *d, int iexpr, float fexpr, double dexpr,
> long double ldexpr)
> /* { dg-begin-multiline-output "" }
> sprintf (d, " %-8LE ", dexpr);
> ~~~~^ ~~~~~
> + | |
> + | double
> + long double
> %-8E
> { dg-end-multiline-output "" } */
>
> @@ -367,18 +469,24 @@ test_everything (char *d, long lexpr)
> /* { dg-begin-multiline-output "" }
> sprintf (d, "before %-+*.*lld after", lexpr, lexpr, lexpr);
> ~~~^~~~~~ ~~~~~
> + | |
> + int long int
> { dg-end-multiline-output "" } */
>
> /* { dg-warning "28: field precision specifier '\\.\\*' expects argument
> of type 'int', but argument 4 has type 'long int'" "" { target *-*-* }
> test_everything_sprintf } */
> /* { dg-begin-multiline-output "" }
> sprintf (d, "before %-+*.*lld after", lexpr, lexpr, lexpr);
> ~~~~~^~~~ ~~~~~
> + | |
> + int long int
> { dg-end-multiline-output "" } */
>
> /* { dg-warning "31: format '%lld' expects argument of type 'long long
> int', but argument 5 has type 'long int'" "" { target *-*-* }
> test_everything_sprintf } */
> /* { dg-begin-multiline-output "" }
> sprintf (d, "before %-+*.*lld after", lexpr, lexpr, lexpr);
> ~~~~~~~~^ ~~~~~
> + | |
> + long long int long int
> %-+*.*ld
> { dg-end-multiline-output "" } */
> }
> diff --git a/gcc/testsuite/gcc.dg/format/pr78498.c
> b/gcc/testsuite/gcc.dg/format/pr78498.c
> index 4b53a68..b911b04 100644
> --- a/gcc/testsuite/gcc.dg/format/pr78498.c
> +++ b/gcc/testsuite/gcc.dg/format/pr78498.c
> @@ -7,6 +7,8 @@ void f (void)
> /* { dg-begin-multiline-output "" }
> __builtin_printf ("%i", "");
> ~^ ~~
> + | |
> + int char *
> %s
> { dg-end-multiline-output "" } */
> }
> diff --git a/gcc/testsuite/gcc.dg/param-type-mismatch.c
> b/gcc/testsuite/gcc.dg/param-type-mismatch.c
> index 9498a74..9e654a9 100644
> --- a/gcc/testsuite/gcc.dg/param-type-mismatch.c
> +++ b/gcc/testsuite/gcc.dg/param-type-mismatch.c
> @@ -1,4 +1,4 @@
> -/* { dg-options "-fdiagnostics-show-caret" } */
> +/* { dg-options "-fdiagnostics-show-caret -Wpointer-sign" } */
>
> /* A collection of calls where argument 2 is of the wrong type. */
>
> @@ -12,6 +12,8 @@ int test_1 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_1 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> /* { dg-message "expected 'const char \\*' but argument is of type 'int'"
> "" { target *-*-* } callee_1 } */
> /* { dg-begin-multiline-output "" }
> @@ -30,6 +32,8 @@ int test_2 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_2 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> /* { dg-message "expected 'const char \\*' but argument is of type 'int'"
> "" { target *-*-* } callee_2 } */
> /* { dg-begin-multiline-output "" }
> @@ -51,6 +55,8 @@ int test_3 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_3 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> /* { dg-message "expected 'const char \\*' but argument is of type 'int'"
> "" { target *-*-* } callee_3 } */
> /* { dg-begin-multiline-output "" }
> @@ -69,6 +75,8 @@ int test_4 (int first, const char *second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_4 (first, second, third);
> ^~~~~~
> + |
> + const char *
> { dg-end-multiline-output "" } */
> /* { dg-message "expected 'float' but argument is of type 'const char
> \\*'" "" { target *-*-* } callee_4 } */
> /* { dg-begin-multiline-output "" }
> @@ -87,6 +95,8 @@ int test_5 (int first, const char *second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_5 (first, second, third);
> ^~~~~~
> + |
> + const char *
> { dg-end-multiline-output "" } */
> /* { dg-message "expected 'float' but argument is of type 'const char
> \\*'" "" { target *-*-* } callee_5 } */
> /* { dg-begin-multiline-output "" }
> @@ -105,6 +115,8 @@ int test_6 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_6 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> /* { dg-message " expected 'int \\(\\*\\)\\(int, int\\)' but argument is
> of type 'int'" "" { target *-*-* } callee_6 } */
> /* { dg-begin-multiline-output "" }
> @@ -123,6 +135,8 @@ int test_7 (int first, int second, float third)
> /* { dg-begin-multiline-output "" }
> return callee_7 (first, second, third);
> ^~~~~~
> + |
> + int
> { dg-end-multiline-output "" } */
> /* { dg-message " expected 'int \\(\\*\\)\\(int, int\\)' but argument is
> of type 'int'" "" { target *-*-* } callee_7 } */
> /* { dg-begin-multiline-output "" }
> @@ -130,3 +144,43 @@ int test_7 (int first, int second, float third)
> ^~~~~~~~~~~~~~~~~
> { dg-end-multiline-output "" } */
> }
> +
> +/* -Wincompatible-pointer-types for a parameter. */
> +
> +extern int callee_8 (int one, float *two, float (three)); /* { dg-line
> callee_8 } */
> +
> +int test_8 (int first, int *second, float third)
> +{
> + return callee_8 (first, second, third); /* { dg-warning "passing argument
> 2 of 'callee_8' from incompatible pointer type" } */
> + /* { dg-begin-multiline-output "" }
> + return callee_8 (first, second, third);
> + ^~~~~~
> + |
> + int *
> + { dg-end-multiline-output "" } */
> + /* { dg-message "expected 'float \\*' but argument is of type 'int \\*'"
> "" { target *-*-* } callee_8 } */
> + /* { dg-begin-multiline-output "" }
> + extern int callee_8 (int one, float *two, float (three));
> + ~~~~~~~^~~
> + { dg-end-multiline-output "" } */
> +}
> +
> +/* -Wpointer-sign for a parameter. */
> +
> +extern int callee_9 (int one, int *two, float (three)); /* { dg-line
> callee_9 } */
> +
> +int test_9 (int first, unsigned int *second, float third)
> +{
> + return callee_9 (first, second, third); /* { dg-warning "pointer targets
> in passing argument 2 of 'callee_9' differ in signedness" } */
> + /* { dg-begin-multiline-output "" }
> + return callee_9 (first, second, third);
> + ^~~~~~
> + |
> + unsigned int *
> + { dg-end-multiline-output "" } */
> + /* { dg-message "expected 'int \\*' but argument is of type 'unsigned int
> \\*'" "" { target *-*-* } callee_9 } */
> + /* { dg-begin-multiline-output "" }
> + extern int callee_9 (int one, int *two, float (three));
> + ~~~~~^~~
> + { dg-end-multiline-output "" } */
> +}
> diff --git
> a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw-line-numbers.c
> b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw-line-numbers.c
> index 66a2faa..89213eb 100644
> ---
> a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw-line-numbers.c
> +++
> b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw-line-numbers.c
> @@ -31,6 +31,8 @@ void test_multiline (void)
> | ~~~~~~~~~~~~~~~~~
> 27 | + second_function ());
> | ^ ~~~~~~~~~~~~~~~~~~
> + | |
> + | label
> { dg-end-multiline-output "" } */
> #endif
> }
> @@ -43,8 +45,10 @@ void test_very_wide_line (void)
> | 0 0 0 0 0 0 1
>
> | 4 5 6 7 8 9 0
>
> |
> 0123456789012345678901234567890123456789012345678901234567890123456789
> -41 | float f = foo * bar;
> +43 | float f = foo * bar;
> | ~~~~^~~~~
> + | |
> + | label
> | bar * foo
> { dg-end-multiline-output "" } */
> #endif
> @@ -58,7 +62,7 @@ void test_fixit_insert (void)
> #if 0
> int a[2][2] = { 0, 1 , 2, 3 }; /* { dg-warning "insertion hints" } */
> /* { dg-begin-multiline-output "" }
> -59 | int a[2][2] = { 0, 1 , 2, 3 };
> +63 | int a[2][2] = { 0, 1 , 2, 3 };
> | ^~~~
> | { }
> { dg-end-multiline-output "" } */
> @@ -72,7 +76,7 @@ void test_fixit_remove (void)
> #if 0
> int a;; /* { dg-warning "example of a removal hint" } */
> /* { dg-begin-multiline-output "" }
> -73 | int a;;
> +77 | int a;;
> | ^
> | -
> { dg-end-multiline-output "" } */
> @@ -86,7 +90,7 @@ void test_fixit_replace (void)
> #if 0
> gtk_widget_showall (dlg); /* { dg-warning "example of a replacement hint"
> } */
> /* { dg-begin-multiline-output "" }
> -87 | gtk_widget_showall (dlg);
> +91 | gtk_widget_showall (dlg);
> | ^~~~~~~~~~~~~~~~~~
> | gtk_widget_show_all
> { dg-end-multiline-output "" } */
> @@ -108,7 +112,7 @@ void test_fixit_insert_newline (void)
> }
> /* { dg-begin-multiline-output "" }
> |+ break;
> -106 | case 'b':
> +110 | case 'b':
> | ^~~~~~~~
> { dg-end-multiline-output "" } */
> #endif
> diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
> b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
> index 513c0af..bdfa420 100644
> --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
> +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
> @@ -44,6 +44,8 @@ void test_multiline (void)
> ~~~~~~~~~~~~~~~~~
> + second_function ());
> ^ ~~~~~~~~~~~~~~~~~~
> + |
> + label
> { dg-end-multiline-output "" } */
> #endif
> }
> @@ -66,6 +68,8 @@ void test_many_lines (void)
> /* { dg-begin-multiline-output "" }
> x = (first_function_with_a_very_long_name (lorem, ipsum, dolor, sit,
> amet,
>
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + |
> + label 1
> consectetur, adipiscing,
> elit,
>
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> sed, eiusmod, tempor,
> @@ -76,6 +80,9 @@ void test_many_lines (void)
> ~~~~~~~~~~~~~~~~~~~~~~
> + second_function_with_a_very_long_name (lorem, ipsum, dolor, sit,
> ^
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + | |
> + | label 2
> + label 0
> amet, consectetur,
> ~~~~~~~~~~~~~~~~~~
> adipiscing, elit, sed,
> @@ -115,13 +122,32 @@ void test_caret_within_proper_range (void)
> void test_very_wide_line (void)
> {
> #if 0
> -
> float f = foo * bar; /* { dg-warning "95: test" } */
> + float x
> = foo * bar; /* { dg-warning "95: test" } */
> /* { dg-begin-multiline-output "" }
> 0 0 0 0 0 0 1
> 4 5 6 7 8 9 0
> 6789012345678901234567890123456789012345678901234567890123456789012345
> - float f = foo * bar;
> + x = foo * bar;
> + ~ ~~~~^~~~~
> + | |
> + label 1 label 0
> + bar * foo
> + { dg-end-multiline-output "" } */
> +#endif
> +}
> +
> +void test_very_wide_line_2 (void)
> +{
> +#if 0
> + float x
> = foo * bar; /* { dg-warning "95: test" } */
> +/* { dg-begin-multiline-output "" }
> + 0 0 0 0 0 0 1
> + 4 5 6 7 8 9 0
> + 6789012345678901234567890123456789012345678901234567890123456789012345
> + = foo * bar;
> ~~~~^~~~~
> + |
> + label 0
> bar * foo
> { dg-end-multiline-output "" } */
> #endif
> @@ -226,27 +252,69 @@ void test_many_nested_locations (void)
> ^
> Lorem ipsum dolor sit amet, consectetur adipiscing elit,
> ^~~~~ ^~~~~ ^~~~~ ^~~ ^~~~ ^~~~~~~~~~~ ^~~~~~~~~~ ^~~~
> + | | | | | | | |
> + | | | | label label label label
> + label label label label
> LOREM IPSUM DOLOR SIT AMET CONSECTETUR ADIPISCING ELIT
> sed do eiusmod tempor incididunt ut labore et dolore magna
> ^~~ ^~ ^~~~~~~ ^~~~~~ ^~~~~~~~~~ ^~ ^~~~~~ ^~ ^~~~~~ ^~~~~
> + | | | | | | | | | |
> + | | | | | | | | label label
> + | | | | | | label label
> + | | label label label label
> + | label
> + label
> SED DO EIUSMOD TEMPOR INCIDIDUNT UT LABORE ET DOLORE MAGNA
> aliqua. Ut enim ad minim veniam, quis nostrud exercitation
> ^~~~~~ ^~ ^~~~ ^~ ^~~~~ ^~~~~~ ^~~~ ^~~~~~~ ^~~~~~~~~~~~
> + | | | | | | | | |
> + | | | | | | | label label
> + | | | | label label label
> + | | | label
> + | | label
> + label label
> ALIQUA UT ENIM AD MINIM VENIAM QUIS NOSTRUD EXERCITATION
> ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
> ^~~~~~~ ^~~~~~~ ^~~~ ^~ ^~~~~~~ ^~ ^~ ^~~~~~~ ^~~~~~~~~ ^~~~
> + | | | | | | | | | |
> + | | | | | | | label label label
> + | | | | | | label
> + | | | | label label
> + | | | label
> + label label label
> ULLAMCO LABORIS NISI UT ALIQUIP EX EA COMMODO CONSEQUAT DUIS
> aute irure dolor in reprehenderit in voluptate velit esse cillum
> ^~~~ ^~~~~ ^~~~~ ^~ ^~~~~~~~~~~~~ ^~ ^~~~~~~~~ ^~~~~ ^~~~ ^~~~~~
> + | | | | | | | | | |
> + | | | | | | | | | label
> + | | | | | | label label label
> + | | | | label label
> + | label label label
> + label
> AUTE IRURE DOLOR IN REPREHENDERIT IN VOLUPTATE VELIT ESSE CILLUM
> dolore eu fugiat nulla pariatur. Excepteur sint occaecat
> ^~~~~~ ^~ ^~~~~~ ^~~~~ ^~~~~~~~ ^~~~~~~~~ ^~~~ ^~~~~~~~
> + | | | | | | | |
> + | | | | | | | label
> + | | label label label label label
> + label label
> DOLORE EU FUGIAT NULLA PARIATUR EXCEPTEUR SINT OCCAECAT
> cupidatat non proident, sunt in culpa qui officia deserunt
> ^~~~~~~~~ ^~~ ^~~~~~~~ ^~~~ ^~ ^~~~~ ^~~ ^~~~~~~ ^~~~~~~~
> + | | | | | | | | |
> + | | | | | | | label label
> + | | | | | label label
> + | | | | label
> + | | label label
> + label label
> CUPIDATAT NON PROIDENT SUNT IN CULPA QUI OFFICIA DESERUNT
> mollit anim id est laborum.
> ^~~~~~ ^~~~ ^~ ^~~ ^~~~~~~
> + | | | | |
> + | | | | label
> + | | | label
> + | | label
> + label label
> MOLLIT ANIM ID EST LABORUM
> { dg-end-multiline-output "" } */
> }
> diff --git
> a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color-line-numbers.c
> b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color-line-numbers.c
> index a80b6de..0453c52 100644
> ---
> a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color-line-numbers.c
> +++
> b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color-line-numbers.c
> @@ -19,6 +19,8 @@ void test_multiline (void)
> | [32m [K~~~~~~~~~~~~~~~~~ [m [K
> 15 | [01;35m [K+ [m [K [34m [Ksecond_function () [m [K);
> | [01;35m [K^ [m [K [34m [K~~~~~~~~~~~~~~~~~~ [m [K
> + | [01;35m [K| [m [K
> + | [01;35m [Klabel [m [K
> { dg-end-multiline-output "" } */
> #endif
> }
> diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
> b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
> index 4cc406d..094bc65 100644
> --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
> +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
> @@ -44,6 +44,8 @@ void test_multiline (void)
> [32m [K~~~~~~~~~~~~~~~~~ [m [K
> [01;35m [K+ [m [K [34m [Ksecond_function () [m [K);
> [01;35m [K^ [m [K [34m [K~~~~~~~~~~~~~~~~~~ [m [K
> + [01;35m [K| [m [K
> + [01;35m [Klabel [m [K
> { dg-end-multiline-output "" } */
> #endif
> }
> @@ -66,6 +68,8 @@ void test_many_lines (void)
> /* { dg-begin-multiline-output "" }
> x = ( [32m [Kfirst_function_with_a_very_long_name (lorem, ipsum, dolor,
> sit, amet, [m [K
> [32m
> [K~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [m
> [K
> + [32m [K| [m [K
> + [32m [Klabel 1 [m [K
> [32m [K consectetur,
> adipiscing, elit, [m [K
> [32m
> [K~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [m [K
> [32m [K sed, eiusmod, tempor,
> [m [K
> @@ -76,6 +80,9 @@ void test_many_lines (void)
> [32m [K~~~~~~~~~~~~~~~~~~~~~~
> [m [K
> [01;35m [K+ [m [K [34m [Ksecond_function_with_a_very_long_name
> (lorem, ipsum, dolor, sit,
> [01;35m [K^ [m [K [34m
> [K~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> [m [K
> + [01;35m [K| [m [K [34m [K| [m [K
> + [01;35m [K| [m [K [34m [Klabel 2 [m [K
> + [01;35m [Klabel 0 [m [K
> [34m [K amet, consectetur,
> [m [K
> [34m [K~~~~~~~~~~~~~~~~~~
> [m [K
> [34m [K adipiscing, elit,
> sed, [m [K
> @@ -115,13 +122,15 @@ void test_caret_within_proper_range (void)
> void test_very_wide_line (void)
> {
> #if 0
> -
> float f = foo * bar; /* { dg-warning "95: test" } */
> + float x
> = foo * bar; /* { dg-warning "95: test" } */
> /* { dg-begin-multiline-output "" }
> 0 0 0 0 0 0 1
> 4 5 6 7 8 9 0
> 6789012345678901234567890123456789012345678901234567890123456789012345
> - float f = [01;35m [Kfoo *
> bar [m [K;
> - [01;35m
> [K~~~~^~~~~ [m [K
> + [32m [Kx [m [K =
> [01;35m [Kfoo * bar [m [K;
> + [32m [K~ [m [K
> [01;35m [K~~~~^~~~~ [m [K
> + [32m [K| [m [K
> [01;35m [K| [m [K
> + [32m [Klabel 1 [m [K
> [01;35m [Klabel 0 [m [K
> [32m [Kbar * foo
> [m [K
> { dg-end-multiline-output "" } */
> #endif
> diff --git
> a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-no-labels.c
> b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-no-labels.c
> new file mode 100644
> index 0000000..4c06368
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-no-labels.c
> @@ -0,0 +1,27 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O -fdiagnostics-show-caret -fno-diagnostics-show-labels"
> } */
> +
> +/* Verify that -fno-diagnostics-show-labels works. */
> +
> +/* This is a collection of unittests for diagnostic_show_locus;
> + see the overview in diagnostic_plugin_test_show_locus.c.
> +
> + In particular, note the discussion of why we need a very long line
> here:
> +01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
> + and that we can't use macros in this file. */
> +
> +void test_multiline (void)
> +{
> +#if 0
> + x = (first_function ()
> + + second_function ()); /* { dg-warning "test" } */
> +
> + /* This shouldn't have a label. */
> + /* { dg-begin-multiline-output "" }
> + x = (first_function ()
> + ~~~~~~~~~~~~~~~~~
> + + second_function ());
> + ^ ~~~~~~~~~~~~~~~~~~
> + { dg-end-multiline-output "" } */
> +#endif
> +}
> diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.c
> b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.c
> index 0bdd877..71e6740 100644
> --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.c
> +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.c
> @@ -41,7 +41,7 @@ show_tree (tree node)
> return;
>
> gcc_rich_location richloc (EXPR_LOCATION (node));
> - richloc.add_expr (node);
> + richloc.add_expr (node, NULL);
>
> if (richloc.get_num_locations () < 2)
> {
> diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
> b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
> index 1d340aa..3d78538 100644
> --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
> +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
> @@ -145,9 +145,10 @@ custom_diagnostic_finalizer (diagnostic_context
> *context,
>
> static void
> add_range (rich_location *richloc, location_t start, location_t finish,
> - bool show_caret_p)
> + bool show_caret_p, const range_label *label = NULL)
> {
> - richloc->add_range (make_location (start, start, finish), show_caret_p);
> + richloc->add_range (make_location (start, start, finish), show_caret_p,
> + label);
> }
>
> /* Exercise the diagnostic machinery to emit various warnings,
> @@ -192,7 +193,8 @@ test_show_locus (function *fun)
> if (0 == strcmp (fnname, "test_multiline"))
> {
> const int line = fnstart_line + 2;
> - rich_location richloc (line_table, get_loc (line + 1, 7));
> + text_range_label label ("label");
> + rich_location richloc (line_table, get_loc (line + 1, 7), &label);
> add_range (&richloc, get_loc (line, 7), get_loc (line, 23), false);
> add_range (&richloc, get_loc (line + 1, 9), get_loc (line + 1, 26),
> false);
> @@ -202,10 +204,14 @@ test_show_locus (function *fun)
> if (0 == strcmp (fnname, "test_many_lines"))
> {
> const int line = fnstart_line + 2;
> - rich_location richloc (line_table, get_loc (line + 5, 7));
> - add_range (&richloc, get_loc (line, 7), get_loc (line + 4, 65),
> false);
> + text_range_label label0 ("label 0");
> + text_range_label label1 ("label 1");
> + text_range_label label2 ("label 2");
> + rich_location richloc (line_table, get_loc (line + 5, 7), &label0);
> + add_range (&richloc, get_loc (line, 7), get_loc (line + 4, 65),
> false,
> + &label1);
> add_range (&richloc, get_loc (line + 5, 9), get_loc (line + 10, 61),
> - false);
> + false, &label2);
> warning_at (&richloc, 0, "test");
> }
>
> @@ -231,16 +237,40 @@ test_show_locus (function *fun)
> }
>
> /* Example of a very wide line, where the information of interest
> - is beyond the width of the terminal (hardcoded above). */
> + is beyond the width of the terminal (hardcoded above), with
> + a secondary location that exactly fits on the left-margin. */
> if (0 == strcmp (fnname, "test_very_wide_line"))
> {
> const int line = fnstart_line + 2;
> global_dc->show_ruler_p = true;
> + text_range_label label0 ("label 0");
> + text_range_label label1 ("label 1");
> + rich_location richloc (line_table,
> + make_location (get_loc (line, 94),
> + get_loc (line, 90),
> + get_loc (line, 98)),
> + &label0);
> + richloc.add_range (get_loc (line, 35), false, &label1);
> + richloc.add_fixit_replace ("bar * foo");
> + warning_at (&richloc, 0, "test");
> + global_dc->show_ruler_p = false;
> + }
> +
> + /* Likewise, but with a secondary location that's immediately before
> + the left margin; the location and label should be gracefully dropped.
> */
> + if (0 == strcmp (fnname, "test_very_wide_line_2"))
> + {
> + const int line = fnstart_line + 2;
> + global_dc->show_ruler_p = true;
> + text_range_label label0 ("label 0");
> + text_range_label label1 ("label 1");
> rich_location richloc (line_table,
> make_location (get_loc (line, 94),
> get_loc (line, 90),
> - get_loc (line, 98)));
> + get_loc (line, 98)),
> + &label0);
> richloc.add_fixit_replace ("bar * foo");
> + richloc.add_range (get_loc (line, 34), false, &label1);
> warning_at (&richloc, 0, "test");
> global_dc->show_ruler_p = false;
> }
> @@ -391,13 +421,14 @@ test_show_locus (function *fun)
>
> /* Example of many locations and many fixits.
> Underline (separately) every word in a comment, and convert them
> - to upper case. */
> + to upper case. Give all of the ranges labels (sharing one label).
> */
> if (0 == strcmp (fnname, "test_many_nested_locations"))
> {
> const char *file = LOCATION_FILE (fnstart);
> const int start_line = fnstart_line + 2;
> const int finish_line = start_line + 7;
> location_t loc = get_loc (start_line - 1, 2);
> + text_range_label label ("label");
> rich_location richloc (line_table, loc);
> for (int line = start_line; line <= finish_line; line++)
> {
> @@ -418,7 +449,7 @@ test_show_locus (function *fun)
> location_t word
> = make_location (start_of_word, start_of_word,
> end_of_word);
> - richloc.add_range (word, true);
> + richloc.add_range (word, true, &label);
>
> /* Add a fixit, converting to upper case. */
> char_span word_span = content.subspan (start_idx, idx -
> start_idx);
> diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp
> b/gcc/testsuite/gcc.dg/plugin/plugin.exp
> index b2f8507..86ab1dd 100644
> --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
> +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
> @@ -72,6 +72,7 @@ set plugin_test_list [list \
> { diagnostic_plugin_test_show_locus.c \
> diagnostic-test-show-locus-bw.c \
> diagnostic-test-show-locus-color.c \
> + diagnostic-test-show-locus-no-labels.c \
> diagnostic-test-show-locus-bw-line-numbers.c \
> diagnostic-test-show-locus-color-line-numbers.c \
> diagnostic-test-show-locus-parseable-fixits.c \
> diff --git a/gcc/testsuite/gcc.dg/pr69554-1.c
> b/gcc/testsuite/gcc.dg/pr69554-1.c
> index 07ad0db..b979b55 100644
> --- a/gcc/testsuite/gcc.dg/pr69554-1.c
> +++ b/gcc/testsuite/gcc.dg/pr69554-1.c
> @@ -12,6 +12,9 @@ int test_1 (const char *p, const char *q)
> /* { dg-begin-multiline-output "" }
> return (p + 1) + (q + 1);
> ~~~~~~~ ^ ~~~~~~~
> + | |
> + | const char *
> + const char *
> { dg-end-multiline-output "" } */
> }
>
> @@ -26,10 +29,14 @@ int test_2 (const char *p, const char *q)
> /* { dg-begin-multiline-output "" }
> return (p + 1)
> ~~~~~~~
> + |
> + const char *
> +
> ^
> (q + 1);
> ~~~~~~~
> + |
> + const char *
> { dg-end-multiline-output "" } */
> }
>
> @@ -43,16 +50,20 @@ int test_3 (const char *p, const char *q)
>
> + /* { dg-error "invalid operands" } */
> (q + 1);
> -/* { dg-locus "12" "" { target *-*-* } "44" } */
> +/* { dg-locus "12" "" { target *-*-* } "51" } */
> /* { dg-begin-multiline-output "" }
> return (p + 1)
> ~~~~~~~
> + |
> + const char *
> { dg-end-multiline-output "" } */
> /* { dg-begin-multiline-output "" }
> +
> ^
> (q + 1);
> ~~~~~~~
> + |
> + const char *
> { dg-end-multiline-output "" } */
> }
>
> @@ -68,12 +79,16 @@ int test_4 (const char *p, const char *q)
> /* { dg-begin-multiline-output "" }
> return (p + 1)
> ~~~~~~~
> + |
> + const char *
> +
> ^
> { dg-end-multiline-output "" } */
> /* { dg-begin-multiline-output "" }
> (q + 1);
> ~~~~~~~
> + |
> + const char *
> { dg-end-multiline-output "" } */
> }
>
> @@ -88,10 +103,12 @@ int test_5 (const char *p, const char *q)
> + /* { dg-error "invalid operands" } */
>
> (q + 1); /* { dg-locus "14" } */
> -/* { dg-locus "12" "" { target *-*-* } "88" } */
> +/* { dg-locus "12" "" { target *-*-* } "103" } */
> /* { dg-begin-multiline-output "" }
> return (p + 1)
> ~~~~~~~
> + |
> + const char *
> { dg-end-multiline-output "" } */
> /* { dg-begin-multiline-output "" }
> +
> @@ -100,6 +117,8 @@ int test_5 (const char *p, const char *q)
> /* { dg-begin-multiline-output "" }
> (q + 1);
> ~~~~~~~
> + |
> + const char *
> { dg-end-multiline-output "" } */
> }
>
> @@ -136,10 +155,12 @@ int test_6 (const char *p, const char *q)
> fringilla sapien elit vitae nisl. Fusce mattis commodo risus
> nec convallis. */
> (q + 1); /* { dg-locus "14" } */
> -/* { dg-locus "12" "" { target *-*-* } "125" } */
> +/* { dg-locus "12" "" { target *-*-* } "144" } */
> /* { dg-begin-multiline-output "" }
> return (p + 1)
> ~~~~~~~
> + |
> + const char *
> { dg-end-multiline-output "" } */
> /* { dg-begin-multiline-output "" }
> +
> @@ -148,5 +169,7 @@ int test_6 (const char *p, const char *q)
> /* { dg-begin-multiline-output "" }
> (q + 1);
> ~~~~~~~
> + |
> + const char *
> { dg-end-multiline-output "" } */
> }
> diff --git a/gcc/testsuite/gcc.dg/pr69627.c
> b/gcc/testsuite/gcc.dg/pr69627.c
> index b7f56cd..bc48bb1 100644
> --- a/gcc/testsuite/gcc.dg/pr69627.c
> +++ b/gcc/testsuite/gcc.dg/pr69627.c
> @@ -11,6 +11,8 @@ foo ()
> /* { dg-begin-multiline-output "" }
> t[1] / s;
> ~~~~ ^
> + |
> + float
> { dg-end-multiline-output "" } */
> }
>
> @@ -23,5 +25,7 @@ bar ()
> /* { dg-begin-multiline-output "" }
> t[1] / s[0];
> ~~~~ ^ ~~~~
> + | |
> + float const int *
> { dg-end-multiline-output "" } */
> }
> diff --git a/gcc/testsuite/lib/multiline.exp
> b/gcc/testsuite/lib/multiline.exp
> index 84c59e1..5f8b62f 100644
> --- a/gcc/testsuite/lib/multiline.exp
> +++ b/gcc/testsuite/lib/multiline.exp
> @@ -202,26 +202,6 @@ proc _build_multiline_regex { multiline index } {
> if {[string match "*^" $line] || [string match "*~" $line]} {
> # Assume a line containing a caret/range. This must be
> # an exact match.
> - } elseif {[string match "*\\|" $line]} {
> - # Assume a source line with a right-margin. Support
> - # arbitrary text in place of any whitespace before the
> - # right-margin, to deal with comments containing containing
> - # DejaGnu directives.
> -
> - # Remove final "\|":
> - set rexp [string range $rexp 0 [expr [string length $rexp] - 3]]
> -
> - # Trim off trailing whitespace:
> - set old_length [string length $rexp]
> - set rexp [string trimright $rexp]
> - set new_length [string length $rexp]
> -
> - # Replace the trimmed whitespace with "." chars to match anything:
> - set ws [string repeat "." [expr $old_length - $new_length]]
> - set rexp "${rexp}${ws}"
> -
> - # Add back the trailing '\|':
> - set rexp "${rexp}\\|"
> } else {
> # Assume that we have a quoted source line.
> if {![string equal "" $line] } {
> diff --git a/gcc/toplev.c b/gcc/toplev.c
> index aa943a8..2789d71 100644
> --- a/gcc/toplev.c
> +++ b/gcc/toplev.c
> @@ -1112,6 +1112,8 @@ general_init (const char *argv0, bool init_signals)
>
> global_dc->show_caret
> = global_options_init.x_flag_diagnostics_show_caret;
> + global_dc->show_labels_p
> + = global_options_init.x_flag_diagnostics_show_labels;
> global_dc->show_line_numbers_p
> = global_options_init.x_flag_diagnostics_show_line_numbers;
> global_dc->show_option_requested
> diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
> index 1061d20..4f0ff87 100644
> --- a/libcpp/include/line-map.h
> +++ b/libcpp/include/line-map.h
> @@ -1281,8 +1281,11 @@ typedef struct
> bool sysp;
> } expanded_location;
>
> +class range_label;
> +
> /* A location within a rich_location: a caret&range, with
> - the caret potentially flagged for display. */
> + the caret potentially flagged for display, and an optional
> + label. */
>
> struct location_range
> {
> @@ -1298,6 +1301,9 @@ struct location_range
>
> where "1" and "2" are notionally carets. */
> bool m_show_caret_p;
> +
> + /* If non-NULL, the label for this range. */
> + const range_label *m_label;
> };
>
> /* A partially-embedded vec for use within rich_location for storing
> @@ -1439,6 +1445,8 @@ class fixit_hint;
> Additional ranges may be added to help the user identify other
> pertinent clauses in a diagnostic.
>
> + Ranges can (optionally) be given labels via class range_label.
> +
> rich_location instances are intended to be allocated on the stack
> when generating diagnostics, and to be short-lived.
>
> @@ -1484,18 +1492,22 @@ class fixit_hint;
> equal to their caret point. The frontend overrides the diagnostic
> context's default caret character for these ranges.
>
> - Example E
> - *********
> + Example E (range labels)
> + ************************
> printf ("arg0: %i arg1: %s arg2: %i",
> ^~
> + |
> + const char *
> 100, 101, 102);
> ~~~
> + |
> + int
> This rich location has two ranges:
> - range 0 is at the "%s" with start = caret = "%" and finish at
> - the "s".
> + the "s". It has a range_label ("const char *").
> - range 1 has start/finish covering the "101" and is not flagged for
> - caret printing; it is perhaps at the start of "101".
> -
> + caret printing. The caret is at the start of "101", where its
> + range_label is printed ("int").
>
> Fix-it hints
> ------------
> @@ -1587,7 +1599,8 @@ class rich_location
> /* Constructors. */
>
> /* Constructing from a location. */
> - rich_location (line_maps *set, source_location loc);
> + rich_location (line_maps *set, source_location loc,
> + const range_label *label = NULL);
>
> /* Destructor. */
> ~rich_location ();
> @@ -1597,7 +1610,8 @@ class rich_location
> source_location get_loc (unsigned int idx) const;
>
> void
> - add_range (source_location loc, bool show_caret_p);
> + add_range (source_location loc, bool show_caret_p,
> + const range_label *label = NULL);
>
> void
> set_range (unsigned int idx, source_location loc, bool show_caret_p);
> @@ -1721,6 +1735,54 @@ protected:
> bool m_fixits_cannot_be_auto_applied;
> };
>
> +/* A struct for the result of range_label::get_text: a NUL-terminated
> buffer
> + of localized text, and a flag to determine if the caller should "free"
> the
> + buffer. */
> +
> +struct label_text
> +{
> + label_text ()
> + : m_buffer (NULL), m_caller_owned (false)
> + {}
> +
> + label_text (char *buffer, bool caller_owned)
> + : m_buffer (buffer), m_caller_owned (caller_owned)
> + {}
> +
> + void maybe_free ()
> + {
> + if (m_caller_owned)
> + free (m_buffer);
> + }
> +
> + char *m_buffer;
> + bool m_caller_owned;
> +};
> +
> +/* Abstract base class for labelling a range within a rich_location
> + (e.g. for labelling expressions with their type).
> +
> + Generating the text could require non-trivial work, so this work
> + is delayed (via the "get_text" virtual function) until the diagnostic
> + printing code "knows" it needs it, thus avoiding doing it e.g. for
> + warnings that are filtered by command-line flags. This virtual
> + function also isolates libcpp and the diagnostics subsystem from
> + the front-end and middle-end-specific code for generating the text
> + for the labels.
> +
> + Like the rich_location instances they annotate, range_label instances
> + are intended to be allocated on the stack when generating diagnostics,
> + and to be short-lived. */
> +
> +class range_label
> +{
> + public:
> + virtual ~range_label () {}
> +
> + /* Get localized text for the label. */
> + virtual label_text get_text () const = 0;
> +};
> +
> /* A fix-it hint: a suggested insertion, replacement, or deletion of text.
> We handle these three types of edit with one class, by representing
> them as replacement of a half-open range:
> diff --git a/libcpp/line-map.c b/libcpp/line-map.c
> index 555cd12..f0e6318 100644
> --- a/libcpp/line-map.c
> +++ b/libcpp/line-map.c
> @@ -1988,7 +1988,8 @@ line_table_dump (FILE *stream, struct line_maps *set,
> unsigned int num_ordinary,
>
> /* Construct a rich_location with location LOC as its initial range. */
>
> -rich_location::rich_location (line_maps *set, source_location loc) :
> +rich_location::rich_location (line_maps *set, source_location loc,
> + const range_label *label) :
> m_line_table (set),
> m_ranges (),
> m_column_override (0),
> @@ -1997,7 +1998,7 @@ rich_location::rich_location (line_maps *set,
> source_location loc) :
> m_seen_impossible_fixit (false),
> m_fixits_cannot_be_auto_applied (false)
> {
> - add_range (loc, true);
> + add_range (loc, true, label);
> }
>
> /* The destructor for class rich_location. */
> @@ -2073,11 +2074,13 @@ rich_location::override_column (int column)
> /* Add the given range. */
>
> void
> -rich_location::add_range (source_location loc, bool show_caret_p)
> +rich_location::add_range (source_location loc, bool show_caret_p,
> + const range_label *label)
> {
> location_range range;
> range.m_loc = loc;
> range.m_show_caret_p = show_caret_p;
> + range.m_label = label;
> m_ranges.push (range);
> }
>
> --
> 1.8.5.3
>
>
More information about the Gcc-patches
mailing list