-- --
-- B o d y --
-- --
--- Copyright (C) 2009, Free Software Foundation, Inc. --
+-- Copyright (C) 2009-2010, 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- --
-- --
------------------------------------------------------------------------------
-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;
+with Einfo; use Einfo;
+with Nlists; use Nlists;
+with Rtsfind; use Rtsfind;
+with Sem_Aux; use Sem_Aux;
+with Sinfo; use Sinfo;
+with Stand; use Stand;
+with SCIL_LL; use SCIL_LL;
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;
+ SCIL_Node : constant Node_Id := Get_SCIL_Node (N);
+ 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.
+ -- For nodes that do not have SCIL node continue traversing the tree
- 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);
+ if No (SCIL_Node) then
+ return OK;
+ end if;
- case Nkind (Ctrl_Tag) is
+ case Nkind (SCIL_Node) is
+ when N_SCIL_Dispatch_Table_Tag_Init =>
+ pragma Assert (Nkind (N) = N_Object_Declaration);
+ null;
- -- For class-wide membership tests the SCIL tag value is the tag
- -- of the tested object (i.e. Obj.Tag).
+ when N_SCIL_Dispatching_Call =>
+ Ctrl_Tag := SCIL_Controlling_Tag (SCIL_Node);
- when N_Selected_Component =>
- pragma Assert (Etype (Ctrl_Tag) = RTE (RE_Tag));
- null;
+ -- Parent of SCIL dispatching call nodes MUST be a subprogram call
- when others =>
+ if not Nkind_In (N, N_Function_Call,
+ N_Procedure_Call_Statement)
+ then
pragma Assert (False);
- null;
-
- end case;
-
- return Skip;
+ raise Program_Error;
- elsif Nkind (N) = N_SCIL_Dispatching_Call then
- Ctrl_Tag := SCIL_Controlling_Tag (N);
+ -- In simple cases the controlling tag is the tag of the
+ -- controlling argument (i.e. Obj.Tag).
- -- SCIL_Related_Node of SCIL dispatching call nodes MUST reference
- -- subprogram calls.
+ elsif Nkind (Ctrl_Tag) = N_Selected_Component then
+ Ctrl_Typ := Etype (Ctrl_Tag);
- if not Nkind_In (SCIL_Related_Node (N), N_Function_Call,
- N_Procedure_Call_Statement)
- then
- pragma Assert (False);
- raise Program_Error;
+ -- Interface types are unsupported
- -- In simple cases the controlling tag is the tag of the controlling
- -- argument (i.e. Obj.Tag).
+ if Is_Interface (Ctrl_Typ)
+ or else (RTE_Available (RE_Interface_Tag)
+ and then Ctrl_Typ = RTE (RE_Interface_Tag))
+ then
+ null;
- elsif Nkind (Ctrl_Tag) = N_Selected_Component then
- Ctrl_Typ := Etype (Ctrl_Tag);
+ else
+ pragma Assert (Ctrl_Typ = RTE (RE_Tag));
+ null;
+ end if;
- -- Interface types are unsupported
+ -- 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.
- if Is_Interface (Ctrl_Typ)
- or else (RTE_Available (RE_Interface_Tag)
- and then Ctrl_Typ = RTE (RE_Interface_Tag))
+ elsif Nkind_In (Ctrl_Tag, N_Object_Declaration,
+ N_Parameter_Specification)
then
- null;
+ 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));
- null;
- end if;
+ 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;
- -- 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;
+ -- Interface types are unsupported
- 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)));
+ elsif Is_Interface (Etype (Ctrl_Tag)) then
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;
+ else
+ pragma Assert (False);
+ raise Program_Error;
end if;
- Next (N);
- end loop;
+ return Skip;
- Found_Node := Empty;
- return False;
- end Find_SCIL_Node;
+ when N_SCIL_Membership_Test =>
- -- Local variables
+ -- Check contents of the boolean expression associated with the
+ -- membership test.
- P : Node_Id;
+ pragma Assert (Nkind_In (N, N_Identifier,
+ N_And_Then,
+ N_Or_Else,
+ N_Expression_With_Actions)
+ and then Etype (N) = Standard_Boolean);
- -- Start of processing for Find_SCIL_Node
+ -- 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).
- 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
+ -- 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.
- -- Actions associated with AND THEN or OR ELSE
+ pragma Assert
+ (Is_Tagged_Type (Underlying_Type (SCIL_Entity (SCIL_Node))));
- 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
+ -- Interface types are unsupported
- when
- N_Handled_Sequence_Of_Statements =>
- if Find_SCIL_Node (Statements (P)) then
- return Found_Node;
- end if;
+ pragma Assert
+ (not Is_Interface (Underlying_Type (SCIL_Entity (SCIL_Node))));
- -- Conditions of while expression or elsif.
+ -- Check the decoration of the expression that denotes the tag
+ -- value being tested
- 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;
+ Ctrl_Tag := SCIL_Tag_Value (SCIL_Node);
- -- 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;
+ case Nkind (Ctrl_Tag) is
- -- 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.
+ -- For class-wide membership tests the SCIL tag value is the
+ -- tag of the tested object (i.e. Obj.Tag).
- elsif Nkind (Parent (P)) = N_Component_Association then
+ when N_Selected_Component =>
+ pragma Assert (Etype (Ctrl_Tag) = RTE (RE_Tag));
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
+ when others =>
+ pragma Assert (False);
null;
+ end case;
- -- 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.
+ return Skip;
- P := Corresponding_Stub (Parent (P));
-
- else
- P := Parent (P);
- end if;
- end loop;
-
- -- SCIL node not found
+ when others =>
+ pragma Assert (False);
+ raise Program_Error;
+ end case;
- return Empty;
- end Find_SCIL_Node;
+ return Skip;
+ end Check_SCIL_Node;
-------------------------
-- First_Non_SCIL_Node --