]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
diagnostics: add labeling of source ranges
authordmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 15 Aug 2018 18:09:35 +0000 (18:09 +0000)
committerdmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 15 Aug 2018 18:09:35 +0000 (18:09 +0000)
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
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);
  |                               ~~~~~~~~~~~~^~~

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++

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.

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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@263564 138bc75d-0d04-0410-961f-82ee72b054a4

51 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-format.c
gcc/c/ChangeLog
gcc/c/c-objc-common.c
gcc/c/c-typeck.c
gcc/common.opt
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/error.c
gcc/cp/typeck.c
gcc/diagnostic-show-locus.c
gcc/diagnostic.c
gcc/diagnostic.h
gcc/doc/invoke.texi
gcc/dwarf2out.c
gcc/gcc-rich-location.c
gcc/gcc-rich-location.h
gcc/gimple-ssa-sprintf.c
gcc/lto-wrapper.c
gcc/opts.c
gcc/selftest-diagnostic.c
gcc/substring-locations.c
gcc/substring-locations.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/diagnostic/aka3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
gcc/testsuite/g++.dg/plugin/plugin.exp
gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/bad-binary-ops.c
gcc/testsuite/gcc.dg/cpp/pr66415-1.c
gcc/testsuite/gcc.dg/format/diagnostic-ranges.c
gcc/testsuite/gcc.dg/format/pr72858.c
gcc/testsuite/gcc.dg/format/pr78498.c
gcc/testsuite/gcc.dg/param-type-mismatch.c
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw-line-numbers.c
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color-line-numbers.c
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-no-labels.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.c
gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
gcc/testsuite/gcc.dg/plugin/plugin.exp
gcc/testsuite/gcc.dg/pr69554-1.c
gcc/testsuite/gcc.dg/pr69627.c
gcc/testsuite/lib/multiline.exp
gcc/toplev.c
libcpp/ChangeLog
libcpp/include/line-map.h
libcpp/line-map.c

index e575b553c42ef8d5fd2b9af0aa9e39d8630dd8c1..8ea97839c67357c1da42e150b49ccbcebdbcf969 100644 (file)
@@ -1,3 +1,63 @@
+2018-08-15  David Malcolm  <dmalcolm@redhat.com>
+
+       * 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.
+
 2018-08-15  Qing Zhao  <qing.zhao@oracle.com>
 
        PR testsuite/86519
index 3aec883dd1a5855c64fc2504ecd672097284d0aa..b94a7ae9ab7ceb37100cd1111a1d645570aa746d 100644 (file)
@@ -1,3 +1,18 @@
+2018-08-15  David Malcolm  <dmalcolm@redhat.com>
+
+       * 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.
+
 2018-08-13  Martin Sebor  <msebor@redhat.com>
 
        PR tree-optimization/71625
index dc0e7567c9416877d9d6025b6c41fe7aa58faf26..5a04f050acd0d0229d79bd9be0e99e054d66d4bc 100644 (file)
@@ -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, &param_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, &param_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, &param_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, &param_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, &param_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
index be714d28b4d4efd5d2a33d0c631e14e3698586c3..7bde11c1f1959c2eead755bc7b170704c54660f4 100644 (file)
@@ -1,3 +1,14 @@
+2018-08-15  David Malcolm  <dmalcolm@redhat.com>
+
+       * 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.
+
 2018-08-15  Prathamesh Kulkarni  <prathamesh.kulkarni@linaro.org>
        
        * c-decl.c (start_decl): Do not warn if variables is named as main
index ddbd60ce624804a547e962df030b0cf82e4b3d5e..238af199ab5222fb3946866fe4945b892b5fdcf8 100644 (file)
@@ -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, &quoted);
+  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)
index 2e9338e3458b4ccfc07fb5f9a21795321bf2167d..726ea832ae1056e47499bd717c6ab226aa26eeac 100644 (file)
@@ -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;
     }
index b2f2215ecc6fafe4e9d0707a227d31bb9ea217b8..507291f43945ec9603ae4459f3330ef6f9276289 100644 (file)
@@ -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
index 8e12371387365274e336abacc73e78366cf0c562..0b695907cf137ea6bc85198707581e395db9755c 100644 (file)
@@ -1,3 +1,15 @@
+2018-08-15  David Malcolm  <dmalcolm@redhat.com>
+
+       * 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.
+
 2018-08-15  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * decl.c (check_previous_goto_1): When decl_jump_unsafe returns 2
