| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT COMPILER COMPONENTS -- |
| -- -- |
| -- F R E E Z E -- |
| -- -- |
| -- S p e c -- |
| -- -- |
| -- Copyright (C) 1992-2022, 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 Types; use Types; |
| |
| package Freeze is |
| |
| -------------------------- |
| -- Handling of Freezing -- |
| -------------------------- |
| |
| -- In the formal Ada semantics, freezing of entities occurs at a well |
| -- defined point, described in (RM 13.14). The model in GNAT of freezing |
| -- is that a Freeze_Entity node is generated at the point where an entity |
| -- is frozen, and the entity contains a pointer (Freeze_Node) to this |
| -- generated freeze node. |
| |
| -- The freeze node is processed in the expander to generate associated |
| -- data and subprograms (e.g. an initialization procedure) which must |
| -- be delayed until the type is frozen and its representation can be |
| -- fully determined. Subsequently the freeze node is used by Gigi to |
| -- determine the point at which it should elaborate the corresponding |
| -- entity (this elaboration also requires the representation of the |
| -- entity to be fully determinable). The freeze node is also used to |
| -- provide additional diagnostic information (pinpointing the freeze |
| -- point), when order of freezing errors are detected. |
| |
| -- If we were fully faithful to the Ada model, we would generate freeze |
| -- nodes for all entities, but that is a bit heavy so we optimize (that |
| -- is the nice word) or cut corners (which is a bit more honest). For |
| -- many entities, we do not need to delay the freeze and instead can |
| -- freeze them at the point of declaration. The conditions for this |
| -- early freezing being permissible are as follows: |
| |
| -- There is no associated expander activity that needs to be delayed |
| |
| -- Gigi can fully elaborate the entity at the point of occurrence (or, |
| -- equivalently, no real elaboration is required for the entity). |
| |
| -- In order for these conditions to be met (especially the second), it |
| -- must be the case that all representation characteristics of the entity |
| -- can be determined at declaration time. |
| |
| -- The following indicates how freezing is handled for all entity kinds: |
| |
| -- Types |
| |
| -- All declared types have freeze nodes, as well as anonymous base |
| -- types created for type declarations where the defining identifier |
| -- is a first subtype of the anonymous type. |
| |
| -- Subtypes |
| |
| -- All first subtypes have freeze nodes. Other subtypes need freeze |
| -- nodes if the corresponding base type has not yet been frozen. If |
| -- the base type has been frozen, then there is no need for a freeze |
| -- node, since no rep clauses can appear for the subtype in any case. |
| |
| -- Implicit types and subtypes |
| |
| -- As noted above, implicit base types always have freeze nodes. Other |
| -- implicit types and subtypes typically do not require freeze nodes, |
| -- because there is no possibility of delaying any information about |
| -- their representation. |
| |
| -- Subprograms |
| -- |
| -- Are frozen at the point of declaration unless one or more of the |
| -- formal types or return type themselves have delayed freezing and |
| -- are not yet frozen. This includes the case of a formal access type |
| -- where the designated type is not frozen. Note that we are talking |
| -- about subprogram specs here (subprogram body entities have no |
| -- relevance), and in any case, subprogram bodies freeze everything. |
| |
| -- Objects with dynamic address clauses |
| -- |
| -- These have a delayed freeze. Gigi will generate code to evaluate |
| -- the initialization expression if present and store it in a temp. |
| -- The actual object is created at the point of the freeze, and if |
| -- necessary initialized by copying the value of this temporary. |
| |
| -- Formal Parameters |
| -- |
| -- Are frozen when the associated subprogram is frozen, so there is |
| -- never any need for them to have delayed freezing. |
| |
| -- Other Objects |
| -- |
| -- Are always frozen at the point of declaration |
| |
| -- All Other Entities |
| |
| -- Are always frozen at the point of declaration |
| |
| -- The flag Has_Delayed_Freeze is used to indicate that delayed freezing |
| -- is required. Usually the associated freeze node is allocated at the |
| -- freezing point. One special exception occurs with anonymous base types, |
| -- where the freeze node is preallocated at the point of declaration, so |
| -- that the First_Subtype_Link field can be set. |
| |
| Freezing_Library_Level_Tagged_Type : Boolean := False; |
| -- Flag used to indicate that we are freezing the primitives of a library |
| -- level tagged type. Used to disable checks on premature freezing. |
| -- More documentation needed??? why is this flag needed? what are these |
| -- checks? why do they need disabling in some cases? |
| |
| ----------------- |
| -- Subprograms -- |
| ----------------- |
| |
| function Build_Renamed_Body |
| (Decl : Node_Id; |
| New_S : Entity_Id) return Node_Id; |
| -- Rewrite renaming declaration as a subprogram body, whose single |
| -- statement is a call to the renamed entity. New_S is the entity that |
| -- appears in the renaming declaration. If this is a Renaming_As_Body, |
| -- then Decl is the original subprogram declaration that is completed |
| -- by the renaming, otherwise it is the renaming declaration itself. |
| -- The caller inserts the body where required. If this call comes |
| -- from a freezing action, the resulting body is analyzed at once. |
| |
| procedure Check_Compile_Time_Size (T : Entity_Id); |
| -- Check to see whether the size of the type T is known at compile time. |
| -- There are three possible cases: |
| -- |
| -- Size is not known at compile time. In this case, the call has no |
| -- effect. Note that the processing is conservative here, in the sense |
| -- that this routine may decide that the size is not known even if in |
| -- fact Gigi decides it is known, but the opposite situation can never |
| -- occur. |
| -- |
| -- Size is known at compile time, but the actual value of the size is not |
| -- known to the front end or is greater than System_Max_Integer_Size. In |
| -- this case, Size_Known_At_Compile_Time is set, but the RM_Size field is |
| -- left set to zero (to be set by Gigi). |
| -- |
| -- Size is known at compile time, and the actual value of the size is |
| -- known to the front end and not greater than System_Max_Integer_Size. |
| -- In this case, Size_Known_At_Compile_Time is set, and in addition the |
| -- RM_Size field is set to the required size, allowing for possible front |
| -- end packing of an array using this type as a component type. |
| -- |
| -- Note: the flag Size_Known_At_Compile_Time is used to determine if the |
| -- secondary stack must be used to return a value of the type, and also |
| -- to determine whether a component clause is allowed for a component |
| -- of the given type. |
| -- |
| -- Note: this is public because of one dubious use in Sem_Res??? |
| -- |
| -- Note: Check_Compile_Time_Size does not test the case of the size being |
| -- known because a size clause is specifically given. That is because we |
| -- do not allow a size clause if the size would not otherwise be known at |
| -- compile time in any case. |
| |
| procedure Check_Inherited_Conditions |
| (R : Entity_Id; |
| Late_Overriding : Boolean := False); |
| -- For a tagged derived type R, create wrappers for inherited operations |
| -- that have class-wide conditions, so it can be properly rewritten if |
| -- it involves calls to other overriding primitives. Late_Overriding is |
| -- True when we are processing the body of a primitive with no previous |
| -- spec defined after R is frozen (see Check_Dispatching_Operation). |
| |
| function Is_Full_Access_Aggregate (N : Node_Id) return Boolean; |
| -- If a full access object is initialized with an aggregate or is assigned |
| -- an aggregate, we have to prevent a piecemeal access or assignment to the |
| -- object, even if the aggregate is to be expanded. We create a temporary |
| -- for the aggregate, and assign the temporary instead, so that the back |
| -- end can generate an atomic move for it. This is only done in the context |
| -- of an object declaration or an assignment. Function is a noop and |
| -- returns false in other contexts. |
| |
| procedure Explode_Initialization_Compound_Statement (E : Entity_Id); |
| -- If Initialization_Statements (E) is an N_Compound_Statement, insert its |
| -- actions in the enclosing list and reset the attribute. |
| |
| function Freeze_Entity |
| (E : Entity_Id; |
| N : Node_Id; |
| Do_Freeze_Profile : Boolean := True) return List_Id; |
| -- Freeze an entity, and return Freeze nodes, to be inserted at the point |
| -- of call. N is a node whose source location corresponds to the freeze |
| -- point. This is used in placing warning messages in the situation where |
| -- it appears that a type has been frozen too early, e.g. when a primitive |
| -- operation is declared after the freezing point of its tagged type. |
| -- Returns No_List if no freeze nodes needed. Parameter Do_Freeze_Profile |
| -- is used when E is a subprogram, and determines whether the profile of |
| -- the subprogram should be frozen as well. |
| |
| procedure Freeze_All (From : Entity_Id; After : in out Node_Id); |
| -- Before a non-instance body, or at the end of a declarative part, |
| -- freeze all entities therein that are not yet frozen. Calls itself |
| -- recursively to catch types in inner packages that were not frozen |
| -- at the inner level because they were not yet completely defined. |
| -- This routine also analyzes and freezes default parameter expressions |
| -- in subprogram specifications (this has to be delayed until all the |
| -- types are frozen). The resulting freeze nodes are inserted just |
| -- after node After (which is a list node) and analyzed. On return, |
| -- 'After' is updated to point to the last node inserted (or is returned |
| -- unchanged if no nodes were inserted). 'From' is the last entity frozen |
| -- in the scope. It is used to prevent a quadratic traversal over already |
| -- frozen entities. |
| |
| procedure Freeze_Before |
| (N : Node_Id; |
| T : Entity_Id; |
| Do_Freeze_Profile : Boolean := True); |
| -- Freeze T then Insert the generated Freeze nodes before the node N. Flag |
| -- Do_Freeze_Profile is used when T is an overloadable entity and indicates |
| -- whether its profile should be frozen at the same time. |
| |
| procedure Freeze_Expression (N : Node_Id); |
| -- Freezes the required entities when the Expression N causes freezing. |
| -- The node N here is either a subexpression node (a "real" expression) |
| -- or a subtype mark, or a subtype indication. The latter two cases are |
| -- not really expressions, but they can appear within expressions and |
| -- so need to be similarly treated. Freeze_Expression takes care of |
| -- determining the proper insertion point for generated freeze actions. |
| |
| procedure Freeze_Expr_Types |
| (Def_Id : Entity_Id; |
| Typ : Entity_Id; |
| Expr : Node_Id; |
| N : Node_Id); |
| -- N is the body constructed for an expression function that is a |
| -- completion, and Def_Id is the function being completed. |
| -- This procedure freezes before N all the types referenced in Expr, |
| -- which is either the expression of the expression function, or |
| -- the expression in a pre/post aspect that applies to Def_Id; |
| |
| procedure Freeze_Fixed_Point_Type (Typ : Entity_Id); |
| -- Freeze fixed point type. For fixed-point types, we have to defer |
| -- setting the size and bounds till the freeze point, since they are |
| -- potentially affected by the presence of size and small clauses. |
| |
| procedure Freeze_Itype (T : Entity_Id; N : Node_Id); |
| -- This routine is called when an Itype is created and must be frozen |
| -- immediately at the point of creation (for the sake of the expansion |
| -- activities in Exp_Ch3 (for example, the creation of packed array |
| -- types). We can't just let Freeze_Expression do this job since it |
| -- goes out of its way to make sure that the freeze node occurs at a |
| -- point outside the current construct, e.g. outside the expression or |
| -- outside the initialization procedure. That's normally right, but |
| -- not in this case, since if we create an Itype in an expression it |
| -- may be the case that it is not always elaborated (for example it |
| -- may result from the right operand of a short circuit). In this case |
| -- we want the freeze node to be inserted at the same point as the Itype. |
| -- The node N provides both the location for the freezing and also the |
| -- insertion point for the resulting freeze nodes. |
| |
| end Freeze; |