From patchwork Thu Dec 3 14:55:39 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 552334 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id CFCC614029C for ; Fri, 4 Dec 2015 01:39:14 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=UbwZcjrP; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=a0KZeJUDFIjyxWDDtd/AHM8W3l+4kXJgqKE0+2ckgJUSkPd6T6Q9Y 4l2q4TmSJTvjawaK78m4C20o29uPwj7V3qkGeJzQxMyAQ6xlYhydcQUg/+Eh71W6 Rgto2HvMoZ144Jjr7wwS1Pj+4QL0YSsCtOdSQXJEkZgB/r789IRA4o= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=3FGc8evT+CiQtL0+KmckO5r9/aY=; b=UbwZcjrPmcZ1F/iQkaVr oZxONYczQX/RzfjuoWfQuRx8nYtPZlFuXmsMw0MyygvLX7C+aUiKACi+QBI/XYVB YJwPGfh1UpWG9ctZGcf6CHvtXNOdUNvS6skBy8JCQ5pA2657fiCaeITeRO78kKYC L9Jfma7OBuykVHm9mzRu8fw= Received: (qmail 29488 invoked by alias); 3 Dec 2015 14:37:43 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 29373 invoked by uid 89); 3 Dec 2015 14:37:42 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.1 required=5.0 tests=AWL, BAYES_50, KAM_ASCII_DIVIDERS, SPF_HELO_PASS, T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Thu, 03 Dec 2015 14:36:49 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (Postfix) with ESMTPS id C936E96C1 for ; Thu, 3 Dec 2015 14:36:47 +0000 (UTC) Received: from c64.redhat.com (vpn-235-143.phx2.redhat.com [10.3.235.143]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id tB3Eajde027193; Thu, 3 Dec 2015 09:36:46 -0500 From: David Malcolm To: Jason Merrill Cc: gcc-patches@gcc.gnu.org, David Malcolm Subject: [PATCH 01/10] C++ FE: expression ranges v4 Date: Thu, 3 Dec 2015 09:55:39 -0500 Message-Id: <1449154548-43964-2-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1449154548-43964-1-git-send-email-dmalcolm@redhat.com> References: <565627A0.6040107@redhat.com> <1449154548-43964-1-git-send-email-dmalcolm@redhat.com> X-IsSubscribed: yes Changes in this version: - removal of gcc_assert (m_loc != UNKNOWN_LOCATION) from cp_expr ctor - uses protected_set_expr_location or cp_expr::set_location/set_range, rather than attempting to add location_t arguments - adds location support and test coverage based on issues seen in the analogous work onthe C FE (see r230497 and r230775). Specifically: - various Objective C++ constructs (creating obj-c++.dg/plugin in order to unit-test these, analogous to changes for C FE) - braced initializers - statement expressions - address of label - transaction expressions - __FUNCTION__ et al - __builtin_va_arg and __builtin_offsetof - handle locations of functional casts and _Cilk_spawn - fixes locations of negative numeric literals - various other bugfixes and additional test coverage 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. * name-lookup.c (lookup_arg_dependent_1): Likewise. (lookup_arg_dependent): Likewise; also for local "ret". * name-lookup.h (lookup_arg_dependent): Likewise for return type. * parser.c (struct cp_parser_expression_stack_entry): Likewise for field "lhs". (cp_parser_identifier): Likewise for return type. Use cp_expr ctor to preserve the token's location. (cp_parser_string_literal): Likewise, building up a meaningful location for the case where a compound string literal is built by concatentation. (cp_parser_userdef_char_literal): Likewise for return type. (cp_parser_userdef_numeric_literal): Likewise. (cp_parser_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_initializer_clause): Likewise for local "initializer". (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_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/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. * 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. --- gcc/convert.c | 9 +- gcc/cp/cp-tree.h | 82 ++- gcc/cp/name-lookup.c | 6 +- gcc/cp/name-lookup.h | 2 +- gcc/cp/parser.c | 569 +++++++++++---- gcc/cp/semantics.c | 53 +- gcc/cp/typeck.c | 42 +- .../g++.dg/plugin/diagnostic-test-expressions-1.C | 775 +++++++++++++++++++++ gcc/testsuite/g++.dg/plugin/plugin.exp | 5 +- .../plugin/diagnostic-test-expressions-1.mm | 94 +++ gcc/testsuite/obj-c++.dg/plugin/plugin.exp | 90 +++ gcc/tree.c | 25 +- gcc/tree.h | 17 +- 13 files changed, 1570 insertions(+), 199 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/convert.c b/gcc/convert.c index e27a6fe..8fb8624 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/cp-tree.h b/gcc/cp/cp-tree.h index 38ae70f..6ddab8a 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/name-lookup.c b/gcc/cp/name-lookup.c index cebe57e..86c07ef 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -5659,7 +5659,7 @@ arg_assoc (struct arg_lookup *k, tree n) /* Performs Koenig lookup depending on arguments, where fns are the functions found in normal lookup. */ -static tree +static cp_expr lookup_arg_dependent_1 (tree name, tree fns, vec *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 d430edb..d2453e9 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -347,7 +347,7 @@ extern void do_toplevel_using_decl (tree, tree, tree); extern void do_local_using_decl (tree, tree, tree); extern tree do_class_using_decl (tree, tree); extern void do_using_directive (tree); -extern tree lookup_arg_dependent (tree, tree, vec *); +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 b4ecac7..d859a89 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1793,7 +1793,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 +1947,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 +1965,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 +1977,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 +2007,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 +2178,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 +2249,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 +2389,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 +2397,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 +2422,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 +2432,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 +2448,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 +3681,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 +3689,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 +3709,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 +3731,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 +3770,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 +3831,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 +3888,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 +3939,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 +4031,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 +4284,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 +4299,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 +4435,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 +4555,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 +4640,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 +4698,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 +4747,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 +4771,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 +4792,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 +4819,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 +4868,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 +4883,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 +4963,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 +5035,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 +5105,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 +5123,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 +5134,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 +5179,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 +5314,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 +5577,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 +6167,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 +6176,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 +6195,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 +6228,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 +6264,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 +6340,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 +6383,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 +6460,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 +6515,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 +6563,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 +6579,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 +6598,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 +6741,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 +6805,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 +7007,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 +7015,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 +7045,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 +7162,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 +7220,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 +7325,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 +7497,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 +7695,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 +7719,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 +7736,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 +7752,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 +7764,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 +7787,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 +7865,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 +7951,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 +8343,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 +8351,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 +8364,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 +8468,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 +8569,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 +8579,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 +8719,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 +8734,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 +8766,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 +8790,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 +8832,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 +8860,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 +8893,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 +8907,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 +9031,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 +9062,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 +9099,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 +9107,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 +9180,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 +9196,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 +9243,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 +9258,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 +9490,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 +13487,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 +13527,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 +13536,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 +13555,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 +13566,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 +13575,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 +13823,7 @@ cp_parser_operator (cp_parser* parser) id = error_mark_node; } - return id; + return cp_expr (id, start_loc); } /* Parse a template-declaration. @@ -20316,10 +20519,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 +20555,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 +20578,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 +24290,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 +24532,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 +25536,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 +25546,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 +25567,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 +25607,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 +27370,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 +27422,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 +27555,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 +27588,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 +27626,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 +27718,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. @@ -36286,16 +36565,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 3bb6184..82f7d3a 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 1d2943f..0a1e446 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/g++.dg/plugin/diagnostic-test-expressions-1.C b/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C new file mode 100644 index 0000000..826e835 --- /dev/null +++ b/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C @@ -0,0 +1,775 @@ +/* { 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_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 3ed1397..3be89a0 100644 --- a/gcc/testsuite/g++.dg/plugin/plugin.exp +++ b/gcc/testsuite/g++.dg/plugin/plugin.exp @@ -62,7 +62,10 @@ set plugin_test_list [list \ { dumb_plugin.c dumb-plugin-test-1.C } \ { header_plugin.c header-plugin-test.C } \ { decl_plugin.c decl-plugin-test.C } \ - { def_plugin.c def-plugin-test.C } ] + { def_plugin.c def-plugin-test.C } \ + { ../../gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c \ + diagnostic-test-expressions-1.C } \ +] foreach plugin_test $plugin_test_list { # Replace each source file with its full-path name diff --git a/gcc/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 0000000..609fe3d --- /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 0000000..d0d400b --- /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 bd5cf73..c8b3ab8 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 a60e9dd..aef825d 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)