index 62654a9e40724232bb9fa015e1b8276b0cd67b75..16bb6bfd46726b68c264fde3bc484f3dca48e2fe 100644 (file)
@@ -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;
     }
index c49f4d7c378cfff99bd97b1caf5054efc1844202..355a5e82f15064003e5668a8aa3c0e53e4a4afae 100644 (file)
@@ -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);
+}
index 1335da5e9bcf3b4694460275e72ebd83d009c25c..64b3d583356c45c1ff4c3fba608525ed9142366c 100644 (file)
@@ -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),
index 238c689be1ac10efb8994cf636aff02a6a923f03..c9edaab4e22ae277e0212ee5c52bad9aa159438c 100644 (file)
@@ -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.  */
index e9d93d531d5125c5d3d15d455e49a847d9fecf71..59477ce93f607d124b6c00109fb41da019ddd1ed 100644 (file)
@@ -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;
index 744aec1a68f788589097013fccc2b24f0323b2fe..fe3130bdf9d14fa6e99b8a5fdc5c4725b89f1f88 100644 (file)
@@ -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;
index d7fd0e175555417e30f005830560735f008b2af3..586af1787c7f7c4760125784bed665b86b1181a6 100644 (file)
@@ -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
index 9ed473088e739ba95658dc0e0f794d82f62785ee..5a74131d332d132975ed58d07eda9cfaffc0d7e4 100644 (file)
@@ -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:
index 0a0adf932c1dceafc3872e12420ffd60256df090..2576c7387ee38d4bc5a33d48350243894dd46f2d 100644 (file)
@@ -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
index 9c705c86a726612c8c3102c594c53c83329781ef..dc11ee87552d9208426d49c9bd660b9eadc62557 100644 (file)
@@ -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 */
index c652c556f9762e4efed3f395d9277abbc445f66b..5213e17d68f51f7e9d2cced332c1d5ddede69644 100644 (file)
@@ -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);
index 39d9f088bc6d3a06e5a543eae41ee355f2ef3869..d44678694c3d630c51a50244004d9f96400813d3 100644 (file)
@@ -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_:
index 4153263fcab9841edfed27e2a0d5d81139de2b30..a5c9ed9d09d332e42ea7583483563e685bb7ac22 100644 (file)
@@ -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;
index 837488bd3304893f2a380c9785bc73f72a4a26a3..f3c255e3346409c2fbf4a256d752389f9875dcde 100644 (file)
@@ -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;
 }
index 2d7f0c15133738feeb22827636ce86b2ba3b13f5..82f2f4577f0bb7cc0b1d86fb8e6971ee6d10f9cd 100644 (file)
@@ -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);
index fca6fd333c4e7aca626cd5f5bec4abcd1e5116d5..919fdf0127d8c4a3aa6dc2a5a90b7d8b67efc3b2 100644 (file)
@@ -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.  */
index bd167b3a77ecd922ec8991e404ad7c8eb18fe270..20e0b99f02ae9b205b01eb1af29949d976b34377 100644 (file)
@@ -1,3 +1,46 @@
+2018-08-15  David Malcolm  <dmalcolm@redhat.com>
+
+       * 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 '|'.
+
 2018-08-15  Qing Zhao <qing.zhao@oracle.com>
 
        PR testsuite/86519
