rt_gccstream/gcc/ada/sem_scil.adb

703 lines
27 KiB
Ada

------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- S E M _ S C I L --
-- --
-- B o d y --
-- --
-- Copyright (C) 2009, 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 Einfo; use Einfo;
with Namet; use Namet;
with Nlists; use Nlists;
with Opt; use Opt;
with Rtsfind; use Rtsfind;
with Sem; use Sem;
with Sem_Aux; use Sem_Aux;
with Sem_Util; use Sem_Util;
with Sinfo; use Sinfo;
with Snames; use Snames;
with Stand; use Stand;
package body Sem_SCIL is
----------------------
-- Adjust_SCIL_Node --
----------------------
procedure Adjust_SCIL_Node (Old_Node : Node_Id; New_Node : Node_Id) is
SCIL_Node : Node_Id;
begin
pragma Assert (Generate_SCIL);
-- Check cases in which no action is required. Currently the only SCIL
-- nodes that may require adjustment are those of dispatching calls
-- internally generated by the frontend.
if Comes_From_Source (Old_Node)
or else not
Nkind_In (New_Node, N_Function_Call, N_Procedure_Call_Statement)
then
return;
-- Conditional expression associated with equality operator. Old_Node
-- may be part of the expansion of the predefined equality operator of
-- a tagged type and hence we need to check if it has a SCIL dispatching
-- node that needs adjustment.
elsif Nkind (Old_Node) = N_Conditional_Expression
and then (Nkind (Original_Node (Old_Node)) = N_Op_Eq
or else
(Nkind (Original_Node (Old_Node)) = N_Function_Call
and then Chars (Name (Original_Node (Old_Node))) =
Name_Op_Eq))
then
null;
-- Type conversions may involve dispatching calls to functions whose
-- associated SCIL dispatching node needs adjustment.
elsif Nkind_In (Old_Node, N_Type_Conversion,
N_Unchecked_Type_Conversion)
then
null;
-- Relocated subprogram call
elsif Nkind (Old_Node) = Nkind (New_Node)
and then Original_Node (Old_Node) = Original_Node (New_Node)
then
null;
else
return;
end if;
-- Search for the SCIL node and update it (if found)
SCIL_Node := Find_SCIL_Node (Old_Node);
if Present (SCIL_Node) then
Set_SCIL_Related_Node (SCIL_Node, New_Node);
end if;
end Adjust_SCIL_Node;
---------------------
-- Check_SCIL_Node --
---------------------
function Check_SCIL_Node (N : Node_Id) return Traverse_Result is
Ctrl_Tag : Node_Id;
Ctrl_Typ : Entity_Id;
begin
if Nkind (N) = N_SCIL_Membership_Test then
-- Check contents of the boolean expression associated with the
-- membership test.
pragma Assert (Nkind (SCIL_Related_Node (N)) = N_Identifier
and then Etype (SCIL_Related_Node (N)) = Standard_Boolean);
-- Check the entity identifier of the associated tagged type (that
-- is, in testing for membership in T'Class, the entity id of the
-- specific type T).
-- Note: When the SCIL node is generated the private and full-view
-- of the tagged types may have been swapped and hence the node
-- referenced by attribute SCIL_Entity may be the private view.
-- Therefore, in order to uniformily locate the full-view we use
-- attribute Underlying_Type.
pragma Assert (Is_Tagged_Type (Underlying_Type (SCIL_Entity (N))));
-- Interface types are unsupported
pragma Assert (not Is_Interface (Underlying_Type (SCIL_Entity (N))));
-- Check the decoration of the expression that denotes the tag value
-- being tested
Ctrl_Tag := SCIL_Tag_Value (N);
case Nkind (Ctrl_Tag) is
-- For class-wide membership tests the SCIL tag value is the tag
-- of the tested object (i.e. Obj.Tag).
when N_Selected_Component =>
pragma Assert (Etype (Ctrl_Tag) = RTE (RE_Tag));
null;
when others =>
pragma Assert (False);
null;
end case;
return Skip;
elsif Nkind (N) = N_SCIL_Dispatching_Call then
Ctrl_Tag := SCIL_Controlling_Tag (N);
-- SCIL_Related_Node of SCIL dispatching call nodes MUST reference
-- subprogram calls.
if not Nkind_In (SCIL_Related_Node (N), N_Function_Call,
N_Procedure_Call_Statement)
then
pragma Assert (False);
raise Program_Error;
-- In simple cases the controlling tag is the tag of the controlling
-- argument (i.e. Obj.Tag).
elsif Nkind (Ctrl_Tag) = N_Selected_Component then
Ctrl_Typ := Etype (Ctrl_Tag);
-- Interface types are unsupported
if Is_Interface (Ctrl_Typ)
or else (RTE_Available (RE_Interface_Tag)
and then Ctrl_Typ = RTE (RE_Interface_Tag))
then
null;
else
pragma Assert (Ctrl_Typ = RTE (RE_Tag));
null;
end if;
-- When the controlling tag of a dispatching call is an identifier
-- the SCIL_Controlling_Tag attribute references the corresponding
-- object or parameter declaration. Interface types are still
-- unsupported.
elsif Nkind_In (Ctrl_Tag, N_Object_Declaration,
N_Parameter_Specification)
then
Ctrl_Typ := Etype (Defining_Identifier (Ctrl_Tag));
-- Interface types are unsupported.
if Is_Interface (Ctrl_Typ)
or else (RTE_Available (RE_Interface_Tag)
and then Ctrl_Typ = RTE (RE_Interface_Tag))
or else (Is_Access_Type (Ctrl_Typ)
and then
Is_Interface
(Available_View
(Base_Type (Designated_Type (Ctrl_Typ)))))
then
null;
else
pragma Assert
(Ctrl_Typ = RTE (RE_Tag)
or else
(Is_Access_Type (Ctrl_Typ)
and then Available_View
(Base_Type (Designated_Type (Ctrl_Typ))) =
RTE (RE_Tag)));
null;
end if;
-- Interface types are unsupported
elsif Is_Interface (Etype (Ctrl_Tag)) then
null;
else
pragma Assert (False);
raise Program_Error;
end if;
return Skip;
-- Node is not N_SCIL_Dispatching_Call
else
return OK;
end if;
end Check_SCIL_Node;
--------------------
-- Find_SCIL_Node --
--------------------
function Find_SCIL_Node (Node : Node_Id) return Node_Id is
Found_Node : Node_Id;
-- This variable stores the last node found by the nested subprogram
-- Find_SCIL_Node.
function Find_SCIL_Node (L : List_Id) return Boolean;
-- Searches in list L for a SCIL node associated with a dispatching call
-- whose SCIL_Related_Node is Node. If found returns true and stores the
-- SCIL node in Found_Node; otherwise returns False and sets Found_Node
-- to Empty.
--------------------
-- Find_SCIL_Node --
--------------------
function Find_SCIL_Node (L : List_Id) return Boolean is
N : Node_Id;
begin
N := First (L);
while Present (N) loop
if Nkind (N) in N_SCIL_Node
and then SCIL_Related_Node (N) = Node
then
Found_Node := N;
return True;
end if;
Next (N);
end loop;
Found_Node := Empty;
return False;
end Find_SCIL_Node;
-- Local variables
P : Node_Id;
-- Start of processing for Find_SCIL_Node
begin
pragma Assert (Generate_SCIL);
-- Search for the SCIL node in list associated with a transient scope
if Scope_Is_Transient then
declare
SE : Scope_Stack_Entry
renames Scope_Stack.Table (Scope_Stack.Last);
begin
if SE.Is_Transient
and then Present (SE.Actions_To_Be_Wrapped_Before)
and then Find_SCIL_Node (SE.Actions_To_Be_Wrapped_Before)
then
return Found_Node;
end if;
end;
end if;
-- Otherwise climb up the tree searching for the SCIL node analyzing
-- all the lists in which Insert_Actions may have inserted it
P := Node;
while Present (P) loop
case Nkind (P) is
-- Actions associated with AND THEN or OR ELSE
when N_Short_Circuit =>
if Present (Actions (P))
and then Find_SCIL_Node (Actions (P))
then
return Found_Node;
end if;
-- Actions of conditional expressions
when N_Conditional_Expression =>
if (Present (Then_Actions (P))
and then Find_SCIL_Node (Actions (P)))
or else
(Present (Else_Actions (P))
and then Find_SCIL_Node (Else_Actions (P)))
then
return Found_Node;
end if;
-- Actions in handled sequence of statements
when
N_Handled_Sequence_Of_Statements =>
if Find_SCIL_Node (Statements (P)) then
return Found_Node;
end if;
-- Conditions of while expression or elsif.
when N_Iteration_Scheme |
N_Elsif_Part
=>
if Present (Condition_Actions (P))
and then Find_SCIL_Node (Condition_Actions (P))
then
return Found_Node;
end if;
-- Statements, declarations, pragmas, representation clauses
when
-- Statements
N_Procedure_Call_Statement |
N_Statement_Other_Than_Procedure_Call |
-- Pragmas
N_Pragma |
-- Representation_Clause
N_At_Clause |
N_Attribute_Definition_Clause |
N_Enumeration_Representation_Clause |
N_Record_Representation_Clause |
-- Declarations
N_Abstract_Subprogram_Declaration |
N_Entry_Body |
N_Exception_Declaration |
N_Exception_Renaming_Declaration |
N_Formal_Abstract_Subprogram_Declaration |
N_Formal_Concrete_Subprogram_Declaration |
N_Formal_Object_Declaration |
N_Formal_Type_Declaration |
N_Full_Type_Declaration |
N_Function_Instantiation |
N_Generic_Function_Renaming_Declaration |
N_Generic_Package_Declaration |
N_Generic_Package_Renaming_Declaration |
N_Generic_Procedure_Renaming_Declaration |
N_Generic_Subprogram_Declaration |
N_Implicit_Label_Declaration |
N_Incomplete_Type_Declaration |
N_Number_Declaration |
N_Object_Declaration |
N_Object_Renaming_Declaration |
N_Package_Body |
N_Package_Body_Stub |
N_Package_Declaration |
N_Package_Instantiation |
N_Package_Renaming_Declaration |
N_Private_Extension_Declaration |
N_Private_Type_Declaration |
N_Procedure_Instantiation |
N_Protected_Body |
N_Protected_Body_Stub |
N_Protected_Type_Declaration |
N_Single_Task_Declaration |
N_Subprogram_Body |
N_Subprogram_Body_Stub |
N_Subprogram_Declaration |
N_Subprogram_Renaming_Declaration |
N_Subtype_Declaration |
N_Task_Body |
N_Task_Body_Stub |
N_Task_Type_Declaration |
-- Freeze entity behaves like a declaration or statement
N_Freeze_Entity
=>
-- Do not search here if the item is not a list member
if not Is_List_Member (P) then
null;
-- Do not search if parent of P is an N_Component_Association
-- node (i.e. we are in the context of an N_Aggregate or
-- N_Extension_Aggregate node). In this case the node should
-- have been added before the entire aggregate.
elsif Nkind (Parent (P)) = N_Component_Association then
null;
-- Do not search if the parent of P is either an N_Variant
-- node or an N_Record_Definition node. In this case the node
-- should have been added before the entire record.
elsif Nkind (Parent (P)) = N_Variant
or else Nkind (Parent (P)) = N_Record_Definition
then
null;
-- Otherwise search it in the list containing this node
elsif Find_SCIL_Node (List_Containing (P)) then
return Found_Node;
end if;
-- A special case, N_Raise_xxx_Error can act either as a statement
-- or a subexpression. We diferentiate them by looking at the
-- Etype. It is set to Standard_Void_Type in the statement case.
when
N_Raise_xxx_Error =>
if Etype (P) = Standard_Void_Type then
if Is_List_Member (P)
and then Find_SCIL_Node (List_Containing (P))
then
return Found_Node;
end if;
-- In the subexpression case, keep climbing
else
null;
end if;
-- If a component association appears within a loop created for
-- an array aggregate, check if the SCIL node was added to the
-- the list of nodes attached to the association.
when
N_Component_Association =>
if Nkind (Parent (P)) = N_Aggregate
and then Present (Loop_Actions (P))
and then Find_SCIL_Node (Loop_Actions (P))
then
return Found_Node;
end if;
-- Another special case, an attribute denoting a procedure call
when
N_Attribute_Reference =>
if Is_Procedure_Attribute_Name (Attribute_Name (P))
and then Find_SCIL_Node (List_Containing (P))
then
return Found_Node;
-- In the subexpression case, keep climbing
else
null;
end if;
-- SCIL nodes do not have subtrees and hence they can never be
-- found climbing tree
when
N_SCIL_Dispatch_Table_Object_Init |
N_SCIL_Dispatch_Table_Tag_Init |
N_SCIL_Dispatching_Call |
N_SCIL_Membership_Test |
N_SCIL_Tag_Init
=>
pragma Assert (False);
raise Program_Error;
-- For all other node types, keep climbing tree
when
N_Abortable_Part |
N_Accept_Alternative |
N_Access_Definition |
N_Access_Function_Definition |
N_Access_Procedure_Definition |
N_Access_To_Object_Definition |
N_Aggregate |
N_Allocator |
N_Case_Statement_Alternative |
N_Character_Literal |
N_Compilation_Unit |
N_Compilation_Unit_Aux |
N_Component_Clause |
N_Component_Declaration |
N_Component_Definition |
N_Component_List |
N_Constrained_Array_Definition |
N_Decimal_Fixed_Point_Definition |
N_Defining_Character_Literal |
N_Defining_Identifier |
N_Defining_Operator_Symbol |
N_Defining_Program_Unit_Name |
N_Delay_Alternative |
N_Delta_Constraint |
N_Derived_Type_Definition |
N_Designator |
N_Digits_Constraint |
N_Discriminant_Association |
N_Discriminant_Specification |
N_Empty |
N_Entry_Body_Formal_Part |
N_Entry_Call_Alternative |
N_Entry_Declaration |
N_Entry_Index_Specification |
N_Enumeration_Type_Definition |
N_Error |
N_Exception_Handler |
N_Expanded_Name |
N_Explicit_Dereference |
N_Extension_Aggregate |
N_Floating_Point_Definition |
N_Formal_Decimal_Fixed_Point_Definition |
N_Formal_Derived_Type_Definition |
N_Formal_Discrete_Type_Definition |
N_Formal_Floating_Point_Definition |
N_Formal_Modular_Type_Definition |
N_Formal_Ordinary_Fixed_Point_Definition |
N_Formal_Package_Declaration |
N_Formal_Private_Type_Definition |
N_Formal_Signed_Integer_Type_Definition |
N_Function_Call |
N_Function_Specification |
N_Generic_Association |
N_Identifier |
N_In |
N_Index_Or_Discriminant_Constraint |
N_Indexed_Component |
N_Integer_Literal |
N_Itype_Reference |
N_Label |
N_Loop_Parameter_Specification |
N_Mod_Clause |
N_Modular_Type_Definition |
N_Not_In |
N_Null |
N_Op_Abs |
N_Op_Add |
N_Op_And |
N_Op_Concat |
N_Op_Divide |
N_Op_Eq |
N_Op_Expon |
N_Op_Ge |
N_Op_Gt |
N_Op_Le |
N_Op_Lt |
N_Op_Minus |
N_Op_Mod |
N_Op_Multiply |
N_Op_Ne |
N_Op_Not |
N_Op_Or |
N_Op_Plus |
N_Op_Rem |
N_Op_Rotate_Left |
N_Op_Rotate_Right |
N_Op_Shift_Left |
N_Op_Shift_Right |
N_Op_Shift_Right_Arithmetic |
N_Op_Subtract |
N_Op_Xor |
N_Operator_Symbol |
N_Ordinary_Fixed_Point_Definition |
N_Others_Choice |
N_Package_Specification |
N_Parameter_Association |
N_Parameter_Specification |
N_Pop_Constraint_Error_Label |
N_Pop_Program_Error_Label |
N_Pop_Storage_Error_Label |
N_Pragma_Argument_Association |
N_Procedure_Specification |
N_Protected_Definition |
N_Push_Constraint_Error_Label |
N_Push_Program_Error_Label |
N_Push_Storage_Error_Label |
N_Qualified_Expression |
N_Range |
N_Range_Constraint |
N_Real_Literal |
N_Real_Range_Specification |
N_Record_Definition |
N_Reference |
N_Selected_Component |
N_Signed_Integer_Type_Definition |
N_Single_Protected_Declaration |
N_Slice |
N_String_Literal |
N_Subprogram_Info |
N_Subtype_Indication |
N_Subunit |
N_Task_Definition |
N_Terminate_Alternative |
N_Triggering_Alternative |
N_Type_Conversion |
N_Unchecked_Expression |
N_Unchecked_Type_Conversion |
N_Unconstrained_Array_Definition |
N_Unused_At_End |
N_Unused_At_Start |
N_Use_Package_Clause |
N_Use_Type_Clause |
N_Variant |
N_Variant_Part |
N_Validate_Unchecked_Conversion |
N_With_Clause
=>
null;
end case;
-- If we fall through above tests, keep climbing tree
if Nkind (Parent (P)) = N_Subunit then
-- This is the proper body corresponding to a stub. Insertion done
-- at the point of the stub, which is in the declarative part of
-- the parent unit.
P := Corresponding_Stub (Parent (P));
else
P := Parent (P);
end if;
end loop;
-- SCIL node not found
return Empty;
end Find_SCIL_Node;
-------------------------
-- First_Non_SCIL_Node --
-------------------------
function First_Non_SCIL_Node (L : List_Id) return Node_Id is
N : Node_Id;
begin
N := First (L);
while Nkind (N) in N_SCIL_Node loop
Next (N);
end loop;
return N;
end First_Non_SCIL_Node;
------------------------
-- Next_Non_SCIL_Node --
------------------------
function Next_Non_SCIL_Node (N : Node_Id) return Node_Id is
Aux_N : Node_Id;
begin
Aux_N := Next (N);
while Nkind (Aux_N) in N_SCIL_Node loop
Next (Aux_N);
end loop;
return Aux_N;
end Next_Non_SCIL_Node;
end Sem_SCIL;