From e87eed2a9cbc1fe429ad550337e819cddcdc9c5a Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 4 Dec 2015 18:09:54 +0000 Subject: [PATCH] C++ FE: expression ranges gcc/ChangeLog: * convert.c (convert_to_real_1): When converting from a REAL_TYPE, preserve the location of EXPR in the result. * 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. (get_finish): New inline function. (set_source_range): Convert return type from void to location_t. (make_location): New decl. gcc/cp/ChangeLog: * cp-tree.h (class cp_expr): New class. (finish_parenthesized_expr): Convert return type and param to cp_expr. (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. * cvt.c (cp_convert_and_check): When warning about conversions, attempt to use the location of "expr" if available, otherwise falling back to the old behavior of using input_location. * name-lookup.c (lookup_arg_dependent_1): Convert return type from tree to cp_expr. (lookup_arg_dependent): Likewise; also for local "ret". * name-lookup.h (lookup_arg_dependent): Likewise for return type. * parser.c (cp_lexer_previous_token): Skip past purged tokens. (struct cp_parser_expression_stack_entry): Convert field "lhs" to cp_expr. (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_statement_expr): Convert return type to cp_expr. Generate a suitable location for the expr and return it via the cp_expr ctor. (cp_parser_fold_expression): Convert return type to cp_expr. (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. Preserve the location for "this" tokens. Generate suitable locations for "__builtin_va_arg" constructs and for Objective C 2.0 dot-syntax. Set the location for the result of finish_id_expression. (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". Generate suitable locations for C++-style casts, "_Cilk_spawn" constructs. Convert local "initializer" to cp_expr and use it to preserve the location of compound literals. Capture the location of the closing parenthesis of a call site via 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. Generate and set a location. (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 addresses of labels and for cast expressions. Call cp_expr::set_location where necessary. Preserve the locations of negated numeric literals. (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, adding a cp_expr::set_location to the latter case. (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. Remove saving of input_location in favor of a call to cp_expr::set_location. (cp_parser_expression): Convert return type and locals "expression" and "assignment_expression" to cp_expr. Build a meaningful spelling range for assignment expressions. (cp_parser_constant_expression): Likewise for return type and local "expression". (cp_parser_builtin_offsetof): Convert return type and local "expr" to cp_expr. Generate suitable locations. (cp_parser_lambda_expression): Convert return return type to cp_expr. (cp_parser_operator_function_id): Likewise. (cp_parser_operator): Likewise. Generate a meaningful range, using cp_expr's ctor to return it. (cp_parser_template_id): When converting a token to CPP_TEMPLATE_ID, update the location. (cp_parser_initializer_clause): Convert return type and local "initializer" to cp_expr. (cp_parser_braced_list): Likewise for return type. Generate suitable locations. (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. (cp_parser_functional_cast): Convert return type and local "cast" to cp_expr. Generate suitable locations. (cp_parser_objc_expression): Convert return type to cp_expr.k Generate (cp_parser_objc_message_expression): Generate suitable locations. (cp_parser_objc_encode_expression): Convert return type to cp_expr. Generate suitable locations. (cp_parser_objc_protocol_expression): Generate suitable locations. (cp_parser_objc_selector_expression): Generate suitable locations. (cp_parser_omp_for_cond): Attempt to use the location of "cond" for the binary op. (cp_parser_transaction_expression): Issue the tm-not-enabled error at the location of the __transaction_foo token, rather than at input_location. * semantics.c (finish_parenthesized_expr): Convert return type and param to cp_expr. Preserve location. (perform_koenig_lookup): Likewise for return type and param. (finish_increment_expr): Likewise. Generate suitable locations. (finish_unary_op_expr): Likewise for return type and local "result". Generate suitable locations. (finish_id_expression): Convert return type to cp_expr and use cp_expr ctor to preserve location information. * typeck.c (build_class_member_access_expr): Convert param to cp_expr. (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_nop): Preserve the location of 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/cpp0x/nsdmi-template14.C: Move dg-error directive. * g++.dg/gomp/loop-1.C: Update dg-error locations. * g++.dg/plugin/diagnostic-test-expressions-1.C: New file, adapted from gcc.dg/plugin/diagnostic-test-expressions-1.c. * g++.dg/plugin/plugin.exp (plugin_test_list): Add the above. * g++.dg/template/crash55.C: Update dg-error directives. * g++.dg/template/pseudodtor3.C: Update column numbers in dg-error directives. * g++.dg/template/pr64100.C: Update location of dg-error directive. * g++.dg/template/ref3.C: Add XFAIL (PR c++/68699). * g++.dg/ubsan/pr63956.C: Update dg directives to reflect improved location information. * g++.dg/warn/pr35635.C (func3): Update location of a dg-warning. * g++.dg/warn/Wconversion-real-integer2.C: Update location of dg-warning; add a dg-message. * obj-c++.dg/plugin/diagnostic-test-expressions-1.mm: New file, based on objc.dg/plugin/diagnostic-test-expressions-1.m. * obj-c++.dg/plugin/plugin.exp: New file, based on objc.dg/plugin/plugin.exp. From-SVN: r231293 --- gcc/ChangeLog | 12 + gcc/convert.c | 9 +- gcc/cp/ChangeLog | 136 +++ gcc/cp/cp-tree.h | 82 +- gcc/cp/cvt.c | 4 +- gcc/cp/name-lookup.c | 6 +- gcc/cp/name-lookup.h | 2 +- gcc/cp/parser.c | 591 +++++++++---- gcc/cp/semantics.c | 53 +- gcc/cp/typeck.c | 42 +- gcc/testsuite/ChangeLog | 24 + gcc/testsuite/g++.dg/cpp0x/nsdmi-template14.C | 4 +- gcc/testsuite/g++.dg/gomp/loop-1.C | 32 +- .../plugin/diagnostic-test-expressions-1.C | 784 ++++++++++++++++++ gcc/testsuite/g++.dg/plugin/plugin.exp | 5 +- gcc/testsuite/g++.dg/template/crash55.C | 3 +- gcc/testsuite/g++.dg/template/pr64100.C | 4 +- gcc/testsuite/g++.dg/template/pseudodtor3.C | 4 +- gcc/testsuite/g++.dg/template/ref3.C | 3 +- gcc/testsuite/g++.dg/ubsan/pr63956.C | 28 +- .../g++.dg/warn/Wconversion-real-integer2.C | 4 +- gcc/testsuite/g++.dg/warn/pr35635.C | 6 +- .../plugin/diagnostic-test-expressions-1.mm | 94 +++ gcc/testsuite/obj-c++.dg/plugin/plugin.exp | 90 ++ gcc/tree.c | 25 +- gcc/tree.h | 17 +- 26 files changed, 1822 insertions(+), 242 deletions(-) create mode 100644 gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C create mode 100644 gcc/testsuite/obj-c++.dg/plugin/diagnostic-test-expressions-1.mm create mode 100644 gcc/testsuite/obj-c++.dg/plugin/plugin.exp diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5ff2fbf315c..9aba352870c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2015-12-04 David Malcolm + + * convert.c (convert_to_real_1): When converting from a + REAL_TYPE, preserve the location of EXPR in the result. + * 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. + (get_finish): New inline function. + (set_source_range): Convert return type from void to location_t. + (make_location): New decl. + 2015-12-04 Jakub Jelinek PR c/68656 diff --git a/gcc/convert.c b/gcc/convert.c index e27a6feeda5..8fb86240189 100644 --- a/gcc/convert.c +++ b/gcc/convert.c @@ -362,10 +362,11 @@ convert_to_real_1 (tree type, tree expr, bool fold_p) case REAL_TYPE: /* Ignore the conversion if we don't need to store intermediate results and neither type is a decimal float. */ - return build1 ((flag_float_store - || DECIMAL_FLOAT_TYPE_P (type) - || DECIMAL_FLOAT_TYPE_P (itype)) - ? CONVERT_EXPR : NOP_EXPR, type, expr); + return build1_loc (loc, + (flag_float_store + || DECIMAL_FLOAT_TYPE_P (type) + || DECIMAL_FLOAT_TYPE_P (itype)) + ? CONVERT_EXPR : NOP_EXPR, type, expr); case INTEGER_TYPE: case ENUMERAL_TYPE: diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 711169e8f02..dd56155b349 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,139 @@ +2015-12-04 David Malcolm + + * cp-tree.h (class cp_expr): New class. + (finish_parenthesized_expr): Convert return type and param to + cp_expr. + (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. + * cvt.c (cp_convert_and_check): When warning about conversions, + attempt to use the location of "expr" if available, otherwise + falling back to the old behavior of using input_location. + * name-lookup.c (lookup_arg_dependent_1): Convert return type from + tree to cp_expr. + (lookup_arg_dependent): Likewise; also for local "ret". + * name-lookup.h (lookup_arg_dependent): Likewise for return type. + * parser.c (cp_lexer_previous_token): Skip past purged tokens. + (struct cp_parser_expression_stack_entry): Convert field "lhs" to + cp_expr. + (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_statement_expr): Convert return type to cp_expr. + Generate a suitable location for the expr and return it via the + cp_expr ctor. + (cp_parser_fold_expression): Convert return type to cp_expr. + (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. + Preserve the location for "this" tokens. Generate suitable + locations for "__builtin_va_arg" constructs and for + Objective C 2.0 dot-syntax. Set the location for the result of + finish_id_expression. + (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". Generate suitable locations for + C++-style casts, "_Cilk_spawn" constructs. Convert local + "initializer" to cp_expr and use it to preserve the location of + compound literals. Capture the location of the closing + parenthesis of a call site via + 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. Generate and set a location. + (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 addresses of + labels and for cast expressions. Call cp_expr::set_location where + necessary. Preserve the locations of negated numeric literals. + (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, adding a + cp_expr::set_location to the latter case. + (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. Remove saving of input_location in favor of a + call to cp_expr::set_location. + (cp_parser_expression): Convert return type and locals + "expression" and "assignment_expression" to cp_expr. Build a + meaningful spelling range for assignment expressions. + (cp_parser_constant_expression): Likewise for return type and + local "expression". + (cp_parser_builtin_offsetof): Convert return type and local "expr" + to cp_expr. Generate suitable locations. + (cp_parser_lambda_expression): Convert return return type to + cp_expr. + (cp_parser_operator_function_id): Likewise. + (cp_parser_operator): Likewise. Generate a meaningful range, + using cp_expr's ctor to return it. + (cp_parser_template_id): When converting a token to + CPP_TEMPLATE_ID, update the location. + (cp_parser_initializer_clause): Convert return type and local + "initializer" to cp_expr. + (cp_parser_braced_list): Likewise for return type. Generate + suitable locations. + (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. + (cp_parser_functional_cast): Convert return type and local "cast" + to cp_expr. Generate suitable locations. + (cp_parser_objc_expression): Convert return type to cp_expr.k Generate + (cp_parser_objc_message_expression): Generate suitable locations. + (cp_parser_objc_encode_expression): Convert return type to + cp_expr. Generate suitable locations. + (cp_parser_objc_protocol_expression): Generate suitable locations. + (cp_parser_objc_selector_expression): Generate suitable locations. + (cp_parser_omp_for_cond): Attempt to use the location + of "cond" for the binary op. + (cp_parser_transaction_expression): Issue the tm-not-enabled error + at the location of the __transaction_foo token, rather than at + input_location. + * semantics.c (finish_parenthesized_expr): Convert return type and + param to cp_expr. Preserve location. + (perform_koenig_lookup): Likewise for return type + and param. + (finish_increment_expr): Likewise. Generate suitable locations. + (finish_unary_op_expr): Likewise for return type and local "result". + Generate suitable locations. + (finish_id_expression): Convert return type to cp_expr and use + cp_expr ctor to preserve location information. + * typeck.c (build_class_member_access_expr): Convert param to + cp_expr. + (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_nop): Preserve the location of 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. + 2015-12-03 Cesar Philippidis * parser.c (cp_ensure_no_oacc_routine): Update error message. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 38ae70f7461..6ddab8a57cf 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -40,6 +40,68 @@ 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) {} + + 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) + { + set_location (make_location (m_loc, 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_?: @@ -6291,7 +6353,7 @@ extern tree finish_asm_stmt (int, tree, tree, tree, tree, tree); extern tree finish_label_stmt (tree); extern void finish_label_decl (tree); -extern tree finish_parenthesized_expr (tree); +extern cp_expr finish_parenthesized_expr (cp_expr); extern tree force_paren_expr (tree); extern tree finish_non_static_data_member (tree, tree, tree); extern tree begin_stmt_expr (void); @@ -6299,15 +6361,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 *, +extern cp_expr perform_koenig_lookup (cp_expr, vec *, tsubst_flags_t); extern tree finish_call_expr (tree, vec **, 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); @@ -6321,7 +6383,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, @@ -6564,9 +6626,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); @@ -6588,7 +6650,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, @@ -6608,8 +6670,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/cvt.c b/gcc/cp/cvt.c index ebca00497e1..f24f28059ba 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -650,8 +650,8 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain) folded_result = fold_simple (folded_result); if (!TREE_OVERFLOW_P (folded) && folded_result != error_mark_node) - warnings_for_convert_and_check (input_location, type, folded, - folded_result); + warnings_for_convert_and_check (EXPR_LOC_OR_LOC (expr, input_location), + type, folded, folded_result); } return result; diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index cebe57ead77..86c07ef02b2 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 *args) { struct arg_lookup k; @@ -5720,10 +5720,10 @@ lookup_arg_dependent_1 (tree name, tree fns, vec *args) /* Wrapper for lookup_arg_dependent_1. */ -tree +cp_expr lookup_arg_dependent (tree name, tree fns, vec *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 d430edb73b7..d2453e95ec5 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 *); +extern cp_expr lookup_arg_dependent (tree, tree, vec *); 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 1c143541045..17dba0d0dc6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -733,6 +733,13 @@ cp_lexer_previous_token (cp_lexer *lexer) { cp_token_position tp = cp_lexer_previous_token_position (lexer); + /* Skip past purged tokens. */ + while (tp->purged_p) + { + gcc_assert (tp != lexer->buffer->address ()); + tp--; + } + return cp_lexer_token_at (lexer, tp); } @@ -1793,7 +1800,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; @@ -1947,15 +1954,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] */ @@ -1965,11 +1972,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); @@ -1977,19 +1984,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 *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 *); @@ -2007,23 +2014,23 @@ static vec *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 +static cp_expr 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); @@ -2178,9 +2185,9 @@ 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 +static cp_expr cp_parser_braced_list (cp_parser*, bool*); static vec *cp_parser_initializer_list (cp_parser *, bool *); @@ -2249,9 +2256,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] */ @@ -2389,7 +2396,7 @@ static tree cp_parser_objc_message_args (cp_parser *); static tree cp_parser_objc_message_expression (cp_parser *); -static tree cp_parser_objc_encode_expression +static cp_expr cp_parser_objc_encode_expression (cp_parser *); static tree cp_parser_objc_defs_expression (cp_parser *); @@ -2397,7 +2404,7 @@ static tree cp_parser_objc_protocol_expression (cp_parser *); static tree cp_parser_objc_selector_expression (cp_parser *); -static tree cp_parser_objc_expression +static cp_expr cp_parser_objc_expression (cp_parser *); static bool cp_parser_objc_selector_p (enum cpp_ttype); @@ -2422,7 +2429,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); @@ -2432,7 +2439,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); @@ -2448,7 +2455,7 @@ static void cp_parser_perform_template_parameter_access_checks (vec *); static tree cp_parser_single_declaration (cp_parser *, vec *, bool, bool, bool *); -static tree cp_parser_functional_cast +static cp_expr cp_parser_functional_cast (cp_parser *, tree); static tree cp_parser_save_member_function_body (cp_parser *, cp_decl_specifier_seq *, cp_declarator *, tree); @@ -3681,7 +3688,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; @@ -3689,7 +3696,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 @@ -3706,7 +3716,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) { @@ -3728,6 +3738,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); @@ -3765,11 +3777,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); @@ -3824,6 +3838,11 @@ 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_finish (last_tok_loc)); + strs = (cpp_string *) obstack_finish (&str_ob); } @@ -3876,7 +3895,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. */ @@ -3927,7 +3946,7 @@ lookup_literal_operator (tree name, vec *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); @@ -4019,7 +4038,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); @@ -4272,12 +4291,13 @@ cp_parser_end_tentative_firewall (cp_parser *parser, cp_token_position start, /* Parse a GNU statement-expression, i.e. ({ stmts }), except for the enclosing parentheses. */ -static tree +static cp_expr cp_parser_statement_expr (cp_parser *parser) { cp_token_position start = cp_parser_start_tentative_firewall (parser); /* Consume the '('. */ + location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); /* Start the statement-expression. */ tree expr = begin_stmt_expr (); @@ -4286,11 +4306,13 @@ cp_parser_statement_expr (cp_parser *parser) /* Finish up. */ expr = finish_stmt_expr (expr, false); /* Consume the ')'. */ + location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location; if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) cp_parser_skip_to_end_of_statement (parser); cp_parser_end_tentative_firewall (parser, start, expr); - return expr; + location_t combined_loc = make_location (start_loc, start_loc, finish_loc); + return cp_expr (expr, combined_loc); } /* Expressions [gram.expr] */ @@ -4420,7 +4442,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; @@ -4540,7 +4562,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, @@ -4625,7 +4647,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: @@ -4683,9 +4705,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 @@ -4730,7 +4754,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); @@ -4750,7 +4778,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; @@ -4771,20 +4799,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: @@ -4798,7 +4826,7 @@ cp_parser_primary_expression (cp_parser *parser, /* Pointers cannot appear in constant-expressions. */ if (cp_parser_non_integral_constant_expression (parser, NIC_THIS)) return error_mark_node; - return finish_this_expr (); + return cp_expr (finish_this_expr (), token->location); /* The `operator' keyword can be the beginning of an id-expression. */ @@ -4847,7 +4875,8 @@ cp_parser_primary_expression (cp_parser *parser, tree expression; tree type; source_location type_location; - + location_t start_loc + = cp_lexer_peek_token (parser->lexer)->location; /* The `__builtin_va_arg' construct is used to handle `va_arg'. Consume the `__builtin_va_arg' token. */ cp_lexer_consume_token (parser->lexer); @@ -4861,13 +4890,22 @@ cp_parser_primary_expression (cp_parser *parser, /* Parse the type-id. */ type = cp_parser_type_id (parser); /* Look for the closing `)'. */ + location_t finish_loc + = cp_lexer_peek_token (parser->lexer)->location; cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); /* Using `va_arg' in a constant-expression is not allowed. */ if (cp_parser_non_integral_constant_expression (parser, NIC_VA_ARG)) return error_mark_node; - return build_x_va_arg (type_location, expression, type); + /* Construct a location of the form: + __builtin_va_arg (v, int) + ~~~~~~~~~~~~~~~~~~~~~^~~~ + with the caret at the type, ranging from the start of the + "__builtin_va_arg" token to the close paren. */ + location_t combined_loc + = make_location (type_location, start_loc, finish_loc); + return build_x_va_arg (combined_loc, expression, type); } case RID_OFFSETOF: @@ -4932,14 +4970,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, @@ -5004,12 +5042,36 @@ cp_parser_primary_expression (cp_parser *parser, if (component == error_mark_node) return error_mark_node; - return objc_build_class_component_ref (id_expression, component); + tree result = objc_build_class_component_ref (id_expression, + component); + /* Build a location of the form: + expr.component + ~~~~~^~~~~~~~~ + with caret at the start of the component name (at + input_location), ranging from the start of the id_expression + to the end of the component name. */ + location_t combined_loc + = make_location (input_location, id_expression.get_start (), + get_finish (input_location)); + protected_set_expr_location (result, combined_loc); + return result; } /* 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. */ @@ -5050,7 +5112,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; } } @@ -5068,6 +5130,7 @@ cp_parser_primary_expression (cp_parser *parser, id_expr_token->location)); if (error_msg) cp_parser_error (parser, error_msg); + decl.set_location (id_expr_token->location); return decl; } @@ -5078,7 +5141,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, @@ -5123,7 +5186,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, @@ -5258,7 +5321,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, @@ -5521,7 +5584,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); @@ -6111,7 +6174,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) @@ -6120,13 +6183,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) @@ -6137,7 +6202,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; @@ -6170,7 +6235,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; @@ -6203,6 +6271,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, default: gcc_unreachable (); } + + /* Construct a location e.g. : + reinterpret_cast (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; @@ -6271,6 +6347,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, case RID_CILK_SPAWN: { + location_t cilk_spawn_loc + = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); token = cp_lexer_peek_token (parser->lexer); if (token->type == CPP_SEMICOLON) @@ -6312,8 +6390,17 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, } else { + location_t loc = postfix_expression.get_location (); postfix_expression = build_cilk_spawn (token->location, postfix_expression); + /* Build a location of the form: + _Cilk_spawn expr + ~~~~~~~~~~~~^~~~ + with caret at the expr, ranging from the start of the + _Cilk_spawn token to the end of the expression. */ + location_t combined_loc = + make_location (loc, cilk_spawn_loc, get_finish (loc)); + postfix_expression.set_location (combined_loc); if (postfix_expression != error_mark_node) SET_EXPR_LOCATION (postfix_expression, input_location); parser->in_statement = parser->in_statement & ~IN_CILK_SPAWN; @@ -6380,7 +6467,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, if (cp_parser_allow_gnu_extensions_p (parser) && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { - tree initializer = NULL_TREE; + cp_expr initializer = NULL_TREE; cp_parser_parse_tentatively (parser); @@ -6435,6 +6522,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, postfix_expression = finish_compound_literal (type, initializer, tf_warning_or_error); + postfix_expression.set_location (initializer.get_location ()); break; } } @@ -6482,6 +6570,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; @@ -6495,6 +6586,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 *args; + location_t close_paren_loc; is_member_access = false; @@ -6513,7 +6605,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 @@ -6655,7 +6748,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); + postfix_expression.set_location (combined_loc); /* The POSTFIX_EXPRESSION is certainly no longer an id. */ idk = CP_ID_KIND_NONE; @@ -6716,7 +6812,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; } @@ -6916,7 +7014,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) { @@ -6924,6 +7022,7 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, bool dependent_p; bool pseudo_destructor_p; tree scope = NULL_TREE; + location_t start_loc = postfix_expression.get_start (); /* If this is a `->' operator, dereference the pointer. */ if (token_type == CPP_DEREF) @@ -6953,7 +7052,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 @@ -7070,6 +7169,16 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, = finish_class_member_access_expr (postfix_expression, name, template_p, tf_warning_or_error); + /* Build a location e.g.: + ptr->access_expr + ~~~^~~~~~~~~~~~~ + where the caret is at the deref token, ranging from + the start of postfix_expression to the end of the access expr. */ + location_t end_loc + = get_finish (cp_lexer_previous_token (parser->lexer)->location); + location_t combined_loc + = make_location (input_location, start_loc, end_loc); + protected_set_expr_location (postfix_expression, combined_loc); } } @@ -7118,7 +7227,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 *expression_list; bool fold_expr_p = is_attribute_list != non_attr; @@ -7222,6 +7332,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; @@ -7391,7 +7504,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) { @@ -7589,14 +7702,22 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, { tree identifier; tree expression; - location_t loc = token->location; + location_t start_loc = token->location; /* Consume the '&&' token. */ cp_lexer_consume_token (parser->lexer); /* Look for the identifier. */ + location_t finish_loc + = get_finish (cp_lexer_peek_token (parser->lexer)->location); identifier = cp_parser_identifier (parser); + /* Construct a location of the form: + &&label + ^~~~~~~ + with caret==start at the "&&", finish at the end of the label. */ + location_t combined_loc + = make_location (start_loc, start_loc, finish_loc); /* Create an expression representing the address. */ - expression = finish_label_address_expr (identifier, loc); + expression = finish_label_address_expr (identifier, combined_loc); if (cp_parser_non_integral_constant_expression (parser, NIC_ADDR_LABEL)) expression = error_mark_node; @@ -7605,8 +7726,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); @@ -7622,6 +7743,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) { @@ -7630,6 +7759,9 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, expression = build_x_indirect_ref (loc, cast_expression, RO_UNARY_STAR, complain); + /* TODO: build_x_indirect_ref does not always honor the + location, so ensure it is set. */ + expression.set_location (loc); break; case ADDR_EXPR: @@ -7639,6 +7771,9 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, expression = build_x_unary_op (loc, unary_operator, cast_expression, complain); + /* TODO: build_x_unary_op does not always honor the location, + so ensure it is set. */ + expression.set_location (loc); break; case PREINCREMENT_EXPR: @@ -7659,7 +7794,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, cast_expression); if (CONSTANT_CLASS_P (folded) && !TREE_OVERFLOW (folded)) { - expression = folded; + expression = cp_expr (folded, loc); break; } } @@ -7737,6 +7872,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, @@ -7821,9 +7958,19 @@ 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_finish (end_tok->location); + 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) @@ -8203,7 +8350,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) { @@ -8211,7 +8358,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; @@ -8224,7 +8371,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 @@ -8326,7 +8475,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; } } @@ -8419,7 +8576,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, @@ -8429,7 +8586,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; @@ -8569,6 +8726,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 @@ -8579,18 +8741,22 @@ 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, current.lhs_type, - rhs, rhs_type, &overload, - complain_flags (decltype_p)); + { + current.lhs = build_x_binary_op (combined_loc, current.tree_type, + current.lhs, current.lhs_type, + rhs, rhs_type, &overload, + complain_flags (decltype_p)); + /* TODO: build_x_binary_op doesn't always honor the location. */ + current.lhs.set_location (combined_loc); + } 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. @@ -8607,7 +8773,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, @@ -8631,10 +8797,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; @@ -8673,6 +8839,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, @@ -8692,11 +8867,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. */ @@ -8725,10 +8900,10 @@ cp_parser_assignment_expression (cp_parser* parser, cp_id_kind * pidk, if (assignment_operator != ERROR_MARK) { bool non_constant_p; - 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); @@ -8739,14 +8914,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. */ - saved_input_location = input_location; - input_location = loc; + 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 ()); expr = build_x_modify_expr (loc, expr, assignment_operator, rhs, complain_flags (decltype_p)); - input_location = saved_input_location; + /* TODO: build_x_modify_expr doesn't honor the location, + so we must set it here. */ + expr.set_location (loc); } } } @@ -8855,16 +9038,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 @@ -8886,9 +9069,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) @@ -8915,7 +9106,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) @@ -8923,7 +9114,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 @@ -8996,13 +9187,15 @@ cp_parser_constant_expression (cp_parser* parser, | offsetof-member-designator "[" expression "]" | offsetof-member-designator "->" id-expression */ -static tree +static cp_expr cp_parser_builtin_offsetof (cp_parser *parser) { int save_ice_p, save_non_ice_p; - tree type, expr; + tree type; + cp_expr expr; cp_id_kind dummy; cp_token *token; + location_t finish_loc; /* We're about to accept non-integral-constant things, but will definitely yield an integral constant expression. Save and @@ -9010,6 +9203,8 @@ cp_parser_builtin_offsetof (cp_parser *parser) save_ice_p = parser->integral_constant_expression_p; save_non_ice_p = parser->non_integral_constant_expression_p; + location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; + /* Consume the "__builtin_offsetof" token. */ cp_lexer_consume_token (parser->lexer); /* Consume the opening `('. */ @@ -9055,6 +9250,7 @@ cp_parser_builtin_offsetof (cp_parser *parser) case CPP_CLOSE_PAREN: /* Consume the ")" token. */ + finish_loc = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); goto success; @@ -9069,7 +9265,15 @@ cp_parser_builtin_offsetof (cp_parser *parser) } success: - expr = finish_offsetof (expr, loc); + /* Make a location of the form: + __builtin_offsetof (struct s, f) + ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~ + with caret at the type-id, ranging from the start of the + "_builtin_offsetof" token to the close paren. */ + loc = make_location (loc, start_loc, finish_loc); + /* The result will be an INTEGER_CST, so we need to explicitly + preserve the location. */ + expr = cp_expr (finish_offsetof (expr, loc), loc); failure: parser->integral_constant_expression_p = save_ice_p; @@ -9293,7 +9497,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 (); @@ -13290,7 +13494,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. */ @@ -13330,7 +13534,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; @@ -13339,6 +13543,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) { @@ -13355,7 +13562,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); @@ -13366,7 +13573,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); } @@ -13374,7 +13582,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: @@ -13620,7 +13830,7 @@ cp_parser_operator (cp_parser* parser) id = error_mark_node; } - return id; + return cp_expr (id, start_loc); } /* Parse a template-declaration. @@ -14530,6 +14740,18 @@ cp_parser_template_id (cp_parser *parser, /* Reset the contents of the START_OF_ID token. */ token->type = CPP_TEMPLATE_ID; + + /* Update the location to be of the form: + template-name < template-argument-list [opt] > + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + with caret == start at the start of the template-name, + ranging until the closing '>'. */ + location_t finish_loc + = get_finish (cp_lexer_previous_token (parser->lexer)->location); + location_t combined_loc + = make_location (token->location, token->location, finish_loc); + token->location = combined_loc; + /* Retrieve any deferred checks. Do not pop this access checks yet so the memory will not be reclaimed during token replacing below. */ token->u.tree_check_value = ggc_cleared_alloc (); @@ -20316,10 +20538,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; @@ -20352,10 +20574,11 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p) trailing `,' was provided. NON_CONSTANT_P is as for cp_parser_initializer. */ -static tree +static cp_expr cp_parser_braced_list (cp_parser* parser, bool* non_constant_p) { tree initializer; + location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; /* Consume the `{' token. */ cp_lexer_consume_token (parser->lexer); @@ -20374,9 +20597,18 @@ cp_parser_braced_list (cp_parser* parser, bool* non_constant_p) else *non_constant_p = false; /* Now, there should be a trailing `}'. */ + location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location; cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); TREE_TYPE (initializer) = init_list_type_node; - return initializer; + + cp_expr result (initializer); + /* Build a location of the form: + { ... } + ^~~~~~~ + with caret==start at the open brace, finish at the close brace. */ + location_t combined_loc = make_location (start_loc, start_loc, finish_loc); + result.set_location (combined_loc); + return result; } /* Consume tokens up to, and including, the next non-nested closing `]'. @@ -24077,7 +24309,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, @@ -24319,7 +24551,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 @@ -25323,7 +25555,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, @@ -25333,14 +25565,16 @@ cp_parser_simple_cast_expression (cp_parser *parser) /* Parse a functional cast to TYPE. Returns an expression representing the cast. */ -static tree +static cp_expr cp_parser_functional_cast (cp_parser* parser, tree type) { vec *vec; tree expression_list; - tree cast; + cp_expr cast; bool nonconst_p; + location_t start_loc = input_location; + if (!type) type = error_mark_node; @@ -25352,9 +25586,21 @@ cp_parser_functional_cast (cp_parser* parser, tree type) CONSTRUCTOR_IS_DIRECT_INIT (expression_list) = 1; if (TREE_CODE (type) == TYPE_DECL) type = TREE_TYPE (type); - return finish_compound_literal (type, expression_list, + + cast = finish_compound_literal (type, expression_list, tf_warning_or_error); - } + /* Create a location of the form: + type_name{i, f} + ^~~~~~~~~~~~~~~ + with caret == start at the start of the type name, + finishing at the closing brace. */ + location_t finish_loc + = get_finish (cp_lexer_previous_token (parser->lexer)->location); + location_t combined_loc = make_location (start_loc, start_loc, + finish_loc); + cast.set_location (combined_loc); + return cast; + } vec = cp_parser_parenthesized_expression_list (parser, non_attr, @@ -25380,6 +25626,16 @@ cp_parser_functional_cast (cp_parser* parser, tree type) && cp_parser_non_integral_constant_expression (parser, NIC_CONSTRUCTOR)) return error_mark_node; + + /* Create a location of the form: + float(i) + ^~~~~~~~ + with caret == start at the start of the type name, + finishing at the closing paren. */ + location_t finish_loc + = get_finish (cp_lexer_previous_token (parser->lexer)->location); + location_t combined_loc = make_location (start_loc, start_loc, finish_loc); + cast.set_location (combined_loc); return cast; } @@ -27133,7 +27389,7 @@ cp_parser_allow_gnu_extensions_p (cp_parser* parser) Returns a tree representation of the expression. */ -static tree +static cp_expr cp_parser_objc_expression (cp_parser* parser) { /* Try to figure out what kind of declaration is present. */ @@ -27185,12 +27441,23 @@ cp_parser_objc_message_expression (cp_parser* parser) { tree receiver, messageargs; + location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); /* Eat '['. */ receiver = cp_parser_objc_message_receiver (parser); messageargs = cp_parser_objc_message_args (parser); + location_t end_loc = cp_lexer_peek_token (parser->lexer)->location; cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); - return objc_build_message_expr (receiver, messageargs); + tree result = objc_build_message_expr (receiver, messageargs); + + /* Construct a location e.g. + [self func1:5] + ^~~~~~~~~~~~~~ + ranging from the '[' to the ']', with the caret at the start. */ + location_t combined_loc = make_location (start_loc, start_loc, end_loc); + protected_set_expr_location (result, combined_loc); + + return result; } /* Parse an objc-message-receiver. @@ -27307,11 +27574,12 @@ cp_parser_objc_message_args (cp_parser* parser) Returns an encoded representation of the type argument. */ -static tree +static cp_expr cp_parser_objc_encode_expression (cp_parser* parser) { tree type; cp_token *token; + location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); /* Eat '@encode'. */ cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); @@ -27339,7 +27607,16 @@ cp_parser_objc_encode_expression (cp_parser* parser) return value; } - return objc_build_encode_expr (type); + + /* Build a location of the form: + @encode(int) + ^~~~~~~~~~~~ + with caret==start at the @ token, finishing at the close paren. */ + location_t combined_loc + = make_location (start_loc, start_loc, + cp_lexer_previous_token (parser->lexer)->location); + + return cp_expr (objc_build_encode_expr (type), combined_loc); } /* Parse an Objective-C @defs expression. */ @@ -27368,13 +27645,23 @@ static tree cp_parser_objc_protocol_expression (cp_parser* parser) { tree proto; + location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); /* Eat '@protocol'. */ cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); proto = cp_parser_identifier (parser); cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); - return objc_build_protocol_expr (proto); + /* Build a location of the form: + @protocol(prot) + ^~~~~~~~~~~~~~~ + with caret==start at the @ token, finishing at the close paren. */ + location_t combined_loc + = make_location (start_loc, start_loc, + cp_lexer_previous_token (parser->lexer)->location); + tree result = objc_build_protocol_expr (proto); + protected_set_expr_location (result, combined_loc); + return result; } /* Parse an Objective-C selector expression. @@ -27450,7 +27737,18 @@ cp_parser_objc_selector_expression (cp_parser* parser) finish_selector: cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); - return objc_build_selector_expr (loc, sel_seq); + + /* Build a location of the form: + @selector(func) + ^~~~~~~~~~~~~~~ + with caret==start at the @ token, finishing at the close paren. */ + location_t combined_loc + = make_location (loc, loc, + cp_lexer_previous_token (parser->lexer)->location); + tree result = objc_build_selector_expr (combined_loc, sel_seq); + /* TODO: objc_build_selector_expr doesn't always honor the location. */ + protected_set_expr_location (result, combined_loc); + return result; } /* Parse a list of identifiers. @@ -32560,7 +32858,8 @@ cp_parser_omp_for_cond (cp_parser *parser, tree decl, enum tree_code code) || CLASS_TYPE_P (TREE_TYPE (decl)))) return cond; - return build_x_binary_op (input_location, TREE_CODE (cond), + return build_x_binary_op (EXPR_LOC_OR_LOC (cond, input_location), + TREE_CODE (cond), TREE_OPERAND (cond, 0), ERROR_MARK, TREE_OPERAND (cond, 1), ERROR_MARK, /*overload=*/NULL, tf_warning_or_error); @@ -36287,16 +36586,18 @@ cp_parser_transaction_expression (cp_parser *parser, enum rid keyword) cp_token *token; tree expr, noex; bool noex_expr; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; gcc_assert (keyword == RID_TRANSACTION_ATOMIC || keyword == RID_TRANSACTION_RELAXED); if (!flag_tm) - error (keyword == RID_TRANSACTION_RELAXED - ? G_("%<__transaction_relaxed%> without transactional memory " - "support enabled") - : G_("%<__transaction_atomic%> without transactional memory " - "support enabled")); + error_at (loc, + keyword == RID_TRANSACTION_RELAXED + ? G_("%<__transaction_relaxed%> without transactional memory " + "support enabled") + : G_("%<__transaction_atomic%> without transactional memory " + "support enabled")); token = cp_parser_require_keyword (parser, keyword, (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 3bb61847ca8..82f7d3a2c5e 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1672,8 +1672,8 @@ force_paren_expr (tree expr) /* Finish a parenthesized expression EXPR. */ -tree -finish_parenthesized_expr (tree expr) +cp_expr +finish_parenthesized_expr (cp_expr expr) { if (EXPR_P (expr)) /* This inhibits warnings in c_common_truthvalue_conversion. */ @@ -1688,7 +1688,7 @@ finish_parenthesized_expr (tree expr) if (TREE_CODE (expr) == STRING_CST) PAREN_STRING_LITERAL_P (expr) = 1; - expr = force_paren_expr (expr); + expr = cp_expr (force_paren_expr (expr), expr.get_location ()); return expr; } @@ -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 *args, +cp_expr +perform_koenig_lookup (cp_expr fn, vec *args, tsubst_flags_t complain) { tree identifier = NULL_TREE; @@ -2460,10 +2460,23 @@ finish_call_expr (tree fn, vec **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) -{ - return build_x_unary_op (input_location, code, expr, tf_warning_or_error); +cp_expr +finish_increment_expr (cp_expr expr, enum tree_code code) +{ + /* input_location holds the location of the trailing operator token. + Build a location of the form: + expr++ + ~~~~^~ + with the caret at the operator token, ranging from the start + of EXPR to the end of the operator token. */ + location_t combined_loc = make_location (input_location, + expr.get_start (), + get_finish (input_location)); + cp_expr result = build_x_unary_op (combined_loc, code, expr, + tf_warning_or_error); + /* TODO: build_x_unary_op doesn't honor the location, so set it here. */ + result.set_location (combined_loc); + return result; } /* Finish a use of `this'. Returns an expression for `this'. */ @@ -2557,11 +2570,21 @@ 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); + /* Build a location of the form: + ++expr + ^~~~~~ + with the caret at the operator token, ranging from the start + of the operator token to the end of EXPR. */ + location_t combined_loc = make_location (op_loc, + op_loc, expr.get_finish ()); + cp_expr result = build_x_unary_op (combined_loc, code, expr, complain); + /* TODO: build_x_unary_op doesn't always honor the location. */ + result.set_location (combined_loc); + tree result_ovl, expr_ovl; if (!(complain & tf_warning)) @@ -2581,7 +2604,7 @@ 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; } @@ -3324,7 +3347,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 +3692,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 1d2943f50fb..0a1e446c95c 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; } @@ -2624,7 +2624,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 +2658,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 +2681,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; } @@ -5111,7 +5111,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); @@ -5269,7 +5269,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; @@ -5279,7 +5279,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); } @@ -5314,7 +5314,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; } } @@ -5330,7 +5330,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"); } @@ -5341,7 +5341,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; @@ -5438,7 +5438,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. @@ -7270,6 +7270,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. */ @@ -7775,7 +7787,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/ChangeLog b/gcc/testsuite/ChangeLog index b7effc3b04a..352c0fa3724 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,27 @@ +2015-12-04 David Malcolm + + * g++.dg/cpp0x/nsdmi-template14.C: Move dg-error directive. + * g++.dg/gomp/loop-1.C: Update dg-error locations. + * g++.dg/plugin/diagnostic-test-expressions-1.C: New file, adapted + from gcc.dg/plugin/diagnostic-test-expressions-1.c. + * g++.dg/plugin/plugin.exp (plugin_test_list): Add the above. + * g++.dg/template/crash55.C: Update dg-error directives. + * g++.dg/template/pseudodtor3.C: Update column numbers in dg-error + directives. + * g++.dg/template/pr64100.C: Update location of dg-error + directive. + * g++.dg/template/ref3.C: Add XFAIL (PR c++/68699). + * g++.dg/ubsan/pr63956.C: Update dg directives to reflect + improved location information. + * g++.dg/warn/pr35635.C (func3): Update location of a + dg-warning. + * g++.dg/warn/Wconversion-real-integer2.C: Update location of + dg-warning; add a dg-message. + * obj-c++.dg/plugin/diagnostic-test-expressions-1.mm: New file, + based on objc.dg/plugin/diagnostic-test-expressions-1.m. + * obj-c++.dg/plugin/plugin.exp: New file, based on + objc.dg/plugin/plugin.exp. + 2015-12-04 Jakub Jelinek PR c/68656 diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-template14.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-template14.C index 9cb01f1b7ee..47f5b631bf9 100644 --- a/gcc/testsuite/g++.dg/cpp0x/nsdmi-template14.C +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-template14.C @@ -8,10 +8,10 @@ template struct A // { dg-error "has been parsed" } template struct B { - B* p = new B; + B* p = new B; // { dg-error "recursive instantiation of non-static data" } }; -B<1> x; // { dg-error "recursive instantiation of non-static data" } +B<1> x; struct C { diff --git a/gcc/testsuite/g++.dg/gomp/loop-1.C b/gcc/testsuite/g++.dg/gomp/loop-1.C index 46e707fc4c9..de08eb3271d 100644 --- a/gcc/testsuite/g++.dg/gomp/loop-1.C +++ b/gcc/testsuite/g++.dg/gomp/loop-1.C @@ -86,16 +86,16 @@ f1 (int x) for (j = baz (&i); j < 16; j += 2) ; #pragma omp for collapse(2) - for (i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */ - for (j = 16; j > (i & x); j--) + for (i = 0; i < 16; i++) + for (j = 16; j > (i & x); j--) /* { dg-error "condition expression refers to iteration variable" } */ ; #pragma omp for collapse(2) - for (i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */ - for (j = 0; j < i; j++) + for (i = 0; i < 16; i++) + for (j = 0; j < i; j++) /* { dg-error "condition expression refers to iteration variable" } */ ; #pragma omp for collapse(2) - for (i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */ - for (j = 0; j < i + 4; j++) + for (i = 0; i < 16; i++) + for (j = 0; j < i + 4; j++) /* { dg-error "condition expression refers to iteration variable" } */ ; #pragma omp for collapse(2) for (i = 0; i < j + 4; i++) /* { dg-error "condition expression refers to iteration variable" } */ @@ -110,8 +110,8 @@ f1 (int x) for (j = 0; j < 16; j++) ; #pragma omp for collapse(2) - for (i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */ - for (j = 0; j < baz (&i); j++) + for (i = 0; i < 16; i++) + for (j = 0; j < baz (&i); j++) /* { dg-error "condition expression refers to iteration variable" } */ ; #pragma omp for collapse(2) for (i = 0; i < 16; i += j) /* { dg-error "increment expression refers to iteration variable" } */ @@ -219,20 +219,20 @@ f2 (int x) for (int j = baz (&i); j < 16; j += 2) ; #pragma omp for collapse(2) - for (int i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */ - for (int j = 16; j > (i & x); j--) + for (int i = 0; i < 16; i++) + for (int j = 16; j > (i & x); j--) /* { dg-error "condition expression refers to iteration variable" } */ ; #pragma omp for collapse(2) - for (int i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */ - for (int j = 0; j < i; j++) + for (int i = 0; i < 16; i++) + for (int j = 0; j < i; j++) /* { dg-error "condition expression refers to iteration variable" } */ ; #pragma omp for collapse(2) - for (int i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */ - for (int j = 0; j < i + 4; j++) + for (int i = 0; i < 16; i++) + for (int j = 0; j < i + 4; j++) /* { dg-error "condition expression refers to iteration variable" } */ ; #pragma omp for collapse(2) - for (int i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */ - for (int j = 0; j < baz (&i); j++) + for (int i = 0; i < 16; i++) + for (int j = 0; j < baz (&i); j++) /* { dg-error "condition expression refers to iteration variable" } */ ; #pragma omp for collapse(2) for (int i = 0; i < 16; i++) /* { dg-error "increment expression refers to iteration variable" } */ 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 00000000000..4d3b07cbc5f --- /dev/null +++ b/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C @@ -0,0 +1,784 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdiagnostics-show-caret -fpermissive" } */ + +/* 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 "" } */ +} + +void test_numeric_literals (int i) +{ + __emit_expression_range (0, 42 + i ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, 42 + i ); + ~~~^~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, i + 42 ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, i + 42 ); + ~~^~~~ + { dg-end-multiline-output "" } */ + + /* Verify locations of negative literals (via folding of + unary negation). */ + + __emit_expression_range (0, -42 + i ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, -42 + i ); + ~~~~^~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, i + -42 ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, i + -42 ); + ~~^~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, i ? 0 : -1 ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, i ? 0 : -1 ); + ~~^~~~~~~~ + { dg-end-multiline-output "" } */ +} + +/* Braced initializers. ***************************************/ + +/* We can't test the ranges of these 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. */ + +#define vector(elcount, type) \ +__attribute__((vector_size((elcount)*sizeof(type)))) type + +void test_braced_init (void) +{ + /* Verify start of range. */ + __emit_expression_range (0, (vector(4, float)){2., 2., 2., 2.} + 1); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, (vector(4, float)){2., 2., 2., 2.} + 1); + ~~~~~~~~~~~~~~~~~^~~ + { dg-end-multiline-output "" } */ + + /* Verify end of range. */ + __emit_expression_range (0, 1 + (vector(4, float)){2., 2., 2., 2.}); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, 1 + (vector(4, float)){2., 2., 2., 2.}); + ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +} + +/* Statement expressions. ***************************************/ + +void test_statement_expression (void) +{ + __emit_expression_range (0, ({ static int a; a; }) + 1); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, ({ static int a; a; }) + 1); + ~~~~~~~~~~~~~~~~~~~~~~~^~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, 1 + ({ static int a; a; }) ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, 1 + ({ static int a; a; }) ); + ~~^~~~~~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +} + +/* Other expressions. */ + +void test_address_of_label (void) +{ + label: + __emit_expression_range (0, &&label ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, &&label ); + ^~~~~~~ + { dg-end-multiline-output "" } */ +} + +void test_transaction_expressions (void) +{ + int i; + i = __transaction_atomic (42); /* { dg-error "without transactional memory support enabled" } */ +/* { dg-begin-multiline-output "" } + i = __transaction_atomic (42); + ^~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + i = __transaction_relaxed (42); /* { dg-error "without transactional memory support enabled" } */ +/* { dg-begin-multiline-output "" } + i = __transaction_relaxed (42); + ^~~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +} + +void test_keywords (int i) +{ + __emit_expression_range (0, __FUNCTION__[i] ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, __FUNCTION__[i] ); + ~~~~~~~~~~~~~~^ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, __PRETTY_FUNCTION__[i] ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, __PRETTY_FUNCTION__[i] ); + ~~~~~~~~~~~~~~~~~~~~~^ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, __func__[i] ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, __func__[i] ); + ~~~~~~~~~~^ + { dg-end-multiline-output "" } */ +} + +void test_builtin_va_arg (__builtin_va_list v) +{ + __emit_expression_range (0, __builtin_va_arg (v, int) ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, __builtin_va_arg (v, int) ); + ~~~~~~~~~~~~~~~~~~~~~^~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, __builtin_va_arg (v, int) + 1 ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, __builtin_va_arg (v, int) + 1 ); + ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~ + { dg-end-multiline-output "" } */ +} + +struct s { int i; float f; }; + +void test_builtin_offsetof (int i) +{ + __emit_expression_range (0, i + __builtin_offsetof (struct s, f) ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, i + __builtin_offsetof (struct s, f) ); + ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, __builtin_offsetof (struct s, f) + i ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, __builtin_offsetof (struct s, f) + i ); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~ + { 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 "" } */ + +} + +int bar (int); +void test_combinations (int a) +{ + __emit_expression_range (0, bar (a) > a ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, bar (a) > 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 (); + int pub (); +private: + int priv (); +}; +class derived : public base { ~derived (); }; + +void test_cp_casts (base *ptr) +{ + __emit_expression_range (0, dynamic_cast (ptr)); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, dynamic_cast (ptr)); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, static_cast (ptr)); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, static_cast (ptr)); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, reinterpret_cast (ptr)); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, reinterpret_cast (ptr)); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, const_cast (ptr)); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, const_cast (ptr)); + ^~~~~~~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +} + +void test_functional_casts (int i, float f) +{ + __emit_expression_range (0, float(i)); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, float(i)); + ^~~~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, int(f)); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, int(f)); + ^~~~~~ + { dg-end-multiline-output "" } */ + + __emit_expression_range (0, s{i, f}); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, s{i, f}); + ^~~~~~~ + { dg-end-multiline-output "" } */ +} + +template +class example_template +{ +public: + example_template (TYPENAME v); +}; + +void test_template_id (void) +{ + example_template ; /* { dg-warning "declaration does not declare anything" } */ +/* { dg-begin-multiline-output "" } + example_template ; + ^~~~~~~~~~~~~~~~~~~~~~ + { 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. */ + + __emit_expression_range (0, new example_template (42)); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, new example_template (42)); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +} + +void test_methods () +{ + __emit_expression_range (0, ((base *)1)->pub () ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, ((base *)1)->pub () ); + ~~~~~~~~~~~~~~~~~^~ + { dg-end-multiline-output "" } */ + + ((base *)1)->priv (); // { dg-error " is private " } +/* { dg-begin-multiline-output "" } + ((base *)1)->priv (); + ^ + { dg-end-multiline-output "" } + { dg-begin-multiline-output "" } + int priv (); + ^~~~ + { dg-end-multiline-output "" } */ +} + +class tests +{ +public: + void test_method_calls (); + int some_method () const; +}; + +void +tests::test_method_calls () +{ + __emit_expression_range (0, this->some_method () ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range (0, this->some_method () ); + ~~~~~~~~~~~~~~~~~~^~ + { dg-end-multiline-output "" } */ +} diff --git a/gcc/testsuite/g++.dg/plugin/plugin.exp b/gcc/testsuite/g++.dg/plugin/plugin.exp index 3ed13974124..3be89a0f4e8 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/testsuite/g++.dg/template/crash55.C b/gcc/testsuite/g++.dg/template/crash55.C index 9b80fd125da..b9b29f7fc8d 100644 --- a/gcc/testsuite/g++.dg/template/crash55.C +++ b/gcc/testsuite/g++.dg/template/crash55.C @@ -1,6 +1,7 @@ //PR c++/27668 template // { dg-error "nested-name-specifier|two or more|valid type" } +// { dg-error "cast" "" { target c++98_only } 3 } struct A {}; -template void foo(A); // { dg-error "cast|argument" "" { target c++98_only } } +template void foo(A); // { dg-error "template argument 2" "" { target c++98_only } } diff --git a/gcc/testsuite/g++.dg/template/pr64100.C b/gcc/testsuite/g++.dg/template/pr64100.C index 493849f24cf..051800cbca0 100644 --- a/gcc/testsuite/g++.dg/template/pr64100.C +++ b/gcc/testsuite/g++.dg/template/pr64100.C @@ -1,8 +1,8 @@ // { dg-do compile { target c++11 } } template struct foo // { dg-message "note" } -{ // { dg-error "incomplete type" } - static_assert(noexcept(((foo *)1)->~foo()), ""); +{ + static_assert(noexcept(((foo *)1)->~foo()), ""); // { dg-error "incomplete type" } }; template class foo; diff --git a/gcc/testsuite/g++.dg/template/pseudodtor3.C b/gcc/testsuite/g++.dg/template/pseudodtor3.C index 202182f5337..8700bb95252 100644 --- a/gcc/testsuite/g++.dg/template/pseudodtor3.C +++ b/gcc/testsuite/g++.dg/template/pseudodtor3.C @@ -11,7 +11,7 @@ struct A template struct B { T &foo (); - B () { foo.~T (); } // { dg-error "10:invalid use of member" } + B () { foo.~T (); } // { dg-error "15:invalid use of member" } }; B b; @@ -19,7 +19,7 @@ B b; template struct C { T t; - C () { t.~S (); } // { dg-error "10:is not of type" } + C () { t.~S (); } // { dg-error "13:is not of type" } }; C c; diff --git a/gcc/testsuite/g++.dg/template/ref3.C b/gcc/testsuite/g++.dg/template/ref3.C index 976c093a15b..91e3c93a35d 100644 --- a/gcc/testsuite/g++.dg/template/ref3.C +++ b/gcc/testsuite/g++.dg/template/ref3.C @@ -5,7 +5,8 @@ template struct A {}; template struct B { A<(T)0> b; // { dg-error "constant|not a valid" } - A a; // { dg-error "constant|not a valid" } + A a; // { dg-error "constant|not a valid" "" { xfail c++98_only } } + // PR c++/68699 }; B b; diff --git a/gcc/testsuite/g++.dg/ubsan/pr63956.C b/gcc/testsuite/g++.dg/ubsan/pr63956.C index 185a719c8c4..b2656313b33 100644 --- a/gcc/testsuite/g++.dg/ubsan/pr63956.C +++ b/gcc/testsuite/g++.dg/ubsan/pr63956.C @@ -10,15 +10,18 @@ fn1 (int a, int b) { if (b != 2) a <<= b; + // { dg-error "5 << -2.. is negative" "" { target *-*-* } 12 } + // { dg-error "is >= than the precision of the left operand" "" { target *-*-* } 12 } + // { dg-error "-2 << 4.. is negative" "" { target *-*-* } 12 } return a; } constexpr int i1 = fn1 (5, 3); -constexpr int i2 = fn1 (5, -2); // { dg-error "is negative" } -constexpr int i3 = fn1 (5, sizeof (int) * __CHAR_BIT__); // { dg-error "is >= than the precision of the left operand" } -constexpr int i4 = fn1 (5, 256); // { dg-error "is >= than the precision of the left operand" } +constexpr int i2 = fn1 (5, -2); // { dg-message "in constexpr expansion" } +constexpr int i3 = fn1 (5, sizeof (int) * __CHAR_BIT__); // { dg-message "in constexpr expansion" } +constexpr int i4 = fn1 (5, 256); // { dg-message "in constexpr expansion" } constexpr int i5 = fn1 (5, 2); -constexpr int i6 = fn1 (-2, 4); // { dg-error "is negative" } +constexpr int i6 = fn1 (-2, 4); // { dg-message "in constexpr expansion" } constexpr int i7 = fn1 (0, 2); SA (i1 == 40); @@ -30,13 +33,16 @@ fn2 (int a, int b) { if (b != 2) a >>= b; + // { dg-error "4 >> -1.. is negative" "" { target *-*-* } 35 } + // { dg-error "is >= than the precision of the left operand" "" { target *-*-* } 35 } + return a; } constexpr int j1 = fn2 (4, 1); -constexpr int j2 = fn2 (4, -1); // { dg-error "is negative" } -constexpr int j3 = fn2 (10, sizeof (int) * __CHAR_BIT__); // { dg-error "is >= than the precision of the left operand" } -constexpr int j4 = fn2 (1, 256); // { dg-error "is >= than the precision of the left operand" } +constexpr int j2 = fn2 (4, -1); // { dg-message "in constexpr expansion" } +constexpr int j3 = fn2 (10, sizeof (int) * __CHAR_BIT__); // { dg-message "in constexpr expansion" } +constexpr int j4 = fn2 (1, 256); // { dg-message "in constexpr expansion" } constexpr int j5 = fn2 (5, 2); constexpr int j6 = fn2 (-2, 4); constexpr int j7 = fn2 (0, 4); @@ -49,12 +55,12 @@ constexpr int fn3 (int a, int b) { if (b != 2) - a = a / b; + a = a / b; // { dg-error "..7 / 0.. is not a constant expression" } return a; } constexpr int k1 = fn3 (8, 4); -constexpr int k2 = fn3 (7, 0); // { dg-error "is not a constant expression" } +constexpr int k2 = fn3 (7, 0); // { dg-message "in constexpr expansion" } constexpr int k3 = fn3 (INT_MIN, -1); // { dg-error "overflow in constant expression" } SA (k1 == 2); @@ -63,12 +69,12 @@ constexpr float fn4 (float a, float b) { if (b != 2.0) - a = a / b; + a = a / b; // { dg-error "is not a constant expression" } return a; } constexpr float l1 = fn4 (5.0, 3.0); -constexpr float l2 = fn4 (7.0, 0.0); // { dg-error "is not a constant expression" } +constexpr float l2 = fn4 (7.0, 0.0); // { dg-message "in constexpr expansion" } constexpr int fn5 (const int *a, int b) diff --git a/gcc/testsuite/g++.dg/warn/Wconversion-real-integer2.C b/gcc/testsuite/g++.dg/warn/Wconversion-real-integer2.C index 0494588c15b..7e39d5fa747 100644 --- a/gcc/testsuite/g++.dg/warn/Wconversion-real-integer2.C +++ b/gcc/testsuite/g++.dg/warn/Wconversion-real-integer2.C @@ -23,11 +23,11 @@ // // That is more useful. -#define INT_MAX __INT_MAX__ +#define INT_MAX __INT_MAX__ // { dg-warning "17: conversion to .float. alters .int. constant value" } float vfloat; void h (void) { - vfloat = INT_MAX; // { dg-warning "conversion to .float. alters .int. constant value" } + vfloat = INT_MAX; // { dg-message "14: in expansion of macro .INT_MAX." } } diff --git a/gcc/testsuite/g++.dg/warn/pr35635.C b/gcc/testsuite/g++.dg/warn/pr35635.C index de68ceb484c..19345c51162 100644 --- a/gcc/testsuite/g++.dg/warn/pr35635.C +++ b/gcc/testsuite/g++.dg/warn/pr35635.C @@ -62,9 +62,9 @@ void func3() /* At least one branch of ? does not fit in the destination, thus warn. */ uchar_x = bar != 0 ? 2.1 : 10; /* { dg-warning "conversion" } */ - uchar_x = bar != 0 /* { dg-warning "negative integer implicitly converted to unsigned type" } */ - ? (unsigned char) 1024 - : -1; + uchar_x = bar != 0 + ? (unsigned char) 1024 /* { dg-warning "negative integer implicitly converted to unsigned type" } */ + : -1; } void func4() diff --git a/gcc/testsuite/obj-c++.dg/plugin/diagnostic-test-expressions-1.mm b/gcc/testsuite/obj-c++.dg/plugin/diagnostic-test-expressions-1.mm new file mode 100644 index 00000000000..609fe3d0f93 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/plugin/diagnostic-test-expressions-1.mm @@ -0,0 +1,94 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdiagnostics-show-caret" } */ + +/* This file is similar to diagnostic-test-expressions-1.c + (see the notes in that file); this file adds test + coverage for various Objective C constructs. */ + +extern void __emit_expression_range (int dummy, ...); + +@protocol prot +@end + +@interface tests +- (int) func0; +- (int) func1:(int)i; ++ (int) func2; +- (void) test_sending_messages; ++ (void) test_class_dot_name; +- (void) test_at_selector; +- (void) test_at_protocol; +- (void) test_at_encode:(int)i; +@end + +@implementation tests +- (int) func0 +{ + return 42; +} +- (int) func1:(int)i +{ + return i * i; +} ++ (int) func2 +{ + return 0; +} +- (void) test_sending_messages +{ + __emit_expression_range ( 0, [self func0] ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range ( 0, [self func0] ); + ^~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + __emit_expression_range ( 0, [self func1:5] ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range ( 0, [self func1:5] ); + ^~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +} ++ (void) test_class_dot_name +{ + __emit_expression_range ( 0, tests.func2 ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range ( 0, tests.func2 ); + ~~~~~~^~~~~ + { dg-end-multiline-output "" } */ +} +- (void) test_at_selector +{ + __emit_expression_range ( 0, @selector(func0) ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range ( 0, @selector(func0) ); + ^~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +} +- (void) test_at_protocol +{ + __emit_expression_range ( 0, @protocol(prot) ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range ( 0, @protocol(prot) ); + ^~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +} +- (void) test_at_encode:(int)i +{ + /* @encode() generates a STRING_CST which doesn't retain a location + after parsing, so we need to access it via compound expressions + that can't be folded away. */ + + /* Verify start. */ + __emit_expression_range ( 0, @encode(int) + i ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range ( 0, @encode(int) + i ); + ~~~~~~~~~~~~~^~~ + { dg-end-multiline-output "" } */ + + /* Verify finish. */ + __emit_expression_range ( 0, i + @encode(int) ); /* { dg-warning "range" } */ +/* { dg-begin-multiline-output "" } + __emit_expression_range ( 0, i + @encode(int) ); + ~~^~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +} +@end diff --git a/gcc/testsuite/obj-c++.dg/plugin/plugin.exp b/gcc/testsuite/obj-c++.dg/plugin/plugin.exp new file mode 100644 index 00000000000..d0d400bb602 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/plugin/plugin.exp @@ -0,0 +1,90 @@ +# Copyright (C) 2009-2015 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# Test the functionality of the GCC plugin support + +load_lib target-supports.exp +load_lib obj-c++-dg.exp + +global TESTING_IN_BUILD_TREE +global ENABLE_PLUGIN + +# The plugin testcases currently only work when the build tree is available. +# Also check whether the host supports plugins. +if { ![info exists TESTING_IN_BUILD_TREE] || ![info exists ENABLE_PLUGIN] } { + return +} + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS " -ansi -pedantic-errors" +} + +# The procedures in plugin-support.exp need these parameters. +set default_flags $DEFAULT_CFLAGS + +if $tracelevel then { + strace $tracelevel +} + +# Load support procs. +load_lib plugin-support.exp + +# These tests don't run runtest_file_p consistently if it +# doesn't return the same values, so disable parallelization +# of this *.exp file. The first parallel runtest to reach +# this will run all the tests serially. +if ![gcc_parallel_test_run_p plugin] { + return +} +gcc_parallel_test_enable 0 + +# Specify the plugin source file and the associated test files in a list. +# plugin_test_list={ {plugin1 test1 test2 ...} {plugin2 test1 ...} ... } +set plugin_test_list [list \ + { ../../gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c \ + diagnostic-test-expressions-1.mm } \ +] + +foreach plugin_test $plugin_test_list { + # Replace each source file with its full-path name + for {set i 0} {$i < [llength $plugin_test]} {incr i} { + set basename [lindex $plugin_test $i] + set plugin_test [lreplace $plugin_test $i $i $srcdir/$subdir/$basename] + } + set plugin_src [lindex $plugin_test 0] + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $plugin_src] then { + continue + } + set plugin_input_tests [lreplace $plugin_test 0 0] + plugin-test-execute $plugin_src $plugin_input_tests +} + +# run the plugindir tests + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/plugindir*.mm]] \ + "" $DEFAULT_CFLAGS + +# All done. +dg-finish + +gcc_parallel_test_enable 1 diff --git a/gcc/tree.c b/gcc/tree.c index bd5cf73b659..c8b3ab8531c 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -13905,7 +13905,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)) @@ -13935,20 +13935,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, @@ -13956,6 +13956,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 a60e9dd31cb..aef825d092f 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -5369,6 +5369,16 @@ type_with_alias_set_p (const_tree t) return false; } +extern location_t get_pure_location (location_t loc); + +/* Get the endpoint of any range encoded within location LOC. */ + +static inline location_t +get_finish (location_t loc) +{ + return get_range_from_loc (line_table, loc).m_finish; +} + extern location_t set_block (location_t loc, tree block); extern void gt_ggc_mx (tree &); @@ -5377,10 +5387,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 @@ -5390,6 +5400,9 @@ 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); + /* Return true if it makes sense to promote/demote from_type to to_type. */ inline bool desired_pro_or_demotion_p (const_tree to_type, const_tree from_type) -- 2.30.2