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