From 879ac954ef76a1af1888abfaa44257f6f728372b Mon Sep 17 00:00:00 2001 From: Arnaud Charlet Date: Fri, 23 Oct 2015 15:04:01 +0200 Subject: [PATCH] [multiple changes] 2015-10-23 Hristian Kirtchev * contracts.ads, contracts.adb: New unit. * exp_ch6.adb Add with and use clauses for Contracts. (Expand_Subprogram_Contract): Moved to Contracts. * exp_ch6.ads (Expand_Subprogram_Contract): Moved to Contracts. * sem_ch3.adb Add with and use clauses for Contracts. (Analyze_Object_Contract): Moved to Contracts. (Analyze_Declarations): Remove local variable Pack_Decl. Do not capture global references in contracts. Check the hidden states of a package body. * sem_ch6.adb Add with and use clauses in Contracts. (Analyze_Generic_Subprogram_Body): Do not capture global references in contracts. (Analyze_Subprogram_Body_Contract): Moved to Contracts. (Analyze_Subprogram_Body_Helper): Freeze the contract of the nearest enclosing package body. Always analyze the subprogram body contract. Do not expand the subprogram body contract. (Analyze_Subprogram_Contract): Moved to Contracts. * sem_ch6.ads (Analyze_Subprogram_Body_Contract): Moved to Contracts. (Analyze_Subprogram_Contract): Moved to Contracts. * sem_ch7.adb Add with and use clauses for Contracts. (Analyze_Package_Body_Contract): Moved to Contracts. (Analyze_Package_Body_Helper): Freeze the contract of the nearest enclosing package body. (Analyze_Package_Contract): Moved to Contracts. * sem_ch7.ads (Analyze_Package_Body_Contract): Moved to Contracts. (Analyze_Package_Contract): Moved to Contracts. * sem_ch10.adb Add with and use clauses for Contracts. (Analyze_Compilation_Unit): Do not capture global references in contracts. (Analyze_Subprogram_Body_Stub_Contract): Moved to Contracts. * sem_ch10.ads (Analyze_Subprogram_Body_Stub_Contract): Moved to Contracts. * sem_ch12.adb Add with and use clauses for Contracts. (Analyze_Subprogram_Instantiation): Update the call to Instantiate_Subprogram_Contract. (Instantiate_Package_Body): Do not copy the entity of the spec when creating an entity for the body. Construct a brand new defining identifier for the body and inherit the Comes_From_Source flag from the spec. (Instantiate_Subprogram_Body): Remove Anon_Id to Act_Decl_Id and update all occurrences. Construct a brand new defining identifier for the body and inherit the Comes_From_Source flag from the spec. (Instantiate_Subprogram_Contract): Moved to Contracts. (Save_Global_References_In_Aspects): Moved to the spec of Sem_Ch12. (Save_Global_References_In_Contract): Moved to Contracts. * sem_ch12.ads (Save_Global_References_In_Aspects): Moved from the body of Sem_Ch12. (Save_Global_References_In_Contract): Moved to Contracts. * sem_prag.adb Add with and use clauses for Contracts. (Add_Item): Removed. All references to this routine have been replaced with calls to Append_New_Elmt. (Analyze_Constituent): Add special diagnostics for errors caused by freezing of contracts. (Analyze_Refined_State_In_Decl_Part): Add formal parameter Freeze_Id. Add new global variable Freeze_Posted. (Collect_Body_States): Removed. (Report_Unused_States): Removed. * sem_prag.ads (Analyze_Defined_State_In_Decl_Part): Add formal parameter Freeze_Id and update comment on usage. * sem_util.adb Remove with and use clauses for Sem_Ch12. (Add_Contract_Item): Moved to Contracts. (Check_Unused_Body_States): New routine. (Collect_Body_States): New routine. (Create_Generic_Contract): Moved to Contracts. (Inherit_Subprogram_Contract): Moved to Contracts. (Report_Unused_Body_States): New routine. * sem_util.ads (Add_Contract_Item): Moved to Contracts. (Check_Unused_Body_States): New routine. (Collect_Body_States): New routine. (Create_Generic_Contract): Moved to Contracts. (Inherit_Subprogram_Contract): Moved to Contracts. (Report_Unused_Body_States): New routine. * sinfo.adb (Is_Expanded_Contract): New routine. (Set_Is_Expanded_Contract): New routine. * sinfo.ads New attribute Is_Expanded_Contract along with placement in nodes. (Is_Expanded_Contract): New routine along with pragma Inline. (Set_Is_Expanded_Contract): New routine along with pragma Inline. * gcc-interface/Make-lang.in: Add entry for contracts.o 2015-10-23 Bob Duff * bindgen.adb, init.c, opt.ads, switch-b.adb: Implement new -Ea and -Es switches. * switch-b.ads: Minor comment fix. * bindusg.adb: Document new -Ea and -Es switches. * s-exctra.ads: Use -Es instead of -E. From-SVN: r229253 --- gcc/ada/ChangeLog | 102 ++ gcc/ada/bindgen.adb | 26 +- gcc/ada/bindusg.adb | 5 +- gcc/ada/contracts.adb | 2453 ++++++++++++++++++++++++++++ gcc/ada/contracts.ads | 156 ++ gcc/ada/exp_ch6.adb | 1362 +-------------- gcc/ada/exp_ch6.ads | 6 - gcc/ada/gcc-interface/Make-lang.in | 1 + gcc/ada/init.c | 1 + gcc/ada/opt.ads | 7 +- gcc/ada/s-exctra.ads | 15 +- gcc/ada/sem_ch10.adb | 130 +- gcc/ada/sem_ch10.ads | 16 +- gcc/ada/sem_ch12.adb | 283 +--- gcc/ada/sem_ch12.ads | 9 +- gcc/ada/sem_ch3.adb | 331 +--- gcc/ada/sem_ch6.adb | 391 +---- gcc/ada/sem_ch6.ads | 25 - gcc/ada/sem_ch7.adb | 208 +-- gcc/ada/sem_ch7.ads | 16 +- gcc/ada/sem_prag.adb | 422 ++--- gcc/ada/sem_prag.ads | 8 +- gcc/ada/sem_util.adb | 674 ++++---- gcc/ada/sem_util.ads | 71 +- gcc/ada/sinfo.adb | 16 + gcc/ada/sinfo.ads | 16 + gcc/ada/switch-b.adb | 30 +- gcc/ada/switch-b.ads | 4 +- 28 files changed, 3681 insertions(+), 3103 deletions(-) create mode 100644 gcc/ada/contracts.adb create mode 100644 gcc/ada/contracts.ads diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 28cc00cf8e0..88a2197025d 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,105 @@ +2015-10-23 Hristian Kirtchev + + * contracts.ads, contracts.adb: New unit. + * exp_ch6.adb Add with and use clauses for Contracts. + (Expand_Subprogram_Contract): Moved to Contracts. + * exp_ch6.ads (Expand_Subprogram_Contract): Moved to Contracts. + * sem_ch3.adb Add with and use clauses for Contracts. + (Analyze_Object_Contract): Moved to Contracts. + (Analyze_Declarations): Remove local variable Pack_Decl. Do not + capture global references in contracts. Check the hidden states + of a package body. + * sem_ch6.adb Add with and use clauses in Contracts. + (Analyze_Generic_Subprogram_Body): Do not capture global + references in contracts. + (Analyze_Subprogram_Body_Contract): + Moved to Contracts. + (Analyze_Subprogram_Body_Helper): Freeze the + contract of the nearest enclosing package body. Always analyze + the subprogram body contract. Do not expand the subprogram + body contract. + (Analyze_Subprogram_Contract): Moved to Contracts. + * sem_ch6.ads (Analyze_Subprogram_Body_Contract): Moved to Contracts. + (Analyze_Subprogram_Contract): Moved to Contracts. + * sem_ch7.adb Add with and use clauses for Contracts. + (Analyze_Package_Body_Contract): Moved to Contracts. + (Analyze_Package_Body_Helper): Freeze the contract of the + nearest enclosing package body. + (Analyze_Package_Contract): Moved to Contracts. + * sem_ch7.ads (Analyze_Package_Body_Contract): Moved to Contracts. + (Analyze_Package_Contract): Moved to Contracts. + * sem_ch10.adb Add with and use clauses for Contracts. + (Analyze_Compilation_Unit): Do not capture global references + in contracts. + (Analyze_Subprogram_Body_Stub_Contract): Moved to Contracts. + * sem_ch10.ads (Analyze_Subprogram_Body_Stub_Contract): Moved + to Contracts. + * sem_ch12.adb Add with and use clauses for Contracts. + (Analyze_Subprogram_Instantiation): Update the call to + Instantiate_Subprogram_Contract. + (Instantiate_Package_Body): + Do not copy the entity of the spec when creating an entity + for the body. Construct a brand new defining identifier for + the body and inherit the Comes_From_Source flag from the spec. + (Instantiate_Subprogram_Body): Remove Anon_Id to Act_Decl_Id + and update all occurrences. Construct a brand new defining + identifier for the body and inherit the Comes_From_Source + flag from the spec. + (Instantiate_Subprogram_Contract): Moved + to Contracts. + (Save_Global_References_In_Aspects): Moved to + the spec of Sem_Ch12. + (Save_Global_References_In_Contract): + Moved to Contracts. + * sem_ch12.ads (Save_Global_References_In_Aspects): Moved from + the body of Sem_Ch12. + (Save_Global_References_In_Contract): + Moved to Contracts. + * sem_prag.adb Add with and use clauses for Contracts. + (Add_Item): Removed. All references to this routine have been + replaced with calls to Append_New_Elmt. + (Analyze_Constituent): + Add special diagnostics for errors caused by freezing of + contracts. + (Analyze_Refined_State_In_Decl_Part): Add formal + parameter Freeze_Id. Add new global variable Freeze_Posted. + (Collect_Body_States): Removed. + (Report_Unused_States): Removed. + * sem_prag.ads (Analyze_Defined_State_In_Decl_Part): Add formal + parameter Freeze_Id and update comment on usage. + * sem_util.adb Remove with and use clauses for + Sem_Ch12. + (Add_Contract_Item): Moved to Contracts. + (Check_Unused_Body_States): New routine. + (Collect_Body_States): + New routine. + (Create_Generic_Contract): Moved to Contracts. + (Inherit_Subprogram_Contract): Moved to Contracts. + (Report_Unused_Body_States): New routine. + * sem_util.ads (Add_Contract_Item): Moved to Contracts. + (Check_Unused_Body_States): New routine. + (Collect_Body_States): New routine. + (Create_Generic_Contract): Moved to Contracts. + (Inherit_Subprogram_Contract): Moved to Contracts. + (Report_Unused_Body_States): New routine. + * sinfo.adb (Is_Expanded_Contract): New routine. + (Set_Is_Expanded_Contract): New routine. + * sinfo.ads New attribute Is_Expanded_Contract along with + placement in nodes. + (Is_Expanded_Contract): New routine along + with pragma Inline. + (Set_Is_Expanded_Contract): New routine + along with pragma Inline. + * gcc-interface/Make-lang.in: Add entry for contracts.o + +2015-10-23 Bob Duff + + * bindgen.adb, init.c, opt.ads, switch-b.adb: Implement new -Ea and + -Es switches. + * switch-b.ads: Minor comment fix. + * bindusg.adb: Document new -Ea and -Es switches. + * s-exctra.ads: Use -Es instead of -E. + 2015-10-23 Tristan Gingold * gcc-interface/utils2.c (build_call_alloc_dealloc): Check no implicit diff --git a/gcc/ada/bindgen.adb b/gcc/ada/bindgen.adb index cf4b59f981a..e284a0e130b 100644 --- a/gcc/ada/bindgen.adb +++ b/gcc/ada/bindgen.adb @@ -166,6 +166,7 @@ package body Bindgen is -- Num_Interrupt_States : Integer; -- Unreserve_All_Interrupts : Integer; -- Exception_Tracebacks : Integer; + -- Exception_Tracebacks_Symbolic : Integer; -- Detect_Blocking : Integer; -- Default_Stack_Size : Integer; -- Leap_Seconds_Support : Integer; @@ -235,10 +236,13 @@ package body Bindgen is -- Unreserve_All_Interrupts is set to one if at least one unit in the -- partition had a pragma Unreserve_All_Interrupts, and zero otherwise. - -- Exception_Tracebacks is set to one if the -E parameter was present - -- in the bind and to zero otherwise. Note that on some targets exception - -- tracebacks are provided by default, so a value of zero for this - -- parameter does not necessarily mean no trace backs are available. + -- Exception_Tracebacks is set to one if the -Ea or -E parameter was + -- present in the bind and to zero otherwise. Note that on some targets + -- exception tracebacks are provided by default, so a value of zero for + -- this parameter does not necessarily mean no trace backs are available. + + -- Exception_Tracebacks_Symbolic is set to one if the -Es parameter was + -- present in the bind and to zero otherwise. -- Detect_Blocking indicates whether pragma Detect_Blocking is active or -- not. A value of zero indicates that the pragma is not present, while a @@ -607,10 +611,16 @@ package body Bindgen is WBI (" pragma Import (C, Unreserve_All_Interrupts, " & """__gl_unreserve_all_interrupts"");"); - if Exception_Tracebacks then + if Exception_Tracebacks or Exception_Tracebacks_Symbolic then WBI (" Exception_Tracebacks : Integer;"); WBI (" pragma Import (C, Exception_Tracebacks, " & """__gl_exception_tracebacks"");"); + + if Exception_Tracebacks_Symbolic then + WBI (" Exception_Tracebacks_Symbolic : Integer;"); + WBI (" pragma Import (C, Exception_Tracebacks_Symbolic, " & + """__gl_exception_tracebacks_symbolic"");"); + end if; end if; WBI (" Detect_Blocking : Integer;"); @@ -795,8 +805,12 @@ package body Bindgen is Set_Char (';'); Write_Statement_Buffer; - if Exception_Tracebacks then + if Exception_Tracebacks or Exception_Tracebacks_Symbolic then WBI (" Exception_Tracebacks := 1;"); + + if Exception_Tracebacks_Symbolic then + WBI (" Exception_Tracebacks_Symbolic := 1;"); + end if; end if; Set_String (" Detect_Blocking := "); diff --git a/gcc/ada/bindusg.adb b/gcc/ada/bindusg.adb index e5c0e362faa..f1a61777bfb 100644 --- a/gcc/ada/bindusg.adb +++ b/gcc/ada/bindusg.adb @@ -108,7 +108,10 @@ package body Bindusg is -- Line for -E switch - Write_Line (" -E Store tracebacks in exception occurrences"); + Write_Line (" -Ea Store tracebacks in exception occurrences"); + Write_Line (" -Es Store tracebacks in exception occurrences,"); + Write_Line (" and enable symbolic tracebacks"); + Write_Line (" -E Same as -Ea"); -- The -f switch is voluntarily omitted, because it is obsolete diff --git a/gcc/ada/contracts.adb b/gcc/ada/contracts.adb new file mode 100644 index 00000000000..ffdd510acac --- /dev/null +++ b/gcc/ada/contracts.adb @@ -0,0 +1,2453 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- C O N T R A C T S -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 2015, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT 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 distributed with GNAT; see file COPYING3. If not, go to -- +-- http://www.gnu.org/licenses for a complete copy of the license. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +with Aspects; use Aspects; +with Atree; use Atree; +with Einfo; use Einfo; +with Elists; use Elists; +with Errout; use Errout; +with Exp_Prag; use Exp_Prag; +with Exp_Tss; use Exp_Tss; +with Exp_Util; use Exp_Util; +with Namet; use Namet; +with Nlists; use Nlists; +with Nmake; use Nmake; +with Opt; use Opt; +with Sem; use Sem; +with Sem_Aux; use Sem_Aux; +with Sem_Ch6; use Sem_Ch6; +with Sem_Ch8; use Sem_Ch8; +with Sem_Ch12; use Sem_Ch12; +with Sem_Disp; use Sem_Disp; +with Sem_Prag; use Sem_Prag; +with Sem_Util; use Sem_Util; +with Sinfo; use Sinfo; +with Snames; use Snames; +with Stringt; use Stringt; +with Tbuild; use Tbuild; + +package body Contracts is + + procedure Expand_Subprogram_Contract (Body_Id : Entity_Id); + -- Expand the contracts of a subprogram body and its correspoding spec (if + -- any). This routine processes all [refined] pre- and postconditions as + -- well as Contract_Cases, invariants and predicates. Body_Id denotes the + -- entity of the subprogram body. + + ----------------------- + -- Add_Contract_Item -- + ----------------------- + + procedure Add_Contract_Item (Prag : Node_Id; Id : Entity_Id) is + Items : Node_Id := Contract (Id); + + procedure Add_Classification; + -- Prepend Prag to the list of classifications + + procedure Add_Contract_Test_Case; + -- Prepend Prag to the list of contract and test cases + + procedure Add_Pre_Post_Condition; + -- Prepend Prag to the list of pre- and postconditions + + ------------------------ + -- Add_Classification -- + ------------------------ + + procedure Add_Classification is + begin + Set_Next_Pragma (Prag, Classifications (Items)); + Set_Classifications (Items, Prag); + end Add_Classification; + + ---------------------------- + -- Add_Contract_Test_Case -- + ---------------------------- + + procedure Add_Contract_Test_Case is + begin + Set_Next_Pragma (Prag, Contract_Test_Cases (Items)); + Set_Contract_Test_Cases (Items, Prag); + end Add_Contract_Test_Case; + + ---------------------------- + -- Add_Pre_Post_Condition -- + ---------------------------- + + procedure Add_Pre_Post_Condition is + begin + Set_Next_Pragma (Prag, Pre_Post_Conditions (Items)); + Set_Pre_Post_Conditions (Items, Prag); + end Add_Pre_Post_Condition; + + -- Local variables + + Prag_Nam : Name_Id; + + -- Start of processing for Add_Contract_Item + + begin + -- A contract must contain only pragmas + + pragma Assert (Nkind (Prag) = N_Pragma); + Prag_Nam := Pragma_Name (Prag); + + -- Create a new contract when adding the first item + + if No (Items) then + Items := Make_Contract (Sloc (Id)); + Set_Contract (Id, Items); + end if; + + -- Contract items related to constants. Applicable pragmas are: + -- Part_Of + + if Ekind (Id) = E_Constant then + if Prag_Nam = Name_Part_Of then + Add_Classification; + + -- The pragma is not a proper contract item + + else + raise Program_Error; + end if; + + -- Contract items related to [generic] packages or instantiations. The + -- applicable pragmas are: + -- Abstract_States + -- Initial_Condition + -- Initializes + -- Part_Of (instantiation only) + + elsif Ekind_In (Id, E_Generic_Package, E_Package) then + if Nam_In (Prag_Nam, Name_Abstract_State, + Name_Initial_Condition, + Name_Initializes) + then + Add_Classification; + + -- Indicator Part_Of must be associated with a package instantiation + + elsif Prag_Nam = Name_Part_Of and then Is_Generic_Instance (Id) then + Add_Classification; + + -- The pragma is not a proper contract item + + else + raise Program_Error; + end if; + + -- Contract items related to package bodies. The applicable pragmas are: + -- Refined_States + + elsif Ekind (Id) = E_Package_Body then + if Prag_Nam = Name_Refined_State then + Add_Classification; + + -- The pragma is not a proper contract item + + else + raise Program_Error; + end if; + + -- Contract items related to subprogram or entry declarations. The + -- applicable pragmas are: + -- Contract_Cases + -- Depends + -- Extensions_Visible + -- Global + -- Postcondition + -- Precondition + -- Test_Case + -- Volatile_Function + + elsif Ekind_In (Id, E_Entry, E_Entry_Family) + or else Is_Generic_Subprogram (Id) + or else Is_Subprogram (Id) + then + if Nam_In (Prag_Nam, Name_Postcondition, Name_Precondition) then + Add_Pre_Post_Condition; + + elsif Nam_In (Prag_Nam, Name_Contract_Cases, Name_Test_Case) then + Add_Contract_Test_Case; + + elsif Nam_In (Prag_Nam, Name_Depends, + Name_Extensions_Visible, + Name_Global) + then + Add_Classification; + + elsif Prag_Nam = Name_Volatile_Function + and then Ekind_In (Id, E_Function, E_Generic_Function) + then + Add_Classification; + + -- The pragma is not a proper contract item + + else + raise Program_Error; + end if; + + -- Contract items related to subprogram bodies. Applicable pragmas are: + -- Postcondition + -- Precondition + -- Refined_Depends + -- Refined_Global + -- Refined_Post + + elsif Ekind (Id) = E_Subprogram_Body then + if Nam_In (Prag_Nam, Name_Refined_Depends, Name_Refined_Global) then + Add_Classification; + + elsif Nam_In (Prag_Nam, Name_Postcondition, + Name_Precondition, + Name_Refined_Post) + then + Add_Pre_Post_Condition; + + -- The pragma is not a proper contract item + + else + raise Program_Error; + end if; + + -- Contract items related to variables. Applicable pragmas are: + -- Async_Readers + -- Async_Writers + -- Constant_After_Elaboration + -- Effective_Reads + -- Effective_Writes + -- Part_Of + + elsif Ekind (Id) = E_Variable then + if Nam_In (Prag_Nam, Name_Async_Readers, + Name_Async_Writers, + Name_Constant_After_Elaboration, + Name_Effective_Reads, + Name_Effective_Writes, + Name_Part_Of) + then + Add_Classification; + + -- The pragma is not a proper contract item + + else + raise Program_Error; + end if; + end if; + end Add_Contract_Item; + + --------------------------------------------- + -- Analyze_Enclosing_Package_Body_Contract -- + --------------------------------------------- + + procedure Analyze_Enclosing_Package_Body_Contract (Body_Decl : Node_Id) is + Par : Node_Id; + + begin + -- Climb the parent chain looking for an enclosing body. Do not use the + -- scope stack as a body uses the entity of its corresponding spec. + + Par := Parent (Body_Decl); + while Present (Par) loop + if Nkind (Par) = N_Package_Body then + Analyze_Package_Body_Contract + (Body_Id => Defining_Entity (Par), + Freeze_Id => Defining_Entity (Body_Decl)); + + return; + end if; + + Par := Parent (Par); + end loop; + end Analyze_Enclosing_Package_Body_Contract; + + ----------------------------- + -- Analyze_Object_Contract -- + ----------------------------- + + procedure Analyze_Object_Contract (Obj_Id : Entity_Id) is + Obj_Typ : constant Entity_Id := Etype (Obj_Id); + AR_Val : Boolean := False; + AW_Val : Boolean := False; + ER_Val : Boolean := False; + EW_Val : Boolean := False; + Items : Node_Id; + Prag : Node_Id; + Seen : Boolean := False; + + begin + -- The loop parameter in an element iterator over a formal container + -- is declared with an object declaration but no contracts apply. + + if Ekind (Obj_Id) = E_Loop_Parameter then + return; + end if; + + -- Do not analyze a contract mutiple times + + Items := Contract (Obj_Id); + + if Present (Items) then + if Analyzed (Items) then + return; + else + Set_Analyzed (Items); + end if; + end if; + + -- Constant related checks + + if Ekind (Obj_Id) = E_Constant then + + -- A constant cannot be effectively volatile (SPARK RM 7.1.3(4)). + -- This check is relevant only when SPARK_Mode is on as it is not a + -- standard Ada legality rule. Internally-generated constants that + -- map generic formals to actuals in instantiations are allowed to + -- be volatile. + + if SPARK_Mode = On + and then Comes_From_Source (Obj_Id) + and then Is_Effectively_Volatile (Obj_Id) + and then No (Corresponding_Generic_Association (Parent (Obj_Id))) + then + Error_Msg_N ("constant cannot be volatile", Obj_Id); + end if; + + -- Variable related checks + + else pragma Assert (Ekind (Obj_Id) = E_Variable); + + -- The following checks are relevant only when SPARK_Mode is on as + -- they are not standard Ada legality rules. Internally generated + -- temporaries are ignored. + + if SPARK_Mode = On and then Comes_From_Source (Obj_Id) then + if Is_Effectively_Volatile (Obj_Id) then + + -- The declaration of an effectively volatile object must + -- appear at the library level (SPARK RM 7.1.3(3), C.6(6)). + + if not Is_Library_Level_Entity (Obj_Id) then + Error_Msg_N + ("volatile variable & must be declared at library level", + Obj_Id); + + -- An object of a discriminated type cannot be effectively + -- volatile except for protected objects (SPARK RM 7.1.3(5)). + + elsif Has_Discriminants (Obj_Typ) + and then not Is_Protected_Type (Obj_Typ) + then + Error_Msg_N + ("discriminated object & cannot be volatile", Obj_Id); + + -- An object of a tagged type cannot be effectively volatile + -- (SPARK RM C.6(5)). + + elsif Is_Tagged_Type (Obj_Typ) then + Error_Msg_N ("tagged object & cannot be volatile", Obj_Id); + end if; + + -- The object is not effectively volatile + + else + -- A non-effectively volatile object cannot have effectively + -- volatile components (SPARK RM 7.1.3(6)). + + if not Is_Effectively_Volatile (Obj_Id) + and then Has_Volatile_Component (Obj_Typ) + then + Error_Msg_N + ("non-volatile object & cannot have volatile components", + Obj_Id); + end if; + end if; + end if; + + if Is_Ghost_Entity (Obj_Id) then + + -- A Ghost object cannot be effectively volatile (SPARK RM 6.9(8)) + + if Is_Effectively_Volatile (Obj_Id) then + Error_Msg_N ("ghost variable & cannot be volatile", Obj_Id); + + -- A Ghost object cannot be imported or exported (SPARK RM 6.9(8)) + + elsif Is_Imported (Obj_Id) then + Error_Msg_N ("ghost object & cannot be imported", Obj_Id); + + elsif Is_Exported (Obj_Id) then + Error_Msg_N ("ghost object & cannot be exported", Obj_Id); + end if; + end if; + + -- Analyze all external properties + + Prag := Get_Pragma (Obj_Id, Pragma_Async_Readers); + + if Present (Prag) then + Analyze_External_Property_In_Decl_Part (Prag, AR_Val); + Seen := True; + end if; + + Prag := Get_Pragma (Obj_Id, Pragma_Async_Writers); + + if Present (Prag) then + Analyze_External_Property_In_Decl_Part (Prag, AW_Val); + Seen := True; + end if; + + Prag := Get_Pragma (Obj_Id, Pragma_Effective_Reads); + + if Present (Prag) then + Analyze_External_Property_In_Decl_Part (Prag, ER_Val); + Seen := True; + end if; + + Prag := Get_Pragma (Obj_Id, Pragma_Effective_Writes); + + if Present (Prag) then + Analyze_External_Property_In_Decl_Part (Prag, EW_Val); + Seen := True; + end if; + + -- Verify the mutual interaction of the various external properties + + if Seen then + Check_External_Properties (Obj_Id, AR_Val, AW_Val, ER_Val, EW_Val); + end if; + end if; + + -- Check whether the lack of indicator Part_Of agrees with the placement + -- of the object with respect to the state space. + + Prag := Get_Pragma (Obj_Id, Pragma_Part_Of); + + if No (Prag) then + Check_Missing_Part_Of (Obj_Id); + end if; + + -- A ghost object cannot be imported or exported (SPARK RM 6.9(8)). One + -- exception to this is the object that represents the dispatch table of + -- a Ghost tagged type as the symbol needs to be exported. + + if Comes_From_Source (Obj_Id) and then Is_Ghost_Entity (Obj_Id) then + if Is_Exported (Obj_Id) then + Error_Msg_N ("ghost object & cannot be exported", Obj_Id); + + elsif Is_Imported (Obj_Id) then + Error_Msg_N ("ghost object & cannot be imported", Obj_Id); + end if; + end if; + end Analyze_Object_Contract; + + ----------------------------------- + -- Analyze_Package_Body_Contract -- + ----------------------------------- + + procedure Analyze_Package_Body_Contract + (Body_Id : Entity_Id; + Freeze_Id : Entity_Id := Empty) + is + Body_Decl : constant Node_Id := Unit_Declaration_Node (Body_Id); + Items : constant Node_Id := Contract (Body_Id); + Spec_Id : constant Entity_Id := Spec_Entity (Body_Id); + Mode : SPARK_Mode_Type; + Ref_State : Node_Id; + + begin + -- Do not analyze a contract mutiple times + + if Present (Items) then + if Analyzed (Items) then + return; + else + Set_Analyzed (Items); + end if; + end if; + + -- Due to the timing of contract analysis, delayed pragmas may be + -- subject to the wrong SPARK_Mode, usually that of the enclosing + -- context. To remedy this, restore the original SPARK_Mode of the + -- related package body. + + Save_SPARK_Mode_And_Set (Body_Id, Mode); + + Ref_State := Get_Pragma (Body_Id, Pragma_Refined_State); + + -- The analysis of pragma Refined_State detects whether the spec has + -- abstract states available for refinement. + + if Present (Ref_State) then + Analyze_Refined_State_In_Decl_Part (Ref_State, Freeze_Id); + + -- State refinement is required when the package declaration defines at + -- least one abstract state. Null states are not considered. Refinement + -- is not envorced when SPARK checks are turned off. + + elsif SPARK_Mode /= Off + and then Requires_State_Refinement (Spec_Id, Body_Id) + then + Error_Msg_N ("package & requires state refinement", Spec_Id); + end if; + + -- Restore the SPARK_Mode of the enclosing context after all delayed + -- pragmas have been analyzed. + + Restore_SPARK_Mode (Mode); + + -- Capture all global references in a generic package body now that the + -- contract has been analyzed. + + if Is_Generic_Declaration_Or_Body (Body_Decl) then + Save_Global_References_In_Contract + (Templ => Original_Node (Body_Decl), + Gen_Id => Spec_Id); + end if; + end Analyze_Package_Body_Contract; + + ------------------------------ + -- Analyze_Package_Contract -- + ------------------------------ + + procedure Analyze_Package_Contract (Pack_Id : Entity_Id) is + Items : constant Node_Id := Contract (Pack_Id); + Pack_Decl : constant Node_Id := Unit_Declaration_Node (Pack_Id); + Init : Node_Id := Empty; + Init_Cond : Node_Id := Empty; + Mode : SPARK_Mode_Type; + Prag : Node_Id; + Prag_Nam : Name_Id; + + begin + -- Do not analyze a contract mutiple times + + if Present (Items) then + if Analyzed (Items) then + return; + else + Set_Analyzed (Items); + end if; + end if; + + -- Due to the timing of contract analysis, delayed pragmas may be + -- subject to the wrong SPARK_Mode, usually that of the enclosing + -- context. To remedy this, restore the original SPARK_Mode of the + -- related package. + + Save_SPARK_Mode_And_Set (Pack_Id, Mode); + + if Present (Items) then + + -- Locate and store pragmas Initial_Condition and Initializes since + -- their order of analysis matters. + + Prag := Classifications (Items); + while Present (Prag) loop + Prag_Nam := Pragma_Name (Prag); + + if Prag_Nam = Name_Initial_Condition then + Init_Cond := Prag; + + elsif Prag_Nam = Name_Initializes then + Init := Prag; + end if; + + Prag := Next_Pragma (Prag); + end loop; + + -- Analyze the initialization related pragmas. Initializes must come + -- before Initial_Condition due to item dependencies. + + if Present (Init) then + Analyze_Initializes_In_Decl_Part (Init); + end if; + + if Present (Init_Cond) then + Analyze_Initial_Condition_In_Decl_Part (Init_Cond); + end if; + end if; + + -- Check whether the lack of indicator Part_Of agrees with the placement + -- of the package instantiation with respect to the state space. + + if Is_Generic_Instance (Pack_Id) then + Prag := Get_Pragma (Pack_Id, Pragma_Part_Of); + + if No (Prag) then + Check_Missing_Part_Of (Pack_Id); + end if; + end if; + + -- Restore the SPARK_Mode of the enclosing context after all delayed + -- pragmas have been analyzed. + + Restore_SPARK_Mode (Mode); + + -- Capture all global references in a generic package now that the + -- contract has been analyzed. + + if Is_Generic_Declaration_Or_Body (Pack_Decl) then + Save_Global_References_In_Contract + (Templ => Original_Node (Pack_Decl), + Gen_Id => Pack_Id); + end if; + end Analyze_Package_Contract; + + -------------------------------------- + -- Analyze_Subprogram_Body_Contract -- + -------------------------------------- + + procedure Analyze_Subprogram_Body_Contract (Body_Id : Entity_Id) is + Body_Decl : constant Node_Id := Unit_Declaration_Node (Body_Id); + Items : constant Node_Id := Contract (Body_Id); + Spec_Id : constant Entity_Id := Corresponding_Spec_Of (Body_Decl); + Mode : SPARK_Mode_Type; + Prag : Node_Id; + Prag_Nam : Name_Id; + Ref_Depends : Node_Id := Empty; + Ref_Global : Node_Id := Empty; + + begin + -- When a subprogram body declaration is illegal, its defining entity is + -- left unanalyzed. There is nothing left to do in this case because the + -- body lacks a contract, or even a proper Ekind. + + if Ekind (Body_Id) = E_Void then + return; + + -- Do not analyze a contract mutiple times + + elsif Present (Items) then + if Analyzed (Items) then + return; + else + Set_Analyzed (Items); + end if; + end if; + + -- Due to the timing of contract analysis, delayed pragmas may be + -- subject to the wrong SPARK_Mode, usually that of the enclosing + -- context. To remedy this, restore the original SPARK_Mode of the + -- related subprogram body. + + Save_SPARK_Mode_And_Set (Body_Id, Mode); + + -- All subprograms carry a contract, but for some it is not significant + -- and should not be processed. + + if not Has_Significant_Contract (Body_Id) then + null; + + -- The subprogram body is a completion, analyze all delayed pragmas that + -- apply. Note that when the body is stand alone, the pragmas are always + -- analyzed on the spot. + + elsif Present (Items) then + + -- Locate and store pragmas Refined_Depends and Refined_Global since + -- their order of analysis matters. + + Prag := Classifications (Items); + while Present (Prag) loop + Prag_Nam := Pragma_Name (Prag); + + if Prag_Nam = Name_Refined_Depends then + Ref_Depends := Prag; + + elsif Prag_Nam = Name_Refined_Global then + Ref_Global := Prag; + end if; + + Prag := Next_Pragma (Prag); + end loop; + + -- Analyze Refined_Global first as Refined_Depends may mention items + -- classified in the global refinement. + + if Present (Ref_Global) then + Analyze_Refined_Global_In_Decl_Part (Ref_Global); + end if; + + -- Refined_Depends must be analyzed after Refined_Global in order to + -- see the modes of all global refinements. + + if Present (Ref_Depends) then + Analyze_Refined_Depends_In_Decl_Part (Ref_Depends); + end if; + end if; + + -- Ensure that the contract cases or postconditions mention 'Result or + -- define a post-state. + + Check_Result_And_Post_State (Body_Id); + + -- A stand alone non-volatile function body cannot have an effectively + -- volatile formal parameter or return type (SPARK RM 7.1.3(9)). This + -- check is relevant only when SPARK_Mode is on as it is not a standard + -- legality rule. The check is performed here because Volatile_Function + -- is processed after the analysis of the related subprogram body. + + if SPARK_Mode = On + and then Ekind_In (Body_Id, E_Function, E_Generic_Function) + and then not Is_Volatile_Function (Body_Id) + then + Check_Nonvolatile_Function_Profile (Body_Id); + end if; + + -- Restore the SPARK_Mode of the enclosing context after all delayed + -- pragmas have been analyzed. + + Restore_SPARK_Mode (Mode); + + -- Capture all global references in a generic subprogram body now that + -- the contract has been analyzed. + + if Is_Generic_Declaration_Or_Body (Body_Decl) then + Save_Global_References_In_Contract + (Templ => Original_Node (Body_Decl), + Gen_Id => Spec_Id); + end if; + + -- Deal with preconditions, [refined] postconditions, Contract_Cases, + -- invariants and predicates associated with body and its spec. Do not + -- expand the contract of subprogram body stubs. + + if Nkind (Body_Decl) = N_Subprogram_Body then + Expand_Subprogram_Contract (Body_Id); + end if; + end Analyze_Subprogram_Body_Contract; + + --------------------------------- + -- Analyze_Subprogram_Contract -- + --------------------------------- + + procedure Analyze_Subprogram_Contract (Subp_Id : Entity_Id) is + Items : constant Node_Id := Contract (Subp_Id); + Subp_Decl : constant Node_Id := Unit_Declaration_Node (Subp_Id); + Depends : Node_Id := Empty; + Global : Node_Id := Empty; + Mode : SPARK_Mode_Type; + Prag : Node_Id; + Prag_Nam : Name_Id; + + begin + -- Do not analyze a contract mutiple times + + if Present (Items) then + if Analyzed (Items) then + return; + else + Set_Analyzed (Items); + end if; + end if; + + -- Due to the timing of contract analysis, delayed pragmas may be + -- subject to the wrong SPARK_Mode, usually that of the enclosing + -- context. To remedy this, restore the original SPARK_Mode of the + -- related subprogram body. + + Save_SPARK_Mode_And_Set (Subp_Id, Mode); + + -- All subprograms carry a contract, but for some it is not significant + -- and should not be processed. + + if not Has_Significant_Contract (Subp_Id) then + null; + + elsif Present (Items) then + + -- Analyze pre- and postconditions + + Prag := Pre_Post_Conditions (Items); + while Present (Prag) loop + Analyze_Pre_Post_Condition_In_Decl_Part (Prag); + Prag := Next_Pragma (Prag); + end loop; + + -- Analyze contract-cases and test-cases + + Prag := Contract_Test_Cases (Items); + while Present (Prag) loop + Prag_Nam := Pragma_Name (Prag); + + if Prag_Nam = Name_Contract_Cases then + Analyze_Contract_Cases_In_Decl_Part (Prag); + else + pragma Assert (Prag_Nam = Name_Test_Case); + Analyze_Test_Case_In_Decl_Part (Prag); + end if; + + Prag := Next_Pragma (Prag); + end loop; + + -- Analyze classification pragmas + + Prag := Classifications (Items); + while Present (Prag) loop + Prag_Nam := Pragma_Name (Prag); + + if Prag_Nam = Name_Depends then + Depends := Prag; + + elsif Prag_Nam = Name_Global then + Global := Prag; + end if; + + Prag := Next_Pragma (Prag); + end loop; + + -- Analyze Global first as Depends may mention items classified in + -- the global categorization. + + if Present (Global) then + Analyze_Global_In_Decl_Part (Global); + end if; + + -- Depends must be analyzed after Global in order to see the modes of + -- all global items. + + if Present (Depends) then + Analyze_Depends_In_Decl_Part (Depends); + end if; + + -- Ensure that the contract cases or postconditions mention 'Result + -- or define a post-state. + + Check_Result_And_Post_State (Subp_Id); + end if; + + -- A non-volatile function cannot have an effectively volatile formal + -- parameter or return type (SPARK RM 7.1.3(9)). This check is relevant + -- only when SPARK_Mode is on as it is not a standard legality rule. The + -- check is performed here because pragma Volatile_Function is processed + -- after the analysis of the related subprogram declaration. + + if SPARK_Mode = On + and then Ekind_In (Subp_Id, E_Function, E_Generic_Function) + and then not Is_Volatile_Function (Subp_Id) + then + Check_Nonvolatile_Function_Profile (Subp_Id); + end if; + + -- Restore the SPARK_Mode of the enclosing context after all delayed + -- pragmas have been analyzed. + + Restore_SPARK_Mode (Mode); + + -- Capture all global references in a generic subprogram now that the + -- contract has been analyzed. + + if Is_Generic_Declaration_Or_Body (Subp_Decl) then + Save_Global_References_In_Contract + (Templ => Original_Node (Subp_Decl), + Gen_Id => Subp_Id); + end if; + end Analyze_Subprogram_Contract; + + ------------------------------------------- + -- Analyze_Subprogram_Body_Stub_Contract -- + ------------------------------------------- + + procedure Analyze_Subprogram_Body_Stub_Contract (Stub_Id : Entity_Id) is + Stub_Decl : constant Node_Id := Parent (Parent (Stub_Id)); + Spec_Id : constant Entity_Id := Corresponding_Spec_Of_Stub (Stub_Decl); + + begin + -- A subprogram body stub may act as its own spec or as the completion + -- of a previous declaration. Depending on the context, the contract of + -- the stub may contain two sets of pragmas. + + -- The stub is a completion, the applicable pragmas are: + -- Refined_Depends + -- Refined_Global + + if Present (Spec_Id) then + Analyze_Subprogram_Body_Contract (Stub_Id); + + -- The stub acts as its own spec, the applicable pragmas are: + -- Contract_Cases + -- Depends + -- Global + -- Postcondition + -- Precondition + -- Test_Case + + else + Analyze_Subprogram_Contract (Stub_Id); + end if; + end Analyze_Subprogram_Body_Stub_Contract; + + ----------------------------- + -- Create_Generic_Contract -- + ----------------------------- + + procedure Create_Generic_Contract (Unit : Node_Id) is + Templ : constant Node_Id := Original_Node (Unit); + Templ_Id : constant Entity_Id := Defining_Entity (Templ); + + procedure Add_Generic_Contract_Pragma (Prag : Node_Id); + -- Add a single contract-related source pragma Prag to the contract of + -- generic template Templ_Id. + + --------------------------------- + -- Add_Generic_Contract_Pragma -- + --------------------------------- + + procedure Add_Generic_Contract_Pragma (Prag : Node_Id) is + Prag_Templ : Node_Id; + + begin + -- Mark the pragma to prevent the premature capture of global + -- references when capturing global references of the context + -- (see Save_References_In_Pragma). + + Set_Is_Generic_Contract_Pragma (Prag); + + -- Pragmas that apply to a generic subprogram declaration are not + -- part of the semantic structure of the generic template: + + -- generic + -- procedure Example (Formal : Integer); + -- pragma Precondition (Formal > 0); + + -- Create a generic template for such pragmas and link the template + -- of the pragma with the generic template. + + if Nkind (Templ) = N_Generic_Subprogram_Declaration then + Rewrite + (Prag, Copy_Generic_Node (Prag, Empty, Instantiating => False)); + Prag_Templ := Original_Node (Prag); + + Set_Is_Generic_Contract_Pragma (Prag_Templ); + Add_Contract_Item (Prag_Templ, Templ_Id); + + -- Otherwise link the pragma with the generic template + + else + Add_Contract_Item (Prag, Templ_Id); + end if; + end Add_Generic_Contract_Pragma; + + -- Local variables + + Context : constant Node_Id := Parent (Unit); + Decl : Node_Id := Empty; + + -- Start of processing for Create_Generic_Contract + + begin + -- A generic package declaration carries contract-related source pragmas + -- in its visible declarations. + + if Nkind (Templ) = N_Generic_Package_Declaration then + Set_Ekind (Templ_Id, E_Generic_Package); + + if Present (Visible_Declarations (Specification (Templ))) then + Decl := First (Visible_Declarations (Specification (Templ))); + end if; + + -- A generic package body carries contract-related source pragmas in its + -- declarations. + + elsif Nkind (Templ) = N_Package_Body then + Set_Ekind (Templ_Id, E_Package_Body); + + if Present (Declarations (Templ)) then + Decl := First (Declarations (Templ)); + end if; + + -- Generic subprogram declaration + + elsif Nkind (Templ) = N_Generic_Subprogram_Declaration then + if Nkind (Specification (Templ)) = N_Function_Specification then + Set_Ekind (Templ_Id, E_Generic_Function); + else + Set_Ekind (Templ_Id, E_Generic_Procedure); + end if; + + -- When the generic subprogram acts as a compilation unit, inspect + -- the Pragmas_After list for contract-related source pragmas. + + if Nkind (Context) = N_Compilation_Unit then + if Present (Aux_Decls_Node (Context)) + and then Present (Pragmas_After (Aux_Decls_Node (Context))) + then + Decl := First (Pragmas_After (Aux_Decls_Node (Context))); + end if; + + -- Otherwise inspect the successive declarations for contract-related + -- source pragmas. + + else + Decl := Next (Unit); + end if; + + -- A generic subprogram body carries contract-related source pragmas in + -- its declarations. + + elsif Nkind (Templ) = N_Subprogram_Body then + Set_Ekind (Templ_Id, E_Subprogram_Body); + + if Present (Declarations (Templ)) then + Decl := First (Declarations (Templ)); + end if; + end if; + + -- Inspect the relevant declarations looking for contract-related source + -- pragmas and add them to the contract of the generic unit. + + while Present (Decl) loop + if Comes_From_Source (Decl) then + if Nkind (Decl) = N_Pragma then + + -- The source pragma is a contract annotation + + if Is_Contract_Annotation (Decl) then + Add_Generic_Contract_Pragma (Decl); + end if; + + -- The region where a contract-related source pragma may appear + -- ends with the first source non-pragma declaration or statement. + + else + exit; + end if; + end if; + + Next (Decl); + end loop; + end Create_Generic_Contract; + + -------------------------------- + -- Expand_Subprogram_Contract -- + -------------------------------- + + procedure Expand_Subprogram_Contract (Body_Id : Entity_Id) is + Body_Decl : constant Node_Id := Unit_Declaration_Node (Body_Id); + Spec_Id : constant Entity_Id := Corresponding_Spec (Body_Decl); + + procedure Add_Invariant_And_Predicate_Checks + (Subp_Id : Entity_Id; + Stmts : in out List_Id; + Result : out Node_Id); + -- Process the result of function Subp_Id (if applicable) and all its + -- formals. Add invariant and predicate checks where applicable. The + -- routine appends all the checks to list Stmts. If Subp_Id denotes a + -- function, Result contains the entity of parameter _Result, to be + -- used in the creation of procedure _Postconditions. + + procedure Append_Enabled_Item (Item : Node_Id; List : in out List_Id); + -- Append a node to a list. If there is no list, create a new one. When + -- the item denotes a pragma, it is added to the list only when it is + -- enabled. + + procedure Build_Postconditions_Procedure + (Subp_Id : Entity_Id; + Stmts : List_Id; + Result : Entity_Id); + -- Create the body of procedure _Postconditions which handles various + -- assertion actions on exit from subprogram Subp_Id. Stmts is the list + -- of statements to be checked on exit. Parameter Result is the entity + -- of parameter _Result when Subp_Id denotes a function. + + function Build_Pragma_Check_Equivalent + (Prag : Node_Id; + Subp_Id : Entity_Id := Empty; + Inher_Id : Entity_Id := Empty) return Node_Id; + -- Transform a [refined] pre- or postcondition denoted by Prag into an + -- equivalent pragma Check. When the pre- or postcondition is inherited, + -- the routine corrects the references of all formals of Inher_Id to + -- point to the formals of Subp_Id. + + procedure Process_Contract_Cases (Stmts : in out List_Id); + -- Process pragma Contract_Cases. This routine prepends items to the + -- body declarations and appends items to list Stmts. + + procedure Process_Postconditions (Stmts : in out List_Id); + -- Collect all [inherited] spec and body postconditions and accumulate + -- their pragma Check equivalents in list Stmts. + + procedure Process_Preconditions; + -- Collect all [inherited] spec and body preconditions and prepend their + -- pragma Check equivalents to the declarations of the body. + + ---------------------------------------- + -- Add_Invariant_And_Predicate_Checks -- + ---------------------------------------- + + procedure Add_Invariant_And_Predicate_Checks + (Subp_Id : Entity_Id; + Stmts : in out List_Id; + Result : out Node_Id) + is + procedure Add_Invariant_Access_Checks (Id : Entity_Id); + -- Id denotes the return value of a function or a formal parameter. + -- Add an invariant check if the type of Id is access to a type with + -- invariants. The routine appends the generated code to Stmts. + + function Invariant_Checks_OK (Typ : Entity_Id) return Boolean; + -- Determine whether type Typ can benefit from invariant checks. To + -- qualify, the type must have a non-null invariant procedure and + -- subprogram Subp_Id must appear visible from the point of view of + -- the type. + + --------------------------------- + -- Add_Invariant_Access_Checks -- + --------------------------------- + + procedure Add_Invariant_Access_Checks (Id : Entity_Id) is + Loc : constant Source_Ptr := Sloc (Body_Decl); + Ref : Node_Id; + Typ : Entity_Id; + + begin + Typ := Etype (Id); + + if Is_Access_Type (Typ) and then not Is_Access_Constant (Typ) then + Typ := Designated_Type (Typ); + + if Invariant_Checks_OK (Typ) then + Ref := + Make_Explicit_Dereference (Loc, + Prefix => New_Occurrence_Of (Id, Loc)); + Set_Etype (Ref, Typ); + + -- Generate: + -- if /= null then + -- )> + -- end if; + + Append_Enabled_Item + (Item => + Make_If_Statement (Loc, + Condition => + Make_Op_Ne (Loc, + Left_Opnd => New_Occurrence_Of (Id, Loc), + Right_Opnd => Make_Null (Loc)), + Then_Statements => New_List ( + Make_Invariant_Call (Ref))), + List => Stmts); + end if; + end if; + end Add_Invariant_Access_Checks; + + ------------------------- + -- Invariant_Checks_OK -- + ------------------------- + + function Invariant_Checks_OK (Typ : Entity_Id) return Boolean is + function Has_Null_Body (Proc_Id : Entity_Id) return Boolean; + -- Determine whether the body of procedure Proc_Id contains a sole + -- null statement, possibly followed by an optional return. + + function Has_Public_Visibility_Of_Subprogram return Boolean; + -- Determine whether type Typ has public visibility of subprogram + -- Subp_Id. + + ------------------- + -- Has_Null_Body -- + ------------------- + + function Has_Null_Body (Proc_Id : Entity_Id) return Boolean is + Body_Id : Entity_Id; + Decl : Node_Id; + Spec : Node_Id; + Stmt1 : Node_Id; + Stmt2 : Node_Id; + + begin + Spec := Parent (Proc_Id); + Decl := Parent (Spec); + + -- Retrieve the entity of the invariant procedure body + + if Nkind (Spec) = N_Procedure_Specification + and then Nkind (Decl) = N_Subprogram_Declaration + then + Body_Id := Corresponding_Body (Decl); + + -- The body acts as a spec + + else + Body_Id := Proc_Id; + end if; + + -- The body will be generated later + + if No (Body_Id) then + return False; + end if; + + Spec := Parent (Body_Id); + Decl := Parent (Spec); + + pragma Assert + (Nkind (Spec) = N_Procedure_Specification + and then Nkind (Decl) = N_Subprogram_Body); + + Stmt1 := First (Statements (Handled_Statement_Sequence (Decl))); + + -- Look for a null statement followed by an optional return + -- statement. + + if Nkind (Stmt1) = N_Null_Statement then + Stmt2 := Next (Stmt1); + + if Present (Stmt2) then + return Nkind (Stmt2) = N_Simple_Return_Statement; + else + return True; + end if; + end if; + + return False; + end Has_Null_Body; + + ----------------------------------------- + -- Has_Public_Visibility_Of_Subprogram -- + ----------------------------------------- + + function Has_Public_Visibility_Of_Subprogram return Boolean is + Subp_Decl : constant Node_Id := Unit_Declaration_Node (Subp_Id); + + begin + -- An Initialization procedure must be considered visible even + -- though it is internally generated. + + if Is_Init_Proc (Defining_Entity (Subp_Decl)) then + return True; + + elsif Ekind (Scope (Typ)) /= E_Package then + return False; + + -- Internally generated code is never publicly visible except + -- for a subprogram that is the implementation of an expression + -- function. In that case the visibility is determined by the + -- last check. + + elsif not Comes_From_Source (Subp_Decl) + and then + (Nkind (Original_Node (Subp_Decl)) /= N_Expression_Function + or else not + Comes_From_Source (Defining_Entity (Subp_Decl))) + then + return False; + + -- Determine whether the subprogram is declared in the visible + -- declarations of the package containing the type. + + else + return List_Containing (Subp_Decl) = + Visible_Declarations + (Specification (Unit_Declaration_Node (Scope (Typ)))); + end if; + end Has_Public_Visibility_Of_Subprogram; + + -- Start of processing for Invariant_Checks_OK + + begin + return + Has_Invariants (Typ) + and then Present (Invariant_Procedure (Typ)) + and then not Has_Null_Body (Invariant_Procedure (Typ)) + and then Has_Public_Visibility_Of_Subprogram; + end Invariant_Checks_OK; + + -- Local variables + + Loc : constant Source_Ptr := Sloc (Body_Decl); + -- Source location of subprogram body contract + + Formal : Entity_Id; + Typ : Entity_Id; + + -- Start of processing for Add_Invariant_And_Predicate_Checks + + begin + Result := Empty; + + -- Process the result of a function + + if Ekind (Subp_Id) = E_Function then + Typ := Etype (Subp_Id); + + -- Generate _Result which is used in procedure _Postconditions to + -- verify the return value. + + Result := Make_Defining_Identifier (Loc, Name_uResult); + Set_Etype (Result, Typ); + + -- Add an invariant check when the return type has invariants and + -- the related function is visible to the outside. + + if Invariant_Checks_OK (Typ) then + Append_Enabled_Item + (Item => + Make_Invariant_Call (New_Occurrence_Of (Result, Loc)), + List => Stmts); + end if; + + -- Add an invariant check when the return type is an access to a + -- type with invariants. + + Add_Invariant_Access_Checks (Result); + end if; + + -- Add invariant and predicates for all formals that qualify + + Formal := First_Formal (Subp_Id); + while Present (Formal) loop + Typ := Etype (Formal); + + if Ekind (Formal) /= E_In_Parameter + or else Is_Access_Type (Typ) + then + if Invariant_Checks_OK (Typ) then + Append_Enabled_Item + (Item => + Make_Invariant_Call (New_Occurrence_Of (Formal, Loc)), + List => Stmts); + end if; + + Add_Invariant_Access_Checks (Formal); + + -- Note: we used to add predicate checks for OUT and IN OUT + -- formals here, but that was misguided, since such checks are + -- performed on the caller side, based on the predicate of the + -- actual, rather than the predicate of the formal. + + end if; + + Next_Formal (Formal); + end loop; + end Add_Invariant_And_Predicate_Checks; + + ------------------------- + -- Append_Enabled_Item -- + ------------------------- + + procedure Append_Enabled_Item (Item : Node_Id; List : in out List_Id) is + begin + -- Do not chain ignored or disabled pragmas + + if Nkind (Item) = N_Pragma + and then (Is_Ignored (Item) or else Is_Disabled (Item)) + then + null; + + -- Otherwise, add the item + + else + if No (List) then + List := New_List; + end if; + + -- If the pragma is a conjunct in a composite postcondition, it + -- has been processed in reverse order. In the postcondition body + -- if must appear before the others. + + if Nkind (Item) = N_Pragma + and then From_Aspect_Specification (Item) + and then Split_PPC (Item) + then + Prepend (Item, List); + else + Append (Item, List); + end if; + end if; + end Append_Enabled_Item; + + ------------------------------------ + -- Build_Postconditions_Procedure -- + ------------------------------------ + + procedure Build_Postconditions_Procedure + (Subp_Id : Entity_Id; + Stmts : List_Id; + Result : Entity_Id) + is + procedure Insert_Before_First_Source_Declaration (Stmt : Node_Id); + -- Insert node Stmt before the first source declaration of the + -- related subprogram's body. If no such declaration exists, Stmt + -- becomes the last declaration. + + -------------------------------------------- + -- Insert_Before_First_Source_Declaration -- + -------------------------------------------- + + procedure Insert_Before_First_Source_Declaration (Stmt : Node_Id) is + Decls : constant List_Id := Declarations (Body_Decl); + Decl : Node_Id; + + begin + -- Inspect the declarations of the related subprogram body looking + -- for the first source declaration. + + if Present (Decls) then + Decl := First (Decls); + while Present (Decl) loop + if Comes_From_Source (Decl) then + Insert_Before (Decl, Stmt); + return; + end if; + + Next (Decl); + end loop; + + -- If we get there, then the subprogram body lacks any source + -- declarations. The body of _Postconditions now acts as the + -- last declaration. + + Append (Stmt, Decls); + + -- Ensure that the body has a declaration list + + else + Set_Declarations (Body_Decl, New_List (Stmt)); + end if; + end Insert_Before_First_Source_Declaration; + + -- Local variables + + Loc : constant Source_Ptr := Sloc (Body_Decl); + Params : List_Id := No_List; + Proc_Bod : Node_Id; + Proc_Id : Entity_Id; + + -- Start of processing for Build_Postconditions_Procedure + + begin + -- Nothing to do if there are no actions to check on exit + + if No (Stmts) then + return; + end if; + + Proc_Id := Make_Defining_Identifier (Loc, Name_uPostconditions); + Set_Debug_Info_Needed (Proc_Id); + Set_Postconditions_Proc (Subp_Id, Proc_Id); + + -- The related subprogram is a function, create the specification of + -- parameter _Result. + + if Present (Result) then + Params := New_List ( + Make_Parameter_Specification (Loc, + Defining_Identifier => Result, + Parameter_Type => + New_Occurrence_Of (Etype (Result), Loc))); + end if; + + -- Insert _Postconditions before the first source declaration of the + -- body. This ensures that the body will not cause any premature + -- freezing as it may mention types: + + -- procedure Proc (Obj : Array_Typ) is + -- procedure _postconditions is + -- begin + -- ... Obj ... + -- end _postconditions; + + -- subtype T is Array_Typ (Obj'First (1) .. Obj'Last (1)); + -- begin + + -- In the example above, Obj is of type T but the incorrect placement + -- of _Postconditions will cause a crash in gigi due to an out of + -- order reference. The body of _Postconditions must be placed after + -- the declaration of Temp to preserve correct visibility. + + -- Set an explicit End_Lavel to override the sloc of the implicit + -- RETURN statement, and prevent it from inheriting the sloc of one + -- the postconditions: this would cause confusing debug into to be + -- produced, interfering with coverage analysis tools. + + Proc_Bod := + Make_Subprogram_Body (Loc, + Specification => + Make_Procedure_Specification (Loc, + Defining_Unit_Name => Proc_Id, + Parameter_Specifications => Params), + + Declarations => Empty_List, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => Stmts, + End_Label => Make_Identifier (Loc, Chars (Proc_Id)))); + + Insert_Before_First_Source_Declaration (Proc_Bod); + Analyze (Proc_Bod); + end Build_Postconditions_Procedure; + + ----------------------------------- + -- Build_Pragma_Check_Equivalent -- + ----------------------------------- + + function Build_Pragma_Check_Equivalent + (Prag : Node_Id; + Subp_Id : Entity_Id := Empty; + Inher_Id : Entity_Id := Empty) return Node_Id + is + function Suppress_Reference (N : Node_Id) return Traverse_Result; + -- Detect whether node N references a formal parameter subject to + -- pragma Unreferenced. If this is the case, set Comes_From_Source + -- to False to suppress the generation of a reference when analyzing + -- N later on. + + ------------------------ + -- Suppress_Reference -- + ------------------------ + + function Suppress_Reference (N : Node_Id) return Traverse_Result is + Formal : Entity_Id; + + begin + if Is_Entity_Name (N) and then Present (Entity (N)) then + Formal := Entity (N); + + -- The formal parameter is subject to pragma Unreferenced. + -- Prevent the generation of a reference by resetting the + -- Comes_From_Source flag. + + if Is_Formal (Formal) + and then Has_Pragma_Unreferenced (Formal) + then + Set_Comes_From_Source (N, False); + end if; + end if; + + return OK; + end Suppress_Reference; + + procedure Suppress_References is + new Traverse_Proc (Suppress_Reference); + + -- Local variables + + Loc : constant Source_Ptr := Sloc (Prag); + Prag_Nam : constant Name_Id := Pragma_Name (Prag); + Check_Prag : Node_Id; + Formals_Map : Elist_Id; + Inher_Formal : Entity_Id; + Msg_Arg : Node_Id; + Nam : Name_Id; + Subp_Formal : Entity_Id; + + -- Start of processing for Build_Pragma_Check_Equivalent + + begin + Formals_Map := No_Elist; + + -- When the pre- or postcondition is inherited, map the formals of + -- the inherited subprogram to those of the current subprogram. + + if Present (Inher_Id) then + pragma Assert (Present (Subp_Id)); + + Formals_Map := New_Elmt_List; + + -- Create a relation => + + Inher_Formal := First_Formal (Inher_Id); + Subp_Formal := First_Formal (Subp_Id); + while Present (Inher_Formal) and then Present (Subp_Formal) loop + Append_Elmt (Inher_Formal, Formals_Map); + Append_Elmt (Subp_Formal, Formals_Map); + + Next_Formal (Inher_Formal); + Next_Formal (Subp_Formal); + end loop; + end if; + + -- Copy the original pragma while performing substitutions (if + -- applicable). + + Check_Prag := + New_Copy_Tree + (Source => Prag, + Map => Formals_Map, + New_Scope => Current_Scope); + + -- Mark the pragma as being internally generated and reset the + -- Analyzed flag. + + Set_Analyzed (Check_Prag, False); + Set_Comes_From_Source (Check_Prag, False); + + -- The tree of the original pragma may contain references to the + -- formal parameters of the related subprogram. At the same time + -- the corresponding body may mark the formals as unreferenced: + + -- procedure Proc (Formal : ...) + -- with Pre => Formal ...; + + -- procedure Proc (Formal : ...) is + -- pragma Unreferenced (Formal); + -- ... + + -- This creates problems because all pragma Check equivalents are + -- analyzed at the end of the body declarations. Since all source + -- references have already been accounted for, reset any references + -- to such formals in the generated pragma Check equivalent. + + Suppress_References (Check_Prag); + + if Present (Corresponding_Aspect (Prag)) then + Nam := Chars (Identifier (Corresponding_Aspect (Prag))); + else + Nam := Prag_Nam; + end if; + + -- Convert the copy into pragma Check by correcting the name and + -- adding a check_kind argument. + + Set_Pragma_Identifier + (Check_Prag, Make_Identifier (Loc, Name_Check)); + + Prepend_To (Pragma_Argument_Associations (Check_Prag), + Make_Pragma_Argument_Association (Loc, + Expression => Make_Identifier (Loc, Nam))); + + -- Update the error message when the pragma is inherited + + if Present (Inher_Id) then + Msg_Arg := Last (Pragma_Argument_Associations (Check_Prag)); + + if Chars (Msg_Arg) = Name_Message then + String_To_Name_Buffer (Strval (Expression (Msg_Arg))); + + -- Insert "inherited" to improve the error message + + if Name_Buffer (1 .. 8) = "failed p" then + Insert_Str_In_Name_Buffer ("inherited ", 8); + Set_Strval (Expression (Msg_Arg), String_From_Name_Buffer); + end if; + end if; + end if; + + return Check_Prag; + end Build_Pragma_Check_Equivalent; + + ---------------------------- + -- Process_Contract_Cases -- + ---------------------------- + + procedure Process_Contract_Cases (Stmts : in out List_Id) is + procedure Process_Contract_Cases_For (Subp_Id : Entity_Id); + -- Process pragma Contract_Cases for subprogram Subp_Id + + -------------------------------- + -- Process_Contract_Cases_For -- + -------------------------------- + + procedure Process_Contract_Cases_For (Subp_Id : Entity_Id) is + Items : constant Node_Id := Contract (Subp_Id); + Prag : Node_Id; + + begin + if Present (Items) then + Prag := Contract_Test_Cases (Items); + while Present (Prag) loop + if Pragma_Name (Prag) = Name_Contract_Cases then + Expand_Pragma_Contract_Cases + (CCs => Prag, + Subp_Id => Subp_Id, + Decls => Declarations (Body_Decl), + Stmts => Stmts); + end if; + + Prag := Next_Pragma (Prag); + end loop; + end if; + end Process_Contract_Cases_For; + + -- Start of processing for Process_Contract_Cases + + begin + Process_Contract_Cases_For (Body_Id); + + if Present (Spec_Id) then + Process_Contract_Cases_For (Spec_Id); + end if; + end Process_Contract_Cases; + + ---------------------------- + -- Process_Postconditions -- + ---------------------------- + + procedure Process_Postconditions (Stmts : in out List_Id) is + procedure Process_Body_Postconditions (Post_Nam : Name_Id); + -- Collect all [refined] postconditions of a specific kind denoted + -- by Post_Nam that belong to the body and generate pragma Check + -- equivalents in list Stmts. + + procedure Process_Spec_Postconditions; + -- Collect all [inherited] postconditions of the spec and generate + -- pragma Check equivalents in list Stmts. + + --------------------------------- + -- Process_Body_Postconditions -- + --------------------------------- + + procedure Process_Body_Postconditions (Post_Nam : Name_Id) is + Items : constant Node_Id := Contract (Body_Id); + Unit_Decl : constant Node_Id := Parent (Body_Decl); + Decl : Node_Id; + Prag : Node_Id; + + begin + -- Process the contract + + if Present (Items) then + Prag := Pre_Post_Conditions (Items); + while Present (Prag) loop + if Pragma_Name (Prag) = Post_Nam then + Append_Enabled_Item + (Item => Build_Pragma_Check_Equivalent (Prag), + List => Stmts); + end if; + + Prag := Next_Pragma (Prag); + end loop; + end if; + + -- The subprogram body being processed is actually the proper body + -- of a stub with a corresponding spec. The subprogram stub may + -- carry a postcondition pragma in which case it must be taken + -- into account. The pragma appears after the stub. + + if Present (Spec_Id) and then Nkind (Unit_Decl) = N_Subunit then + Decl := Next (Corresponding_Stub (Unit_Decl)); + while Present (Decl) loop + + -- Note that non-matching pragmas are skipped + + if Nkind (Decl) = N_Pragma then + if Pragma_Name (Decl) = Post_Nam then + Append_Enabled_Item + (Item => Build_Pragma_Check_Equivalent (Decl), + List => Stmts); + end if; + + -- Skip internally generated code + + elsif not Comes_From_Source (Decl) then + null; + + -- Postcondition pragmas are usually grouped together. There + -- is no need to inspect the whole declarative list. + + else + exit; + end if; + + Next (Decl); + end loop; + end if; + end Process_Body_Postconditions; + + --------------------------------- + -- Process_Spec_Postconditions -- + --------------------------------- + + procedure Process_Spec_Postconditions is + Subps : constant Subprogram_List := + Inherited_Subprograms (Spec_Id); + Items : Node_Id; + Prag : Node_Id; + Subp_Id : Entity_Id; + + begin + -- Process the contract + + Items := Contract (Spec_Id); + + if Present (Items) then + Prag := Pre_Post_Conditions (Items); + while Present (Prag) loop + if Pragma_Name (Prag) = Name_Postcondition then + Append_Enabled_Item + (Item => Build_Pragma_Check_Equivalent (Prag), + List => Stmts); + end if; + + Prag := Next_Pragma (Prag); + end loop; + end if; + + -- Process the contracts of all inherited subprograms, looking for + -- class-wide postconditions. + + for Index in Subps'Range loop + Subp_Id := Subps (Index); + Items := Contract (Subp_Id); + + if Present (Items) then + Prag := Pre_Post_Conditions (Items); + while Present (Prag) loop + if Pragma_Name (Prag) = Name_Postcondition + and then Class_Present (Prag) + then + Append_Enabled_Item + (Item => + Build_Pragma_Check_Equivalent + (Prag => Prag, + Subp_Id => Spec_Id, + Inher_Id => Subp_Id), + List => Stmts); + end if; + + Prag := Next_Pragma (Prag); + end loop; + end if; + end loop; + end Process_Spec_Postconditions; + + -- Start of processing for Process_Postconditions + + begin + -- The processing of postconditions is done in reverse order (body + -- first) to ensure the following arrangement: + + -- + -- + -- + -- + + Process_Body_Postconditions (Name_Refined_Post); + Process_Body_Postconditions (Name_Postcondition); + + if Present (Spec_Id) then + Process_Spec_Postconditions; + end if; + end Process_Postconditions; + + --------------------------- + -- Process_Preconditions -- + --------------------------- + + procedure Process_Preconditions is + Class_Pre : Node_Id := Empty; + -- The sole [inherited] class-wide precondition pragma that applies + -- to the subprogram. + + Insert_Node : Node_Id := Empty; + -- The insertion node after which all pragma Check equivalents are + -- inserted. + + procedure Merge_Preconditions (From : Node_Id; Into : Node_Id); + -- Merge two class-wide preconditions by "or else"-ing them. The + -- changes are accumulated in parameter Into. Update the error + -- message of Into. + + procedure Prepend_To_Decls (Item : Node_Id); + -- Prepend a single item to the declarations of the subprogram body + + procedure Prepend_To_Decls_Or_Save (Prag : Node_Id); + -- Save a class-wide precondition into Class_Pre or prepend a normal + -- precondition ot the declarations of the body and analyze it. + + procedure Process_Inherited_Preconditions; + -- Collect all inherited class-wide preconditions and merge them into + -- one big precondition to be evaluated as pragma Check. + + procedure Process_Preconditions_For (Subp_Id : Entity_Id); + -- Collect all preconditions of subprogram Subp_Id and prepend their + -- pragma Check equivalents to the declarations of the body. + + ------------------------- + -- Merge_Preconditions -- + ------------------------- + + procedure Merge_Preconditions (From : Node_Id; Into : Node_Id) is + function Expression_Arg (Prag : Node_Id) return Node_Id; + -- Return the boolean expression argument of a precondition while + -- updating its parenteses count for the subsequent merge. + + function Message_Arg (Prag : Node_Id) return Node_Id; + -- Return the message argument of a precondition + + -------------------- + -- Expression_Arg -- + -------------------- + + function Expression_Arg (Prag : Node_Id) return Node_Id is + Args : constant List_Id := Pragma_Argument_Associations (Prag); + Arg : constant Node_Id := Get_Pragma_Arg (Next (First (Args))); + + begin + if Paren_Count (Arg) = 0 then + Set_Paren_Count (Arg, 1); + end if; + + return Arg; + end Expression_Arg; + + ----------------- + -- Message_Arg -- + ----------------- + + function Message_Arg (Prag : Node_Id) return Node_Id is + Args : constant List_Id := Pragma_Argument_Associations (Prag); + begin + return Get_Pragma_Arg (Last (Args)); + end Message_Arg; + + -- Local variables + + From_Expr : constant Node_Id := Expression_Arg (From); + From_Msg : constant Node_Id := Message_Arg (From); + Into_Expr : constant Node_Id := Expression_Arg (Into); + Into_Msg : constant Node_Id := Message_Arg (Into); + Loc : constant Source_Ptr := Sloc (Into); + + -- Start of processing for Merge_Preconditions + + begin + -- Merge the two preconditions by "or else"-ing them + + Rewrite (Into_Expr, + Make_Or_Else (Loc, + Right_Opnd => Relocate_Node (Into_Expr), + Left_Opnd => From_Expr)); + + -- Merge the two error messages to produce a single message of the + -- form: + + -- failed precondition from ... + -- also failed inherited precondition from ... + + if not Exception_Locations_Suppressed then + Start_String (Strval (Into_Msg)); + Store_String_Char (ASCII.LF); + Store_String_Chars (" also "); + Store_String_Chars (Strval (From_Msg)); + + Set_Strval (Into_Msg, End_String); + end if; + end Merge_Preconditions; + + ---------------------- + -- Prepend_To_Decls -- + ---------------------- + + procedure Prepend_To_Decls (Item : Node_Id) is + Decls : List_Id := Declarations (Body_Decl); + + begin + -- Ensure that the body has a declarative list + + if No (Decls) then + Decls := New_List; + Set_Declarations (Body_Decl, Decls); + end if; + + Prepend_To (Decls, Item); + end Prepend_To_Decls; + + ------------------------------ + -- Prepend_To_Decls_Or_Save -- + ------------------------------ + + procedure Prepend_To_Decls_Or_Save (Prag : Node_Id) is + Check_Prag : Node_Id; + + begin + Check_Prag := Build_Pragma_Check_Equivalent (Prag); + + -- Save the sole class-wide precondition (if any) for the next + -- step where it will be merged with inherited preconditions. + + if Class_Present (Prag) then + pragma Assert (No (Class_Pre)); + Class_Pre := Check_Prag; + + -- Accumulate the corresponding Check pragmas at the top of the + -- declarations. Prepending the items ensures that they will be + -- evaluated in their original order. + + else + if Present (Insert_Node) then + Insert_After (Insert_Node, Check_Prag); + else + Prepend_To_Decls (Check_Prag); + end if; + + Analyze (Check_Prag); + end if; + end Prepend_To_Decls_Or_Save; + + ------------------------------------- + -- Process_Inherited_Preconditions -- + ------------------------------------- + + procedure Process_Inherited_Preconditions is + Subps : constant Subprogram_List := + Inherited_Subprograms (Spec_Id); + Check_Prag : Node_Id; + Items : Node_Id; + Prag : Node_Id; + Subp_Id : Entity_Id; + + begin + -- Process the contracts of all inherited subprograms, looking for + -- class-wide preconditions. + + for Index in Subps'Range loop + Subp_Id := Subps (Index); + Items := Contract (Subp_Id); + + if Present (Items) then + Prag := Pre_Post_Conditions (Items); + while Present (Prag) loop + if Pragma_Name (Prag) = Name_Precondition + and then Class_Present (Prag) + then + Check_Prag := + Build_Pragma_Check_Equivalent + (Prag => Prag, + Subp_Id => Spec_Id, + Inher_Id => Subp_Id); + + -- The spec or an inherited subprogram already yielded + -- a class-wide precondition. Merge the existing + -- precondition with the current one using "or else". + + if Present (Class_Pre) then + Merge_Preconditions (Check_Prag, Class_Pre); + else + Class_Pre := Check_Prag; + end if; + end if; + + Prag := Next_Pragma (Prag); + end loop; + end if; + end loop; + + -- Add the merged class-wide preconditions + + if Present (Class_Pre) then + Prepend_To_Decls (Class_Pre); + Analyze (Class_Pre); + end if; + end Process_Inherited_Preconditions; + + ------------------------------- + -- Process_Preconditions_For -- + ------------------------------- + + procedure Process_Preconditions_For (Subp_Id : Entity_Id) is + Items : constant Node_Id := Contract (Subp_Id); + Decl : Node_Id; + Prag : Node_Id; + Subp_Decl : Node_Id; + + begin + -- Process the contract + + if Present (Items) then + Prag := Pre_Post_Conditions (Items); + while Present (Prag) loop + if Pragma_Name (Prag) = Name_Precondition then + Prepend_To_Decls_Or_Save (Prag); + end if; + + Prag := Next_Pragma (Prag); + end loop; + end if; + + -- The subprogram declaration being processed is actually a body + -- stub. The stub may carry a precondition pragma in which case it + -- must be taken into account. The pragma appears after the stub. + + Subp_Decl := Unit_Declaration_Node (Subp_Id); + + if Nkind (Subp_Decl) = N_Subprogram_Body_Stub then + + -- Inspect the declarations following the body stub + + Decl := Next (Subp_Decl); + while Present (Decl) loop + + -- Note that non-matching pragmas are skipped + + if Nkind (Decl) = N_Pragma then + if Pragma_Name (Decl) = Name_Precondition then + Prepend_To_Decls_Or_Save (Decl); + end if; + + -- Skip internally generated code + + elsif not Comes_From_Source (Decl) then + null; + + -- Preconditions are usually grouped together. There is no + -- need to inspect the whole declarative list. + + else + exit; + end if; + + Next (Decl); + end loop; + end if; + end Process_Preconditions_For; + + -- Local variables + + Decls : constant List_Id := Declarations (Body_Decl); + Decl : Node_Id; + + -- Start of processing for Process_Preconditions + + begin + -- Find the last internally generate declaration starting from the + -- top of the body declarations. This ensures that discriminals and + -- subtypes are properly visible to the pragma Check equivalents. + + if Present (Decls) then + Decl := First (Decls); + while Present (Decl) loop + exit when Comes_From_Source (Decl); + Insert_Node := Decl; + Next (Decl); + end loop; + end if; + + -- The processing of preconditions is done in reverse order (body + -- first) because each pragma Check equivalent is inserted at the + -- top of the declarations. This ensures that the final order is + -- consistent with following diagram: + + -- + -- + -- + + Process_Preconditions_For (Body_Id); + + if Present (Spec_Id) then + Process_Preconditions_For (Spec_Id); + Process_Inherited_Preconditions; + end if; + end Process_Preconditions; + + -- Local variables + + Restore_Scope : Boolean := False; + Result : Entity_Id; + Stmts : List_Id := No_List; + Subp_Id : Entity_Id; + + -- Start of processing for Expand_Subprogram_Contract + + begin + -- Obtain the entity of the initial declaration + + if Present (Spec_Id) then + Subp_Id := Spec_Id; + else + Subp_Id := Body_Id; + end if; + + -- Do not perform expansion activity when it is not needed + + if not Expander_Active then + return; + + -- ASIS requires an unaltered tree + + elsif ASIS_Mode then + return; + + -- GNATprove does not need the executable semantics of a contract + + elsif GNATprove_Mode then + return; + + -- The contract of a generic subprogram or one declared in a generic + -- context is not expanded as the corresponding instance will provide + -- the executable semantics of the contract. + + elsif Is_Generic_Subprogram (Subp_Id) or else Inside_A_Generic then + return; + + -- All subprograms carry a contract, but for some it is not significant + -- and should not be processed. This is a small optimization. + + elsif not Has_Significant_Contract (Subp_Id) then + return; + + -- The contract of an ignored Ghost subprogram does not need expansion + -- because the subprogram and all calls to it will be removed. + + elsif Is_Ignored_Ghost_Entity (Subp_Id) then + return; + end if; + + -- Do not re-expand the same contract. This scenario occurs when a + -- construct is rewritten into something else during its analysis + -- (expression functions for instance). + + if Has_Expanded_Contract (Subp_Id) then + return; + + -- Otherwise mark the subprogram + + else + Set_Has_Expanded_Contract (Subp_Id); + end if; + + -- Ensure that the formal parameters are visible when expanding all + -- contract items. + + if not In_Open_Scopes (Subp_Id) then + Restore_Scope := True; + Push_Scope (Subp_Id); + + if Is_Generic_Subprogram (Subp_Id) then + Install_Generic_Formals (Subp_Id); + else + Install_Formals (Subp_Id); + end if; + end if; + + -- The expansion of a subprogram contract involves the creation of Check + -- pragmas to verify the contract assertions of the spec and body in a + -- particular order. The order is as follows: + + -- function Example (...) return ... is + -- procedure _Postconditions (...) is + -- begin + -- + -- + -- + -- + -- + -- + -- + -- end _Postconditions; + + -- + -- + -- + -- + + -- + -- begin + -- + + -- _Preconditions (Result); + -- return Result; + -- end Example; + + -- Routine _Postconditions holds all contract assertions that must be + -- verified on exit from the related subprogram. + + -- Step 1: Handle all preconditions. This action must come before the + -- processing of pragma Contract_Cases because the pragma prepends items + -- to the body declarations. + + Process_Preconditions; + + -- Step 2: Handle all postconditions. This action must come before the + -- processing of pragma Contract_Cases because the pragma appends items + -- to list Stmts. + + Process_Postconditions (Stmts); + + -- Step 3: Handle pragma Contract_Cases. This action must come before + -- the processing of invariants and predicates because those append + -- items to list Smts. + + Process_Contract_Cases (Stmts); + + -- Step 4: Apply invariant and predicate checks on a function result and + -- all formals. The resulting checks are accumulated in list Stmts. + + Add_Invariant_And_Predicate_Checks (Subp_Id, Stmts, Result); + + -- Step 5: Construct procedure _Postconditions + + Build_Postconditions_Procedure (Subp_Id, Stmts, Result); + + if Restore_Scope then + End_Scope; + end if; + end Expand_Subprogram_Contract; + + --------------------------------- + -- Inherit_Subprogram_Contract -- + --------------------------------- + + procedure Inherit_Subprogram_Contract + (Subp : Entity_Id; + From_Subp : Entity_Id) + is + procedure Inherit_Pragma (Prag_Id : Pragma_Id); + -- Propagate a pragma denoted by Prag_Id from From_Subp's contract to + -- Subp's contract. + + -------------------- + -- Inherit_Pragma -- + -------------------- + + procedure Inherit_Pragma (Prag_Id : Pragma_Id) is + Prag : constant Node_Id := Get_Pragma (From_Subp, Prag_Id); + New_Prag : Node_Id; + + begin + -- A pragma cannot be part of more than one First_Pragma/Next_Pragma + -- chains, therefore the node must be replicated. The new pragma is + -- flagged is inherited for distrinction purposes. + + if Present (Prag) then + New_Prag := New_Copy_Tree (Prag); + Set_Is_Inherited (New_Prag); + + Add_Contract_Item (New_Prag, Subp); + end if; + end Inherit_Pragma; + + -- Start of processing for Inherit_Subprogram_Contract + + begin + -- Inheritance is carried out only when both entities are subprograms + -- with contracts. + + if Is_Subprogram_Or_Generic_Subprogram (Subp) + and then Is_Subprogram_Or_Generic_Subprogram (From_Subp) + and then Present (Contract (From_Subp)) + then + Inherit_Pragma (Pragma_Extensions_Visible); + end if; + end Inherit_Subprogram_Contract; + + ------------------------------------- + -- Instantiate_Subprogram_Contract -- + ------------------------------------- + + procedure Instantiate_Subprogram_Contract (Templ : Node_Id; L : List_Id) is + procedure Instantiate_Pragmas (First_Prag : Node_Id); + -- Instantiate all contract-related source pragmas found in the list + -- starting with pragma First_Prag. Each instantiated pragma is added + -- to list L. + + ------------------------- + -- Instantiate_Pragmas -- + ------------------------- + + procedure Instantiate_Pragmas (First_Prag : Node_Id) is + Inst_Prag : Node_Id; + Prag : Node_Id; + + begin + Prag := First_Prag; + while Present (Prag) loop + if Is_Generic_Contract_Pragma (Prag) then + Inst_Prag := + Copy_Generic_Node (Prag, Empty, Instantiating => True); + + Set_Analyzed (Inst_Prag, False); + Append_To (L, Inst_Prag); + end if; + + Prag := Next_Pragma (Prag); + end loop; + end Instantiate_Pragmas; + + -- Local variables + + Items : constant Node_Id := Contract (Defining_Entity (Templ)); + + -- Start of processing for Instantiate_Subprogram_Contract + + begin + if Present (Items) then + Instantiate_Pragmas (Pre_Post_Conditions (Items)); + Instantiate_Pragmas (Contract_Test_Cases (Items)); + Instantiate_Pragmas (Classifications (Items)); + end if; + end Instantiate_Subprogram_Contract; + + ---------------------------------------- + -- Save_Global_References_In_Contract -- + ---------------------------------------- + + procedure Save_Global_References_In_Contract + (Templ : Node_Id; + Gen_Id : Entity_Id) + is + procedure Save_Global_References_In_List (First_Prag : Node_Id); + -- Save all global references in contract-related source pragmas found + -- in the list starting with pragma First_Prag. + + ------------------------------------ + -- Save_Global_References_In_List -- + ------------------------------------ + + procedure Save_Global_References_In_List (First_Prag : Node_Id) is + Prag : Node_Id; + + begin + Prag := First_Prag; + while Present (Prag) loop + if Is_Generic_Contract_Pragma (Prag) then + Save_Global_References (Prag); + end if; + + Prag := Next_Pragma (Prag); + end loop; + end Save_Global_References_In_List; + + -- Local variables + + Items : constant Node_Id := Contract (Defining_Entity (Templ)); + + -- Start of processing for Save_Global_References_In_Contract + + begin + -- The entity of the analyzed generic copy must be on the scope stack + -- to ensure proper detection of global references. + + Push_Scope (Gen_Id); + + if Permits_Aspect_Specifications (Templ) + and then Has_Aspects (Templ) + then + Save_Global_References_In_Aspects (Templ); + end if; + + if Present (Items) then + Save_Global_References_In_List (Pre_Post_Conditions (Items)); + Save_Global_References_In_List (Contract_Test_Cases (Items)); + Save_Global_References_In_List (Classifications (Items)); + end if; + + Pop_Scope; + end Save_Global_References_In_Contract; + +end Contracts; diff --git a/gcc/ada/contracts.ads b/gcc/ada/contracts.ads new file mode 100644 index 00000000000..beeed57a798 --- /dev/null +++ b/gcc/ada/contracts.ads @@ -0,0 +1,156 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- C O N T R A C T S -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 2015, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT 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 distributed with GNAT; see file COPYING3. If not, go to -- +-- http://www.gnu.org/licenses for a complete copy of the license. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- This package contains routines that perform analysis and expansion of +-- various contracts. + +with Types; use Types; + +package Contracts is + + procedure Add_Contract_Item (Prag : Node_Id; Id : Entity_Id); + -- Add pragma Prag to the contract of a constant, entry, package [body], + -- subprogram [body] or variable denoted by Id. The following are valid + -- pragmas: + -- Abstract_State + -- Async_Readers + -- Async_Writers + -- Constant_After_Elaboration + -- Contract_Cases + -- Depends + -- Effective_Reads + -- Effective_Writes + -- Extensions_Visible + -- Global + -- Initial_Condition + -- Initializes + -- Part_Of + -- Postcondition + -- Precondition + -- Refined_Depends + -- Refined_Global + -- Refined_Post + -- Refined_States + -- Test_Case + -- Volatile_Function + + procedure Analyze_Enclosing_Package_Body_Contract (Body_Decl : Node_Id); + -- Analyze the contract of the nearest package body (if any) which encloses + -- package or subprogram body Body_Decl. + + procedure Analyze_Object_Contract (Obj_Id : Entity_Id); + -- Analyze all delayed pragmas chained on the contract of object Obj_Id as + -- if they appeared at the end of the declarative region. The pragmas to be + -- considered are: + -- Async_Readers + -- Async_Writers + -- Effective_Reads + -- Effective_Writes + -- Part_Of + + procedure Analyze_Package_Body_Contract + (Body_Id : Entity_Id; + Freeze_Id : Entity_Id := Empty); + -- Analyze all delayed aspects chained on the contract of package body + -- Body_Id as if they appeared at the end of a declarative region. The + -- aspects that are considered are: + -- Refined_State + -- + -- Freeze_Id is the entity of a [generic] package body or a [generic] + -- subprogram body which "feezes" the contract of Body_Id. + + procedure Analyze_Package_Contract (Pack_Id : Entity_Id); + -- Analyze all delayed aspects chained on the contract of package Pack_Id + -- as if they appeared at the end of a declarative region. The aspects + -- that are considered are: + -- Initial_Condition + -- Initializes + -- Part_Of + + procedure Analyze_Subprogram_Body_Contract (Body_Id : Entity_Id); + -- Analyze all delayed aspects chained on the contract of subprogram body + -- Body_Id as if they appeared at the end of a declarative region. Aspects + -- in question are: + -- Contract_Cases (stand alone body) + -- Depends (stand alone body) + -- Global (stand alone body) + -- Postcondition (stand alone body) + -- Precondition (stand alone body) + -- Refined_Depends + -- Refined_Global + -- Refined_Post + -- Test_Case (stand alone body) + + procedure Analyze_Subprogram_Contract (Subp_Id : Entity_Id); + -- Analyze all delayed aspects chained on the contract of subprogram + -- Subp_Id as if they appeared at the end of a declarative region. The + -- aspects in question are: + -- Contract_Cases + -- Depends + -- Global + -- Postcondition + -- Precondition + -- Test_Case + + procedure Analyze_Subprogram_Body_Stub_Contract (Stub_Id : Entity_Id); + -- Analyze all delayed aspects chained on the contract of a subprogram body + -- stub Stub_Id as if they appeared at the end of a declarative region. The + -- aspects in question are: + -- Contract_Cases + -- Depends + -- Global + -- Postcondition + -- Precondition + -- Refined_Depends + -- Refined_Global + -- Refined_Post + -- Test_Case + + procedure Create_Generic_Contract (Unit : Node_Id); + -- Create a contract node for a generic package, generic subprogram or a + -- generic body denoted by Unit by collecting all source contract-related + -- pragmas in the contract of the unit. + + procedure Inherit_Subprogram_Contract + (Subp : Entity_Id; + From_Subp : Entity_Id); + -- Inherit relevant contract items from source subprogram From_Subp. Subp + -- denotes the destination subprogram. The inherited items are: + -- Extensions_Visible + -- ??? it would be nice if this routine handles Pre'Class and Post'Class + + procedure Instantiate_Subprogram_Contract (Templ : Node_Id; L : List_Id); + -- Instantiate all source pragmas found in the contract of the generic + -- subprogram declaration template denoted by Templ. The instantiated + -- pragmas are added to list L. + + procedure Save_Global_References_In_Contract + (Templ : Node_Id; + Gen_Id : Entity_Id); + -- Save all global references found within the aspect specifications and + -- the contract-related source pragmas assocated with generic template + -- Templ. Gen_Id denotes the entity of the analyzed generic copy. + +end Contracts; diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb index 05828b2fe07..1e142aa96f6 100644 --- a/gcc/ada/exp_ch6.adb +++ b/gcc/ada/exp_ch6.adb @@ -23,60 +23,59 @@ -- -- ------------------------------------------------------------------------------ -with Atree; use Atree; -with Checks; use Checks; -with Debug; use Debug; -with Einfo; use Einfo; -with Errout; use Errout; -with Elists; use Elists; -with Exp_Aggr; use Exp_Aggr; -with Exp_Atag; use Exp_Atag; -with Exp_Ch2; use Exp_Ch2; -with Exp_Ch3; use Exp_Ch3; -with Exp_Ch7; use Exp_Ch7; -with Exp_Ch9; use Exp_Ch9; -with Exp_Dbug; use Exp_Dbug; -with Exp_Disp; use Exp_Disp; -with Exp_Dist; use Exp_Dist; -with Exp_Intr; use Exp_Intr; -with Exp_Pakd; use Exp_Pakd; -with Exp_Prag; use Exp_Prag; -with Exp_Tss; use Exp_Tss; -with Exp_Unst; use Exp_Unst; -with Exp_Util; use Exp_Util; -with Freeze; use Freeze; -with Ghost; use Ghost; -with Inline; use Inline; -with Lib; use Lib; -with Namet; use Namet; -with Nlists; use Nlists; -with Nmake; use Nmake; -with Opt; use Opt; -with Restrict; use Restrict; -with Rident; use Rident; -with Rtsfind; use Rtsfind; -with Sem; use Sem; -with Sem_Aux; use Sem_Aux; -with Sem_Ch6; use Sem_Ch6; -with Sem_Ch8; use Sem_Ch8; -with Sem_Ch13; use Sem_Ch13; -with Sem_Dim; use Sem_Dim; -with Sem_Disp; use Sem_Disp; -with Sem_Dist; use Sem_Dist; -with Sem_Eval; use Sem_Eval; -with Sem_Mech; use Sem_Mech; -with Sem_Res; use Sem_Res; -with Sem_SCIL; use Sem_SCIL; -with Sem_Util; use Sem_Util; -with Sinfo; use Sinfo; -with Snames; use Snames; -with Stand; use Stand; -with Stringt; use Stringt; +with Atree; use Atree; +with Checks; use Checks; +with Contracts; use Contracts; +with Debug; use Debug; +with Einfo; use Einfo; +with Errout; use Errout; +with Elists; use Elists; +with Exp_Aggr; use Exp_Aggr; +with Exp_Atag; use Exp_Atag; +with Exp_Ch2; use Exp_Ch2; +with Exp_Ch3; use Exp_Ch3; +with Exp_Ch7; use Exp_Ch7; +with Exp_Ch9; use Exp_Ch9; +with Exp_Dbug; use Exp_Dbug; +with Exp_Disp; use Exp_Disp; +with Exp_Dist; use Exp_Dist; +with Exp_Intr; use Exp_Intr; +with Exp_Pakd; use Exp_Pakd; +with Exp_Tss; use Exp_Tss; +with Exp_Unst; use Exp_Unst; +with Exp_Util; use Exp_Util; +with Freeze; use Freeze; +with Ghost; use Ghost; +with Inline; use Inline; +with Lib; use Lib; +with Namet; use Namet; +with Nlists; use Nlists; +with Nmake; use Nmake; +with Opt; use Opt; +with Restrict; use Restrict; +with Rident; use Rident; +with Rtsfind; use Rtsfind; +with Sem; use Sem; +with Sem_Aux; use Sem_Aux; +with Sem_Ch6; use Sem_Ch6; +with Sem_Ch8; use Sem_Ch8; +with Sem_Ch13; use Sem_Ch13; +with Sem_Dim; use Sem_Dim; +with Sem_Disp; use Sem_Disp; +with Sem_Dist; use Sem_Dist; +with Sem_Eval; use Sem_Eval; +with Sem_Mech; use Sem_Mech; +with Sem_Res; use Sem_Res; +with Sem_SCIL; use Sem_SCIL; +with Sem_Util; use Sem_Util; +with Sinfo; use Sinfo; +with Snames; use Snames; +with Stand; use Stand; with Table; -with Targparm; use Targparm; -with Tbuild; use Tbuild; -with Uintp; use Uintp; -with Validsw; use Validsw; +with Targparm; use Targparm; +with Tbuild; use Tbuild; +with Uintp; use Uintp; +with Validsw; use Validsw; package body Exp_Ch6 is @@ -6773,1263 +6772,6 @@ package body Exp_Ch6 is end if; end Expand_Simple_Function_Return; - -------------------------------- - -- Expand_Subprogram_Contract -- - -------------------------------- - - procedure Expand_Subprogram_Contract (N : Node_Id) is - Body_Id : constant Entity_Id := Defining_Entity (N); - Spec_Id : constant Entity_Id := Corresponding_Spec (N); - - procedure Add_Invariant_And_Predicate_Checks - (Subp_Id : Entity_Id; - Stmts : in out List_Id; - Result : out Node_Id); - -- Process the result of function Subp_Id (if applicable) and all its - -- formals. Add invariant and predicate checks where applicable. The - -- routine appends all the checks to list Stmts. If Subp_Id denotes a - -- function, Result contains the entity of parameter _Result, to be - -- used in the creation of procedure _Postconditions. - - procedure Append_Enabled_Item (Item : Node_Id; List : in out List_Id); - -- Append a node to a list. If there is no list, create a new one. When - -- the item denotes a pragma, it is added to the list only when it is - -- enabled. - - procedure Build_Postconditions_Procedure - (Subp_Id : Entity_Id; - Stmts : List_Id; - Result : Entity_Id); - -- Create the body of procedure _Postconditions which handles various - -- assertion actions on exit from subprogram Subp_Id. Stmts is the list - -- of statements to be checked on exit. Parameter Result is the entity - -- of parameter _Result when Subp_Id denotes a function. - - function Build_Pragma_Check_Equivalent - (Prag : Node_Id; - Subp_Id : Entity_Id := Empty; - Inher_Id : Entity_Id := Empty) return Node_Id; - -- Transform a [refined] pre- or postcondition denoted by Prag into an - -- equivalent pragma Check. When the pre- or postcondition is inherited, - -- the routine corrects the references of all formals of Inher_Id to - -- point to the formals of Subp_Id. - - procedure Process_Contract_Cases (Stmts : in out List_Id); - -- Process pragma Contract_Cases. This routine prepends items to the - -- body declarations and appends items to list Stmts. - - procedure Process_Postconditions (Stmts : in out List_Id); - -- Collect all [inherited] spec and body postconditions and accumulate - -- their pragma Check equivalents in list Stmts. - - procedure Process_Preconditions; - -- Collect all [inherited] spec and body preconditions and prepend their - -- pragma Check equivalents to the declarations of the body. - - ---------------------------------------- - -- Add_Invariant_And_Predicate_Checks -- - ---------------------------------------- - - procedure Add_Invariant_And_Predicate_Checks - (Subp_Id : Entity_Id; - Stmts : in out List_Id; - Result : out Node_Id) - is - procedure Add_Invariant_Access_Checks (Id : Entity_Id); - -- Id denotes the return value of a function or a formal parameter. - -- Add an invariant check if the type of Id is access to a type with - -- invariants. The routine appends the generated code to Stmts. - - function Invariant_Checks_OK (Typ : Entity_Id) return Boolean; - -- Determine whether type Typ can benefit from invariant checks. To - -- qualify, the type must have a non-null invariant procedure and - -- subprogram Subp_Id must appear visible from the point of view of - -- the type. - - --------------------------------- - -- Add_Invariant_Access_Checks -- - --------------------------------- - - procedure Add_Invariant_Access_Checks (Id : Entity_Id) is - Loc : constant Source_Ptr := Sloc (N); - Ref : Node_Id; - Typ : Entity_Id; - - begin - Typ := Etype (Id); - - if Is_Access_Type (Typ) and then not Is_Access_Constant (Typ) then - Typ := Designated_Type (Typ); - - if Invariant_Checks_OK (Typ) then - Ref := - Make_Explicit_Dereference (Loc, - Prefix => New_Occurrence_Of (Id, Loc)); - Set_Etype (Ref, Typ); - - -- Generate: - -- if /= null then - -- )> - -- end if; - - Append_Enabled_Item - (Item => - Make_If_Statement (Loc, - Condition => - Make_Op_Ne (Loc, - Left_Opnd => New_Occurrence_Of (Id, Loc), - Right_Opnd => Make_Null (Loc)), - Then_Statements => New_List ( - Make_Invariant_Call (Ref))), - List => Stmts); - end if; - end if; - end Add_Invariant_Access_Checks; - - ------------------------- - -- Invariant_Checks_OK -- - ------------------------- - - function Invariant_Checks_OK (Typ : Entity_Id) return Boolean is - function Has_Null_Body (Proc_Id : Entity_Id) return Boolean; - -- Determine whether the body of procedure Proc_Id contains a sole - -- null statement, possibly followed by an optional return. - - function Has_Public_Visibility_Of_Subprogram return Boolean; - -- Determine whether type Typ has public visibility of subprogram - -- Subp_Id. - - ------------------- - -- Has_Null_Body -- - ------------------- - - function Has_Null_Body (Proc_Id : Entity_Id) return Boolean is - Body_Id : Entity_Id; - Decl : Node_Id; - Spec : Node_Id; - Stmt1 : Node_Id; - Stmt2 : Node_Id; - - begin - Spec := Parent (Proc_Id); - Decl := Parent (Spec); - - -- Retrieve the entity of the invariant procedure body - - if Nkind (Spec) = N_Procedure_Specification - and then Nkind (Decl) = N_Subprogram_Declaration - then - Body_Id := Corresponding_Body (Decl); - - -- The body acts as a spec - - else - Body_Id := Proc_Id; - end if; - - -- The body will be generated later - - if No (Body_Id) then - return False; - end if; - - Spec := Parent (Body_Id); - Decl := Parent (Spec); - - pragma Assert - (Nkind (Spec) = N_Procedure_Specification - and then Nkind (Decl) = N_Subprogram_Body); - - Stmt1 := First (Statements (Handled_Statement_Sequence (Decl))); - - -- Look for a null statement followed by an optional return - -- statement. - - if Nkind (Stmt1) = N_Null_Statement then - Stmt2 := Next (Stmt1); - - if Present (Stmt2) then - return Nkind (Stmt2) = N_Simple_Return_Statement; - else - return True; - end if; - end if; - - return False; - end Has_Null_Body; - - ----------------------------------------- - -- Has_Public_Visibility_Of_Subprogram -- - ----------------------------------------- - - function Has_Public_Visibility_Of_Subprogram return Boolean is - Subp_Decl : constant Node_Id := Unit_Declaration_Node (Subp_Id); - - begin - -- An Initialization procedure must be considered visible even - -- though it is internally generated. - - if Is_Init_Proc (Defining_Entity (Subp_Decl)) then - return True; - - elsif Ekind (Scope (Typ)) /= E_Package then - return False; - - -- Internally generated code is never publicly visible except - -- for a subprogram that is the implementation of an expression - -- function. In that case the visibility is determined by the - -- last check. - - elsif not Comes_From_Source (Subp_Decl) - and then - (Nkind (Original_Node (Subp_Decl)) /= N_Expression_Function - or else not - Comes_From_Source (Defining_Entity (Subp_Decl))) - then - return False; - - -- Determine whether the subprogram is declared in the visible - -- declarations of the package containing the type. - - else - return List_Containing (Subp_Decl) = - Visible_Declarations - (Specification (Unit_Declaration_Node (Scope (Typ)))); - end if; - end Has_Public_Visibility_Of_Subprogram; - - -- Start of processing for Invariant_Checks_OK - - begin - return - Has_Invariants (Typ) - and then Present (Invariant_Procedure (Typ)) - and then not Has_Null_Body (Invariant_Procedure (Typ)) - and then Has_Public_Visibility_Of_Subprogram; - end Invariant_Checks_OK; - - -- Local variables - - Loc : constant Source_Ptr := Sloc (N); - -- Source location of subprogram contract - - Formal : Entity_Id; - Typ : Entity_Id; - - -- Start of processing for Add_Invariant_And_Predicate_Checks - - begin - Result := Empty; - - -- Process the result of a function - - if Ekind (Subp_Id) = E_Function then - Typ := Etype (Subp_Id); - - -- Generate _Result which is used in procedure _Postconditions to - -- verify the return value. - - Result := Make_Defining_Identifier (Loc, Name_uResult); - Set_Etype (Result, Typ); - - -- Add an invariant check when the return type has invariants and - -- the related function is visible to the outside. - - if Invariant_Checks_OK (Typ) then - Append_Enabled_Item - (Item => - Make_Invariant_Call (New_Occurrence_Of (Result, Loc)), - List => Stmts); - end if; - - -- Add an invariant check when the return type is an access to a - -- type with invariants. - - Add_Invariant_Access_Checks (Result); - end if; - - -- Add invariant and predicates for all formals that qualify - - Formal := First_Formal (Subp_Id); - while Present (Formal) loop - Typ := Etype (Formal); - - if Ekind (Formal) /= E_In_Parameter - or else Is_Access_Type (Typ) - then - if Invariant_Checks_OK (Typ) then - Append_Enabled_Item - (Item => - Make_Invariant_Call (New_Occurrence_Of (Formal, Loc)), - List => Stmts); - end if; - - Add_Invariant_Access_Checks (Formal); - - -- Note: we used to add predicate checks for OUT and IN OUT - -- formals here, but that was misguided, since such checks are - -- performed on the caller side, based on the predicate of the - -- actual, rather than the predicate of the formal. - - end if; - - Next_Formal (Formal); - end loop; - end Add_Invariant_And_Predicate_Checks; - - ------------------------- - -- Append_Enabled_Item -- - ------------------------- - - procedure Append_Enabled_Item (Item : Node_Id; List : in out List_Id) is - begin - -- Do not chain ignored or disabled pragmas - - if Nkind (Item) = N_Pragma - and then (Is_Ignored (Item) or else Is_Disabled (Item)) - then - null; - - -- Otherwise, add the item - - else - if No (List) then - List := New_List; - end if; - - -- If the pragma is a conjunct in a composite postcondition, it - -- has been processed in reverse order. In the postcondition body - -- if must appear before the others. - - if Nkind (Item) = N_Pragma - and then From_Aspect_Specification (Item) - and then Split_PPC (Item) - then - Prepend (Item, List); - else - Append (Item, List); - end if; - end if; - end Append_Enabled_Item; - - ------------------------------------ - -- Build_Postconditions_Procedure -- - ------------------------------------ - - procedure Build_Postconditions_Procedure - (Subp_Id : Entity_Id; - Stmts : List_Id; - Result : Entity_Id) - is - procedure Insert_Before_First_Source_Declaration (Stmt : Node_Id); - -- Insert node Stmt before the first source declaration of the - -- related subprogram's body. If no such declaration exists, Stmt - -- becomes the last declaration. - - -------------------------------------------- - -- Insert_Before_First_Source_Declaration -- - -------------------------------------------- - - procedure Insert_Before_First_Source_Declaration (Stmt : Node_Id) is - Decls : constant List_Id := Declarations (N); - Decl : Node_Id; - - begin - -- Inspect the declarations of the related subprogram body looking - -- for the first source declaration. - - if Present (Decls) then - Decl := First (Decls); - while Present (Decl) loop - if Comes_From_Source (Decl) then - Insert_Before (Decl, Stmt); - return; - end if; - - Next (Decl); - end loop; - - -- If we get there, then the subprogram body lacks any source - -- declarations. The body of _Postconditions now acts as the - -- last declaration. - - Append (Stmt, Decls); - - -- Ensure that the body has a declaration list - - else - Set_Declarations (N, New_List (Stmt)); - end if; - end Insert_Before_First_Source_Declaration; - - -- Local variables - - Loc : constant Source_Ptr := Sloc (N); - Params : List_Id := No_List; - Proc_Bod : Node_Id; - Proc_Id : Entity_Id; - - -- Start of processing for Build_Postconditions_Procedure - - begin - -- Nothing to do if there are no actions to check on exit - - if No (Stmts) then - return; - end if; - - Proc_Id := Make_Defining_Identifier (Loc, Name_uPostconditions); - Set_Debug_Info_Needed (Proc_Id); - Set_Postconditions_Proc (Subp_Id, Proc_Id); - - -- The related subprogram is a function, create the specification of - -- parameter _Result. - - if Present (Result) then - Params := New_List ( - Make_Parameter_Specification (Loc, - Defining_Identifier => Result, - Parameter_Type => - New_Occurrence_Of (Etype (Result), Loc))); - end if; - - -- Insert _Postconditions before the first source declaration of the - -- body. This ensures that the body will not cause any premature - -- freezing as it may mention types: - - -- procedure Proc (Obj : Array_Typ) is - -- procedure _postconditions is - -- begin - -- ... Obj ... - -- end _postconditions; - - -- subtype T is Array_Typ (Obj'First (1) .. Obj'Last (1)); - -- begin - - -- In the example above, Obj is of type T but the incorrect placement - -- of _Postconditions will cause a crash in gigi due to an out of - -- order reference. The body of _Postconditions must be placed after - -- the declaration of Temp to preserve correct visibility. - - -- Set an explicit End_Lavel to override the sloc of the implicit - -- RETURN statement, and prevent it from inheriting the sloc of one - -- the postconditions: this would cause confusing debug into to be - -- produced, interfering with coverage analysis tools. - - Proc_Bod := - Make_Subprogram_Body (Loc, - Specification => - Make_Procedure_Specification (Loc, - Defining_Unit_Name => Proc_Id, - Parameter_Specifications => Params), - - Declarations => Empty_List, - Handled_Statement_Sequence => - Make_Handled_Sequence_Of_Statements (Loc, - Statements => Stmts, - End_Label => Make_Identifier (Loc, Chars (Proc_Id)))); - - Insert_Before_First_Source_Declaration (Proc_Bod); - Analyze (Proc_Bod); - end Build_Postconditions_Procedure; - - ----------------------------------- - -- Build_Pragma_Check_Equivalent -- - ----------------------------------- - - function Build_Pragma_Check_Equivalent - (Prag : Node_Id; - Subp_Id : Entity_Id := Empty; - Inher_Id : Entity_Id := Empty) return Node_Id - is - function Suppress_Reference (N : Node_Id) return Traverse_Result; - -- Detect whether node N references a formal parameter subject to - -- pragma Unreferenced. If this is the case, set Comes_From_Source - -- to False to suppress the generation of a reference when analyzing - -- N later on. - - ------------------------ - -- Suppress_Reference -- - ------------------------ - - function Suppress_Reference (N : Node_Id) return Traverse_Result is - Formal : Entity_Id; - - begin - if Is_Entity_Name (N) and then Present (Entity (N)) then - Formal := Entity (N); - - -- The formal parameter is subject to pragma Unreferenced. - -- Prevent the generation of a reference by resetting the - -- Comes_From_Source flag. - - if Is_Formal (Formal) - and then Has_Pragma_Unreferenced (Formal) - then - Set_Comes_From_Source (N, False); - end if; - end if; - - return OK; - end Suppress_Reference; - - procedure Suppress_References is - new Traverse_Proc (Suppress_Reference); - - -- Local variables - - Loc : constant Source_Ptr := Sloc (Prag); - Prag_Nam : constant Name_Id := Pragma_Name (Prag); - Check_Prag : Node_Id; - Formals_Map : Elist_Id; - Inher_Formal : Entity_Id; - Msg_Arg : Node_Id; - Nam : Name_Id; - Subp_Formal : Entity_Id; - - -- Start of processing for Build_Pragma_Check_Equivalent - - begin - Formals_Map := No_Elist; - - -- When the pre- or postcondition is inherited, map the formals of - -- the inherited subprogram to those of the current subprogram. - - if Present (Inher_Id) then - pragma Assert (Present (Subp_Id)); - - Formals_Map := New_Elmt_List; - - -- Create a relation => - - Inher_Formal := First_Formal (Inher_Id); - Subp_Formal := First_Formal (Subp_Id); - while Present (Inher_Formal) and then Present (Subp_Formal) loop - Append_Elmt (Inher_Formal, Formals_Map); - Append_Elmt (Subp_Formal, Formals_Map); - - Next_Formal (Inher_Formal); - Next_Formal (Subp_Formal); - end loop; - end if; - - -- Copy the original pragma while performing substitutions (if - -- applicable). - - Check_Prag := - New_Copy_Tree - (Source => Prag, - Map => Formals_Map, - New_Scope => Current_Scope); - - -- Mark the pragma as being internally generated and reset the - -- Analyzed flag. - - Set_Analyzed (Check_Prag, False); - Set_Comes_From_Source (Check_Prag, False); - - -- The tree of the original pragma may contain references to the - -- formal parameters of the related subprogram. At the same time - -- the corresponding body may mark the formals as unreferenced: - - -- procedure Proc (Formal : ...) - -- with Pre => Formal ...; - - -- procedure Proc (Formal : ...) is - -- pragma Unreferenced (Formal); - -- ... - - -- This creates problems because all pragma Check equivalents are - -- analyzed at the end of the body declarations. Since all source - -- references have already been accounted for, reset any references - -- to such formals in the generated pragma Check equivalent. - - Suppress_References (Check_Prag); - - if Present (Corresponding_Aspect (Prag)) then - Nam := Chars (Identifier (Corresponding_Aspect (Prag))); - else - Nam := Prag_Nam; - end if; - - -- Convert the copy into pragma Check by correcting the name and - -- adding a check_kind argument. - - Set_Pragma_Identifier - (Check_Prag, Make_Identifier (Loc, Name_Check)); - - Prepend_To (Pragma_Argument_Associations (Check_Prag), - Make_Pragma_Argument_Association (Loc, - Expression => Make_Identifier (Loc, Nam))); - - -- Update the error message when the pragma is inherited - - if Present (Inher_Id) then - Msg_Arg := Last (Pragma_Argument_Associations (Check_Prag)); - - if Chars (Msg_Arg) = Name_Message then - String_To_Name_Buffer (Strval (Expression (Msg_Arg))); - - -- Insert "inherited" to improve the error message - - if Name_Buffer (1 .. 8) = "failed p" then - Insert_Str_In_Name_Buffer ("inherited ", 8); - Set_Strval (Expression (Msg_Arg), String_From_Name_Buffer); - end if; - end if; - end if; - - return Check_Prag; - end Build_Pragma_Check_Equivalent; - - ---------------------------- - -- Process_Contract_Cases -- - ---------------------------- - - procedure Process_Contract_Cases (Stmts : in out List_Id) is - procedure Process_Contract_Cases_For (Subp_Id : Entity_Id); - -- Process pragma Contract_Cases for subprogram Subp_Id - - -------------------------------- - -- Process_Contract_Cases_For -- - -------------------------------- - - procedure Process_Contract_Cases_For (Subp_Id : Entity_Id) is - Items : constant Node_Id := Contract (Subp_Id); - Prag : Node_Id; - - begin - if Present (Items) then - Prag := Contract_Test_Cases (Items); - while Present (Prag) loop - if Pragma_Name (Prag) = Name_Contract_Cases then - Expand_Pragma_Contract_Cases - (CCs => Prag, - Subp_Id => Subp_Id, - Decls => Declarations (N), - Stmts => Stmts); - end if; - - Prag := Next_Pragma (Prag); - end loop; - end if; - end Process_Contract_Cases_For; - - -- Start of processing for Process_Contract_Cases - - begin - Process_Contract_Cases_For (Body_Id); - - if Present (Spec_Id) then - Process_Contract_Cases_For (Spec_Id); - end if; - end Process_Contract_Cases; - - ---------------------------- - -- Process_Postconditions -- - ---------------------------- - - procedure Process_Postconditions (Stmts : in out List_Id) is - procedure Process_Body_Postconditions (Post_Nam : Name_Id); - -- Collect all [refined] postconditions of a specific kind denoted - -- by Post_Nam that belong to the body and generate pragma Check - -- equivalents in list Stmts. - - procedure Process_Spec_Postconditions; - -- Collect all [inherited] postconditions of the spec and generate - -- pragma Check equivalents in list Stmts. - - --------------------------------- - -- Process_Body_Postconditions -- - --------------------------------- - - procedure Process_Body_Postconditions (Post_Nam : Name_Id) is - Items : constant Node_Id := Contract (Body_Id); - Unit_Decl : constant Node_Id := Parent (N); - Decl : Node_Id; - Prag : Node_Id; - - begin - -- Process the contract - - if Present (Items) then - Prag := Pre_Post_Conditions (Items); - while Present (Prag) loop - if Pragma_Name (Prag) = Post_Nam then - Append_Enabled_Item - (Item => Build_Pragma_Check_Equivalent (Prag), - List => Stmts); - end if; - - Prag := Next_Pragma (Prag); - end loop; - end if; - - -- The subprogram body being processed is actually the proper body - -- of a stub with a corresponding spec. The subprogram stub may - -- carry a postcondition pragma in which case it must be taken - -- into account. The pragma appears after the stub. - - if Present (Spec_Id) and then Nkind (Unit_Decl) = N_Subunit then - Decl := Next (Corresponding_Stub (Unit_Decl)); - while Present (Decl) loop - - -- Note that non-matching pragmas are skipped - - if Nkind (Decl) = N_Pragma then - if Pragma_Name (Decl) = Post_Nam then - Append_Enabled_Item - (Item => Build_Pragma_Check_Equivalent (Decl), - List => Stmts); - end if; - - -- Skip internally generated code - - elsif not Comes_From_Source (Decl) then - null; - - -- Postcondition pragmas are usually grouped together. There - -- is no need to inspect the whole declarative list. - - else - exit; - end if; - - Next (Decl); - end loop; - end if; - end Process_Body_Postconditions; - - --------------------------------- - -- Process_Spec_Postconditions -- - --------------------------------- - - procedure Process_Spec_Postconditions is - Subps : constant Subprogram_List := - Inherited_Subprograms (Spec_Id); - Items : Node_Id; - Prag : Node_Id; - Subp_Id : Entity_Id; - - begin - -- Process the contract - - Items := Contract (Spec_Id); - - if Present (Items) then - Prag := Pre_Post_Conditions (Items); - while Present (Prag) loop - if Pragma_Name (Prag) = Name_Postcondition then - Append_Enabled_Item - (Item => Build_Pragma_Check_Equivalent (Prag), - List => Stmts); - end if; - - Prag := Next_Pragma (Prag); - end loop; - end if; - - -- Process the contracts of all inherited subprograms, looking for - -- class-wide postconditions. - - for Index in Subps'Range loop - Subp_Id := Subps (Index); - Items := Contract (Subp_Id); - - if Present (Items) then - Prag := Pre_Post_Conditions (Items); - while Present (Prag) loop - if Pragma_Name (Prag) = Name_Postcondition - and then Class_Present (Prag) - then - Append_Enabled_Item - (Item => - Build_Pragma_Check_Equivalent - (Prag => Prag, - Subp_Id => Spec_Id, - Inher_Id => Subp_Id), - List => Stmts); - end if; - - Prag := Next_Pragma (Prag); - end loop; - end if; - end loop; - end Process_Spec_Postconditions; - - -- Start of processing for Process_Postconditions - - begin - -- The processing of postconditions is done in reverse order (body - -- first) to ensure the following arrangement: - - -- - -- - -- - -- - - Process_Body_Postconditions (Name_Refined_Post); - Process_Body_Postconditions (Name_Postcondition); - - if Present (Spec_Id) then - Process_Spec_Postconditions; - end if; - end Process_Postconditions; - - --------------------------- - -- Process_Preconditions -- - --------------------------- - - procedure Process_Preconditions is - Class_Pre : Node_Id := Empty; - -- The sole [inherited] class-wide precondition pragma that applies - -- to the subprogram. - - Insert_Node : Node_Id := Empty; - -- The insertion node after which all pragma Check equivalents are - -- inserted. - - procedure Merge_Preconditions (From : Node_Id; Into : Node_Id); - -- Merge two class-wide preconditions by "or else"-ing them. The - -- changes are accumulated in parameter Into. Update the error - -- message of Into. - - procedure Prepend_To_Decls (Item : Node_Id); - -- Prepend a single item to the declarations of the subprogram body - - procedure Prepend_To_Decls_Or_Save (Prag : Node_Id); - -- Save a class-wide precondition into Class_Pre or prepend a normal - -- precondition ot the declarations of the body and analyze it. - - procedure Process_Inherited_Preconditions; - -- Collect all inherited class-wide preconditions and merge them into - -- one big precondition to be evaluated as pragma Check. - - procedure Process_Preconditions_For (Subp_Id : Entity_Id); - -- Collect all preconditions of subprogram Subp_Id and prepend their - -- pragma Check equivalents to the declarations of the body. - - ------------------------- - -- Merge_Preconditions -- - ------------------------- - - procedure Merge_Preconditions (From : Node_Id; Into : Node_Id) is - function Expression_Arg (Prag : Node_Id) return Node_Id; - -- Return the boolean expression argument of a precondition while - -- updating its parenteses count for the subsequent merge. - - function Message_Arg (Prag : Node_Id) return Node_Id; - -- Return the message argument of a precondition - - -------------------- - -- Expression_Arg -- - -------------------- - - function Expression_Arg (Prag : Node_Id) return Node_Id is - Args : constant List_Id := Pragma_Argument_Associations (Prag); - Arg : constant Node_Id := Get_Pragma_Arg (Next (First (Args))); - - begin - if Paren_Count (Arg) = 0 then - Set_Paren_Count (Arg, 1); - end if; - - return Arg; - end Expression_Arg; - - ----------------- - -- Message_Arg -- - ----------------- - - function Message_Arg (Prag : Node_Id) return Node_Id is - Args : constant List_Id := Pragma_Argument_Associations (Prag); - begin - return Get_Pragma_Arg (Last (Args)); - end Message_Arg; - - -- Local variables - - From_Expr : constant Node_Id := Expression_Arg (From); - From_Msg : constant Node_Id := Message_Arg (From); - Into_Expr : constant Node_Id := Expression_Arg (Into); - Into_Msg : constant Node_Id := Message_Arg (Into); - Loc : constant Source_Ptr := Sloc (Into); - - -- Start of processing for Merge_Preconditions - - begin - -- Merge the two preconditions by "or else"-ing them - - Rewrite (Into_Expr, - Make_Or_Else (Loc, - Right_Opnd => Relocate_Node (Into_Expr), - Left_Opnd => From_Expr)); - - -- Merge the two error messages to produce a single message of the - -- form: - - -- failed precondition from ... - -- also failed inherited precondition from ... - - if not Exception_Locations_Suppressed then - Start_String (Strval (Into_Msg)); - Store_String_Char (ASCII.LF); - Store_String_Chars (" also "); - Store_String_Chars (Strval (From_Msg)); - - Set_Strval (Into_Msg, End_String); - end if; - end Merge_Preconditions; - - ---------------------- - -- Prepend_To_Decls -- - ---------------------- - - procedure Prepend_To_Decls (Item : Node_Id) is - Decls : List_Id := Declarations (N); - - begin - -- Ensure that the body has a declarative list - - if No (Decls) then - Decls := New_List; - Set_Declarations (N, Decls); - end if; - - Prepend_To (Decls, Item); - end Prepend_To_Decls; - - ------------------------------ - -- Prepend_To_Decls_Or_Save -- - ------------------------------ - - procedure Prepend_To_Decls_Or_Save (Prag : Node_Id) is - Check_Prag : Node_Id; - - begin - Check_Prag := Build_Pragma_Check_Equivalent (Prag); - - -- Save the sole class-wide precondition (if any) for the next - -- step where it will be merged with inherited preconditions. - - if Class_Present (Prag) then - pragma Assert (No (Class_Pre)); - Class_Pre := Check_Prag; - - -- Accumulate the corresponding Check pragmas at the top of the - -- declarations. Prepending the items ensures that they will be - -- evaluated in their original order. - - else - if Present (Insert_Node) then - Insert_After (Insert_Node, Check_Prag); - else - Prepend_To_Decls (Check_Prag); - end if; - - Analyze (Check_Prag); - end if; - end Prepend_To_Decls_Or_Save; - - ------------------------------------- - -- Process_Inherited_Preconditions -- - ------------------------------------- - - procedure Process_Inherited_Preconditions is - Subps : constant Subprogram_List := - Inherited_Subprograms (Spec_Id); - Check_Prag : Node_Id; - Items : Node_Id; - Prag : Node_Id; - Subp_Id : Entity_Id; - - begin - -- Process the contracts of all inherited subprograms, looking for - -- class-wide preconditions. - - for Index in Subps'Range loop - Subp_Id := Subps (Index); - Items := Contract (Subp_Id); - - if Present (Items) then - Prag := Pre_Post_Conditions (Items); - while Present (Prag) loop - if Pragma_Name (Prag) = Name_Precondition - and then Class_Present (Prag) - then - Check_Prag := - Build_Pragma_Check_Equivalent - (Prag => Prag, - Subp_Id => Spec_Id, - Inher_Id => Subp_Id); - - -- The spec or an inherited subprogram already yielded - -- a class-wide precondition. Merge the existing - -- precondition with the current one using "or else". - - if Present (Class_Pre) then - Merge_Preconditions (Check_Prag, Class_Pre); - else - Class_Pre := Check_Prag; - end if; - end if; - - Prag := Next_Pragma (Prag); - end loop; - end if; - end loop; - - -- Add the merged class-wide preconditions - - if Present (Class_Pre) then - Prepend_To_Decls (Class_Pre); - Analyze (Class_Pre); - end if; - end Process_Inherited_Preconditions; - - ------------------------------- - -- Process_Preconditions_For -- - ------------------------------- - - procedure Process_Preconditions_For (Subp_Id : Entity_Id) is - Items : constant Node_Id := Contract (Subp_Id); - Decl : Node_Id; - Prag : Node_Id; - Subp_Decl : Node_Id; - - begin - -- Process the contract - - if Present (Items) then - Prag := Pre_Post_Conditions (Items); - while Present (Prag) loop - if Pragma_Name (Prag) = Name_Precondition then - Prepend_To_Decls_Or_Save (Prag); - end if; - - Prag := Next_Pragma (Prag); - end loop; - end if; - - -- The subprogram declaration being processed is actually a body - -- stub. The stub may carry a precondition pragma in which case it - -- must be taken into account. The pragma appears after the stub. - - Subp_Decl := Unit_Declaration_Node (Subp_Id); - - if Nkind (Subp_Decl) = N_Subprogram_Body_Stub then - - -- Inspect the declarations following the body stub - - Decl := Next (Subp_Decl); - while Present (Decl) loop - - -- Note that non-matching pragmas are skipped - - if Nkind (Decl) = N_Pragma then - if Pragma_Name (Decl) = Name_Precondition then - Prepend_To_Decls_Or_Save (Decl); - end if; - - -- Skip internally generated code - - elsif not Comes_From_Source (Decl) then - null; - - -- Preconditions are usually grouped together. There is no - -- need to inspect the whole declarative list. - - else - exit; - end if; - - Next (Decl); - end loop; - end if; - end Process_Preconditions_For; - - -- Local variables - - Decls : constant List_Id := Declarations (N); - Decl : Node_Id; - - -- Start of processing for Process_Preconditions - - begin - -- Find the last internally generate declaration starting from the - -- top of the body declarations. This ensures that discriminals and - -- subtypes are properly visible to the pragma Check equivalents. - - if Present (Decls) then - Decl := First (Decls); - while Present (Decl) loop - exit when Comes_From_Source (Decl); - Insert_Node := Decl; - Next (Decl); - end loop; - end if; - - -- The processing of preconditions is done in reverse order (body - -- first) because each pragma Check equivalent is inserted at the - -- top of the declarations. This ensures that the final order is - -- consistent with following diagram: - - -- - -- - -- - - Process_Preconditions_For (Body_Id); - - if Present (Spec_Id) then - Process_Preconditions_For (Spec_Id); - Process_Inherited_Preconditions; - end if; - end Process_Preconditions; - - -- Local variables - - Restore_Scope : Boolean := False; - Result : Entity_Id; - Stmts : List_Id := No_List; - Subp_Id : Entity_Id; - - -- Start of processing for Expand_Subprogram_Contract - - begin - -- Obtain the entity of the initial declaration - - if Present (Spec_Id) then - Subp_Id := Spec_Id; - else - Subp_Id := Body_Id; - end if; - - -- Do not perform expansion activity when it is not needed - - if not Expander_Active then - return; - - -- ASIS requires an unaltered tree - - elsif ASIS_Mode then - return; - - -- GNATprove does not need the executable semantics of a contract - - elsif GNATprove_Mode then - return; - - -- The contract of a generic subprogram or one declared in a generic - -- context is not expanded as the corresponding instance will provide - -- the executable semantics of the contract. - - elsif Is_Generic_Subprogram (Subp_Id) or else Inside_A_Generic then - return; - - -- All subprograms carry a contract, but for some it is not significant - -- and should not be processed. This is a small optimization. - - elsif not Has_Significant_Contract (Subp_Id) then - return; - - -- The contract of an ignored Ghost subprogram does not need expansion - -- because the subprogram and all calls to it will be removed. - - elsif Is_Ignored_Ghost_Entity (Subp_Id) then - return; - end if; - - -- Do not re-expand the same contract. This scenario occurs when a - -- construct is rewritten into something else during its analysis - -- (expression functions for instance). - - if Has_Expanded_Contract (Subp_Id) then - return; - - -- Otherwise mark the subprogram - - else - Set_Has_Expanded_Contract (Subp_Id); - end if; - - -- Ensure that the formal parameters are visible when expanding all - -- contract items. - - if not In_Open_Scopes (Subp_Id) then - Restore_Scope := True; - Push_Scope (Subp_Id); - - if Is_Generic_Subprogram (Subp_Id) then - Install_Generic_Formals (Subp_Id); - else - Install_Formals (Subp_Id); - end if; - end if; - - -- The expansion of a subprogram contract involves the creation of Check - -- pragmas to verify the contract assertions of the spec and body in a - -- particular order. The order is as follows: - - -- function Example (...) return ... is - -- procedure _Postconditions (...) is - -- begin - -- - -- - -- - -- - -- - -- - -- - -- end _Postconditions; - - -- - -- - -- - -- - - -- - -- begin - -- - - -- _Preconditions (Result); - -- return Result; - -- end Example; - - -- Routine _Postconditions holds all contract assertions that must be - -- verified on exit from the related subprogram. - - -- Step 1: Handle all preconditions. This action must come before the - -- processing of pragma Contract_Cases because the pragma prepends items - -- to the body declarations. - - Process_Preconditions; - - -- Step 2: Handle all postconditions. This action must come before the - -- processing of pragma Contract_Cases because the pragma appends items - -- to list Stmts. - - Process_Postconditions (Stmts); - - -- Step 3: Handle pragma Contract_Cases. This action must come before - -- the processing of invariants and predicates because those append - -- items to list Smts. - - Process_Contract_Cases (Stmts); - - -- Step 4: Apply invariant and predicate checks on a function result and - -- all formals. The resulting checks are accumulated in list Stmts. - - Add_Invariant_And_Predicate_Checks (Subp_Id, Stmts, Result); - - -- Step 5: Construct procedure _Postconditions - - Build_Postconditions_Procedure (Subp_Id, Stmts, Result); - - if Restore_Scope then - End_Scope; - end if; - end Expand_Subprogram_Contract; - -------------------------------------------- -- Has_Unconstrained_Access_Discriminants -- -------------------------------------------- diff --git a/gcc/ada/exp_ch6.ads b/gcc/ada/exp_ch6.ads index 1cc993f509e..2184d5863ab 100644 --- a/gcc/ada/exp_ch6.ads +++ b/gcc/ada/exp_ch6.ads @@ -41,12 +41,6 @@ package Exp_Ch6 is -- This procedure contains common processing for Expand_N_Function_Call, -- Expand_N_Procedure_Statement, and Expand_N_Entry_Call. - procedure Expand_Subprogram_Contract (N : Node_Id); - -- Expand the contracts of a subprogram body and its correspoding spec (if - -- any). This routine processes all [refined] pre- and postconditions as - -- well as Contract_Cases, invariants and predicates. N denotes the body of - -- the subprogram. - procedure Freeze_Subprogram (N : Node_Id); -- generate the appropriate expansions related to Subprogram freeze -- nodes (e.g. the filling of the corresponding Dispatch Table for diff --git a/gcc/ada/gcc-interface/Make-lang.in b/gcc/ada/gcc-interface/Make-lang.in index 7378d6f39d4..a8ce6722491 100644 --- a/gcc/ada/gcc-interface/Make-lang.in +++ b/gcc/ada/gcc-interface/Make-lang.in @@ -243,6 +243,7 @@ GNAT_ADA_OBJS = \ ada/casing.o \ ada/checks.o \ ada/comperr.o \ + ada/contracts.o \ ada/csets.o \ ada/cstand.o \ ada/debug.o \ diff --git a/gcc/ada/init.c b/gcc/ada/init.c index c649d672414..243f3b80d57 100644 --- a/gcc/ada/init.c +++ b/gcc/ada/init.c @@ -110,6 +110,7 @@ char *__gl_interrupt_states = 0; int __gl_num_interrupt_states = 0; int __gl_unreserve_all_interrupts = 0; int __gl_exception_tracebacks = 0; +int __gl_exception_tracebacks_symbolic = 0; int __gl_detect_blocking = 0; int __gl_default_stack_size = -1; int __gl_leap_seconds_support = 0; diff --git a/gcc/ada/opt.ads b/gcc/ada/opt.ads index 992658e47f1..e99c6b71b25 100644 --- a/gcc/ada/opt.ads +++ b/gcc/ada/opt.ads @@ -595,7 +595,12 @@ package Opt is Exception_Tracebacks : Boolean := False; -- GNATBIND - -- Set to True to store tracebacks in exception occurrences (-E) + -- Set to True to store tracebacks in exception occurrences (-Ea or -E) + + Exception_Tracebacks_Symbolic : Boolean := False; + -- GNATBIND + -- Set to True to store tracebacks in exception occurrences and enable + -- symbolic tracebacks (-Es). Extensions_Allowed : Boolean := False; -- GNAT diff --git a/gcc/ada/s-exctra.ads b/gcc/ada/s-exctra.ads index 25c2f729dbc..ae6936e93dd 100644 --- a/gcc/ada/s-exctra.ads +++ b/gcc/ada/s-exctra.ads @@ -48,6 +48,10 @@ -- may return any string output in association with a provided call chain. -- The decorator replaces the default backtrace mentioned above. +-- On systems that use DWARF debugging output, then if the "-g" compiler +-- switch and the "-Es" binder switch are used, the decorator is automatically +-- set to Symbolic_Traceback. + with System.Traceback_Entries; package System.Exception_Traces is @@ -89,12 +93,15 @@ package System.Exception_Traces is -- output for a call chain provided by way of a tracebacks array. procedure Set_Trace_Decorator (Decorator : Traceback_Decorator); - -- Set the decorator to be used for future automatic outputs. Restore - -- the default behavior (output of raw addresses) if the provided - -- access value is null. + -- Set the decorator to be used for future automatic outputs. Restore the + -- default behavior if the provided access value is null. -- -- Note: System.Traceback.Symbolic.Symbolic_Traceback may be used as the -- Decorator, to get a symbolic traceback. This will cause a significant - -- cpu and memory overhead. + -- cpu and memory overhead on some platforms. + -- + -- Note: The Decorator is called when constructing the + -- Exception_Information; that needs to be taken into account + -- if the Decorator has any side effects. end System.Exception_Traces; diff --git a/gcc/ada/sem_ch10.adb b/gcc/ada/sem_ch10.adb index bae9762f718..41ceb3d4cab 100644 --- a/gcc/ada/sem_ch10.adb +++ b/gcc/ada/sem_ch10.adb @@ -23,50 +23,50 @@ -- -- ------------------------------------------------------------------------------ -with Aspects; use Aspects; -with Atree; use Atree; -with Debug; use Debug; -with Einfo; use Einfo; -with Errout; use Errout; -with Exp_Util; use Exp_Util; -with Elists; use Elists; -with Fname; use Fname; -with Fname.UF; use Fname.UF; -with Freeze; use Freeze; -with Impunit; use Impunit; -with Inline; use Inline; -with Lib; use Lib; -with Lib.Load; use Lib.Load; -with Lib.Xref; use Lib.Xref; -with Namet; use Namet; -with Nlists; use Nlists; -with Nmake; use Nmake; -with Opt; use Opt; -with Output; use Output; -with Par_SCO; use Par_SCO; -with Restrict; use Restrict; -with Rident; use Rident; -with Rtsfind; use Rtsfind; -with Sem; use Sem; -with Sem_Aux; use Sem_Aux; -with Sem_Ch3; use Sem_Ch3; -with Sem_Ch6; use Sem_Ch6; -with Sem_Ch7; use Sem_Ch7; -with Sem_Ch8; use Sem_Ch8; -with Sem_Ch12; use Sem_Ch12; -with Sem_Dist; use Sem_Dist; -with Sem_Prag; use Sem_Prag; -with Sem_Util; use Sem_Util; -with Sem_Warn; use Sem_Warn; -with Stand; use Stand; -with Sinfo; use Sinfo; -with Sinfo.CN; use Sinfo.CN; -with Sinput; use Sinput; -with Snames; use Snames; -with Style; use Style; -with Stylesw; use Stylesw; -with Tbuild; use Tbuild; -with Uname; use Uname; +with Aspects; use Aspects; +with Atree; use Atree; +with Contracts; use Contracts; +with Debug; use Debug; +with Einfo; use Einfo; +with Errout; use Errout; +with Exp_Util; use Exp_Util; +with Elists; use Elists; +with Fname; use Fname; +with Fname.UF; use Fname.UF; +with Freeze; use Freeze; +with Impunit; use Impunit; +with Inline; use Inline; +with Lib; use Lib; +with Lib.Load; use Lib.Load; +with Lib.Xref; use Lib.Xref; +with Namet; use Namet; +with Nlists; use Nlists; +with Nmake; use Nmake; +with Opt; use Opt; +with Output; use Output; +with Par_SCO; use Par_SCO; +with Restrict; use Restrict; +with Rident; use Rident; +with Rtsfind; use Rtsfind; +with Sem; use Sem; +with Sem_Aux; use Sem_Aux; +with Sem_Ch3; use Sem_Ch3; +with Sem_Ch6; use Sem_Ch6; +with Sem_Ch7; use Sem_Ch7; +with Sem_Ch8; use Sem_Ch8; +with Sem_Dist; use Sem_Dist; +with Sem_Prag; use Sem_Prag; +with Sem_Util; use Sem_Util; +with Sem_Warn; use Sem_Warn; +with Stand; use Stand; +with Sinfo; use Sinfo; +with Sinfo.CN; use Sinfo.CN; +with Sinput; use Sinput; +with Snames; use Snames; +with Style; use Style; +with Stylesw; use Stylesw; +with Tbuild; use Tbuild; +with Uname; use Uname; package body Sem_Ch10 is @@ -940,15 +940,6 @@ package body Sem_Ch10 is N_Subprogram_Declaration) then Analyze_Subprogram_Contract (Defining_Entity (Unit_Node)); - - -- Capture all global references in a generic subprogram that acts as - -- a compilation unit now that the contract has been analyzed. - - if Is_Generic_Declaration_Or_Body (Unit_Node) then - Save_Global_References_In_Contract - (Templ => Original_Node (Unit_Node), - Gen_Id => Defining_Entity (Unit_Node)); - end if; end if; -- Generate distribution stubs if requested and no error @@ -2006,39 +1997,6 @@ package body Sem_Ch10 is Restore_Opt_Config_Switches (Opts); end Analyze_Subprogram_Body_Stub; - ------------------------------------------- - -- Analyze_Subprogram_Body_Stub_Contract -- - ------------------------------------------- - - procedure Analyze_Subprogram_Body_Stub_Contract (Stub_Id : Entity_Id) is - Stub_Decl : constant Node_Id := Parent (Parent (Stub_Id)); - Spec_Id : constant Entity_Id := Corresponding_Spec_Of_Stub (Stub_Decl); - - begin - -- A subprogram body stub may act as its own spec or as the completion - -- of a previous declaration. Depending on the context, the contract of - -- the stub may contain two sets of pragmas. - - -- The stub is a completion, the applicable pragmas are: - -- Refined_Depends - -- Refined_Global - - if Present (Spec_Id) then - Analyze_Subprogram_Body_Contract (Stub_Id); - - -- The stub acts as its own spec, the applicable pragmas are: - -- Contract_Cases - -- Depends - -- Global - -- Postcondition - -- Precondition - -- Test_Case - - else - Analyze_Subprogram_Contract (Stub_Id); - end if; - end Analyze_Subprogram_Body_Stub_Contract; - --------------------- -- Analyze_Subunit -- --------------------- diff --git a/gcc/ada/sem_ch10.ads b/gcc/ada/sem_ch10.ads index c003526ecbe..d4b28cde8af 100644 --- a/gcc/ada/sem_ch10.ads +++ b/gcc/ada/sem_ch10.ads @@ -6,7 +6,7 @@ -- -- -- S p e c -- -- -- --- Copyright (C) 1992-2014, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2015, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -24,6 +24,7 @@ ------------------------------------------------------------------------------ with Types; use Types; + package Sem_Ch10 is procedure Analyze_Compilation_Unit (N : Node_Id); procedure Analyze_With_Clause (N : Node_Id); @@ -33,19 +34,6 @@ package Sem_Ch10 is procedure Analyze_Protected_Body_Stub (N : Node_Id); procedure Analyze_Subunit (N : Node_Id); - procedure Analyze_Subprogram_Body_Stub_Contract (Stub_Id : Entity_Id); - -- Analyze all delayed aspects chained on the contract of a subprogram body - -- stub Stub_Id as if they appeared at the end of a declarative region. The - -- aspects in question are: - -- Contract_Cases - -- Depends - -- Global - -- Postcondition - -- Precondition - -- Refined_Depends - -- Refined_Global - -- Test_Case - procedure Install_Context (N : Node_Id); -- Installs the entities from the context clause of the given compilation -- unit into the visibility chains. This is done before analyzing a unit. diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb index 60bd94c1b3c..6891c64b225 100644 --- a/gcc/ada/sem_ch12.adb +++ b/gcc/ada/sem_ch12.adb @@ -23,60 +23,61 @@ -- -- ------------------------------------------------------------------------------ -with Aspects; use Aspects; -with Atree; use Atree; -with Einfo; use Einfo; -with Elists; use Elists; -with Errout; use Errout; -with Expander; use Expander; -with Exp_Disp; use Exp_Disp; -with Fname; use Fname; -with Fname.UF; use Fname.UF; -with Freeze; use Freeze; -with Ghost; use Ghost; -with Itypes; use Itypes; -with Lib; use Lib; -with Lib.Load; use Lib.Load; -with Lib.Xref; use Lib.Xref; -with Nlists; use Nlists; -with Namet; use Namet; -with Nmake; use Nmake; -with Opt; use Opt; -with Rident; use Rident; -with Restrict; use Restrict; -with Rtsfind; use Rtsfind; -with Sem; use Sem; -with Sem_Aux; use Sem_Aux; -with Sem_Cat; use Sem_Cat; -with Sem_Ch3; use Sem_Ch3; -with Sem_Ch6; use Sem_Ch6; -with Sem_Ch7; use Sem_Ch7; -with Sem_Ch8; use Sem_Ch8; -with Sem_Ch10; use Sem_Ch10; -with Sem_Ch13; use Sem_Ch13; -with Sem_Dim; use Sem_Dim; -with Sem_Disp; use Sem_Disp; -with Sem_Elab; use Sem_Elab; -with Sem_Elim; use Sem_Elim; -with Sem_Eval; use Sem_Eval; -with Sem_Prag; use Sem_Prag; -with Sem_Res; use Sem_Res; -with Sem_Type; use Sem_Type; -with Sem_Util; use Sem_Util; -with Sem_Warn; use Sem_Warn; -with Stand; use Stand; -with Sinfo; use Sinfo; -with Sinfo.CN; use Sinfo.CN; -with Sinput; use Sinput; -with Sinput.L; use Sinput.L; -with Snames; use Snames; -with Stringt; use Stringt; -with Uname; use Uname; +with Aspects; use Aspects; +with Atree; use Atree; +with Contracts; use Contracts; +with Einfo; use Einfo; +with Elists; use Elists; +with Errout; use Errout; +with Expander; use Expander; +with Exp_Disp; use Exp_Disp; +with Fname; use Fname; +with Fname.UF; use Fname.UF; +with Freeze; use Freeze; +with Ghost; use Ghost; +with Itypes; use Itypes; +with Lib; use Lib; +with Lib.Load; use Lib.Load; +with Lib.Xref; use Lib.Xref; +with Nlists; use Nlists; +with Namet; use Namet; +with Nmake; use Nmake; +with Opt; use Opt; +with Rident; use Rident; +with Restrict; use Restrict; +with Rtsfind; use Rtsfind; +with Sem; use Sem; +with Sem_Aux; use Sem_Aux; +with Sem_Cat; use Sem_Cat; +with Sem_Ch3; use Sem_Ch3; +with Sem_Ch6; use Sem_Ch6; +with Sem_Ch7; use Sem_Ch7; +with Sem_Ch8; use Sem_Ch8; +with Sem_Ch10; use Sem_Ch10; +with Sem_Ch13; use Sem_Ch13; +with Sem_Dim; use Sem_Dim; +with Sem_Disp; use Sem_Disp; +with Sem_Elab; use Sem_Elab; +with Sem_Elim; use Sem_Elim; +with Sem_Eval; use Sem_Eval; +with Sem_Prag; use Sem_Prag; +with Sem_Res; use Sem_Res; +with Sem_Type; use Sem_Type; +with Sem_Util; use Sem_Util; +with Sem_Warn; use Sem_Warn; +with Stand; use Stand; +with Sinfo; use Sinfo; +with Sinfo.CN; use Sinfo.CN; +with Sinput; use Sinput; +with Sinput.L; use Sinput.L; +with Snames; use Snames; +with Stringt; use Stringt; +with Uname; use Uname; with Table; -with Tbuild; use Tbuild; -with Uintp; use Uintp; -with Urealp; use Urealp; -with Warnsw; use Warnsw; +with Tbuild; use Tbuild; +with Uintp; use Uintp; +with Urealp; use Urealp; +with Warnsw; use Warnsw; with GNAT.HTable; @@ -842,10 +843,6 @@ package body Sem_Ch12 is -- Restore suffix 'P' to primitives of Prims_List and leave Prims_List -- set to No_Elist. - procedure Save_Global_References_In_Aspects (N : Node_Id); - -- Save all global references found within the expressions of all aspects - -- that appear on node N. - procedure Set_Instance_Env (Gen_Unit : Entity_Id; Act_Unit : Entity_Id); @@ -4803,11 +4800,6 @@ package body Sem_Ch12 is -- aspects that appear in the generic. This renaming declaration is -- inserted after the instance declaration which it renames. - procedure Instantiate_Subprogram_Contract (Templ : Node_Id); - -- Instantiate all source pragmas found in the contract of the generic - -- subprogram declaration template denoted by Templ. The instantiated - -- pragmas are added to list Renaming_List. - ------------------------------------ -- Analyze_Instance_And_Renamings -- ------------------------------------ @@ -5009,53 +5001,6 @@ package body Sem_Ch12 is end if; end Build_Subprogram_Renaming; - ------------------------------------- - -- Instantiate_Subprogram_Contract -- - ------------------------------------- - - procedure Instantiate_Subprogram_Contract (Templ : Node_Id) is - procedure Instantiate_Pragmas (First_Prag : Node_Id); - -- Instantiate all contract-related source pragmas found in the list - -- starting with pragma First_Prag. Each instantiated pragma is added - -- to list Renaming_List. - - ------------------------- - -- Instantiate_Pragmas -- - ------------------------- - - procedure Instantiate_Pragmas (First_Prag : Node_Id) is - Inst_Prag : Node_Id; - Prag : Node_Id; - - begin - Prag := First_Prag; - while Present (Prag) loop - if Is_Generic_Contract_Pragma (Prag) then - Inst_Prag := - Copy_Generic_Node (Prag, Empty, Instantiating => True); - - Set_Analyzed (Inst_Prag, False); - Append_To (Renaming_List, Inst_Prag); - end if; - - Prag := Next_Pragma (Prag); - end loop; - end Instantiate_Pragmas; - - -- Local variables - - Items : constant Node_Id := Contract (Defining_Entity (Templ)); - - -- Start of processing for Instantiate_Subprogram_Contract - - begin - if Present (Items) then - Instantiate_Pragmas (Pre_Post_Conditions (Items)); - Instantiate_Pragmas (Contract_Test_Cases (Items)); - Instantiate_Pragmas (Classifications (Items)); - end if; - end Instantiate_Subprogram_Contract; - -- Local variables Save_IPSM : constant Boolean := Ignore_Pragma_SPARK_Mode; @@ -5227,9 +5172,10 @@ package body Sem_Ch12 is -- must be instantiated explicitly because they are not part of the -- subprogram template. - Instantiate_Subprogram_Contract (Original_Node (Gen_Decl)); - Build_Subprogram_Renaming; + Instantiate_Subprogram_Contract + (Original_Node (Gen_Decl), Renaming_List); + Build_Subprogram_Renaming; Analyze_Instance_And_Renamings; -- If the generic is marked Import (Intrinsic), then so is the @@ -10888,9 +10834,12 @@ package body Sem_Ch12 is Copy_Generic_Node (Original_Node (Gen_Body), Empty, Instantiating => True); - -- Build new name (possibly qualified) for body declaration + -- Create proper (possibly qualified) defining name for the body, to + -- correspond to the one in the spec. - Act_Body_Id := New_Copy (Act_Decl_Id); + Act_Body_Id := + Make_Defining_Identifier (Sloc (Act_Decl_Id), Chars (Act_Decl_Id)); + Set_Comes_From_Source (Act_Body_Id, Comes_From_Source (Act_Decl_Id)); -- Some attributes of spec entity are not inherited by body entity @@ -10901,7 +10850,8 @@ package body Sem_Ch12 is then Act_Body_Name := Make_Defining_Program_Unit_Name (Loc, - Name => New_Copy_Tree (Name (Defining_Unit_Name (Act_Spec))), + Name => + New_Copy_Tree (Name (Defining_Unit_Name (Act_Spec))), Defining_Identifier => Act_Body_Id); else Act_Body_Name := Act_Body_Id; @@ -11109,7 +11059,7 @@ package body Sem_Ch12 is Gen_Id : constant Node_Id := Name (Inst_Node); Gen_Unit : constant Entity_Id := Get_Generic_Entity (Inst_Node); Gen_Decl : constant Node_Id := Unit_Declaration_Node (Gen_Unit); - Anon_Id : constant Entity_Id := + Act_Decl_Id : constant Entity_Id := Defining_Unit_Name (Specification (Act_Decl)); Pack_Id : constant Entity_Id := Defining_Unit_Name (Parent (Act_Decl)); @@ -11119,6 +11069,7 @@ package body Sem_Ch12 is Saved_Warnings : constant Warning_Record := Save_Warnings; Act_Body : Node_Id; + Act_Body_Id : Entity_Id; Gen_Body : Node_Id; Gen_Body_Id : Node_Id; Pack_Body : Node_Id; @@ -11160,11 +11111,11 @@ package body Sem_Ch12 is -- the spec entity appropriately. if Is_Imported (Gen_Unit) then - Set_Is_Imported (Anon_Id); - Set_First_Rep_Item (Anon_Id, First_Rep_Item (Gen_Unit)); - Set_Interface_Name (Anon_Id, Interface_Name (Gen_Unit)); - Set_Convention (Anon_Id, Convention (Gen_Unit)); - Set_Has_Completion (Anon_Id); + Set_Is_Imported (Act_Decl_Id); + Set_First_Rep_Item (Act_Decl_Id, First_Rep_Item (Gen_Unit)); + Set_Interface_Name (Act_Decl_Id, Interface_Name (Gen_Unit)); + Set_Convention (Act_Decl_Id, Convention (Gen_Unit)); + Set_Has_Completion (Act_Decl_Id); return; -- For other cases, compile the body @@ -11194,11 +11145,11 @@ package body Sem_Ch12 is ("missing proper body for instantiation", Gen_Body); end if; - Set_Has_Completion (Anon_Id); + Set_Has_Completion (Act_Decl_Id); return; end if; - Save_Env (Gen_Unit, Anon_Id); + Save_Env (Gen_Unit, Act_Decl_Id); Style_Check := False; -- If the context of the instance is subject to SPARK_Mode "off" or @@ -11221,14 +11172,17 @@ package body Sem_Ch12 is Copy_Generic_Node (Original_Node (Gen_Body), Empty, Instantiating => True); - -- Create proper defining name for the body, to correspond to - -- the one in the spec. + -- Create proper defining name for the body, to correspond to the one + -- in the spec. - Set_Defining_Unit_Name (Specification (Act_Body), - Make_Defining_Identifier - (Sloc (Defining_Entity (Inst_Node)), Chars (Anon_Id))); - Set_Corresponding_Spec (Act_Body, Anon_Id); - Set_Has_Completion (Anon_Id); + Act_Body_Id := + Make_Defining_Identifier (Sloc (Act_Decl_Id), Chars (Act_Decl_Id)); + + Set_Comes_From_Source (Act_Body_Id, Comes_From_Source (Act_Decl_Id)); + Set_Defining_Unit_Name (Specification (Act_Body), Act_Body_Id); + + Set_Corresponding_Spec (Act_Body, Act_Decl_Id); + Set_Has_Completion (Act_Decl_Id); Check_Generic_Actuals (Pack_Id, False); -- Generate a reference to link the visible subprogram instance to @@ -11327,16 +11281,16 @@ package body Sem_Ch12 is if Body_Optional then return; - elsif Ekind (Anon_Id) = E_Procedure then + elsif Ekind (Act_Decl_Id) = E_Procedure then Act_Body := Make_Subprogram_Body (Loc, Specification => Make_Procedure_Specification (Loc, Defining_Unit_Name => - Make_Defining_Identifier (Loc, Chars (Anon_Id)), + Make_Defining_Identifier (Loc, Chars (Act_Decl_Id)), Parameter_Specifications => New_Copy_List - (Parameter_Specifications (Parent (Anon_Id)))), + (Parameter_Specifications (Parent (Act_Decl_Id)))), Declarations => Empty_List, Handled_Statement_Sequence => @@ -11352,7 +11306,7 @@ package body Sem_Ch12 is Make_Raise_Program_Error (Loc, Reason => PE_Access_Before_Elaboration); - Set_Etype (Ret_Expr, (Etype (Anon_Id))); + Set_Etype (Ret_Expr, (Etype (Act_Decl_Id))); Set_Analyzed (Ret_Expr); Act_Body := @@ -11360,12 +11314,12 @@ package body Sem_Ch12 is Specification => Make_Function_Specification (Loc, Defining_Unit_Name => - Make_Defining_Identifier (Loc, Chars (Anon_Id)), + Make_Defining_Identifier (Loc, Chars (Act_Decl_Id)), Parameter_Specifications => New_Copy_List - (Parameter_Specifications (Parent (Anon_Id))), + (Parameter_Specifications (Parent (Act_Decl_Id))), Result_Definition => - New_Occurrence_Of (Etype (Anon_Id), Loc)), + New_Occurrence_Of (Etype (Act_Decl_Id), Loc)), Declarations => Empty_List, Handled_Statement_Sequence => @@ -14970,63 +14924,6 @@ package body Sem_Ch12 is end loop; end Save_Global_References_In_Aspects; - ---------------------------------------- - -- Save_Global_References_In_Contract -- - ---------------------------------------- - - procedure Save_Global_References_In_Contract - (Templ : Node_Id; - Gen_Id : Entity_Id) - is - procedure Save_Global_References_In_List (First_Prag : Node_Id); - -- Save all global references in contract-related source pragmas found - -- in the list starting with pragma First_Prag. - - ------------------------------------ - -- Save_Global_References_In_List -- - ------------------------------------ - - procedure Save_Global_References_In_List (First_Prag : Node_Id) is - Prag : Node_Id; - - begin - Prag := First_Prag; - while Present (Prag) loop - if Is_Generic_Contract_Pragma (Prag) then - Save_Global_References (Prag); - end if; - - Prag := Next_Pragma (Prag); - end loop; - end Save_Global_References_In_List; - - -- Local variables - - Items : constant Node_Id := Contract (Defining_Entity (Templ)); - - -- Start of processing for Save_Global_References_In_Contract - - begin - -- The entity of the analyzed generic copy must be on the scope stack - -- to ensure proper detection of global references. - - Push_Scope (Gen_Id); - - if Permits_Aspect_Specifications (Templ) - and then Has_Aspects (Templ) - then - Save_Global_References_In_Aspects (Templ); - end if; - - if Present (Items) then - Save_Global_References_In_List (Pre_Post_Conditions (Items)); - Save_Global_References_In_List (Contract_Test_Cases (Items)); - Save_Global_References_In_List (Classifications (Items)); - end if; - - Pop_Scope; - end Save_Global_References_In_Contract; - -------------------------------------- -- Set_Copied_Sloc_For_Inlined_Body -- -------------------------------------- diff --git a/gcc/ada/sem_ch12.ads b/gcc/ada/sem_ch12.ads index 53ff6c50e95..c54d7359dee 100644 --- a/gcc/ada/sem_ch12.ads +++ b/gcc/ada/sem_ch12.ads @@ -152,12 +152,9 @@ package Sem_Ch12 is -- restored in stack-like fashion. Front-end inlining also uses these -- structures for the management of private/full views. - procedure Save_Global_References_In_Contract - (Templ : Node_Id; - Gen_Id : Entity_Id); - -- Save all global references found within the aspect specifications and - -- the contract-related source pragmas assocated with generic template - -- Templ. Gen_Id denotes the entity of the analyzed generic copy. + procedure Save_Global_References_In_Aspects (N : Node_Id); + -- Save all global references found within the expressions of all aspects + -- that appear on node N. procedure Set_Copied_Sloc_For_Inlined_Body (N : Node_Id; E : Entity_Id); -- This procedure is used when a subprogram body is inlined. This process diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb index 82c3dd8254b..43553290f69 100644 --- a/gcc/ada/sem_ch3.adb +++ b/gcc/ada/sem_ch3.adb @@ -23,64 +23,62 @@ -- -- ------------------------------------------------------------------------------ -with Aspects; use Aspects; -with Atree; use Atree; -with Checks; use Checks; -with Debug; use Debug; -with Elists; use Elists; -with Einfo; use Einfo; -with Errout; use Errout; -with Eval_Fat; use Eval_Fat; -with Exp_Ch3; use Exp_Ch3; -with Exp_Ch9; use Exp_Ch9; -with Exp_Disp; use Exp_Disp; -with Exp_Dist; use Exp_Dist; -with Exp_Tss; use Exp_Tss; -with Exp_Util; use Exp_Util; -with Fname; use Fname; -with Freeze; use Freeze; -with Ghost; use Ghost; -with Itypes; use Itypes; -with Layout; use Layout; -with Lib; use Lib; -with Lib.Xref; use Lib.Xref; -with Namet; use Namet; -with Nmake; use Nmake; -with Opt; use Opt; -with Restrict; use Restrict; -with Rident; use Rident; -with Rtsfind; use Rtsfind; -with Sem; use Sem; -with Sem_Aux; use Sem_Aux; -with Sem_Case; use Sem_Case; -with Sem_Cat; use Sem_Cat; -with Sem_Ch6; use Sem_Ch6; -with Sem_Ch7; use Sem_Ch7; -with Sem_Ch8; use Sem_Ch8; -with Sem_Ch10; use Sem_Ch10; -with Sem_Ch12; use Sem_Ch12; -with Sem_Ch13; use Sem_Ch13; -with Sem_Dim; use Sem_Dim; -with Sem_Disp; use Sem_Disp; -with Sem_Dist; use Sem_Dist; -with Sem_Elim; use Sem_Elim; -with Sem_Eval; use Sem_Eval; -with Sem_Mech; use Sem_Mech; -with Sem_Prag; use Sem_Prag; -with Sem_Res; use Sem_Res; -with Sem_Smem; use Sem_Smem; -with Sem_Type; use Sem_Type; -with Sem_Util; use Sem_Util; -with Sem_Warn; use Sem_Warn; -with Stand; use Stand; -with Sinfo; use Sinfo; -with Sinput; use Sinput; -with Snames; use Snames; -with Targparm; use Targparm; -with Tbuild; use Tbuild; -with Ttypes; use Ttypes; -with Uintp; use Uintp; -with Urealp; use Urealp; +with Aspects; use Aspects; +with Atree; use Atree; +with Checks; use Checks; +with Contracts; use Contracts; +with Debug; use Debug; +with Elists; use Elists; +with Einfo; use Einfo; +with Errout; use Errout; +with Eval_Fat; use Eval_Fat; +with Exp_Ch3; use Exp_Ch3; +with Exp_Ch9; use Exp_Ch9; +with Exp_Disp; use Exp_Disp; +with Exp_Dist; use Exp_Dist; +with Exp_Tss; use Exp_Tss; +with Exp_Util; use Exp_Util; +with Fname; use Fname; +with Freeze; use Freeze; +with Ghost; use Ghost; +with Itypes; use Itypes; +with Layout; use Layout; +with Lib; use Lib; +with Lib.Xref; use Lib.Xref; +with Namet; use Namet; +with Nmake; use Nmake; +with Opt; use Opt; +with Restrict; use Restrict; +with Rident; use Rident; +with Rtsfind; use Rtsfind; +with Sem; use Sem; +with Sem_Aux; use Sem_Aux; +with Sem_Case; use Sem_Case; +with Sem_Cat; use Sem_Cat; +with Sem_Ch6; use Sem_Ch6; +with Sem_Ch7; use Sem_Ch7; +with Sem_Ch8; use Sem_Ch8; +with Sem_Ch13; use Sem_Ch13; +with Sem_Dim; use Sem_Dim; +with Sem_Disp; use Sem_Disp; +with Sem_Dist; use Sem_Dist; +with Sem_Elim; use Sem_Elim; +with Sem_Eval; use Sem_Eval; +with Sem_Mech; use Sem_Mech; +with Sem_Res; use Sem_Res; +with Sem_Smem; use Sem_Smem; +with Sem_Type; use Sem_Type; +with Sem_Util; use Sem_Util; +with Sem_Warn; use Sem_Warn; +with Stand; use Stand; +with Sinfo; use Sinfo; +with Sinput; use Sinput; +with Snames; use Snames; +with Targparm; use Targparm; +with Tbuild; use Tbuild; +with Ttypes; use Ttypes; +with Uintp; use Uintp; +with Urealp; use Urealp; package body Sem_Ch3 is @@ -93,16 +91,6 @@ package body Sem_Ch3 is -- abstract interface types implemented by a record type or a derived -- record type. - procedure Analyze_Object_Contract (Obj_Id : Entity_Id); - -- Analyze all delayed pragmas chained on the contract of object Obj_Id as - -- if they appeared at the end of the declarative region. The pragmas to be - -- considered are: - -- Async_Readers - -- Async_Writers - -- Effective_Reads - -- Effective_Writes - -- Part_Of - procedure Build_Derived_Type (N : Node_Id; Parent_Type : Entity_Id; @@ -2306,7 +2294,6 @@ package body Sem_Ch3 is Context : Node_Id := Empty; Freeze_From : Entity_Id := Empty; Next_Decl : Node_Id; - Pack_Decl : Node_Id := Empty; Body_Seen : Boolean := False; -- Flag set when the first body [stub] is encountered @@ -2477,7 +2464,6 @@ package body Sem_Ch3 is Context := Parent (L); if Nkind (Context) = N_Package_Specification then - Pack_Decl := Parent (Context); -- When a package has private declarations, its contract must be -- analyzed at the end of the said declarations. This way both the @@ -2506,14 +2492,12 @@ package body Sem_Ch3 is end if; elsif Nkind (Context) = N_Package_Body then - Pack_Decl := Context; Analyze_Package_Body_Contract (Defining_Entity (Context)); end if; -- Analyze the contracts of all subprogram declarations, subprogram - -- bodies and variables now due to the delayed visibility needs of - -- of their aspects and pragmas. Capture global references in generic - -- subprograms or bodies. + -- bodies and variables due to the delayed visibility needs of their + -- aspects and pragmas. Decl := First (L); while Present (Decl) loop @@ -2533,43 +2517,21 @@ package body Sem_Ch3 is Analyze_Subprogram_Body_Stub_Contract (Defining_Entity (Decl)); end if; - -- Capture all global references in a generic subprogram or a body - -- [stub] now that the contract has been analyzed. - - if Nkind_In (Decl, N_Generic_Subprogram_Declaration, - N_Subprogram_Body, - N_Subprogram_Body_Stub) - and then Is_Generic_Declaration_Or_Body (Decl) - then - Save_Global_References_In_Contract - (Templ => Original_Node (Decl), - Gen_Id => Corresponding_Spec_Of (Decl)); - end if; - Next (Decl); end loop; - -- The owner of the declarations is a package [body] + if Nkind (Context) = N_Package_Body then - if Present (Pack_Decl) then + -- Ensure that all abstract states and objects declared in the + -- state space of a package body are utilized as constituents. - -- Capture all global references in a generic package or a body - -- after all nested generic subprograms and bodies were subjected - -- to the same processing. - - if Is_Generic_Declaration_Or_Body (Pack_Decl) then - Save_Global_References_In_Contract - (Templ => Original_Node (Pack_Decl), - Gen_Id => Corresponding_Spec_Of (Pack_Decl)); - end if; + Check_Unused_Body_States (Defining_Entity (Context)); -- State refinements are visible upto the end the of the package -- body declarations. Hide the state refinements from visibility -- to restore the original state conditions. - if Nkind (Pack_Decl) = N_Package_Body then - Remove_Visible_Refinements (Corresponding_Spec (Pack_Decl)); - end if; + Remove_Visible_Refinements (Corresponding_Spec (Context)); end if; end if; end Analyze_Declarations; @@ -3288,173 +3250,6 @@ package body Sem_Ch3 is end if; end Analyze_Number_Declaration; - ----------------------------- - -- Analyze_Object_Contract -- - ----------------------------- - - procedure Analyze_Object_Contract (Obj_Id : Entity_Id) is - Obj_Typ : constant Entity_Id := Etype (Obj_Id); - AR_Val : Boolean := False; - AW_Val : Boolean := False; - ER_Val : Boolean := False; - EW_Val : Boolean := False; - Prag : Node_Id; - Seen : Boolean := False; - - begin - -- The loop parameter in an element iterator over a formal container - -- is declared with an object declaration but no contracts apply. - - if Ekind (Obj_Id) = E_Loop_Parameter then - return; - end if; - - -- Constant related checks - - if Ekind (Obj_Id) = E_Constant then - - -- A constant cannot be effectively volatile (SPARK RM 7.1.3(4)). - -- This check is relevant only when SPARK_Mode is on as it is not a - -- standard Ada legality rule. Internally-generated constants that - -- map generic formals to actuals in instantiations are allowed to - -- be volatile. - - if SPARK_Mode = On - and then Comes_From_Source (Obj_Id) - and then Is_Effectively_Volatile (Obj_Id) - and then No (Corresponding_Generic_Association (Parent (Obj_Id))) - then - Error_Msg_N ("constant cannot be volatile", Obj_Id); - end if; - - -- Variable related checks - - else pragma Assert (Ekind (Obj_Id) = E_Variable); - - -- The following checks are relevant only when SPARK_Mode is on as - -- they are not standard Ada legality rules. Internally generated - -- temporaries are ignored. - - if SPARK_Mode = On and then Comes_From_Source (Obj_Id) then - if Is_Effectively_Volatile (Obj_Id) then - - -- The declaration of an effectively volatile object must - -- appear at the library level (SPARK RM 7.1.3(3), C.6(6)). - - if not Is_Library_Level_Entity (Obj_Id) then - Error_Msg_N - ("volatile variable & must be declared at library level", - Obj_Id); - - -- An object of a discriminated type cannot be effectively - -- volatile except for protected objects (SPARK RM 7.1.3(5)). - - elsif Has_Discriminants (Obj_Typ) - and then not Is_Protected_Type (Obj_Typ) - then - Error_Msg_N - ("discriminated object & cannot be volatile", Obj_Id); - - -- An object of a tagged type cannot be effectively volatile - -- (SPARK RM C.6(5)). - - elsif Is_Tagged_Type (Obj_Typ) then - Error_Msg_N ("tagged object & cannot be volatile", Obj_Id); - end if; - - -- The object is not effectively volatile - - else - -- A non-effectively volatile object cannot have effectively - -- volatile components (SPARK RM 7.1.3(6)). - - if not Is_Effectively_Volatile (Obj_Id) - and then Has_Volatile_Component (Obj_Typ) - then - Error_Msg_N - ("non-volatile object & cannot have volatile components", - Obj_Id); - end if; - end if; - end if; - - if Is_Ghost_Entity (Obj_Id) then - - -- A Ghost object cannot be effectively volatile (SPARK RM 6.9(8)) - - if Is_Effectively_Volatile (Obj_Id) then - Error_Msg_N ("ghost variable & cannot be volatile", Obj_Id); - - -- A Ghost object cannot be imported or exported (SPARK RM 6.9(8)) - - elsif Is_Imported (Obj_Id) then - Error_Msg_N ("ghost object & cannot be imported", Obj_Id); - - elsif Is_Exported (Obj_Id) then - Error_Msg_N ("ghost object & cannot be exported", Obj_Id); - end if; - end if; - - -- Analyze all external properties - - Prag := Get_Pragma (Obj_Id, Pragma_Async_Readers); - - if Present (Prag) then - Analyze_External_Property_In_Decl_Part (Prag, AR_Val); - Seen := True; - end if; - - Prag := Get_Pragma (Obj_Id, Pragma_Async_Writers); - - if Present (Prag) then - Analyze_External_Property_In_Decl_Part (Prag, AW_Val); - Seen := True; - end if; - - Prag := Get_Pragma (Obj_Id, Pragma_Effective_Reads); - - if Present (Prag) then - Analyze_External_Property_In_Decl_Part (Prag, ER_Val); - Seen := True; - end if; - - Prag := Get_Pragma (Obj_Id, Pragma_Effective_Writes); - - if Present (Prag) then - Analyze_External_Property_In_Decl_Part (Prag, EW_Val); - Seen := True; - end if; - - -- Verify the mutual interaction of the various external properties - - if Seen then - Check_External_Properties (Obj_Id, AR_Val, AW_Val, ER_Val, EW_Val); - end if; - end if; - - -- Check whether the lack of indicator Part_Of agrees with the placement - -- of the object with respect to the state space. - - Prag := Get_Pragma (Obj_Id, Pragma_Part_Of); - - if No (Prag) then - Check_Missing_Part_Of (Obj_Id); - end if; - - -- A ghost object cannot be imported or exported (SPARK RM 6.9(8)). One - -- exception to this is the object that represents the dispatch table of - -- a Ghost tagged type as the symbol needs to be exported. - - if Comes_From_Source (Obj_Id) and then Is_Ghost_Entity (Obj_Id) then - if Is_Exported (Obj_Id) then - Error_Msg_N ("ghost object & cannot be exported", Obj_Id); - - elsif Is_Imported (Obj_Id) then - Error_Msg_N ("ghost object & cannot be imported", Obj_Id); - end if; - end if; - end Analyze_Object_Contract; - -------------------------------- -- Analyze_Object_Declaration -- -------------------------------- diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb index 30be33330c8..283b770d611 100644 --- a/gcc/ada/sem_ch6.adb +++ b/gcc/ada/sem_ch6.adb @@ -23,70 +23,71 @@ -- -- ------------------------------------------------------------------------------ -with Aspects; use Aspects; -with Atree; use Atree; -with Checks; use Checks; -with Debug; use Debug; -with Einfo; use Einfo; -with Elists; use Elists; -with Errout; use Errout; -with Expander; use Expander; -with Exp_Ch6; use Exp_Ch6; -with Exp_Ch7; use Exp_Ch7; -with Exp_Ch9; use Exp_Ch9; -with Exp_Dbug; use Exp_Dbug; -with Exp_Disp; use Exp_Disp; -with Exp_Tss; use Exp_Tss; -with Exp_Util; use Exp_Util; -with Fname; use Fname; -with Freeze; use Freeze; -with Ghost; use Ghost; -with Inline; use Inline; -with Itypes; use Itypes; -with Lib.Xref; use Lib.Xref; -with Layout; use Layout; -with Namet; use Namet; -with Lib; use Lib; -with Nlists; use Nlists; -with Nmake; use Nmake; -with Opt; use Opt; -with Output; use Output; -with Restrict; use Restrict; -with Rident; use Rident; -with Rtsfind; use Rtsfind; -with Sem; use Sem; -with Sem_Aux; use Sem_Aux; -with Sem_Cat; use Sem_Cat; -with Sem_Ch3; use Sem_Ch3; -with Sem_Ch4; use Sem_Ch4; -with Sem_Ch5; use Sem_Ch5; -with Sem_Ch8; use Sem_Ch8; -with Sem_Ch10; use Sem_Ch10; -with Sem_Ch12; use Sem_Ch12; -with Sem_Ch13; use Sem_Ch13; -with Sem_Dim; use Sem_Dim; -with Sem_Disp; use Sem_Disp; -with Sem_Dist; use Sem_Dist; -with Sem_Elim; use Sem_Elim; -with Sem_Eval; use Sem_Eval; -with Sem_Mech; use Sem_Mech; -with Sem_Prag; use Sem_Prag; -with Sem_Res; use Sem_Res; -with Sem_Util; use Sem_Util; -with Sem_Type; use Sem_Type; -with Sem_Warn; use Sem_Warn; -with Sinput; use Sinput; -with Stand; use Stand; -with Sinfo; use Sinfo; -with Sinfo.CN; use Sinfo.CN; -with Snames; use Snames; -with Stringt; use Stringt; +with Aspects; use Aspects; +with Atree; use Atree; +with Checks; use Checks; +with Contracts; use Contracts; +with Debug; use Debug; +with Einfo; use Einfo; +with Elists; use Elists; +with Errout; use Errout; +with Expander; use Expander; +with Exp_Ch6; use Exp_Ch6; +with Exp_Ch7; use Exp_Ch7; +with Exp_Ch9; use Exp_Ch9; +with Exp_Dbug; use Exp_Dbug; +with Exp_Disp; use Exp_Disp; +with Exp_Tss; use Exp_Tss; +with Exp_Util; use Exp_Util; +with Fname; use Fname; +with Freeze; use Freeze; +with Ghost; use Ghost; +with Inline; use Inline; +with Itypes; use Itypes; +with Lib.Xref; use Lib.Xref; +with Layout; use Layout; +with Namet; use Namet; +with Lib; use Lib; +with Nlists; use Nlists; +with Nmake; use Nmake; +with Opt; use Opt; +with Output; use Output; +with Restrict; use Restrict; +with Rident; use Rident; +with Rtsfind; use Rtsfind; +with Sem; use Sem; +with Sem_Aux; use Sem_Aux; +with Sem_Cat; use Sem_Cat; +with Sem_Ch3; use Sem_Ch3; +with Sem_Ch4; use Sem_Ch4; +with Sem_Ch5; use Sem_Ch5; +with Sem_Ch8; use Sem_Ch8; +with Sem_Ch10; use Sem_Ch10; +with Sem_Ch12; use Sem_Ch12; +with Sem_Ch13; use Sem_Ch13; +with Sem_Dim; use Sem_Dim; +with Sem_Disp; use Sem_Disp; +with Sem_Dist; use Sem_Dist; +with Sem_Elim; use Sem_Elim; +with Sem_Eval; use Sem_Eval; +with Sem_Mech; use Sem_Mech; +with Sem_Prag; use Sem_Prag; +with Sem_Res; use Sem_Res; +with Sem_Util; use Sem_Util; +with Sem_Type; use Sem_Type; +with Sem_Warn; use Sem_Warn; +with Sinput; use Sinput; +with Stand; use Stand; +with Sinfo; use Sinfo; +with Sinfo.CN; use Sinfo.CN; +with Snames; use Snames; +with Stringt; use Stringt; with Style; -with Stylesw; use Stylesw; -with Tbuild; use Tbuild; -with Uintp; use Uintp; -with Urealp; use Urealp; -with Validsw; use Validsw; +with Stylesw; use Stylesw; +with Tbuild; use Tbuild; +with Uintp; use Uintp; +with Urealp; use Urealp; +with Validsw; use Validsw; package body Sem_Ch6 is @@ -1377,23 +1378,11 @@ package body Sem_Ch6 is Analyze_Declarations (Declarations (N)); Check_Completion; - -- When a generic subprogram body appears inside a package, its - -- contract is analyzed at the end of the package body declarations. - -- This is due to the delay with respect of the package contract upon - -- which the body contract may depend. When the generic subprogram - -- body is a compilation unit, this delay is not necessary. + -- Process the contract of the subprogram body after all declarations + -- have been analyzed. This ensures that any contract-related pragmas + -- are available through the N_Contract node of the body. - if Nkind (Parent (N)) = N_Compilation_Unit then - Analyze_Subprogram_Body_Contract (Body_Id); - - -- Capture all global references in a generic subprogram body - -- that acts as a compilation unit now that the contract has - -- been analyzed. - - Save_Global_References_In_Contract - (Templ => Original_Node (N), - Gen_Id => Gen_Id); - end if; + Analyze_Subprogram_Body_Contract (Body_Id); Analyze (Handled_Statement_Sequence (N)); Save_Global_References (Original_Node (N)); @@ -2220,102 +2209,6 @@ package body Sem_Ch6 is end if; end Analyze_Subprogram_Body; - -------------------------------------- - -- Analyze_Subprogram_Body_Contract -- - -------------------------------------- - - procedure Analyze_Subprogram_Body_Contract (Body_Id : Entity_Id) is - Items : constant Node_Id := Contract (Body_Id); - Mode : SPARK_Mode_Type; - Prag : Node_Id; - Prag_Nam : Name_Id; - Ref_Depends : Node_Id := Empty; - Ref_Global : Node_Id := Empty; - - begin - -- When a subprogram body declaration is illegal, its defining entity is - -- left unanalyzed. There is nothing left to do in this case because the - -- body lacks a contract, or even a proper Ekind. - - if Ekind (Body_Id) = E_Void then - return; - end if; - - -- Due to the timing of contract analysis, delayed pragmas may be - -- subject to the wrong SPARK_Mode, usually that of the enclosing - -- context. To remedy this, restore the original SPARK_Mode of the - -- related subprogram body. - - Save_SPARK_Mode_And_Set (Body_Id, Mode); - - -- All subprograms carry a contract, but for some it is not significant - -- and should not be processed. - - if not Has_Significant_Contract (Body_Id) then - null; - - -- The subprogram body is a completion, analyze all delayed pragmas that - -- apply. Note that when the body is stand alone, the pragmas are always - -- analyzed on the spot. - - elsif Present (Items) then - - -- Locate and store pragmas Refined_Depends and Refined_Global since - -- their order of analysis matters. - - Prag := Classifications (Items); - while Present (Prag) loop - Prag_Nam := Pragma_Name (Prag); - - if Prag_Nam = Name_Refined_Depends then - Ref_Depends := Prag; - - elsif Prag_Nam = Name_Refined_Global then - Ref_Global := Prag; - end if; - - Prag := Next_Pragma (Prag); - end loop; - - -- Analyze Refined_Global first as Refined_Depends may mention items - -- classified in the global refinement. - - if Present (Ref_Global) then - Analyze_Refined_Global_In_Decl_Part (Ref_Global); - end if; - - -- Refined_Depends must be analyzed after Refined_Global in order to - -- see the modes of all global refinements. - - if Present (Ref_Depends) then - Analyze_Refined_Depends_In_Decl_Part (Ref_Depends); - end if; - end if; - - -- Ensure that the contract cases or postconditions mention 'Result or - -- define a post-state. - - Check_Result_And_Post_State (Body_Id); - - -- A stand alone non-volatile function body cannot have an effectively - -- volatile formal parameter or return type (SPARK RM 7.1.3(9)). This - -- check is relevant only when SPARK_Mode is on as it is not a standard - -- legality rule. The check is performed here because Volatile_Function - -- is processed after the analysis of the related subprogram body. - - if SPARK_Mode = On - and then Ekind_In (Body_Id, E_Function, E_Generic_Function) - and then not Is_Volatile_Function (Body_Id) - then - Check_Nonvolatile_Function_Profile (Body_Id); - end if; - - -- Restore the SPARK_Mode of the enclosing context after all delayed - -- pragmas have been analyzed. - - Restore_SPARK_Mode (Mode); - end Analyze_Subprogram_Body_Contract; - ------------------------------------ -- Analyze_Subprogram_Body_Helper -- ------------------------------------ @@ -3102,6 +2995,24 @@ package body Sem_Ch6 is -- Start of processing for Analyze_Subprogram_Body_Helper begin + -- A [generic] subprogram body "freezes" the contract of the nearest + -- enclosing package body: + + -- package body Nearest_Enclosing_Package + -- with Refined_State => (State => Constit) + -- is + -- Constit : ...; + + -- procedure Freezes_Enclosing_Package_Body + -- with Refined_Depends => (Input => Constit) ... + + -- This ensures that any annotations referenced by the contract of the + -- [generic] subprogram body are available. This form of "freezing" is + -- decoupled from the usual Freeze_xxx mechanism because it must also + -- work in the context of generics where normal freezing is disabled. + + Analyze_Enclosing_Package_Body_Contract (N); + -- Generic subprograms are handled separately. They always have a -- generic specification. Determine whether current scope has a -- previous declaration. @@ -3842,23 +3753,11 @@ package body Sem_Ch6 is end if; end if; - -- When a subprogram body appears inside a package, its contract is - -- analyzed at the end of the package body declarations. This is due - -- to the delay with respect of the package contract upon which the - -- body contract may depend. When the subprogram body is stand alone - -- and acts as a compilation unit, this delay is not necessary. + -- A subprogram body "freezes" its own contract. Analyze the contract + -- after the declarations of the body have been processed as pragmas + -- are now chained on the contract of the subprogram body. - if Nkind (Parent (N)) = N_Compilation_Unit then - Analyze_Subprogram_Body_Contract (Body_Id); - end if; - - -- Deal with preconditions, [refined] postconditions, Contract_Cases, - -- invariants and predicates associated with body and its spec. Since - -- there is no routine Expand_Declarations which would otherwise deal - -- with the contract expansion, generate all necessary mechanisms to - -- verify the contract assertions now. - - Expand_Subprogram_Contract (N); + Analyze_Subprogram_Body_Contract (Body_Id); -- If SPARK_Mode for body is not On, disable frontend inlining for this -- subprogram in GNATprove mode, as its body should not be analyzed. @@ -4096,116 +3995,6 @@ package body Sem_Ch6 is Ghost_Mode := Save_Ghost_Mode; end Analyze_Subprogram_Body_Helper; - --------------------------------- - -- Analyze_Subprogram_Contract -- - --------------------------------- - - procedure Analyze_Subprogram_Contract (Subp_Id : Entity_Id) is - Items : constant Node_Id := Contract (Subp_Id); - Depends : Node_Id := Empty; - Global : Node_Id := Empty; - Mode : SPARK_Mode_Type; - Prag : Node_Id; - Prag_Nam : Name_Id; - - begin - -- Due to the timing of contract analysis, delayed pragmas may be - -- subject to the wrong SPARK_Mode, usually that of the enclosing - -- context. To remedy this, restore the original SPARK_Mode of the - -- related subprogram body. - - Save_SPARK_Mode_And_Set (Subp_Id, Mode); - - -- All subprograms carry a contract, but for some it is not significant - -- and should not be processed. - - if not Has_Significant_Contract (Subp_Id) then - null; - - elsif Present (Items) then - - -- Analyze pre- and postconditions - - Prag := Pre_Post_Conditions (Items); - while Present (Prag) loop - Analyze_Pre_Post_Condition_In_Decl_Part (Prag); - Prag := Next_Pragma (Prag); - end loop; - - -- Analyze contract-cases and test-cases - - Prag := Contract_Test_Cases (Items); - while Present (Prag) loop - Prag_Nam := Pragma_Name (Prag); - - if Prag_Nam = Name_Contract_Cases then - Analyze_Contract_Cases_In_Decl_Part (Prag); - else - pragma Assert (Prag_Nam = Name_Test_Case); - Analyze_Test_Case_In_Decl_Part (Prag); - end if; - - Prag := Next_Pragma (Prag); - end loop; - - -- Analyze classification pragmas - - Prag := Classifications (Items); - while Present (Prag) loop - Prag_Nam := Pragma_Name (Prag); - - if Prag_Nam = Name_Depends then - Depends := Prag; - - elsif Prag_Nam = Name_Global then - Global := Prag; - - -- Note that pragma Extensions_Visible has already been analyzed - - end if; - - Prag := Next_Pragma (Prag); - end loop; - - -- Analyze Global first as Depends may mention items classified in - -- the global categorization. - - if Present (Global) then - Analyze_Global_In_Decl_Part (Global); - end if; - - -- Depends must be analyzed after Global in order to see the modes of - -- all global items. - - if Present (Depends) then - Analyze_Depends_In_Decl_Part (Depends); - end if; - - -- Ensure that the contract cases or postconditions mention 'Result - -- or define a post-state. - - Check_Result_And_Post_State (Subp_Id); - end if; - - -- A non-volatile function cannot have an effectively volatile formal - -- parameter or return type (SPARK RM 7.1.3(9)). This check is relevant - -- only when SPARK_Mode is on as it is not a standard legality rule. The - -- check is performed here because pragma Volatile_Function is processed - -- after the analysis of the related subprogram declaration. - - if SPARK_Mode = On - and then Ekind_In (Subp_Id, E_Function, E_Generic_Function) - and then not Is_Volatile_Function (Subp_Id) - then - Check_Nonvolatile_Function_Profile (Subp_Id); - end if; - - -- Restore the SPARK_Mode of the enclosing context after all delayed - -- pragmas have been analyzed. - - Restore_SPARK_Mode (Mode); - end Analyze_Subprogram_Contract; - ------------------------------------ -- Analyze_Subprogram_Declaration -- ------------------------------------ diff --git a/gcc/ada/sem_ch6.ads b/gcc/ada/sem_ch6.ads index 427559e527b..ff24ed83acc 100644 --- a/gcc/ada/sem_ch6.ads +++ b/gcc/ada/sem_ch6.ads @@ -45,31 +45,6 @@ package Sem_Ch6 is procedure Analyze_Subprogram_Declaration (N : Node_Id); procedure Analyze_Subprogram_Body (N : Node_Id); - procedure Analyze_Subprogram_Body_Contract (Body_Id : Entity_Id); - -- Analyze all delayed aspects chained on the contract of subprogram body - -- Body_Id as if they appeared at the end of a declarative region. Aspects - -- in question are: - -- Contract_Cases (stand alone body) - -- Depends (stand alone body) - -- Global (stand alone body) - -- Postcondition (stand alone body) - -- Precondition (stand alone body) - -- Refined_Depends - -- Refined_Global - -- Refined_Post - -- Test_Case (stand alone body) - - procedure Analyze_Subprogram_Contract (Subp_Id : Entity_Id); - -- Analyze all delayed aspects chained on the contract of subprogram - -- Subp_Id as if they appeared at the end of a declarative region. The - -- aspects in question are: - -- Contract_Cases - -- Depends - -- Global - -- Postcondition - -- Precondition - -- Test_Case - function Analyze_Subprogram_Specification (N : Node_Id) return Entity_Id; -- Analyze subprogram specification in both subprogram declarations -- and body declarations. Returns the defining entity for the diff --git a/gcc/ada/sem_ch7.adb b/gcc/ada/sem_ch7.adb index a3870e89500..5814bc8eee3 100644 --- a/gcc/ada/sem_ch7.adb +++ b/gcc/ada/sem_ch7.adb @@ -28,44 +28,45 @@ -- handling of private and full declarations, and the construction of dispatch -- tables for tagged types. -with Aspects; use Aspects; -with Atree; use Atree; -with Debug; use Debug; -with Einfo; use Einfo; -with Elists; use Elists; -with Errout; use Errout; -with Exp_Disp; use Exp_Disp; -with Exp_Dist; use Exp_Dist; -with Exp_Dbug; use Exp_Dbug; -with Ghost; use Ghost; -with Lib; use Lib; -with Lib.Xref; use Lib.Xref; -with Namet; use Namet; -with Nmake; use Nmake; -with Nlists; use Nlists; -with Opt; use Opt; -with Output; use Output; -with Restrict; use Restrict; -with Sem; use Sem; -with Sem_Aux; use Sem_Aux; -with Sem_Cat; use Sem_Cat; -with Sem_Ch3; use Sem_Ch3; -with Sem_Ch6; use Sem_Ch6; -with Sem_Ch8; use Sem_Ch8; -with Sem_Ch10; use Sem_Ch10; -with Sem_Ch12; use Sem_Ch12; -with Sem_Ch13; use Sem_Ch13; -with Sem_Disp; use Sem_Disp; -with Sem_Eval; use Sem_Eval; -with Sem_Prag; use Sem_Prag; -with Sem_Util; use Sem_Util; -with Sem_Warn; use Sem_Warn; -with Snames; use Snames; -with Stand; use Stand; -with Sinfo; use Sinfo; -with Sinput; use Sinput; +with Aspects; use Aspects; +with Atree; use Atree; +with Contracts; use Contracts; +with Debug; use Debug; +with Einfo; use Einfo; +with Elists; use Elists; +with Errout; use Errout; +with Exp_Disp; use Exp_Disp; +with Exp_Dist; use Exp_Dist; +with Exp_Dbug; use Exp_Dbug; +with Ghost; use Ghost; +with Lib; use Lib; +with Lib.Xref; use Lib.Xref; +with Namet; use Namet; +with Nmake; use Nmake; +with Nlists; use Nlists; +with Opt; use Opt; +with Output; use Output; +with Restrict; use Restrict; +with Sem; use Sem; +with Sem_Aux; use Sem_Aux; +with Sem_Cat; use Sem_Cat; +with Sem_Ch3; use Sem_Ch3; +with Sem_Ch6; use Sem_Ch6; +with Sem_Ch8; use Sem_Ch8; +with Sem_Ch10; use Sem_Ch10; +with Sem_Ch12; use Sem_Ch12; +with Sem_Ch13; use Sem_Ch13; +with Sem_Disp; use Sem_Disp; +with Sem_Eval; use Sem_Eval; +with Sem_Prag; use Sem_Prag; +with Sem_Util; use Sem_Util; +with Sem_Warn; use Sem_Warn; +with Snames; use Snames; +with Stand; use Stand; +with Sinfo; use Sinfo; +with Sinput; use Sinput; with Style; -with Uintp; use Uintp; +with Uintp; use Uintp; package body Sem_Ch7 is @@ -182,47 +183,6 @@ package body Sem_Ch7 is end if; end Analyze_Package_Body; - ----------------------------------- - -- Analyze_Package_Body_Contract -- - ----------------------------------- - - procedure Analyze_Package_Body_Contract (Body_Id : Entity_Id) is - Spec_Id : constant Entity_Id := Spec_Entity (Body_Id); - Mode : SPARK_Mode_Type; - Ref_State : Node_Id; - - begin - -- Due to the timing of contract analysis, delayed pragmas may be - -- subject to the wrong SPARK_Mode, usually that of the enclosing - -- context. To remedy this, restore the original SPARK_Mode of the - -- related package body. - - Save_SPARK_Mode_And_Set (Body_Id, Mode); - - Ref_State := Get_Pragma (Body_Id, Pragma_Refined_State); - - -- The analysis of pragma Refined_State detects whether the spec has - -- abstract states available for refinement. - - if Present (Ref_State) then - Analyze_Refined_State_In_Decl_Part (Ref_State); - - -- State refinement is required when the package declaration defines at - -- least one abstract state. Null states are not considered. Refinement - -- is not envorced when SPARK checks are turned off. - - elsif SPARK_Mode /= Off - and then Requires_State_Refinement (Spec_Id, Body_Id) - then - Error_Msg_N ("package & requires state refinement", Spec_Id); - end if; - - -- Restore the SPARK_Mode of the enclosing context after all delayed - -- pragmas have been analyzed. - - Restore_SPARK_Mode (Mode); - end Analyze_Package_Body_Contract; - --------------------------------- -- Analyze_Package_Body_Helper -- --------------------------------- @@ -582,6 +542,30 @@ package body Sem_Ch7 is -- Start of processing for Analyze_Package_Body_Helper begin + -- A [generic] package body "freezes" the contract of the nearest + -- enclosing package body: + + -- package body Nearest_Enclosing_Package + -- with Refined_State => (State => Constit) + -- is + -- Constit : ...; + + -- package body Freezes_Enclosing_Package_Body + -- with Refined_State => (State_2 => Constit_2) + -- is + -- Constit_2 : ...; + + -- procedure Proc + -- with Refined_Depends => (Input => (Constit, Constit_2)) ... + + -- This ensures that any annotations referenced by the contract of a + -- [generic] subprogram body declared within the current package body + -- are available. This form of "freezing" is decoupled from the usual + -- Freeze_xxx mechanism because it must also work in the context of + -- generics where normal freezing is disabled. + + Analyze_Enclosing_Package_Body_Contract (N); + -- Find corresponding package specification, and establish the current -- scope. The visible defining entity for the package is the defining -- occurrence in the spec. On exit from the package body, all body @@ -944,74 +928,6 @@ package body Sem_Ch7 is Ghost_Mode := Save_Ghost_Mode; end Analyze_Package_Body_Helper; - ------------------------------ - -- Analyze_Package_Contract -- - ------------------------------ - - procedure Analyze_Package_Contract (Pack_Id : Entity_Id) is - Items : constant Node_Id := Contract (Pack_Id); - Init : Node_Id := Empty; - Init_Cond : Node_Id := Empty; - Mode : SPARK_Mode_Type; - Prag : Node_Id; - Prag_Nam : Name_Id; - - begin - -- Due to the timing of contract analysis, delayed pragmas may be - -- subject to the wrong SPARK_Mode, usually that of the enclosing - -- context. To remedy this, restore the original SPARK_Mode of the - -- related package. - - Save_SPARK_Mode_And_Set (Pack_Id, Mode); - - if Present (Items) then - - -- Locate and store pragmas Initial_Condition and Initializes since - -- their order of analysis matters. - - Prag := Classifications (Items); - while Present (Prag) loop - Prag_Nam := Pragma_Name (Prag); - - if Prag_Nam = Name_Initial_Condition then - Init_Cond := Prag; - - elsif Prag_Nam = Name_Initializes then - Init := Prag; - end if; - - Prag := Next_Pragma (Prag); - end loop; - - -- Analyze the initialization related pragmas. Initializes must come - -- before Initial_Condition due to item dependencies. - - if Present (Init) then - Analyze_Initializes_In_Decl_Part (Init); - end if; - - if Present (Init_Cond) then - Analyze_Initial_Condition_In_Decl_Part (Init_Cond); - end if; - end if; - - -- Check whether the lack of indicator Part_Of agrees with the placement - -- of the package instantiation with respect to the state space. - - if Is_Generic_Instance (Pack_Id) then - Prag := Get_Pragma (Pack_Id, Pragma_Part_Of); - - if No (Prag) then - Check_Missing_Part_Of (Pack_Id); - end if; - end if; - - -- Restore the SPARK_Mode of the enclosing context after all delayed - -- pragmas have been analyzed. - - Restore_SPARK_Mode (Mode); - end Analyze_Package_Contract; - --------------------------------- -- Analyze_Package_Declaration -- --------------------------------- diff --git a/gcc/ada/sem_ch7.ads b/gcc/ada/sem_ch7.ads index a243ac5f3dc..59f27b086bb 100644 --- a/gcc/ada/sem_ch7.ads +++ b/gcc/ada/sem_ch7.ads @@ -6,7 +6,7 @@ -- -- -- S p e c -- -- -- --- Copyright (C) 1992-2014, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2015, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -32,20 +32,6 @@ package Sem_Ch7 is procedure Analyze_Package_Specification (N : Node_Id); procedure Analyze_Private_Type_Declaration (N : Node_Id); - procedure Analyze_Package_Body_Contract (Body_Id : Entity_Id); - -- Analyze all delayed aspects chained on the contract of package body - -- Body_Id as if they appeared at the end of a declarative region. The - -- aspects that are considered are: - -- Refined_State - - procedure Analyze_Package_Contract (Pack_Id : Entity_Id); - -- Analyze all delayed aspects chained on the contract of package Pack_Id - -- as if they appeared at the end of a declarative region. The aspects - -- that are considered are: - -- Initial_Condition - -- Initializes - -- Part_Of - procedure End_Package_Scope (P : Entity_Id); -- Calls Uninstall_Declarations, and then pops the scope stack diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb index b9526747a86..d97bc86de6c 100644 --- a/gcc/ada/sem_prag.adb +++ b/gcc/ada/sem_prag.adb @@ -29,62 +29,63 @@ -- to complete the syntax checks. Certain pragmas are handled partially or -- completely by the parser (see Par.Prag for further details). -with Aspects; use Aspects; -with Atree; use Atree; -with Casing; use Casing; -with Checks; use Checks; -with Csets; use Csets; -with Debug; use Debug; -with Einfo; use Einfo; -with Elists; use Elists; -with Errout; use Errout; -with Exp_Dist; use Exp_Dist; -with Exp_Util; use Exp_Util; -with Freeze; use Freeze; -with Ghost; use Ghost; -with Lib; use Lib; -with Lib.Writ; use Lib.Writ; -with Lib.Xref; use Lib.Xref; -with Namet.Sp; use Namet.Sp; -with Nlists; use Nlists; -with Nmake; use Nmake; -with Output; use Output; -with Par_SCO; use Par_SCO; -with Restrict; use Restrict; -with Rident; use Rident; -with Rtsfind; use Rtsfind; -with Sem; use Sem; -with Sem_Aux; use Sem_Aux; -with Sem_Ch3; use Sem_Ch3; -with Sem_Ch6; use Sem_Ch6; -with Sem_Ch8; use Sem_Ch8; -with Sem_Ch12; use Sem_Ch12; -with Sem_Ch13; use Sem_Ch13; -with Sem_Disp; use Sem_Disp; -with Sem_Dist; use Sem_Dist; -with Sem_Elim; use Sem_Elim; -with Sem_Eval; use Sem_Eval; -with Sem_Intr; use Sem_Intr; -with Sem_Mech; use Sem_Mech; -with Sem_Res; use Sem_Res; -with Sem_Type; use Sem_Type; -with Sem_Util; use Sem_Util; -with Sem_Warn; use Sem_Warn; -with Stand; use Stand; -with Sinfo; use Sinfo; -with Sinfo.CN; use Sinfo.CN; -with Sinput; use Sinput; -with Stringt; use Stringt; -with Stylesw; use Stylesw; +with Aspects; use Aspects; +with Atree; use Atree; +with Casing; use Casing; +with Checks; use Checks; +with Contracts; use Contracts; +with Csets; use Csets; +with Debug; use Debug; +with Einfo; use Einfo; +with Elists; use Elists; +with Errout; use Errout; +with Exp_Dist; use Exp_Dist; +with Exp_Util; use Exp_Util; +with Freeze; use Freeze; +with Ghost; use Ghost; +with Lib; use Lib; +with Lib.Writ; use Lib.Writ; +with Lib.Xref; use Lib.Xref; +with Namet.Sp; use Namet.Sp; +with Nlists; use Nlists; +with Nmake; use Nmake; +with Output; use Output; +with Par_SCO; use Par_SCO; +with Restrict; use Restrict; +with Rident; use Rident; +with Rtsfind; use Rtsfind; +with Sem; use Sem; +with Sem_Aux; use Sem_Aux; +with Sem_Ch3; use Sem_Ch3; +with Sem_Ch6; use Sem_Ch6; +with Sem_Ch8; use Sem_Ch8; +with Sem_Ch12; use Sem_Ch12; +with Sem_Ch13; use Sem_Ch13; +with Sem_Disp; use Sem_Disp; +with Sem_Dist; use Sem_Dist; +with Sem_Elim; use Sem_Elim; +with Sem_Eval; use Sem_Eval; +with Sem_Intr; use Sem_Intr; +with Sem_Mech; use Sem_Mech; +with Sem_Res; use Sem_Res; +with Sem_Type; use Sem_Type; +with Sem_Util; use Sem_Util; +with Sem_Warn; use Sem_Warn; +with Stand; use Stand; +with Sinfo; use Sinfo; +with Sinfo.CN; use Sinfo.CN; +with Sinput; use Sinput; +with Stringt; use Stringt; +with Stylesw; use Stylesw; with Table; -with Targparm; use Targparm; -with Tbuild; use Tbuild; +with Targparm; use Targparm; +with Tbuild; use Tbuild; with Ttypes; -with Uintp; use Uintp; -with Uname; use Uname; -with Urealp; use Urealp; -with Validsw; use Validsw; -with Warnsw; use Warnsw; +with Uintp; use Uintp; +with Uname; use Uname; +with Urealp; use Urealp; +with Validsw; use Validsw; +with Warnsw; use Warnsw; package body Sem_Prag is @@ -165,11 +166,6 @@ package body Sem_Prag is -- Local Subprograms and Variables -- ------------------------------------- - procedure Add_Item (Item : Entity_Id; To_List : in out Elist_Id); - -- Subsidiary routine to the analysis of pragmas Depends, Global and - -- Refined_State. Append an entity to a list. If the list is empty, create - -- a new list. - function Adjust_External_Name_Case (N : Node_Id) return Node_Id; -- This routine is used for possible casing adjustment of an explicit -- external name supplied as a string literal (the node N), according to @@ -277,15 +273,6 @@ package body Sem_Prag is -- pragma in the source program, a breakpoint on rv catches this place in -- the source, allowing convenient stepping to the point of interest. - -------------- - -- Add_Item -- - -------------- - - procedure Add_Item (Item : Entity_Id; To_List : in out Elist_Id) is - begin - Append_New_Elmt (Item, To => To_List); - end Add_Item; - ------------------------------- -- Adjust_External_Name_Case -- ------------------------------- @@ -826,7 +813,7 @@ package body Sem_Prag is SPARK_Msg_NE ("duplicate use of item &", Item, Item_Id); else - Add_Item (Item_Id, Seen); + Append_New_Elmt (Item_Id, Seen); end if; -- Detect illegal use of an input related to a null @@ -846,7 +833,7 @@ package body Sem_Prag is -- of all processed inputs. if Is_Input or else Self_Ref then - Add_Item (Item_Id, All_Inputs_Seen); + Append_New_Elmt (Item_Id, All_Inputs_Seen); end if; -- State related checks (SPARK RM 6.1.5(3)) @@ -901,7 +888,7 @@ package body Sem_Prag is -- processed items. if Ekind (Item_Id) = E_Abstract_State then - Add_Item (Item_Id, States_Seen); + Append_New_Elmt (Item_Id, States_Seen); end if; if Ekind_In (Item_Id, E_Abstract_State, @@ -909,7 +896,7 @@ package body Sem_Prag is E_Variable) and then Present (Encapsulating_State (Item_Id)) then - Add_Item (Item_Id, Constits_Seen); + Append_New_Elmt (Item_Id, Constits_Seen); end if; -- All other input/output items are illegal @@ -2016,16 +2003,16 @@ package body Sem_Prag is -- items. else - Add_Item (Item_Id, Seen); + Append_New_Elmt (Item_Id, Seen); if Ekind (Item_Id) = E_Abstract_State then - Add_Item (Item_Id, States_Seen); + Append_New_Elmt (Item_Id, States_Seen); end if; if Ekind_In (Item_Id, E_Abstract_State, E_Constant, E_Variable) and then Present (Encapsulating_State (Item_Id)) then - Add_Item (Item_Id, Constits_Seen); + Append_New_Elmt (Item_Id, Constits_Seen); end if; end if; end Analyze_Global_Item; @@ -2396,14 +2383,14 @@ package body Sem_Prag is -- and variables. else - Add_Item (Item_Id, Items_Seen); + Append_New_Elmt (Item_Id, Items_Seen); if Ekind (Item_Id) = E_Abstract_State then - Add_Item (Item_Id, States_Seen); + Append_New_Elmt (Item_Id, States_Seen); end if; if Present (Encapsulating_State (Item_Id)) then - Add_Item (Item_Id, Constits_Seen); + Append_New_Elmt (Item_Id, Constits_Seen); end if; end if; @@ -2504,10 +2491,10 @@ package body Sem_Prag is -- Input is legal, add it to the list of processed inputs else - Add_Item (Input_Id, Inputs_Seen); + Append_New_Elmt (Input_Id, Inputs_Seen); if Ekind (Input_Id) = E_Abstract_State then - Add_Item (Input_Id, States_Seen); + Append_New_Elmt (Input_Id, States_Seen); end if; if Ekind_In (Input_Id, E_Abstract_State, @@ -2515,7 +2502,7 @@ package body Sem_Prag is E_Variable) and then Present (Encapsulating_State (Input_Id)) then - Add_Item (Input_Id, Constits_Seen); + Append_New_Elmt (Input_Id, Constits_Seen); end if; end if; @@ -2610,7 +2597,7 @@ package body Sem_Prag is if Comes_From_Source (Decl) and then Nkind (Decl) = N_Object_Declaration then - Add_Item (Defining_Entity (Decl), States_And_Objs); + Append_New_Elmt (Defining_Entity (Decl), States_And_Objs); end if; Next (Decl); @@ -3481,8 +3468,8 @@ package body Sem_Prag is if not Is_Child_Or_Sibling (Pack_Id, Scope (State_Id)) then SPARK_Msg_NE - ("indicator Part_Of must denote an abstract state of& " - & "or public descendant (SPARK RM 7.2.6(3))", + ("indicator Part_Of must denote an abstract state or " + & "public descendant of & (SPARK RM 7.2.6(3))", Indic, Parent_Unit); elsif Scope (State_Id) = Parent_Unit @@ -3494,8 +3481,8 @@ package body Sem_Prag is else SPARK_Msg_NE - ("indicator Part_Of must denote an abstract state of& " - & "or public descendant (SPARK RM 7.2.6(3))", + ("indicator Part_Of must denote an abstract state or " + & "public descendant of & (SPARK RM 7.2.6(3))", Indic, Parent_Unit); end if; @@ -22493,7 +22480,7 @@ package body Sem_Prag is procedure Record_Item (Item_Id : Entity_Id) is begin if not Contains (Matched_Items, Item_Id) then - Add_Item (Item_Id, Matched_Items); + Append_New_Elmt (Item_Id, Matched_Items); end if; end Record_Item; @@ -23664,16 +23651,16 @@ package body Sem_Prag is and then Has_Visible_Refinement (Encapsulating_State (Item_Id)) then if Global_Mode = Name_Input then - Add_Item (Item_Id, In_Constits); + Append_New_Elmt (Item_Id, In_Constits); elsif Global_Mode = Name_In_Out then - Add_Item (Item_Id, In_Out_Constits); + Append_New_Elmt (Item_Id, In_Out_Constits); elsif Global_Mode = Name_Output then - Add_Item (Item_Id, Out_Constits); + Append_New_Elmt (Item_Id, Out_Constits); elsif Global_Mode = Name_Proof_In then - Add_Item (Item_Id, Proof_In_Constits); + Append_New_Elmt (Item_Id, Proof_In_Constits); end if; -- When not a constituent, ensure that both occurrences of the @@ -23821,13 +23808,13 @@ package body Sem_Prag is -- Add the item to the proper list if Item_Mode = Name_Input then - Add_Item (Item_Id, In_Items); + Append_New_Elmt (Item_Id, In_Items); elsif Item_Mode = Name_In_Out then - Add_Item (Item_Id, In_Out_Items); + Append_New_Elmt (Item_Id, In_Out_Items); elsif Item_Mode = Name_Output then - Add_Item (Item_Id, Out_Items); + Append_New_Elmt (Item_Id, Out_Items); elsif Item_Mode = Name_Proof_In then - Add_Item (Item_Id, Proof_In_Items); + Append_New_Elmt (Item_Id, Proof_In_Items); end if; end Collect_Global_Item; @@ -24091,7 +24078,10 @@ package body Sem_Prag is -- Analyze_Refined_State_In_Decl_Part -- ---------------------------------------- - procedure Analyze_Refined_State_In_Decl_Part (N : Node_Id) is + procedure Analyze_Refined_State_In_Decl_Part + (N : Node_Id; + Freeze_Id : Entity_Id := Empty) + is Body_Decl : constant Node_Id := Find_Related_Package_Or_Body (N); Body_Id : constant Entity_Id := Defining_Entity (Body_Decl); Spec_Id : constant Entity_Id := Corresponding_Spec (Body_Decl); @@ -24109,6 +24099,10 @@ package body Sem_Prag is -- A list that contains all constituents processed so far. The list is -- used to detect multiple uses of the same constituent. + Freeze_Posted : Boolean := False; + -- A flag that controls the output of a freezing-related error (see use + -- below). + Refined_States_Seen : Elist_Id := No_Elist; -- A list that contains all refined states processed so far. The list is -- used to detect duplicate refinements. @@ -24116,16 +24110,9 @@ package body Sem_Prag is procedure Analyze_Refinement_Clause (Clause : Node_Id); -- Perform full analysis of a single refinement clause - function Collect_Body_States (Pack_Id : Entity_Id) return Elist_Id; - -- Gather the entities of all abstract states and objects declared in - -- the body state space of package Pack_Id. - procedure Report_Unrefined_States (States : Elist_Id); -- Emit errors for all unrefined abstract states found in list States - procedure Report_Unused_States (States : Elist_Id); - -- Emit errors for all unused states found in list States - ------------------------------- -- Analyze_Refinement_Clause -- ------------------------------- @@ -24190,10 +24177,10 @@ package body Sem_Prag is procedure Check_Matching_Constituent (Constit_Id : Entity_Id); -- Determine whether constituent Constit denoted by its entity - -- Constit_Id appears in Hidden_States. Emit an error when the + -- Constit_Id appears in Body_States. Emit an error when the -- constituent is not a valid hidden state of the related package -- or when it is used more than once. Otherwise remove the - -- constituent from Hidden_States. + -- constituent from Body_States. -------------------------------- -- Check_Matching_Constituent -- @@ -24212,7 +24199,7 @@ package body Sem_Prag is -- Add the constituent to the list of processed items to aid -- with the detection of duplicates. - Add_Item (Constit_Id, Constituents_Seen); + Append_New_Elmt (Constit_Id, Constituents_Seen); -- Collect the constituent in the list of refinement items -- and establish a relation between the refined state and @@ -24436,12 +24423,56 @@ package body Sem_Prag is if Is_Entity_Name (Constit) then Constit_Id := Entity_Of (Constit); - if Ekind_In (Constit_Id, E_Abstract_State, - E_Constant, - E_Variable) + -- When a constituent is declared after a subprogram body + -- that caused "freezing" of the related contract where + -- pragma Refined_State resides, the constituent appears + -- undefined and carries Any_Id as its entity. + + -- package body Pack + -- with Refined_State => (State => Constit) + -- is + -- procedure Proc + -- with Refined_Global => (Input => Constit) + -- is + -- ... + -- end Proc; + + -- Constit : ...; + -- end Pack; + + if Constit_Id = Any_Id then + SPARK_Msg_NE ("& is undefined", Constit, Constit_Id); + + -- Emit a specialized info message when the contract of + -- the related package body was "frozen" by another body. + -- Note that it is not possible to precisely identify why + -- the constituent is undefined because it is not visible + -- when pragma Refined_State is analyzed. This message is + -- a reasonable approximation. + + if Present (Freeze_Id) and then not Freeze_Posted then + Freeze_Posted := True; + + Error_Msg_Name_1 := Chars (Body_Id); + Error_Msg_Sloc := Sloc (Freeze_Id); + SPARK_Msg_NE + ("body & declared # freezes the contract of %", + N, Freeze_Id); + SPARK_Msg_N + ("\all constituents must be declared before body #", + N); + end if; + + -- The constituent is a valid state or object + + elsif Ekind_In (Constit_Id, E_Abstract_State, + E_Constant, + E_Variable) then Check_Matching_Constituent (Constit_Id); + -- Otherwise the constituent is illegal + else SPARK_Msg_NE ("constituent & must denote object or state", @@ -24519,7 +24550,7 @@ package body Sem_Prag is -- been refined. if Node (State_Elmt) = State_Id then - Add_Item (State_Id, Refined_States_Seen); + Append_New_Elmt (State_Id, Refined_States_Seen); Remove_Elmt (Available_States, State_Elmt); return; end if; @@ -24754,104 +24785,6 @@ package body Sem_Prag is Report_Unused_Constituents (Part_Of_Constits); end Analyze_Refinement_Clause; - ------------------------- - -- Collect_Body_States -- - ------------------------- - - function Collect_Body_States (Pack_Id : Entity_Id) return Elist_Id is - Result : Elist_Id := No_Elist; - -- A list containing all body states of Pack_Id - - procedure Collect_Visible_States (Pack_Id : Entity_Id); - -- Gather the entities of all abstract states and objects declared in - -- the visible state space of package Pack_Id. - - ---------------------------- - -- Collect_Visible_States -- - ---------------------------- - - procedure Collect_Visible_States (Pack_Id : Entity_Id) is - Item_Id : Entity_Id; - - begin - -- Traverse the entity chain of the package and inspect all - -- visible items. - - Item_Id := First_Entity (Pack_Id); - while Present (Item_Id) and then not In_Private_Part (Item_Id) loop - - -- Do not consider internally generated items as those cannot - -- be named and participate in refinement. - - if not Comes_From_Source (Item_Id) then - null; - - elsif Ekind (Item_Id) = E_Abstract_State then - Add_Item (Item_Id, Result); - - -- Do not consider constants or variables that map generic - -- formals to their actuals, as the formals cannot be named - -- from the outside and participate in refinement. - - elsif Ekind_In (Item_Id, E_Constant, E_Variable) - and then No (Corresponding_Generic_Association - (Declaration_Node (Item_Id))) - then - Add_Item (Item_Id, Result); - - -- Recursively gather the visible states of a nested package - - elsif Ekind (Item_Id) = E_Package then - Collect_Visible_States (Item_Id); - end if; - - Next_Entity (Item_Id); - end loop; - end Collect_Visible_States; - - -- Local variables - - Pack_Body : constant Node_Id := - Declaration_Node (Body_Entity (Pack_Id)); - Decl : Node_Id; - Item_Id : Entity_Id; - - -- Start of processing for Collect_Body_States - - begin - -- Inspect the declarations of the body looking for source objects, - -- packages and package instantiations. - - Decl := First (Declarations (Pack_Body)); - while Present (Decl) loop - - -- Capture source objects as internally generated temporaries - -- cannot be named and participate in refinement. - - if Nkind (Decl) = N_Object_Declaration then - Item_Id := Defining_Entity (Decl); - - if Comes_From_Source (Item_Id) then - Add_Item (Item_Id, Result); - end if; - - -- Capture the visible abstract states and objects of a source - -- package [instantiation]. - - elsif Nkind (Decl) = N_Package_Declaration then - Item_Id := Defining_Entity (Decl); - - if Comes_From_Source (Item_Id) then - Collect_Visible_States (Item_Id); - end if; - end if; - - Next (Decl); - end loop; - - return Result; - end Collect_Body_States; - ----------------------------- -- Report_Unrefined_States -- ----------------------------- @@ -24871,61 +24804,6 @@ package body Sem_Prag is end if; end Report_Unrefined_States; - -------------------------- - -- Report_Unused_States -- - -------------------------- - - procedure Report_Unused_States (States : Elist_Id) is - Posted : Boolean := False; - State_Elmt : Elmt_Id; - State_Id : Entity_Id; - - begin - if Present (States) then - State_Elmt := First_Elmt (States); - while Present (State_Elmt) loop - State_Id := Node (State_Elmt); - - -- Constants are part of the hidden state of a package, but the - -- compiler cannot determine whether they have variable input - -- (SPARK RM 7.1.1(2)) and cannot classify them properly as a - -- hidden state. Do not emit an error when a constant does not - -- participate in a state refinement, even though it acts as a - -- hidden state. - - if Ekind (State_Id) = E_Constant then - null; - - -- Generate an error message of the form: - - -- body of package ... has unused hidden states - -- abstract state ... defined at ... - -- variable ... defined at ... - - else - if not Posted then - Posted := True; - SPARK_Msg_N - ("body of package & has unused hidden states", Body_Id); - end if; - - Error_Msg_Sloc := Sloc (State_Id); - - if Ekind (State_Id) = E_Abstract_State then - SPARK_Msg_NE - ("\abstract state & defined #", Body_Id, State_Id); - - else - pragma Assert (Ekind (State_Id) = E_Variable); - SPARK_Msg_NE ("\variable & defined #", Body_Id, State_Id); - end if; - end if; - - Next_Elmt (State_Elmt); - end loop; - end if; - end Report_Unused_States; - -- Local declarations Clauses : constant Node_Id := Expression (Get_Argument (N, Spec_Id)); @@ -24945,7 +24823,7 @@ package body Sem_Prag is -- state space of the package body. These items must be utilized as -- constituents in a state refinement. - Body_States := Collect_Body_States (Spec_Id); + Body_States := Collect_Body_States (Body_Id); -- Multiple non-null state refinements appear as an aggregate @@ -24977,7 +24855,7 @@ package body Sem_Prag is -- Ensure that all abstract states and objects declared in the body -- state space of the related package are utilized as constituents. - Report_Unused_States (Body_States); + Report_Unused_Body_States (Body_Id, Body_States); end Analyze_Refined_State_In_Decl_Part; ------------------------------------ @@ -25857,9 +25735,9 @@ package body Sem_Prag is else if Is_Input then - Add_Item (Item, Subp_Inputs); + Append_New_Elmt (Item, Subp_Inputs); else - Add_Item (Item, Subp_Outputs); + Append_New_Elmt (Item, Subp_Outputs); end if; end if; end Collect_Dependency_Item; @@ -25908,11 +25786,11 @@ package body Sem_Prag is procedure Collect_Global_Item (Item : Node_Id; Mode : Name_Id) is begin if Nam_In (Mode, Name_In_Out, Name_Input) then - Add_Item (Item, Subp_Inputs); + Append_New_Elmt (Item, Subp_Inputs); end if; if Nam_In (Mode, Name_In_Out, Name_Output) then - Add_Item (Item, Subp_Outputs); + Append_New_Elmt (Item, Subp_Outputs); end if; end Collect_Global_Item; @@ -25988,14 +25866,14 @@ package body Sem_Prag is E_In_Out_Parameter, E_In_Parameter) then - Add_Item (Formal, Subp_Inputs); + Append_New_Elmt (Formal, Subp_Inputs); end if; if Ekind_In (Formal, E_Generic_In_Out_Parameter, E_In_Out_Parameter, E_Out_Parameter) then - Add_Item (Formal, Subp_Outputs); + Append_New_Elmt (Formal, Subp_Outputs); -- Out parameters can act as inputs when the related type is -- tagged, unconstrained array, unconstrained record or record @@ -26004,7 +25882,7 @@ package body Sem_Prag is if Ekind (Formal) = E_Out_Parameter and then Is_Unconstrained_Or_Tagged_Item (Formal) then - Add_Item (Formal, Subp_Inputs); + Append_New_Elmt (Formal, Subp_Inputs); end if; end if; diff --git a/gcc/ada/sem_prag.ads b/gcc/ada/sem_prag.ads index 862c564f0da..45a3ebcc2ea 100644 --- a/gcc/ada/sem_prag.ads +++ b/gcc/ada/sem_prag.ads @@ -209,8 +209,12 @@ package Sem_Prag is -- uses Analyze_Global_In_Decl_Part as a starting point, then performs -- various consistency checks between Global and Refined_Global. - procedure Analyze_Refined_State_In_Decl_Part (N : Node_Id); - -- Perform full analysis of delayed pragma Refined_State + procedure Analyze_Refined_State_In_Decl_Part + (N : Node_Id; + Freeze_Id : Entity_Id := Empty); + -- Perform full analysis of delayed pragma Refined_State. Freeze_Id denotes + -- the entity of [generic] package body or [generic] subprogram body which + -- caused "freezing" of the related contract where the pragma resides. procedure Analyze_Test_Case_In_Decl_Part (N : Node_Id); -- Perform preanalysis of pragma Test_Case diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb index a8052000b31..634b4790c61 100644 --- a/gcc/ada/sem_util.adb +++ b/gcc/ada/sem_util.adb @@ -52,7 +52,6 @@ with Sem_Aux; use Sem_Aux; with Sem_Attr; use Sem_Attr; with Sem_Ch6; use Sem_Ch6; with Sem_Ch8; use Sem_Ch8; -with Sem_Ch12; use Sem_Ch12; with Sem_Ch13; use Sem_Ch13; with Sem_Disp; use Sem_Disp; with Sem_Eval; use Sem_Eval; @@ -250,209 +249,6 @@ package body Sem_Util is end if; end Add_Block_Identifier; - ----------------------- - -- Add_Contract_Item -- - ----------------------- - - procedure Add_Contract_Item (Prag : Node_Id; Id : Entity_Id) is - Items : Node_Id := Contract (Id); - - procedure Add_Classification; - -- Prepend Prag to the list of classifications - - procedure Add_Contract_Test_Case; - -- Prepend Prag to the list of contract and test cases - - procedure Add_Pre_Post_Condition; - -- Prepend Prag to the list of pre- and postconditions - - ------------------------ - -- Add_Classification -- - ------------------------ - - procedure Add_Classification is - begin - Set_Next_Pragma (Prag, Classifications (Items)); - Set_Classifications (Items, Prag); - end Add_Classification; - - ---------------------------- - -- Add_Contract_Test_Case -- - ---------------------------- - - procedure Add_Contract_Test_Case is - begin - Set_Next_Pragma (Prag, Contract_Test_Cases (Items)); - Set_Contract_Test_Cases (Items, Prag); - end Add_Contract_Test_Case; - - ---------------------------- - -- Add_Pre_Post_Condition -- - ---------------------------- - - procedure Add_Pre_Post_Condition is - begin - Set_Next_Pragma (Prag, Pre_Post_Conditions (Items)); - Set_Pre_Post_Conditions (Items, Prag); - end Add_Pre_Post_Condition; - - -- Local variables - - Prag_Nam : Name_Id; - - -- Start of processing for Add_Contract_Item - - begin - -- A contract must contain only pragmas - - pragma Assert (Nkind (Prag) = N_Pragma); - Prag_Nam := Pragma_Name (Prag); - - -- Create a new contract when adding the first item - - if No (Items) then - Items := Make_Contract (Sloc (Id)); - Set_Contract (Id, Items); - end if; - - -- Contract items related to constants. Applicable pragmas are: - -- Part_Of - - if Ekind (Id) = E_Constant then - if Prag_Nam = Name_Part_Of then - Add_Classification; - - -- The pragma is not a proper contract item - - else - raise Program_Error; - end if; - - -- Contract items related to [generic] packages or instantiations. The - -- applicable pragmas are: - -- Abstract_States - -- Initial_Condition - -- Initializes - -- Part_Of (instantiation only) - - elsif Ekind_In (Id, E_Generic_Package, E_Package) then - if Nam_In (Prag_Nam, Name_Abstract_State, - Name_Initial_Condition, - Name_Initializes) - then - Add_Classification; - - -- Indicator Part_Of must be associated with a package instantiation - - elsif Prag_Nam = Name_Part_Of and then Is_Generic_Instance (Id) then - Add_Classification; - - -- The pragma is not a proper contract item - - else - raise Program_Error; - end if; - - -- Contract items related to package bodies. The applicable pragmas are: - -- Refined_States - - elsif Ekind (Id) = E_Package_Body then - if Prag_Nam = Name_Refined_State then - Add_Classification; - - -- The pragma is not a proper contract item - - else - raise Program_Error; - end if; - - -- Contract items related to subprogram or entry declarations. The - -- applicable pragmas are: - -- Contract_Cases - -- Depends - -- Extensions_Visible - -- Global - -- Postcondition - -- Precondition - -- Test_Case - -- Volatile_Function - - elsif Ekind_In (Id, E_Entry, E_Entry_Family) - or else Is_Generic_Subprogram (Id) - or else Is_Subprogram (Id) - then - if Nam_In (Prag_Nam, Name_Postcondition, Name_Precondition) then - Add_Pre_Post_Condition; - - elsif Nam_In (Prag_Nam, Name_Contract_Cases, Name_Test_Case) then - Add_Contract_Test_Case; - - elsif Nam_In (Prag_Nam, Name_Depends, - Name_Extensions_Visible, - Name_Global) - then - Add_Classification; - - elsif Prag_Nam = Name_Volatile_Function - and then Ekind_In (Id, E_Function, E_Generic_Function) - then - Add_Classification; - - -- The pragma is not a proper contract item - - else - raise Program_Error; - end if; - - -- Contract items related to subprogram bodies. Applicable pragmas are: - -- Postcondition - -- Precondition - -- Refined_Depends - -- Refined_Global - -- Refined_Post - - elsif Ekind (Id) = E_Subprogram_Body then - if Nam_In (Prag_Nam, Name_Refined_Depends, Name_Refined_Global) then - Add_Classification; - - elsif Nam_In (Prag_Nam, Name_Postcondition, - Name_Precondition, - Name_Refined_Post) - then - Add_Pre_Post_Condition; - - -- The pragma is not a proper contract item - - else - raise Program_Error; - end if; - - -- Contract items related to variables. Applicable pragmas are: - -- Async_Readers - -- Async_Writers - -- Constant_After_Elaboration - -- Effective_Reads - -- Effective_Writes - -- Part_Of - - elsif Ekind (Id) = E_Variable then - if Nam_In (Prag_Nam, Name_Async_Readers, - Name_Async_Writers, - Name_Constant_After_Elaboration, - Name_Effective_Reads, - Name_Effective_Writes, - Name_Part_Of) - then - Add_Classification; - - -- The pragma is not a proper contract item - - else - raise Program_Error; - end if; - end if; - end Add_Contract_Item; - ---------------------------- -- Add_Global_Declaration -- ---------------------------- @@ -3692,6 +3488,231 @@ package body Sem_Util is end if; end Check_Unprotected_Access; + ------------------------------ + -- Check_Unused_Body_States -- + ------------------------------ + + procedure Check_Unused_Body_States (Body_Id : Entity_Id) is + Legal_Constits : Boolean := True; + -- This flag designates whether all constituents of pragma Refined_State + -- are legal. The flag is used to suppress the generation of potentially + -- misleading error messages due to a malformed pragma. + + procedure Process_Refinement_Clause + (Clause : Node_Id; + States : Elist_Id); + -- Inspect all constituents of refinement clause Clause and remove any + -- matches from body state list States. + + ------------------------------- + -- Process_Refinement_Clause -- + ------------------------------- + + procedure Process_Refinement_Clause + (Clause : Node_Id; + States : Elist_Id) + is + procedure Process_Constituent (Constit : Node_Id); + -- Remove constituent Constit from body state list States + + ------------------------- + -- Process_Constituent -- + ------------------------- + + procedure Process_Constituent (Constit : Node_Id) is + Constit_Id : Entity_Id; + + begin + if Error_Posted (Constit) then + Legal_Constits := False; + end if; + + -- Guard against illegal constituents. Only abstract states and + -- objects can appear on the right hand side of a refinement. + + if Is_Entity_Name (Constit) then + Constit_Id := Entity_Of (Constit); + + if Present (Constit_Id) + and then Ekind_In (Constit_Id, E_Abstract_State, + E_Constant, + E_Variable) + then + Remove (States, Constit_Id); + end if; + end if; + end Process_Constituent; + + -- Local variables + + Constit : Node_Id; + + -- Start of processing for Process_Refinement_Clause + + begin + if Nkind (Clause) = N_Component_Association then + Constit := Expression (Clause); + + -- Multiple constituents appear as an aggregate + + if Nkind (Constit) = N_Aggregate then + Constit := First (Expressions (Constit)); + while Present (Constit) loop + Process_Constituent (Constit); + Next (Constit); + end loop; + + -- Various forms of a single constituent + + else + Process_Constituent (Constit); + end if; + end if; + end Process_Refinement_Clause; + + -- Local variables + + Prag : constant Node_Id := + Get_Pragma (Body_Id, Pragma_Refined_State); + Spec_Id : constant Entity_Id := Spec_Entity (Body_Id); + Clause : Node_Id; + States : Elist_Id; + + -- Start of processing for Check_Unused_Body_States + + begin + -- Inspect the clauses of pragma Refined_State and determine whether all + -- visible states declared within the body of the package participate in + -- the refinement. + + if Present (Prag) then + Clause := Expression (Get_Argument (Prag, Spec_Id)); + States := Collect_Body_States (Body_Id); + + -- Multiple non-null state refinements appear as an aggregate + + if Nkind (Clause) = N_Aggregate then + Clause := First (Component_Associations (Clause)); + while Present (Clause) loop + Process_Refinement_Clause (Clause, States); + Next (Clause); + end loop; + + -- Various forms of a single state refinement + + else + Process_Refinement_Clause (Clause, States); + end if; + + -- Ensure that all abstract states and objects declared in the body + -- state space of the related package are utilized as constituents. + + if Legal_Constits then + Report_Unused_Body_States (Body_Id, States); + end if; + end if; + end Check_Unused_Body_States; + + ------------------------- + -- Collect_Body_States -- + ------------------------- + + function Collect_Body_States (Body_Id : Entity_Id) return Elist_Id is + procedure Collect_Visible_States + (Pack_Id : Entity_Id; + States : in out Elist_Id); + -- Gather the entities of all abstract states and objects declared in + -- the visible state space of package Pack_Id. + + ---------------------------- + -- Collect_Visible_States -- + ---------------------------- + + procedure Collect_Visible_States + (Pack_Id : Entity_Id; + States : in out Elist_Id) + is + Item_Id : Entity_Id; + + begin + -- Traverse the entity chain of the package and inspect all visible + -- items. + + Item_Id := First_Entity (Pack_Id); + while Present (Item_Id) and then not In_Private_Part (Item_Id) loop + + -- Do not consider internally generated items as those cannot be + -- named and participate in refinement. + + if not Comes_From_Source (Item_Id) then + null; + + elsif Ekind (Item_Id) = E_Abstract_State then + Append_New_Elmt (Item_Id, States); + + -- Do not consider objects that map generic formals to their + -- actuals, as the formals cannot be named from the outside and + -- participate in refinement. + + elsif Ekind_In (Item_Id, E_Constant, E_Variable) + and then No (Corresponding_Generic_Association + (Declaration_Node (Item_Id))) + then + Append_New_Elmt (Item_Id, States); + + -- Recursively gather the visible states of a nested package + + elsif Ekind (Item_Id) = E_Package then + Collect_Visible_States (Item_Id, States); + end if; + + Next_Entity (Item_Id); + end loop; + end Collect_Visible_States; + + -- Local variables + + Body_Decl : constant Node_Id := Unit_Declaration_Node (Body_Id); + Decl : Node_Id; + Item_Id : Entity_Id; + States : Elist_Id := No_Elist; + + -- Start of processing for Collect_Body_States + + begin + -- Inspect the declarations of the body looking for source objects, + -- packages and package instantiations. + + Decl := First (Declarations (Body_Decl)); + while Present (Decl) loop + + -- Capture source objects as internally generated temporaries cannot + -- be named and participate in refinement. + + if Nkind (Decl) = N_Object_Declaration then + Item_Id := Defining_Entity (Decl); + + if Comes_From_Source (Item_Id) then + Append_New_Elmt (Item_Id, States); + end if; + + -- Capture the visible abstract states and objects of a source + -- package [instantiation]. + + elsif Nkind (Decl) = N_Package_Declaration then + Item_Id := Defining_Entity (Decl); + + if Comes_From_Source (Item_Id) then + Collect_Visible_States (Item_Id, States); + end if; + end if; + + Next (Decl); + end loop; + + return States; + end Collect_Body_States; + ------------------------ -- Collect_Interfaces -- ------------------------ @@ -4766,147 +4787,6 @@ package body Sem_Util is end if; end Corresponding_Spec_Of; - ----------------------------- - -- Create_Generic_Contract -- - ----------------------------- - - procedure Create_Generic_Contract (Unit : Node_Id) is - Templ : constant Node_Id := Original_Node (Unit); - Templ_Id : constant Entity_Id := Defining_Entity (Templ); - - procedure Add_Generic_Contract_Pragma (Prag : Node_Id); - -- Add a single contract-related source pragma Prag to the contract of - -- generic template Templ_Id. - - --------------------------------- - -- Add_Generic_Contract_Pragma -- - --------------------------------- - - procedure Add_Generic_Contract_Pragma (Prag : Node_Id) is - Prag_Templ : Node_Id; - - begin - -- Mark the pragma to prevent the premature capture of global - -- references when capturing global references of the context - -- (see Save_References_In_Pragma). - - Set_Is_Generic_Contract_Pragma (Prag); - - -- Pragmas that apply to a generic subprogram declaration are not - -- part of the semantic structure of the generic template: - - -- generic - -- procedure Example (Formal : Integer); - -- pragma Precondition (Formal > 0); - - -- Create a generic template for such pragmas and link the template - -- of the pragma with the generic template. - - if Nkind (Templ) = N_Generic_Subprogram_Declaration then - Rewrite - (Prag, Copy_Generic_Node (Prag, Empty, Instantiating => False)); - Prag_Templ := Original_Node (Prag); - - Set_Is_Generic_Contract_Pragma (Prag_Templ); - Add_Contract_Item (Prag_Templ, Templ_Id); - - -- Otherwise link the pragma with the generic template - - else - Add_Contract_Item (Prag, Templ_Id); - end if; - end Add_Generic_Contract_Pragma; - - -- Local variables - - Context : constant Node_Id := Parent (Unit); - Decl : Node_Id := Empty; - - -- Start of processing for Create_Generic_Contract - - begin - -- A generic package declaration carries contract-related source pragmas - -- in its visible declarations. - - if Nkind (Templ) = N_Generic_Package_Declaration then - Set_Ekind (Templ_Id, E_Generic_Package); - - if Present (Visible_Declarations (Specification (Templ))) then - Decl := First (Visible_Declarations (Specification (Templ))); - end if; - - -- A generic package body carries contract-related source pragmas in its - -- declarations. - - elsif Nkind (Templ) = N_Package_Body then - Set_Ekind (Templ_Id, E_Package_Body); - - if Present (Declarations (Templ)) then - Decl := First (Declarations (Templ)); - end if; - - -- Generic subprogram declaration - - elsif Nkind (Templ) = N_Generic_Subprogram_Declaration then - if Nkind (Specification (Templ)) = N_Function_Specification then - Set_Ekind (Templ_Id, E_Generic_Function); - else - Set_Ekind (Templ_Id, E_Generic_Procedure); - end if; - - -- When the generic subprogram acts as a compilation unit, inspect - -- the Pragmas_After list for contract-related source pragmas. - - if Nkind (Context) = N_Compilation_Unit then - if Present (Aux_Decls_Node (Context)) - and then Present (Pragmas_After (Aux_Decls_Node (Context))) - then - Decl := First (Pragmas_After (Aux_Decls_Node (Context))); - end if; - - -- Otherwise inspect the successive declarations for contract-related - -- source pragmas. - - else - Decl := Next (Unit); - end if; - - -- A generic subprogram body carries contract-related source pragmas in - -- its declarations. - - elsif Nkind (Templ) = N_Subprogram_Body then - Set_Ekind (Templ_Id, E_Subprogram_Body); - - if Present (Declarations (Templ)) then - Decl := First (Declarations (Templ)); - end if; - end if; - - -- Inspect the relevant declarations looking for contract-related source - -- pragmas and add them to the contract of the generic unit. - - while Present (Decl) loop - if Comes_From_Source (Decl) then - if Nkind (Decl) = N_Pragma then - - -- The source pragma is a contract annotation - - if Is_Contract_Annotation (Decl) then - Add_Generic_Contract_Pragma (Decl); - end if; - - -- The region where a contract-related source pragma may appear - -- ends with the first source non-pragma declaration or statement. - - else - exit; - end if; - end if; - - Next (Decl); - end loop; - end Create_Generic_Contract; - -------------------- -- Current_Entity -- -------------------- @@ -10249,53 +10129,6 @@ package body Sem_Util is end if; end Inherit_Rep_Item_Chain; - --------------------------------- - -- Inherit_Subprogram_Contract -- - --------------------------------- - - procedure Inherit_Subprogram_Contract - (Subp : Entity_Id; - From_Subp : Entity_Id) - is - procedure Inherit_Pragma (Prag_Id : Pragma_Id); - -- Propagate a pragma denoted by Prag_Id from From_Subp's contract to - -- Subp's contract. - - -------------------- - -- Inherit_Pragma -- - -------------------- - - procedure Inherit_Pragma (Prag_Id : Pragma_Id) is - Prag : constant Node_Id := Get_Pragma (From_Subp, Prag_Id); - New_Prag : Node_Id; - - begin - -- A pragma cannot be part of more than one First_Pragma/Next_Pragma - -- chains, therefore the node must be replicated. The new pragma is - -- flagged is inherited for distrinction purposes. - - if Present (Prag) then - New_Prag := New_Copy_Tree (Prag); - Set_Is_Inherited (New_Prag); - - Add_Contract_Item (New_Prag, Subp); - end if; - end Inherit_Pragma; - - -- Start of processing for Inherit_Subprogram_Contract - - begin - -- Inheritance is carried out only when both entities are subprograms - -- with contracts. - - if Is_Subprogram_Or_Generic_Subprogram (Subp) - and then Is_Subprogram_Or_Generic_Subprogram (From_Subp) - and then Present (Contract (From_Subp)) - then - Inherit_Pragma (Pragma_Extensions_Visible); - end if; - end Inherit_Subprogram_Contract; - --------------------------------- -- Insert_Explicit_Dereference -- --------------------------------- @@ -17171,6 +17004,63 @@ package body Sem_Util is (Boolean_Literals (not Range_Checks_Suppressed (E)), Loc); end Rep_To_Pos_Flag; + ------------------------------- + -- Report_Unused_Body_States -- + ------------------------------- + + procedure Report_Unused_Body_States + (Body_Id : Entity_Id; + States : Elist_Id) + is + Posted : Boolean := False; + State_Elmt : Elmt_Id; + State_Id : Entity_Id; + + begin + if Present (States) then + State_Elmt := First_Elmt (States); + while Present (State_Elmt) loop + State_Id := Node (State_Elmt); + + -- Constants are part of the hidden state of a package, but the + -- compiler cannot determine whether they have variable input + -- (SPARK RM 7.1.1(2)) and cannot classify them properly as a + -- hidden state. Do not emit an error when a constant does not + -- participate in a state refinement, even though it acts as a + -- hidden state. + + if Ekind (State_Id) = E_Constant then + null; + + -- Generate an error message of the form: + + -- body of package ... has unused hidden states + -- abstract state ... defined at ... + -- variable ... defined at ... + + else + if not Posted then + Posted := True; + SPARK_Msg_N + ("body of package & has unused hidden states", Body_Id); + end if; + + Error_Msg_Sloc := Sloc (State_Id); + + if Ekind (State_Id) = E_Abstract_State then + SPARK_Msg_NE + ("\abstract state & defined #", Body_Id, State_Id); + + else + SPARK_Msg_NE ("\variable & defined #", Body_Id, State_Id); + end if; + end if; + + Next_Elmt (State_Elmt); + end loop; + end if; + end Report_Unused_Body_States; + -------------------- -- Require_Entity -- -------------------- diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads index 1ed93de6243..81e63ed73d7 100644 --- a/gcc/ada/sem_util.ads +++ b/gcc/ada/sem_util.ads @@ -49,32 +49,6 @@ package Sem_Util is -- it the identifier of the block. Id denotes the generated entity. If the -- block already has an identifier, Id returns the entity of its label. - procedure Add_Contract_Item (Prag : Node_Id; Id : Entity_Id); - -- Add pragma Prag to the contract of a constant, entry, package [body], - -- subprogram [body] or variable denoted by Id. The following are valid - -- pragmas: - -- Abstract_State - -- Async_Readers - -- Async_Writers - -- Constant_After_Elaboration - -- Contract_Cases - -- Depends - -- Effective_Reads - -- Effective_Writes - -- Extensions_Visible - -- Global - -- Initial_Condition - -- Initializes - -- Part_Of - -- Postcondition - -- Precondition - -- Refined_Depends - -- Refined_Global - -- Refined_Post - -- Refined_States - -- Test_Case - -- Volatile_Function - procedure Add_Global_Declaration (N : Node_Id); -- These procedures adds a declaration N at the library level, to be -- elaborated before any other code in the unit. It is used for example @@ -276,6 +250,14 @@ package Sem_Util is -- error message on node N. Used in object declarations, type conversions -- and qualified expressions. + procedure Check_Function_With_Address_Parameter (Subp_Id : Entity_Id); + -- A subprogram that has an Address parameter and is declared in a Pure + -- package is not considered Pure, because the parameter may be used as a + -- pointer and the referenced data may change even if the address value + -- itself does not. + -- If the programmer gave an explicit Pure_Function pragma, then we respect + -- the pragma and leave the subprogram Pure. + procedure Check_Function_Writable_Actuals (N : Node_Id); -- (Ada 2012): If the construct N has two or more direct constituents that -- are names or expressions whose evaluation may occur in an arbitrary @@ -322,19 +304,20 @@ package Sem_Util is -- N is one of the statement forms that is a potentially blocking -- operation. If it appears within a protected action, emit warning. - procedure Check_Function_With_Address_Parameter (Subp_Id : Entity_Id); - -- A subprogram that has an Address parameter and is declared in a Pure - -- package is not considered Pure, because the parameter may be used as a - -- pointer and the referenced data may change even if the address value - -- itself does not. - -- If the programmer gave an explicit Pure_Function pragma, then we respect - -- the pragma and leave the subprogram Pure. - procedure Check_Result_And_Post_State (Subp_Id : Entity_Id); -- Determine whether the contract of subprogram Subp_Id mentions attribute -- 'Result and it contains an expression that evaluates differently in pre- -- and post-state. + procedure Check_Unused_Body_States (Body_Id : Entity_Id); + -- Verify that all abstract states and object declared in the state space + -- of a package body denoted by entity Body_Id are used as constituents. + -- Emit an error if this is not the case. + + function Collect_Body_States (Body_Id : Entity_Id) return Elist_Id; + -- Gather the entities of all abstract states and objects declared in the + -- body state space of package body Body_Id. + procedure Check_Unprotected_Access (Context : Node_Id; Expr : Node_Id); @@ -434,11 +417,6 @@ package Sem_Util is -- Return the corresponding spec of Decl when it denotes a package or a -- subprogram [stub], or the defining entity of Decl. - procedure Create_Generic_Contract (Unit : Node_Id); - -- Create a contract node for a generic package, generic subprogram or a - -- generic body denoted by Unit by collecting all source contract-related - -- pragmas in the contract of the unit. - function Current_Entity (N : Node_Id) return Entity_Id; pragma Inline (Current_Entity); -- Find the currently visible definition for a given identifier, that is to @@ -1159,14 +1137,6 @@ package Sem_Util is -- Inherit the rep item chain of type From_Typ without clobbering any -- existing rep items on Typ's chain. Typ is the destination type. - procedure Inherit_Subprogram_Contract - (Subp : Entity_Id; - From_Subp : Entity_Id); - -- Inherit relevant contract items from source subprogram From_Subp. Subp - -- denotes the destination subprogram. The inherited items are: - -- Extensions_Visible - -- ??? it would be nice if this routine handles Pre'Class and Post'Class - procedure Insert_Explicit_Dereference (N : Node_Id); -- In a context that requires a composite or subprogram type and where a -- prefix is an access type, rewrite the access type node N (which is the @@ -1877,6 +1847,13 @@ package Sem_Util is -- more there is at least one case in the generated code (the code for -- array assignment in a loop) that depends on this suppression. + procedure Report_Unused_Body_States + (Body_Id : Entity_Id; + States : Elist_Id); + -- Emit errors for each abstract state or object found in list States that + -- is declared in package body Body_Id, but is not used as constituent in a + -- state refinement. + procedure Require_Entity (N : Node_Id); -- N is a node which should have an entity value if it is an entity name. -- If not, then check if there were previous errors. If so, just fill diff --git a/gcc/ada/sinfo.adb b/gcc/ada/sinfo.adb index 824acd51ca1..0fc3851bac7 100644 --- a/gcc/ada/sinfo.adb +++ b/gcc/ada/sinfo.adb @@ -1860,6 +1860,14 @@ package body Sinfo is return Flag11 (N); end Is_Expanded_Build_In_Place_Call; + function Is_Expanded_Contract + (N : Node_Id) return Boolean is + begin + pragma Assert (False + or else NT (N).Nkind = N_Contract); + return Flag1 (N); + end Is_Expanded_Contract; + function Is_Finalization_Wrapper (N : Node_Id) return Boolean is begin @@ -5073,6 +5081,14 @@ package body Sinfo is Set_Flag11 (N, Val); end Set_Is_Expanded_Build_In_Place_Call; + procedure Set_Is_Expanded_Contract + (N : Node_Id; Val : Boolean := True) is + begin + pragma Assert (False + or else NT (N).Nkind = N_Contract); + Set_Flag1 (N, Val); + end Set_Is_Expanded_Contract; + procedure Set_Is_Finalization_Wrapper (N : Node_Id; Val : Boolean := True) is begin diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads index 218f4bcd3c8..5f2f0920eaf 100644 --- a/gcc/ada/sinfo.ads +++ b/gcc/ada/sinfo.ads @@ -1542,6 +1542,10 @@ package Sinfo is -- is called in a dispatching context. Used to prevent a formal/actual -- mismatch when the call is rewritten as a dispatching call. + -- Is_Expanded_Contract (Flag1-Sem) + -- Present in N_Contract nodes. Set if the contract has already undergone + -- expansion activities. + -- Is_Asynchronous_Call_Block (Flag7-Sem) -- A flag set in a Block_Statement node to indicate that it is the -- expansion of an asynchronous entry call. Such a block needs cleanup @@ -7564,6 +7568,7 @@ package Sinfo is -- Pre_Post_Conditions (Node1-Sem) (set to Empty if none) -- Contract_Test_Cases (Node2-Sem) (set to Empty if none) -- Classifications (Node3-Sem) (set to Empty if none) + -- Is_Expanded_Contract (Flag1-Sem) -- Pre_Post_Conditions contains a collection of pragmas that correspond -- to pre- and postconditions associated with an entry or a subprogram @@ -7592,9 +7597,11 @@ package Sinfo is -- Abstract_States -- Async_Readers -- Async_Writers + -- Constant_After_Elaboration -- Depends -- Effective_Reads -- Effective_Writes + -- Extensions_Visible -- Global -- Initial_Condition -- Initializes @@ -7602,6 +7609,7 @@ package Sinfo is -- Refined_Depends -- Refined_Global -- Refined_States + -- Volatile_Function -- The ordering is in LIFO fashion. ------------------- @@ -9322,6 +9330,9 @@ package Sinfo is function Is_Expanded_Build_In_Place_Call (N : Node_Id) return Boolean; -- Flag11 + function Is_Expanded_Contract + (N : Node_Id) return Boolean; -- Flag1 + function Is_Finalization_Wrapper (N : Node_Id) return Boolean; -- Flag9 @@ -10348,6 +10359,9 @@ package Sinfo is procedure Set_Is_Expanded_Build_In_Place_Call (N : Node_Id; Val : Boolean := True); -- Flag11 + procedure Set_Is_Expanded_Contract + (N : Node_Id; Val : Boolean := True); -- Flag1 + procedure Set_Is_Finalization_Wrapper (N : Node_Id; Val : Boolean := True); -- Flag9 @@ -12748,6 +12762,7 @@ package Sinfo is pragma Inline (Is_Elsif); pragma Inline (Is_Entry_Barrier_Function); pragma Inline (Is_Expanded_Build_In_Place_Call); + pragma Inline (Is_Expanded_Contract); pragma Inline (Is_Finalization_Wrapper); pragma Inline (Is_Folded_In_Parser); pragma Inline (Is_Generic_Contract_Pragma); @@ -13085,6 +13100,7 @@ package Sinfo is pragma Inline (Set_Is_Elsif); pragma Inline (Set_Is_Entry_Barrier_Function); pragma Inline (Set_Is_Expanded_Build_In_Place_Call); + pragma Inline (Set_Is_Expanded_Contract); pragma Inline (Set_Is_Finalization_Wrapper); pragma Inline (Set_Is_Folded_In_Parser); pragma Inline (Set_Is_Generic_Contract_Pragma); diff --git a/gcc/ada/switch-b.adb b/gcc/ada/switch-b.adb index 8e3806e0ef9..b26c583ea93 100644 --- a/gcc/ada/switch-b.adb +++ b/gcc/ada/switch-b.adb @@ -127,7 +127,7 @@ package body Switch.B is -- A little check, "gnat" at the start of a switch is not allowed except -- for the compiler - if Switch_Chars'Last >= Ptr + 3 + if Max >= Ptr + 3 and then Switch_Chars (Ptr .. Ptr + 3) = "gnat" then Osint.Fail ("invalid switch: """ & Switch_Chars & """" @@ -229,8 +229,28 @@ package body Switch.B is -- Processing for E switch when 'E' => - Ptr := Ptr + 1; + + -- -E is equivalent to -Ea (see below) + Exception_Tracebacks := True; + Ptr := Ptr + 1; + + if Ptr <= Max then + case Switch_Chars (Ptr) is + + -- -Ea sets Exception_Tracebacks + + when 'a' => null; + + -- -Es sets both Exception_Tracebacks and + -- Exception_Tracebacks_Symbolic. + + when 's' => Exception_Tracebacks_Symbolic := True; + when others => Bad_Switch (Switch_Chars); + end case; + + Ptr := Ptr + 1; + end if; -- Processing for F switch @@ -542,13 +562,11 @@ package body Switch.B is declare Src_Path_Name : constant String_Ptr := Get_RTS_Search_Dir - (Switch_Chars - (Ptr + 1 .. Switch_Chars'Last), + (Switch_Chars (Ptr + 1 .. Max), Include); Lib_Path_Name : constant String_Ptr := Get_RTS_Search_Dir - (Switch_Chars - (Ptr + 1 .. Switch_Chars'Last), + (Switch_Chars (Ptr + 1 .. Max), Objects); begin diff --git a/gcc/ada/switch-b.ads b/gcc/ada/switch-b.ads index 9ec91896650..e22296a15b4 100644 --- a/gcc/ada/switch-b.ads +++ b/gcc/ada/switch-b.ads @@ -6,7 +6,7 @@ -- -- -- S p e c -- -- -- --- Copyright (C) 2001-2007, Free Software Foundation, Inc. -- +-- Copyright (C) 2001-2015, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -32,7 +32,7 @@ package Switch.B is procedure Scan_Binder_Switches (Switch_Chars : String); - -- Procedures to scan out binder switches stored in the given string. + -- Procedure to scan out binder switches stored in the given string. -- The first character is known to be a valid switch character, and there -- are no blanks or other switch terminator characters in the string, so -- the entire string should consist of valid switch characters, except that