On 8/15/18, David Malcolm <dmalc...@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 > >