aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/exp_ch8.adb
blob: e59b17fdff5c11a21771d275bd984d5ee24e2fd4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                              E X P _ C H 8                               --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--                            $Revision$
--                                                                          --
--          Copyright (C) 1992-2001 Free Software Foundation, Inc.          --
--                                                                          --
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 2,  or (at your option) any later ver- --
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
-- for  more details.  You should have  received  a copy of the GNU General --
-- Public License  distributed with GNAT;  see file COPYING.  If not, write --
-- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
-- MA 02111-1307, USA.                                                      --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
--                                                                          --
------------------------------------------------------------------------------

with Atree;    use Atree;
with Einfo;    use Einfo;
with Exp_Dbug; use Exp_Dbug;
with Exp_Util; use Exp_Util;
with Nlists;   use Nlists;
with Sem;      use Sem;
with Sem_Ch8;  use Sem_Ch8;
with Sinfo;    use Sinfo;
with Stand;    use Stand;

package body Exp_Ch8 is

   ---------------------------------------------
   -- Expand_N_Exception_Renaming_Declaration --
   ---------------------------------------------

   procedure Expand_N_Exception_Renaming_Declaration (N : Node_Id) is
      Decl : constant Node_Id := Debug_Renaming_Declaration (N);

   begin
      if Present (Decl) then
         Insert_Action (N, Decl);
      end if;
   end Expand_N_Exception_Renaming_Declaration;

   ------------------------------------------
   -- Expand_N_Object_Renaming_Declaration --
   ------------------------------------------

   --  Most object renaming cases can be done by just capturing the address
   --  of the renamed object. The cases in which this is not true are when
   --  this address is not computable, since it involves extraction of a
   --  packed array element, or of a record component to which a component
   --  clause applies (that can specify an arbitrary bit boundary).

   --  In these two cases, we pre-evaluate the renaming expression, by
   --  extracting and freezing the values of any subscripts, and then we
   --  set the flag Is_Renaming_Of_Object which means that any reference
   --  to the object will be handled by macro substitution in the front
   --  end, and the back end will know to ignore the renaming declaration.

   --  An additional odd case that requires processing by expansion is
   --  the renaming of a discriminant of a mutable record type. The object
   --  is a constant because it renames something that cannot be assigned to,
   --  but in fact the underlying value can change and must be reevaluated
   --  at each reference. Gigi does have a notion of a "constant view" of
   --  an object, and therefore the front-end must perform the expansion.
   --  For simplicity, and to bypass some obscure code-generation problem,
   --  we use macro substitution for all renamed discriminants, whether the
   --  enclosing type is constrained or not.

   --  The other special processing required is for the case of renaming
   --  of an object of a class wide type, where it is necessary to build
   --  the appropriate subtype for the renamed object.
   --  More comments needed for this para ???

   procedure Expand_N_Object_Renaming_Declaration (N : Node_Id) is
      Nam  : Node_Id := Name (N);
      T    : Entity_Id;
      Decl : Node_Id;

      procedure Evaluate_Name (Fname : Node_Id);
      --  A recursive procedure used to freeze a name in the sense described
      --  above, i.e. any variable references or function calls are removed.
      --  Of course the outer level variable reference must not be removed.
      --  For example in A(J,F(K)), A is left as is, but J and F(K) are
      --  evaluated and removed.

      function Evaluation_Required (Nam : Node_Id) return Boolean;
      --  Determines whether it is necessary to do static name evaluation
      --  for renaming of Nam. It is considered necessary if evaluating the
      --  name involves indexing a packed array, or extracting a component
      --  of a record to which a component clause applies. Note that we are
      --  only interested in these operations if they occur as part of the
      --  name itself, subscripts are just values that are computed as part
      --  of the evaluation, so their form is unimportant.

      -------------------
      -- Evaluate_Name --
      -------------------

      procedure Evaluate_Name (Fname : Node_Id) is
         K : constant Node_Kind := Nkind (Fname);
         E : Node_Id;

      begin
         --  For an explicit dereference, we simply force the evaluation
         --  of the name expression. The dereference provides a value that
         --  is the address for the renamed object, and it is precisely
         --  this value that we want to preserve.

         if K = N_Explicit_Dereference then
            Force_Evaluation (Prefix (Fname));

         --  For a selected component, we simply evaluate the prefix

         elsif K = N_Selected_Component then
            Evaluate_Name (Prefix (Fname));

         --  For an indexed component, or an attribute reference, we evaluate
         --  the prefix, which is itself a name, recursively, and then force
         --  the evaluation of all the subscripts (or attribute expressions).

         elsif K = N_Indexed_Component
           or else K = N_Attribute_Reference
         then
            Evaluate_Name (Prefix (Fname));

            E := First (Expressions (Fname));
            while Present (E) loop
               Force_Evaluation (E);

               if Original_Node (E) /= E then
                  Set_Do_Range_Check (E, Do_Range_Check (Original_Node (E)));
               end if;

               Next (E);
            end loop;

         --  For a slice, we evaluate the prefix, as for the indexed component
         --  case and then, if there is a range present, either directly or
         --  as the constraint of a discrete subtype indication, we evaluate
         --  the two bounds of this range.

         elsif K = N_Slice then
            Evaluate_Name (Prefix (Fname));

            declare
               DR     : constant Node_Id := Discrete_Range (Fname);
               Constr : Node_Id;
               Rexpr  : Node_Id;

            begin
               if Nkind (DR) = N_Range then
                  Force_Evaluation (Low_Bound (DR));
                  Force_Evaluation (High_Bound (DR));

               elsif Nkind (DR) = N_Subtype_Indication then
                  Constr := Constraint (DR);

                  if Nkind (Constr) = N_Range_Constraint then
                     Rexpr := Range_Expression (Constr);

                     Force_Evaluation (Low_Bound (Rexpr));
                     Force_Evaluation (High_Bound (Rexpr));
                  end if;
               end if;
            end;

         --  For a type conversion, the expression of the conversion must be
         --  the name of an object, and we simply need to evaluate this name.

         elsif K = N_Type_Conversion then
            Evaluate_Name (Expression (Fname));

         --  For a function call, we evaluate the call.

         elsif K = N_Function_Call then
            Force_Evaluation (Fname);

         --  The remaining cases are direct name, operator symbol and
         --  character literal. In all these cases, we do nothing, since
         --  we want to reevaluate each time the renamed object is used.

         else
            return;
         end if;
      end Evaluate_Name;

      -------------------------
      -- Evaluation_Required --
      -------------------------

      function Evaluation_Required (Nam : Node_Id) return Boolean is
      begin
         if Nkind (Nam) = N_Indexed_Component
           or else Nkind (Nam) = N_Slice
         then
            if Is_Packed (Etype (Prefix (Nam))) then
               return True;
            else
               return Evaluation_Required (Prefix (Nam));
            end if;

         elsif Nkind (Nam) = N_Selected_Component then
            if Present (Component_Clause (Entity (Selector_Name (Nam)))) then
               return True;

            elsif Ekind (Entity (Selector_Name (Nam))) = E_Discriminant
              and then Is_Record_Type (Etype (Prefix (Nam)))
              and then not Is_Concurrent_Record_Type (Etype (Prefix (Nam)))
            then
               return True;

            else
               return Evaluation_Required (Prefix (Nam));
            end if;

         else
            return False;
         end if;
      end Evaluation_Required;

   --  Start of processing for Expand_N_Object_Renaming_Declaration

   begin
      --  Perform name evaluation if required

      if Evaluation_Required (Nam) then
         Evaluate_Name (Nam);
         Set_Is_Renaming_Of_Object (Defining_Identifier (N));
      end if;

      --  Deal with construction of subtype in class-wide case

      T := Etype (Defining_Identifier (N));

      if Is_Class_Wide_Type (T) then
         Expand_Subtype_From_Expr (N, T, Subtype_Mark (N), Name (N));
         Find_Type (Subtype_Mark (N));
         Set_Etype (Defining_Identifier (N), Entity (Subtype_Mark (N)));
      end if;

      --  Create renaming entry for debug information

      Decl := Debug_Renaming_Declaration (N);

      if Present (Decl) then
         Insert_Action (N, Decl);
      end if;
   end Expand_N_Object_Renaming_Declaration;

   -------------------------------------------
   -- Expand_N_Package_Renaming_Declaration --
   -------------------------------------------

   procedure Expand_N_Package_Renaming_Declaration (N : Node_Id) is
      Decl : constant Node_Id := Debug_Renaming_Declaration (N);

   begin
      if Present (Decl) then

         --  If we are in a compilation unit, then this is an outer
         --  level declaration, and must have a scope of Standard

         if Nkind (Parent (N)) = N_Compilation_Unit then
            declare
               Aux : constant Node_Id := Aux_Decls_Node (Parent (N));

            begin
               New_Scope (Standard_Standard);

               if No (Actions (Aux)) then
                  Set_Actions (Aux, New_List (Decl));
               else
                  Append (Decl, Actions (Aux));
               end if;

               Analyze (Decl);
               Pop_Scope;
            end;

         --  Otherwise, just insert after the package declaration

         else
            Insert_Action (N, Decl);
         end if;
      end if;
   end Expand_N_Package_Renaming_Declaration;

end Exp_Ch8;