summaryrefslogtreecommitdiff
path: root/gcc/ada/exp_ch3.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/exp_ch3.adb')
-rw-r--r--gcc/ada/exp_ch3.adb238
1 files changed, 219 insertions, 19 deletions
diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb
index 7f7aa6f6bb7..369d895906b 100644
--- a/gcc/ada/exp_ch3.adb
+++ b/gcc/ada/exp_ch3.adb
@@ -202,6 +202,9 @@ package body Exp_Ch3 is
-- Check if E is defined in the RTL (in a child of Ada or System). Used
-- to avoid to bring in the overhead of _Input, _Output for tagged types.
+ function Is_User_Defined_Equality (Prim : Node_Id) return Boolean;
+ -- Returns true if Prim is a user defined equality function
+
function Is_Variable_Size_Array (E : Entity_Id) return Boolean;
-- Returns true if E has variable size components
@@ -237,6 +240,11 @@ package body Exp_Ch3 is
-- formals at some upper level). E provides the Sloc to be used for the
-- generated code.
+ function Make_Neq_Body (Tag_Typ : Entity_Id) return Node_Id;
+ -- Search for a renaming of the inequality dispatching primitive of
+ -- this tagged type. If found then build and return the corresponding
+ -- rename-as-body inequality subprogram; otherwise return Empty.
+
procedure Make_Predefined_Primitive_Specs
(Tag_Typ : Entity_Id;
Predef_List : out List_Id;
@@ -7677,6 +7685,18 @@ package body Exp_Ch3 is
end loop;
end Init_Secondary_Tags;
+ ------------------------
+ -- Is_User_Defined_Eq --
+ ------------------------
+
+ function Is_User_Defined_Equality (Prim : Node_Id) return Boolean is
+ begin
+ return Chars (Prim) = Name_Op_Eq
+ and then Etype (First_Formal (Prim)) =
+ Etype (Next_Formal (First_Formal (Prim)))
+ and then Base_Type (Etype (Prim)) = Standard_Boolean;
+ end Is_User_Defined_Equality;
+
----------------------------
-- Is_Variable_Size_Array --
----------------------------
@@ -8140,6 +8160,175 @@ package body Exp_Ch3 is
end if;
end Make_Eq_If;
+ --------------------
+ -- Make_Neq_Body --
+ --------------------
+
+ function Make_Neq_Body (Tag_Typ : Entity_Id) return Node_Id is
+
+ function Is_Predefined_Neq_Renaming (Prim : Node_Id) return Boolean;
+ -- Returns true if Prim is a renaming of an unresolved predefined
+ -- inequality operation.
+
+ --------------------------------
+ -- Is_Predefined_Neq_Renaming --
+ --------------------------------
+
+ function Is_Predefined_Neq_Renaming (Prim : Node_Id) return Boolean is
+ begin
+ return Chars (Prim) /= Name_Op_Ne
+ and then Present (Alias (Prim))
+ and then Comes_From_Source (Prim)
+ and then Is_Intrinsic_Subprogram (Alias (Prim))
+ and then Chars (Alias (Prim)) = Name_Op_Ne;
+ end Is_Predefined_Neq_Renaming;
+
+ -- Local variables
+
+ Loc : constant Source_Ptr := Sloc (Parent (Tag_Typ));
+ Stmts : constant List_Id := New_List;
+ Decl : Node_Id;
+ Eq_Prim : Entity_Id;
+ Left_Op : Entity_Id;
+ Renaming_Prim : Entity_Id;
+ Right_Op : Entity_Id;
+ Target : Entity_Id;
+
+ -- Start of processing for Make_Neq_Body
+
+ begin
+ -- For a call on a renaming of a dispatching subprogram that is
+ -- overridden, if the overriding occurred before the renaming, then
+ -- the body executed is that of the overriding declaration, even if the
+ -- overriding declaration is not visible at the place of the renaming;
+ -- otherwise, the inherited or predefined subprogram is called, see
+ -- (RM 8.5.4(8))
+
+ -- Stage 1: Search for a renaming of the unequality primitive and also
+ -- search for an overriding of the equality primitive located before the
+ -- renaming declaration.
+
+ declare
+ Elmt : Elmt_Id;
+ Prim : Node_Id;
+
+ begin
+ Eq_Prim := Empty;
+ Renaming_Prim := Empty;
+
+ Elmt := First_Elmt (Primitive_Operations (Tag_Typ));
+ while Present (Elmt) loop
+ Prim := Node (Elmt);
+
+ if Is_User_Defined_Equality (Prim)
+ and then No (Alias (Prim))
+ then
+ if No (Renaming_Prim) then
+ pragma Assert (No (Eq_Prim));
+ Eq_Prim := Prim;
+ end if;
+
+ elsif Is_Predefined_Neq_Renaming (Prim) then
+ Renaming_Prim := Prim;
+ end if;
+
+ Next_Elmt (Elmt);
+ end loop;
+ end;
+
+ -- No further action needed if no renaming was found
+
+ if No (Renaming_Prim) then
+ return Empty;
+ end if;
+
+ -- Stage 2: Replace the renaming declaration by a subprogram declaration
+ -- (required to add its body)
+
+ Decl := Parent (Parent (Renaming_Prim));
+ Rewrite (Decl,
+ Make_Subprogram_Declaration (Loc,
+ Specification => Specification (Decl)));
+ Set_Analyzed (Decl);
+
+ -- Remove the decoration of intrinsic renaming subprogram
+
+ Set_Is_Intrinsic_Subprogram (Renaming_Prim, False);
+ Set_Convention (Renaming_Prim, Convention_Ada);
+ Set_Alias (Renaming_Prim, Empty);
+ Set_Has_Completion (Renaming_Prim, False);
+
+ -- Stage 3: Build the corresponding body
+
+ Left_Op := First_Formal (Renaming_Prim);
+ Right_Op := Next_Formal (Left_Op);
+
+ Decl :=
+ Predef_Spec_Or_Body (Loc,
+ Tag_Typ => Tag_Typ,
+ Name => Chars (Renaming_Prim),
+ Profile => New_List (
+ Make_Parameter_Specification (Loc,
+ Defining_Identifier =>
+ Make_Defining_Identifier (Loc, Chars (Left_Op)),
+ Parameter_Type => New_Reference_To (Tag_Typ, Loc)),
+
+ Make_Parameter_Specification (Loc,
+ Defining_Identifier =>
+ Make_Defining_Identifier (Loc, Chars (Right_Op)),
+ Parameter_Type => New_Reference_To (Tag_Typ, Loc))),
+
+ Ret_Type => Standard_Boolean,
+ For_Body => True);
+
+ -- If the overriding of the equality primitive occurred before the
+ -- renaming, then generate:
+
+ -- function <Neq_Name> (X : Y : Typ) return Boolean is
+ -- begin
+ -- return not Oeq (X, Y);
+ -- end;
+
+ if Present (Eq_Prim) then
+ Target := Eq_Prim;
+
+ -- Otherwise build a nested subprogram which performs the predefined
+ -- evaluation of the equality operator. That is, generate:
+
+ -- function <Neq_Name> (X : Y : Typ) return Boolean is
+ -- function Oeq (X : Y) return Boolean is
+ -- begin
+ -- <<body of default implementation>>
+ -- end;
+ -- begin
+ -- return not Oeq (X, Y);
+ -- end;
+
+ else
+ declare
+ Local_Subp : Node_Id;
+ begin
+ Local_Subp := Make_Eq_Body (Tag_Typ, Name_Op_Eq);
+ Set_Declarations (Decl, New_List (Local_Subp));
+ Target := Defining_Entity (Local_Subp);
+ end;
+ end if;
+
+ Append_To (Stmts,
+ Make_Simple_Return_Statement (Loc,
+ Expression =>
+ Make_Op_Not (Loc,
+ Make_Function_Call (Loc,
+ Name => New_Reference_To (Target, Loc),
+ Parameter_Associations => New_List (
+ Make_Identifier (Loc, Chars (Left_Op)),
+ Make_Identifier (Loc, Chars (Right_Op)))))));
+
+ Set_Handled_Statement_Sequence
+ (Decl, Make_Handled_Sequence_Of_Statements (Loc, Stmts));
+ return Decl;
+ end Make_Neq_Body;
+
-------------------------------
-- Make_Null_Procedure_Specs --
-------------------------------
@@ -8238,13 +8427,6 @@ package body Exp_Ch3 is
Predef_List : out List_Id;
Renamed_Eq : out Entity_Id)
is
- Loc : constant Source_Ptr := Sloc (Tag_Typ);
- Res : constant List_Id := New_List;
- Eq_Name : Name_Id := Name_Op_Eq;
- Eq_Needed : Boolean;
- Eq_Spec : Node_Id;
- Prim : Elmt_Id;
-
function Is_Predefined_Eq_Renaming (Prim : Node_Id) return Boolean;
-- Returns true if Prim is a renaming of an unresolved predefined
-- equality operation.
@@ -8262,6 +8444,19 @@ package body Exp_Ch3 is
and then Chars (Alias (Prim)) = Name_Op_Eq;
end Is_Predefined_Eq_Renaming;
+ -- Local variables
+
+ Loc : constant Source_Ptr := Sloc (Tag_Typ);
+ Res : constant List_Id := New_List;
+ Eq_Name : Name_Id := Name_Op_Eq;
+ Eq_Needed : Boolean;
+ Eq_Spec : Node_Id;
+ Prim : Elmt_Id;
+
+ Has_Predef_Eq_Renaming : Boolean := False;
+ -- Set to True if Tag_Typ has a primitive that renames the predefined
+ -- equality operator. Used to implement (RM 8-5-4(8)).
+
-- Start of processing for Make_Predefined_Primitive_Specs
begin
@@ -8299,9 +8494,9 @@ package body Exp_Ch3 is
end loop;
end;
- -- Spec of "=" is expanded if the type is not limited and if a
- -- user defined "=" was not already declared for the non-full
- -- view of a private extension
+ -- Spec of "=" is expanded if the type is not limited and if a user
+ -- defined "=" was not already declared for the non-full view of a
+ -- private extension
if not Is_Limited_Type (Tag_Typ) then
Eq_Needed := True;
@@ -8311,21 +8506,18 @@ package body Exp_Ch3 is
-- If a primitive is encountered that renames the predefined
-- equality operator before reaching any explicit equality
-- primitive, then we still need to create a predefined equality
- -- function, because calls to it can occur via the renaming. A new
- -- name is created for the equality to avoid conflicting with any
- -- user-defined equality. (Note that this doesn't account for
+ -- function, because calls to it can occur via the renaming. A
+ -- new name is created for the equality to avoid conflicting with
+ -- any user-defined equality. (Note that this doesn't account for
-- renamings of equality nested within subpackages???)
if Is_Predefined_Eq_Renaming (Node (Prim)) then
+ Has_Predef_Eq_Renaming := True;
Eq_Name := New_External_Name (Chars (Node (Prim)), 'E');
-- User-defined equality
- elsif Chars (Node (Prim)) = Name_Op_Eq
- and then Etype (First_Formal (Node (Prim))) =
- Etype (Next_Formal (First_Formal (Node (Prim))))
- and then Base_Type (Etype (Node (Prim))) = Standard_Boolean
- then
+ elsif Is_User_Defined_Equality (Node (Prim)) then
if No (Alias (Node (Prim)))
or else Nkind (Unit_Declaration_Node (Node (Prim))) =
N_Subprogram_Renaming_Declaration
@@ -8394,7 +8586,7 @@ package body Exp_Ch3 is
Ret_Type => Standard_Boolean);
Append_To (Res, Eq_Spec);
- if Eq_Name /= Name_Op_Eq then
+ if Has_Predef_Eq_Renaming then
Renamed_Eq := Defining_Unit_Name (Specification (Eq_Spec));
Prim := First_Elmt (Primitive_Operations (Tag_Typ));
@@ -8966,6 +9158,14 @@ package body Exp_Ch3 is
Append_To (Res, Decl);
end if;
+ -- Body for inequality (if required!)
+
+ Decl := Make_Neq_Body (Tag_Typ);
+
+ if Present (Decl) then
+ Append_To (Res, Decl);
+ end if;
+
-- Body for dispatching assignment
Decl :=