This is a combination of various patches from v1 of the kit, including: 12/22: Add source-ranges for trees 13/22: gcc-rich-location.[ch]: add methods for working with tree ranges 14/22: C: capture tree ranges for various expressions
The implementation of how ranges are stored has completely changed since v1 of the kit. Rather than introducing a SOURCE_RANGE tree node and adding fields to decl and expr, the patch now captures ranges for all C expressions during parsing within a new field of c_expr, and for all tree nodes with a location_t, it stores them in ad-hoc locations for later use. Hence compound expressions get ranges; see: https://dmalcolm.fedorapeople.org/gcc/2015-09-22/diagnostic-test-expressions-1.html and for this example: int test (int foo) { return foo * 100; ^^^ ^^^ } we have access to the ranges of "foo" and "100" during C parsing via the c_expr, but once we have GENERIC, all we have is a VAR_DECL and an INTEGER_CST (the former's location is in at the top of the function, and the latter has no location). This restriction means that I had to remove various expressions from diagnostic-test-expressions-1.c; specifically: test_global test_param test_local test_integer_constants test_character_constants test_floating_constants test_enumeration_constant test_string_literal test_unary_plus test_sizeof There are still some FIXMEs in here that probably need addressing. gcc/ChangeLog: * Makefile.in (OBJS): Add gcc-rich-location.o. * gcc-rich-location.c: New file. * gcc-rich-location.h: New file. * gimple.h (gimple_set_block): Use "set_block". * print-tree.c (print_node): Print any source range information. * tree-cfg.c (move_block_to_fn): Use "set_block". (move_block_to_fn): Likewise. * tree-inline.c (copy_phis_for_bb): Likewise. * tree.c (tree_set_block): Use "set_block". (set_source_range): New functions. (set_block): New function. * tree.h (CAN_HAVE_RANGE_P): New. (EXPR_LOCATION_RANGE): New. (EXPR_HAS_RANGE): New. (get_expr_source_range): New inline function. (DECL_LOCATION_RANGE): New. (set_source_range): New decls. (set_block): New decl. (get_decl_source_range): New inline function. gcc/c-family/ChangeLog: * c-common.c (c_fully_fold_internal): Capture existing souce_range, and store it on the result. gcc/c/ChangeLog: * c-parser.c (set_c_expr_source_range): New functions. (c_parser_expr_no_commas): Call set_c_expr_source_range on the ret based on the range from the start of the LHS to the end of the RHS. (c_parser_conditional_expression): Likewise, based on the range from the start of the cond.value to the end of exp2.value. (c_parser_binary_expression): Call set_c_expr_source_range on the stack values for TRUTH_ANDIF_EXPR and TRUTH_ORIF_EXPR. (c_parser_cast_expression): Call set_c_expr_source_range on ret based on the cast_loc through to the end of the expr. (c_parser_unary_expression): Likewise, based on the op_loc through to the end of op. (c_parser_sizeof_expression) Likewise, based on the start of the sizeof token through to either the closing paren or the end of expr. (c_parser_postfix_expression): Likewise, using the token range, or from the open paren through to the close paren for parenthesized expressions. (c_parser_postfix_expression_after_primary): Likewise, for various kinds of expression. * c-tree.h (struct c_expr): Add field "src_range". (set_c_expr_source_range): New decls. * c-typeck.c (parser_build_unary_op): Call set_c_expr_source_range on ret for prefix unary ops. (parser_build_binary_op): Likewise, running from the start of arg1.value through to the end of arg2.value. gcc/testsuite/ChangeLog: * gcc.dg/plugin/diagnostic-test-expressions-1.c: New file. * gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c: New file. * gcc.dg/plugin/plugin.exp (plugin_test_list): Add diagnostic_plugin_test_tree_expression_range.c and diagnostic-test-expressions-1.c. libcpp/ChangeLog: * include/line-map.h (location_adhoc_data): Add field "src_range". (get_combined_adhoc_loc): Add source_range param. (get_range_from_adhoc_loc): New decl. (COMBINE_LOCATION_DATA): Add source_range param. * line-map.c (location_adhoc_data_hash): Contribute the src_range start and finish to the hash value. (location_adhoc_data_eq): Require that the src_range values be equal. (get_combined_adhoc_loc): Add source_range param and store it. Remove the requirement that "data" be non-NULL. (get_range_from_adhoc_loc): New function. (linemap_expand_location): Move the update of "loc" until after extracting "data". --- gcc/Makefile.in | 1 + gcc/c-family/c-common.c | 10 +- gcc/c/c-parser.c | 89 ++++- gcc/c/c-tree.h | 11 + gcc/c/c-typeck.c | 10 + gcc/gcc-rich-location.c | 86 +++++ gcc/gcc-rich-location.h | 47 +++ gcc/gimple.h | 6 +- gcc/print-tree.c | 21 + .../gcc.dg/plugin/diagnostic-test-expressions-1.c | 422 +++++++++++++++++++++ .../diagnostic_plugin_test_tree_expression_range.c | 159 ++++++++ gcc/testsuite/gcc.dg/plugin/plugin.exp | 2 + gcc/tree-cfg.c | 9 +- gcc/tree-inline.c | 5 +- gcc/tree.c | 40 +- gcc/tree.h | 40 ++ libcpp/include/line-map.h | 13 +- libcpp/line-map.c | 26 +- 18 files changed, 964 insertions(+), 33 deletions(-) create mode 100644 gcc/gcc-rich-location.c create mode 100644 gcc/gcc-rich-location.h create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 009c745..8cd446d 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1255,6 +1255,7 @@ OBJS = \ fold-const.o \ function.o \ fwprop.o \ + gcc-rich-location.o \ gcse.o \ gcse-common.o \ ggc-common.o \ diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index ded23d3..4505db7 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -1178,6 +1178,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, bool op0_const_self = true, op1_const_self = true, op2_const_self = true; bool nowarning = TREE_NO_WARNING (expr); bool unused_p; + source_range old_range; /* This function is not relevant to C++ because C++ folds while parsing, and may need changes to be correct for C++ when C++ @@ -1193,6 +1194,9 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, || code == SAVE_EXPR) return expr; + if (IS_EXPR_CODE_CLASS (kind)) + old_range = EXPR_LOCATION_RANGE (expr); + /* Operands of variable-length expressions (function calls) have already been folded, as have __builtin_* function calls, and such expressions cannot occur in constant expressions. */ @@ -1617,7 +1621,11 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, TREE_NO_WARNING (ret) = 1; } if (ret != expr) - protected_set_expr_location (ret, loc); + { + protected_set_expr_location (ret, loc); + if (IS_EXPR_CODE_CLASS (kind)) + set_source_range (&ret, old_range.m_start, old_range.m_finish); + } return ret; } diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 5edf563..f0f39d4 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -67,6 +67,24 @@ along with GCC; see the file COPYING3. If not see #include "gomp-constants.h" #include "c-family/c-indentation.h" +void +set_c_expr_source_range (c_expr *expr, + location_t start, location_t finish) +{ + expr->src_range.m_start = start; + expr->src_range.m_finish = finish; + set_source_range (&expr->value, + start, finish); +} + +void +set_c_expr_source_range (c_expr *expr, + source_range src_range) +{ + expr->src_range = src_range; + set_source_range (&expr->value, src_range); +} + /* Initialization routine for this file. */ @@ -6053,6 +6071,9 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after, ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type, code, exp_location, rhs.value, rhs.original_type); + set_c_expr_source_range (&ret, + lhs.src_range.m_start, + rhs.src_range.m_finish); if (code == NOP_EXPR) ret.original_code = MODIFY_EXPR; else @@ -6083,7 +6104,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after, tree omp_atomic_lhs) { struct c_expr cond, exp1, exp2, ret; - location_t cond_loc, colon_loc, middle_loc; + location_t start, cond_loc, colon_loc, middle_loc; gcc_assert (!after || c_dialect_objc ()); @@ -6091,6 +6112,10 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after, if (c_parser_next_token_is_not (parser, CPP_QUERY)) return cond; + if (cond.value != error_mark_node) + start = cond.src_range.m_start; + else + start = UNKNOWN_LOCATION; cond_loc = c_parser_peek_token (parser)->location; cond = convert_lvalue_to_rvalue (cond_loc, cond, true, true); c_parser_consume_token (parser); @@ -6166,6 +6191,9 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after, ? t1 : NULL); } + set_c_expr_source_range (&ret, + start, + exp2.src_range.m_finish); return ret; } @@ -6318,6 +6346,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, { enum c_parser_prec oprec; enum tree_code ocode; + source_range src_range; if (parser->error) goto out; switch (c_parser_peek_token (parser)->type) @@ -6406,6 +6435,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, switch (ocode) { case TRUTH_ANDIF_EXPR: + src_range = stack[sp].expr.src_range; stack[sp].expr = convert_lvalue_to_rvalue (stack[sp].loc, stack[sp].expr, true, true); @@ -6413,8 +6443,10 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, (stack[sp].loc, default_conversion (stack[sp].expr.value)); c_inhibit_evaluation_warnings += (stack[sp].expr.value == truthvalue_false_node); + set_c_expr_source_range (&stack[sp].expr, src_range); break; case TRUTH_ORIF_EXPR: + src_range = stack[sp].expr.src_range; stack[sp].expr = convert_lvalue_to_rvalue (stack[sp].loc, stack[sp].expr, true, true); @@ -6422,6 +6454,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, (stack[sp].loc, default_conversion (stack[sp].expr.value)); c_inhibit_evaluation_warnings += (stack[sp].expr.value == truthvalue_true_node); + set_c_expr_source_range (&stack[sp].expr, src_range); break; default: break; @@ -6490,6 +6523,10 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true); } ret.value = c_cast_expr (cast_loc, type_name, expr.value); + if (ret.value && expr.value) + set_c_expr_source_range (&ret, + cast_loc, + expr.src_range.m_finish); ret.original_code = ERROR_MARK; ret.original_type = NULL; return ret; @@ -6539,6 +6576,7 @@ c_parser_unary_expression (c_parser *parser) struct c_expr ret, op; location_t op_loc = c_parser_peek_token (parser)->location; location_t exp_loc; + location_t finish; ret.original_code = ERROR_MARK; ret.original_type = NULL; switch (c_parser_peek_token (parser)->type) @@ -6578,8 +6616,10 @@ c_parser_unary_expression (c_parser *parser) c_parser_consume_token (parser); exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); + finish = op.src_range.m_finish; op = convert_lvalue_to_rvalue (exp_loc, op, true, true); ret.value = build_indirect_ref (op_loc, op.value, RO_UNARY_STAR); + set_c_expr_source_range (&ret, op_loc, finish); return ret; case CPP_PLUS: if (!c_dialect_objc () && !in_system_header_at (input_location)) @@ -6667,8 +6707,15 @@ static struct c_expr c_parser_sizeof_expression (c_parser *parser) { struct c_expr expr; + struct c_expr result; location_t expr_loc; gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF)); + + location_t start; + location_t finish = UNKNOWN_LOCATION; + + start = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); c_inhibit_evaluation_warnings++; in_sizeof++; @@ -6682,6 +6729,7 @@ c_parser_sizeof_expression (c_parser *parser) expr_loc = c_parser_peek_token (parser)->location; type_name = c_parser_type_name (parser); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + finish = parser->tokens_buf[0].range.m_finish; // FIXME: better access API to last token if (type_name == NULL) { struct c_expr ret; @@ -6697,17 +6745,19 @@ c_parser_sizeof_expression (c_parser *parser) expr = c_parser_postfix_expression_after_paren_type (parser, type_name, expr_loc); + finish = expr.src_range.m_finish; goto sizeof_expr; } /* sizeof ( type-name ). */ c_inhibit_evaluation_warnings--; in_sizeof--; - return c_expr_sizeof_type (expr_loc, type_name); + result = c_expr_sizeof_type (expr_loc, type_name); } else { expr_loc = c_parser_peek_token (parser)->location; expr = c_parser_unary_expression (parser); + finish = expr.src_range.m_finish; sizeof_expr: c_inhibit_evaluation_warnings--; in_sizeof--; @@ -6715,8 +6765,11 @@ c_parser_sizeof_expression (c_parser *parser) if (TREE_CODE (expr.value) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) error_at (expr_loc, "%<sizeof%> applied to a bit-field"); - return c_expr_sizeof_expr (expr_loc, expr); + result = c_expr_sizeof_expr (expr_loc, expr); } + if (finish != UNKNOWN_LOCATION) + set_c_expr_source_range (&result, start, finish); + return result; } /* Parse an alignof expression. */ @@ -7136,12 +7189,14 @@ c_parser_postfix_expression (c_parser *parser) struct c_expr expr, e1; struct c_type_name *t1, *t2; location_t loc = c_parser_peek_token (parser)->location;; + source_range tok_range = c_parser_peek_token (parser)->range; expr.original_code = ERROR_MARK; expr.original_type = NULL; switch (c_parser_peek_token (parser)->type) { case CPP_NUMBER: expr.value = c_parser_peek_token (parser)->value; + set_c_expr_source_range (&expr, tok_range); loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); if (TREE_CODE (expr.value) == FIXED_CST @@ -7156,6 +7211,7 @@ c_parser_postfix_expression (c_parser *parser) case CPP_CHAR32: case CPP_WCHAR: expr.value = c_parser_peek_token (parser)->value; + set_c_expr_source_range (&expr, tok_range); c_parser_consume_token (parser); break; case CPP_STRING: @@ -7164,6 +7220,7 @@ c_parser_postfix_expression (c_parser *parser) case CPP_WSTRING: case CPP_UTF8STRING: expr.value = c_parser_peek_token (parser)->value; + set_c_expr_source_range (&expr, tok_range); expr.original_code = STRING_CST; c_parser_consume_token (parser); break; @@ -7171,6 +7228,7 @@ c_parser_postfix_expression (c_parser *parser) gcc_assert (c_dialect_objc ()); expr.value = objc_build_string_object (c_parser_peek_token (parser)->value); + set_c_expr_source_range (&expr, tok_range); c_parser_consume_token (parser); break; case CPP_NAME: @@ -7184,6 +7242,7 @@ c_parser_postfix_expression (c_parser *parser) (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN), &expr.original_type); + set_c_expr_source_range (&expr, tok_range); break; } case C_ID_CLASSNAME: @@ -7272,6 +7331,7 @@ c_parser_postfix_expression (c_parser *parser) else { /* A parenthesized expression. */ + location_t loc_open_paren = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); expr = c_parser_expression (parser); if (TREE_CODE (expr.value) == MODIFY_EXPR) @@ -7279,6 +7339,8 @@ c_parser_postfix_expression (c_parser *parser) if (expr.original_code != C_MAYBE_CONST_EXPR) expr.original_code = ERROR_MARK; /* Don't change EXPR.ORIGINAL_TYPE. */ + location_t loc_close_paren = c_parser_peek_token (parser)->location; + set_c_expr_source_range (&expr, loc_open_paren, loc_close_paren); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } @@ -7869,6 +7931,8 @@ c_parser_postfix_expression_after_primary (c_parser *parser, vec<tree, va_gc> *exprlist; vec<tree, va_gc> *origtypes = NULL; vec<location_t> arg_loc = vNULL; + location_t start; + location_t finish; while (true) { @@ -7905,7 +7969,10 @@ c_parser_postfix_expression_after_primary (c_parser *parser, { c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); + start = expr.src_range.m_start; + finish = parser->tokens_buf[0].range.m_finish; // FIXME: better access API to last token expr.value = build_array_ref (op_loc, expr.value, idx); + set_c_expr_source_range (&expr, start, finish); } } expr.original_code = ERROR_MARK; @@ -7948,9 +8015,13 @@ c_parser_postfix_expression_after_primary (c_parser *parser, "%<memset%> used with constant zero length parameter; " "this could be due to transposed parameters"); + start = expr.src_range.m_start; + finish = parser->tokens_buf[0].range.m_finish; // FIXME: better access API to last token expr.value = c_build_function_call_vec (expr_loc, arg_loc, expr.value, exprlist, origtypes); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; if (TREE_CODE (expr.value) == INTEGER_CST && TREE_CODE (orig_expr.value) == FUNCTION_DECL @@ -7979,8 +8050,11 @@ c_parser_postfix_expression_after_primary (c_parser *parser, expr.original_type = NULL; return expr; } + start = expr.src_range.m_start; + finish = c_parser_peek_token (parser)->range.m_finish; c_parser_consume_token (parser); expr.value = build_component_ref (op_loc, expr.value, ident); + set_c_expr_source_range (&expr, start, finish); expr.original_code = ERROR_MARK; if (TREE_CODE (expr.value) != COMPONENT_REF) expr.original_type = NULL; @@ -8008,12 +8082,15 @@ c_parser_postfix_expression_after_primary (c_parser *parser, expr.original_type = NULL; return expr; } + start = expr.src_range.m_start; + finish = c_parser_peek_token (parser)->range.m_finish; c_parser_consume_token (parser); expr.value = build_component_ref (op_loc, build_indirect_ref (op_loc, expr.value, RO_ARROW), ident); + set_c_expr_source_range (&expr, start, finish); expr.original_code = ERROR_MARK; if (TREE_CODE (expr.value) != COMPONENT_REF) expr.original_type = NULL; @@ -8029,6 +8106,8 @@ c_parser_postfix_expression_after_primary (c_parser *parser, break; case CPP_PLUS_PLUS: /* Postincrement. */ + start = expr.src_range.m_start; + finish = c_parser_peek_token (parser)->range.m_finish; c_parser_consume_token (parser); /* If the expressions have array notations, we expand them. */ if (flag_cilkplus @@ -8040,11 +8119,14 @@ c_parser_postfix_expression_after_primary (c_parser *parser, expr.value = build_unary_op (op_loc, POSTINCREMENT_EXPR, expr.value, 0); } + set_c_expr_source_range (&expr, start, finish); expr.original_code = ERROR_MARK; expr.original_type = NULL; break; case CPP_MINUS_MINUS: /* Postdecrement. */ + start = expr.src_range.m_start; + finish = c_parser_peek_token (parser)->range.m_finish; c_parser_consume_token (parser); /* If the expressions have array notations, we expand them. */ if (flag_cilkplus @@ -8056,6 +8138,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, expr.value = build_unary_op (op_loc, POSTDECREMENT_EXPR, expr.value, 0); } + set_c_expr_source_range (&expr, start, finish); expr.original_code = ERROR_MARK; expr.original_type = NULL; break; diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 667529a..9453caf 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -132,6 +132,9 @@ struct c_expr The type of an enum constant is a plain integer type, but this field will be the enum type. */ tree original_type; + + /* FIXME. */ + source_range src_range; }; /* Type alias for struct c_expr. This allows to use the structure @@ -709,4 +712,12 @@ extern void pedwarn_c90 (location_t, int opt, const char *, ...) extern bool pedwarn_c99 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); +extern void +set_c_expr_source_range (c_expr *expr, + location_t start, location_t finish); + +extern void +set_c_expr_source_range (c_expr *expr, + source_range src_range); + #endif /* ! GCC_C_TREE_H */ diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 3b26231..8f3e0a8 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -3395,6 +3395,12 @@ parser_build_unary_op (location_t loc, enum tree_code code, struct c_expr arg) overflow_warning (loc, result.value); } + /* We are typically called when parsing a prefix token at LOC acting on + ARG. Reflect this by updating the source range of the result to + start at LOC and end at the end of ARG. */ + set_c_expr_source_range (&result, + loc, arg.src_range.m_finish); + return result; } @@ -3432,6 +3438,10 @@ parser_build_binary_op (location_t location, enum tree_code code, if (location != UNKNOWN_LOCATION) protected_set_expr_location (result.value, location); + set_c_expr_source_range (&result, + arg1.src_range.m_start, + arg2.src_range.m_finish); + /* Check for cases such as x+y<<z which users are likely to misinterpret. */ if (warn_parentheses) diff --git a/gcc/gcc-rich-location.c b/gcc/gcc-rich-location.c new file mode 100644 index 0000000..b0ec47b --- /dev/null +++ b/gcc/gcc-rich-location.c @@ -0,0 +1,86 @@ +/* Implementation of gcc_rich_location class + Copyright (C) 2014-2015 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "hash-set.h" +#include "machmode.h" +#include "vec.h" +#include "double-int.h" +#include "input.h" +#include "alias.h" +#include "symtab.h" +#include "wide-int.h" +#include "inchash.h" +#include "tree-core.h" +#include "tree.h" +#include "diagnostic-core.h" +#include "gcc-rich-location.h" +#include "print-tree.h" +#include "pretty-print.h" +#include "intl.h" +#include "cpplib.h" +#include "diagnostic.h" + +/* Extract any source range information from EXPR and write it + to *R. */ + +static bool +get_range_for_expr (tree expr, location_range *r) +{ + if (EXPR_HAS_RANGE (expr)) + { + source_range sr = EXPR_LOCATION_RANGE (expr); + + /* Do we have meaningful data? */ + if (sr.m_start && sr.m_finish) + { + r->m_start = expand_location (sr.m_start); + r->m_finish = expand_location (sr.m_finish); + return true; + } + } + + return false; +} + +/* Add a range to the rich_location, covering expression EXPR. */ + +void +gcc_rich_location::add_expr (tree expr) +{ + gcc_assert (expr); + + location_range r; + r.m_show_caret_p = false; + if (get_range_for_expr (expr, &r)) + add_range (&r); +} + +/* If T is an expression, add a range for it to the rich_location. */ + +void +gcc_rich_location::maybe_add_expr (tree t) +{ + if (EXPR_P (t)) + add_expr (t); +} diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h new file mode 100644 index 0000000..c82cbf1 --- /dev/null +++ b/gcc/gcc-rich-location.h @@ -0,0 +1,47 @@ +/* Declarations relating to class gcc_rich_location + Copyright (C) 2014-2015 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_RICH_LOCATION_H +#define GCC_RICH_LOCATION_H + +/* A gcc_rich_location is libcpp's rich_location with additional + helper methods for working with gcc's types. */ +class gcc_rich_location : public rich_location +{ + public: + /* Constructors. */ + + /* Constructing from a location. */ + gcc_rich_location (source_location loc) : + rich_location (loc) {} + + /* Constructing from a source_range. */ + gcc_rich_location (source_range src_range) : + rich_location (src_range) {} + + + /* Methods for adding ranges via gcc entities. */ + void + add_expr (tree expr); + + void + maybe_add_expr (tree t); +}; + +#endif /* GCC_RICH_LOCATION_H */ diff --git a/gcc/gimple.h b/gcc/gimple.h index 91c26b6..ba8f410 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -1709,11 +1709,7 @@ gimple_block (const gimple *g) static inline void gimple_set_block (gimple *g, tree block) { - if (block) - g->location = - COMBINE_LOCATION_DATA (line_table, g->location, block); - else - g->location = LOCATION_LOCUS (g->location); + g->location = set_block (g->location, block); } diff --git a/gcc/print-tree.c b/gcc/print-tree.c index ea50056..8b3794a 100644 --- a/gcc/print-tree.c +++ b/gcc/print-tree.c @@ -936,6 +936,27 @@ print_node (FILE *file, const char *prefix, tree node, int indent) expanded_location xloc = expand_location (EXPR_LOCATION (node)); indent_to (file, indent+4); fprintf (file, "%s:%d:%d", xloc.file, xloc.line, xloc.column); + + /* Print the range, if any */ + source_range r = EXPR_LOCATION_RANGE (node); + if (r.m_start) + { + xloc = expand_location (r.m_start); + fprintf (file, " start: %s:%d:%d", xloc.file, xloc.line, xloc.column); + } + else + { + fprintf (file, " start: unknown"); + } + if (r.m_finish) + { + xloc = expand_location (r.m_finish); + fprintf (file, " finish: %s:%d:%d", xloc.file, xloc.line, xloc.column); + } + else + { + fprintf (file, " finish: unknown"); + } } fprintf (file, ">"); diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c new file mode 100644 index 0000000..5485aaf --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c @@ -0,0 +1,422 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdiagnostics-show-caret" } */ + +/* This is a collection of unittests to verify that we're correctly + capturing the source code ranges of various kinds of expression. + + It uses the various "diagnostic_test_*_expression_range_plugin" + plugins which handles "__emit_expression_range" by generating a warning + at the given source range of the input argument. Each of the + different plugins do this at a different phase of the internal + representation (tree, gimple, etc), so we can verify that the + source code range information is valid at each phase. + + We want to accept an expression of any type. To do this in C, we + use variadic arguments, but C requires at least one argument before + the ellipsis, so we have a dummy one. */ + +extern void __emit_expression_range (int dummy, ...); + +int global; + +void test_parentheses (int a, int b) +{ + __emit_expression_range (0, (a + b) ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, (a + b) ); + ~~~^~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, (a + b) * (a - b) ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, (a + b) * (a - b) ); + ~~~~~~~~^~~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, !(a && b) ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, !(a && b) ); + ^~~~~~~~~ + { dg-end-multiline-output "" } */ +} + +/* Postfix expressions. ************************************************/ + +void test_array_reference (int *arr) +{ + __emit_expression_range (0, arr[100] ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, arr[100] ); + ~~~^~~~~ + { dg-end-multiline-output "" } */ +} + +int test_function_call (int p, int q, int r) +{ + __emit_expression_range (0, test_function_call (p, q, r) ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, test_function_call (p, q, r) ); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + return 0; +} + +struct test_struct +{ + int field; +}; + +int test_structure_references (struct test_struct *ptr) +{ + struct test_struct local; + local.field = 42; + + __emit_expression_range (0, local.field ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, local.field ); + ~~~~~^~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, ptr->field ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, ptr->field ); + ~~~^~~~~~~ + { dg-end-multiline-output "" } */ +} + +int test_postfix_incdec (int i) +{ + __emit_expression_range (0, i++ ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, i++ ); + ~^~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, i-- ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, i-- ); + ~^~ + { dg-end-multiline-output "" } */ +} + +/* Unary operators. ****************************************************/ + +int test_prefix_incdec (int i) +{ + __emit_expression_range (0, ++i ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, ++i ); + ^~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, --i ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, --i ); + ^~~ + { dg-end-multiline-output "" } */ +} + +void test_address_operator (void) +{ + __emit_expression_range (0, &global ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, &global ); + ^~~~~~~ + { dg-end-multiline-output "" } */ +} + +void test_indirection (int *ptr) +{ + __emit_expression_range (0, *ptr ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, *ptr ); + ^~~~ + { dg-end-multiline-output "" } */ +} + +void test_unary_minus (int i) +{ + __emit_expression_range (0, -i ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, -i ); + ^~ + { dg-end-multiline-output "" } */ +} + +void test_ones_complement (int i) +{ + __emit_expression_range (0, ~i ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, ~i ); + ^~ + { dg-end-multiline-output "" } */ +} + +void test_logical_negation (int flag) +{ + __emit_expression_range (0, !flag ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, !flag ); + ^~~~~ + { dg-end-multiline-output "" } */ +} + +/* Casts. ****************************************************/ + +void test_cast (void *ptr) +{ + __emit_expression_range (0, (int *)ptr ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, (int *)ptr ); + ^~~~~~~~~~ + { dg-end-multiline-output "" } */ + +} + +/* Binary operators. *******************************************/ + +void test_multiplicative_operators (int lhs, int rhs) +{ + __emit_expression_range (0, lhs * rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs * rhs ); + ~~~~^~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, lhs / rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs / rhs ); + ~~~~^~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, lhs % rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs % rhs ); + ~~~~^~~~~ + { dg-end-multiline-output "" } */ +} + +void test_additive_operators (int lhs, int rhs) +{ + __emit_expression_range (0, lhs + rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs + rhs ); + ~~~~^~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, lhs - rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs - rhs ); + ~~~~^~~~~ + { dg-end-multiline-output "" } */ +} + +void test_shift_operators (int lhs, int rhs) +{ + __emit_expression_range (0, lhs << rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs << rhs ); + ~~~~^~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, lhs >> rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs >> rhs ); + ~~~~^~~~~~ + { dg-end-multiline-output "" } */ +} + +void test_relational_operators (int lhs, int rhs) +{ + __emit_expression_range (0, lhs < rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs < rhs ); + ~~~~^~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, lhs > rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs > rhs ); + ~~~~^~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, lhs <= rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs <= rhs ); + ~~~~^~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, lhs >= rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs >= rhs ); + ~~~~^~~~~~ + { dg-end-multiline-output "" } */ +} + +void test_equality_operators (int lhs, int rhs) +{ + __emit_expression_range (0, lhs == rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs == rhs ); + ~~~~^~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, lhs != rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs != rhs ); + ~~~~^~~~~~ + { dg-end-multiline-output "" } */ +} + +void test_bitwise_binary_operators (int lhs, int rhs) +{ + __emit_expression_range (0, lhs & rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs & rhs ); + ~~~~^~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, lhs ^ rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs ^ rhs ); + ~~~~^~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, lhs | rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs | rhs ); + ~~~~^~~~~ + { dg-end-multiline-output "" } */ +} + +void test_logical_operators (int lhs, int rhs) +{ + __emit_expression_range (0, lhs && rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs && rhs ); + ~~~~^~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, lhs || rhs ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, lhs || rhs ); + ~~~~^~~~~~ + { dg-end-multiline-output "" } */ +} + +/* Conditional operator. *******************************************/ + +void test_conditional_operators (int flag, int on_true, int on_false) +{ + __emit_expression_range (0, flag ? on_true : on_false ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, flag ? on_true : on_false ); + ~~~~~~~~~~~~~~~^~~~~~~~~~ + { dg-end-multiline-output "" } */ +} + +/* Assignment expressions. *******************************************/ + +void test_assignment_expressions (int dest, int other) +{ + __emit_expression_range (0, dest = other ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, dest = other ); + ~~~~~^~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, dest *= other ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, dest *= other ); + ~~~~~^~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, dest /= other ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, dest /= other ); + ~~~~~^~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, dest %= other ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, dest %= other ); + ~~~~~^~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, dest += other ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, dest += other ); + ~~~~~^~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, dest -= other ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, dest -= other ); + ~~~~~^~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, dest <<= other ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, dest <<= other ); + ~~~~~^~~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, dest >>= other ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, dest >>= other ); + ~~~~~^~~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, dest &= other ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, dest &= other ); + ~~~~~^~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, dest ^= other ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, dest ^= other ); + ~~~~~^~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, dest |= other ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, dest |= other ); + ~~~~~^~~~~~~~ + { dg-end-multiline-output "" } */ +} + +/* Comma operator. *******************************************/ + +void test_comma_operator (int a, int b) +{ + __emit_expression_range (0, (a++, a + b) ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, (a++, a + b) ); + ~~~~^~~~~~~~ + { dg-end-multiline-output "" } */ +} + +/* Examples of non-trivial expressions. ****************************/ + +extern double sqrt (double x); + +void test_quadratic (double a, double b, double c) +{ + __emit_expression_range (0, b * b - 4 * a * c ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, b * b - 4 * a * c ); + ~~~~~~^~~~~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, + (-b + sqrt (b * b - 4 * a * c)) + / (2 * a)); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + (-b + sqrt (b * b - 4 * a * c)) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + / (2 * a)); + ^~~~~~~~~ + { dg-end-multiline-output "" } */ + +} diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c new file mode 100644 index 0000000..ef7d13f --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c @@ -0,0 +1,159 @@ +/* This plugin verifies the source-code location ranges of + expressions, at the pre-gimplification tree stage. */ +/* { dg-options "-O" } */ + +#include "gcc-plugin.h" +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "stringpool.h" +#include "toplev.h" +#include "basic-block.h" +#include "hash-table.h" +#include "vec.h" +#include "ggc.h" +#include "basic-block.h" +#include "tree-ssa-alias.h" +#include "internal-fn.h" +#include "gimple-fold.h" +#include "tree-eh.h" +#include "gimple-expr.h" +#include "is-a.h" +#include "gimple.h" +#include "gimple-iterator.h" +#include "tree.h" +#include "tree-pass.h" +#include "intl.h" +#include "plugin-version.h" +#include "diagnostic.h" +#include "context.h" +#include "gcc-rich-location.h" +#include "print-tree.h" + +/* + Hack: fails with linker error: +./diagnostic_plugin_test_tree_expression_range.so: undefined symbol: _ZN17gcc_rich_location8add_exprEP9tree_node + since nothing in the tree is using gcc_rich_location::add_expr yet. + + I've tried various workarounds (adding DEBUG_FUNCTION to the + method, taking its address), but can't seem to fix it that way. + So as a nasty workaround, the following material is copied&pasted + from gcc-rich-location.c: */ + +static bool +get_range_for_expr (tree expr, location_range *r) +{ + if (EXPR_HAS_RANGE (expr)) + { + source_range sr = EXPR_LOCATION_RANGE (expr); + + /* Do we have meaningful data? */ + if (sr.m_start && sr.m_finish) + { + r->m_start = expand_location (sr.m_start); + r->m_finish = expand_location (sr.m_finish); + return true; + } + } + + return false; +} + +/* Add a range to the rich_location, covering expression EXPR. */ + +void +gcc_rich_location::add_expr (tree expr) +{ + gcc_assert (expr); + + location_range r; + r.m_show_caret_p = false; + if (get_range_for_expr (expr, &r)) + add_range (&r); +} + +/* FIXME: end of material taken from gcc-rich-location.c */ + + +int plugin_is_GPL_compatible; + +static void +emit_warning (rich_location *richloc) +{ + if (richloc->get_num_locations () < 2) + { + error_at_rich_loc (richloc, "range not found"); + return; + } + + location_range *range = richloc->get_range (1); + warning_at_rich_loc (richloc, 0, + "tree range %i:%i-%i:%i", + range->m_start.line, + range->m_start.column, + range->m_finish.line, + range->m_finish.column); +} + +tree +cb_walk_tree_fn (tree * tp, int * walk_subtrees, + void * data ATTRIBUTE_UNUSED) +{ + if (TREE_CODE (*tp) != CALL_EXPR) + return NULL_TREE; + + tree call_expr = *tp; + tree fn = CALL_EXPR_FN (call_expr); + if (TREE_CODE (fn) != ADDR_EXPR) + return NULL_TREE; + fn = TREE_OPERAND (fn, 0); + if (TREE_CODE (fn) != FUNCTION_DECL) + return NULL_TREE; + if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fn)), "__emit_expression_range")) + return NULL_TREE; + + /* Get arg 1; print it! */ + //debug_tree (call_expr); + + tree arg = CALL_EXPR_ARG (call_expr, 1); + //debug_tree (arg); + + gcc_rich_location richloc (EXPR_LOCATION (arg)); + richloc.add_expr (arg); + emit_warning (&richloc); + + return NULL_TREE; // should we be setting *walk_subtrees? +} + +static void +callback (void *gcc_data, void *user_data) +{ + //fprintf (stdout, "callback called!\n"); + tree fndecl = (tree)gcc_data; + + /* FIXME: is this actually going to be valid on all frontends + before genericize? */ + walk_tree (&DECL_SAVED_TREE (fndecl), cb_walk_tree_fn, NULL, NULL); +} + +int +plugin_init (struct plugin_name_args *plugin_info, + struct plugin_gcc_version *version) +{ + struct register_pass_info pass_info; + const char *plugin_name = plugin_info->base_name; + int argc = plugin_info->argc; + struct plugin_argument *argv = plugin_info->argv; + + if (!plugin_default_version_check (version, &gcc_version)) + return 1; + + register_callback (plugin_name, + PLUGIN_PRE_GENERICIZE, + callback, + NULL); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp index 941bccc..b7efcf5 100644 --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp @@ -66,6 +66,8 @@ set plugin_test_list [list \ { diagnostic_plugin_test_show_locus.c \ diagnostic-test-show-locus-bw.c \ diagnostic-test-show-locus-color.c } \ + { diagnostic_plugin_test_tree_expression_range.c \ + diagnostic-test-expressions-1.c } \ ] foreach plugin_test $plugin_test_list { diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 807d96f..e605b0b 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -6738,10 +6738,7 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb, continue; if (d->orig_block == NULL_TREE || block == d->orig_block) { - if (d->new_block == NULL_TREE) - locus = LOCATION_LOCUS (locus); - else - locus = COMBINE_LOCATION_DATA (line_table, locus, d->new_block); + locus = set_block (locus, d->new_block); gimple_phi_arg_set_location (phi, i, locus); } } @@ -6801,9 +6798,7 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb, tree block = LOCATION_BLOCK (e->goto_locus); if (d->orig_block == NULL_TREE || block == d->orig_block) - e->goto_locus = d->new_block ? - COMBINE_LOCATION_DATA (line_table, e->goto_locus, d->new_block) : - LOCATION_LOCUS (e->goto_locus); + e->goto_locus = set_block (e->goto_locus, d->new_block); } } diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index abaea3f..d98b7d2 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -2352,10 +2352,7 @@ copy_phis_for_bb (basic_block bb, copy_body_data *id) tree *n; n = id->decl_map->get (LOCATION_BLOCK (locus)); gcc_assert (n); - if (*n) - locus = COMBINE_LOCATION_DATA (line_table, locus, *n); - else - locus = LOCATION_LOCUS (locus); + locus = set_block (locus, *n); } else locus = LOCATION_LOCUS (locus); diff --git a/gcc/tree.c b/gcc/tree.c index 84fd34d..9e91d2c 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -11659,10 +11659,7 @@ tree_set_block (tree t, tree b) if (IS_EXPR_CODE_CLASS (c)) { - if (b) - t->exp.locus = COMBINE_LOCATION_DATA (line_table, t->exp.locus, b); - else - t->exp.locus = LOCATION_LOCUS (t->exp.locus); + t->exp.locus = set_block (t->exp.locus, b); } else gcc_unreachable (); @@ -13646,5 +13643,40 @@ nonnull_arg_p (const_tree arg) return false; } +void +set_source_range (tree *expr, location_t start, location_t finish) +{ + source_range src_range; + src_range.m_start = start; + src_range.m_finish = finish; + set_source_range (expr, src_range); +} + +void +set_source_range (tree *expr, source_range src_range) +{ + if (!EXPR_P (*expr)) + return; + + location_t adhoc = COMBINE_LOCATION_DATA (line_table, + EXPR_LOCATION (*expr), + src_range, + NULL /* FIXME */); + SET_EXPR_LOCATION (*expr, adhoc); +} + +location_t +set_block (location_t loc, tree block) +{ + source_range src_range; + if (IS_ADHOC_LOC (loc)) + /* FIXME: can we update in-place? */ + src_range = get_range_from_adhoc_loc (line_table, loc); + else + src_range = source_range::from_location (loc); + + return COMBINE_LOCATION_DATA (line_table, loc, src_range, block); +} + #include "gt-tree.h" diff --git a/gcc/tree.h b/gcc/tree.h index e500151..2cfbf30 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1066,10 +1066,28 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, #define EXPR_FILENAME(NODE) LOCATION_FILE (EXPR_CHECK ((NODE))->exp.locus) #define EXPR_LINENO(NODE) LOCATION_LINE (EXPR_CHECK (NODE)->exp.locus) +#define CAN_HAVE_RANGE_P(NODE) (CAN_HAVE_LOCATION_P (NODE)) +#define EXPR_LOCATION_RANGE(NODE) (get_expr_source_range (EXPR_CHECK ((NODE)))) + +#define EXPR_HAS_RANGE(NODE) \ + (CAN_HAVE_RANGE_P (NODE) \ + ? EXPR_LOCATION_RANGE (NODE).m_start != UNKNOWN_LOCATION \ + : false) + /* True if a tree is an expression or statement that can have a location. */ #define CAN_HAVE_LOCATION_P(NODE) ((NODE) && EXPR_P (NODE)) +static inline source_range +get_expr_source_range (tree expr) +{ + location_t loc = EXPR_LOCATION (expr); + if (IS_ADHOC_LOC (loc)) + return get_range_from_adhoc_loc (line_table, loc); + else + return source_range::from_location (loc); +} + extern void protected_set_expr_location (tree, location_t); /* In a TARGET_EXPR node. */ @@ -2092,6 +2110,9 @@ extern machine_mode element_mode (const_tree t); #define DECL_IS_BUILTIN(DECL) \ (LOCATION_LOCUS (DECL_SOURCE_LOCATION (DECL)) <= BUILTINS_LOCATION) +#define DECL_LOCATION_RANGE(NODE) \ + (get_decl_source_range (DECL_MINIMAL_CHECK (NODE))) + /* For FIELD_DECLs, this is the RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE node that the field is a member of. For VAR_DECL, PARM_DECL, FUNCTION_DECL, LABEL_DECL, RESULT_DECL, and CONST_DECL @@ -5133,10 +5154,29 @@ type_with_alias_set_p (const_tree t) return false; } +extern void +set_source_range (tree *expr, location_t start, location_t finish); + +extern void +set_source_range (tree *expr, source_range src_range); + +extern location_t +set_block (location_t loc, tree block); + extern void gt_ggc_mx (tree &); extern void gt_pch_nx (tree &); extern void gt_pch_nx (tree &, gt_pointer_operator, void *); extern bool nonnull_arg_p (const_tree); +static inline source_range +get_decl_source_range (tree decl) +{ + location_t loc = DECL_SOURCE_LOCATION (decl); + if (IS_ADHOC_LOC (loc)) + return get_range_from_adhoc_loc (line_table, loc); + else + return source_range::from_location (loc); +} + #endif /* GCC_TREE_H */ diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h index bd73780..8deb798 100644 --- a/libcpp/include/line-map.h +++ b/libcpp/include/line-map.h @@ -499,9 +499,11 @@ struct GTY(()) maps_info_macro { unsigned int cache; }; -/* Data structure to associate an arbitrary data to a source location. */ +/* Data structure to associate a source_range together with an arbitrary + data pointer with a source location. */ struct GTY(()) location_adhoc_data { source_location locus; + source_range src_range; void * GTY((skip)) data; }; @@ -800,10 +802,14 @@ LINEMAPS_LAST_ALLOCATED_MACRO_MAP (const line_maps *set) extern void location_adhoc_data_fini (struct line_maps *); extern source_location get_combined_adhoc_loc (struct line_maps *, - source_location, void *); + source_location, + source_range, + void *); extern void *get_data_from_adhoc_loc (struct line_maps *, source_location); extern source_location get_location_from_adhoc_loc (struct line_maps *, source_location); +extern source_range get_range_from_adhoc_loc (struct line_maps *, + source_location); /* Get whether location LOC is an ad-hoc location. */ @@ -818,9 +824,10 @@ IS_ADHOC_LOC (source_location loc) inline source_location COMBINE_LOCATION_DATA (struct line_maps *set, source_location loc, + source_range src_range, void *block) { - return get_combined_adhoc_loc (set, loc, block); + return get_combined_adhoc_loc (set, loc, src_range, block); } extern void rebuild_location_adhoc_htab (struct line_maps *); diff --git a/libcpp/line-map.c b/libcpp/line-map.c index a6fa782..439157e 100644 --- a/libcpp/line-map.c +++ b/libcpp/line-map.c @@ -69,7 +69,10 @@ location_adhoc_data_hash (const void *l) { const struct location_adhoc_data *lb = (const struct location_adhoc_data *) l; - return (hashval_t) lb->locus + (size_t) lb->data; + return ((hashval_t) lb->locus + + (hashval_t) lb->src_range.m_start + + (hashval_t) lb->src_range.m_finish + + (size_t) lb->data); } /* Compare function for location_adhoc_data hashtable. */ @@ -81,7 +84,10 @@ location_adhoc_data_eq (const void *l1, const void *l2) (const struct location_adhoc_data *) l1; const struct location_adhoc_data *lb2 = (const struct location_adhoc_data *) l2; - return lb1->locus == lb2->locus && lb1->data == lb2->data; + return (lb1->locus == lb2->locus + && lb1->src_range.m_start == lb2->src_range.m_start + && lb1->src_range.m_finish == lb2->src_range.m_finish + && lb1->data == lb2->data); } /* Update the hashtable when location_adhoc_data is reallocated. */ @@ -110,19 +116,20 @@ rebuild_location_adhoc_htab (struct line_maps *set) source_location get_combined_adhoc_loc (struct line_maps *set, - source_location locus, void *data) + source_location locus, + source_range src_range, + void *data) { struct location_adhoc_data lb; struct location_adhoc_data **slot; - linemap_assert (data); - if (IS_ADHOC_LOC (locus)) locus = set->location_adhoc_data_map.data[locus & MAX_SOURCE_LOCATION].locus; if (locus == 0 && data == NULL) return 0; lb.locus = locus; + lb.src_range = src_range; lb.data = data; slot = (struct location_adhoc_data **) htab_find_slot (set->location_adhoc_data_map.htab, &lb, INSERT); @@ -177,6 +184,13 @@ get_location_from_adhoc_loc (struct line_maps *set, source_location loc) return set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].locus; } +source_range +get_range_from_adhoc_loc (struct line_maps *set, source_location loc) +{ + linemap_assert (IS_ADHOC_LOC (loc)); + return set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].src_range; +} + /* Finalize the location_adhoc_data structure. */ void location_adhoc_data_fini (struct line_maps *set) @@ -1478,9 +1492,9 @@ linemap_expand_location (struct line_maps *set, memset (&xloc, 0, sizeof (xloc)); if (IS_ADHOC_LOC (loc)) { - loc = set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].locus; xloc.data = set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].data; + loc = set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].locus; } if (loc < RESERVED_LOCATION_COUNT) -- 1.8.5.3