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