aboutsummaryrefslogtreecommitdiff
path: root/libcpp
diff options
context:
space:
mode:
authordmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4>2018-08-15 18:09:35 +0000
committerdmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4>2018-08-15 18:09:35 +0000
commitb7bb52644cb759ef9c6433d216dd54d62fe77248 (patch)
tree3ac7b1d0a088c0fb8d1ae7fe7866fa06b3d3f232 /libcpp
parentee1b788e96b04edf90ac8e7408d39427a8268018 (diff)
diagnostics: add labeling of source ranges
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
Diffstat (limited to 'libcpp')
-rw-r--r--libcpp/ChangeLog14
-rw-r--r--libcpp/include/line-map.h78
-rw-r--r--libcpp/line-map.c9
3 files changed, 90 insertions, 11 deletions
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index 3eaebfd812f..a39144c6b01 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -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
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index 1061d201389..4f0ff8719a7 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -1281,8 +1281,11 @@ typedef struct
bool sysp;
} expanded_location;
+class range_label;
+
/* A location within a rich_location: a caret&range, with
- the caret potentially flagged for display. */
+ the caret potentially flagged for display, and an optional
+ label. */
struct location_range
{
@@ -1298,6 +1301,9 @@ struct location_range
where "1" and "2" are notionally carets. */
bool m_show_caret_p;
+
+ /* If non-NULL, the label for this range. */
+ const range_label *m_label;
};
/* A partially-embedded vec for use within rich_location for storing
@@ -1439,6 +1445,8 @@ class fixit_hint;
Additional ranges may be added to help the user identify other
pertinent clauses in a diagnostic.
+ Ranges can (optionally) be given labels via class range_label.
+
rich_location instances are intended to be allocated on the stack
when generating diagnostics, and to be short-lived.
@@ -1484,18 +1492,22 @@ class fixit_hint;
equal to their caret point. The frontend overrides the diagnostic
context's default caret character for these ranges.
- Example E
- *********
+ Example E (range labels)
+ ************************
printf ("arg0: %i arg1: %s arg2: %i",
^~
+ |
+ const char *
100, 101, 102);
~~~
+ |
+ int
This rich location has two ranges:
- range 0 is at the "%s" with start = caret = "%" and finish at
- the "s".
+ the "s". It has a range_label ("const char *").
- range 1 has start/finish covering the "101" and is not flagged for
- caret printing; it is perhaps at the start of "101".
-
+ caret printing. The caret is at the start of "101", where its
+ range_label is printed ("int").
Fix-it hints
------------
@@ -1587,7 +1599,8 @@ class rich_location
/* Constructors. */
/* Constructing from a location. */
- rich_location (line_maps *set, source_location loc);
+ rich_location (line_maps *set, source_location loc,
+ const range_label *label = NULL);
/* Destructor. */
~rich_location ();
@@ -1597,7 +1610,8 @@ class rich_location
source_location get_loc (unsigned int idx) const;
void
- add_range (source_location loc, bool show_caret_p);
+ add_range (source_location loc, bool show_caret_p,
+ const range_label *label = NULL);
void
set_range (unsigned int idx, source_location loc, bool show_caret_p);
@@ -1721,6 +1735,54 @@ protected:
bool m_fixits_cannot_be_auto_applied;
};
+/* A struct for the result of range_label::get_text: a NUL-terminated buffer
+ of localized text, and a flag to determine if the caller should "free" the
+ buffer. */
+
+struct label_text
+{
+ label_text ()
+ : m_buffer (NULL), m_caller_owned (false)
+ {}
+
+ label_text (char *buffer, bool caller_owned)
+ : m_buffer (buffer), m_caller_owned (caller_owned)
+ {}
+
+ void maybe_free ()
+ {
+ if (m_caller_owned)
+ free (m_buffer);
+ }
+
+ char *m_buffer;
+ bool m_caller_owned;
+};
+
+/* Abstract base class for labelling a range within a rich_location
+ (e.g. for labelling expressions with their type).
+
+ Generating the text could require non-trivial work, so this work
+ is delayed (via the "get_text" virtual function) until the diagnostic
+ printing code "knows" it needs it, thus avoiding doing it e.g. for
+ warnings that are filtered by command-line flags. This virtual
+ function also isolates libcpp and the diagnostics subsystem from
+ the front-end and middle-end-specific code for generating the text
+ for the labels.
+
+ Like the rich_location instances they annotate, range_label instances
+ are intended to be allocated on the stack when generating diagnostics,
+ and to be short-lived. */
+
+class range_label
+{
+ public:
+ virtual ~range_label () {}
+
+ /* Get localized text for the label. */
+ virtual label_text get_text () const = 0;
+};
+
/* A fix-it hint: a suggested insertion, replacement, or deletion of text.
We handle these three types of edit with one class, by representing
them as replacement of a half-open range:
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index 555cd129a9c..f0e6318e412 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -1988,7 +1988,8 @@ line_table_dump (FILE *stream, struct line_maps *set, unsigned int num_ordinary,
/* Construct a rich_location with location LOC as its initial range. */
-rich_location::rich_location (line_maps *set, source_location loc) :
+rich_location::rich_location (line_maps *set, source_location loc,
+ const range_label *label) :
m_line_table (set),
m_ranges (),
m_column_override (0),
@@ -1997,7 +1998,7 @@ rich_location::rich_location (line_maps *set, source_location loc) :
m_seen_impossible_fixit (false),
m_fixits_cannot_be_auto_applied (false)
{
- add_range (loc, true);
+ add_range (loc, true, label);
}
/* The destructor for class rich_location. */
@@ -2073,11 +2074,13 @@ rich_location::override_column (int column)
/* Add the given range. */
void
-rich_location::add_range (source_location loc, bool show_caret_p)
+rich_location::add_range (source_location loc, bool show_caret_p,
+ const range_label *label)
{
location_range range;
range.m_loc = loc;
range.m_show_caret_p = show_caret_p;
+ range.m_label = label;
m_ranges.push (range);
}