home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
gnat-2.06-src.tgz
/
tar.out
/
fsf
/
gnat
/
ada
/
exp_ch4.adb
< prev
next >
Wrap
Text File
|
1996-09-28
|
116KB
|
3,371 lines
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- E X P _ C H 4 --
-- --
-- B o d y --
-- --
-- $Revision: 1.203 $ --
-- --
-- Copyright (c) 1992,1993,1994,1995 NYU, All Rights Reserved --
-- --
-- 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, 675 Mass Ave, Cambridge, MA 02139, USA. --
-- --
------------------------------------------------------------------------------
with Atree; use Atree;
with Checks; use Checks;
with Einfo; use Einfo;
with Elists; use Elists;
with Exp_Ch3; use Exp_Ch3;
with Exp_Ch7; use Exp_Ch7;
with Exp_Ch9; use Exp_Ch9;
with Exp_Disp; use Exp_Disp;
with Exp_Fixd; use Exp_Fixd;
with Exp_Pakd; use Exp_Pakd;
with Exp_TSS; use Exp_TSS;
with Exp_Util; use Exp_Util;
with Freeze; use Freeze;
with Itypes; use Itypes;
with Nlists; use Nlists;
with Nmake; use Nmake;
with Opt; use Opt;
with Rtsfind; use Rtsfind;
with Sem; use Sem;
with Sem_Dist; use Sem_Dist;
with Sem_Eval; use Sem_Eval;
with Sem_Res; use Sem_Res;
with Sem_Type; use Sem_Type;
with Sem_Util; use Sem_Util;
with Sinfo; use Sinfo;
with Sinfo.CN; use Sinfo.CN;
with Snames; use Snames;
with Stand; use Stand;
with Tbuild; use Tbuild;
with Ttypes; use Ttypes;
with Uintp; use Uintp;
with Urealp; use Urealp;
package body Exp_Ch4 is
------------------------
-- Local Subprograms --
------------------------
function Expand_Array_Equality
(Loc : Source_Ptr; Typ : Entity_Id; Lhs, Rhs : Node_Id) return Node_Id;
-- Expand an array equality into an expression-action containing a local
-- function implementing this equality, and a call to it. Loc is the
-- location for the generated nodes. Typ is the type of the array, and
-- Lhs, Rhs are the array expressions to be compared.
procedure Expand_Boolean_Operator (N : Node_Id);
-- Common expansion processing for Boolean operators (And, Or, Xor)
-- for the case of array type arguments.
procedure Expand_Comparison_Operator (N : Node_Id);
-- This routine handles expansion of the comparison operators (N_Op_Lt,
-- N_Op_Le, N_Op_Gt, N_Op_Ge). The basic code for these operators is
-- similar, differing only in the details of the actual comparison
-- call that is made.
function Expand_Composite_Equality
(Loc : Source_Ptr;
Typ : Entity_Id;
Lhs : Node_Id;
Rhs : Node_Id)
return Node_Id;
-- Local recursive function used to expand equality for nested
-- composite types. Used by Expand_Record_Equality, Expand_Array_Equality.
procedure Expand_Concatenation (Node : Node_Id; Ops : List_Id);
-- This routine handles expansion of concatenation operations, where
-- N is the N_Op_Concat or N_Concat_Multiple node being expanded, and
-- Ops is the list of operands (at least two are present).
procedure Expand_Zero_Divide_Check (N : Node_Id);
-- The node kind is N_Op_Divide, N_Op_Mod, or N_Op_Rem. The right operand
-- is replaced by an expression actions node that checks that the divisor
-- (right operand) is non-zero. Note that in the divide case, but not in
-- the other two cases, overflow can still occur with a non-zero divisor
-- as a result of dividing the largest negative number by minus one.
function Make_Array_Comparison_Op
(Typ : Entity_Id;
Loc : Source_Ptr;
Equal : Boolean)
return Node_Id;
-- Comparisons between arrays are expanded in line. This function
-- produces the body of the implementation of (a > b), or (a >= b), when
-- a and b are one-dimensional arrays of some discrete type. The original
-- node is then expanded into the appropriate call to this function.
function Tagged_Membership (N : Node_Id) return Node_Id;
-- Construct the expression corresponding to the tagged membership test.
-- Deals with a second operand being (or not) a class-wide type.
---------------------------
-- Expand_Array_Equality --
---------------------------
-- Expand an equality function for multi-dimentionnal arrays. Here is
-- an example of such a function for Nb_Dimension = 2
-- function Enn (A : arr; B : arr) return boolean is
-- J1 : integer := B'first (1);
-- J2 : integer := B'first (2);
-- begin
-- if A'length (1) /= B'length (1) then
-- return false;
-- else
-- for I1 in A'first (1) .. A'last (1) loop
-- if A'length (2) /= B'length (2) then
-- return false;
-- else
-- for I2 in A'first (2) .. A'last (2) loop
-- if A (I1, I2) /= B (J1, J2) then
-- return false;
-- end if;
-- J2 := Integer'succ (J2);
-- end loop;
-- end if;
-- J1 := Integer'succ (J1);
-- end loop;
-- end if;
-- return true;
-- end Enn;
function Expand_Array_Equality
(Loc : Source_Ptr;
Typ : Entity_Id;
Lhs, Rhs : Node_Id)
return Node_Id
is
Decls : List_Id := New_List;
Index_List1 : List_Id := New_List;
Index_List2 : List_Id := New_List;
Index : Entity_Id := First_Index (Typ);
Index_Type : Entity_Id;
Formals : List_Id;
Result : Node_Id;
Stats : Node_Id;
Func_Name : Entity_Id;
Func_Body : Node_Id;
A : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uA);
B : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uB);
function Component_Equality (Typ : Entity_Id) return Node_Id;
-- Create one statement to compare corresponding components, designated
-- by a full set of indices.
function Loop_One_Dimension (N : Int) return Node_Id;
-- Loop over the n'th dimension of the arrays. The single statement
-- in the body of the loop is a loop over the next dimension, or
-- the comparison of corresponding components.
------------------------
-- Component_Equality --
------------------------
function Component_Equality (Typ : Entity_Id) return Node_Id is
Test : Node_Id;
L, R : Node_Id;
begin
-- if a(i1...) /= b(j1...) then return false; end if;
L :=
Make_Indexed_Component (Loc,
Prefix => Make_Identifier (Loc, Chars (A)),
Expressions => Index_List1);
R :=
Make_Indexed_Component (Loc,
Prefix => Make_Identifier (Loc, Chars (B)),
Expressions => Index_List2);
Test := Expand_Composite_Equality (Loc, Component_Type (Typ), L, R);
return
Make_If_Statement (Loc,
Condition => Make_Op_Not (Loc, Right_Opnd => Test),
Then_Statements => New_List (
Make_Return_Statement (Loc,
Expression => New_Occurrence_Of (Standard_False, Loc))));
end Component_Equality;
------------------------
-- Loop_One_Dimension --
------------------------
function Loop_One_Dimension (N : Int) return Node_Id is
I : constant Entity_Id := Make_Defining_Identifier (Loc,
New_Internal_Name ('I'));
J : constant Entity_Id := Make_Defining_Identifier (Loc,
New_Internal_Name ('J'));
Stats : Node_Id;
begin
if N > Number_Dimensions (Typ) then
return Component_Equality (Typ);
else
-- Generate the following:
-- j: index_type := b'first (n);
-- ...
-- if a'length (n) /= b'length (n) then
-- return false;
-- else
-- for i in a'range (n) loop
-- -- loop over remaining dimensions.
-- j := index_type'succ (j);
-- end loop;
-- end if;
-- retrieve index type for current dimension.
Index_Type := Base_Type (Etype (Index));
Append (New_Reference_To (I, Loc), Index_List1);
Append (New_Reference_To (J, Loc), Index_List2);
-- Declare index for j as a local variable to the function.
-- Index i is a loop variable.
Append_To (Decls,
Make_Object_Declaration (Loc,
Defining_Identifier => J,
Object_Definition => New_Reference_To (Index_Type, Loc),
Expression =>
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (B, Loc),
Attribute_Name => Name_First,
Expressions => New_List (
Make_Integer_Literal (Loc, UI_From_Int (N))))));
Stats :=
Make_If_Statement (Loc,
Condition =>
Make_Op_Ne (Loc,
Left_Opnd =>
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (A, Loc),
Attribute_Name => Name_Length,
Expressions => New_List (
Make_Integer_Literal (Loc, UI_From_Int (N)))),
Right_Opnd =>
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (B, Loc),
Attribute_Name => Name_Length,
Expressions => New_List (
Make_Integer_Literal (Loc, UI_From_Int (N))))),
Then_Statements => New_List (
Make_Return_Statement (Loc,
Expression => New_Occurrence_Of (Standard_False, Loc))),
Else_Statements => New_List (
Make_Loop_Statement (Loc,
Identifier => Empty,
Iteration_Scheme =>
Make_Iteration_Scheme (Loc,
Loop_Parameter_Specification =>
Make_Loop_Parameter_Specification (Loc,
Defining_Identifier => I,
Discrete_Subtype_Definition =>
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (A, Loc),
Attribute_Name => Name_Range,
Expressions => New_List (
Make_Integer_Literal (Loc,
Intval => UI_From_Int (N)))))),
Statements => New_List (
Loop_One_Dimension (N + 1),
Make_Assignment_Statement (Loc,
Name => New_Reference_To (J, Loc),
Expression =>
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (Index_Type, Loc),
Attribute_Name => Name_Succ,
Expressions => New_List (
New_Reference_To (J, Loc))))))));
Index := Next_Index (Index);
return Stats;
end if;
end Loop_One_Dimension;
------------------------------------------
-- Processing for Expand_Array_Equality --
------------------------------------------
begin
Formals := New_List (
Make_Parameter_Specification (Loc,
Defining_Identifier => A,
Parameter_Type => New_Reference_To (Typ, Loc)),
Make_Parameter_Specification (Loc,
Defining_Identifier => B,
Parameter_Type => New_Reference_To (Typ, Loc)));
Func_Name := Make_Defining_Identifier (Loc, New_Internal_Name ('E'));
Stats := Loop_One_Dimension (1);
Func_Body :=
Make_Subprogram_Body (Loc,
Specification =>
Make_Function_Specification (Loc,
Defining_Unit_Name => Func_Name,
Parameter_Specifications => Formals,
Subtype_Mark => New_Reference_To (Standard_Boolean, Loc)),
Declarations => Decls,
Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Loc,
Statements => New_List (
Stats,
Make_Return_Statement (Loc,
Expression => New_Occurrence_Of (Standard_True, Loc)))));
Set_Has_Completion (Func_Name, True);
Result :=
Make_Expression_Actions (Loc,
Actions => New_List (Func_Body),
Expression => Make_Function_Call (Loc,
Name => New_Reference_To (Func_Name, Loc),
Parameter_Associations => New_List (Lhs, Rhs)));
return Result;
end Expand_Array_Equality;
-----------------------------
-- Expand_Boolean_Operator --
-----------------------------
-- Note that we first get the actual subtypes of the operands, since
-- we always want to deal with types that have bounds.
procedure Expand_Boolean_Operator (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Typ : constant Entity_Id := Etype (N);
L : constant Node_Id := Convert_To_Actual_Subtype
(Left_Opnd (N));
R : constant Node_Id := Convert_To_Actual_Subtype
(Right_Opnd (N));
Func_Body : Node_Id;
Func_Name : Entity_Id;
begin
Apply_Length_Check (R, Etype (L));
if Is_Packed (Typ) then
Expand_Packed_Boolean_Operator (N);
-- For the normal non-packed case, the expansion is to build a function
-- for carrying out the comparison (using Make_Boolean_Array_Op) and
-- then inserting it into the tree. The original operator node is then
-- rewritten as a call to this function.
else
Func_Body := Make_Boolean_Array_Op (Etype (L), N);
Func_Name := Defining_Unit_Name (Specification (Func_Body));
Insert_Action (N, Func_Body);
-- Now rewrite the expression with a call
Rewrite_Substitute_Tree (N,
Make_Function_Call (Loc,
Name => New_Reference_To (Func_Name, Loc),
Parameter_Associations => New_List (L, R)));
Analyze (N);
Resolve (N, Typ);
end if;
end Expand_Boolean_Operator;
--------------------------------
-- Expand_Comparison_Operator --
--------------------------------
-- Expansion is only required in the case of array types. The form of
-- the expansion is:
-- [body for greater_nn; boolean_expression]
-- The body is built by Make_Array_Comparison_Op, and the form of the
-- Boolean expression depends on the operator involved.
procedure Expand_Comparison_Operator (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Op1 : Node_Id := Left_Opnd (N);
Op2 : Node_Id := Right_Opnd (N);
Typ1 : constant Node_Id := Base_Type (Etype (Op1));
Result : Node_Id;
Expr : Node_Id;
Func_Body : Node_Id;
Func_Name : Entity_Id;
-- ??? can't Op1, Op2 be constants, aren't assignments to Op1, Op2
-- below redundant, if not why not? RBKD
begin
if Is_Array_Type (Typ1) then
-- For (a <= b) we convert to not (a > b)
if Chars (N) = Name_Op_Le then
Rewrite_Substitute_Tree (N,
Make_Op_Not (Loc,
Right_Opnd =>
Make_Op_Gt (Loc,
Left_Opnd => Op1,
Right_Opnd => Op2)));
Analyze (N);
Resolve (N, Standard_Boolean);
return;
-- For < the Boolean expression is
-- greater__nn (op2, op1)
elsif Chars (N) = Name_Op_Lt then
Func_Body := Make_Array_Comparison_Op (Typ1, Loc, False);
Op1 := Right_Opnd (N);
Op2 := Left_Opnd (N);
-- For (a >= b) we convert to not (a < b)
-- op1 = op2 or else greater__nn (op1, op2)
elsif Chars (N) = Name_Op_Ge then
Rewrite_Substitute_Tree (N,
Make_Op_Not (Loc,
Right_Opnd =>
Make_Op_Lt (Loc,
Left_Opnd => Op1,
Right_Opnd => Op2)));
Analyze (N);
Resolve (N, Standard_Boolean);
return;
-- For > the Boolean expression is
-- greater__nn (op1, op2)
elsif Chars (N) = Name_Op_Gt then
Func_Body := Make_Array_Comparison_Op (Typ1, Loc, False);
else
pragma Assert (False); null;
end if;
Func_Name := Defining_Unit_Name (Specification (Func_Body));
Expr :=
Make_Function_Call (Loc,
Name => New_Reference_To (Func_Name, Loc),
Parameter_Associations => New_List (Op1, Op2));
Result :=
Make_Expression_Actions (Loc,
Actions => New_List (Func_Body),
Expression => Expr);
Rewrite_Substitute_Tree (N, Result);
Analyze (N);
Resolve (N, Standard_Boolean);
end if;
end Expand_Comparison_Operator;
-------------------------------
-- Expand_Composite_Equality --
-------------------------------
-- This function is only called for comparing internal fields of composite
-- types when these fields are themselves composites. This is a special
-- case because it is not possible to respect normal Ada visibility rules.
function Expand_Composite_Equality
(Loc : Source_Ptr;
Typ : Entity_Id;
Lhs : Node_Id;
Rhs : Node_Id)
return Node_Id
is
Full_Type : Entity_Id;
Prim : Elmt_Id;
begin
if Is_Private_Type (Typ) then
Full_Type := Underlying_Type (Typ);
else
Full_Type := Typ;
end if;
Full_Type := Base_Type (Full_Type);
if Is_Array_Type (Full_Type) then
if Is_Scalar_Type (Component_Type (Full_Type)) then
return Make_Op_Eq (Loc, Left_Opnd => Lhs, Right_Opnd => Rhs);
else
return Expand_Array_Equality (Loc, Full_Type, Lhs, Rhs);
end if;
elsif Is_Tagged_Type (Full_Type) then
-- Call the primitive operation "=" of this type
if Is_Class_Wide_Type (Full_Type) then
Full_Type := Root_Type (Full_Type);
end if;
Prim := First_Elmt (Primitive_Operations (Full_Type));
while Chars (Node (Prim)) /= Name_Op_Eq loop
Prim := Next_Elmt (Prim);
pragma Assert (Present (Prim));
end loop;
return
Make_Function_Call (Loc,
Name => New_Reference_To (Node (Prim), Loc),
Parameter_Associations => New_List (Lhs, Rhs));
elsif Is_Record_Type (Full_Type) then
return Expand_Record_Equality (Loc, Full_Type, Lhs, Rhs);
else
-- It can be a simple record or the full view of a scalar private
return Make_Op_Eq (Loc, Left_Opnd => Lhs, Right_Opnd => Rhs);
end if;
end Expand_Composite_Equality;
--------------------------
-- Expand_Concatenation --
--------------------------
-- We construct the following expression actions node, where Atyp is
-- the base type of the array involved and Ityp is the index type
-- of this array:
-- [function Cnn (S1 : Atyp; S2 : Atyp; .. Sn : Atyp) return Atyp is
-- L : constant Ityp := S1'Length + S2'Length + ... Sn'Length;
-- R : Atyp (S1'First .. S1'First + L - 1)
-- P : Ityp := S1'First;
--
-- begin
-- R (P .. P + S1'Length - 1) := S1;
-- P := P + S1'Length;
-- R (P .. P + S2'Length - 1) := S2;
-- P := P + S2'Length;
-- ...
-- R (P .. P + Sn'Length - 1) := Sn;
-- P := P + Sn'Length;
-- return R;
-- end Cnn;
--
-- Cnn (operand1, operand2, ... operandn)]
-- Note: the low bound is not quite right, to be fixed later ???
procedure Expand_Concatenation (Node : Node_Id; Ops : List_Id) is
Loc : constant Source_Ptr := Sloc (Node);
Atyp : constant Entity_Id := Base_Type (Etype (Node));
Ityp : constant Entity_Id := Etype (First_Index (Atyp));
N : constant Nat := List_Length (Ops);
Op : Node_Id;
Pspec : List_Id;
Lexpr : Node_Id;
Slist : List_Id;
Alist : List_Id;
Decls : List_Id;
Func : Node_Id;
function L return Node_Id;
-- Build reference to identifier l
function Nam (J : Nat) return Name_Id;
-- Build reference to identifier Sn, where n is the value given
function One return Node_Id;
-- Build integer literal one
function P return Node_Id;
-- Build reference to identifier p
function R return Node_Id;
-- Build referrnce to identifier r
function S1first return Node_Id;
-- Build expression S1'First
function Slength (J : Nat) return Node_Id;
-- Build expression S1'Length
function L return Node_Id is
begin
return Make_Identifier (Loc, Name_uL);
end L;
function Nam (J : Nat) return Name_Id is
begin
return New_External_Name ('S', J);
end Nam;
function One return Node_Id is
begin
return Make_Integer_Literal (Loc, Uint_1);
end One;
function P return Node_Id is
begin
return Make_Identifier (Loc, Name_uP);
end P;
function R return Node_Id is
begin
return Make_Identifier (Loc, Name_uR);
end R;
function S1first return Node_Id is
begin
return
Make_Attribute_Reference (Loc,
Prefix => Make_Identifier (Loc, Nam (1)),
Attribute_Name => Name_First);
end S1first;
function Slength (J : Nat) return Node_Id is
begin
return
Make_Attribute_Reference (Loc,
Prefix => Make_Identifier (Loc, Nam (J)),
Attribute_Name => Name_Length);
end Slength;
-- Start of processing for Expand_Concatenation
begin
-- Construct parameter specification list
Pspec := New_List;
for J in 1 .. N loop
Append_To (Pspec,
Make_Parameter_Specification (Loc,
Defining_Identifier => Make_Defining_Identifier (Loc, Nam (J)),
Parameter_Type => New_Reference_To (Atyp, Loc)));
end loop;
-- Construct expression for total length of result
Lexpr := Slength (1);
for J in 2 .. N loop
Lexpr := Make_Op_Add (Loc, Lexpr, Slength (J));
end loop;
-- Construct list of statements
Slist := New_List;
for J in 1 .. N loop
Append_To (Slist,
Make_Assignment_Statement (Loc,
Name =>
Make_Slice (Loc,
Prefix => R,
Discrete_Range =>
Make_Range (Loc,
Low_Bound => P,
High_Bound =>
Make_Op_Subtract (Loc,
Left_Opnd => Make_Op_Add (Loc, P, Slength (J)),
Right_Opnd => One))),
Expression => Make_Identifier (Loc, Nam (J))));
Append_To (Slist,
Make_Assignment_Statement (Loc,
Name => P,
Expression => Make_Op_Add (Loc, P, Slength (J))));
end loop;
Append_To (Slist, Make_Return_Statement (Loc, Expression => R));
-- Construct list of arguments for the call
Alist := New_List;
Op := First (Ops);
for J in 1 .. N loop
Append_To (Alist, New_Copy (Op));
Op := Next (Op);
end loop;
-- Construct the declarations for the function
Decls := New_List (
Make_Object_Declaration (Loc,
Defining_Identifier => Make_Defining_Identifier (Loc, Name_uL),
Object_Definition => New_Reference_To (Ityp, Loc),
Constant_Present => True,
Expression => Lexpr),
Make_Object_Declaration (Loc,
Defining_Identifier => Make_Defining_Identifier (Loc, Name_uR),
Object_Definition =>
Make_Subtype_Indication (Loc,
Subtype_Mark => New_Reference_To (Atyp, Loc),
Constraint =>
Make_Index_Or_Discriminant_Constraint (Loc,
Constraints => New_List (
Make_Range (Loc,
Low_Bound => S1first,
High_Bound =>
Make_Op_Subtract (Loc,
Left_Opnd => Make_Op_Add (Loc, S1first, L),
Right_Opnd => One)))))),
Make_Object_Declaration (Loc,
Defining_Identifier => Make_Defining_Identifier (Loc, Name_uP),
Object_Definition => New_Reference_To (Ityp, Loc),
Expression => S1first));
-- Now construct the expression actions node and do the replace
Func := Make_Defining_Identifier (Loc, New_Internal_Name ('C'));
Rewrite_Substitute_Tree (Node,
Make_Expression_Actions (Loc,
Actions => New_List (
Make_Subprogram_Body (Loc,
Specification =>
Make_Function_Specification (Loc,
Defining_Unit_Name => Func,
Parameter_Specifications => Pspec,
Subtype_Mark => New_Reference_To (Atyp, Loc)),
Declarations => Decls,
Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Loc, Slist))),
Expression =>
Make_Function_Call (Loc, New_Reference_To (Func, Loc), Alist)));
Analyze (Node);
Resolve (Node, Atyp);
Set_Is_Inlined (Func);
end Expand_Concatenation;
------------------------
-- Expand_N_Allocator --
------------------------
-- If the allocator is for a type which requires initialization, and
-- there is no initial value (i.e. the operand is a subtype indication
-- rather than a qualifed expression), then we must generate a call to
-- the initialization routine. This is done using an expression actions
-- node:
--
-- [Pnnn : constant ptr_T := new (T); Init (Pnnn.all,...); Pnnn]
--
-- Here ptr_T is the pointer type for the allocator, and T is the
-- subtype of the allocator. A special case arises if the designated
-- type of the access type is a task or contains tasks. In this case
-- the call to Init (Temp.all ...) is replaced by code that ensures
-- that the tasks get activated (see Exp_Ch9.Build_Task_Allocate_Block
-- for details). In addition, if the type T is a task T, then the first
-- argument to Init must be converted to the task record type.
procedure Expand_N_Allocator (N : Node_Id) is
PtrT : constant Entity_Id := Etype (N);
Loc : constant Source_Ptr := Sloc (N);
Temp : Entity_Id;
Node : Node_Id;
begin
-- RM E.2.3(22). We enforce that the expected type of an allocator
-- shall not be a remote access-to-class-wide-limited-private type
Validate_Remote_Access_To_Class_Wide_Type (N);
-- Set the Storage Pool
Set_Storage_Pool (N, Associated_Storage_Pool (PtrT));
if Present (Storage_Pool (N)) then
Set_Procedure_To_Call
(N, Find_Prim_Op (Etype (Storage_Pool (N)), Name_Allocate));
end if;
if Nkind (Expression (N)) = N_Qualified_Expression then
declare
Indic : constant Node_Id := Subtype_Mark (Expression (N));
T : constant Entity_Id := Entity (Indic);
Exp : constant Node_Id := Expression (Expression (N));
Tag_Assign : Node_Id;
begin
if Is_Tagged_Type (T) or else Controlled_Type (T) then
-- Actions inserted before:
-- Temp : constant ptr_T := new T'(Expression);
-- <no CW> Temp._tag := T'tag;
-- <CTRL> Adjust (Finalizable (Temp.all));
-- <CTRL> Attach_To_Final_List (Finalizable (Temp.all));
-- We analyze by hand the new internal allocator to avoid
-- any recursion and inappropriate call to Initialize
Remove_Side_Effects (Exp);
Temp :=
Make_Defining_Identifier (Loc, New_Internal_Name ('P'));
-- For a class wide allocation generate the following code:
-- type Equiv_Record is record ... end record;
-- implicit subtype CW is <Class_Wide_Subytpe>;
-- temp : PtrT := new CW'(CW!(expr));
if Is_Class_Wide_Type (T) then
Expand_Subtype_From_Expr (Empty, T, Indic, Exp);
Set_Expression (Expression (N),
Make_Unchecked_Type_Conversion (Loc,
Subtype_Mark => New_Reference_To (Entity (Indic), Loc),
Expression => Exp));
Analyze (Expression (N));
Resolve (Expression (N), Entity (Indic));
end if;
Node := Relocate_Node (N);
Set_Analyzed (Node);
Insert_Action (N,
Make_Object_Declaration (Loc,
Defining_Identifier => Temp,
Constant_Present => True,
Object_Definition => New_Reference_To (PtrT, Loc),
Expression => Node));
if Is_Tagged_Type (T)
and then not Is_Class_Wide_Type (T)
then
Tag_Assign :=
Make_Assignment_Statement (Loc,
Name =>
Make_Selected_Component (Loc,
Prefix => New_Reference_To (Temp, Loc),
Selector_Name =>
New_Reference_To (Tag_Component (T), Loc)),
Expression =>
Make_Unchecked_Type_Conversion (Loc,
Subtype_Mark =>
New_Reference_To (RTE (RE_Tag), Loc),
Expression =>
New_Reference_To (Access_Disp_Table (T), Loc)));
-- The previous assignment has to be done in any case
Set_Assignment_OK (Name (Tag_Assign));
Insert_Action (N, Tag_Assign);
end if;
if Controlled_Type (T) then
declare
Flist : Node_Id;
Attach : Entity_Id;
begin
-- If it is an allocation on the secondary stack
-- (i.e. a returned value of a function), the
-- Finalization chain must come from the caller thru
-- an implicit parameter. ??? not implemented yet ???
-- for now the value is not attached.
if Associated_Storage_Pool (PtrT) = RTE (RE_SS_Pool) then
Flist :=
New_Reference_To (RTE (RE_Global_Final_List), Loc);
Attach := Standard_False;
else
Flist := Find_Final_List (PtrT);
Attach := Standard_True;
end if;
Insert_Actions (N,
Make_Adjust_Call (
Ref =>
-- An unchecked conversion is needed in the
-- classwide case because the designated type
-- can be an ancestor of the subtype mark of
-- the allocator.
Make_Unchecked_Type_Conversion (Loc,
Subtype_Mark => New_Reference_To (T, Loc),
Expression =>
Make_Explicit_Dereference (Loc,
New_Reference_To (Temp, Loc))),
Typ => T,
Flist_Ref => Flist,
With_Attach => New_Reference_To (Attach, Loc)));
end;
end if;
Rewrite_Substitute_Tree (N, New_Reference_To (Temp, Loc));
Analyze (N);
Resolve (N, PtrT);
end if;
end;
-- In this case, an initialization routine may be required
else
declare
T : constant Entity_Id := Entity (Expression (N));
Init : constant Entity_Id := Base_Init_Proc (T);
Arg1 : Node_Id;
Args : List_Id;
Discr : Elmt_Id;
Eact : Node_Id;
begin
-- If there is no initialization procedure, then the only case
-- where we need to do anything is if the designated type is
-- itself a pointer, in which case we must make sure that it
-- is initialized to null.
if No (Init) then
if Is_Access_Type (T)
or else (Is_Private_Type (T)
and then Present (Underlying_Type (T))
and then Is_Access_Type (Underlying_Type (T)))
then
Rewrite_Substitute_Tree (Expression (N),
Make_Qualified_Expression (Loc,
Subtype_Mark => New_Occurrence_Of (T, Loc),
Expression => Make_Null (Loc)));
Set_Etype (Expression (Expression (N)), T);
Set_Paren_Count (Expression (Expression (N)), 1);
Expand_N_Allocator (N);
else
null;
end if;
-- Else we have the case that definitely needs a call to
-- the initialization procedure.
else
Node := N;
Temp :=
Make_Defining_Identifier (Loc, New_Internal_Name ('P'));
-- Construct argument list for the initialization routine call
-- The CPP constructor needs the address directly
if Is_CPP_Class (T) then
Arg1 := New_Reference_To (Temp, Loc);
else
Arg1 :=
Make_Explicit_Dereference (Loc,
Prefix => New_Reference_To (Temp, Loc));
-- The initialization procedure expects a specific type.
-- if the context is access to class wide, indicate that
-- the object being allocated has the right specific type.
if Is_Class_Wide_Type (Designated_Type (PtrT)) then
Arg1 :=
Make_Unchecked_Type_Conversion (Loc,
Subtype_Mark => New_Reference_To (T, Loc),
Expression => Arg1);
end if;
end if;
-- If designated type is a concurrent type or if it is a
-- private type whose definition is a concurrent type,
-- the first argument in the Init routine has to be
-- unchecked conversion to the corresponding record type.
if Is_Concurrent_Type (T) then
Arg1 :=
Make_Unchecked_Type_Conversion (Loc,
Subtype_Mark =>
New_Reference_To (Corresponding_Record_Type (T), Loc),
Expression => Arg1);
elsif Is_Private_Type (T)
and then Is_Concurrent_Type (Full_View (T))
then
Arg1 :=
Make_Unchecked_Type_Conversion (Loc,
Subtype_Mark =>
New_Reference_To (
Corresponding_Record_Type (Full_View (T)), Loc),
Expression => Arg1);
end if;
Args := New_List (Arg1);
-- For the task case, pass the Master_Id of the access type
-- as the value of the _Master parameter, and _Chain as the
-- value of the _Chain parameter (_Chain will be defined as
-- part of the generated code for the allocator).
if Has_Tasks (T) then
if No (Master_Id (PtrT)) then
-- The designated type was an incomplete type, and
-- the access type did not get expanded. Salvage
-- it now. This may be a more general problem.
Expand_N_Full_Type_Declaration (Parent (PtrT));
end if;
Append_To (Args, New_Reference_To (Master_Id (PtrT), Loc));
Append_To (Args, Make_Identifier (Loc, Name_uChain));
end if;
-- Add discriminants if discriminated type
if Has_Discriminants (T) then
Discr := First_Elmt (Discriminant_Constraint (T));
while Present (Discr) loop
Append (New_Copy (Elists.Node (Discr)), Args);
Discr := Next_Elmt (Discr);
end loop;
end if;
-- We set the allocator as analyzed so that when we analyze the
-- expression actions node, we do not get an unwanted recursive
-- expansion of the allocator expression.
Set_Analyzed (N, True);
-- Now we can rewrite the allocator. First see if it is
-- already in an expression actions node, which will often
-- be the case, because this is how we handle the case of
-- discriminants being present. If so, we can just modify
-- that expression actions node that is there, otherwise
-- we must create an expression actions node.
Eact := Parent (N);
if Nkind (Eact) = N_Expression_Actions
and then Expression (Eact) = N
then
Node := N;
else
Rewrite_Substitute_Tree (N,
Make_Expression_Actions (Loc,
Actions => New_List,
Expression => Relocate_Node (N)));
Eact := N;
Node := Expression (N);
end if;
-- Now we modify the expression actions node as follows
-- input: [... ; new T]
-- output: [... ;
-- Temp : constant ptr_T := new (T);
-- Init (Temp.all, ...);
-- <CTRL> Attach_To_Final_List (Finalizable (Temp.all));
-- <CTRL> Initialize (Finalizable (Temp.all));
-- Temp]
-- Here ptr_T is the pointer type for the allocator, and T
-- is the subtype of the allocator.
Append_To (Actions (Eact),
Make_Object_Declaration (Loc,
Defining_Identifier => Temp,
Constant_Present => True,
Object_Definition => New_Reference_To (PtrT, Loc),
Expression => Node));
-- Case of designated type is task or contains task
if Has_Tasks (T) then
Build_Task_Allocate_Block (Actions (Eact), Node, Args);
else
Append_To (Actions (Eact),
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (Init, Loc),
Parameter_Associations => Args));
end if;
if Controlled_Type (T) then
Append_List_To (Actions (Eact),
Make_Init_Call (
Ref => New_Copy_Tree (Arg1),
Typ => T,
Flist_Ref => Find_Final_List (PtrT)));
end if;
Set_Expression (Eact, New_Reference_To (Temp, Loc));
Analyze (Eact);
end if;
end;
end if;
end Expand_N_Allocator;
-----------------------
-- Expand_N_And_Then --
-----------------------
-- Expand into conditional expression if Actions present
procedure Expand_N_And_Then (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Typ : constant Entity_Id := Etype (N);
Actlist : List_Id;
begin
-- If Actions are present, we expand
-- left and then right
-- into
-- if left then right else false end
-- with the actions becoming the Then_Actions of the conditional
-- expression. This conditional expression is then further expanded
-- (and will eventually disappear)
if Present (Actions (N)) then
Actlist := Actions (N);
Rewrite_Substitute_Tree (N,
Make_Conditional_Expression (Loc,
Expressions => New_List (
Left_Opnd (N),
Right_Opnd (N),
New_Occurrence_Of (Standard_False, Loc))));
Set_Then_Actions (N, Actlist);
Analyze (N);
Resolve (N, Typ);
end if;
end Expand_N_And_Then;
------------------------------
-- Expand_N_Concat_Multiple --
------------------------------
procedure Expand_N_Concat_Multiple (N : Node_Id) is
begin
Expand_Concatenation (N, Expressions (N));
end Expand_N_Concat_Multiple;
-------------------------------------
-- Expand_N_Conditional_Expression --
-------------------------------------
-- Expand into expression actions if then/else actions present
procedure Expand_N_Conditional_Expression (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Cond : constant Node_Id := First (Expressions (N));
Thenx : constant Node_Id := Next (Cond);
Elsex : constant Node_Id := Next (Thenx);
Typ : constant Entity_Id := Etype (N);
Cnn : Entity_Id;
New_If : Node_Id;
begin
-- If either then or else actions are present, then given:
-- if cond then then-expr else else-expr end
-- we insert the following sequence of actions (using Insert_Actions):
-- Cnn : typ;
-- if cond then
-- <<then actions>>
-- Cnn := then-expr;
-- else
-- <<else actions>>
-- Cnn := else-expr
-- end if;
-- and replace the conditional expression by a reference to Cnn.
if Present (Then_Actions (N)) or else Present (Else_Actions (N)) then
Cnn := Make_Defining_Identifier (Loc, New_Internal_Name ('C'));
New_If :=
Make_If_Statement (Loc,
Condition => Relocate_Node (Cond),
Then_Statements => New_List (
Make_Assignment_Statement (Sloc (Thenx),
Name => New_Occurrence_Of (Cnn, Sloc (Thenx)),
Expression => Relocate_Node (Thenx))),
Else_Statements => New_List (
Make_Assignment_Statement (Sloc (Elsex),
Name => New_Occurrence_Of (Cnn, Sloc (Elsex)),
Expression => Relocate_Node (Elsex))));
if Present (Then_Actions (N)) then
Insert_List_Before
(First (Then_Statements (New_If)), Then_Actions (N));
end if;
if Present (Else_Actions (N)) then
Insert_List_Before
(First (Else_Statements (New_If)), Else_Actions (N));
end if;
Rewrite_Substitute_Tree (N, New_Occurrence_Of (Cnn, Loc));
Insert_Action (N,
Make_Object_Declaration (Loc,
Defining_Identifier => Cnn,
Object_Definition => New_Occurrence_Of (Typ, Loc)));
Insert_Action (N, New_If);
Analyze (N);
Resolve (N, Typ);
end if;
end Expand_N_Conditional_Expression;
-----------------
-- Expand_N_In --
-----------------
procedure Expand_N_In (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Typ : constant Entity_Id := Etype (N);
begin
-- No expansion is required if we have an explicit range
if Nkind (Right_Opnd (N)) = N_Range then
return;
-- Here right operand is a subtype mark
else
declare
Subt : constant Entity_Id := Etype (Right_Opnd (N));
begin
-- For tagged type, do tagged membership operation
if Is_Tagged_Type (Subt) then
Rewrite_Substitute_Tree (N, Tagged_Membership (N));
Analyze (N);
Resolve (N, Typ);
-- If type is its own base type, result is always true
elsif Base_Type (Subt) = Subt then
Rewrite_Substitute_Tree (N,
New_Reference_To (Standard_True, Loc));
Analyze (N);
Resolve (N, Typ);
-- If type is scalar type, rewrite as x in t'first .. t'last
-- This reason we do this is that the bounds may have the wrong
-- type if they come from the original type definition.
elsif Is_Scalar_Type (Subt) then
Rewrite_Substitute_Tree (Right_Opnd (N),
Make_Range (Loc,
Low_Bound =>
Make_Attribute_Reference (Loc,
Attribute_Name => Name_First,
Prefix => New_Reference_To (Subt, Loc)),
High_Bound =>
Make_Attribute_Reference (Loc,
Attribute_Name => Name_Last,
Prefix => New_Reference_To (Subt, Loc))));
Analyze (N);
Resolve (N, Typ);
end if;
end;
end if;
end Expand_N_In;
--------------------------------
-- Expand_N_Indexed_Component --
--------------------------------
-- The only case we deal with is indexing a packed array, where we
-- convert the reference to a reference to the apropriate bits in the
-- object of the corresponding Packed_Array_Type. This processing is
-- done only for a reference, not for an assignment left hand side,
-- which is handled directly in Expand_N_Assignment.
procedure Expand_N_Indexed_Component (N : Node_Id) is
begin
Apply_Subscript_Conversion_Checks (N);
if Is_Packed (Etype (Prefix (N)))
and then (Nkind (Parent (N)) /= N_Assignment_Statement
or else Name (Parent (N)) /= N)
then
Expand_Packed_Element_Get (N);
end if;
end Expand_N_Indexed_Component;
---------------------
-- Expand_N_Not_In --
---------------------
-- Replace a not in b by not (a in b) so that the expansions for (a in b)
-- can be done. This avoids needing to duplicate this expansion code.
procedure Expand_N_Not_In (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Typ : constant Entity_Id := Etype (N);
begin
Rewrite_Substitute_Tree (N,
Make_Op_Not (Loc,
Right_Opnd =>
Make_In (Loc,
Left_Opnd => Left_Opnd (N),
Right_Opnd => Right_Opnd (N))));
Analyze (N);
Resolve (N, Typ);
end Expand_N_Not_In;
---------------------
-- Expand_N_Op_Abs --
---------------------
procedure Expand_N_Op_Abs (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Expr : Multi_Use.Exp_Id;
Added_Code : List_Id;
begin
if Software_Overflow_Checking
and then Is_Signed_Integer_Type (Etype (N))
and then Do_Overflow_Check (N)
then
-- Software overflow checking expands abs (expr) into
-- (if expr >= 0 then expr else -expr)
-- with the usual multiple use coding for expr
Multi_Use.Prepare (Right_Opnd (N), Expr, Added_Code);
Rewrite_Substitute_Tree (N,
Multi_Use.Wrap (Added_Code,
Make_Conditional_Expression (Loc,
Expressions => New_List (
Make_Op_Ge (Loc,
Left_Opnd => Multi_Use.New_Ref (Expr),
Right_Opnd => Make_Integer_Literal (Loc, Uint_0)),
Multi_Use.New_Ref (Expr),
Make_Op_Minus (Loc,
Right_Opnd => Multi_Use.New_Ref (Expr))))));
Analyze (N);
Resolve (N, Etype (N));
end if;
end Expand_N_Op_Abs;
---------------------
-- Expand_N_Op_Add --
---------------------
procedure Expand_N_Op_Add (N : Node_Id) is
begin
if Software_Overflow_Checking
and then Is_Signed_Integer_Type (Etype (N))
and then Do_Overflow_Check (N)
then
Apply_Arithmetic_Overflow_Check (N);
end if;
end Expand_N_Op_Add;
---------------------
-- Expand_N_Op_And --
---------------------
procedure Expand_N_Op_And (N : Node_Id) is
begin
if Is_Array_Type (Etype (N)) then
Expand_Boolean_Operator (N);
end if;
end Expand_N_Op_And;
------------------------
-- Expand_N_Op_Concat --
------------------------
procedure Expand_N_Op_Concat (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Lhs : Node_Id := Left_Opnd (N);
Rhs : Node_Id := Right_Opnd (N);
Ltyp : Entity_Id := Base_Type (Etype (Lhs));
Rtyp : Entity_Id := Base_Type (Etype (Rhs));
Comp_Typ : Entity_Id := Base_Type (Component_Type (Etype (N)));
begin
-- If left operand is a single component, replace by an aggregate
-- of the form (1 => operand), as required by concatenation semantics.
if Ltyp = Comp_Typ then
Lhs :=
Make_Aggregate (Loc,
Component_Associations => New_List (
Make_Component_Association (Loc,
Choices => New_List (Make_Integer_Literal (Loc, Uint_1)),
Expression => Relocate_Node (Lhs))));
Ltyp := Base_Type (Etype (N));
end if;
-- Similar handling for right operand
if Rtyp = Comp_Typ then
Rhs :=
Make_Aggregate (Loc,
Component_Associations => New_List (
Make_Component_Association (Loc,
Choices => New_List (Make_Integer_Literal (Loc, Uint_1)),
Expression => Relocate_Node (Rhs))));
Rtyp := Base_Type (Etype (N));
end if;
-- Handle case of concatenating Standard.String with runtime call
if Ltyp = Standard_String and then Rtyp = Standard_String then
Rewrite_Substitute_Tree (N,
Make_Function_Call (Loc,
Name => New_Reference_To (RTE (RE_Str_Concat), Loc),
Parameter_Associations => New_List (Lhs, Rhs)));
Analyze (N);
Resolve (N, Standard_String);
-- For other than Standard.String, use general routine
else
Expand_Concatenation (N, New_List (Lhs, Rhs));
end if;
end Expand_N_Op_Concat;
------------------------
-- Expand_N_Op_Divide --
------------------------
procedure Expand_N_Op_Divide (N : Node_Id) is
Typ : constant Entity_Id := Etype (N);
Ltyp : constant Entity_Id := Etype (Left_Opnd (N));
Rtyp : constant Entity_Id := Etype (Right_Opnd (N));
begin
-- Do nothing if result type is universal fixed, this means that
-- the node above us is a conversion node or a 'Round attribute
-- reference, and we will build and expand the properly typed
-- division node when we expand the parent node.
if Typ = Universal_Fixed then
return;
-- Divisions with other fixed-point results. Note that we exclude
-- the case where Treat_Fixed_As_Integer is set, since from a
-- semantic point of view, these are just integer divisions.
elsif Is_Fixed_Point_Type (Typ)
and then not Treat_Fixed_As_Integer (N)
then
if Is_Integer_Type (Rtyp) then
Expand_Divide_Fixed_By_Integer_Giving_Fixed (N);
else
Expand_Divide_Fixed_By_Fixed_Giving_Fixed (N);
end if;
-- Other cases of division of fixed-point operands. Again we exclude
-- the case where Treat_Fixed_As_Integer is set.
elsif (Is_Fixed_Point_Type (Ltyp) or else
Is_Fixed_Point_Type (Rtyp))
and then not Treat_Fixed_As_Integer (N)
then
if Is_Integer_Type (Typ) then
Expand_Divide_Fixed_By_Fixed_Giving_Integer (N);
else
pragma Assert (Is_Floating_Point_Type (Typ));
Expand_Divide_Fixed_By_Fixed_Giving_Float (N);
end if;
-- Non-fixed point cases, check for software overflow checking
elsif Software_Overflow_Checking
and then Is_Integer_Type (Typ)
and then Do_Overflow_Check (N)
then
Expand_Zero_Divide_Check (N);
if Is_Signed_Integer_Type (Etype (N)) then
Apply_Arithmetic_Overflow_Check (N);
end if;
end if;
end Expand_N_Op_Divide;
--------------------
-- Expand_N_Op_Eq --
--------------------
procedure Expand_N_Op_Eq (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Lhs : constant Node_Id := Left_Opnd (N);
Rhs : constant Node_Id := Right_Opnd (N);
Typl : Entity_Id := Etype (Lhs);
begin
if Ekind (Typl) = E_Private_Type then
Typl := Underlying_Type (Typl);
end if;
Typl := Base_Type (Typl);
if Is_Array_Type (Typl) then
if Is_Scalar_Type (Component_Type (Typl)) then
-- The case of two constrained arrays can be left to Gigi
if Nkind (Lhs) /= N_Expression_Actions
and then Nkind (Rhs) /= N_Expression_Actions
then
null;
-- Kludge to avoid a bug in Gigi (works only for Strings) ???
elsif Typl = Standard_String then
Rewrite_Substitute_Tree (N,
Make_Function_Call (Loc,
Name => New_Reference_To (RTE (RE_Str_Equal), Loc),
Parameter_Associations =>
New_List (New_Copy (Lhs), New_Copy (Rhs))));
Analyze (N);
Resolve (N, Standard_Boolean);
-- Other cases, we hope Gigi will not blow up ???
else
null;
end if;
else
Rewrite_Substitute_Tree (N,
Expand_Array_Equality
(Loc, Typl, New_Copy (Lhs), New_Copy (Rhs)));
Analyze (N);
Resolve (N, Standard_Boolean);
end if;
elsif Is_Record_Type (Typl) then
-- For tagged types, use the primitive "="
if Is_Tagged_Type (Typl) then
Rewrite_Substitute_Tree (N,
Make_Function_Call (Loc,
Name =>
New_Reference_To (Find_Prim_Op (Typl, Name_Op_Eq), Loc),
Parameter_Associations => New_List (
Node1 => Relocate_Node (Lhs),
Node2 =>
Make_Unchecked_Type_Conversion (Loc,
Subtype_Mark => New_Reference_To (Etype (Lhs), Loc),
Expression => Relocate_Node (Rhs)))));
Analyze (N);
Resolve (N, Standard_Boolean);
-- If a type support function is present (for complex cases), use it
elsif Present (TSS (Typl, Name_uEquality)) then
Rewrite_Substitute_Tree (N,
Make_Function_Call (Loc,
Name => New_Reference_To (TSS (Typl, Name_uEquality), Loc),
Parameter_Associations => New_List (
Node1 => Relocate_Node (Lhs),
Node2 => Relocate_Node (Rhs))));
Analyze (N);
Resolve (N, Standard_Boolean);
-- Otherwise expand the component by component equality
else
declare
use Multi_Use;
Actions : constant List_Id := New_List;
L : Exp_Id;
R : Exp_Id;
begin
Multi_Use.New_Exp_Id (Lhs, Actions, L);
Multi_Use.New_Exp_Id (Rhs, Actions, R);
if Is_Empty_List (Actions) then
Rewrite_Substitute_Tree (N,
Expand_Record_Equality (Loc, Typl,
Multi_Use.New_Ref (L), Multi_Use.New_Ref (R)));
else
Rewrite_Substitute_Tree (N,
Make_Expression_Actions (Loc,
Actions => Actions,
Expression =>
Expand_Record_Equality (Loc, Typl,
Multi_Use.New_Ref (L),
Multi_Use.New_Ref (R))));
end if;
Analyze (N);
Resolve (N, Standard_Boolean);
end;
end if;
end if;
end Expand_N_Op_Eq;
-----------------------
-- Expand_N_Op_Expon --
-----------------------
procedure Expand_N_Op_Expon (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Typ : constant Entity_Id := Etype (N);
Btyp : constant Entity_Id := Root_Type (Typ);
Max : constant Uint := Uint_4;
Min : constant Uint := Uint_Minus_4;
Base : constant Node_Id := New_Copy (Left_Opnd (N));
Exp : constant Node_Id := New_Copy (Right_Opnd (N));
Ovflo : constant Boolean := Do_Overflow_Check (N);
Expv : Uint;
Xnode : Node_Id;
Temp : Node_Id;
Rent : RE_Id;
Ent : Entity_Id;
E_Base : Multi_Use.Exp_Id;
Added_Code : List_Id;
begin
-- At this point the exponentiation must be dynamic since the static
-- case has already been folded after Resolve by Eval_Op_Expon.
-- Test for case of literal right argument
if Nkind (Exp) = N_Integer_Literal then
Expv := Intval (Exp);
if (Ekind (Typ) in Float_Kind
and then Expv >= Min
and then Expv <= Max)
or else
(Ekind (Typ) in Integer_Kind
and then Expv >= 0
and then Expv <= Max)
then
Expv := abs Expv;
-- X ** 0 = 1 (or 1.0)
if Expv = 0 then
if Ekind (Typ) in Integer_Kind then
Xnode := Make_Integer_Literal (Loc, Intval => Uint_1);
else
Xnode := Make_Real_Literal (Loc, Ureal_1);
end if;
-- X ** 1 = X
elsif Expv = 1 then
Xnode := Base;
-- X ** 2 = X * X
elsif Expv = 2 then
Multi_Use.Prepare (Base, E_Base, Added_Code);
Xnode := Multi_Use.Wrap (Added_Code,
Make_Op_Multiply (Loc,
Left_Opnd => Multi_Use.New_Ref (E_Base),
Right_Opnd => Multi_Use.New_Ref (E_Base)));
-- X ** 3 = X * X * X
elsif Expv = 3 then
Multi_Use.Prepare (Base, E_Base, Added_Code);
Xnode := Multi_Use.Wrap (Added_Code,
Make_Op_Multiply (Loc,
Left_Opnd =>
Make_Op_Multiply (Loc,
Left_Opnd => Multi_Use.New_Ref (E_Base),
Right_Opnd => Multi_Use.New_Ref (E_Base)),
Right_Opnd => Multi_Use.New_Ref (E_Base)));
-- X ** 4 -> [Xn : constant base'type := base * base; Xn * Xn]
elsif Expv = 4 then
Multi_Use.Prepare (Base, E_Base, Added_Code);
Temp :=
Make_Defining_Identifier (Loc, New_Internal_Name ('X'));
Xnode :=
Make_Expression_Actions (Loc,
Actions => New_List (
Make_Object_Declaration (Loc,
Defining_Identifier => Temp,
Constant_Present => True,
Object_Definition => New_Reference_To (Typ, Loc),
Expression =>
Make_Op_Multiply (Loc,
Left_Opnd => Multi_Use.New_Ref (E_Base),
Right_Opnd => Multi_Use.New_Ref (E_Base)))),
Expression =>
Make_Op_Multiply (Loc,
Left_Opnd => New_Reference_To (Temp, Loc),
Right_Opnd => New_Reference_To (Temp, Loc)));
if Present (Added_Code) then
Append_List (Actions (Xnode), Added_Code);
Set_Actions (Xnode, Added_Code);
end if;
end if;
-- For non-negative case, we are all set
if Intval (Exp) >= 0 then
Rewrite_Substitute_Tree (N, Xnode);
-- For negative cases, take reciprocal (base must be real)
else
Set_Paren_Count (Xnode, 1);
Rewrite_Substitute_Tree (N,
Make_Op_Divide (Loc,
Left_Opnd => Make_Real_Literal (Loc, Ureal_1),
Right_Opnd => Xnode));
end if;
Analyze (N);
Resolve (N, Typ);
return;
-- Don't fold cases of large literal exponents, and also don't fold
-- cases of integer bases with negative literal exponents.
end if;
-- Don't fold cases where exponent is not integer literal
end if;
-- Fall through if exponentiation must be done using a runtime routine
-- First deal with modular case.
if Is_Modular_Integer_Type (Btyp) then
-- Non-binary case, we call the special exponentiation routine for
-- the non-binary case, converting the argument to Long_Long_Integer
-- and passing the modulus value. Then the result is converted back
-- to the base type.
if Non_Binary_Modulus (Btyp) then
Rewrite_Substitute_Tree (N,
Make_Type_Conversion (Loc,
Subtype_Mark => New_Reference_To (Typ, Loc),
Expression =>
Make_Function_Call (Loc,
Name => New_Reference_To (RTE (RE_Exp_Modular), Loc),
Parameter_Associations => New_List (
Make_Type_Conversion (Loc,
Subtype_Mark =>
New_Reference_To (Standard_Integer, Loc),
Expression => Base),
Make_Integer_Literal (Loc, Modulus (Btyp)),
Exp))));
-- Binary case, in this case, we call one of two routines, either
-- the unsigned integer case, or the unsigned long long integer
-- case, with the final conversion doing the required truncation.
else
if UI_To_Int (Esize (Btyp)) <= Standard_Integer_Size then
Ent := RTE (RE_Exp_Unsigned);
else
Ent := RTE (RE_Exp_Long_Long_Unsigned);
end if;
Rewrite_Substitute_Tree (N,
Make_Type_Conversion (Loc,
Subtype_Mark => New_Reference_To (Typ, Loc),
Expression =>
Make_Function_Call (Loc,
Name => New_Reference_To (Ent, Loc),
Parameter_Associations => New_List (
Make_Type_Conversion (Loc,
Subtype_Mark =>
New_Reference_To (Etype (First_Formal (Ent)), Loc),
Expression => Base),
Exp))));
end if;
-- Common exit point for modular type case
Analyze (N);
Resolve (N, Typ);
return;
-- Signed integer cases
elsif Btyp = Standard_Integer then
if Ovflo then
Rent := RE_Exp_Integer;
else
Rent := RE_Exn_Integer;
end if;
elsif Btyp = Standard_Short_Integer then
if Ovflo then
Rent := RE_Exp_Short_Integer;
else
Rent := RE_Exn_Short_Integer;
end if;
elsif Btyp = Standard_Short_Short_Integer then
if Ovflo then
Rent := RE_Exp_Short_Short_Integer;
else
Rent := RE_Exn_Short_Short_Integer;
end if;
elsif Btyp = Standard_Long_Integer then
if Ovflo then
Rent := RE_Exp_Long_Integer;
else
Rent := RE_Exn_Long_Integer;
end if;
elsif (Btyp = Standard_Long_Long_Integer
or else Btyp = Universal_Integer)
then
if Ovflo then
Rent := RE_Exp_Long_Long_Integer;
else
Rent := RE_Exn_Long_Long_Integer;
end if;
-- Floating-point cases
elsif Btyp = Standard_Float then
if Ovflo then
Rent := RE_Exp_Float;
else
Rent := RE_Exn_Float;
end if;
elsif Btyp = Standard_Short_Float then
if Ovflo then
Rent := RE_Exp_Short_Float;
else
Rent := RE_Exn_Short_Float;
end if;
elsif Btyp = Standard_Long_Float then
if Ovflo then
Rent := RE_Exp_Long_Float;
else
Rent := RE_Exn_Long_Float;
end if;
elsif Btyp = Standard_Long_Long_Float
or else Btyp = Universal_Real
then
if Ovflo then
Rent := RE_Exp_Long_Long_Float;
else
Rent := RE_Exn_Long_Long_Float;
end if;
else
pragma Assert (False); null;
end if;
-- Common processing for integer cases and floating-point cases.
-- If we are in the base type, we can call runtime routine directly
if Typ = Btyp
and then Btyp /= Universal_Integer
and then Btyp /= Universal_Real
then
Rewrite_Substitute_Tree (N,
Make_Function_Call (Loc,
Name => New_Reference_To (RTE (Rent), Loc),
Parameter_Associations => New_List (Base, Exp)));
-- Otherwise we have to introduce conversions (conversions are also
-- required in the universal cases, since the runtime routine was
-- typed using the largest integer or real case.
else
Rewrite_Substitute_Tree (N,
Make_Type_Conversion (Loc,
Subtype_Mark => New_Reference_To (Typ, Loc),
Expression =>
Make_Function_Call (Loc,
Name => New_Reference_To (RTE (Rent), Loc),
Parameter_Associations => New_List (
Make_Type_Conversion (Loc,
Subtype_Mark => New_Reference_To (Btyp, Loc),
Expression => Base),
Exp))));
end if;
Analyze (N);
Resolve (N, Typ);
return;
end Expand_N_Op_Expon;
--------------------
-- Expand_N_Op_Ge --
--------------------
procedure Expand_N_Op_Ge (N : Node_Id) is
begin
Expand_Comparison_Operator (N);
end Expand_N_Op_Ge;
--------------------
-- Expand_N_Op_Gt --
--------------------
procedure Expand_N_Op_Gt (N : Node_Id) is
begin
Expand_Comparison_Operator (N);
end Expand_N_Op_Gt;
--------------------
-- Expand_N_Op_Le --
--------------------
procedure Expand_N_Op_Le (N : Node_Id) is
begin
Expand_Comparison_Operator (N);
end Expand_N_Op_Le;
--------------------
-- Expand_N_Op_Lt --
--------------------
procedure Expand_N_Op_Lt (N : Node_Id) is
begin
Expand_Comparison_Operator (N);
end Expand_N_Op_Lt;
-----------------------
-- Expand_N_Op_Minus --
-----------------------
procedure Expand_N_Op_Minus (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Typ : constant Entity_Id := Etype (N);
begin
if Software_Overflow_Checking
and then Is_Signed_Integer_Type (Etype (N))
and then Do_Overflow_Check (N)
then
-- Software overflow checking expands -expr into (0 - expr)
Rewrite_Substitute_Tree (N,
Make_Op_Subtract (Loc,
Left_Opnd => Make_Integer_Literal (Loc, Uint_0),
Right_Opnd => Right_Opnd (N)));
Analyze (N);
Resolve (N, Typ);
end if;
end Expand_N_Op_Minus;
---------------------
-- Expand_N_Op_Mod --
---------------------
procedure Expand_N_Op_Mod (N : Node_Id) is
begin
if Software_Overflow_Checking
and then Is_Integer_Type (Etype (N))
and then Do_Overflow_Check (N)
then
Expand_Zero_Divide_Check (N);
end if;
end Expand_N_Op_Mod;
--------------------------
-- Expand_N_Op_Multiply --
--------------------------
procedure Expand_N_Op_Multiply (N : Node_Id) is
Typ : constant Entity_Id := Etype (N);
Ltyp : constant Entity_Id := Etype (Left_Opnd (N));
Rtyp : constant Entity_Id := Etype (Right_Opnd (N));
begin
-- Do nothing if result type is universal fixed, this means that
-- the node above us is a conversion node or a 'Round attribute
-- reference, and we will build and expand the properly typed
-- multiplication node when we expand the parent node.
if Typ = Universal_Fixed then
return;
-- Multiplications with other fixed-point results. Note that we
-- exclude the cases where Treat_Fixed_As_Integer is set, since
-- from a semantic point of view, these are just integer multiplies.
elsif Is_Fixed_Point_Type (Typ)
and then not Treat_Fixed_As_Integer (N)
then
-- Case of fixed * integer => fixed
if Is_Integer_Type (Rtyp) then
Expand_Multiply_Fixed_By_Integer_Giving_Fixed (N);
-- Case of integer * fixed => fixed
elsif Is_Integer_Type (Ltyp) then
Expand_Multiply_Integer_By_Fixed_Giving_Fixed (N);
-- Case of fixed * fixed => fixed
else
Expand_Multiply_Fixed_By_Fixed_Giving_Fixed (N);
end if;
-- Other cases of multiplication of fixed-point operands. Again we
-- exclude the cases where Treat_Fixed_As_Integer flag is set.
elsif (Is_Fixed_Point_Type (Ltyp) or else
Is_Fixed_Point_Type (Rtyp))
and then not Treat_Fixed_As_Integer (N)
then
if Is_Integer_Type (Typ) then
Expand_Multiply_Fixed_By_Fixed_Giving_Integer (N);
else
pragma Assert (Is_Floating_Point_Type (Typ));
Expand_Multiply_Fixed_By_Fixed_Giving_Float (N);
end if;
-- Non-fixed point cases, check software overflow checking required
elsif Software_Overflow_Checking
and then Is_Signed_Integer_Type (Etype (N))
and then Do_Overflow_Check (N)
then
Apply_Arithmetic_Overflow_Check (N);
end if;
end Expand_N_Op_Multiply;
--------------------
-- Expand_N_Op_Ne --
--------------------
-- Rewrite node as the negation of an equality operation, and reanalyze.
-- The equality to be used is defined in the same scope and has the same
-- signature. It must be set explicitly because in an instance it may not
-- have the same visibility as in the generic unit.
procedure Expand_N_Op_Ne (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Neg : Node_Id;
Ne : constant Entity_Id := Entity (N);
Eq : Entity_Id;
begin
Neg := Make_Op_Not (Loc,
Make_Op_Eq (Loc, Left_Opnd (N), Right_Opnd (N)));
if Scope (Ne) /= Standard_Standard then
Eq := First_Entity (Scope (Ne));
while Present (Eq)
and then (Chars (Eq) /= Name_Op_Eq
or else Next_Entity (Eq) /= Ne)
loop
Eq := Next_Entity (Eq);
end loop;
Set_Entity (Right_Opnd (Neg), Eq);
end if;
Rewrite_Substitute_Tree (N, Neg);
Analyze (N);
Resolve (N, Standard_Boolean);
end Expand_N_Op_Ne;
---------------------
-- Expand_N_Op_Not --
---------------------
-- If the argument is other than a Boolean array type, there is no
-- special expansion required.
-- For the packed case, we call the special routine in Exp_Pakd, except
-- that if the component size is greater than one, we use the standard
-- routine generating a gruesome loop (it is so peculiar to have packed
-- arrays with non-standard Boolean representations anyway, so it does
-- not matter that we do not handle this case efficiently).
-- For the unpacked case (and for the special packed case where we have
-- non standard Booleans, as discussed above), we generate and insert
-- into the tree the following function definition:
-- function Nnnn (A : arr) is
-- B : arr;
-- begin
-- for J in a'range loop
-- B (J) := not A (J);
-- end loop;
-- return B;
-- end Nnnn;
-- Here arr is the actual subtype of the parameter (and hence always
-- constrained). Then we replace the not with a call to this function.
procedure Expand_N_Op_Not (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Typ : constant Entity_Id := Etype (N);
Opnd : Node_Id;
Arr : Entity_Id;
A : Entity_Id;
B : Entity_Id;
J : Entity_Id;
A_J : Node_Id;
B_J : Node_Id;
Func_Name : Entity_Id;
Loop_Statement : Node_Id;
begin
if not Is_Array_Type (Typ) then
return;
elsif Is_Packed (Typ) and then Esize (Component_Type (Typ)) = 1 then
Expand_Packed_Not (N);
return;
end if;
Opnd := Convert_To_Actual_Subtype (Right_Opnd (N));
Arr := Etype (Opnd);
A := Make_Defining_Identifier (Loc, Name_uA);
B := Make_Defining_Identifier (Loc, Name_uB);
J := Make_Defining_Identifier (Loc, Name_uJ);
A_J :=
Make_Indexed_Component (Loc,
Prefix => New_Reference_To (A, Loc),
Expressions => New_List (New_Reference_To (J, Loc)));
B_J :=
Make_Indexed_Component (Loc,
Prefix => New_Reference_To (B, Loc),
Expressions => New_List (New_Reference_To (J, Loc)));
Loop_Statement :=
Make_Loop_Statement (Loc,
Identifier => Empty,
Iteration_Scheme =>
Make_Iteration_Scheme (Loc,
Loop_Parameter_Specification =>
Make_Loop_Parameter_Specification (Loc,
Defining_Identifier => J,
Discrete_Subtype_Definition =>
Make_Attribute_Reference (Loc,
Prefix => Make_Identifier (Loc, Chars (A)),
Attribute_Name => Name_Range))),
Statements => New_List (
Make_Assignment_Statement (Loc,
Name => B_J,
Expression => Make_Op_Not (Loc, A_J))));
Func_Name := Make_Defining_Identifier (Loc, New_Internal_Name ('N'));
Insert_Action (N,
Make_Subprogram_Body (Loc,
Specification =>
Make_Function_Specification (Loc,
Defining_Unit_Name => Func_Name,
Parameter_Specifications => New_List (
Make_Parameter_Specification (Loc,
Defining_Identifier => A,
Parameter_Type => New_Reference_To (Typ, Loc))),
Subtype_Mark => New_Reference_To (Typ, Loc)),
Declarations => New_List (
Make_Object_Declaration (Loc,
Defining_Identifier => B,
Object_Definition => New_Reference_To (Typ, Loc))),
Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Loc,
Statements => New_List (
Loop_Statement,
Make_Return_Statement (Loc,
Expression =>
Make_Identifier (Loc, Chars (B)))))));
Rewrite_Substitute_Tree (N,
Make_Function_Call (Loc,
Name => New_Reference_To (Func_Name, Loc),
Parameter_Associations => New_List (Opnd)));
Analyze (N);
Resolve (N, Typ);
end Expand_N_Op_Not;
--------------------
-- Expand_N_Op_Or --
--------------------
procedure Expand_N_Op_Or (N : Node_Id) is
begin
if Is_Array_Type (Etype (N)) then
Expand_Boolean_Operator (N);
end if;
end Expand_N_Op_Or;
---------------------
-- Expand_N_Op_Rem --
---------------------
procedure Expand_N_Op_Rem (N : Node_Id) is
begin
if Software_Overflow_Checking
and then Is_Integer_Type (Etype (N))
and then Do_Overflow_Check (N)
then
Expand_Zero_Divide_Check (N);
end if;
end Expand_N_Op_Rem;
--------------------------
-- Expand_N_Op_Subtract --
--------------------------
procedure Expand_N_Op_Subtract (N : Node_Id) is
begin
if Software_Overflow_Checking
and then Is_Signed_Integer_Type (Etype (N))
and then Do_Overflow_Check (N)
then
Apply_Arithmetic_Overflow_Check (N);
end if;
end Expand_N_Op_Subtract;
---------------------
-- Expand_N_Op_Xor --
---------------------
procedure Expand_N_Op_Xor (N : Node_Id) is
begin
if Is_Array_Type (Etype (N)) then
Expand_Boolean_Operator (N);
end if;
end Expand_N_Op_Xor;
----------------------
-- Expand_N_Or_Else --
----------------------
-- Expand into conditional expression if Actions present
procedure Expand_N_Or_Else (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Typ : constant Entity_Id := Etype (N);
Actlist : List_Id;
begin
-- If Actions are present, we expand
-- left or else right
-- into
-- if left then True else right end
-- with the actions becoming the Else_Actions of the conditional
-- expression. This conditional expression is then further expanded
-- (and will eventually disappear)
if Present (Actions (N)) then
Actlist := Actions (N);
Rewrite_Substitute_Tree (N,
Make_Conditional_Expression (Loc,
Expressions => New_List (
Left_Opnd (N),
New_Occurrence_Of (Standard_True, Loc),
Right_Opnd (N))));
Set_Else_Actions (N, Actlist);
Analyze (N);
Resolve (N, Typ);
end if;
end Expand_N_Or_Else;
--------------------
-- Expand_N_Slice --
--------------------
-- Build an implicit subtype declaration to represent the type delivered
-- by the slice. This is an abbreviated version of an array subtype. We
-- define an index subtype for the slice, using either the subtype name
-- or the discrete range of the slice. To be consistent with index usage
-- elsewhere, we create a list header to hold the single index. This list
-- is not otherwise attached to the syntax tree.
procedure Expand_N_Slice (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Index : Node_Id;
Index_List : List_Id := New_List;
Index_Subtype : Entity_Id;
Index_Type : Entity_Id;
Slice_Subtype : Entity_Id;
begin
if Is_Entity_Name (Discrete_Range (N)) then
Index_Subtype := Entity (Discrete_Range (N));
else
Index_Type := Base_Type (Etype (Discrete_Range (N)));
Index_Subtype := New_Itype (Subtype_Kind (Ekind (Index_Type)), N);
Set_Scalar_Range (Index_Subtype, Discrete_Range (N));
Set_Etype (Index_Subtype, Index_Type);
Set_Esize (Index_Subtype, Esize (Index_Type));
end if;
Slice_Subtype := New_Itype (E_Array_Subtype, N);
Index := New_Occurrence_Of (Index_Subtype, Loc);
Set_Etype (Index, Index_Subtype);
Append (Index, Index_List);
Set_Component_Type (Slice_Subtype, Component_Type (Etype (N)));
Set_First_Index (Slice_Subtype, Index);
Set_Etype (Slice_Subtype, Base_Type (Etype (N)));
Set_Is_Constrained (Slice_Subtype);
Check_Compile_Time_Size (Slice_Subtype);
-- The Etype of the existing Slice node is reset to this slice
-- subtype. Its bounds are obtained from its first index.
Set_Etype (N, Slice_Subtype);
end Expand_N_Slice;
------------------------------
-- Expand_N_Type_Conversion --
------------------------------
procedure Expand_N_Type_Conversion (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Expr : constant Node_Id := Expression (N);
T : constant Entity_Id := Etype (N);
begin
-- When needed, that is to say when the expression is class-wide,
-- Add runtime a tag check for (strict) downward conversion by using
-- the membership test:
-- [if Expr not in T'Class then raise Constraint_Error; end if; N]
-- or in the access type case
-- [if Expr /= null
-- and then Expr.all not in Designated_Type (T)'Class
-- then
-- raise Constraint_Error;
-- end if;
-- N]
if (Is_Access_Type (T)
and then Is_Tagged_Type (Designated_Type (T)))
or else Is_Tagged_Type (T)
then
declare
E : Multi_Use.Exp_Id;
Expr_Type : Entity_Id := Etype (Expr);
Target_Typ : Entity_Id := T;
Cond : Node_Id;
begin
if Is_Access_Type (T) then
Expr_Type := Designated_Type (Expr_Type);
Target_Typ := Designated_Type (T);
end if;
if Is_Class_Wide_Type (Expr_Type)
and then Root_Type (Expr_Type) /= Target_Typ
and then Is_Ancestor (Root_Type (Expr_Type), Target_Typ)
and then not Tag_Checks_Suppressed (Target_Typ)
then
-- The conversion is valid for any descendant of the
-- target type
Target_Typ := Class_Wide_Type (Target_Typ);
Replace_Substitute_Tree (N,
Make_Expression_Actions (Loc,
Actions => New_List,
Expression => Relocate_Node (N)));
Multi_Use.New_Exp_Id (Expr, Actions (N), E);
Replace_Substitute_Tree (Expr, Multi_Use.New_Ref (E));
if Is_Access_Type (T) then
Cond :=
Make_And_Then (Loc,
Left_Opnd =>
Make_Op_Ne (Loc,
Left_Opnd => Multi_Use.New_Ref (E),
Right_Opnd => Make_Null (Loc)),
Right_Opnd =>
Make_Not_In (Loc,
Left_Opnd =>
Make_Explicit_Dereference (Loc,
Prefix => Multi_Use.New_Ref (E)),
Right_Opnd => New_Reference_To (Target_Typ, Loc)));
else
Cond :=
Make_Not_In (Loc,
Left_Opnd => Multi_Use.New_Ref (E),
Right_Opnd => New_Reference_To (Target_Typ, Loc));
end if;
Append_To (Actions (N),
Make_If_Statement (Loc,
Condition => Cond,
Then_Statements => New_List (New_Constraint_Error (Loc))));
Change_Conversion_To_Unchecked (Expression (N));
Analyze (N);
Resolve (N, T);
end if;
end;
-- Deal with cases where the operand is universal fixed, which means
-- it must be a multiply or divide. In these cases, we simply replace
-- the conversion by the multiply or divide node, retyping its result
-- as the target type of the conversion. Note that all nodes have been
-- analyzed already, so we don't need to reanalyze them.
elsif Etype (Expr) = Universal_Fixed then
if Nkind (Expr) = N_Op_Multiply then
Replace_Substitute_Tree (N, Expr);
Set_Etype (N, T);
Expand_N_Op_Multiply (N);
else
pragma Assert (Nkind (Expr) = N_Op_Divide);
Replace_Substitute_Tree (N, Expr);
Set_Etype (N, T);
Expand_N_Op_Divide (N);
end if;
-- Expansion of conversions whose source is a fixed-point type. Note
-- we ignore cases where Conversion_OK is set, since from a semantic
-- point of view, these are normal arithmetic conversions.
elsif Is_Fixed_Point_Type (Etype (Expr))
and then not Conversion_OK (N)
then
if Is_Fixed_Point_Type (T) then
Expand_Convert_Fixed_To_Fixed (N);
elsif Is_Integer_Type (T) then
Expand_Convert_Fixed_To_Integer (N);
else
pragma Assert (Is_Floating_Point_Type (T));
Expand_Convert_Fixed_To_Float (N);
end if;
-- Expansions of conversions whose result type is fixed-point. We
-- exclude conversions with Conversion_OK set, since from a semantic
-- point of view, these are just integer conversions.
elsif Is_Fixed_Point_Type (T)
and then not Conversion_OK (N)
then
if Is_Integer_Type (Etype (Expr)) then
Expand_Convert_Integer_To_Fixed (N);
else
pragma Assert (Is_Floating_Point_Type (Etype (Expr)));
Expand_Convert_Float_To_Fixed (N);
end if;
-- Expansion of float-to-integer conversions. Note that we also handle
-- float-to-fixed here for the case where Conversion_OK is set. We do
-- not have to explicitly test Conversion_OK, since if it is not set,
-- one of the above two cases would have applied.
-- We skip this expansion if the conversion node has Float_Truncate
-- set, because in that case, Gigi does the correct conversion.
elsif (Is_Integer_Type (T) or else
Is_Fixed_Point_Type (T))
and then Is_Floating_Point_Type (Etype (Expr))
and then not Float_Truncate (N)
then
-- Special case, if the expression is a typ'Truncation attribute,
-- then this attribute can be eliminated, and Float_Truncate set
-- on the conversion node.
if Nkind (Expr) = N_Attribute_Reference
and then Attribute_Name (Expr) = Name_Truncation
then
Rewrite_Substitute_Tree (Expr,
Relocate_Node (First (Expressions (Expr))));
Set_Float_Truncate (N, True);
-- Otherwise, we expand T (S) into
-- [Tnn : constant rtyp := S;
-- [if Tnn >= 0.0 then ityp^(Tnn + 0.5) else ityp^(Tnn - 0.5)]]
-- where rtyp is the base type of the floating-point source type,
-- and itype is the base type of the integer target type.
else
declare
Tnn : constant Entity_Id :=
Make_Defining_Identifier
(Loc, New_Internal_Name ('T'));
Ityp : constant Entity_Id := T;
Rtyp : constant Entity_Id := Etype (Expr);
function Truncate_Conversion (Expr : Node_Id) return Node_Id;
-- Builds a type conversion with the Float_Truncate flag set,
-- the given argument Expr as the source, and the base type'
-- as the destination subtype. The Conversion_OK flag is
-- copied from the parent cnversion node.
function Truncate_Conversion (Expr : Node_Id) return Node_Id is
Cnode : constant Node_Id :=
Make_Type_Conversion (Loc,
Subtype_Mark => New_Reference_To (Ityp, Loc),
Expression => Expr);
begin
Set_Float_Truncate (Cnode, True);
Set_Conversion_OK (Cnode, Conversion_OK (N));
-- Set Etype in case Conversion_OK is set
Set_Etype (Cnode, T);
return Cnode;
end Truncate_Conversion;
begin
Rewrite_Substitute_Tree (N,
Make_Expression_Actions (Loc,
Actions => New_List (
Make_Object_Declaration (Loc,
Defining_Identifier => Tnn,
Constant_Present => True,
Object_Definition => New_Reference_To (Rtyp, Loc),
Expression => Expression (N))),
Expression =>
Make_Conditional_Expression (Loc, New_List (
Make_Op_Ge (Loc,
Left_Opnd => New_Reference_To (Tnn, Loc),
Right_Opnd => Make_Real_Literal (Loc, Ureal_0)),
Truncate_Conversion (
Make_Op_Add (Loc,
Left_Opnd => New_Reference_To (Tnn, Loc),
Right_Opnd =>
Make_Real_Literal (Loc, Ureal_Half))),
Truncate_Conversion (
Make_Op_Subtract (Loc,
Left_Opnd => New_Reference_To (Tnn, Loc),
Right_Opnd =>
Make_Real_Literal (Loc, Ureal_Half)))))));
Analyze (N);
Resolve (N, T);
end;
end if;
elsif Is_Array_Type (T) then
if Is_Constrained (T) then
Apply_Length_Check (Expr, T);
else
-- ??? this declare loop needs a name!
declare
Opnd_Index : Node_Id;
Targ_Index : Node_Id;
procedure Check_Array_Conversion
(Val : Node_Id; Bound : Node_Id; Lt : Boolean);
-- Generate an Action to check that the bounds of the
-- source value are within the constraints imposed by the
-- target type for a conversion to an unconstrained type.
-- Rule is 4.6(38).
-- if Lt is True the condition that will raise Constraint_Error
-- is Val < Bound otherwise it is Val > Bound
procedure Check_Array_Conversion
(Val : Node_Id; Bound : Node_Id; Lt : Boolean)
is
Cond : Node_Id;
begin
if Lt then
Cond :=
Make_Op_Lt (Loc,
Left_Opnd =>
Convert_To (Etype (Targ_Index),
Duplicate_Subexpr (Val)),
Right_Opnd => Duplicate_Subexpr (Bound));
else
Cond :=
Make_Op_Gt (Loc,
Left_Opnd =>
Convert_To (Etype (Targ_Index),
Duplicate_Subexpr (Val)),
Right_Opnd => Duplicate_Subexpr (Bound));
end if;
Insert_Action (N,
Make_If_Statement (Loc,
Condition => Cond,
Then_Statements => New_List (
Make_Raise_Statement (Loc,
Name =>
New_Reference_To
(Standard_Constraint_Error, Loc)))));
end Check_Array_Conversion;
-- Start of processing for ???
begin
Opnd_Index := First_Index (Etype (Expr));
Targ_Index := First_Index (T);
while Opnd_Index /= Empty loop
if Nkind (Opnd_Index) = N_Range then
if Is_In_Range
(Low_Bound (Opnd_Index), Etype (Targ_Index))
then
null;
elsif Is_Out_Of_Range
(Low_Bound (Opnd_Index), Etype (Targ_Index))
then
Compile_Time_Constraint_Error
(Expr, "value out of range?");
else
Check_Array_Conversion (
Low_Bound (Opnd_Index),
Type_Low_Bound (Etype (Targ_Index)),
Lt => True);
end if;
if Is_In_Range
(High_Bound (Opnd_Index), Etype (Targ_Index))
then
null;
elsif Is_Out_Of_Range
(High_Bound (Opnd_Index), Etype (Targ_Index))
then
Compile_Time_Constraint_Error
(Expr, "value out of range?");
else
Check_Array_Conversion (
High_Bound (Opnd_Index),
Type_High_Bound (Etype (Targ_Index)),
Lt => False);
end if;
end if;
Opnd_Index := Next_Index (Opnd_Index);
Targ_Index := Next_Index (Targ_Index);
end loop;
end;
end if;
end if;
end Expand_N_Type_Conversion;
----------------------------
-- Expand_Record_Equality --
----------------------------
-- For non-variant records, Equality is expanded when needed into:
-- and then Lhs.Discr1 = Rhs.Discr1
-- and then ...
-- and then Lhs.Discrn = Rhs.Discrn
-- and then Lhs.Cmp1 = Rhs.Cmp1
-- and then ...
-- and then Lhs.Cmpn = Rhs.Cmpn
-- The expression is folded by the back-end for adjacent fields. This
-- function is called for tagged record in only one occasion: for imple-
-- menting predefined primitive equality (see Predefined_Primitives_Bodies)
-- otherwise the primitive "=" is used directly.
function Expand_Record_Equality
(Loc : Source_Ptr;
Typ : Entity_Id;
Lhs : Node_Id;
Rhs : Node_Id)
return Node_Id
is
function Suitable_Element (C : Entity_Id) return Entity_Id;
-- return the first field to compare beginning with C, skipping the
-- inherited components
function Suitable_Element (C : Entity_Id) return Entity_Id is
begin
if No (C) then
return Empty;
elsif (Ekind (C) /= E_Discriminant and then Ekind (C) /= E_Component)
or else (Is_Tagged_Type (Typ)
and then C /= Original_Record_Component (C))
then
return Suitable_Element (Next_Entity (C));
else
return C;
end if;
end Suitable_Element;
Result : Node_Id;
C : Entity_Id;
-- Start of processing for Expand_Record_Equality
begin
-- Generates the following code: (assuming that Typ has one Discr and
-- component C2 is also a record)
-- True
-- and then Lhs.Discr1 = Rhs.Discr1
-- and then Lhs.C1 = Rhs.C1
-- and then Lhs.C2.C1=Rhs.C2.C1 and then ... Lhs.C2.Cn=Rhs.C2.Cn
-- and then ...
-- and then Lhs.Cmpn = Rhs.Cmpn
Result := New_Reference_To (Standard_True, Loc);
C := Suitable_Element (First_Entity (Typ));
while Present (C) loop
Result :=
Make_And_Then (Loc,
Left_Opnd => Result,
Right_Opnd =>
Expand_Composite_Equality (Loc, Etype (C),
Lhs => Make_Selected_Component (Loc,
Prefix => Lhs,
Selector_Name => New_Reference_To (C, Loc)),
Rhs => Make_Selected_Component (Loc,
Prefix => Rhs,
Selector_Name => New_Reference_To (C, Loc))));
C := Suitable_Element (Next_Entity (C));
end loop;
return Result;
end Expand_Record_Equality;
---------------------------------
-- Expand_N_Selected_Component --
---------------------------------
-- If the selector is a discriminant of a concurrent object, rewrite the
-- prefix to denote the corresponding record type.
procedure Expand_N_Selected_Component (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
P : Node_Id := Prefix (N);
Ptyp : Entity_Id := Etype (P);
Sel : Name_Id;
New_N : Node_Id;
begin
if Is_Protected_Type (Ptyp) then
Sel := Name_uObject;
elsif Is_Task_Type (Ptyp) then
Sel := Name_uTask_Id;
else
return;
end if;
if Ekind (Entity (Selector_Name (N))) = E_Discriminant then
New_N :=
Make_Selected_Component (Loc,
Prefix =>
Make_Unchecked_Type_Conversion (Loc,
Subtype_Mark =>
New_Reference_To (Corresponding_Record_Type (Ptyp), Loc),
Expression => New_Copy_Tree (P)),
Selector_Name =>
Make_Identifier (Loc, Chars (Selector_Name (N))));
Rewrite_Substitute_Tree (N, New_N);
Analyze (N);
end if;
end Expand_N_Selected_Component;
------------------------------
-- Expand_Zero_Divide_Check --
------------------------------
-- This routine is called only if a software zero divide check is needed,
-- i.e. if the operation is a signed integer divide (or mod/rem) operation
-- and software overflow checking is enabled, and Do_Overflow_Check is
-- True. Given an expression a op b, the following check is inserted into
-- the tree:
-- if b = 0 then
-- raise Constraint_Error;
-- end if;
-- The check is required if software overflow checking is enabled, the
-- operation is for an integer type, and Do_Overflow_Check is True
procedure Expand_Zero_Divide_Check (N : Node_Id) is
Opnd : constant Node_Id := Right_Opnd (N);
Loc : constant Source_Ptr := Sloc (Opnd);
begin
Insert_Action (N,
Make_If_Statement (Loc,
Condition =>
Make_Op_Eq (Loc,
Left_Opnd => Duplicate_Subexpr (Opnd),
Right_Opnd => Make_Integer_Literal (Loc, Uint_0)),
Then_Statements => New_List (
Make_Raise_Statement (Loc,
Name =>
New_Reference_To (
Standard_Constraint_Error, Loc)))));
end Expand_Zero_Divide_Check;
------------------------------
-- Make_Array_Comparison_Op --
------------------------------
-- This is a hand-coded expansion of the following generic function:
-- generic
-- type elem is (<>);
-- type index is (<>);
-- type a is array (index range <>) of elem;
--
-- function Gnnn (X : a; Y: a) return boolean is
-- J : index := Y'first;
--
-- begin
-- if X'length = 0 then
-- return false;
--
-- elsif Y'length = 0 then
-- return true;
--
-- else
-- for I in X'range loop
-- if X (I) = Y (J) then
-- if J = Y'last then
-- exit;
-- else
-- J := index'succ (J);
-- end if;
--
-- else
-- return X (I) > Y (J);
-- end if;
-- end loop;
--
-- return X'length > Y'length;
-- end if;
-- end Gnnn;
-- If the flag Equal is true, the procedure generates the body for
-- >= instead. This only affects the last return statement.
-- Note that since we are essentially doing this expansion by hand, we
-- do not need to generate an actual or formal generic part, just the
-- instantiated function itself.
function Make_Array_Comparison_Op
(Typ : Entity_Id;
Loc : Source_Ptr;
Equal : Boolean)
return Node_Id
is
X : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uX);
Y : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uY);
I : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uI);
J : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uJ);
Index : constant Entity_Id := Base_Type (Etype (First_Index (Typ)));
Loop_Statement : Node_Id;
Loop_Body : Node_Id;
If_Stat : Node_Id;
Inner_If : Node_Id;
Final_Expr : Node_Id;
Func_Body : Node_Id;
Func_Name : Entity_Id;
Formals : List_Id;
Length1 : Node_Id;
Length2 : Node_Id;
begin
-- if J = Y'last then
-- exit;
-- else
-- J := index'succ (J);
-- end if;
Inner_If :=
Make_If_Statement (Loc,
Condition =>
Make_Op_Eq (Loc,
Left_Opnd => New_Reference_To (J, Loc),
Right_Opnd =>
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (Y, Loc),
Attribute_Name => Name_Last)),
Then_Statements => New_List (
Make_Exit_Statement (Loc)),
Else_Statements =>
New_List (
Make_Assignment_Statement (Loc,
Name => New_Reference_To (J, Loc),
Expression =>
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (Index, Loc),
Attribute_Name => Name_Succ,
Expressions => New_List (New_Reference_To (J, Loc))))));
-- if X (I) = Y (J) then
-- if ... end if;
-- else
-- return X (I) > Y (J);
-- end if;
Loop_Body :=
Make_If_Statement (Loc,
Condition =>
Make_Op_Eq (Loc,
Left_Opnd =>
Make_Indexed_Component (Loc,
Prefix => New_Reference_To (X, Loc),
Expressions => New_List (New_Reference_To (I, Loc))),
Right_Opnd =>
Make_Indexed_Component (Loc,
Prefix => New_Reference_To (Y, Loc),
Expressions => New_List (New_Reference_To (J, Loc)))),
Then_Statements => New_List (Inner_If),
Else_Statements => New_List (
Make_Return_Statement (Loc,
Expression =>
Make_Op_Gt (Loc,
Left_Opnd =>
Make_Indexed_Component (Loc,
Prefix => New_Reference_To (X, Loc),
Expressions => New_List (New_Reference_To (I, Loc))),
Right_Opnd =>
Make_Indexed_Component (Loc,
Prefix => New_Reference_To (Y, Loc),
Expressions => New_List (
New_Reference_To (J, Loc)))))));
-- for I in X'range loop
-- if ... end if;
-- end loop;
Loop_Statement :=
Make_Loop_Statement (Loc,
Identifier => Empty,
Iteration_Scheme =>
Make_Iteration_Scheme (Loc,
Loop_Parameter_Specification =>
Make_Loop_Parameter_Specification (Loc,
Defining_Identifier => I,
Discrete_Subtype_Definition =>
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (X, Loc),
Attribute_Name => Name_Range))),
Statements => New_List (Loop_Body));
-- if X'length = 0 then
-- return false;
-- elsif Y'length = 0 then
-- return true;
-- else
-- for ... loop ... end loop;
-- return X'length > Y'length;
-- -- return X'length >= Y'length to implement >=.
-- end if;
Length1 :=
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (X, Loc),
Attribute_Name => Name_Length);
Length2 :=
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (Y, Loc),
Attribute_Name => Name_Length);
if Equal then
Final_Expr :=
Make_Op_Ge (Loc,
Left_Opnd => Length1,
Right_Opnd => Length2);
else
Final_Expr :=
Make_Op_Gt (Loc,
Left_Opnd => Length1,
Right_Opnd => Length2);
end if;
If_Stat :=
Make_If_Statement (Loc,
Condition =>
Make_Op_Eq (Loc,
Left_Opnd =>
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (X, Loc),
Attribute_Name => Name_Length),
Right_Opnd =>
Make_Integer_Literal (Loc, Uint_0)),
Then_Statements =>
New_List (
Make_Return_Statement (Loc,
Expression => New_Reference_To (Standard_False, Loc))),
Elsif_Parts => New_List (
Make_Elsif_Part (Loc,
Condition =>
Make_Op_Eq (Loc,
Left_Opnd =>
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (Y, Loc),
Attribute_Name => Name_Length),
Right_Opnd =>
Make_Integer_Literal (Loc, Uint_0)),
Then_Statements =>
New_List (
Make_Return_Statement (Loc,
Expression => New_Reference_To (Standard_True, Loc))))),
Else_Statements => New_List (
Loop_Statement,
Make_Return_Statement (Loc,
Expression => Final_Expr)));
-- (X : a; Y: a)
Formals := New_List (
Make_Parameter_Specification (Loc,
Defining_Identifier => X,
Parameter_Type => New_Reference_To (Typ, Loc)),
Make_Parameter_Specification (Loc,
Defining_Identifier => Y,
Parameter_Type => New_Reference_To (Typ, Loc)));
-- function Gnnn (...) return boolean is
-- J : index := Y'first;
-- begin
-- if ... end if;
-- end Gnnn;
Func_Name := Make_Defining_Identifier (Loc, New_Internal_Name ('G'));
Func_Body :=
Make_Subprogram_Body (Loc,
Specification =>
Make_Function_Specification (Loc,
Defining_Unit_Name => Func_Name,
Parameter_Specifications => Formals,
Subtype_Mark => New_Reference_To (Standard_Boolean, Loc)),
Declarations => New_List (
Make_Object_Declaration (Loc,
Defining_Identifier => J,
Object_Definition => New_Reference_To (Index, Loc),
Expression =>
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (Y, Loc),
Attribute_Name => Name_First))),
Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Loc,
Statements => New_List (If_Stat)));
return Func_Body;
end Make_Array_Comparison_Op;
---------------------------
-- Make_Boolean_Array_Op --
---------------------------
-- For logical operations on boolean arrays, expand in line the
-- following, replacing 'and' with 'or' or 'xor' where needed:
-- function Annn (A : typ; B: typ) return typ is
-- C : typ;
-- begin
-- for J in A'range loop
-- C (J) := A (J) op B (J);
-- end loop;
-- return C;
-- end Annn;
-- Here typ is the array type (either an an array of boolean in the normal
-- case, or an array of unsigned in the packed case).
function Make_Boolean_Array_Op
(Typ : Entity_Id;
N : Node_Id)
return Node_Id
is
Loc : constant Source_Ptr := Sloc (N);
A : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uA);
B : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uB);
C : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uC);
J : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uJ);
A_J : Node_Id;
B_J : Node_Id;
C_J : Node_Id;
Op : Node_Id;
Formals : List_Id;
Func_Name : Entity_Id;
Func_Body : Node_Id;
Loop_Statement : Node_Id;
begin
A_J :=
Make_Indexed_Component (Loc,
Prefix => New_Reference_To (A, Loc),
Expressions => New_List (New_Reference_To (J, Loc)));
B_J :=
Make_Indexed_Component (Loc,
Prefix => New_Reference_To (B, Loc),
Expressions => New_List (New_Reference_To (J, Loc)));
C_J :=
Make_Indexed_Component (Loc,
Prefix => New_Reference_To (C, Loc),
Expressions => New_List (New_Reference_To (J, Loc)));
if Nkind (N) = N_Op_And then
Op :=
Make_Op_And (Loc,
Left_Opnd => A_J,
Right_Opnd => B_J);
elsif Nkind (N) = N_Op_Or then
Op :=
Make_Op_Or (Loc,
Left_Opnd => A_J,
Right_Opnd => B_J);
else
Op :=
Make_Op_Xor (Loc,
Left_Opnd => A_J,
Right_Opnd => B_J);
end if;
Loop_Statement :=
Make_Loop_Statement (Loc,
Identifier => Empty,
Iteration_Scheme =>
Make_Iteration_Scheme (Loc,
Loop_Parameter_Specification =>
Make_Loop_Parameter_Specification (Loc,
Defining_Identifier => J,
Discrete_Subtype_Definition =>
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (A, Loc),
Attribute_Name => Name_Range))),
Statements => New_List (
Make_Assignment_Statement (Loc,
Name => C_J,
Expression => Op)));
Formals := New_List (
Make_Parameter_Specification (Loc,
Defining_Identifier => A,
Parameter_Type => New_Reference_To (Typ, Loc)),
Make_Parameter_Specification (Loc,
Defining_Identifier => B,
Parameter_Type => New_Reference_To (Typ, Loc)));
Func_Name :=
Make_Defining_Identifier (Loc, New_Internal_Name ('A'));
Func_Body :=
Make_Subprogram_Body (Loc,
Specification =>
Make_Function_Specification (Loc,
Defining_Unit_Name => Func_Name,
Parameter_Specifications => Formals,
Subtype_Mark => New_Reference_To (Typ, Loc)),
Declarations => New_List (
Make_Object_Declaration (Loc,
Defining_Identifier => C,
Object_Definition => New_Reference_To (Typ, Loc))),
Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Loc,
Statements => New_List (
Loop_Statement,
Make_Return_Statement (Loc,
Expression => New_Reference_To (C, Loc)))));
return Func_Body;
end Make_Boolean_Array_Op;
------------------------
-- Tagged_Membership --
------------------------
-- There are two different cases to consider depending on whether
-- the right operand is a class-wide type or not. If not we just
-- compare the actual tag of the left expr to the target type tag:
--
-- Left_Expr.Tag = Right_Type'Tag;
--
-- If it is a class-wide type we use the RT function CW_Membership which
-- is usually implemented by looking in the ancestor tables contained in
-- the dispatch table pointed by Left_Expr.Tag for Typ'Tag
function Tagged_Membership (N : Node_Id) return Node_Id is
Left : constant Node_Id := Left_Opnd (N);
Right : constant Node_Id := Right_Opnd (N);
Loc : constant Source_Ptr := Sloc (N);
Left_Type : Entity_Id;
Right_Type : Entity_Id;
Obj_Tag : Node_Id;
begin
Left_Type := Etype (Left);
Right_Type := Etype (Right);
if Is_Class_Wide_Type (Left_Type) then
Left_Type := Root_Type (Left_Type);
end if;
Obj_Tag :=
Make_Selected_Component (Loc,
Prefix => Relocate_Node (Left),
Selector_Name => New_Reference_To (Tag_Component (Left_Type), Loc));
if Is_Class_Wide_Type (Right_Type) then
return
Make_DT_Access_Action (Left_Type,
Action => CW_Membership,
Args => New_List (
Obj_Tag,
New_Reference_To (
Access_Disp_Table (Root_Type (Right_Type)), Loc)));
else
return
Make_Op_Eq (Loc,
Left_Opnd => Obj_Tag,
Right_Opnd =>
New_Reference_To (Access_Disp_Table (Right_Type), Loc));
end if;
end Tagged_Membership;
end Exp_Ch4;