@@ -1087,6 +1087,9 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
bool fromref = false;
tree qualified_to;
+ if (expr)
+ STRIP_LOCATION_EXPRS (expr);
+
to = non_reference (to);
if (TREE_CODE (from) == REFERENCE_TYPE)
{
@@ -5768,7 +5771,11 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
case REALPART_EXPR:
case IMAGPART_EXPR:
case ABS_EXPR:
- return cp_build_unary_op (code, arg1, candidates != 0, complain);
+ {
+ tree result = cp_build_unary_op (code, arg1, candidates != 0, complain);
+ protected_set_expr_location (result, loc);
+ return result;
+ }
case ARRAY_REF:
return cp_build_array_ref (input_location, arg1, arg2, complain);
@@ -1460,6 +1460,9 @@ reduced_constant_expression_p (tree t)
return false;
return true;
+ case LOCATION_EXPR:
+ return reduced_constant_expression_p (TREE_OPERAND (t, 0));
+
default:
/* FIXME are we calling this too much? */
return initializer_constant_valid_p (t, TREE_TYPE (t)) != NULL_TREE;
@@ -1479,6 +1482,8 @@ static bool
verify_constant (tree t, bool allow_non_constant, bool *non_constant_p,
bool *overflow_p)
{
+ t = cp_fully_fold (t);
+
if (!*non_constant_p && !reduced_constant_expression_p (t))
{
if (!allow_non_constant)
@@ -3563,6 +3568,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case VIEW_CONVERT_EXPR:
case NOP_EXPR:
case UNARY_PLUS_EXPR:
+ case LOCATION_EXPR:
{
enum tree_code tcode = TREE_CODE (t);
tree oldop = TREE_OPERAND (t, 0);
@@ -3589,7 +3595,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if (op == oldop && tcode != UNARY_PLUS_EXPR)
/* We didn't fold at the top so we could check for ptr-int
conversion. */
- return fold (t);
+ return cp_fully_fold (t);
if (tcode == UNARY_PLUS_EXPR)
r = fold_convert (TREE_TYPE (t), op);
else
@@ -4753,6 +4759,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
case EMPTY_CLASS_EXPR:
return false;
+ case LOCATION_EXPR:
+ return RECUR (TREE_OPERAND (t, 0), want_rval);
+
default:
if (objc_is_property_ref (t))
return false;
@@ -702,6 +702,9 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
case BREAK_STMT:
gcc_unreachable ();
+ case LOCATION_EXPR:
+ gcc_unreachable ();
+
case OMP_FOR:
case OMP_SIMD:
case OMP_DISTRIBUTE:
@@ -1356,6 +1359,13 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
|| TREE_CODE (stmt) == OMP_DISTRIBUTE
|| TREE_CODE (stmt) == OMP_TASKLOOP)
genericize_omp_for_stmt (stmt_p, walk_subtrees, data);
+ else if (TREE_CODE (stmt) == LOCATION_EXPR)
+ {
+ /* Strip away LOCATION_EXPR nodes. */
+ *stmt_p = TREE_OPERAND (stmt, 0);
+ /* *stmt_p has changed, tail recurse to handle it again. */
+ return cp_genericize_r (stmt_p, walk_subtrees, data);
+ }
else if ((flag_sanitize
& (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_VPTR))
&& !wtd->no_sanitize_p)
@@ -2213,6 +2223,10 @@ cp_fold (tree x)
x = fold (x);
break;
+ case LOCATION_EXPR:
+ x = cp_fold (TREE_OPERAND (x, 0));
+ break;
+
default:
return org_x;
}
@@ -306,6 +306,7 @@ cp_common_init_ts (void)
MARK_TS_TYPED (UNARY_RIGHT_FOLD_EXPR);
MARK_TS_TYPED (BINARY_LEFT_FOLD_EXPR);
MARK_TS_TYPED (BINARY_RIGHT_FOLD_EXPR);
+ MARK_TS_TYPED (LOCATION_EXPR);
}
#include "gt-cp-cp-objcp-common.h"
@@ -582,6 +582,12 @@ DEFTREECODE (PARM_CONSTR, "parm_constr", tcc_expression, 2)
DEFTREECODE (CONJ_CONSTR, "conj_constr", tcc_expression, 2)
DEFTREECODE (DISJ_CONSTR, "disj_constr", tcc_expression, 2)
+/* Wrapper used by the C++ frontend during parsing to add a source code
+ location to an expression, either one that doesn't have one (such as
+ an INTEGER_CST), or to a usage of a variable (e.g. PARAM_DECL or
+ VAR_DECL), where we want to record the site in the source where the
+ variable was *used* rather than where it was declared. */
+DEFTREECODE (LOCATION_EXPR, "location_expr", tcc_unary, 1)
/*
Local variables:
@@ -256,6 +256,13 @@ c-common.h, not after.
#define THUNK_FUNCTION_CHECK(NODE) (NODE)
#endif
+/* Language-dependent macro for stripping away location wrapper nodes. */
+
+#define STRIP_LOCATION_EXPRS(EXP) \
+ while (TREE_CODE (EXP) == LOCATION_EXPR) \
+ (EXP) = TREE_OPERAND ((EXP), 0)
+
+
/* Language-dependent contents of an identifier. */
struct GTY(()) lang_identifier {
@@ -271,6 +278,7 @@ struct GTY(()) lang_identifier {
inline lang_identifier*
identifier_p (tree t)
{
+ STRIP_LOCATION_EXPRS (t);
if (TREE_CODE (t) == IDENTIFIER_NODE)
return (lang_identifier*) t;
return NULL;
@@ -2750,6 +2750,10 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
pp_string (pp, M_("*this"));
break;
+ case LOCATION_EXPR:
+ dump_expr (pp, TREE_OPERAND (t, 0), flags);
+ break;
+
/* This list is incomplete, but should suffice for now.
It is very important that `sorry' does not call
`report_error_function'. That could cause an infinite loop. */
@@ -1414,6 +1414,8 @@ make_id_declarator (tree qualifying_scope, tree unqualified_name,
if (qualifying_scope && TYPE_P (qualifying_scope))
qualifying_scope = TYPE_MAIN_VARIANT (qualifying_scope);
+ STRIP_LOCATION_EXPRS (unqualified_name);
+
gcc_assert (identifier_p (unqualified_name)
|| TREE_CODE (unqualified_name) == BIT_NOT_EXPR
|| TREE_CODE (unqualified_name) == TEMPLATE_ID_EXPR);
@@ -1976,7 +1978,7 @@ static tree cp_parser_postfix_open_square_expression
static tree cp_parser_postfix_dot_deref_expression
(cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *, location_t);
static vec<tree, va_gc> *cp_parser_parenthesized_expression_list
- (cp_parser *, int, bool, bool, bool *);
+ (cp_parser *, int, bool, bool, bool *, location_t * = NULL);
/* Values for the second parameter of cp_parser_parenthesized_expression_list. */
enum { non_attr = 0, normal_attr = 1, id_attr = 2 };
static void cp_parser_pseudo_destructor_name
@@ -3665,6 +3667,18 @@ cp_parser_pop_lexer (cp_parser *parser)
cp_lexer_set_source_position_from_token (parser->lexer->next_token);
}
+/* FIXME. */
+static tree
+wrap_with_location (tree value, location_t loc)
+{
+#if 1
+ tree wrapper = build1_loc (loc, LOCATION_EXPR, TREE_TYPE (value), value);
+ return wrapper;
+#else
+ return value;
+#endif
+}
+
/* Lexical conventions [gram.lex] */
/* Parse an identifier. Returns an IDENTIFIER_NODE representing the
@@ -3678,7 +3692,10 @@ cp_parser_identifier (cp_parser* parser)
/* Look for the identifier. */
token = cp_parser_require (parser, CPP_NAME, RT_NAME);
/* Return the value. */
- return token ? token->u.value : error_mark_node;
+ if (token)
+ return token->u.value; // FIXME //use_as_rvalue (token->u.value, token->location); // FIXME: what if an lvalue?
+ else
+ return error_mark_node;
}
/* Parse a sequence of adjacent string constants. Returns a
@@ -3717,6 +3734,8 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
return error_mark_node;
}
+ location_t loc = tok->location;
+
if (cpp_userdef_string_p (tok->type))
{
string_tree = USERDEF_LITERAL_VALUE (tok->u.value);
@@ -3754,11 +3773,13 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
}
else
{
+ location_t last_tok_loc;
gcc_obstack_init (&str_ob);
count = 0;
do
{
+ last_tok_loc = tok->location;
cp_lexer_consume_token (parser->lexer);
count++;
str.text = (const unsigned char *)TREE_STRING_POINTER (string_tree);
@@ -3813,6 +3834,13 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
}
while (cp_parser_is_string_literal (tok));
+ /* A string literal built by concatenation has its caret=start at
+ the start of the initial string, and its finish at the finish of
+ the final string literal. */
+ loc = make_location (loc, loc,
+ get_range_from_loc (line_table,
+ last_tok_loc).m_finish);
+
strs = (cpp_string *) obstack_finish (&str_ob);
}
@@ -3865,7 +3893,11 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
if (count > 1)
obstack_free (&str_ob, 0);
+#if 0
return value;
+#else
+ return wrap_with_location (value, loc);
+#endif
}
/* Look up a literal operator with the name and the exact arguments. */
@@ -4614,7 +4646,7 @@ cp_parser_primary_expression (cp_parser *parser,
if (!cast_p)
cp_parser_non_integral_constant_expression (parser, NIC_FLOAT);
}
- return token->u.value;
+ return wrap_with_location (token->u.value, token->location);
case CPP_CHAR_USERDEF:
case CPP_CHAR16_USERDEF:
@@ -4675,6 +4707,8 @@ cp_parser_primary_expression (cp_parser *parser,
tree expr;
bool saved_greater_than_is_operator_p;
+ location_t open_paren_loc = token->location;
+
/* Consume the `('. */
cp_lexer_consume_token (parser->lexer);
/* Within a parenthesized expression, a `>' token is always
@@ -4719,7 +4753,11 @@ cp_parser_primary_expression (cp_parser *parser,
template-parameter-list now. */
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
+
/* Consume the `)'. */
+ token = cp_lexer_peek_token (parser->lexer);
+ location_t close_paren_loc = token->location;
+ set_source_range (expr, open_paren_loc, close_paren_loc);
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)
&& !cp_parser_uncommitted_to_tentative_parse_p (parser))
cp_parser_skip_to_end_of_statement (parser);
@@ -4760,20 +4798,20 @@ cp_parser_primary_expression (cp_parser *parser,
/* These two are the boolean literals. */
case RID_TRUE:
cp_lexer_consume_token (parser->lexer);
- return boolean_true_node;
+ return wrap_with_location (boolean_true_node, token->location);
case RID_FALSE:
cp_lexer_consume_token (parser->lexer);
- return boolean_false_node;
+ return wrap_with_location (boolean_false_node, token->location);
/* The `__null' literal. */
case RID_NULL:
cp_lexer_consume_token (parser->lexer);
- return null_node;
+ return wrap_with_location (null_node, token->location);
/* The `nullptr' literal. */
case RID_NULLPTR:
cp_lexer_consume_token (parser->lexer);
- return nullptr_node;
+ return wrap_with_location (nullptr_node, token->location);
/* Recognize the `this' keyword. */
case RID_THIS:
@@ -4921,6 +4959,7 @@ cp_parser_primary_expression (cp_parser *parser,
case CPP_TEMPLATE_ID:
case CPP_NESTED_NAME_SPECIFIER:
{
+ id_expression:
tree id_expression;
tree decl;
const char *error_msg;
@@ -4928,7 +4967,6 @@ cp_parser_primary_expression (cp_parser *parser,
bool done;
cp_token *id_expr_token;
- id_expression:
/* Parse the id-expression. */
id_expression
= cp_parser_id_expression (parser,
@@ -6116,6 +6154,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
loc = token->location;
+ location_t start_loc = get_range_from_loc (line_table, loc).m_start;
+
/* Some of the productions are determined by keywords. */
keyword = token->keyword;
switch (keyword)
@@ -6159,7 +6199,10 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
/* And the expression which is being cast. */
cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
expression = cp_parser_expression (parser, & idk, /*cast_p=*/true);
- cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
+ cp_token *close_paren = cp_parser_require (parser, CPP_CLOSE_PAREN,
+ RT_CLOSE_PAREN);
+ location_t end_loc = close_paren ?
+ close_paren->location : UNKNOWN_LOCATION;
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
@@ -6192,6 +6235,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
default:
gcc_unreachable ();
}
+
+ /* Construct a location e.g. :
+ reinterpret_cast <int *> (expr)
+ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ranging from the start of the "*_cast" token to the final closing
+ paren, with the caret at the start. */
+ location_t cp_cast_loc = make_location (start_loc, start_loc, end_loc);
+ protected_set_expr_location (postfix_expression, cp_cast_loc);
}
break;
@@ -6471,6 +6522,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
postfix_expression,
false,
decltype_p);
+ set_source_range (postfix_expression, start_loc,
+ EXPR_LOCATION (postfix_expression));
idk = CP_ID_KIND_NONE;
is_member_access = false;
break;
@@ -6484,6 +6537,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
bool saved_non_integral_constant_expression_p = false;
tsubst_flags_t complain = complain_flags (decltype_p);
vec<tree, va_gc> *args;
+ location_t close_paren_loc;
is_member_access = false;
@@ -6502,7 +6556,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
args = (cp_parser_parenthesized_expression_list
(parser, non_attr,
/*cast_p=*/false, /*allow_expansion_p=*/true,
- /*non_constant_p=*/NULL));
+ /*non_constant_p=*/NULL,
+ /*close_paren_loc=*/&close_paren_loc));
if (is_builtin_constant_p)
{
parser->integral_constant_expression_p
@@ -6644,7 +6699,10 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
koenig_p,
complain);
- protected_set_expr_location (postfix_expression, token->location);
+ location_t combined_loc = make_location (token->location,
+ start_loc,
+ close_paren_loc);
+ protected_set_expr_location (postfix_expression, combined_loc);
/* The POSTFIX_EXPRESSION is certainly no longer an id. */
idk = CP_ID_KIND_NONE;
@@ -6705,7 +6763,9 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
if (pidk_return != NULL)
* pidk_return = idk;
if (member_access_only_p)
- return is_member_access? postfix_expression : error_mark_node;
+ return is_member_access
+ ? postfix_expression
+ : error_mark_node;
else
return postfix_expression;
}
@@ -7107,7 +7167,8 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
int is_attribute_list,
bool cast_p,
bool allow_expansion_p,
- bool *non_constant_p)
+ bool *non_constant_p,
+ location_t *close_paren_loc)
{
vec<tree, va_gc> *expression_list;
bool fold_expr_p = is_attribute_list != non_attr;
@@ -7211,6 +7272,9 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
cp_lexer_consume_token (parser->lexer);
}
+ if (close_paren_loc)
+ *close_paren_loc = cp_lexer_peek_token (parser->lexer)->location;
+
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
{
int ending;
@@ -7611,6 +7675,14 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
/*cast_p=*/false,
/*decltype*/false,
pidk);
+
+ /* Make a location:
+ OP_TOKEN CAST_EXPRESSION
+ ^~~~~~~~~~~~~~~~~~~~~~~~~
+ with start==caret at the operator token, and
+ extending to the end of the cast_expression. */
+ loc = make_location (loc, loc, get_expr_finish (cast_expression));
+
/* Now, build an appropriate representation. */
switch (unary_operator)
{
@@ -7663,6 +7735,8 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
gcc_unreachable ();
}
+ protected_set_expr_location (expression, loc);
+
if (non_constant_p != NIC_NONE
&& cp_parser_non_integral_constant_expression (parser,
non_constant_p))
@@ -7726,6 +7800,8 @@ cp_parser_new_expression (cp_parser* parser)
tree nelts = NULL_TREE;
tree ret;
+ location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
+
/* Look for the optional `::' operator. */
global_scope_p
= (cp_parser_global_scope_opt (parser,
@@ -7820,6 +7896,17 @@ cp_parser_new_expression (cp_parser* parser)
if (initializer != NULL)
release_tree_vector (initializer);
+ /* Construct a location e.g.:
+ ptr = new int[100]
+ ^~~~~~~~~~~~
+ with caret == start at the start of the "new" token, and the end
+ at the end of the final token we consumed. */
+ cp_token *end_tok = cp_lexer_previous_token (parser->lexer);
+ location_t end_loc = get_range_from_loc (line_table,
+ end_tok->location).m_finish;
+ location_t combined_loc = make_location (start_loc, start_loc, end_loc);
+ protected_set_expr_location (ret, combined_loc);
+
return ret;
}
@@ -8213,7 +8300,9 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
parser->type_definition_forbidden_message
= G_("types may not be defined in casts");
/* Consume the `('. */
- cp_lexer_consume_token (parser->lexer);
+ cp_token *open_paren = cp_lexer_consume_token (parser->lexer);
+ location_t open_paren_loc = open_paren->location;
+
/* A very tricky bit is that `(struct S) { 3 }' is a
compound-literal (which we permit in C++ as an extension).
But, that construct is not a cast-expression -- it is a
@@ -8315,7 +8404,15 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
return error_mark_node;
/* Perform the cast. */
- expr = build_c_cast (input_location, type, expr);
+ /* Make a location:
+ (TYPE) EXPR
+ ^~~~~~~~~~~
+ with start==caret at the open paren, extending to the
+ end of "expr". */
+ location_t cast_loc = make_location (open_paren_loc,
+ open_paren_loc,
+ get_expr_finish (expr));
+ expr = build_c_cast (cast_loc, type, expr);
return expr;
}
}
@@ -8558,6 +8655,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
maybe_constant_value (rhs));
overload = NULL;
+
+ location_t combined_loc = make_location (current.loc,
+ get_expr_start (current.lhs),
+ get_expr_finish (rhs));
+
/* ??? Currently we pass lhs_type == ERROR_MARK and rhs_type ==
ERROR_MARK for everything that is not a binary expression.
This makes warn_about_parentheses miss some warnings that
@@ -8568,18 +8670,18 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
if (no_toplevel_fold_p
&& lookahead_prec <= current.prec
&& sp == stack)
- current.lhs = build2 (current.tree_type,
- TREE_CODE_CLASS (current.tree_type)
- == tcc_comparison
- ? boolean_type_node : TREE_TYPE (current.lhs),
- current.lhs, rhs);
+ current.lhs = build2_loc (combined_loc,
+ current.tree_type,
+ TREE_CODE_CLASS (current.tree_type)
+ == tcc_comparison
+ ? boolean_type_node : TREE_TYPE (current.lhs),
+ current.lhs, rhs);
else
- current.lhs = build_x_binary_op (current.loc, current.tree_type,
+ current.lhs = build_x_binary_op (combined_loc, current.tree_type,
current.lhs, current.lhs_type,
rhs, rhs_type, &overload,
complain_flags (decltype_p));
current.lhs_type = current.tree_type;
- protected_set_expr_location (current.lhs, current.loc);
/* If the binary operator required the use of an overloaded operator,
then this expression cannot be an integral constant-expression.
@@ -8662,6 +8764,15 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
c_inhibit_evaluation_warnings -=
folded_logical_or_expr == truthvalue_true_node;
+ /* Make a location:
+ LOGICAL_OR_EXPR ? EXPR : ASSIGNMENT_EXPR
+ ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
+ with the caret at the "?", ranging from the start of
+ the logical_or_expr to the end of the assignment_expr. */
+ loc = make_location (loc,
+ get_expr_start (logical_or_expr),
+ get_expr_finish (assignment_expr));
+
/* Build the conditional-expression. */
return build_x_conditional_expr (loc, logical_or_expr,
expr,
@@ -8717,7 +8828,8 @@ cp_parser_assignment_expression (cp_parser* parser, cp_id_kind * pidk,
location_t saved_input_location;
/* Parse the right-hand side of the assignment. */
- tree rhs = cp_parser_initializer_clause (parser, &non_constant_p);
+ tree rhs = cp_parser_initializer_clause (parser,
+ &non_constant_p);
if (BRACE_ENCLOSED_INITIALIZER_P (rhs))
maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
@@ -8728,13 +8840,22 @@ cp_parser_assignment_expression (cp_parser* parser, cp_id_kind * pidk,
NIC_ASSIGNMENT))
return error_mark_node;
/* Build the assignment expression. Its default
- location is the location of the '=' token. */
+ location:
+ LHS = RHS
+ ~~~~^~~~~
+ is the location of the '=' token as the
+ caret, ranging from the start of the lhs to the
+ end of the rhs. */
saved_input_location = input_location;
+ loc = make_location (loc,
+ get_expr_start (expr),
+ get_expr_finish (rhs));
input_location = loc;
expr = build_x_modify_expr (loc, expr,
assignment_operator,
rhs,
complain_flags (decltype_p));
+ protected_set_expr_location (expr, loc);
input_location = saved_input_location;
}
}
@@ -8875,9 +8996,17 @@ cp_parser_expression (cp_parser* parser, cp_id_kind * pidk,
if (!expression)
expression = assignment_expression;
else
- expression = build_x_compound_expr (loc, expression,
- assignment_expression,
- complain_flags (decltype_p));
+ {
+ /* Create a location with caret at the comma, ranging
+ from the start of the LHS to the end of the RHS. */
+ loc = make_location (loc,
+ get_expr_start (expression),
+ get_expr_finish (assignment_expression));
+ expression = build_x_compound_expr (loc, expression,
+ assignment_expression,
+ complain_flags (decltype_p));
+ //expression.set_location (loc);
+ }
/* If the next token is not a comma, or we're in a fold-expression, then
we are done with the expression. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)
@@ -12501,6 +12630,7 @@ cp_parser_linkage_specification (cp_parser* parser)
/* Look for the string-literal. */
linkage = cp_parser_string_literal (parser, false, false);
+ STRIP_LOCATION_EXPRS (linkage);
/* Transform the literal into an identifier. If the literal is a
wide-character string, or contains embedded NULs, then we can't
@@ -13333,6 +13463,9 @@ cp_parser_operator (cp_parser* parser)
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
+
+ location_t start_loc = token->location;
+
/* Figure out which operator we have. */
switch (token->type)
{
@@ -13349,7 +13482,7 @@ cp_parser_operator (cp_parser* parser)
break;
/* Consume the `new' or `delete' token. */
- cp_lexer_consume_token (parser->lexer);
+ location_t end_loc = cp_lexer_consume_token (parser->lexer)->location;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
@@ -13360,7 +13493,8 @@ cp_parser_operator (cp_parser* parser)
/* Consume the `[' token. */
cp_lexer_consume_token (parser->lexer);
/* Look for the `]' token. */
- cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
+ end_loc = cp_parser_require (parser, CPP_CLOSE_SQUARE,
+ RT_CLOSE_SQUARE)->location;
id = ansi_opname (op == NEW_EXPR
? VEC_NEW_EXPR : VEC_DELETE_EXPR);
}
@@ -13368,7 +13502,9 @@ cp_parser_operator (cp_parser* parser)
else
id = ansi_opname (op);
- return id;
+ location_t loc = make_location (start_loc, start_loc, end_loc);
+
+ return id; // FIXME: what to do about loc
}
case CPP_PLUS:
@@ -13614,7 +13750,7 @@ cp_parser_operator (cp_parser* parser)
id = error_mark_node;
}
- return id;
+ return id; // FIXME: cp_expr (id, start_loc);
}
/* Parse a template-declaration.
@@ -17357,6 +17493,7 @@ cp_parser_using_declaration (cp_parser* parser,
decl = cp_parser_lookup_name_simple (parser,
identifier,
token->location);
+ STRIP_LOCATION_EXPRS (decl);
if (decl == error_mark_node)
cp_parser_name_lookup_error (parser, identifier,
decl, NLE_NULL,
@@ -17623,6 +17760,8 @@ cp_parser_asm_definition (cp_parser* parser)
return;
/* Look for the string. */
string = cp_parser_string_literal (parser, false, false);
+ STRIP_LOCATION_EXPRS (string);
+
if (string == error_mark_node)
{
cp_parser_skip_to_closing_parenthesis (parser, true, false,
@@ -20696,6 +20835,7 @@ cp_parser_class_name (cp_parser *parser,
}
decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p);
+ STRIP_LOCATION_EXPRS (decl);
/* If this is a typename, create a TYPENAME_TYPE. */
if (typename_p && decl != error_mark_node)
@@ -22876,6 +23016,7 @@ cp_parser_asm_specification_opt (cp_parser* parser)
/* Look for the string-literal. */
asm_specification = cp_parser_string_literal (parser, false, false);
+ STRIP_LOCATION_EXPRS (asm_specification);
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
@@ -22928,6 +23069,7 @@ cp_parser_asm_operand_list (cp_parser* parser)
name = NULL_TREE;
/* Look for the string-literal. */
string_literal = cp_parser_string_literal (parser, false, false);
+ STRIP_LOCATION_EXPRS (string_literal);
/* Look for the `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
@@ -22976,6 +23118,7 @@ cp_parser_asm_clobber_list (cp_parser* parser)
/* Look for the string literal. */
string_literal = cp_parser_string_literal (parser, false, false);
+ STRIP_LOCATION_EXPRS (string_literal);
/* Add it to the list. */
clobbers = tree_cons (NULL_TREE, string_literal, clobbers);
/* If the next token is not a `,', then the list is
@@ -24317,7 +24460,11 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
maybe_record_typedef_use (decl);
- return decl;
+ if (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == PARM_DECL)
+ return wrap_with_location (decl, name_location);
+ else
+ return decl;
}
/* Like cp_parser_lookup_name, but for use in the typical case where
@@ -2463,7 +2463,12 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
tree
finish_increment_expr (tree expr, enum tree_code code)
{
- return build_x_unary_op (input_location, code, expr, tf_warning_or_error);
+ /* input_location holds the location of the trailing operator token. */
+ tree result = build_x_unary_op (input_location, code, expr,
+ tf_warning_or_error);
+ set_source_range (result, get_expr_start (expr),
+ get_finish (input_location));
+ return result;
}
/* Finish a use of `this'. Returns an expression for `this'. */
@@ -2558,10 +2563,12 @@ finish_pseudo_destructor_expr (tree object, tree scope, tree destructor,
/* Finish an expression of the form CODE EXPR. */
tree
-finish_unary_op_expr (location_t loc, enum tree_code code, tree expr,
+finish_unary_op_expr (location_t op_loc, enum tree_code code, tree expr,
tsubst_flags_t complain)
{
- tree result = build_x_unary_op (loc, code, expr, complain);
+ location_t combined_loc = make_location (op_loc,
+ op_loc, get_expr_finish (expr));
+ tree result = build_x_unary_op (combined_loc, code, expr, complain);
tree result_ovl, expr_ovl;
if (!(complain & tf_warning))
@@ -2581,9 +2588,9 @@ finish_unary_op_expr (location_t loc, enum tree_code code, tree expr,
result_ovl = cp_fully_fold (result_ovl);
if (CONSTANT_CLASS_P (result_ovl) && TREE_OVERFLOW_P (result_ovl))
- overflow_warning (input_location, result_ovl);
+ overflow_warning (combined_loc, result_ovl);
- return result;
+ return result; // cp_expr (result, combined_loc);
}
/* Finish a compound-literal expression. TYPE is the type to which
@@ -3669,7 +3676,7 @@ finish_id_expression (tree id_expression,
}
}
- return decl;
+ return decl; // return use_as_rvalue (decl); // FIXME: is this neeeded?
}
/* Implement the __typeof keyword: Return the type of EXPR, suitable for
@@ -56,6 +56,8 @@ lvalue_kind (const_tree ref)
cp_lvalue_kind op1_lvalue_kind = clk_none;
cp_lvalue_kind op2_lvalue_kind = clk_none;
+ STRIP_LOCATION_EXPRS (ref);
+
/* Expressions of reference type are sometimes wrapped in
INDIRECT_REFs. INDIRECT_REFs are just internal compiler
representation, not part of the language, so we have to look
@@ -3598,6 +3600,7 @@ check_abi_tag_args (tree args, tree name)
for (tree arg = args; arg; arg = TREE_CHAIN (arg))
{
tree elt = TREE_VALUE (arg);
+ STRIP_LOCATION_EXPRS (elt);
if (TREE_CODE (elt) != STRING_CST
|| (!same_type_ignoring_top_level_qualifiers_p
(strip_array_types (TREE_TYPE (elt)),
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see
#include "c-family/c-objc.h"
#include "c-family/c-ubsan.h"
#include "params.h"
+//#include "print-tree.h"
static tree cp_build_addr_expr_strict (tree, tsubst_flags_t);
static tree cp_build_function_call (tree, tree, tsubst_flags_t);
@@ -2435,7 +2436,11 @@ build_class_member_access_expr (tree object, tree member,
member_type = cp_build_qualified_type (member_type, type_quals);
}
- result = build3_loc (input_location, COMPONENT_REF, member_type,
+ location_t combined_loc =
+ make_location (input_location,
+ get_expr_start (object),
+ get_finish (input_location));
+ result = build3_loc (combined_loc, COMPONENT_REF, member_type,
object, member, NULL_TREE);
/* Mark the expression const or volatile, as appropriate. Even
@@ -3669,6 +3674,12 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl,
tree type = typetail ? TREE_VALUE (typetail) : 0;
tree val = (**values)[i];
+#if 0
+ fprintf (stderr, "arg %i at start of loop body\n", i);
+ debug_tree (val);
+ inform (EXPR_LOCATION (val), "arg %i at start of loop body", i);
+#endif
+
if (val == error_mark_node || type == error_mark_node)
return -1;
@@ -3683,12 +3694,14 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl,
return -1;
}
+#if 0
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
Strip such NOP_EXPRs, since VAL is used in non-lvalue context. */
if (TREE_CODE (val) == NOP_EXPR
&& TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0))
&& (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))
val = TREE_OPERAND (val, 0);
+#endif
if (type == 0 || TREE_CODE (type) != REFERENCE_TYPE)
{
@@ -3746,6 +3759,12 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl,
if (typetail)
typetail = TREE_CHAIN (typetail);
+
+#if 0
+ fprintf (stderr, "values[%i] at end of loop body\n", i);
+ debug_tree ((**values)[i]);
+ inform (EXPR_LOCATION ((**values)[i]), "values[%i] at end of loop body", i);
+#endif
}
if (typetail != 0 && typetail != void_list_node)
@@ -4024,7 +4043,9 @@ cp_build_binary_op (location_t location,
}
/* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
+ STRIP_LOCATION_EXPRS (op0);
STRIP_TYPE_NOPS (op0);
+ STRIP_LOCATION_EXPRS (op1);
STRIP_TYPE_NOPS (op1);
/* DTRT if one side is an overloaded function, but complain about it. */
@@ -5102,7 +5123,7 @@ cp_build_binary_op (location_t location,
instrument_expr = ubsan_instrument_shift (location, code, op0, op1);
}
- result = build2 (resultcode, build_type, op0, op1);
+ result = build2_loc (location, resultcode, build_type, op0, op1);
if (final_type != 0)
result = cp_convert (final_type, result, complain);
@@ -5429,7 +5450,7 @@ build_nop (tree type, tree expr)
{
if (type == error_mark_node || error_operand_p (expr))
return expr;
- return build1 (NOP_EXPR, type, expr);
+ return build1_loc (EXPR_LOCATION (expr), NOP_EXPR, type, expr);
}
/* Take the address of ARG, whatever that means under C++ semantics.
@@ -7254,9 +7275,11 @@ build_const_cast (tree type, tree expr, tsubst_flags_t complain)
/* Like cp_build_c_cast, but for the c-common bits. */
tree
-build_c_cast (location_t /*loc*/, tree type, tree expr)
+build_c_cast (location_t loc, tree type, tree expr)
{
- return cp_build_c_cast (type, expr, tf_warning_or_error);
+ tree result = cp_build_c_cast (type, expr, tf_warning_or_error);
+ protected_set_expr_location (result, loc);
+ return result;
}
/* Build an expression representing an explicit C-style cast to type
@@ -7784,7 +7807,10 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
return rval;
}
}
- return cp_build_modify_expr (lhs, modifycode, rhs, complain);
+
+ tree result = cp_build_modify_expr (lhs, modifycode, rhs, complain);
+ protected_set_expr_location (result, loc);
+ return result;
}
/* Helper function for get_delta_difference which assumes FROM is a base
@@ -1740,7 +1740,9 @@ build_x_arrow (location_t loc, tree expr, tsubst_flags_t complain)
return expr;
}
- return cp_build_indirect_ref (last_rval, RO_NULL, complain);
+ tree result = cp_build_indirect_ref (last_rval, RO_NULL, complain);
+ protected_set_expr_location (result, loc);
+ return result;
}
if (complain & tf_error)
@@ -779,7 +779,7 @@ diagnostic_show_locus (diagnostic_context * context,
{
if (!context->show_caret
|| diagnostic_location (diagnostic, 0) <= BUILTINS_LOCATION
- || diagnostic_location (diagnostic, 0) == context->last_location)
+ /*|| diagnostic_location (diagnostic, 0) == context->last_location*/)
return;
context->last_location = diagnostic_location (diagnostic, 0);
new file mode 100644
@@ -0,0 +1,568 @@
+/* { 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;
+
+/* Simple expressions. ************************************************/
+
+void test_literals (void)
+{
+ __emit_expression_range (0, 1066 ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, 1066 );
+ ^~~~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, "hello" ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, "hello" );
+ ^~~~~~~
+ { dg-end-multiline-output "" } */
+}
+
+void test_variables (int param)
+{
+ __emit_expression_range (0, param ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, param );
+ ^~~~~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, global ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, global );
+ ^~~~~~
+ { dg-end-multiline-output "" } */
+}
+
+#if 1
+
+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 "" } */
+
+ __emit_expression_range (0, *(int *)0xdeadbeef ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, *(int *)0xdeadbeef );
+ ^~~~~~~~~~~~~~~~~~
+ { 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 "" } */
+}
+
+/* Literals. **************************************************/
+
+/* We can't test the ranges of literals directly, since the underlying
+ tree nodes don't retain a location. However, we can test that they
+ have ranges during parsing by building compound expressions using
+ them, and verifying the ranges of the compound expressions. */
+
+void test_string_literals (int i)
+{
+ __emit_expression_range (0, "foo"[i] ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, "foo"[i] );
+ ~~~~~~~^
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, &"foo" "bar" ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, &"foo" "bar" );
+ ^~~~~~~~~~~~
+ { 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 "" } */
+
+}
+
+/* C++-specific expresssions. ****************************************/
+
+void test_cp_literal_keywords (int a, int b)
+{
+ this; /* { dg-error "invalid use of 'this' in non-member function" } */
+/* { dg-begin-multiline-output "" }
+ this;
+ ^~~~
+ { dg-end-multiline-output "" } */
+
+}
+
+class base {
+ public:
+ base ();
+ base (int i);
+ virtual ~base ();
+};
+class derived : public base { ~derived (); };
+
+void test_cp_casts (base *ptr)
+{
+ __emit_expression_range (0, dynamic_cast <derived *> (ptr)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, dynamic_cast <derived *> (ptr));
+ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, static_cast <derived *> (ptr)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, static_cast <derived *> (ptr));
+ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, reinterpret_cast <int *> (ptr)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, reinterpret_cast <int *> (ptr));
+ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, const_cast <base *> (ptr)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, const_cast <base *> (ptr));
+ ^~~~~~~~~~~~~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+}
+
+void test_new (void)
+{
+ __emit_expression_range (0, ::new base); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, ::new base);
+ ^~~~~~~~~~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, new base); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, new base);
+ ^~~~~~~~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, new (base)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, new (base));
+ ^~~~~~~~~~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, new base (42)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, new base (42));
+ ^~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, new (base) (42)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, new (base) (42));
+ ^~~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+
+ /* TODO: placement new. */
+}
+
+#endif
new file mode 100644
@@ -0,0 +1,106 @@
+/* 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 "cp/cp-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 "print-tree.h"
+
+int plugin_is_GPL_compatible;
+
+static void
+emit_warning (location_t loc)
+{
+ source_range src_range = get_range_from_loc (line_table, loc);
+ warning_at (loc, 0,
+ "tree range %i:%i-%i:%i",
+ LOCATION_LINE (src_range.m_start),
+ LOCATION_COLUMN (src_range.m_start),
+ LOCATION_LINE (src_range.m_finish),
+ LOCATION_COLUMN (src_range.m_finish));
+}
+
+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);
+ STRIP_LOCATION_EXPRS (fn);
+ 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! */
+ tree arg = CALL_EXPR_ARG (call_expr, 1);
+
+#if 0
+ fprintf (stderr, "call_expr: %p\n", call_expr);
+ fprintf (stderr, "arg: %p\n", arg);
+ debug_tree (arg);
+#endif
+
+ emit_warning (EXPR_LOCATION (arg));
+
+ return NULL_TREE;
+}
+
+static void
+callback (void *gcc_data, void *user_data)
+{
+ tree fndecl = (tree)gcc_data;
+ 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;
+}
@@ -62,7 +62,10 @@ set plugin_test_list [list \
{ dumb_plugin.c dumb-plugin-test-1.C } \
{ header_plugin.c header-plugin-test.C } \
{ decl_plugin.c decl-plugin-test.C } \
- { def_plugin.c def-plugin-test.C } ]
+ { def_plugin.c def-plugin-test.C } \
+ { diagnostic_plugin_test_tree_expression_range.c \
+ diagnostic-test-expressions-1.c } \
+]
foreach plugin_test $plugin_test_list {
# Replace each source file with its full-path name
@@ -13884,7 +13884,7 @@ nonnull_arg_p (const_tree arg)
/* Given location LOC, strip away any packed range information
or ad-hoc information. */
-static location_t
+location_t
get_pure_location (location_t loc)
{
if (IS_ADHOC_LOC (loc))
@@ -13914,20 +13914,20 @@ set_block (location_t loc, tree block)
return COMBINE_LOCATION_DATA (line_table, pure_loc, src_range, block);
}
-void
+location_t
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);
+ return set_source_range (expr, src_range);
}
-void
+location_t
set_source_range (tree expr, source_range src_range)
{
if (!EXPR_P (expr))
- return;
+ return UNKNOWN_LOCATION;
location_t pure_loc = get_pure_location (EXPR_LOCATION (expr));
location_t adhoc = COMBINE_LOCATION_DATA (line_table,
@@ -13935,6 +13935,21 @@ set_source_range (tree expr, source_range src_range)
src_range,
NULL);
SET_EXPR_LOCATION (expr, adhoc);
+ return adhoc;
+}
+
+location_t
+make_location (location_t caret, location_t start, location_t finish)
+{
+ location_t pure_loc = get_pure_location (caret);
+ source_range src_range;
+ src_range.m_start = start;
+ src_range.m_finish = finish;
+ location_t combined_loc = COMBINE_LOCATION_DATA (line_table,
+ pure_loc,
+ src_range,
+ NULL);
+ return combined_loc;
}
/* Return the name of combined function FN, for debugging purposes. */
@@ -5337,6 +5337,7 @@ type_with_alias_set_p (const_tree t)
return false;
}
+extern location_t get_pure_location (location_t loc);
extern location_t set_block (location_t loc, tree block);
extern void gt_ggc_mx (tree &);
@@ -5345,10 +5346,10 @@ extern void gt_pch_nx (tree &, gt_pointer_operator, void *);
extern bool nonnull_arg_p (const_tree);
-extern void
+extern location_t
set_source_range (tree expr, location_t start, location_t finish);
-extern void
+extern location_t
set_source_range (tree expr, source_range src_range);
static inline source_range
@@ -5358,4 +5359,37 @@ get_decl_source_range (tree decl)
return get_range_from_loc (line_table, loc);
}
+extern location_t
+make_location (location_t caret, location_t start, location_t finish);
+
+/* FIXME. */
+inline location_t
+get_start (location_t loc)
+{
+ source_range src_range = get_range_from_loc (line_table, loc);
+ return src_range.m_start;
+}
+
+/* FIXME. */
+inline location_t
+get_finish (location_t loc)
+{
+ source_range src_range = get_range_from_loc (line_table, loc);
+ return src_range.m_finish;
+}
+
+/* FIXME. */
+inline location_t
+get_expr_start (tree expr)
+{
+ return get_start (EXPR_LOCATION (expr));
+}
+
+/* FIXME. */
+inline location_t
+get_expr_finish (tree expr)
+{
+ return get_finish (EXPR_LOCATION (expr));
+}
+
#endif /* GCC_TREE_H */