From patchwork Thu Sep 10 20:28:27 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 516444 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 DD02814030C for ; Fri, 11 Sep 2015 06:32:16 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=iTDeZUFj; 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=iAGmy90U88j17xY4vAADZmtFbErU1aK2FkT4yECtb4ZneWDfqKb/k KTllQTTfVr+ERqmgkAWluGklwJzx2Cnz3iyUu4WDOBoza9IyVbqw9LiOZ7NeT7aP KJ9naeZ9BoMcNSh7bDRQaymdIoN6rQwhfat0XY6TGPBOomD4/UyZCk= 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=VEcTclHsoQ7dK5R622U30jtLX5I=; b=iTDeZUFj/bWvtn5NCR9o 8y4gdhoKDY3dOwJyLJF5DdK/2gjya9Va5xMPqnJExPBJYE/Sap24tusSWUm6VaaB SJUBPTrlqLLuGhjOTNV8qoLaDzZ4MGZZrkuZrcqwBIeuKg1DIGrO2vinSAmdFkSN vb1z96GT39M7l1sMMUo+TnU= Received: (qmail 89428 invoked by alias); 10 Sep 2015 20:32:08 -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 89416 invoked by uid 89); 10 Sep 2015 20:32:08 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.0 required=5.0 tests=AWL, BAYES_50, KAM_LAZY_DOMAIN_SECURITY autolearn=no version=3.3.2 X-HELO: eggs.gnu.org Received: from eggs.gnu.org (HELO eggs.gnu.org) (208.118.235.92) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Thu, 10 Sep 2015 20:31:49 +0000 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Za8D5-0003h8-Oa for gcc-patches@gcc.gnu.org; Thu, 10 Sep 2015 16:12:46 -0400 Received: from mx1.redhat.com ([209.132.183.28]:48666) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Za8D5-0003gr-DC for gcc-patches@gcc.gnu.org; Thu, 10 Sep 2015 16:12:43 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (Postfix) with ESMTPS id CD0EC46264 for ; Thu, 10 Sep 2015 20:12:42 +0000 (UTC) Received: from c64.redhat.com (vpn-239-137.phx2.redhat.com [10.3.239.137]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t8AKCWaY003473; Thu, 10 Sep 2015 16:12:42 -0400 From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [PATCH 16/22] C/C++ frontend: use tree ranges in various diagnostics Date: Thu, 10 Sep 2015 16:28:27 -0400 Message-Id: <1441916913-11547-17-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1441916913-11547-1-git-send-email-dmalcolm@redhat.com> References: <1441916913-11547-1-git-send-email-dmalcolm@redhat.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 X-IsSubscribed: yes Screenshot: https://dmalcolm.fedorapeople.org/gcc/2015-09-09/tree-ranges.html This mostly affects the C frontend, but it touches c-common.h so the C++ frontend needs a slight adjustment. gcc/c-family/ChangeLog: * c-common.c: Include gcc-rich-location.h. (binary_op_error): Add params orig_op0 and orig_op1; use them to add ranges and captions to the error. * c-common.h (binary_op_error): Add params orig_op0 and orig_op1. gcc/c/ChangeLog: * c-parser.c (c_parser_static_assert_declaration_no_semi): Convert locals "assert_loc" and "value_loc" from location_t to source_range, thus using ranges in diagnostics. * c-typeck.c (inform_declaration): Use DECL_LOCATION_RANGE of the decl, rather than DECL_SOURCE_LOCATION. (build_function_call_vec): Use the EXPR_LOCATION_RANGE of the function when issuing diagnostics, rather than "loc". (convert_for_assignment): Emit range-based diagnostics, rather than locations when CAN_HAVE_RANGE_P (rhs). (c_finish_return): Likewise when CAN_HAVE_RANGE_P (retval). When issuing warnings about erroneous presence/absence of return values, show the location of current_function_decl using inform. (build_binary_op): Pass orig_op0 and orig_op1 to binary_op_error. gcc/cp/ChangeLog: * typeck.c (cp_build_binary_op): Pass orig_op0 and orig_op1 to binary_op_error. gcc/testsuite/ChangeLog: * gcc.dg/diagnostic-tree-expr-ranges.c: New file. --- gcc/c-family/c-common.c | 9 +- gcc/c-family/c-common.h | 3 +- gcc/c/c-parser.c | 6 +- gcc/c/c-typeck.c | 123 ++++++++++------ gcc/cp/typeck.c | 3 +- gcc/testsuite/gcc.dg/diagnostic-tree-expr-ranges.c | 159 +++++++++++++++++++++ 6 files changed, 250 insertions(+), 53 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/diagnostic-tree-expr-ranges.c diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index ff6f90f..77962fc 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see #include "gimplify.h" #include "wide-int-print.h" #include "gimple-expr.h" +#include "gcc-rich-location.h" cpp_reader *parse_in; /* Declared in c-pragma.h. */ @@ -4340,6 +4341,7 @@ c_register_builtin_type (tree type, const char* name) void binary_op_error (location_t location, enum tree_code code, + tree orig_op0, tree orig_op1, tree type0, tree type1) { const char *opname; @@ -4391,7 +4393,12 @@ binary_op_error (location_t location, enum tree_code code, default: gcc_unreachable (); } - error_at (location, + gcc_rich_location richloc (location); + richloc.maybe_add_expr_with_caption (orig_op0, global_dc, + "%qT", TREE_TYPE (orig_op0)); + richloc.maybe_add_expr_with_caption (orig_op1, global_dc, + "%qT", TREE_TYPE (orig_op1)); + error_at_rich_loc (&richloc, "invalid operands to binary %s (have %qT and %qT)", opname, type0, type1); } diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index bb17fcc..b9a5d72 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -804,7 +804,8 @@ extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int); extern tree c_alignof_expr (location_t, tree); /* Print an error message for invalid operands to arith operation CODE. NOP_EXPR is used as a special case (see truthvalue_conversion). */ -extern void binary_op_error (location_t, enum tree_code, tree, tree); +extern void binary_op_error (location_t, enum tree_code, tree, tree, + tree, tree); extern tree fix_string_type (tree); extern void constant_expression_warning (tree); extern void constant_expression_error (tree); diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 4303496..0c62496 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -2037,12 +2037,12 @@ c_parser_static_assert_declaration (c_parser *parser) static void c_parser_static_assert_declaration_no_semi (c_parser *parser) { - location_t assert_loc, value_loc; + source_range assert_loc, value_loc; tree value; tree string; gcc_assert (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)); - assert_loc = c_parser_peek_token (parser)->location; + assert_loc = c_parser_peek_token (parser)->range; if (flag_isoc99) pedwarn_c99 (assert_loc, OPT_Wpedantic, "ISO C99 does not support %<_Static_assert%>"); @@ -2052,8 +2052,8 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) c_parser_consume_token (parser); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) return; - value_loc = c_parser_peek_token (parser)->location; value = c_parser_expr_no_commas (parser, NULL).value; + value_loc = EXPR_LOCATION_RANGE (value); parser->lex_untranslated_string = true; if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) { diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 4123f11..506abb3 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -2851,7 +2851,7 @@ static void inform_declaration (tree decl) { if (decl && (TREE_CODE (decl) != FUNCTION_DECL || !DECL_IS_BUILTIN (decl))) - inform (DECL_SOURCE_LOCATION (decl), "declared here"); + inform (DECL_LOCATION_RANGE (decl), "declared here"); } /* Build a function call to function FUNCTION with parameters PARAMS. @@ -2873,6 +2873,7 @@ build_function_call_vec (location_t loc, vec arg_loc, int nargs; tree *argarray; + source_range func_range = EXPR_LOCATION_RANGE (function); /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ STRIP_TYPE_NOPS (function); @@ -2921,13 +2922,13 @@ build_function_call_vec (location_t loc, vec arg_loc, function); else if (DECL_P (function)) { - error_at (loc, + error_at (func_range, "called object %qD is not a function or function pointer", function); inform_declaration (function); } else - error_at (loc, + error_at (func_range, "called object is not a function or function pointer"); return error_mark_node; } @@ -2958,11 +2959,12 @@ build_function_call_vec (location_t loc, vec arg_loc, /* This situation leads to run-time undefined behavior. We can't, therefore, simply error unless we can prove that all possible executions of the program must execute the code. */ - warning_at (loc, 0, "function called through a non-compatible type"); + warning_at (func_range, 0, + "function called through a non-compatible type"); if (VOID_TYPE_P (return_type) && TYPE_QUALS (return_type) != TYPE_UNQUALIFIED) - pedwarn (loc, 0, + pedwarn (func_range, 0, "function with qualified void return type called"); } @@ -2999,7 +3001,7 @@ build_function_call_vec (location_t loc, vec arg_loc, if (VOID_TYPE_P (TREE_TYPE (result))) { if (TYPE_QUALS (TREE_TYPE (result)) != TYPE_UNQUALIFIED) - pedwarn (loc, 0, + pedwarn (func_range, 0, "function with qualified void return type called"); return result; } @@ -5734,6 +5736,13 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, tree rname = NULL_TREE; bool objc_ok = false; + source_range rhs_range; + + if (CAN_HAVE_RANGE_P (rhs)) + rhs_range = EXPR_LOCATION_RANGE (rhs); + else + rhs_range = source_range::from_location (expr_loc); + if (errtype == ic_argpass) { tree selector; @@ -5756,14 +5765,14 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, /* This macro is used to emit diagnostics to ensure that all format strings are complete sentences, visible to gettext and checked at compile time. */ -#define PEDWARN_FOR_ASSIGNMENT(LOCATION, PLOC, OPT, AR, AS, IN, RE) \ +#define PEDWARN_FOR_ASSIGNMENT(LOCATION, RANGE, OPT, AR, AS, IN, RE) \ do { \ switch (errtype) \ { \ case ic_argpass: \ - if (pedwarn (PLOC, OPT, AR, parmnum, rname)) \ - inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \ - ? DECL_SOURCE_LOCATION (fundecl) : PLOC, \ + if (pedwarn (RANGE, OPT, AR, parmnum, rname)) \ + inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \ + ? DECL_SOURCE_LOCATION (fundecl) : RANGE.m_start, \ "expected %qT but argument is of type %qT", \ type, rhstype); \ break; \ @@ -5785,14 +5794,14 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, strings are complete sentences, visible to gettext and checked at compile time. It is the same as PEDWARN_FOR_ASSIGNMENT but with an extra parameter to enumerate qualifiers. */ -#define PEDWARN_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \ +#define PEDWARN_FOR_QUALIFIERS(LOCATION, RANGE, OPT, AR, AS, IN, RE, QUALS) \ do { \ switch (errtype) \ { \ case ic_argpass: \ - if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS)) \ - inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \ - ? DECL_SOURCE_LOCATION (fundecl) : PLOC, \ + if (pedwarn (RANGE, OPT, AR, parmnum, rname, QUALS)) \ + inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \ + ? DECL_SOURCE_LOCATION (fundecl) : RANGE.m_start, \ "expected %qT but argument is of type %qT", \ type, rhstype); \ break; \ @@ -5814,14 +5823,14 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, strings are complete sentences, visible to gettext and checked at compile time. It is the same as PEDWARN_FOR_QUALIFIERS but uses warning_at instead of pedwarn. */ -#define WARNING_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \ +#define WARNING_FOR_QUALIFIERS(LOCATION, RANGE, OPT, AR, AS, IN, RE, QUALS) \ do { \ switch (errtype) \ { \ case ic_argpass: \ - if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS)) \ + if (warning_at (RANGE, OPT, AR, parmnum, rname, QUALS)) \ inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \ - ? DECL_SOURCE_LOCATION (fundecl) : PLOC, \ + ? DECL_SOURCE_LOCATION (fundecl) : RANGE.m_start, \ "expected %qT but argument is of type %qT", \ type, rhstype); \ break; \ @@ -5881,7 +5890,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, && TREE_CODE (type) == ENUMERAL_TYPE && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type)) { - PEDWARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wc___compat, + PEDWARN_FOR_ASSIGNMENT (location, rhs_range, OPT_Wc___compat, G_("enum conversion when passing argument " "%d of %qE is invalid in C++"), G_("enum conversion in assignment is " @@ -6050,7 +6059,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, vice-versa. */ if (TYPE_QUALS_NO_ADDR_SPACE (ttl) & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) - PEDWARN_FOR_QUALIFIERS (location, expr_loc, + PEDWARN_FOR_QUALIFIERS (location, rhs_range, OPT_Wdiscarded_qualifiers, G_("passing argument %d of %qE " "makes %q#v qualified function " @@ -6067,7 +6076,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, } else if (TYPE_QUALS_NO_ADDR_SPACE (ttr) & ~TYPE_QUALS_NO_ADDR_SPACE (ttl)) - PEDWARN_FOR_QUALIFIERS (location, expr_loc, + PEDWARN_FOR_QUALIFIERS (location, rhs_range, OPT_Wdiscarded_qualifiers, G_("passing argument %d of %qE discards " "%qv qualifier from pointer target type"), @@ -6158,7 +6167,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, switch (errtype) { case ic_argpass: - error_at (expr_loc, "passing argument %d of %qE from pointer to " + error_at (rhs_range, "passing argument %d of %qE from pointer to " "non-enclosed address space", parmnum, rname); break; case ic_assign: @@ -6187,7 +6196,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, switch (errtype) { case ic_argpass: - warning_at (expr_loc, OPT_Wsuggest_attribute_format, + warning_at (rhs_range, OPT_Wsuggest_attribute_format, "argument %d of %qE might be " "a candidate for a format attribute", parmnum, rname); @@ -6234,7 +6243,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr) & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl)) - WARNING_FOR_QUALIFIERS (location, expr_loc, + WARNING_FOR_QUALIFIERS (location, rhs_range, OPT_Wdiscarded_array_qualifiers, G_("passing argument %d of %qE discards " "%qv qualifier from pointer target type"), @@ -6252,7 +6261,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, (VOID_TYPE_P (ttr) && !null_pointer_constant && TREE_CODE (ttl) == FUNCTION_TYPE))) - PEDWARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wpedantic, + PEDWARN_FOR_ASSIGNMENT (location, rhs_range, OPT_Wpedantic, G_("ISO C forbids passing argument %d of " "%qE between function pointer " "and %"), @@ -6277,7 +6286,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr) & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl)) { - PEDWARN_FOR_QUALIFIERS (location, expr_loc, + PEDWARN_FOR_QUALIFIERS (location, rhs_range, OPT_Wdiscarded_qualifiers, G_("passing argument %d of %qE discards " "%qv qualifier from pointer target type"), @@ -6296,7 +6305,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, ; /* If there is a mismatch, do warn. */ else if (warn_pointer_sign) - PEDWARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wpointer_sign, + PEDWARN_FOR_ASSIGNMENT (location, rhs_range, OPT_Wpointer_sign, G_("pointer targets in passing argument " "%d of %qE differ in signedness"), G_("pointer targets in assignment " @@ -6315,7 +6324,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, where an ordinary one is wanted, but not vice-versa. */ if (TYPE_QUALS_NO_ADDR_SPACE (ttl) & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) - PEDWARN_FOR_QUALIFIERS (location, expr_loc, + PEDWARN_FOR_QUALIFIERS (location, rhs_range, OPT_Wdiscarded_qualifiers, G_("passing argument %d of %qE makes " "%q#v qualified function pointer " @@ -6332,7 +6341,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, else /* Avoid warning about the volatile ObjC EH puts on decls. */ if (!objc_ok) - PEDWARN_FOR_ASSIGNMENT (location, expr_loc, + PEDWARN_FOR_ASSIGNMENT (location, rhs_range, OPT_Wincompatible_pointer_types, G_("passing argument %d of %qE from " "incompatible pointer type"), @@ -6356,7 +6365,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, or one that results from arithmetic, even including a cast to integer type. */ if (!null_pointer_constant) - PEDWARN_FOR_ASSIGNMENT (location, expr_loc, + PEDWARN_FOR_ASSIGNMENT (location, rhs_range, OPT_Wint_conversion, G_("passing argument %d of %qE makes " "pointer from integer without a cast"), @@ -6371,7 +6380,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, } else if (codel == INTEGER_TYPE && coder == POINTER_TYPE) { - PEDWARN_FOR_ASSIGNMENT (location, expr_loc, + PEDWARN_FOR_ASSIGNMENT (location, rhs_range, OPT_Wint_conversion, G_("passing argument %d of %qE makes integer " "from pointer without a cast"), @@ -6396,7 +6405,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, switch (errtype) { case ic_argpass: - error_at (expr_loc, "incompatible type for argument %d of %qE", parmnum, + error_at (rhs_range, "incompatible type for argument %d of %qE", parmnum, rname); inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) ? DECL_SOURCE_LOCATION (fundecl) : expr_loc, @@ -9396,8 +9405,14 @@ c_finish_return (location_t loc, tree retval, tree origtype) bool npc = false; size_t rank = 0; + source_range expr_range; + if (retval && CAN_HAVE_RANGE_P (retval)) + expr_range = EXPR_LOCATION_RANGE (retval); + else + expr_range = source_range::from_location (loc); + if (TREE_THIS_VOLATILE (current_function_decl)) - warning_at (loc, 0, + warning_at (expr_range, 0, "function declared % has a % statement"); if (flag_cilkplus && contains_array_notation_expr (retval)) @@ -9408,14 +9423,15 @@ c_finish_return (location_t loc, tree retval, tree origtype) return error_mark_node; if (rank >= 1) { - error_at (loc, "array notation expression cannot be used as a " + error_at (expr_range, "array notation expression cannot be used as a " "return value"); return error_mark_node; } } if (flag_cilkplus && retval && contains_cilk_spawn_stmt (retval)) { - error_at (loc, "use of %<_Cilk_spawn%> in a return statement is not " + error_at (expr_range, + "use of %<_Cilk_spawn%> in a return statement is not " "allowed"); return error_mark_node; } @@ -9439,24 +9455,36 @@ c_finish_return (location_t loc, tree retval, tree origtype) if ((warn_return_type || flag_isoc99) && valtype != 0 && TREE_CODE (valtype) != VOID_TYPE) { + bool warned_here; if (flag_isoc99) - pedwarn (loc, 0, "% with no value, in " - "function returning non-void"); + warned_here = pedwarn + (loc, 0, + "% with no value, in function returning non-void"); else - warning_at (loc, OPT_Wreturn_type, "% with no value, " - "in function returning non-void"); - no_warning = true; + warned_here = + warning_at (loc, OPT_Wreturn_type, + "% with no value, " + "in function returning non-void"); + if (warned_here) + inform (DECL_SOURCE_LOCATION (current_function_decl), + "declared here"); } } else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE) { current_function_returns_null = 1; + bool warned_here; if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE) - pedwarn (loc, 0, - "% with a value, in function returning void"); + warned_here = pedwarn + (expr_range, 0, + "% with a value, in function returning void"); else - pedwarn (loc, OPT_Wpedantic, "ISO C forbids " - "% with expression, in function returning void"); + warned_here = pedwarn + (expr_range, OPT_Wpedantic, "ISO C forbids " + "% with expression, in function returning void"); + if (warned_here) + inform (DECL_SOURCE_LOCATION (current_function_decl), + "declared here"); } else { @@ -9532,11 +9560,11 @@ c_finish_return (location_t loc, tree retval, tree origtype) && DECL_CONTEXT (inner) == current_function_decl) { if (TREE_CODE (inner) == LABEL_DECL) - warning_at (loc, OPT_Wreturn_local_addr, + warning_at (expr_range, OPT_Wreturn_local_addr, "function returns address of label"); else { - warning_at (loc, OPT_Wreturn_local_addr, + warning_at (expr_range, OPT_Wreturn_local_addr, "function returns address of local variable"); tree zero = build_zero_cst (TREE_TYPE (res)); t = build2 (COMPOUND_EXPR, TREE_TYPE (res), t, zero); @@ -11055,7 +11083,7 @@ build_binary_op (location_t location, enum tree_code code, && (!tree_int_cst_equal (TYPE_SIZE (type0), TYPE_SIZE (type1)) || !vector_types_compatible_elements_p (type0, type1))) { - binary_op_error (location, code, type0, type1); + binary_op_error (location, code, orig_op0, orig_op1, type0, type1); return error_mark_node; } @@ -11294,7 +11322,8 @@ build_binary_op (location_t location, enum tree_code code, if (!result_type) { - binary_op_error (location, code, TREE_TYPE (op0), TREE_TYPE (op1)); + binary_op_error (location, code, orig_op0, orig_op1, + TREE_TYPE (op0), TREE_TYPE (op1)); return error_mark_node; } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 388558c..b5a131c 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -4841,7 +4841,8 @@ cp_build_binary_op (location_t location, || !vector_types_compatible_elements_p (type0, type1)) { if (complain & tf_error) - binary_op_error (location, code, type0, type1); + binary_op_error (location, code, orig_op0, orig_op1, + type0, type1); return error_mark_node; } arithmetic_types_p = 1; diff --git a/gcc/testsuite/gcc.dg/diagnostic-tree-expr-ranges.c b/gcc/testsuite/gcc.dg/diagnostic-tree-expr-ranges.c new file mode 100644 index 0000000..10ab7db --- /dev/null +++ b/gcc/testsuite/gcc.dg/diagnostic-tree-expr-ranges.c @@ -0,0 +1,159 @@ +/* { dg-options "-fdiagnostics-show-caret -Wreturn-local-addr" } */ + +/* Verify that various diagnostics show source code ranges. */ + +/* These ones make use of tree ranges. */ + +void test_nonconst_static_assert (int i) +{ + _Static_assert (i > 0, "message"); /* { dg-error "expression in static assertion is not constant" } */ +/* +{ dg-begin-multiline-output "" } + _Static_assert (i > 0, "message"); + ^~~~~ +{ dg-end-multiline-output "" } +*/ +} + +extern void test_callee (int first, const char *second, int third); + +void test_bad_argument_types (int first, int second, int third) +{ + test_callee (first, first + second + third, third); /* { dg-warning "passing argument 2 of 'test_callee' makes pointer from integer without a cast" } */ + +/* +{ dg-begin-multiline-output "" } + test_callee (first, first + second + third, third); + ^~~~~~~~~~~~~~~~~~~~~~ +{ dg-end-multiline-output "" } +{ dg-begin-multiline-output "" } + extern void test_callee (int first, const char *second, int third); + ^ +{ dg-end-multiline-output "" } +FIXME: we ought to highlight the specific param in the decl +*/ + + test_callee (first, &first, third); /* { dg-warning "passing argument 2 of 'test_callee' from incompatible pointer type" } */ + +/* +{ dg-begin-multiline-output "" } + test_callee (first, &first, third); + ^~~~~~ +{ dg-end-multiline-output "" } +{ dg-begin-multiline-output "" } + extern void test_callee (int first, const char *second, int third); + ^ +{ dg-end-multiline-output "" } +FIXME: again, we ought to highlight the specific param in the decl +*/ + + test_callee ("hello world", "", third); /* { dg-warning "passing argument 1 of 'test_callee' makes integer from pointer without a cast" } */ + +/* +{ dg-begin-multiline-output "" } + test_callee ("hello world", "", third); + ^~~~~~~~~~~~~ +{ dg-end-multiline-output "" } +{ dg-begin-multiline-output "" } + extern void test_callee (int first, const char *second, int third); + ^ +{ dg-end-multiline-output "" } +FIXME: and again, we ought to highlight the specific param in the decl +*/ + +} + +/* Adapted from https://gcc.gnu.org/wiki/ClangDiagnosticsComparison */ + +void call_of_non_function_ptr (char **argP, char **argQ) +{ + (argP - argQ)(); /* { dg-error "called object is not a function or function pointer" } */ + +/* { dg-begin-multiline-output "" } + (argP - argQ)(); + ^~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + + argP(); /* { dg-error "called object 'argP' is not a function or function pointer" } */ + +/* { dg-begin-multiline-output "" } + argP(); + ^~~~ + { dg-end-multiline-output "" } + { dg-begin-multiline-output "" } + void call_of_non_function_ptr (char **argP, char **argQ) + ^ + { dg-end-multiline-output "" } */ + /* TODO: underline all of "argP" in the decl above. */ +} + +/* Adapted from https://gcc.gnu.org/wiki/ClangDiagnosticsComparison */ + +typedef float __m128; +void bad_binary_op () +{ + __m128 myvec[2]; + int const *ptr; + myvec[1]/ptr; /* { dg-error "invalid operands to binary /" } */ + +/* +{ dg-begin-multiline-output "" } + myvec[1]/ptr; + ~~~~~~~~^~~~ +{ dg-end-multiline-output "" } */ + +} + +struct s {}; +struct t {}; +extern struct s some_function (void); +extern struct t some_other_function (void); + +int another_bad_binary_op (void) +{ + return (some_function () + + some_other_function ()); /* { dg-error "invalid operands to binary +" } */ + +/* { dg-begin-multiline-output "" } + return (some_function ()| + ~~~~~~~~~~~~~~~~+'struct s' + + some_other_function ()); | + ^ ~~~~~~~~~~~~~~~~~~~~~~ +'struct t' + { dg-end-multiline-output "" } */ +} + +void surplus_return_when_void (void) +{ + return 500; /* { dg-warning "'return' with a value, in function returning void" } */ +/* { dg-begin-multiline-output "" } + return 500; + ^~~ + { dg-end-multiline-output "" } */ +/* { dg-begin-multiline-output "" } + void surplus_return_when_void (void) + ^ + { dg-end-multiline-output "" } */ +} + +int missing_return_value (void) +{ + return; /* { dg-warning "'return' with no value, in function returning non-void" } */ +/* { dg-begin-multiline-output "" } + return; + ^ + { dg-end-multiline-output "" } */ +/* { dg-begin-multiline-output "" } + int missing_return_value (void) + ^ + { dg-end-multiline-output "" } */ +} + +int *address_of_local (void) +{ + int i; + return &i; /* { dg-warning "function returns address of local variable" } */ +/* { dg-begin-multiline-output "" } + return &i; + ^~ + { dg-end-multiline-output "" } */ +}