From patchwork Sat Oct 28 08:11:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 159238 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:d641:0:b0:403:3b70:6f57 with SMTP id cy1csp1099651vqb; Sat, 28 Oct 2023 01:11:54 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHP4M306FEBKuWsegbsHcb+76wOQXC67Qw50ZGlZG3Lk3YVqjJgMEpkXQgT+LDQGs3kEfwv X-Received: by 2002:ad4:5cc4:0:b0:671:3493:61db with SMTP id iu4-20020ad45cc4000000b00671349361dbmr199683qvb.51.1698480714700; Sat, 28 Oct 2023 01:11:54 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1698480714; cv=pass; d=google.com; s=arc-20160816; b=wH6eeu95pBtc9v/y60Uw9PcnEe2epaKftKbvxXMSdjz/rUkcwwNI9sgz79VDxwlaiO SwOIU91xok8oWXSmbIhZPhkJI2vypfkDxDpuUPzW86PDOGA3b9kP7Q035vudfPE2hdWj yUT8JxsogSlTMwjNQ6HmGExHIcikynXA7g3yX6kmpb6W0iYg9cNpe2GpflVj+HLwRBRq rw+F04mNTZZ/HElCzXAnRlwEr7P9triuPbVYdJybVyYRK9Bf5qJFFFCk6h1HqlcIbgJO F1Hh6x/AnLsfySDMwWC3xJT5YllJNy/E9YV97g9SUFojJogUsmhidWNfzUCq3J6KYL44 vWoQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:message-id:date:subject:cc:to:from:dkim-signature :arc-filter:dmarc-filter:delivered-to; bh=7Au0O8opKwTXbNxHvVG9nw2jf/7ZVOOIM0RwHV9UEqE=; fh=D2tRalIjW6KCgVuqwFHStdMb9uqe8HSQc2WEvRJ6uLE=; b=kxlw8cEWTxy+ZCT0xxfqZKY/znAYbHN2/JFE6HnPMjT4FRX/8wyFPXWLSeV6LtFdMT /4LMaNe4FKsvt1QOw2MH3NRAaxYpajVCKmn2fJmz9XKfg7hHUS+NWXL5/d4FlFq2dYLP brtfEgh+9HbGapNtAEOu1rxyxFPDvwHRzThHLyEkE8HE28ykmL7vj6kV72nUFXygKz9X DjP+dQIahjBzRsVbabV3tdjthE1SaxXiQ2YuCfMPODi2UWmO3I03gFumcIPnar5Koup1 pguLEyNys3bTRZf1LiMmjqdy8CVnmC/FWK7pSKBTyvrIH0mHCvDMGZoABwI0B2QHkFmk dG3A== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@gdcproject.org header.s=MBO0001 header.b=0w2kAeAM; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=gdcproject.org Received: from server2.sourceware.org (server2.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id ev19-20020a0562140a9300b0066d08ac0ba0si1963493qvb.230.2023.10.28.01.11.54 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 28 Oct 2023 01:11:54 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gdcproject.org header.s=MBO0001 header.b=0w2kAeAM; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=gdcproject.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7A4B5385351A for ; Sat, 28 Oct 2023 08:11:54 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mout-p-102.mailbox.org (mout-p-102.mailbox.org [80.241.56.152]) by sourceware.org (Postfix) with ESMTPS id F10FD3858428 for ; Sat, 28 Oct 2023 08:11:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F10FD3858428 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=gdcproject.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gdcproject.org ARC-Filter: OpenARC Filter v1.0.0 sourceware.org F10FD3858428 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=80.241.56.152 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1698480689; cv=none; b=srDrAG/1CHxza4gwcd1Voh54Wqfjb0tVDrLvYkW+HtqyyjHwKPJoHTGKDV5IcB4/TIaiBFqLvjU51iQAlWDcLrZuyKNpTX3J1h/g7S7eW1gZVqlvCNqS11oDbzd7y+hkdA6iaK0Aa6Md+NY+8jkP1QFeycvRD+sT6SGeFllhLa4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1698480689; c=relaxed/simple; bh=g5SfV6xH+3RC2xoIGTswt7DiaiH+NNTLtPPK406WFNY=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=aJWu2dw5MlMaAduESnAHEQl7sFsCt6xWkAPgHZDHGM8TNozeDBdt+OFYjVmwGh2UN1S2dLPMVDqayH1t4ZYyTSuq7omct84NxX6PuxrAQDLlaLIPUJiJDE8rFQ2WXcX79f7gwqNw2ALwYuUT2jydBr/ib2TXHLjU/VfGmP3vaOI= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from smtp102.mailbox.org (smtp102.mailbox.org [IPv6:2001:67c:2050:b231:465::102]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-102.mailbox.org (Postfix) with ESMTPS id 4SHXL34cGcz9sxp; Sat, 28 Oct 2023 10:11:23 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gdcproject.org; s=MBO0001; t=1698480683; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=7Au0O8opKwTXbNxHvVG9nw2jf/7ZVOOIM0RwHV9UEqE=; b=0w2kAeAMWwBf3I6BVAWyGnMgs1TRU6EfxE2u+teitJwgpauJHCkeBO9+C86K/EngogO7L2 h+moQYFDgMuzm7wYxwUcb2GdDaKOUQUYdK+iPKG6jlDMiuJbQaUgyas8AnkLNHgJiOehfl 6/3GM9BmniloSTne9abXYNUlYYmzfl5E5tzk63Iq2MCjqbBXq/frwtUCw6nqlpXr/XDm99 RnnxmhwUShGRFXrgJaNkNhnWoQqfKXcHFvfZ2aKDPtLnYQtUw6daophkaef81cttO2Tmo3 4iTZtcm3SkKOye382Hz556dgftWxQwHr40ZPg8gQBFgx89qNQS5SnwUa//QpiQ== From: Iain Buclaw To: gcc-patches@gcc.gnu.org Cc: Iain Buclaw Subject: [committed] d: Add warning for call expression without side effects Date: Sat, 28 Oct 2023 10:11:21 +0200 Message-Id: <20231028081121.145230-1-ibuclaw@gdcproject.org> MIME-Version: 1.0 X-Rspamd-Queue-Id: 4SHXL34cGcz9sxp X-Spam-Status: No, score=-13.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1780986113884379969 X-GMAIL-MSGID: 1780986113884379969 Hi, In the last merge of the dmd front-end with upstream (r14-4830), this warning got removed from the semantic passes. Reimplement the warning for the code generation pass instead, where it cannot have an effect on conditional compilation. Bootstrapped and regression tested on x86_64-linux-gnu/-m32, committed to mainline. Regards, Iain. --- gcc/d/ChangeLog: * d-codegen.cc (call_side_effect_free_p): New function. * d-tree.h (CALL_EXPR_WARN_IF_UNUSED): New macro. (call_side_effect_free_p): New prototype. * expr.cc (ExprVisitor::visit (CallExp *)): Set CALL_EXPR_WARN_IF_UNUSED on matched call expressions. (ExprVisitor::visit (NewExp *)): Don't dereference the result of an allocation call here. * toir.cc (add_stmt): Emit warning when call expression added to statement list without being used. gcc/testsuite/ChangeLog: * gdc.dg/Wunused_value.d: New test. --- gcc/d/d-codegen.cc | 54 ++++++++++++++++++++++++++++ gcc/d/d-tree.h | 7 ++++ gcc/d/expr.cc | 13 ++++++- gcc/d/toir.cc | 32 +++++++++++++++++ gcc/testsuite/gdc.dg/Wunused_value.d | 29 +++++++++++++++ 5 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gdc.dg/Wunused_value.d diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 155f5d0d618..8c2e6c70ed4 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -2102,6 +2102,60 @@ get_function_type (Type *t) return tf; } +/* Returns TRUE if calling the function FUNC, or the function or delegate type + TYPE is free of side effects. */ + +bool +call_side_effect_free_p (FuncDeclaration *func, Type *type) +{ + gcc_assert (func != NULL || type != NULL); + + if (func != NULL) + { + /* Constructor and invariant calls can't be `pure'. */ + if (func->isCtorDeclaration () || func->isInvariantDeclaration ()) + return false; + + /* Must be a `nothrow' function. */ + TypeFunction *tf = func->type->toTypeFunction (); + if (!tf->isnothrow ()) + return false; + + /* Return type can't be `void' or `noreturn', as that implies all work is + done via side effects. */ + if (tf->next->ty == TY::Tvoid || tf->next->ty == TY::Tnoreturn) + return false; + + /* Only consider it as `pure' if it can't modify its arguments. */ + if (func->isPure () == PURE::const_) + return true; + } + + if (type != NULL) + { + TypeFunction *tf = get_function_type (type); + + /* Must be a `nothrow` function type. */ + if (tf == NULL || !tf->isnothrow ()) + return false; + + /* Return type can't be `void' or `noreturn', as that implies all work is + done via side effects. */ + if (tf->next->ty == TY::Tvoid || tf->next->ty == TY::Tnoreturn) + return false; + + /* Delegates that can modify its context can't be `pure'. */ + if (type->isTypeDelegate () && tf->isMutable ()) + return false; + + /* Only consider it as `pure' if it can't modify its arguments. */ + if (tf->purity == PURE::const_) + return true; + } + + return false; +} + /* Returns TRUE if CALLEE is a plain nested function outside the scope of CALLER. In which case, CALLEE is being called through an alias that was passed to CALLER. */ diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h index 66c2f2465c8..ed26533feb4 100644 --- a/gcc/d/d-tree.h +++ b/gcc/d/d-tree.h @@ -47,6 +47,7 @@ typedef Array Expressions; /* Usage of TREE_LANG_FLAG_?: 0: METHOD_CALL_EXPR + 1: CALL_EXPR_WARN_IF_UNUSED (in CALL_EXPR). Usage of TYPE_LANG_FLAG_?: 0: TYPE_SHARED @@ -357,6 +358,11 @@ lang_tree_node #define METHOD_CALL_EXPR(NODE) \ (TREE_LANG_FLAG_0 (NODE)) +/* True if the CALL_EXPR is free of side effects, and its return value + should not be discarded. */ +#define CALL_EXPR_WARN_IF_UNUSED(NODE) \ + (TREE_LANG_FLAG_1 (CALL_EXPR_CHECK (NODE))) + /* True if the type was declared 'shared'. */ #define TYPE_SHARED(NODE) \ (TYPE_LANG_FLAG_0 (NODE)) @@ -594,6 +600,7 @@ extern tree build_bounds_slice_condition (SliceExp *, tree, tree, tree); extern bool array_bounds_check (void); extern bool checkaction_trap_p (void); extern TypeFunction *get_function_type (Type *); +extern bool call_side_effect_free_p (FuncDeclaration *, Type *); extern bool call_by_alias_p (FuncDeclaration *, FuncDeclaration *); extern tree d_build_call_expr (FuncDeclaration *, tree, Expressions *); extern tree d_build_call (TypeFunction *, tree, tree, Expressions *); diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 52243e61899..72180b100af 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -1714,6 +1714,12 @@ public: build the call expression. */ tree exp = d_build_call (tf, callee, object, e->arguments); + /* Record whether the call expression has no side effects, so we can check + for an unused return value later. */ + if (TREE_CODE (exp) == CALL_EXPR && CALL_EXPR_FN (exp) != NULL_TREE + && call_side_effect_free_p (e->f, e->e1->type)) + CALL_EXPR_WARN_IF_UNUSED (exp) = 1; + if (returnvalue != NULL_TREE) exp = compound_expr (exp, returnvalue); @@ -2338,7 +2344,12 @@ public: new_call = d_save_expr (new_call); se->type = sd->type; se->sym = new_call; - result = compound_expr (build_expr (se), new_call); + + /* Setting `se->sym' would mean that the result of the + constructed struct literal expression is `*(new_call)'. + Strip off the indirect reference, as we don't mean to + compute the value yet. */ + result = build_address (build_expr (se)); } else result = new_call; diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc index db6f71babda..f87e094afca 100644 --- a/gcc/d/toir.cc +++ b/gcc/d/toir.cc @@ -215,6 +215,38 @@ add_stmt (tree t) if (!TREE_SIDE_EFFECTS (t)) return; + /* If a call expression has no side effects, and there's no explicit + `cast(void)', then issue a warning about the unused return value. */ + if (TREE_CODE (t) == INDIRECT_REF) + { + t = TREE_OPERAND (t, 0); + + if (TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE) + warning (OPT_Wunused_value, "value computed is not used"); + } + + if (TREE_CODE (t) == CALL_EXPR && CALL_EXPR_FN (t) != NULL_TREE + && CALL_EXPR_WARN_IF_UNUSED (t)) + { + tree callee = CALL_EXPR_FN (t); + + /* It's a call to a function or function pointer. */ + if (TREE_CODE (callee) == ADDR_EXPR + && VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (callee, 0))) + callee = TREE_OPERAND (callee, 0); + + /* It's a call to a delegate object. */ + if (TREE_CODE (callee) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (callee, 0))) == RECORD_TYPE + && TYPE_DELEGATE (TREE_TYPE (TREE_OPERAND (callee, 0)))) + callee = TREE_OPERAND (callee, 0); + + warning (OPT_Wunused_value, + "calling %qE without side effects discards return value " + "of type %qT; prepend a % if intentional", + callee, TREE_TYPE (t)); + } + if (TREE_CODE (t) == COMPOUND_EXPR) { /* Push out each comma expressions as separate statements. */ diff --git a/gcc/testsuite/gdc.dg/Wunused_value.d b/gcc/testsuite/gdc.dg/Wunused_value.d new file mode 100644 index 00000000000..0afc881a7bb --- /dev/null +++ b/gcc/testsuite/gdc.dg/Wunused_value.d @@ -0,0 +1,29 @@ +// { dg-do compile } +// { dg-options "-Wunused-value" } + +@safe pure nothrow T t1(T)(T x) +{ + return x * x; +} + +nothrow pure int f1(immutable(int)[] a) +{ + return 0; +} + +nothrow pure int f2(immutable(int)* p) +{ + return 0; +} + +void test() +{ + int x = 3; + t1(x); // { dg-warning "without side effects discards return value" } + + auto fp = &t1!int; + fp(x); // { dg-warning "without side effects discards return value" } + + f1([]); // { dg-warning "without side effects discards return value" } + f2(null); // { dg-warning "without side effects discards return value" } +}