From 570ed2a08f958a3c82bc7e0fcd5190379815f35f Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 1 Sep 2015 16:12:50 -0400 Subject: [PATCH 16/56] FIXME: C: capture tree ranges for various expressions including: * numberic literals and identifiers * Add the C frontend tree-range unittesting plugin (including the plugin.exp change) (compiles but needs linker hack, no ChangeLog) * C: tree source ranges: generate/unittest tree source ranges for various expressions * * FIXME: c_parser_conditional_expression: bulletproof EXPR_LOCATION_RANGE vs error_mark_node --- gcc/c/c-convert.c | 17 +- gcc/c/c-parser.c | 74 ++- gcc/c/c-typeck.c | 10 + .../gcc.dg/plugin/diagnostic-test-expressions-1.c | 562 +++++++++++++++++++++ .../diagnostic_plugin_test_tree_expression_range.c | 162 ++++++ gcc/testsuite/gcc.dg/plugin/plugin.exp | 2 + 6 files changed, 821 insertions(+), 6 deletions(-) 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/c/c-convert.c b/gcc/c/c-convert.c index f023de9..c419d49 100644 --- a/gcc/c/c-convert.c +++ b/gcc/c/c-convert.c @@ -55,7 +55,8 @@ along with GCC; see the file COPYING3. If not see In tree.c: get_narrower and get_unwidened. */ /* Subroutines of `convert'. */ - +static tree +real_convert (tree type, tree expr); /* Create an expression whose value is that of EXPR, @@ -67,6 +68,20 @@ along with GCC; see the file COPYING3. If not see tree convert (tree type, tree expr) { + tree result = real_convert (type, expr); + if (TREE_CODE (expr) == SOURCE_RANGE) + { + set_source_range (&result, EXPR_LOCATION_RANGE (expr)); + SET_EXPR_LOCATION (result, EXPR_LOCATION (expr)); + } + return result; +} + +/* FIXME. */ + +static tree +real_convert (tree type, tree expr) +{ tree e = expr; enum tree_code code = TREE_CODE (type); const char *invalid_conv_diag; diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 9bb5200..96c4d66 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -6052,6 +6052,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_source_range (&ret.value, + EXPR_LOCATION_RANGE (lhs.value).m_start, + EXPR_LOCATION_RANGE (rhs.value).m_finish); if (code == NOP_EXPR) ret.original_code = MODIFY_EXPR; else @@ -6082,7 +6085,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 ()); @@ -6090,6 +6093,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 = EXPR_LOCATION_RANGE (cond.value).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); @@ -6165,6 +6172,9 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after, ? t1 : NULL); } + set_source_range (&ret.value, + start, + EXPR_LOCATION_RANGE (exp2.value).m_finish); return ret; } @@ -6317,6 +6327,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) @@ -6405,6 +6416,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, switch (ocode) { case TRUTH_ANDIF_EXPR: + src_range = EXPR_LOCATION_RANGE (stack[sp].expr.value); stack[sp].expr = convert_lvalue_to_rvalue (stack[sp].loc, stack[sp].expr, true, true); @@ -6412,8 +6424,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_source_range (&stack[sp].expr.value, src_range); break; case TRUTH_ORIF_EXPR: + src_range = EXPR_LOCATION_RANGE (stack[sp].expr.value); stack[sp].expr = convert_lvalue_to_rvalue (stack[sp].loc, stack[sp].expr, true, true); @@ -6421,6 +6435,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_source_range (&stack[sp].expr.value, src_range); break; default: break; @@ -6489,6 +6504,9 @@ 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_source_range(&ret.value, cast_loc, + EXPR_LOCATION_RANGE (expr.value).m_finish); ret.original_code = ERROR_MARK; ret.original_type = NULL; return ret; @@ -6538,6 +6556,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) @@ -6577,8 +6596,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 = EXPR_LOCATION_RANGE (op.value).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_source_range (&ret.value, op_loc, finish); return ret; case CPP_PLUS: if (!c_dialect_objc () && !in_system_header_at (input_location)) @@ -6666,8 +6687,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++; @@ -6681,6 +6709,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; @@ -6696,17 +6725,19 @@ c_parser_sizeof_expression (c_parser *parser) expr = c_parser_postfix_expression_after_paren_type (parser, type_name, expr_loc); + finish = EXPR_LOCATION_RANGE (expr.value).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_LOCATION_RANGE (expr.value).m_finish; sizeof_expr: c_inhibit_evaluation_warnings--; in_sizeof--; @@ -6714,8 +6745,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, "% 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_source_range (&result.value, start, finish); + return result; } /* Parse an alignof expression. */ @@ -7135,13 +7169,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 src_range = c_parser_peek_token (parser)->range; + 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_source_range (&expr.value, tok_range); loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); if (TREE_CODE (expr.value) == FIXED_CST @@ -7156,6 +7191,7 @@ c_parser_postfix_expression (c_parser *parser) case CPP_CHAR32: case CPP_WCHAR: expr.value = c_parser_peek_token (parser)->value; + set_source_range (&expr.value, tok_range); c_parser_consume_token (parser); break; case CPP_STRING: @@ -7164,6 +7200,7 @@ c_parser_postfix_expression (c_parser *parser) case CPP_WSTRING: case CPP_UTF8STRING: expr.value = c_parser_peek_token (parser)->value; + set_source_range (&expr.value, tok_range); expr.original_code = STRING_CST; c_parser_consume_token (parser); break; @@ -7171,6 +7208,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_source_range (&expr.value, tok_range); c_parser_consume_token (parser); break; case CPP_NAME: @@ -7180,10 +7218,11 @@ c_parser_postfix_expression (c_parser *parser) { tree id = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); - expr.value = build_external_ref (src_range, id, + expr.value = build_external_ref (tok_range, id, (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN), &expr.original_type); + set_source_range (&expr.value, tok_range); break; } case C_ID_CLASSNAME: @@ -7272,6 +7311,7 @@ c_parser_postfix_expression (c_parser *parser) else { /* A parenthesized expression. */ + location_t loc_open_param = 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 +7319,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_param = c_parser_peek_token (parser)->location; + set_source_range (&expr.value, loc_open_param, loc_close_param); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } @@ -7869,6 +7911,8 @@ c_parser_postfix_expression_after_primary (c_parser *parser, vec *exprlist; vec *origtypes = NULL; vec arg_loc = vNULL; + location_t start; + location_t finish; while (true) { @@ -7905,7 +7949,10 @@ c_parser_postfix_expression_after_primary (c_parser *parser, { c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); + start = EXPR_LOCATION_RANGE (expr.value).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_source_range (&expr.value, start, finish); } } expr.original_code = ERROR_MARK; @@ -7948,9 +7995,14 @@ c_parser_postfix_expression_after_primary (c_parser *parser, "% used with constant zero length parameter; " "this could be due to transposed parameters"); + start = EXPR_LOCATION_RANGE (expr.value).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_source_range (&expr.value, + start, finish); + expr.original_code = ERROR_MARK; if (TREE_CODE (expr.value) == INTEGER_CST && TREE_CODE (orig_expr.value) == FUNCTION_DECL @@ -7979,8 +8031,11 @@ c_parser_postfix_expression_after_primary (c_parser *parser, expr.original_type = NULL; return expr; } + start = EXPR_LOCATION_RANGE (expr.value).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_source_range (&expr.value, start, finish); expr.original_code = ERROR_MARK; if (TREE_CODE (expr.value) != COMPONENT_REF) expr.original_type = NULL; @@ -8008,12 +8063,15 @@ c_parser_postfix_expression_after_primary (c_parser *parser, expr.original_type = NULL; return expr; } + start = EXPR_LOCATION_RANGE (expr.value).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_source_range (&expr.value, start, finish); expr.original_code = ERROR_MARK; if (TREE_CODE (expr.value) != COMPONENT_REF) expr.original_type = NULL; @@ -8029,6 +8087,8 @@ c_parser_postfix_expression_after_primary (c_parser *parser, break; case CPP_PLUS_PLUS: /* Postincrement. */ + start = EXPR_LOCATION_RANGE (expr.value).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 +8100,14 @@ c_parser_postfix_expression_after_primary (c_parser *parser, expr.value = build_unary_op (op_loc, POSTINCREMENT_EXPR, expr.value, 0); } + set_source_range (&expr.value, start, finish); expr.original_code = ERROR_MARK; expr.original_type = NULL; break; case CPP_MINUS_MINUS: /* Postdecrement. */ + start = EXPR_LOCATION_RANGE (expr.value).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 +8119,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, expr.value = build_unary_op (op_loc, POSTDECREMENT_EXPR, expr.value, 0); } + set_source_range (&expr.value, start, finish); expr.original_code = ERROR_MARK; expr.original_type = NULL; break; diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 6c60dc8..4123f11 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -3408,6 +3408,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_source_range (&result.value, + loc, EXPR_LOCATION_RANGE (arg.value).m_finish); + return result; } @@ -3445,6 +3451,10 @@ parser_build_binary_op (location_t location, enum tree_code code, if (location != UNKNOWN_LOCATION) protected_set_expr_location (result.value, location); + set_source_range (&result.value, + EXPR_LOCATION_RANGE (arg1.value).m_start, + EXPR_LOCATION_RANGE (arg2.value).m_finish); + /* Check for cases such as x+y<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_plus (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_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 "" } */ +} + +void test_sizeof (int i) +{ + __emit_expression_range (0, sizeof i ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, sizeof i ); + ^~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, sizeof (char) ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, sizeof (char) ); + ^~~~~~~~~~~~~ + { 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..591ac25 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c @@ -0,0 +1,162 @@ +/* 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_caption = NULL; + 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) == SOURCE_RANGE) + 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 1017044..2d2e47e 100644 --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp @@ -68,6 +68,8 @@ set plugin_test_list [list \ diagnostic-test-show-locus-ascii-color.c \ diagnostic-test-show-locus-utf-8-bw.c \ diagnostic-test-show-locus-utf-8-color.c } \ + { diagnostic_plugin_test_tree_expression_range.c \ + diagnostic-test-expressions-1.c } \ ] foreach plugin_test $plugin_test_list { -- 1.8.5.3