------------------------------------------------------------------------------ -- -- -- GNAT COMPILER COMPONENTS -- -- -- -- E X P _ C H 8 -- -- -- -- B o d y -- -- -- -- Copyright (C) 1992-2004 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 2, 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 COPYING. If not, write -- -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- -- MA 02111-1307, USA. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ with Atree; use Atree; with Einfo; use Einfo; with Exp_Dbug; use Exp_Dbug; with Exp_Util; use Exp_Util; with Freeze; use Freeze; with Nlists; use Nlists; with Sem; use Sem; with Sem_Ch8; use Sem_Ch8; with Sinfo; use Sinfo; with Stand; use Stand; with Targparm; use Targparm; package body Exp_Ch8 is --------------------------------------------- -- Expand_N_Exception_Renaming_Declaration -- --------------------------------------------- procedure Expand_N_Exception_Renaming_Declaration (N : Node_Id) is Decl : constant Node_Id := Debug_Renaming_Declaration (N); begin if Present (Decl) then Insert_Action (N, Decl); end if; end Expand_N_Exception_Renaming_Declaration; ------------------------------------------ -- Expand_N_Object_Renaming_Declaration -- ------------------------------------------ -- Most object renaming cases can be done by just capturing the address -- of the renamed object. The cases in which this is not true are when -- this address is not computable, since it involves extraction of a -- packed array element, or of a record component to which a component -- clause applies (that can specify an arbitrary bit boundary), or where -- the enclosing record itself has a non-standard representation. -- In these two cases, we pre-evaluate the renaming expression, by -- extracting and freezing the values of any subscripts, and then we -- set the flag Is_Renaming_Of_Object which means that any reference -- to the object will be handled by macro substitution in the front -- end, and the back end will know to ignore the renaming declaration. -- An additional odd case that requires processing by expansion is -- the renaming of a discriminant of a mutable record type. The object -- is a constant because it renames something that cannot be assigned to, -- but in fact the underlying value can change and must be reevaluated -- at each reference. Gigi does have a notion of a "constant view" of -- an object, and therefore the front-end must perform the expansion. -- For simplicity, and to bypass some obscure code-generation problem, -- we use macro substitution for all renamed discriminants, whether the -- enclosing type is constrained or not. -- The other special processing required is for the case of renaming -- of an object of a class wide type, where it is necessary to build -- the appropriate subtype for the renamed object. -- More comments needed for this para ??? procedure Expand_N_Object_Renaming_Declaration (N : Node_Id) is Nam : constant Node_Id := Name (N); T : Entity_Id; Decl : Node_Id; procedure Evaluate_Name (Fname : Node_Id); -- A recursive procedure used to freeze a name in the sense described -- above, i.e. any variable references or function calls are removed. -- Of course the outer level variable reference must not be removed. -- For example in A(J,F(K)), A is left as is, but J and F(K) are -- evaluated and removed. function Evaluation_Required (Nam : Node_Id) return Boolean; -- Determines whether it is necessary to do static name evaluation -- for renaming of Nam. It is considered necessary if evaluating the -- name involves indexing a packed array, or extracting a component -- of a record to which a component clause applies. Note that we are -- only interested in these operations if they occur as part of the -- name itself, subscripts are just values that are computed as part -- of the evaluation, so their form is unimportant. ------------------- -- Evaluate_Name -- ------------------- procedure Evaluate_Name (Fname : Node_Id) is K : constant Node_Kind := Nkind (Fname); E : Node_Id; begin -- For an explicit dereference, we simply force the evaluation -- of the name expression. The dereference provides a value that -- is the address for the renamed object, and it is precisely -- this value that we want to preserve. if K = N_Explicit_Dereference then Force_Evaluation (Prefix (Fname)); -- For a selected component, we simply evaluate the prefix elsif K = N_Selected_Component then Evaluate_Name (Prefix (Fname)); -- For an indexed component, or an attribute reference, we evaluate -- the prefix, which is itself a name, recursively, and then force -- the evaluation of all the subscripts (or attribute expressions). elsif K = N_Indexed_Component or else K = N_Attribute_Reference then Evaluate_Name (Prefix (Fname)); E := First (Expressions (Fname)); while Present (E) loop Force_Evaluation (E); if Original_Node (E) /= E then Set_Do_Range_Check (E, Do_Range_Check (Original_Node (E))); end if; Next (E); end loop; -- For a slice, we evaluate the prefix, as for the indexed component -- case and then, if there is a range present, either directly or -- as the constraint of a discrete subtype indication, we evaluate -- the two bounds of this range. elsif K = N_Slice then Evaluate_Name (Prefix (Fname)); declare DR : constant Node_Id := Discrete_Range (Fname); Constr : Node_Id; Rexpr : Node_Id; begin if Nkind (DR) = N_Range then Force_Evaluation (Low_Bound (DR)); Force_Evaluation (High_Bound (DR)); elsif Nkind (DR) = N_Subtype_Indication then Constr := Constraint (DR); if Nkind (Constr) = N_Range_Constraint then Rexpr := Range_Expression (Constr); Force_Evaluation (Low_Bound (Rexpr)); Force_Evaluation (High_Bound (Rexpr)); end if; end if; end; -- For a type conversion, the expression of the conversion must be -- the name of an object, and we simply need to evaluate this name. elsif K = N_Type_Conversion then Evaluate_Name (Expression (Fname)); -- For a function call, we evaluate the call elsif K = N_Function_Call then Force_Evaluation (Fname); -- The remaining cases are direct name, operator symbol and -- character literal. In all these cases, we do nothing, since -- we want to reevaluate each time the renamed object is used. else return; end if; end Evaluate_Name; ------------------------- -- Evaluation_Required -- ------------------------- function Evaluation_Required (Nam : Node_Id) return Boolean is begin if Nkind (Nam) = N_Indexed_Component or else Nkind (Nam) = N_Slice then if Is_Packed (Etype (Prefix (Nam))) then return True; else return Evaluation_Required (Prefix (Nam)); end if; elsif Nkind (Nam) = N_Selected_Component then declare Rec_Type : constant Entity_Id := Etype (Prefix (Nam)); begin if Present (Component_Clause (Entity (Selector_Name (Nam)))) or else Has_Non_Standard_Rep (Rec_Type) then return True; elsif Ekind (Entity (Selector_Name (Nam))) = E_Discriminant and then Is_Record_Type (Rec_Type) and then not Is_Concurrent_Record_Type (Rec_Type) then return True; else return Evaluation_Required (Prefix (Nam)); end if; end; else return False; end if; end Evaluation_Required; -- Start of processing for Expand_N_Object_Renaming_Declaration begin -- Perform name evaluation if required if Evaluation_Required (Nam) then Evaluate_Name (Nam); Set_Is_Renaming_Of_Object (Defining_Identifier (N)); end if; -- Deal with construction of subtype in class-wide case T := Etype (Defining_Identifier (N)); if Is_Class_Wide_Type (T) then Expand_Subtype_From_Expr (N, T, Subtype_Mark (N), Name (N)); Find_Type (Subtype_Mark (N)); Set_Etype (Defining_Identifier (N), Entity (Subtype_Mark (N))); -- Freeze the class-wide subtype here to ensure that the subtype -- and equivalent type are frozen before the renaming. This is -- required for targets where Frontend_Layout_On_Target is true. -- For targets where Gigi is used, class-wide subtype should not -- be frozen (in that case the subtype is marked as already frozen -- when it's created). if Frontend_Layout_On_Target then Freeze_Before (N, Entity (Subtype_Mark (N))); end if; end if; -- Create renaming entry for debug information Decl := Debug_Renaming_Declaration (N); if Present (Decl) then Insert_Action (N, Decl); end if; end Expand_N_Object_Renaming_Declaration; ------------------------------------------- -- Expand_N_Package_Renaming_Declaration -- ------------------------------------------- procedure Expand_N_Package_Renaming_Declaration (N : Node_Id) is Decl : constant Node_Id := Debug_Renaming_Declaration (N); begin if Present (Decl) then -- If we are in a compilation unit, then this is an outer -- level declaration, and must have a scope of Standard if Nkind (Parent (N)) = N_Compilation_Unit then declare Aux : constant Node_Id := Aux_Decls_Node (Parent (N)); begin New_Scope (Standard_Standard); if No (Actions (Aux)) then Set_Actions (Aux, New_List (Decl)); else Append (Decl, Actions (Aux)); end if; Analyze (Decl); Pop_Scope; end; -- Otherwise, just insert after the package declaration else Insert_Action (N, Decl); end if; end if; end Expand_N_Package_Renaming_Declaration; end Exp_Ch8;