From e67c6270888f36eebb789d8070c3c4608373cc35 Mon Sep 17 00:00:00 2001 From: David Malcolm <dmalcolm@redhat.com> Date: Wed, 28 Oct 2015 11:33:44 -0400 Subject: [PATCH 06/26] RFC: C++ FE: expression ranges (work in progress) v3 Changes from previous version: - all new calls to protected_set_expr_location removed; instead the location is passed into a tree-building function, using the preceding patch. - removal of #if 0 code - generates meaningful ranges for new expressions, using cp_lexer_previous_token. - shared the range-testing-plugin directly with the C FE, rather than having an identical copy; renamed the testcase from .c to .C Bootstraps (x86_64-pc-linux-gnu) but regresses the following test cases, due to changes in diagnostic location: g++.dg/gomp/loop-1.C g++.dg/gomp/loop-2.C g++.dg/gomp/loop-3.C g++.dg/init/const7.C g++.dg/ubsan/pr63956.C g++.dg/warn/Wparentheses-26.C gcc/cp/ChangeLog: * cp-tree.h (class cp_expr): New class. (perform_koenig_lookup): Convert return type and param from tree to cp_expr. (finish_increment_expr): Likewise. (finish_unary_op_expr): Likewise. (finish_id_expression): Likewise for return type. (build_class_member_access_expr): Likewise for param. (finish_class_member_access_expr): Likewise. (build_x_unary_op): Likewise. (build_c_cast): New decl. (build_x_modify_expr): Convert return type from tree to cp_expr. * name-lookup.c (lookup_arg_dependent_1): Likewise. (lookup_arg_dependent): Likewise; also for local "ret". * name-lookup.h (lookup_arg_dependent): Likewise for return type. * parser.c (struct cp_parser_expression_stack_entry): Likewise for field "lhs". (cp_parser_identifier): Likewise for return type. Use cp_expr ctor to preserve the token's location. (cp_parser_string_literal): Likewise, building up a meaningful location for the case where a compound string literal is built by concatentation. (cp_parser_userdef_char_literal): Likewise for return type. (cp_parser_userdef_numeric_literal): Likewise. (cp_parser_fold_expression): Likewise. (cp_parser_primary_expression): Likewise, and for locals "expr", "lam", "id_expression", "decl". Use cp_expr ctor when parsing literals, to preserve the spelling location of the token. Preserve the locations of parentheses. Preserve location when calling objc_lookup_ivar. (cp_parser_primary_expression): Convert return type from tree to cp_expr. (cp_parser_id_expression): Likewise. (cp_parser_unqualified_id): Likewise. Also for local "id". (cp_parser_postfix_expression): Likewise, also for local "postfix_expression". Preserve start location. Use it to construct spelling ranges for C++-style casts. Pass on the location of the closing parenthesis of a call site to cp_parser_parenthesized_expression_list, and use it to build a source range for a call. Use cp_expr in ternary expression. (cp_parser_postfix_dot_deref_expression): Convert param from tree to cp_expr. (cp_parser_parenthesized_expression_list): Add "close_paren_loc" out-param, and write back to it. (cp_parser_unary_expression): Convert return type from tree to cp_expr. Also for locals "cast_expression" and "expression". Generate and use suitable locations for cast expressions. (cp_parser_new_expression): Generate meaningful locations/ranges. (cp_parser_cast_expression): Convert return type from tree to cp_expr; also for local "expr". Use the paren location to generate a meaningful range for the expression. (cp_parser_binary_expression): Convert return type from tree to cp_expr; also for local "rhs". Generate a meaningful location for the expression, and use it. Replace call to protected_set_expr_location by converting a build2 to a build2_loc and using the location in the call to build_x_binary_op. (cp_parser_question_colon_clause): Convert param from tree to cp_expr; also for local "assignment_expr". Set the spelling range of the expression. (cp_parser_assignment_expression): Likewise for return type and locals "expr" and "rhs". Build a meaningful spelling range for the expression. (cp_parser_expression): Likewise for return type and locals "expression" and "assignment_expression". Build a meaningful spelling range for assignment expressions. (cp_parser_constant_expression): Likewise for return type and local "expression". (cp_parser_lambda_expression): Likewise for return type. (cp_parser_operator_function_id): Likewise. (cp_parser_operator): Likewise. Generate a meaningful range, using cp_expr's ctor to return it. (cp_parser_initializer_clause): Likewise for local "initializer". (cp_parser_lookup_name): Likewise for return type. Use cp_expr's ctor to preserve the location_t of the name. (cp_parser_simple_cast_expression): Likewise for return type. * semantics.c (perform_koenig_lookup): Likewise for return type and param. (finish_increment_expr): Likewise. Generate a meaningful spelling range. (finish_unary_op_expr): Likewise. (finish_id_expression): Likewise. * typeck.c (build_class_member_access_expr): Likewise for param; generate range for result. (finish_class_member_access_expr): Likewise. (cp_build_binary_op): Convert a build2 to a build2_loc. (build_x_unary_op): Convert param from tree to cp_expr. (build_c_cast): Provide an overloaded variant that takes a cp_expr and returns a cp_expr. (build_x_modify_expr): Convert return type from tree to cp_expr. gcc/testsuite/ChangeLog: * g++.dg/plugin/diagnostic-test-expressions-1.C: New file. * g++.dg/plugin/plugin.exp (plugin_test_list): Add the above. gcc/ChangeLog: * tree.c (get_pure_location): Make non-static. (set_source_range): Return the resulting location_t. (make_location): New function. * tree.h (get_pure_location): New decl. (set_source_range): Convert return type from void to location_t. (make_location): New decl. --- gcc/cp/cp-tree.h | 84 +++- gcc/cp/name-lookup.c | 6 +- gcc/cp/name-lookup.h | 2 +- gcc/cp/parser.c | 331 +++++++++---- gcc/cp/semantics.c | 35 +- gcc/cp/typeck.c | 47 +- .../g++.dg/plugin/diagnostic-test-expressions-1.C | 532 +++++++++++++++++++++ gcc/testsuite/g++.dg/plugin/plugin.exp | 5 +- gcc/tree.c | 25 +- gcc/tree.h | 8 +- 10 files changed, 924 insertions(+), 151 deletions(-) create mode 100644 gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 160bf1e..36da4b8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -40,6 +40,72 @@ c-common.h, not after. #include "c-family/c-common.h" #include "diagnostic.h" +/* A tree node, together with a location, so that we can track locations + (and ranges) during parsing. + + The location is redundant for node kinds that have locations, + but not all node kinds do (e.g. constants, and references to + params, locals, etc), so we stash a copy here. */ + +class cp_expr +{ +public: + cp_expr () : + m_value (NULL), m_loc (UNKNOWN_LOCATION) {} + + cp_expr (tree value) : + m_value (value), m_loc (EXPR_LOCATION (m_value)) {} + + cp_expr (tree value, location_t loc): + m_value (value), m_loc (loc) + { + if (m_value) + gcc_assert (m_loc != UNKNOWN_LOCATION); + } + + cp_expr (const cp_expr &other) : + m_value (other.m_value), m_loc (other.m_loc) {} + + /* Implicit conversions to tree. */ + operator tree () const { return m_value; } + tree & operator* () { return m_value; } + tree & operator-> () { return m_value; } + + tree get_value () const { return m_value; } + location_t get_location () const { return m_loc; } + location_t get_start () const + { + source_range src_range = get_range_from_loc (line_table, m_loc); + return src_range.m_start; + } + location_t get_finish () const + { + source_range src_range = get_range_from_loc (line_table, m_loc); + return src_range.m_finish; + } + + void set_location (location_t loc) + { + protected_set_expr_location (m_value, loc); + m_loc = loc; + } + + void set_range (location_t start, location_t finish) + { + m_loc = set_source_range (m_value, start, finish); + } + + private: + tree m_value; + location_t m_loc; +}; + +inline bool +operator == (const cp_expr &lhs, tree rhs) +{ + return lhs.get_value () == rhs; +} + #include "name-lookup.h" /* Usage of TREE_LANG_FLAG_?: @@ -6288,15 +6354,15 @@ extern tree finish_stmt_expr_expr (tree, tree); extern tree finish_stmt_expr (tree, bool); extern tree stmt_expr_value_expr (tree); bool empty_expr_stmt_p (tree); -extern tree perform_koenig_lookup (tree, vec<tree, va_gc> *, +extern cp_expr perform_koenig_lookup (cp_expr, vec<tree, va_gc> *, tsubst_flags_t); extern tree finish_call_expr (tree, vec<tree, va_gc> **, bool, bool, tsubst_flags_t); extern tree finish_template_variable (tree, tsubst_flags_t = tf_warning_or_error); -extern tree finish_increment_expr (tree, enum tree_code); +extern cp_expr finish_increment_expr (cp_expr, enum tree_code); extern tree finish_this_expr (void); extern tree finish_pseudo_destructor_expr (tree, tree, tree, location_t); -extern tree finish_unary_op_expr (location_t, enum tree_code, tree, +extern cp_expr finish_unary_op_expr (location_t, enum tree_code, cp_expr, tsubst_flags_t); extern tree finish_compound_literal (tree, tree, tsubst_flags_t); extern tree finish_fname (tree); @@ -6310,7 +6376,7 @@ extern tree finish_base_specifier (tree, tree, bool); extern void finish_member_declaration (tree); extern bool outer_automatic_var_p (tree); extern tree process_outer_var_ref (tree, tsubst_flags_t); -extern tree finish_id_expression (tree, tree, tree, +extern cp_expr finish_id_expression (tree, tree, tree, cp_id_kind *, bool, bool, bool *, bool, bool, bool, bool, @@ -6552,9 +6618,9 @@ extern tree unlowered_expr_type (const_tree); extern tree decay_conversion (tree, tsubst_flags_t, bool = true); -extern tree build_class_member_access_expr (tree, tree, tree, bool, +extern tree build_class_member_access_expr (cp_expr, tree, tree, bool, tsubst_flags_t); -extern tree finish_class_member_access_expr (tree, tree, bool, +extern tree finish_class_member_access_expr (cp_expr, tree, bool, tsubst_flags_t); extern tree build_x_indirect_ref (location_t, tree, ref_operator, tsubst_flags_t); @@ -6576,7 +6642,7 @@ extern tree build_x_binary_op (location_t, extern tree build_x_array_ref (location_t, tree, tree, tsubst_flags_t); extern tree build_x_unary_op (location_t, - enum tree_code, tree, + enum tree_code, cp_expr, tsubst_flags_t); extern tree cp_build_addr_expr (tree, tsubst_flags_t); extern tree cp_build_unary_op (enum tree_code, tree, int, @@ -6596,8 +6662,10 @@ extern tree build_static_cast (tree, tree, tsubst_flags_t); extern tree build_reinterpret_cast (tree, tree, tsubst_flags_t); extern tree build_const_cast (tree, tree, tsubst_flags_t); extern tree build_c_cast (location_t, tree, tree); +extern cp_expr build_c_cast (location_t loc, tree type, + cp_expr expr); extern tree cp_build_c_cast (tree, tree, tsubst_flags_t); -extern tree build_x_modify_expr (location_t, tree, +extern cp_expr build_x_modify_expr (location_t, tree, enum tree_code, tree, tsubst_flags_t); extern tree cp_build_modify_expr (tree, enum tree_code, tree, diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index cebe57e..86c07ef 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -5659,7 +5659,7 @@ arg_assoc (struct arg_lookup *k, tree n) /* Performs Koenig lookup depending on arguments, where fns are the functions found in normal lookup. */ -static tree +static cp_expr lookup_arg_dependent_1 (tree name, tree fns, vec<tree, va_gc> *args) { struct arg_lookup k; @@ -5720,10 +5720,10 @@ lookup_arg_dependent_1 (tree name, tree fns, vec<tree, va_gc> *args) /* Wrapper for lookup_arg_dependent_1. */ -tree +cp_expr lookup_arg_dependent (tree name, tree fns, vec<tree, va_gc> *args) { - tree ret; + cp_expr ret; bool subtime; subtime = timevar_cond_start (TV_NAME_LOOKUP); ret = lookup_arg_dependent_1 (name, fns, args); diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index d430edb..d2453e9 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -347,7 +347,7 @@ extern void do_toplevel_using_decl (tree, tree, tree); extern void do_local_using_decl (tree, tree, tree); extern tree do_class_using_decl (tree, tree); extern void do_using_directive (tree); -extern tree lookup_arg_dependent (tree, tree, vec<tree, va_gc> *); +extern cp_expr lookup_arg_dependent (tree, tree, vec<tree, va_gc> *); extern bool is_associated_namespace (tree, tree); extern void parse_using_directive (tree, tree); extern tree innermost_non_namespace_value (tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 0e1116b..1703ad3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1785,7 +1785,7 @@ struct cp_parser_expression_stack_entry { /* Left hand side of the binary operation we are currently parsing. */ - tree lhs; + cp_expr lhs; /* Original tree code for left hand side, if it was a binary expression itself (used for -Wparentheses). */ enum tree_code lhs_type; @@ -1939,15 +1939,15 @@ static cp_parser *cp_parser_new /* Lexical conventions [gram.lex] */ -static tree cp_parser_identifier +static cp_expr cp_parser_identifier (cp_parser *); -static tree cp_parser_string_literal +static cp_expr cp_parser_string_literal (cp_parser *, bool, bool, bool); -static tree cp_parser_userdef_char_literal +static cp_expr cp_parser_userdef_char_literal (cp_parser *); static tree cp_parser_userdef_string_literal (tree); -static tree cp_parser_userdef_numeric_literal +static cp_expr cp_parser_userdef_numeric_literal (cp_parser *); /* Basic concepts [gram.basic] */ @@ -1957,11 +1957,11 @@ static bool cp_parser_translation_unit /* Expressions [gram.expr] */ -static tree cp_parser_primary_expression +static cp_expr cp_parser_primary_expression (cp_parser *, bool, bool, bool, cp_id_kind *); -static tree cp_parser_id_expression +static cp_expr cp_parser_id_expression (cp_parser *, bool, bool, bool *, bool, bool); -static tree cp_parser_unqualified_id +static cp_expr cp_parser_unqualified_id (cp_parser *, bool, bool, bool, bool); static tree cp_parser_nested_name_specifier_opt (cp_parser *, bool, bool, bool, bool); @@ -1969,19 +1969,19 @@ static tree cp_parser_nested_name_specifier (cp_parser *, bool, bool, bool, bool); static tree cp_parser_qualifying_entity (cp_parser *, bool, bool, bool, bool, bool); -static tree cp_parser_postfix_expression +static cp_expr cp_parser_postfix_expression (cp_parser *, bool, bool, bool, bool, cp_id_kind *); static tree cp_parser_postfix_open_square_expression (cp_parser *, tree, bool, bool); static tree cp_parser_postfix_dot_deref_expression - (cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *, location_t); + (cp_parser *, enum cpp_ttype, cp_expr, 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 (cp_parser *, tree, tree *, tree *); -static tree cp_parser_unary_expression +static cp_expr cp_parser_unary_expression (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false, bool = false); static enum tree_code cp_parser_unary_operator (cp_token *); @@ -1999,23 +1999,23 @@ static vec<tree, va_gc> *cp_parser_new_initializer (cp_parser *); static tree cp_parser_delete_expression (cp_parser *); -static tree cp_parser_cast_expression +static cp_expr cp_parser_cast_expression (cp_parser *, bool, bool, bool, cp_id_kind *); -static tree cp_parser_binary_expression +static cp_expr cp_parser_binary_expression (cp_parser *, bool, bool, enum cp_parser_prec, cp_id_kind *); static tree cp_parser_question_colon_clause - (cp_parser *, tree); -static tree cp_parser_assignment_expression + (cp_parser *, cp_expr); +static cp_expr cp_parser_assignment_expression (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false); static enum tree_code cp_parser_assignment_operator_opt (cp_parser *); -static tree cp_parser_expression +static cp_expr cp_parser_expression (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false); -static tree cp_parser_constant_expression +static cp_expr cp_parser_constant_expression (cp_parser *, bool = false, bool * = NULL); static tree cp_parser_builtin_offsetof (cp_parser *); -static tree cp_parser_lambda_expression +static cp_expr cp_parser_lambda_expression (cp_parser *); static void cp_parser_lambda_introducer (cp_parser *, tree); @@ -2170,7 +2170,7 @@ static void cp_parser_function_body (cp_parser *, bool); static tree cp_parser_initializer (cp_parser *, bool *, bool *); -static tree cp_parser_initializer_clause +static cp_expr cp_parser_initializer_clause (cp_parser *, bool *); static tree cp_parser_braced_list (cp_parser*, bool*); @@ -2238,9 +2238,9 @@ static tree cp_parser_mem_initializer_id /* Overloading [gram.over] */ -static tree cp_parser_operator_function_id +static cp_expr cp_parser_operator_function_id (cp_parser *); -static tree cp_parser_operator +static cp_expr cp_parser_operator (cp_parser *); /* Templates [gram.temp] */ @@ -2411,7 +2411,7 @@ static tree cp_parser_objc_struct_declaration /* Utility Routines */ -static tree cp_parser_lookup_name +static cp_expr cp_parser_lookup_name (cp_parser *, tree, enum tag_types, bool, bool, bool, tree *, location_t); static tree cp_parser_lookup_name_simple (cp_parser *, tree, location_t); @@ -2421,7 +2421,7 @@ static bool cp_parser_check_declarator_template_parameters (cp_parser *, cp_declarator *, location_t); static bool cp_parser_check_template_parameters (cp_parser *, unsigned, location_t, cp_declarator *); -static tree cp_parser_simple_cast_expression +static cp_expr cp_parser_simple_cast_expression (cp_parser *); static tree cp_parser_global_scope_opt (cp_parser *, bool); @@ -3670,7 +3670,7 @@ cp_parser_pop_lexer (cp_parser *parser) /* Parse an identifier. Returns an IDENTIFIER_NODE representing the identifier. */ -static tree +static cp_expr cp_parser_identifier (cp_parser* parser) { cp_token *token; @@ -3678,7 +3678,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 cp_expr (token->u.value, token->location); + else + return error_mark_node; } /* Parse a sequence of adjacent string constants. Returns a @@ -3695,7 +3698,7 @@ cp_parser_identifier (cp_parser* parser) This code is largely lifted from lex_string() in c-lex.c. FUTURE: ObjC++ will need to handle @-strings here. */ -static tree +static cp_expr cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok, bool lookup_udlit = true) { @@ -3717,6 +3720,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 +3759,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 +3820,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 +3879,7 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok, if (count > 1) obstack_free (&str_ob, 0); - return value; + return cp_expr (value, loc); } /* Look up a literal operator with the name and the exact arguments. */ @@ -3916,7 +3930,7 @@ lookup_literal_operator (tree name, vec<tree, va_gc> *args) /* Parse a user-defined char constant. Returns a call to a user-defined literal operator taking the character as an argument. */ -static tree +static cp_expr cp_parser_userdef_char_literal (cp_parser *parser) { cp_token *token = cp_lexer_consume_token (parser->lexer); @@ -4008,7 +4022,7 @@ make_string_pack (tree value) /* Parse a user-defined numeric constant. returns a call to a user-defined literal operator. */ -static tree +static cp_expr cp_parser_userdef_numeric_literal (cp_parser *parser) { cp_token *token = cp_lexer_consume_token (parser->lexer); @@ -4409,7 +4423,7 @@ cp_parser_fold_operator (cp_parser *parser) Note that the '(' and ')' are matched in primary expression. */ -static tree +static cp_expr cp_parser_fold_expression (cp_parser *parser, tree expr1) { cp_id_kind pidk; @@ -4529,7 +4543,7 @@ cp_parser_fold_expression (cp_parser *parser, tree expr1) Returns a representation of the expression. Upon return, *IDK indicates what kind of id-expression (if any) was present. */ -static tree +static cp_expr cp_parser_primary_expression (cp_parser *parser, bool address_p, bool cast_p, @@ -4614,7 +4628,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 cp_expr (token->u.value, token->location); case CPP_CHAR_USERDEF: case CPP_CHAR16_USERDEF: @@ -4672,9 +4686,11 @@ cp_parser_primary_expression (cp_parser *parser, } /* Otherwise it's a normal parenthesized expression. */ { - tree expr; + cp_expr 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 +4735,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; + expr.set_range (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); @@ -4739,7 +4759,7 @@ cp_parser_primary_expression (cp_parser *parser, return msg; /* ... else, fall though to see if it's a lambda. */ } - tree lam = cp_parser_lambda_expression (parser); + cp_expr lam = cp_parser_lambda_expression (parser); /* Don't warn about a failed tentative parse. */ if (cp_parser_error_occurred (parser)) return error_mark_node; @@ -4760,20 +4780,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 cp_expr (boolean_true_node, token->location); case RID_FALSE: cp_lexer_consume_token (parser->lexer); - return boolean_false_node; + return cp_expr (boolean_false_node, token->location); /* The `__null' literal. */ case RID_NULL: cp_lexer_consume_token (parser->lexer); - return null_node; + return cp_expr (null_node, token->location); /* The `nullptr' literal. */ case RID_NULLPTR: cp_lexer_consume_token (parser->lexer); - return nullptr_node; + return cp_expr (nullptr_node, token->location); /* Recognize the `this' keyword. */ case RID_THIS: @@ -4921,14 +4941,14 @@ cp_parser_primary_expression (cp_parser *parser, case CPP_TEMPLATE_ID: case CPP_NESTED_NAME_SPECIFIER: { - tree id_expression; - tree decl; + id_expression: + cp_expr id_expression; + cp_expr decl; const char *error_msg; bool template_p; bool done; cp_token *id_expr_token; - id_expression: /* Parse the id-expression. */ id_expression = cp_parser_id_expression (parser, @@ -4997,8 +5017,20 @@ cp_parser_primary_expression (cp_parser *parser, } /* In Objective-C++, an instance variable (ivar) may be preferred - to whatever cp_parser_lookup_name() found. */ - decl = objc_lookup_ivar (decl, id_expression); + to whatever cp_parser_lookup_name() found. + Call objc_lookup_ivar. To avoid exposing cp_expr to the + rest of c-family, we have to do a little extra work to preserve + any location information in cp_expr "decl". Given that + objc_lookup_ivar is implemented in "c-family" and "objc", we + have a trip through the pure "tree" type, rather than cp_expr. + Naively copying it back to "decl" would implicitly give the + new cp_expr value an UNKNOWN_LOCATION for nodes that don't + store an EXPR_LOCATION. Hence we only update "decl" (and + hence its location_t) if we get back a different tree node. */ + tree decl_tree = objc_lookup_ivar (decl.get_value (), + id_expression); + if (decl_tree != decl.get_value ()) + decl = cp_expr (decl_tree); /* If name lookup gives us a SCOPE_REF, then the qualifying scope was dependent. */ @@ -5039,7 +5071,7 @@ cp_parser_primary_expression (cp_parser *parser, { error_at (id_expr_token->location, "local variable %qD may not appear in this context", - decl); + decl.get_value ()); return error_mark_node; } } @@ -5067,7 +5099,7 @@ cp_parser_primary_expression (cp_parser *parser, } } -static inline tree +static inline cp_expr cp_parser_primary_expression (cp_parser *parser, bool address_p, bool cast_p, @@ -5112,7 +5144,7 @@ cp_parser_primary_expression (cp_parser *parser, If DECLARATOR_P is true, the id-expression is appearing as part of a declarator, rather than as part of an expression. */ -static tree +static cp_expr cp_parser_id_expression (cp_parser *parser, bool template_keyword_p, bool check_dependency_p, @@ -5247,7 +5279,7 @@ cp_parser_id_expression (cp_parser *parser, is true, the unqualified-id is appearing as part of a declarator, rather than as part of an expression. */ -static tree +static cp_expr cp_parser_unqualified_id (cp_parser* parser, bool template_keyword_p, bool check_dependency_p, @@ -5510,7 +5542,7 @@ cp_parser_unqualified_id (cp_parser* parser, case CPP_KEYWORD: if (token->keyword == RID_OPERATOR) { - tree id; + cp_expr id; /* This could be a template-id, so we try that first. */ cp_parser_parse_tentatively (parser); @@ -6100,7 +6132,7 @@ cp_parser_compound_literal_p (cp_parser *parser) Returns a representation of the expression. */ -static tree +static cp_expr cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, bool member_access_only_p, bool decltype_p, cp_id_kind * pidk_return) @@ -6109,13 +6141,15 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, location_t loc; enum rid keyword; cp_id_kind idk = CP_ID_KIND_NONE; - tree postfix_expression = NULL_TREE; + cp_expr postfix_expression = NULL_TREE; bool is_member_access = false; int saved_in_statement = -1; /* 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) @@ -6126,7 +6160,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, case RID_CONSTCAST: { tree type; - tree expression; + cp_expr expression; const char *saved_message; bool saved_in_type_id_in_expr_p; @@ -6159,7 +6193,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 +6229,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); + postfix_expression.set_location (cp_cast_loc); } break; @@ -6471,6 +6516,9 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, postfix_expression, false, decltype_p); + postfix_expression.set_range (start_loc, + postfix_expression.get_location ()); + idk = CP_ID_KIND_NONE; is_member_access = false; break; @@ -6484,6 +6532,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 +6551,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 +6694,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 +6758,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 + : cp_expr (error_mark_node); else return postfix_expression; } @@ -6905,7 +6960,7 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, static tree cp_parser_postfix_dot_deref_expression (cp_parser *parser, enum cpp_ttype token_type, - tree postfix_expression, + cp_expr postfix_expression, bool for_offsetof, cp_id_kind *idk, location_t location) { @@ -6942,7 +6997,7 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, if (scope == unknown_type_node) { error_at (location, "%qE does not have class type", - postfix_expression); + postfix_expression.get_value ()); scope = NULL_TREE; } /* Unlike the object expression in other contexts, *this is not @@ -7107,7 +7162,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 +7267,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; @@ -7380,7 +7439,7 @@ cp_parser_pseudo_destructor_name (cp_parser* parser, Returns a representation of the expression. */ -static tree +static cp_expr cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, bool address_p, bool cast_p, bool decltype_p) { @@ -7594,8 +7653,8 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, } if (unary_operator != ERROR_MARK) { - tree cast_expression; - tree expression = error_mark_node; + cp_expr cast_expression; + cp_expr expression = error_mark_node; non_integral_constant non_constant_p = NIC_NONE; location_t loc = token->location; tsubst_flags_t complain = complain_flags (decltype_p); @@ -7611,6 +7670,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, cast_expression.get_finish ()); + /* Now, build an appropriate representation. */ switch (unary_operator) { @@ -7726,6 +7793,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, @@ -7810,9 +7879,20 @@ cp_parser_new_expression (cp_parser* parser) } else { + /* 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); + /* Create a representation of the new-expression. */ ret = build_new (&placement, type, nelts, &initializer, global_scope_p, tf_warning_or_error); + protected_set_expr_location (ret, combined_loc); } if (placement != NULL) @@ -8192,7 +8272,7 @@ cp_parser_tokens_start_cast_expression (cp_parser *parser) Returns a representation of the expression. */ -static tree +static cp_expr cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, bool decltype_p, cp_id_kind * pidk) { @@ -8200,7 +8280,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { tree type = NULL_TREE; - tree expr = NULL_TREE; + cp_expr expr (NULL_TREE); int cast_expression = 0; const char *saved_message; @@ -8213,7 +8293,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 +8397,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, + expr.get_finish ()); + expr = build_c_cast (cast_loc, type, expr); return expr; } } @@ -8408,7 +8498,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, ? PREC_NOT_OPERATOR \ : binops_by_token[token->type].prec) -static tree +static cp_expr cp_parser_binary_expression (cp_parser* parser, bool cast_p, bool no_toplevel_fold_p, bool decltype_p, @@ -8418,7 +8508,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, cp_parser_expression_stack stack; cp_parser_expression_stack_entry *sp = &stack[0]; cp_parser_expression_stack_entry current; - tree rhs; + cp_expr rhs; cp_token *token; enum tree_code rhs_type; enum cp_parser_prec new_prec, lookahead_prec; @@ -8558,6 +8648,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, + current.lhs.get_start (), + rhs.get_finish ()); + /* ??? 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 +8663,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. @@ -8596,7 +8691,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, return current.lhs; } -static tree +static cp_expr cp_parser_binary_expression (cp_parser* parser, bool cast_p, bool no_toplevel_fold_p, enum cp_parser_prec prec, @@ -8620,10 +8715,10 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, ? : assignment-expression */ static tree -cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr) +cp_parser_question_colon_clause (cp_parser* parser, cp_expr logical_or_expr) { tree expr, folded_logical_or_expr = cp_fully_fold (logical_or_expr); - tree assignment_expr; + cp_expr assignment_expr; struct cp_token *token; location_t loc = cp_lexer_peek_token (parser->lexer)->location; @@ -8662,6 +8757,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, + logical_or_expr.get_start (), + assignment_expr.get_finish ()); + /* Build the conditional-expression. */ return build_x_conditional_expr (loc, logical_or_expr, expr, @@ -8681,11 +8785,11 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr) Returns a representation for the expression. */ -static tree +static cp_expr cp_parser_assignment_expression (cp_parser* parser, cp_id_kind * pidk, bool cast_p, bool decltype_p) { - tree expr; + cp_expr expr; /* If the next token is the `throw' keyword, then we're looking at a throw-expression. */ @@ -8717,7 +8821,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); + cp_expr rhs = cp_parser_initializer_clause (parser, + &non_constant_p); if (BRACE_ENCLOSED_INITIALIZER_P (rhs)) maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); @@ -8728,7 +8833,15 @@ 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. */ + loc = make_location (loc, + expr.get_start (), + rhs.get_finish ()); saved_input_location = input_location; input_location = loc; expr = build_x_modify_expr (loc, expr, @@ -8844,16 +8957,16 @@ cp_parser_assignment_operator_opt (cp_parser* parser) Returns a representation of the expression. */ -static tree +static cp_expr cp_parser_expression (cp_parser* parser, cp_id_kind * pidk, bool cast_p, bool decltype_p) { - tree expression = NULL_TREE; + cp_expr expression = NULL_TREE; location_t loc = UNKNOWN_LOCATION; while (true) { - tree assignment_expression; + cp_expr assignment_expression; /* Parse the next assignment-expression. */ assignment_expression @@ -8875,9 +8988,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, + expression.get_start (), + assignment_expression.get_finish ()); + 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) @@ -8904,7 +9025,7 @@ cp_parser_expression (cp_parser* parser, cp_id_kind * pidk, constant, *NON_CONSTANT_P is set to TRUE. If ALLOW_NON_CONSTANT_P is false, NON_CONSTANT_P should be NULL. */ -static tree +static cp_expr cp_parser_constant_expression (cp_parser* parser, bool allow_non_constant_p, bool *non_constant_p) @@ -8912,7 +9033,7 @@ cp_parser_constant_expression (cp_parser* parser, bool saved_integral_constant_expression_p; bool saved_allow_non_integral_constant_expression_p; bool saved_non_integral_constant_expression_p; - tree expression; + cp_expr expression; /* It might seem that we could simply parse the conditional-expression, and then check to see if it were @@ -9282,7 +9403,7 @@ finish_lambda_scope (void) Returns a representation of the expression. */ -static tree +static cp_expr cp_parser_lambda_expression (cp_parser* parser) { tree lambda_expr = build_lambda_expr (); @@ -13284,7 +13405,7 @@ cp_parser_mem_initializer_id (cp_parser* parser) Returns an IDENTIFIER_NODE for the operator which is a human-readable spelling of the identifier, e.g., `operator +'. */ -static tree +static cp_expr cp_parser_operator_function_id (cp_parser* parser) { /* Look for the `operator' keyword. */ @@ -13324,7 +13445,7 @@ cp_literal_operator_id (const char* name) Returns an IDENTIFIER_NODE for the operator which is a human-readable spelling of the identifier, e.g., `operator +'. */ -static tree +static cp_expr cp_parser_operator (cp_parser* parser) { tree id = NULL_TREE; @@ -13333,6 +13454,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 +13473,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 +13484,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 +13493,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 cp_expr (id, loc); } case CPP_PLUS: @@ -13614,7 +13741,7 @@ cp_parser_operator (cp_parser* parser) id = error_mark_node; } - return id; + return cp_expr (id, start_loc); } /* Parse a template-declaration. @@ -20306,10 +20433,10 @@ cp_parser_initializer (cp_parser* parser, bool* is_direct_init, Otherwise, calls cp_parser_braced_list. */ -static tree +static cp_expr cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p) { - tree initializer; + cp_expr initializer; /* Assume the expression is constant. */ *non_constant_p = false; @@ -24075,7 +24202,7 @@ cp_parser_nested_requirement (cp_parser *parser) TREE_LIST of candidates if name-lookup results in an ambiguity, and NULL_TREE otherwise. */ -static tree +static cp_expr cp_parser_lookup_name (cp_parser *parser, tree name, enum tag_types tag_type, bool is_template, @@ -24317,7 +24444,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name, maybe_record_typedef_use (decl); - return decl; + return cp_expr (decl, name_location); } /* Like cp_parser_lookup_name, but for use in the typical case where @@ -25321,7 +25448,7 @@ cp_parser_single_declaration (cp_parser* parser, /* Parse a cast-expression that is not the operand of a unary "&". */ -static tree +static cp_expr cp_parser_simple_cast_expression (cp_parser *parser) { return cp_parser_cast_expression (parser, /*address_p=*/false, diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index e7e5d8e..57d3458 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2164,8 +2164,8 @@ empty_expr_stmt_p (tree expr_stmt) the function (or functions) to call; ARGS are the arguments to the call. Returns the functions to be considered by overload resolution. */ -tree -perform_koenig_lookup (tree fn, vec<tree, va_gc> *args, +cp_expr +perform_koenig_lookup (cp_expr fn, vec<tree, va_gc> *args, tsubst_flags_t complain) { tree identifier = NULL_TREE; @@ -2460,10 +2460,15 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual, is indicated by CODE, which should be POSTINCREMENT_EXPR or POSTDECREMENT_EXPR.) */ -tree -finish_increment_expr (tree expr, enum tree_code code) +cp_expr +finish_increment_expr (cp_expr 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. */ + cp_expr result = build_x_unary_op (input_location, code, expr, + tf_warning_or_error); + result.set_range (expr.get_start (), + get_range_from_loc (line_table, input_location).m_finish); + return result; } /* Finish a use of `this'. Returns an expression for `this'. */ @@ -2557,15 +2562,17 @@ 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, +cp_expr +finish_unary_op_expr (location_t op_loc, enum tree_code code, cp_expr 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, expr.get_finish ()); + tree result = build_x_unary_op (combined_loc, code, expr, complain); tree result_ovl, expr_ovl; if (!(complain & tf_warning)) - return result; + return cp_expr (result, combined_loc); result_ovl = result; expr_ovl = expr; @@ -2575,15 +2582,15 @@ finish_unary_op_expr (location_t loc, enum tree_code code, tree expr, if (!CONSTANT_CLASS_P (expr_ovl) || TREE_OVERFLOW_P (expr_ovl)) - return result; + return cp_expr (result, combined_loc); if (!processing_template_decl) 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 cp_expr (result, combined_loc); } /* Finish a compound-literal expression. TYPE is the type to which @@ -3324,7 +3331,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain) the use of "this" explicit. Upon return, *IDK will be filled in appropriately. */ -tree +cp_expr finish_id_expression (tree id_expression, tree decl, tree scope, @@ -3669,7 +3676,7 @@ finish_id_expression (tree id_expression, } } - return decl; + return cp_expr (decl, location); } /* Implement the __typeof keyword: Return the type of EXPR, suitable for diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 5f7d4bb..0708c6f 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2261,7 +2261,7 @@ lookup_anon_field (tree t, tree type) functions indicated by MEMBER. */ tree -build_class_member_access_expr (tree object, tree member, +build_class_member_access_expr (cp_expr object, tree member, tree access_path, bool preserve_reference, tsubst_flags_t complain) { @@ -2291,10 +2291,10 @@ build_class_member_access_expr (tree object, tree member, && CLASS_TYPE_P (TREE_TYPE (object_type))) error ("request for member %qD in %qE, which is of pointer " "type %qT (maybe you meant to use %<->%> ?)", - member, object, object_type); + member, object.get_value (), object_type); else error ("request for member %qD in %qE, which is of non-class " - "type %qT", member, object, object_type); + "type %qT", member, object.get_value (), object_type); } return error_mark_node; } @@ -2435,7 +2435,12 @@ 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, + object.get_start (), + get_range_from_loc (line_table, + input_location).m_finish); + result = build3_loc (combined_loc, COMPONENT_REF, member_type, object, member, NULL_TREE); /* Mark the expression const or volatile, as appropriate. Even @@ -2624,7 +2629,7 @@ check_template_keyword (tree decl) be a template via the use of the "A::template B" syntax. */ tree -finish_class_member_access_expr (tree object, tree name, bool template_p, +finish_class_member_access_expr (cp_expr object, tree name, bool template_p, tsubst_flags_t complain) { tree expr; @@ -2658,7 +2663,7 @@ finish_class_member_access_expr (tree object, tree name, bool template_p, && TYPE_P (TREE_OPERAND (name, 0)) && dependent_type_p (TREE_OPERAND (name, 0)))) return build_min_nt_loc (UNKNOWN_LOCATION, COMPONENT_REF, - object, name, NULL_TREE); + object.get_value (), name, NULL_TREE); object = build_non_dependent_expr (object); } else if (c_dialect_objc () @@ -2681,10 +2686,10 @@ finish_class_member_access_expr (tree object, tree name, bool template_p, && CLASS_TYPE_P (TREE_TYPE (object_type))) error ("request for member %qD in %qE, which is of pointer " "type %qT (maybe you meant to use %<->%> ?)", - name, object, object_type); + name, object.get_value (), object_type); else error ("request for member %qD in %qE, which is of non-class " - "type %qT", name, object, object_type); + "type %qT", name, object.get_value (), object_type); } return error_mark_node; } @@ -5102,7 +5107,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); @@ -5260,7 +5265,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain) and XARG is the operand. */ tree -build_x_unary_op (location_t loc, enum tree_code code, tree xarg, +build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg, tsubst_flags_t complain) { tree orig_expr = xarg; @@ -5270,7 +5275,7 @@ build_x_unary_op (location_t loc, enum tree_code code, tree xarg, if (processing_template_decl) { if (type_dependent_expression_p (xarg)) - return build_min_nt_loc (loc, code, xarg, NULL_TREE); + return build_min_nt_loc (loc, code, xarg.get_value (), NULL_TREE); xarg = build_non_dependent_expr (xarg); } @@ -5305,7 +5310,7 @@ build_x_unary_op (location_t loc, enum tree_code code, tree xarg, error (DECL_CONSTRUCTOR_P (fn) ? G_("taking address of constructor %qE") : G_("taking address of destructor %qE"), - xarg); + xarg.get_value ()); return error_mark_node; } } @@ -5321,7 +5326,7 @@ build_x_unary_op (location_t loc, enum tree_code code, tree xarg, if (complain & tf_error) { error ("invalid use of %qE to form a " - "pointer-to-member-function", xarg); + "pointer-to-member-function", xarg.get_value ()); if (TREE_CODE (xarg) != OFFSET_REF) inform (input_location, " a qualified-id is required"); } @@ -5332,7 +5337,7 @@ build_x_unary_op (location_t loc, enum tree_code code, tree xarg, if (complain & tf_error) error ("parentheses around %qE cannot be used to form a" " pointer-to-member-function", - xarg); + xarg.get_value ()); else return error_mark_node; PTRMEM_OK_P (xarg) = 1; @@ -7259,6 +7264,18 @@ build_c_cast (location_t /*loc*/, tree type, tree expr) return cp_build_c_cast (type, expr, tf_warning_or_error); } +/* Like the "build_c_cast" used for c-common, but using cp_expr to + preserve location information even for tree nodes that don't + support it. */ + +cp_expr +build_c_cast (location_t loc, tree type, cp_expr expr) +{ + cp_expr result = cp_build_c_cast (type, expr, tf_warning_or_error); + result.set_location (loc); + return result; +} + /* Build an expression representing an explicit C-style cast to type TYPE of expression EXPR. */ @@ -7764,7 +7781,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs, return result; } -tree +cp_expr build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, tree rhs, tsubst_flags_t complain) { diff --git a/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C b/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C new file mode 100644 index 0000000..bba79e3 --- /dev/null +++ b/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C @@ -0,0 +1,532 @@ +/* { 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. We use variadic arguments. + For compatibility with the C tests we have a dummy argument, since + C requires at least one argument before the ellipsis. */ + +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 "" } */ + + __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. */ +} diff --git a/gcc/testsuite/g++.dg/plugin/plugin.exp b/gcc/testsuite/g++.dg/plugin/plugin.exp index 3ed1397..3be89a0 100644 --- a/gcc/testsuite/g++.dg/plugin/plugin.exp +++ b/gcc/testsuite/g++.dg/plugin/plugin.exp @@ -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 } \ + { ../../gcc.dg/plugin/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 diff --git a/gcc/tree.c b/gcc/tree.c index d5a71a3..e7f4dcf 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -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. */ diff --git a/gcc/tree.h b/gcc/tree.h index 41c0f7c..7919860 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -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,7 @@ 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); + #endif /* GCC_TREE_H */ -- 1.8.5.3