diff --git a/gcc/testsuite/g++.dg/diagnostic/aka3.C b/gcc/testsuite/g++.dg/diagnostic/aka3.C
new file mode 100644 (file)
index 0000000..1eb4fb2
--- /dev/null
@@ -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 "" } */
+}
index c3b6f003b3e0c3a3d94f983cabf63616fb64cafd..8cf2dabca64c5324c412a1a3286da8c2d996c4e7 100644 (file)
@@ -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 "" }
index 5fcde0b7755465e3fb4c0b3af1e1f9e43c68bd20..50bbd4ae94eab0dce41e9940b6652e18d99b21e8 100644 (file)
@@ -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 "" }
index 451c4a99e331c0847abd7636b52d4acf2f0124dd..d9f54ab9877e86d307e3e6b72dc234eb50d656aa 100644 (file)
@@ -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 (file)
index 0000000..462e1bd
--- /dev/null
@@ -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 '\e[01m\e[Kvec\e[m\e[K' from '\e[01m\e[Kvector<\e[01;32m\e[Kdouble\e[m\e[K>\e[m\e[K' to '\e[01m\e[Kvector<\e[01;32m\e[Kint\e[m\e[K>\e[m\e[K'
+   fn_1 (\e[01;31m\e[Kvec\e[m\e[K);
+         \e[01;31m\e[K^~~\e[m\e[K
+         \e[01;31m\e[K|\e[m\e[K
+         \e[01;31m\e[Kvector<double>\e[m\e[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 '\e[01m\e[Km\e[m\e[K' from '\e[01m\e[Kmap<[...],\e[01;32m\e[Kdouble\e[m\e[K>\e[m\e[K' to '\e[01m\e[Kmap<[...],\e[01;32m\e[Kint\e[m\e[K>\e[m\e[K'
+   fn_2 (\e[01;31m\e[Km\e[m\e[K);
+         \e[01;31m\e[K^\e[m\e[K
+         \e[01;31m\e[K|\e[m\e[K
+         \e[01;31m\e[Kmap<[...],double>\e[m\e[K
+     { dg-end-multiline-output "" } */
+  // TODO: we don't yet highlight the mismatching part with color
+}
index e1da4d615eedac9526170821a480f3d436d82fb4..46c158e6a5f6780f2edcc8b34ae5dda120937ee5 100644 (file)
@@ -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 "" } */
+}
+
index 515252cd0233d412715af67dd8b1a368ca2b00cb..cc4e41724a200edaf140da98eae5a8aa210f7032 100644 (file)
@@ -11,6 +11,8 @@ fn1 (void)
 /* { dg-begin-multiline-output "" }
    __builtin_printf                                ("xxxxxxxxxxxxxxxxx%dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
                                                                       ~^
+                                                                       |
+                                                                       int
    { dg-end-multiline-output "" } */
 
 }
index e56e1595502f4126672274283ea434b7b5167d6f..84535f018d7323fe565314aba14c0859ac7320af 100644 (file)
@@ -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 "" } */
 }
index b8c5829ed23fcdd08c9654567aa6c82b03f73aa6..77260943c8c71c1843a4811a4918cbf85af33aee 100644 (file)
@@ -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 "" } */
 }
index 4b53a68c2c04e53031ee146c7e66da3da17a0a98..b911b04eb7d36ba878c42dc405a00615465b1f64 100644 (file)
@@ -7,6 +7,8 @@ void f (void)
 /* { dg-begin-multiline-output "" }
    __builtin_printf ("%i", "");
                       ~^   ~~
+                       |   |
+                       int char *
                       %s
    { dg-end-multiline-output "" } */
 }
index 9498a748f308ed8e38ac2f7d38a3a8c18b075c17..9e654a9e9c65abbe260b01ecb264a421d3109560 100644 (file)
@@ -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 "" } */
+}
index 66a2faae40dc4c63f83206448a9dd2362ae82b92..89213eb2b255d218951c74edfd98d8577aa22d92 100644 (file)
@@ -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
index 513c0af772fa2c143d2c052c3b584516eb2f9caf..bdfa420d8497d4bbb19d78cc09869df9bb92f1f5 100644 (file)
@@ -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 "" } */
 }
index a80b6de3e681c7bca0e296d3c33b0c351cfa6748..0453c52b2ccfa2328f6a30e9acbf5cd4ea141c2b 100644 (file)
@@ -19,6 +19,8 @@ void test_multiline (void)
    |        \e[32m\e[K~~~~~~~~~~~~~~~~~\e[m\e[K
 15 |        \e[01;35m\e[K+\e[m\e[K \e[34m\e[Ksecond_function ()\e[m\e[K);
    |        \e[01;35m\e[K^\e[m\e[K \e[34m\e[K~~~~~~~~~~~~~~~~~~\e[m\e[K
+   |        \e[01;35m\e[K|\e[m\e[K
+   |        \e[01;35m\e[Klabel\e[m\e[K
    { dg-end-multiline-output "" } */
 #endif
 }
index 4cc406d76dedd5b1dfcf5a810cbb0d6d30d1e248..094bc6535d5e4c9748c815bea1facef81eba0902 100644 (file)
@@ -44,6 +44,8 @@ void test_multiline (void)
         \e[32m\e[K~~~~~~~~~~~~~~~~~\e[m\e[K
         \e[01;35m\e[K+\e[m\e[K \e[34m\e[Ksecond_function ()\e[m\e[K);
         \e[01;35m\e[K^\e[m\e[K \e[34m\e[K~~~~~~~~~~~~~~~~~~\e[m\e[K
+        \e[01;35m\e[K|\e[m\e[K
+        \e[01;35m\e[Klabel\e[m\e[K
    { dg-end-multiline-output "" } */
 #endif
 }
@@ -66,6 +68,8 @@ void test_many_lines (void)
 /* { dg-begin-multiline-output "" }
    x = (\e[32m\e[Kfirst_function_with_a_very_long_name (lorem, ipsum, dolor, sit, amet,\e[m\e[K
         \e[32m\e[K~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[m\e[K
+        \e[32m\e[K|\e[m\e[K
+        \e[32m\e[Klabel 1\e[m\e[K
  \e[32m\e[K                                            consectetur, adipiscing, elit,\e[m\e[K
                                              \e[32m\e[K~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[m\e[K
  \e[32m\e[K                                            sed, eiusmod, tempor,\e[m\e[K
@@ -76,6 +80,9 @@ void test_many_lines (void)
                                              \e[32m\e[K~~~~~~~~~~~~~~~~~~~~~~\e[m\e[K
         \e[01;35m\e[K+\e[m\e[K \e[34m\e[Ksecond_function_with_a_very_long_name (lorem, ipsum, dolor, sit,
         \e[01;35m\e[K^\e[m\e[K \e[34m\e[K~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[m\e[K
+        \e[01;35m\e[K|\e[m\e[K \e[34m\e[K|\e[m\e[K
+        \e[01;35m\e[K|\e[m\e[K \e[34m\e[Klabel 2\e[m\e[K
+        \e[01;35m\e[Klabel 0\e[m\e[K
  \e[34m\e[K                                                amet, consectetur,\e[m\e[K
                                                  \e[34m\e[K~~~~~~~~~~~~~~~~~~\e[m\e[K
  \e[34m\e[K                                                adipiscing, elit, sed,\e[m\e[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 = \e[01;35m\e[Kfoo * bar\e[m\e[K;
-                                                        \e[01;35m\e[K~~~~^~~~~\e[m\e[K
\e[32m\e[Kx\e[m\e[K                                                    = \e[01;35m\e[Kfoo * bar\e[m\e[K;
\e[32m\e[K~\e[m\e[K                                                      \e[01;35m\e[K~~~~^~~~~\e[m\e[K
\e[32m\e[K|\e[m\e[K                                                          \e[01;35m\e[K|\e[m\e[K
\e[32m\e[Klabel 1\e[m\e[K                                                    \e[01;35m\e[Klabel 0\e[m\e[K
                                                         \e[32m\e[Kbar * foo\e[m\e[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 (file)
index 0000000..4c06368
--- /dev/null
@@ -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
+}
index 0bdd877dbd5aec13096c20295e4f34c903616055..71e6740b17876acb0874b8db4ff97fd1d46981fb 100644 (file)
@@ -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)
     {
index 1d340aa0e6a02b50a30db32663608356ea955a30..3d7853813ae5d0120e961b3037dd59f0d6fb0daf 100644 (file)
@@ -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);
index b2f8507338ad71af2e149791a76454a008f6ef52..86ab1dd8d932aeca9c881c22d61758eb2f3ba439 100644 (file)
@@ -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 \
index 07ad0db7cf6d4245cca4e44f71363305dd8d57bd..b979b5596f2a443ad21f14e6e8251183afdad0b0 100644 (file)
@@ -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 "" } */
 }
index b7f56cd4ac77fdf8f7854274e46f8722bc3b3496..bc48bb1aa81e75d79de69c08b3cb8fdcd068381d 100644 (file)
@@ -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 "" } */
 }
index 84c59e1efd46c7de3f6ac2d013c25fb86f82469d..5f8b62fd301e791d41e124ac1734c93eaeb5f077 100644 (file)
@@ -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] }  {
index aa943a8655eb046d26355a94b473c54a1ad9a877..2789d71b24f5f695d1415cbdbc51f2dc9332b25e 100644 (file)
@@ -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
index 3eaebfd812f28d6a8c7f2b2127be0def45832650..a39144c6b014bd5ea609566431a4437d9c0c4aea 100644 (file)
@@ -1,3 +1,17 @@
+2018-08-15  David Malcolm  <dmalcolm@redhat.com>
+
+       * 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.
+
 2018-08-08  Nathan Sidwell  <nathan@acm.org>
 
        Make linemap::included_from a location
index 1061d201389facce8e12ed38b1fc16d20da3a595..4f0ff8719a79abe5779851205de0549f60b1436e 100644 (file)
@@ -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:
index 555cd129a9c5541c012ed6e9168465201de18213..f0e6318e412cd8823ee5fcdd08fe86d6d950efaa 100644 (file)
@@ -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);
 }