------------------------------------------------------------------------------ -- -- -- GNAT COMPILER COMPONENTS -- -- -- -- C O N T R A C T S -- -- -- -- S p e c -- -- -- -- Copyright (C) 2015-2024, 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, entry family, -- [generic] package, package body, protected unit, [generic] subprogram, -- subprogram body, variable, task unit, or type denoted by Id. -- The following are valid pragmas: -- -- Abstract_State -- Always_Terminates -- Async_Readers -- Async_Writers -- Attach_Handler -- Constant_After_Elaboration -- Contract_Cases -- Depends -- Effective_Reads -- Effective_Writes -- Exceptional_Cases -- Extensions_Visible -- Global -- Initial_Condition -- Initializes -- Interrupt_Handler -- No_Caching -- Part_Of -- Postcondition -- Precondition -- Refined_Depends -- Refined_Global -- Refined_Post -- Refined_States -- Side_Effects -- Subprogram_Variant -- Test_Case -- Volatile_Function procedure Analyze_Contracts (L : List_Id); -- Analyze the contracts of all eligible constructs found in list L procedure Analyze_Pragmas_In_Declarations (Body_Id : Entity_Id); -- Perform early analysis of pragmas at the top of a given subprogram's -- declarations. -- -- The purpose of this is to analyze contract-related pragmas for later -- processing, but also to handle other such pragmas before these -- declarations get moved to an internal wrapper as part of contract -- expansion. For example, pragmas Inline, Ghost, Volatile all need to -- apply directly to the subprogram and not be moved to a wrapper. procedure Analyze_Entry_Or_Subprogram_Body_Contract (Body_Id : Entity_Id); -- Analyze all delayed pragmas chained on the contract of entry or -- subprogram body Body_Id as if they appeared at the end of a declarative -- region. Pragmas in question are: -- -- Always_Terminates (stand alone subprogram body) -- Contract_Cases (stand alone subprogram body) -- Depends (stand alone subprogram body) -- Exceptional_Cases (stand alone subprogram body) -- Global (stand alone subprogram body) -- Postcondition (stand alone subprogram body) -- Precondition (stand alone subprogram body) -- Refined_Depends -- Refined_Global -- Refined_Post -- Subprogram_Variant (stand alone subprogram body) -- Test_Case (stand alone subprogram body) procedure Analyze_Entry_Or_Subprogram_Contract (Subp_Id : Entity_Id; Freeze_Id : Entity_Id := Empty); -- Analyze all delayed pragmas chained on the contract of entry or -- subprogram Subp_Id as if they appeared at the end of a declarative -- region. The pragmas in question are: -- -- Always_Terminates -- Contract_Cases -- Depends -- Exceptional_Cases -- Global -- Postcondition -- Precondition -- Subprogram_Variant -- Test_Case -- -- Freeze_Id is the entity of a [generic] package body or a [generic] -- subprogram body which "freezes" the contract of Subp_Id. procedure Analyze_Object_Contract (Obj_Id : Entity_Id; Freeze_Id : Entity_Id := Empty); -- 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 -- Depends (single concurrent object) -- Effective_Reads -- Effective_Writes -- Global (single concurrent object) -- Part_Of -- -- Freeze_Id is the entity of a [generic] package body or a [generic] -- subprogram body which "freezes" the contract of Obj_Id. procedure Analyze_Type_Contract (Type_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 -- Postcondition -- Precondition -- -- In the case of a protected or task type, there will also be -- a call to Analyze_Protected_Contract or Analyze_Task_Contract. procedure Analyze_Package_Body_Contract (Body_Id : Entity_Id; Freeze_Id : Entity_Id := Empty); -- Analyze all delayed pragmas chained on the contract of package body -- Body_Id as if they appeared at the end of a declarative region. The -- pragmas that are considered are: -- -- Refined_State -- -- Freeze_Id is the entity of a [generic] package body or a [generic] -- subprogram body which "freezes" the contract of Body_Id. procedure Analyze_Package_Contract (Pack_Id : Entity_Id); -- Analyze all delayed pragmas chained on the contract of package Pack_Id -- as if they appeared at the end of a declarative region. The pragmas -- that are considered are: -- -- Initial_Condition -- Initializes procedure Analyze_Protected_Contract (Prot_Id : Entity_Id); -- Analyze all delayed pragmas chained on the contract of protected unit -- Prot_Id if they appeared at the end of a declarative region. Currently -- there are no such pragmas. procedure Analyze_Subprogram_Body_Stub_Contract (Stub_Id : Entity_Id); -- Analyze all delayed pragmas chained on the contract of subprogram body -- stub Stub_Id as if they appeared at the end of a declarative region. The -- pragmas in question are: -- -- Always_Terminates -- Contract_Cases -- Depends -- Exceptional_Cases -- Global -- Postcondition -- Precondition -- Refined_Depends -- Refined_Global -- Refined_Post -- Subprogram_Variant -- Test_Case procedure Analyze_Task_Contract (Task_Id : Entity_Id); -- Analyze all delayed pragmas chained on the contract of task unit Task_Id -- as if they appeared at the end of a declarative region. The pragmas in -- question are: -- -- Depends -- Global procedure Build_Entry_Contract_Wrapper (E : Entity_Id; Decl : Node_Id); -- Build the body of a wrapper procedure for an entry or entry family that -- has contract cases, preconditions, or postconditions, and add it to the -- freeze actions of the related synchronized type. -- -- The body first verifies the preconditions and case guards of the -- contract cases, then invokes the entry [family], and finally verifies -- the postconditions and the consequences of the contract cases. E denotes -- the entry family. Decl denotes the declaration of the enclosing -- synchronized type. 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 Freeze_Previous_Contracts (Body_Decl : Node_Id); -- Freeze the contracts of all source constructs found in the declarative -- list which contains entry, package, protected, subprogram, or task body -- denoted by Body_Decl. In addition, freeze the contract of the nearest -- enclosing package body. 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 -- Side_Effects -- ??? 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 Make_Class_Precondition_Subps (Subp_Id : Entity_Id; Late_Overriding : Boolean := False); -- Build helpers that at run time evaluate statically and dynamically the -- class-wide preconditions of Subp_Id; build also the indirect-call -- wrapper (ICW) required to check class-wide preconditions when the -- subprogram is invoked through an access-to-subprogram, or when it -- overrides an inherited class-wide precondition (see AI12-0195-1). -- Late_Overriding enables special handling required for late-overriding -- subprograms. -- -- For example, if we have a subprogram with the following profile: -- -- procedure Prim (Obj : TagTyp; ) -- with Pre'Class => F1 (Obj) and F2(Obj) -- -- We build the following helper that evaluates statically the class-wide -- precondition: -- -- function PrimSP (Obj : TagTyp) return Boolean is -- begin -- return F1 (Obj) and F2(Obj); -- end PrimSP; -- -- ... and the following helper that evaluates dynamically the class-wide -- precondition: -- -- function PrimDP (Obj : TagTyp'Class; ...) return Boolean is -- begin -- return F1 (Obj) and F2(Obj); -- end PrimSP; -- -- ... and the following indirect-call wrapper (ICW) that is used by the -- code generated by the compiler for indirect calls: -- -- procedure PrimICW (Obj : TagTyp; is -- begin -- if not PrimSP (Obj) then -- $raise_assert_failure ("failed precondition in call at ..."); -- end if; -- -- Prim (Obj, ...); -- end Prim; procedure Merge_Class_Conditions (Spec_Id : Entity_Id); -- Merge and preanalyze all class-wide conditions of Spec_Id (class-wide -- preconditions merged with operator or-else; class-wide postconditions -- merged with operator and-then). Ignored pre/postconditions are also -- merged since, although they are not required to generate code, their -- preanalysis is required to perform semantic checks. Resulting merged -- expressions are later installed by the expander in helper subprograms -- which are invoked from the caller side; they are also used to build -- the dispatch-table wrapper (DTW), if required. procedure Preanalyze_Class_Conditions (Spec_Id : Entity_Id); -- Preanalyze class-wide pre-/postconditions of the given subprogram -- specification. procedure Process_Class_Conditions_At_Freeze_Point (Typ : Entity_Id); -- Merge, preanalyze, and check class-wide pre/postconditions of Typ -- primitives. 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;