diff options
author | David Malcolm <dmalcolm@redhat.com> | 2018-12-19 15:15:42 +0000 |
---|---|---|
committer | David Malcolm <dmalcolm@gcc.gnu.org> | 2018-12-19 15:15:42 +0000 |
commit | a14feb3c783fba6af8d66b8138214a3a313be5c5 (patch) | |
tree | 8077a5987ffd2b51526c4fb5914a366842927823 /gcc/gcc-rich-location.c | |
parent | dfd7fdca2ac17d8b823a16700525824ca312ade0 (diff) | |
download | gcc-a14feb3c783fba6af8d66b8138214a3a313be5c5.zip gcc-a14feb3c783fba6af8d66b8138214a3a313be5c5.tar.gz gcc-a14feb3c783fba6af8d66b8138214a3a313be5c5.tar.bz2 |
C++: improvements to binary operator diagnostics (PR c++/87504)
The C frontend is able (where expression locations are available) to print
problems with binary operators in 3-location form, labelling the types of
the expressions:
arg_0 op arg_1
~~~~~ ^~ ~~~~~
| |
| arg1 type
arg0 type
The C++ frontend currently just shows the combined location:
arg_0 op arg_1
~~~~~~^~~~~~~~
and fails to highlight where the subexpressions are, or their types.
This patch introduces a op_location_t struct for handling the above
operator-location vs combined-location split, and a new
class binary_op_rich_location for displaying the above, so that the
C++ frontend is able to use the more detailed 3-location form for
type mismatches in binary operators, and for -Wtautological-compare
(where types are not displayed). Both forms can be seen in this
example:
bad-binary-ops.C:69:20: error: no match for 'operator&&' (operand types are
's' and 't')
69 | return ns_4::foo && ns_4::inner::bar;
| ~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~~
| | |
| s t
bad-binary-ops.C:69:20: note: candidate: 'operator&&(bool, bool)' <built-in>
69 | return ns_4::foo && ns_4::inner::bar;
| ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
The patch also allows for some uses of macros in
-Wtautological-compare, where both sides of the comparison have
been spelled the same way, e.g.:
Wtautological-compare-ranges.c:23:11: warning: self-comparison always
evaluates to true [-Wtautological-compare]
23 | if (FOO == FOO);
| ^~
gcc/c-family/ChangeLog:
PR c++/87504
* c-common.h (warn_tautological_cmp): Convert 1st param from
location_t to const op_location_t &.
* c-warn.c (find_array_ref_with_const_idx_r): Call fold_for_warn
when testing for INTEGER_CST.
(warn_tautological_bitwise_comparison): Convert 1st param from
location_t to const op_location_t &; use it to build a
binary_op_rich_location, and use this.
(spelled_the_same_p): New function.
(warn_tautological_cmp): Convert 1st param from location_t to
const op_location_t &. Warn for macro expansions if
spelled_the_same_p. Use binary_op_rich_location.
gcc/c/ChangeLog:
PR c++/87504
* c-typeck.c (class maybe_range_label_for_tree_type_mismatch):
Move from here to gcc-rich-location.h and gcc-rich-location.c.
(build_binary_op): Use struct op_location_t and
class binary_op_rich_location.
gcc/cp/ChangeLog:
PR c++/87504
* call.c (op_error): Convert 1st param from location_t to
const op_location_t &. Use binary_op_rich_location for binary
ops.
(build_conditional_expr_1): Convert 1st param from location_t to
const op_location_t &.
(build_conditional_expr): Likewise.
(build_new_op_1): Likewise.
(build_new_op): Likewise.
* cp-tree.h (build_conditional_expr): Likewise.
(build_new_op): Likewise.
(build_x_binary_op): Likewise.
(cp_build_binary_op): Likewise.
* parser.c (cp_parser_primary_expression): Build a location
for id-expression nodes.
(cp_parser_binary_expression): Use an op_location_t when
calling build_x_binary_op.
(cp_parser_operator): Build a location for user-defined literals.
* typeck.c (build_x_binary_op): Convert 1st param from location_t
to const op_location_t &.
(cp_build_binary_op): Likewise. Use binary_op_rich_location.
gcc/ChangeLog:
PR c++/87504
* gcc-rich-location.c
(maybe_range_label_for_tree_type_mismatch::get_text): Move here from
c/c-typeck.c.
(binary_op_rich_location::binary_op_rich_location): New ctor.
(binary_op_rich_location::use_operator_loc_p): New function.
* gcc-rich-location.h
(class maybe_range_label_for_tree_type_mismatch)): Move here from
c/c-typeck.c.
(struct op_location_t): New forward decl.
(class binary_op_rich_location): New class.
* tree.h (struct op_location_t): New struct.
gcc/testsuite/ChangeLog:
* c-c++-common/Wtautological-compare-ranges.c: New test.
* g++.dg/cpp0x/pr51420.C: Add -fdiagnostics-show-caret and update
expected output.
* g++.dg/diagnostic/bad-binary-ops.C: Update expected output from
1-location form to 3-location form, with labelling of ranges with
types. Add examples of id-expression nodes with namespaces.
* g++.dg/diagnostic/param-type-mismatch-2.C: Likewise.
From-SVN: r267273
Diffstat (limited to 'gcc/gcc-rich-location.c')
-rw-r--r-- | gcc/gcc-rich-location.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/gcc/gcc-rich-location.c b/gcc/gcc-rich-location.c index 81beb61..25a604f 100644 --- a/gcc/gcc-rich-location.c +++ b/gcc/gcc-rich-location.c @@ -182,3 +182,92 @@ gcc_rich_location::add_fixit_insert_formatted (const char *content, else add_fixit_insert_before (insertion_point, content); } + +/* Implementation of range_label::get_text for + maybe_range_label_for_tree_type_mismatch. + + If both expressions are non-NULL, then generate text describing + the first expression's type (using the other expression's type + for comparison, analogous to %H and %I in the C++ frontend, but + on expressions rather than types). */ + +label_text +maybe_range_label_for_tree_type_mismatch::get_text (unsigned range_idx) const +{ + 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 (range_idx); +} + +/* binary_op_rich_location's ctor. + + If use_operator_loc_p (LOC, ARG0, ARG1), then attempt to make a 3-location + rich_location of the form: + + arg_0 op arg_1 + ~~~~~ ^~ ~~~~~ + | | + | arg1 type + arg0 type + + labelling the types of the arguments if SHOW_TYPES is true. + + Otherwise, make a 1-location rich_location using the compound + location within LOC: + + arg_0 op arg_1 + ~~~~~~^~~~~~~~ + + for which we can't label the types. */ + +binary_op_rich_location::binary_op_rich_location (const op_location_t &loc, + tree arg0, tree arg1, + bool show_types) +: gcc_rich_location (loc.m_combined_loc), + m_label_for_arg0 (arg0, arg1), + m_label_for_arg1 (arg1, arg0) +{ + /* Default (above) to using the combined loc. + Potentially override it here: if we have location information for the + operator and for both arguments, then split them all out. + Alternatively, override it if we don't have the combined location. */ + if (use_operator_loc_p (loc, arg0, arg1)) + { + set_range (0, loc.m_operator_loc, SHOW_RANGE_WITH_CARET); + maybe_add_expr (arg0, show_types ? &m_label_for_arg0 : NULL); + maybe_add_expr (arg1, show_types ? &m_label_for_arg1 : NULL); + } +} + +/* Determine if binary_op_rich_location's ctor should attempt to make + a 3-location rich_location (the location of the operator and of + the 2 arguments), or fall back to a 1-location rich_location showing + just the combined location of the operation as a whole. */ + +bool +binary_op_rich_location::use_operator_loc_p (const op_location_t &loc, + tree arg0, tree arg1) +{ + /* If we don't have a combined location, then use the operator location, + and try to add ranges for the operators. */ + if (loc.m_combined_loc == UNKNOWN_LOCATION) + return true; + + /* If we don't have the operator location, then use the + combined location. */ + if (loc.m_operator_loc == UNKNOWN_LOCATION) + return false; + + /* We have both operator location and combined location: only use the + operator location if we have locations for both arguments. */ + return (EXPR_HAS_LOCATION (arg0) + && EXPR_HAS_LOCATION (arg1)); +} |