From patchwork Tue Jul 12 12:25:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pierre-Marie de Rodat X-Patchwork-Id: 55949 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2B70C38EC78A for ; Tue, 12 Jul 2022 12:27:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2B70C38EC78A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1657628864; bh=Fi94Bi5Vt++bOOsTf28kGIBTbtSbSdZ62VwDgEWdrJQ=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=n/Hmtc4s93XBa4hUxm5YzBi1XwvwBQMGpXkoOXLDJDuEogPXuB1B4V6mgI3vA7nE7 m0//CEz9OGYpsGsYtF5UuYCGsghcsT5ngLi/Q07vsnM3qix/947wK85kcZYnGHqgf/ iObcLB1qIBtR7PJfy8UaG1fwq4l/0lax4zaHOC/s= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-ej1-x635.google.com (mail-ej1-x635.google.com [IPv6:2a00:1450:4864:20::635]) by sourceware.org (Postfix) with ESMTPS id 4D30E385C33F for ; Tue, 12 Jul 2022 12:25:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4D30E385C33F Received: by mail-ej1-x635.google.com with SMTP id mf4so12818934ejc.3 for ; Tue, 12 Jul 2022 05:25:23 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition; bh=Fi94Bi5Vt++bOOsTf28kGIBTbtSbSdZ62VwDgEWdrJQ=; b=JoBuvLIUkfOa//6d79uVdCpLgak95M8AUVigpNFbSrgXMD0EJVnIzXWiiXYoRt5BbS fmT19/M95H13y+qIrhu6fvCcbidFRy5LgdBrmzvOhEBpmUZqhytyfmmv98ZvSC2xV+bO Y/oQIKd3h0BNhgjhwZvnhrrQAZJo/3NGMe5aAbAIGjA4kDRD9GgQsywkOoNyi42AeWdf gJ7AQ6GybAzihlqpBuvB0AOf/mqJxDEP9M+rbqgRE4+M/tLiEnBmJ66xoN5eINTJm2B7 USlQCC1H0H29AImXGSfJF9CQ2bIn42Ihn33klAdu+gJVjoZ9IskOk1Epxw6UodTC1NzT G2Yg== X-Gm-Message-State: AJIora9t3Xx3OKMTM5u0Ul+PhUUr/+zv94C3wwLAObkNf0lCcI3ND3bv UpOkd+iaPfZovAh8Zo0tRnUwMCP1O1t45g== X-Google-Smtp-Source: AGRyM1u4u9sf0OkT+rNP7kFAKTjAWME/45ewl/Jdpk+62QV9fDAWlIih1LaKjNXhrSEism3Jig1vpw== X-Received: by 2002:a17:906:7e43:b0:72b:52de:b039 with SMTP id z3-20020a1709067e4300b0072b52deb039mr10704079ejr.198.1657628722072; Tue, 12 Jul 2022 05:25:22 -0700 (PDT) Received: from adacore.com ([45.147.211.82]) by smtp.gmail.com with ESMTPSA id dy26-20020a05640231fa00b0043a754d53e5sm5951032edb.78.2022.07.12.05.25.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 Jul 2022 05:25:21 -0700 (PDT) Date: Tue, 12 Jul 2022 12:25:20 +0000 To: gcc-patches@gcc.gnu.org Subject: [Ada] Remove out-of-range warning in unreachable code Message-ID: <20220712122520.GA3404745@adacore.com> MIME-Version: 1.0 Content-Disposition: inline X-Spam-Status: No, score=-12.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Pierre-Marie de Rodat via Gcc-patches From: Pierre-Marie de Rodat Reply-To: Pierre-Marie de Rodat Cc: Bob Duff Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" This patch removes a warning in examples like this: if cond then return; -- or other jump end if; X := ...; -- where the value is out of range where cond is known at compile time. It could, for example, be a generic formal parameter that is known to be True in some instances. As a side effect, this patch adds new warnings about unreachable code. Tested on x86_64-pc-linux-gnu, committed on trunk gcc/ada/ * gnatls.adb (Output_License_Information): Remove pragma No_Return; call sites deal with Exit_Program. * libgnat/g-socthi.adb (C_Connect): Suppress warning about unreachable code. * sem_ch5.adb (Check_Unreachable_Code): Special-case if statements with static conditions. If we remove unreachable code (including the return statement) from a function, add "raise Program_Error", so we won't warn about missing returns. Remove Original_Node in test for N_Raise_Statement; it's not needed. Remove test for CodePeer_Mode; if Operating_Mode = Generate_Code, then CodePeer_Mode can't be True. Misc cleanup. Do not reuse Nxt variable for unrelated purpose (the usage in the Kill_Dead_Code loop is entirely local to the loop). * sem_ch6.adb: Add check for Is_Transfer. Misc cleanup. * sem_prag.adb: Minor. * sem_res.adb: Minor. * sem_util.adb: Minor cleanup. (Is_Trivial_Boolean): Move to nonnested place, so it can be called from elsewhere. (Is_Static_Constant_Boolean): New function. * sem_util.ads (Is_Trivial_Boolean): Export. (Is_Static_Constant_Boolean): New function. diff --git a/gcc/ada/gnatls.adb b/gcc/ada/gnatls.adb --- a/gcc/ada/gnatls.adb +++ b/gcc/ada/gnatls.adb @@ -189,7 +189,6 @@ procedure Gnatls is -- Print usage message procedure Output_License_Information; - pragma No_Return (Output_License_Information); -- Output license statement, and if not found, output reference to COPYING function Image (Restriction : Restriction_Id) return String; @@ -894,8 +893,6 @@ procedure Gnatls is & " for license terms."); Write_Eol; end case; - - Exit_Program (E_Success); end Output_License_Information; ------------------- diff --git a/gcc/ada/libgnat/g-socthi.adb b/gcc/ada/libgnat/g-socthi.adb --- a/gcc/ada/libgnat/g-socthi.adb +++ b/gcc/ada/libgnat/g-socthi.adb @@ -187,7 +187,9 @@ package body GNAT.Sockets.Thin is return Res; end if; - declare + pragma Warnings (Off, "unreachable code"); + declare -- unreachable if Thread_Blocking_IO is statically True + pragma Warnings (On, "unreachable code"); WSet : aliased Fd_Set; Now : aliased Timeval; diff --git a/gcc/ada/sem_ch5.adb b/gcc/ada/sem_ch5.adb --- a/gcc/ada/sem_ch5.adb +++ b/gcc/ada/sem_ch5.adb @@ -4425,7 +4425,7 @@ package body Sem_Ch5 is if not (Present (Current_Subprogram) and then Ekind (Current_Subprogram) = E_Function - and then (Nkind (Original_Node (N)) = N_Raise_Statement + and then (Nkind (N) in N_Raise_Statement or else (Nkind (N) = N_Procedure_Call_Statement and then Is_Entity_Name (Name (N)) @@ -4444,39 +4444,59 @@ package body Sem_Ch5 is -- unreachable code, since it is useless and we don't want -- to generate junk warnings. - -- We skip this step if we are not in code generation mode - -- or CodePeer mode. + -- We skip this step if we are not in code generation mode. -- This is the one case where we remove dead code in the -- semantics as opposed to the expander, and we do not want -- to remove code if we are not in code generation mode, since -- this messes up the tree or loses useful information for - -- CodePeer. + -- analysis tools such as CodePeer. -- Note that one might react by moving the whole circuit to -- exp_ch5, but then we lose the warning in -gnatc mode. - if Operating_Mode = Generate_Code - and then not CodePeer_Mode - then + if Operating_Mode = Generate_Code then loop - Nxt := Next (N); - - -- Quit deleting when we have nothing more to delete - -- or if we hit a label (since someone could transfer - -- control to a label, so we should not delete it). + declare + Del : constant Node_Id := Next (N); + -- Node to be possibly deleted + begin + -- Quit deleting when we have nothing more to delete + -- or if we hit a label (since someone could transfer + -- control to a label, so we should not delete it). - exit when No (Nxt) or else Nkind (Nxt) = N_Label; + exit when No (Del) or else Nkind (Del) = N_Label; - -- Statement/declaration is to be deleted + -- Statement/declaration is to be deleted - Analyze (Nxt); - Remove (Nxt); - Kill_Dead_Code (Nxt); + Analyze (Del); + Kill_Dead_Code (Del); + Remove (Del); + end; end loop; + + -- If this is a function, we add "raise Program_Error;", + -- because otherwise, we will get incorrect warnings about + -- falling off the end of the function. + + declare + Subp : constant Entity_Id := Current_Subprogram; + begin + if Present (Subp) and then Ekind (Subp) = E_Function then + Insert_After_And_Analyze (N, + Make_Raise_Program_Error (Sloc (Error_Node), + Reason => PE_Missing_Return)); + end if; + end; + end if; - Error_Msg_N ("??unreachable code!", Error_Node); + -- Suppress the warning in instances, because a statement can + -- be unreachable in some instances but not others. + + if not In_Instance then + Error_Msg_N ("??unreachable code!", Error_Node); + end if; end if; -- If the unconditional transfer of control instruction is the @@ -4535,9 +4555,33 @@ package body Sem_Ch5 is end if; -- This was one of the cases we are looking for (i.e. the parent - -- construct was IF, CASE or block) so decrement count. - - Unblocked_Exit_Count := Unblocked_Exit_Count - 1; + -- construct was IF, CASE or block). In most cases, we simply + -- decrement the count. However, if the parent is something like: + -- + -- if cond then + -- raise ...; -- or some other jump + -- end if; + -- + -- where cond is an expression that is known-true at compile time, + -- we can treat that as just the jump -- i.e. anything following + -- the if statement is unreachable. We don't do this for simple + -- cases like "if True" or "if Debug_Flag", because that causes + -- too many warnings. + + if Nkind (P) = N_If_Statement + and then Present (Then_Statements (P)) + and then No (Elsif_Parts (P)) + and then No (Else_Statements (P)) + and then Is_OK_Static_Expression (Condition (P)) + and then Is_True (Expr_Value (Condition (P))) + and then not Is_Trivial_Boolean (Condition (P)) + and then not Is_Static_Constant_Name (Condition (P)) + then + pragma Assert (Unblocked_Exit_Count = 2); + Unblocked_Exit_Count := 0; + else + Unblocked_Exit_Count := Unblocked_Exit_Count - 1; + end if; end if; end if; end Check_Unreachable_Code; diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb --- a/gcc/ada/sem_ch6.adb +++ b/gcc/ada/sem_ch6.adb @@ -7564,6 +7564,8 @@ package body Sem_Ch6 is Err : out Boolean; Proc : Entity_Id := Empty) is + pragma Assert (Mode in 'F' | 'P'); + pragma Assert (if Mode = 'F' then No (Proc)); Handler : Node_Id; procedure Check_Statement_Sequence (L : List_Id); @@ -7613,15 +7615,13 @@ package body Sem_Ch6 is -- Local variables - Raise_Exception_Call : Boolean; + Raise_Exception_Call : Boolean := False; -- Set True if statement sequence terminated by Raise_Exception call -- or a Reraise_Occurrence call. -- Start of processing for Check_Statement_Sequence begin - Raise_Exception_Call := False; - -- Get last real statement Last_Stm := Last (L); @@ -7687,7 +7687,8 @@ package body Sem_Ch6 is while Nkind (Last_Stm) = N_Pragma - -- Don't count call to SS_Release (can happen after Raise_Exception) + -- Don't count call to SS_Release (can happen after + -- Raise_Exception). or else (Nkind (Last_Stm) = N_Procedure_Call_Statement @@ -7696,7 +7697,7 @@ package body Sem_Ch6 is and then Is_RTE (Entity (Name (Last_Stm)), RE_SS_Release)) - -- Don't count exception junk + -- Don't count exception junk or else (Nkind (Last_Stm) in @@ -7704,10 +7705,12 @@ package body Sem_Ch6 is and then Exception_Junk (Last_Stm)) or else Nkind (Last_Stm) in N_Push_xxx_Label | N_Pop_xxx_Label - -- Inserted code, such as finalization calls, is irrelevant: we only - -- need to check original source. + -- Inserted code, such as finalization calls, is irrelevant; we + -- only need to check original source. If we see a transfer of + -- control, we stop. - or else Is_Rewrite_Insertion (Last_Stm) + or else (Is_Rewrite_Insertion (Last_Stm) + and then not Is_Transfer (Last_Stm)) loop Prev (Last_Stm); end loop; diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb --- a/gcc/ada/sem_prag.adb +++ b/gcc/ada/sem_prag.adb @@ -6694,7 +6694,7 @@ package body Sem_Prag is if Loc not in Source_First (Sindex) .. Source_Last (Sindex) then -- We do not want to raise an exception here since this code -- is part of the bootstrap path where we cannot rely on - -- exception proapgation working. + -- exception propagation working. -- Instead the caller should check for N being rewritten as -- a null statement. -- This code triggers when compiling a-except.adb. diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb --- a/gcc/ada/sem_res.adb +++ b/gcc/ada/sem_res.adb @@ -7196,9 +7196,7 @@ package body Sem_Res is -- Check unreachable code after calls to procedures with No_Return - if Ekind (Nam) = E_Procedure - and then No_Return (Nam) - then + if Ekind (Nam) = E_Procedure and then No_Return (Nam) then Check_Unreachable_Code (N); end if; diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb --- a/gcc/ada/sem_util.adb +++ b/gcc/ada/sem_util.adb @@ -4868,9 +4868,6 @@ package body Sem_Util is -- and post-state. Prag is a [refined] postcondition or a contract-cases -- pragma. Result_Seen is set when the pragma mentions attribute 'Result - function Is_Trivial_Boolean (N : Node_Id) return Boolean; - -- Determine whether source node N denotes "True" or "False" - ------------------------------------------- -- Check_Result_And_Post_State_In_Pragma -- ------------------------------------------- @@ -5243,20 +5240,6 @@ package body Sem_Util is end if; end Check_Result_And_Post_State_In_Pragma; - ------------------------ - -- Is_Trivial_Boolean -- - ------------------------ - - function Is_Trivial_Boolean (N : Node_Id) return Boolean is - begin - return - Comes_From_Source (N) - and then Is_Entity_Name (N) - and then (Entity (N) = Standard_True - or else - Entity (N) = Standard_False); - end Is_Trivial_Boolean; - -- Local variables Items : constant Node_Id := Contract (Subp_Id); @@ -21501,19 +21484,15 @@ package body Sem_Util is Kind : constant Node_Kind := Nkind (N); begin - if Kind = N_Simple_Return_Statement - or else - Kind = N_Extended_Return_Statement - or else - Kind = N_Goto_Statement - or else - Kind = N_Raise_Statement - or else - Kind = N_Requeue_Statement + if Kind in N_Simple_Return_Statement + | N_Extended_Return_Statement + | N_Goto_Statement + | N_Raise_Statement + | N_Requeue_Statement then return True; - elsif (Kind = N_Exit_Statement or else Kind in N_Raise_xxx_Error) + elsif Kind in N_Exit_Statement | N_Raise_xxx_Error and then No (Condition (N)) then return True; @@ -21542,6 +21521,29 @@ package body Sem_Util is return No (U) or else U = Uint_1; end Is_True; + ------------------------ + -- Is_Trivial_Boolean -- + ------------------------ + + function Is_Trivial_Boolean (N : Node_Id) return Boolean is + begin + return Comes_From_Source (N) + and then Nkind (N) in N_Identifier | N_Expanded_Name + and then Entity (N) in Standard_True | Standard_False; + end Is_Trivial_Boolean; + + ----------------------------- + -- Is_Static_Constant_Name -- + ----------------------------- + + function Is_Static_Constant_Name (N : Node_Id) return Boolean is + begin + return Comes_From_Source (N) + and then Is_Static_Expression (N) + and then Nkind (N) in N_Identifier | N_Expanded_Name + and then Ekind (Entity (N)) = E_Constant; + end Is_Static_Constant_Name; + -------------------------------------- -- Is_Unchecked_Conversion_Instance -- -------------------------------------- diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads --- a/gcc/ada/sem_util.ads +++ b/gcc/ada/sem_util.ads @@ -2481,6 +2481,13 @@ package Sem_Util is -- unconditional transfer of control at run time, i.e. the following -- statement definitely will not be executed. + function Is_Trivial_Boolean (N : Node_Id) return Boolean; + -- Determine whether source node N denotes "True" or "False". Note that + -- this is not true for expressions that got folded to True or False. + + function Is_Static_Constant_Name (N : Node_Id) return Boolean; + -- True if N is a name that statically denotes a static constant. + function Is_Unchecked_Conversion_Instance (Id : Entity_Id) return Boolean; -- Determine whether an arbitrary entity denotes an instance of function -- Ada.Unchecked_Conversion.