From patchwork Mon Jul 24 20:05:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 793018 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-458812-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="vdQD8UgD"; dkim-atps=neutral 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 3xGWtG67Zdz9ryk for ; Tue, 25 Jul 2017 05:40:06 +1000 (AEST) 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=Dkjg8YtRrIQWSEJ4WJ6s6m4b5z/6uWidZuPihJ1KhXLt405OdzTXE DuLJx7Y+YKvL3yOimIVM2mX2nCJWtzjocFpsjLoj80AWugyWDsGMCeIwpq2gmeHZ h5SRyLyV5SWnzQosXqOEDNJq2GKDoL0eHbtGg9ZYFyaGtXYJUls3qc= 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=Vo1l1SMKzlY3hu60Ex2HhxbpohU=; b=vdQD8UgDQGxyQr4NQX5m WY+XNjE9Tt/CTyeenXyWrxs+SGFtxg2HqQZVXzDKstS5os7VkGb7Rguidz3Pqp4x ZeN45Klo0OPGkoLdpEGnfM8URxm7KN7RCPzhuOO/RSQ1vHGl4Z7SfqdJoWubFgkh eqj6Z73IPjGdfl38Q9ZGnAI= Received: (qmail 36211 invoked by alias); 24 Jul 2017 19:39:06 -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 35842 invoked by uid 89); 24 Jul 2017 19:39:06 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy= 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 ESMTP; Mon, 24 Jul 2017 19:39:00 +0000 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 60D2467C4F for ; Mon, 24 Jul 2017 19:31:06 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 60D2467C4F Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=dmalcolm@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 60D2467C4F Received: from c64.redhat.com (ovpn-112-25.phx2.redhat.com [10.3.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7E57769720; Mon, 24 Jul 2017 19:31:03 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [PATCH 09/17] C++: highlight return types when complaining about mismatches Date: Mon, 24 Jul 2017 16:05:06 -0400 Message-Id: <1500926714-56988-10-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1500926714-56988-1-git-send-email-dmalcolm@redhat.com> References: <1500926714-56988-1-git-send-email-dmalcolm@redhat.com> X-IsSubscribed: yes This patch to the C++ frontend uses the BLT infrastructure to highlight the return type of a function when complaining about code within the function that doesn't match it. For example, given: error: return-statement with a value, in function returning 'void' [-fpermissive] return 42; ^~ the patch adds this note: note: the return type was declared as 'void' here void test_1 (void) ^~~~ gcc/cp/ChangeLog: * cp-tree.h (attempt_to_highlight_return_type): New decl. * decl.c (finish_function): Call attempt_to_highlight_return_type when complaining about missing return statements in non-void functions. * typeck.c: Include "blt.h". (get_location_of_return_type): New function. (attempt_to_highlight_return_type): New function. (check_return_expr): Call attempt_to_highlight_return_type when complaining about return statements that mismatch the "void-ness" of the function. gcc/testsuite/ChangeLog: * g++.dg/bad-return-type.C: New test case. --- gcc/cp/cp-tree.h | 2 + gcc/cp/decl.c | 5 +- gcc/cp/typeck.c | 70 ++++++++++++++++- gcc/testsuite/g++.dg/bad-return-type.C | 135 +++++++++++++++++++++++++++++++++ 4 files changed, 206 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/bad-return-type.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 16d8a48..ec83f78 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7146,6 +7146,8 @@ extern tree finish_left_unary_fold_expr (tree, int); extern tree finish_right_unary_fold_expr (tree, int); extern tree finish_binary_fold_expr (tree, tree, int); +extern void attempt_to_highlight_return_type (tree fndecl); + /* in typeck2.c */ extern void require_complete_eh_spec_types (tree, tree); extern void cxx_incomplete_type_diagnostic (location_t, const_tree, diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index bcf305c..84a275f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -15643,8 +15643,9 @@ finish_function (int flags) && !DECL_DESTRUCTOR_P (fndecl) && targetm.warn_func_return (fndecl)) { - warning (OPT_Wreturn_type, - "no return statement in function returning non-void"); + if (warning (OPT_Wreturn_type, + "no return statement in function returning non-void")) + attempt_to_highlight_return_type (current_function_decl); TREE_NO_WARNING (fndecl) = 1; } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 316d57f..054dca5 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "params.h" #include "gcc-rich-location.h" #include "asan.h" +#include "blt.h" static tree cp_build_addr_expr_strict (tree, tsubst_flags_t); static tree cp_build_function_call (tree, tree, tsubst_flags_t); @@ -8869,6 +8870,61 @@ maybe_warn_about_returning_address_of_local (tree retval) return false; } +/* Attempt to use BLT locate the return type within FNDECL, returning + UNKNOWN_LOCATION if there is a problem (or if BLT is disabled). */ + +static location_t +get_location_of_return_type (tree fndecl) +{ + blt_node *node = blt_get_node_for_tree (fndecl); + if (!node) + return UNKNOWN_LOCATION; + + /* We have a direct-declarator within a function-definition, + or a member-declaration. + Locate the function-definition or member-declaration. */ + blt_node *iter; + for (iter = node; iter; iter = iter->get_parent ()) + if (iter->get_kind () == BLT_FUNCTION_DEFINITION + || iter->get_kind () == BLT_MEMBER_DECLARATION) + break; + if (!iter) + return UNKNOWN_LOCATION; + + /* Locate the decl specifiers within the function-definition + or member-declaration. */ + blt_node *dss = iter->get_first_child_of_kind (BLT_DECL_SPECIFIER_SEQ); + if (!dss) + return UNKNOWN_LOCATION; + + /* Locate the type-specifier within the decl specifiers. It ought to + be "void". */ + blt_node *ts = dss->get_first_child_of_kind (BLT_TYPE_SPECIFIER); + if (!ts) + return UNKNOWN_LOCATION; + + return ts->get_range (); +} + +/* Attempt to locate the return type within FNDECL; if successful, + emit a note highlighting it. */ + +void +attempt_to_highlight_return_type (tree fndecl) +{ + location_t ret_type_loc + = get_location_of_return_type (fndecl); + if (ret_type_loc == UNKNOWN_LOCATION) + return; + + tree result = DECL_RESULT (fndecl); + tree return_type = TREE_TYPE (result); + + inform (ret_type_loc, + "the return type was declared as %qT here", return_type); +} + + /* Check that returning RETVAL from the current function is valid. Return an expression explicitly showing all conversions required to change RETVAL into the function return type, and to assign it to @@ -8994,8 +9050,11 @@ check_return_expr (tree retval, bool *no_warning) if (!retval && fn_returns_value_p) { if (functype != error_mark_node) - permerror (input_location, "return-statement with no value, in " - "function returning %qT", valtype); + { + if (permerror (input_location, "return-statement with no value, in " + "function returning %qT", valtype)) + attempt_to_highlight_return_type (current_function_decl); + } /* Remember that this function did return. */ current_function_returns_value = 1; /* And signal caller that TREE_NO_WARNING should be set on the @@ -9013,8 +9072,11 @@ check_return_expr (tree retval, bool *no_warning) its side-effects. */ finish_expr_stmt (retval); else - permerror (input_location, "return-statement with a value, in function " - "returning 'void'"); + { + if (permerror (input_location, "return-statement with a value," + " in function returning %")) + attempt_to_highlight_return_type (current_function_decl); + } current_function_returns_null = 1; /* There's really no value to return, after all. */ diff --git a/gcc/testsuite/g++.dg/bad-return-type.C b/gcc/testsuite/g++.dg/bad-return-type.C new file mode 100644 index 0000000..e62eb0a --- /dev/null +++ b/gcc/testsuite/g++.dg/bad-return-type.C @@ -0,0 +1,135 @@ +/* Verify that we can highlight the return type for various kinds + of bogus return. */ + +// { dg-options "-fdiagnostics-show-caret -fblt -Wreturn-type" } + +void test_1 (void) // { dg-line return_line } +{ + return 42; // { dg-error "return-statement with a value, in function returning 'void'" } + /* { dg-begin-multiline-output "" } + return 42; + ^~ + { dg-end-multiline-output "" } */ + // { dg-message "the return type was declared as 'void' here" "" { target *-*-* } return_line } + /* { dg-begin-multiline-output "" } + void test_1 (void) + ^~~~ + { dg-end-multiline-output "" } */ +} + +/* As before, but with different whitespace. */ + +void // { dg-line return_line_2 } +test_2 (void) +{ + return 42; // { dg-error "return-statement with a value, in function returning 'void'" } + /* { dg-begin-multiline-output "" } + return 42; + ^~ + { dg-end-multiline-output "" } */ + // { dg-message "the return type was declared as 'void' here" "" { target *-*-* } return_line_2 } + /* { dg-begin-multiline-output "" } + void + ^~~~ + { dg-end-multiline-output "" } */ +} + +/* As before, but with "extern". */ + +extern void test_3 (void) // { dg-line return_line_3 } +{ + return 42; // { dg-error "return-statement with a value, in function returning 'void'" } + /* { dg-begin-multiline-output "" } + return 42; + ^~ + { dg-end-multiline-output "" } */ + // { dg-message "the return type was declared as 'void' here" "" { target *-*-* } return_line_3 } + /* { dg-begin-multiline-output "" } + extern void test_3 (void) + ^~~~ + { dg-end-multiline-output "" } */ +} + +/* Type mismatch for non-void return. */ + +extern int test_4 (void) // { dg-line return_line_4 } +{ + return; // { dg-error "return-statement with no value, in function returning 'int'" } + /* { dg-begin-multiline-output "" } + return; + ^~~~~~ + { dg-end-multiline-output "" } */ + // { dg-message "the return type was declared as 'int' here" "" { target *-*-* } return_line_4 } + /* { dg-begin-multiline-output "" } + extern int test_4 (void) + ^~~ + { dg-end-multiline-output "" } */ +} + +/* Falling off the end of a non-void function. */ + +extern int test_5 (void) // { dg-line return_line_5 } +{ +} // { dg-warning "no return statement in function returning non-void" } +/* { dg-begin-multiline-output "" } + } + ^ + { dg-end-multiline-output "" } */ +// { dg-message "the return type was declared as 'int' here" "" { target *-*-* } return_line_5 } +/* { dg-begin-multiline-output "" } + extern int test_5 (void) + ^~~ + { dg-end-multiline-output "" } */ + +/* Member function. */ + +struct test_6 +{ + void member (void) // { dg-line return_line_6 } + { + return 42; // { dg-error "return-statement with a value, in function returning 'void'" } + /* { dg-begin-multiline-output "" } + return 42; + ^~ + { dg-end-multiline-output "" } */ + // { dg-message "the return type was declared as 'void' here" "" { target *-*-* } return_line_6 } + /* { dg-begin-multiline-output "" } + void member (void) + ^~~~ + { dg-end-multiline-output "" } */ + } +}; + +/* Function template. */ +// TODO: highlight "void" for these +template +void test_7 (T t) +{ + return 42; // { dg-error "return-statement with a value, in function returning 'void'" } +/* { dg-begin-multiline-output "" } + return 42; + ^~ + { dg-end-multiline-output "" } */ +} + +/* Class template. */ + +template +struct test_8 +{ + void member (T t) // { dg-line return_line_8 } + { + return 42; // { dg-error "return-statement with a value, in function returning 'void'" } + /* { dg-begin-multiline-output "" } + return 42; + ^~ + { dg-end-multiline-output "" } */ + // { dg-message "the return type was declared as 'void' here" "" { target *-*-* } return_line_8 } + /* { dg-begin-multiline-output "" } + void member (T t) + ^~~~ + { dg-end-multiline-output "" } */ + } +}; + +// TODO: complex return type e.g. const char *