einfo.ads, einfo.adb (Is_Local_Anonymous_Access): New flag on anonymous access types...
[gcc.git] / gcc / ada / exp_ch9.adb
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- E X P _ C H 9 --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2005 Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
21 -- --
22 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 -- --
25 ------------------------------------------------------------------------------
26
27 with Atree; use Atree;
28 with Checks; use Checks;
29 with Einfo; use Einfo;
30 with Elists; use Elists;
31 with Errout; use Errout;
32 with Exp_Ch3; use Exp_Ch3;
33 with Exp_Ch11; use Exp_Ch11;
34 with Exp_Ch6; use Exp_Ch6;
35 with Exp_Dbug; use Exp_Dbug;
36 with Exp_Smem; use Exp_Smem;
37 with Exp_Tss; use Exp_Tss;
38 with Exp_Util; use Exp_Util;
39 with Freeze; use Freeze;
40 with Hostparm;
41 with Namet; use Namet;
42 with Nlists; use Nlists;
43 with Nmake; use Nmake;
44 with Opt; use Opt;
45 with Restrict; use Restrict;
46 with Rident; use Rident;
47 with Rtsfind; use Rtsfind;
48 with Sem; use Sem;
49 with Sem_Ch6; use Sem_Ch6;
50 with Sem_Ch8; use Sem_Ch8;
51 with Sem_Ch11; use Sem_Ch11;
52 with Sem_Elab; use Sem_Elab;
53 with Sem_Res; use Sem_Res;
54 with Sem_Util; use Sem_Util;
55 with Sinfo; use Sinfo;
56 with Snames; use Snames;
57 with Stand; use Stand;
58 with Targparm; use Targparm;
59 with Tbuild; use Tbuild;
60 with Types; use Types;
61 with Uintp; use Uintp;
62
63 package body Exp_Ch9 is
64
65 -----------------------
66 -- Local Subprograms --
67 -----------------------
68
69 function Actual_Index_Expression
70 (Sloc : Source_Ptr;
71 Ent : Entity_Id;
72 Index : Node_Id;
73 Tsk : Entity_Id) return Node_Id;
74 -- Compute the index position for an entry call. Tsk is the target
75 -- task. If the bounds of some entry family depend on discriminants,
76 -- the expression computed by this function uses the discriminants
77 -- of the target task.
78
79 function Index_Constant_Declaration
80 (N : Node_Id;
81 Index_Id : Entity_Id;
82 Prot : Entity_Id) return List_Id;
83 -- For an entry family and its barrier function, we define a local entity
84 -- that maps the index in the call into the entry index into the object:
85 --
86 -- I : constant Index_Type := Index_Type'Val (
87 -- E - <<index of first family member>> +
88 -- Protected_Entry_Index (Index_Type'Pos (Index_Type'First)));
89
90 procedure Add_Object_Pointer
91 (Decls : List_Id;
92 Pid : Entity_Id;
93 Loc : Source_Ptr);
94 -- Prepend an object pointer declaration to the declaration list
95 -- Decls. This object pointer is initialized to a type conversion
96 -- of the System.Address pointer passed to entry barrier functions
97 -- and entry body procedures.
98
99 function Build_Accept_Body (Astat : Node_Id) return Node_Id;
100 -- Transform accept statement into a block with added exception handler.
101 -- Used both for simple accept statements and for accept alternatives in
102 -- select statements. Astat is the accept statement.
103
104 function Build_Barrier_Function
105 (N : Node_Id;
106 Ent : Entity_Id;
107 Pid : Node_Id) return Node_Id;
108 -- Build the function body returning the value of the barrier expression
109 -- for the specified entry body.
110
111 function Build_Barrier_Function_Specification
112 (Def_Id : Entity_Id;
113 Loc : Source_Ptr) return Node_Id;
114 -- Build a specification for a function implementing
115 -- the protected entry barrier of the specified entry body.
116
117 function Build_Corresponding_Record
118 (N : Node_Id;
119 Ctyp : Node_Id;
120 Loc : Source_Ptr) return Node_Id;
121 -- Common to tasks and protected types. Copy discriminant specifications,
122 -- build record declaration. N is the type declaration, Ctyp is the
123 -- concurrent entity (task type or protected type).
124
125 function Build_Entry_Count_Expression
126 (Concurrent_Type : Node_Id;
127 Component_List : List_Id;
128 Loc : Source_Ptr) return Node_Id;
129 -- Compute number of entries for concurrent object. This is a count of
130 -- simple entries, followed by an expression that computes the length
131 -- of the range of each entry family. A single array with that size is
132 -- allocated for each concurrent object of the type.
133
134 function Build_Wrapper_Body
135 (Loc : Source_Ptr;
136 Proc_Nam : Entity_Id;
137 Obj_Typ : Entity_Id;
138 Formals : List_Id) return Node_Id;
139 -- Ada 2005 (AI-345): Build the body that wraps a primitive operation
140 -- associated with a protected or task type. This is required to implement
141 -- dispatching calls through interfaces. Proc_Nam is the entry name to be
142 -- wrapped, Obj_Typ is the type of the newly added formal parameter to
143 -- handle object notation, Formals are the original entry formals that will
144 -- be explicitly replicated.
145
146 function Build_Wrapper_Spec
147 (Loc : Source_Ptr;
148 Proc_Nam : Entity_Id;
149 Obj_Typ : Entity_Id;
150 Formals : List_Id) return Node_Id;
151 -- Ada 2005 (AI-345): Build the specification of a primitive operation
152 -- associated with a protected or task type. This is required implement
153 -- dispatching calls through interfaces. Proc_Nam is the entry name to be
154 -- wrapped, Obj_Typ is the type of the newly added formal parameter to
155 -- handle object notation, Formals are the original entry formals that will
156 -- be explicitly replicated.
157
158 function Build_Find_Body_Index (Typ : Entity_Id) return Node_Id;
159 -- Build the function that translates the entry index in the call
160 -- (which depends on the size of entry families) into an index into the
161 -- Entry_Bodies_Array, to determine the body and barrier function used
162 -- in a protected entry call. A pointer to this function appears in every
163 -- protected object.
164
165 function Build_Find_Body_Index_Spec (Typ : Entity_Id) return Node_Id;
166 -- Build subprogram declaration for previous one
167
168 function Build_Protected_Entry
169 (N : Node_Id;
170 Ent : Entity_Id;
171 Pid : Node_Id) return Node_Id;
172 -- Build the procedure implementing the statement sequence of
173 -- the specified entry body.
174
175 function Build_Protected_Entry_Specification
176 (Def_Id : Entity_Id;
177 Ent_Id : Entity_Id;
178 Loc : Source_Ptr) return Node_Id;
179 -- Build a specification for a procedure implementing
180 -- the statement sequence of the specified entry body.
181 -- Add attributes associating it with the entry defining identifier
182 -- Ent_Id.
183
184 function Build_Protected_Subprogram_Body
185 (N : Node_Id;
186 Pid : Node_Id;
187 N_Op_Spec : Node_Id) return Node_Id;
188 -- This function is used to construct the protected version of a protected
189 -- subprogram. Its statement sequence first defers abort, then locks
190 -- the associated protected object, and then enters a block that contains
191 -- a call to the unprotected version of the subprogram (for details, see
192 -- Build_Unprotected_Subprogram_Body). This block statement requires
193 -- a cleanup handler that unlocks the object in all cases.
194 -- (see Exp_Ch7.Expand_Cleanup_Actions).
195
196 function Build_Protected_Spec
197 (N : Node_Id;
198 Obj_Type : Entity_Id;
199 Unprotected : Boolean := False;
200 Ident : Entity_Id) return List_Id;
201 -- Utility shared by Build_Protected_Sub_Spec and Expand_Access_Protected_
202 -- Subprogram_Type. Builds signature of protected subprogram, adding the
203 -- formal that corresponds to the object itself. For an access to protected
204 -- subprogram, there is no object type to specify, so the additional
205 -- parameter has type Address and mode In. An indirect call through such
206 -- a pointer converts the address to a reference to the actual object.
207 -- The object is a limited record and therefore a by_reference type.
208
209 function Build_Selected_Name
210 (Prefix, Selector : Name_Id;
211 Append_Char : Character := ' ') return Name_Id;
212 -- Build a name in the form of Prefix__Selector, with an optional
213 -- character appended. This is used for internal subprograms generated
214 -- for operations of protected types, including barrier functions.
215 -- For the subprograms generated for entry bodies and entry barriers,
216 -- the generated name includes a sequence number that makes names
217 -- unique in the presence of entry overloading. This is necessary
218 -- because entry body procedures and barrier functions all have the
219 -- same signature.
220
221 procedure Build_Simple_Entry_Call
222 (N : Node_Id;
223 Concval : Node_Id;
224 Ename : Node_Id;
225 Index : Node_Id);
226 -- Some comments here would be useful ???
227
228 function Build_Task_Proc_Specification (T : Entity_Id) return Node_Id;
229 -- This routine constructs a specification for the procedure that we will
230 -- build for the task body for task type T. The spec has the form:
231 --
232 -- procedure tnameB (_Task : access tnameV);
233 --
234 -- where name is the character name taken from the task type entity that
235 -- is passed as the argument to the procedure, and tnameV is the task
236 -- value type that is associated with the task type.
237
238 function Build_Unprotected_Subprogram_Body
239 (N : Node_Id;
240 Pid : Node_Id) return Node_Id;
241 -- This routine constructs the unprotected version of a protected
242 -- subprogram body, which is contains all of the code in the
243 -- original, unexpanded body. This is the version of the protected
244 -- subprogram that is called from all protected operations on the same
245 -- object, including the protected version of the same subprogram.
246
247 procedure Collect_Entry_Families
248 (Loc : Source_Ptr;
249 Cdecls : List_Id;
250 Current_Node : in out Node_Id;
251 Conctyp : Entity_Id);
252 -- For each entry family in a concurrent type, create an anonymous array
253 -- type of the right size, and add a component to the corresponding_record.
254
255 function Family_Offset
256 (Loc : Source_Ptr;
257 Hi : Node_Id;
258 Lo : Node_Id;
259 Ttyp : Entity_Id) return Node_Id;
260 -- Compute (Hi - Lo) for two entry family indices. Hi is the index in
261 -- an accept statement, or the upper bound in the discrete subtype of
262 -- an entry declaration. Lo is the corresponding lower bound. Ttyp is
263 -- the concurrent type of the entry.
264
265 function Family_Size
266 (Loc : Source_Ptr;
267 Hi : Node_Id;
268 Lo : Node_Id;
269 Ttyp : Entity_Id) return Node_Id;
270 -- Compute (Hi - Lo) + 1 Max 0, to determine the number of entries in
271 -- a family, and handle properly the superflat case. This is equivalent
272 -- to the use of 'Length on the index type, but must use Family_Offset
273 -- to handle properly the case of bounds that depend on discriminants.
274
275 procedure Extract_Entry
276 (N : Node_Id;
277 Concval : out Node_Id;
278 Ename : out Node_Id;
279 Index : out Node_Id);
280 -- Given an entry call, returns the associated concurrent object,
281 -- the entry name, and the entry family index.
282
283 function Find_Task_Or_Protected_Pragma
284 (T : Node_Id;
285 P : Name_Id) return Node_Id;
286 -- Searches the task or protected definition T for the first occurrence
287 -- of the pragma whose name is given by P. The caller has ensured that
288 -- the pragma is present in the task definition. A special case is that
289 -- when P is Name_uPriority, the call will also find Interrupt_Priority.
290 -- ??? Should be implemented with the rep item chain mechanism.
291
292 procedure Update_Prival_Subtypes (N : Node_Id);
293 -- The actual subtypes of the privals will differ from the type of the
294 -- private declaration in the original protected type, if the protected
295 -- type has discriminants or if the prival has constrained components.
296 -- This is because the privals are generated out of sequence w.r.t. the
297 -- analysis of a protected body. After generating the bodies for protected
298 -- operations, we set correctly the type of all references to privals, by
299 -- means of a recursive tree traversal, which is heavy-handed but
300 -- correct.
301
302 -----------------------------
303 -- Actual_Index_Expression --
304 -----------------------------
305
306 function Actual_Index_Expression
307 (Sloc : Source_Ptr;
308 Ent : Entity_Id;
309 Index : Node_Id;
310 Tsk : Entity_Id) return Node_Id
311 is
312 Ttyp : constant Entity_Id := Etype (Tsk);
313 Expr : Node_Id;
314 Num : Node_Id;
315 Lo : Node_Id;
316 Hi : Node_Id;
317 Prev : Entity_Id;
318 S : Node_Id;
319
320 function Actual_Family_Offset (Hi, Lo : Node_Id) return Node_Id;
321 -- Compute difference between bounds of entry family
322
323 --------------------------
324 -- Actual_Family_Offset --
325 --------------------------
326
327 function Actual_Family_Offset (Hi, Lo : Node_Id) return Node_Id is
328
329 function Actual_Discriminant_Ref (Bound : Node_Id) return Node_Id;
330 -- Replace a reference to a discriminant with a selected component
331 -- denoting the discriminant of the target task.
332
333 -----------------------------
334 -- Actual_Discriminant_Ref --
335 -----------------------------
336
337 function Actual_Discriminant_Ref (Bound : Node_Id) return Node_Id is
338 Typ : constant Entity_Id := Etype (Bound);
339 B : Node_Id;
340
341 begin
342 if not Is_Entity_Name (Bound)
343 or else Ekind (Entity (Bound)) /= E_Discriminant
344 then
345 if Nkind (Bound) = N_Attribute_Reference then
346 return Bound;
347 else
348 B := New_Copy_Tree (Bound);
349 end if;
350
351 else
352 B :=
353 Make_Selected_Component (Sloc,
354 Prefix => New_Copy_Tree (Tsk),
355 Selector_Name => New_Occurrence_Of (Entity (Bound), Sloc));
356
357 Analyze_And_Resolve (B, Typ);
358 end if;
359
360 return
361 Make_Attribute_Reference (Sloc,
362 Attribute_Name => Name_Pos,
363 Prefix => New_Occurrence_Of (Etype (Bound), Sloc),
364 Expressions => New_List (B));
365 end Actual_Discriminant_Ref;
366
367 -- Start of processing for Actual_Family_Offset
368
369 begin
370 return
371 Make_Op_Subtract (Sloc,
372 Left_Opnd => Actual_Discriminant_Ref (Hi),
373 Right_Opnd => Actual_Discriminant_Ref (Lo));
374 end Actual_Family_Offset;
375
376 -- Start of processing for Actual_Index_Expression
377
378 begin
379 -- The queues of entries and entry families appear in textual
380 -- order in the associated record. The entry index is computed as
381 -- the sum of the number of queues for all entries that precede the
382 -- designated one, to which is added the index expression, if this
383 -- expression denotes a member of a family.
384
385 -- The following is a place holder for the count of simple entries
386
387 Num := Make_Integer_Literal (Sloc, 1);
388
389 -- We construct an expression which is a series of addition
390 -- operations. See comments in Entry_Index_Expression, which is
391 -- identical in structure.
392
393 if Present (Index) then
394 S := Etype (Discrete_Subtype_Definition (Declaration_Node (Ent)));
395
396 Expr :=
397 Make_Op_Add (Sloc,
398 Left_Opnd => Num,
399
400 Right_Opnd =>
401 Actual_Family_Offset (
402 Make_Attribute_Reference (Sloc,
403 Attribute_Name => Name_Pos,
404 Prefix => New_Reference_To (Base_Type (S), Sloc),
405 Expressions => New_List (Relocate_Node (Index))),
406 Type_Low_Bound (S)));
407 else
408 Expr := Num;
409 end if;
410
411 -- Now add lengths of preceding entries and entry families
412
413 Prev := First_Entity (Ttyp);
414
415 while Chars (Prev) /= Chars (Ent)
416 or else (Ekind (Prev) /= Ekind (Ent))
417 or else not Sem_Ch6.Type_Conformant (Ent, Prev)
418 loop
419 if Ekind (Prev) = E_Entry then
420 Set_Intval (Num, Intval (Num) + 1);
421
422 elsif Ekind (Prev) = E_Entry_Family then
423 S :=
424 Etype (Discrete_Subtype_Definition (Declaration_Node (Prev)));
425 Lo := Type_Low_Bound (S);
426 Hi := Type_High_Bound (S);
427
428 Expr :=
429 Make_Op_Add (Sloc,
430 Left_Opnd => Expr,
431 Right_Opnd =>
432 Make_Op_Add (Sloc,
433 Left_Opnd =>
434 Actual_Family_Offset (Hi, Lo),
435 Right_Opnd =>
436 Make_Integer_Literal (Sloc, 1)));
437
438 -- Other components are anonymous types to be ignored
439
440 else
441 null;
442 end if;
443
444 Next_Entity (Prev);
445 end loop;
446
447 return Expr;
448 end Actual_Index_Expression;
449
450 ----------------------------------
451 -- Add_Discriminal_Declarations --
452 ----------------------------------
453
454 procedure Add_Discriminal_Declarations
455 (Decls : List_Id;
456 Typ : Entity_Id;
457 Name : Name_Id;
458 Loc : Source_Ptr)
459 is
460 D : Entity_Id;
461
462 begin
463 if Has_Discriminants (Typ) then
464 D := First_Discriminant (Typ);
465
466 while Present (D) loop
467
468 Prepend_To (Decls,
469 Make_Object_Renaming_Declaration (Loc,
470 Defining_Identifier => Discriminal (D),
471 Subtype_Mark => New_Reference_To (Etype (D), Loc),
472 Name =>
473 Make_Selected_Component (Loc,
474 Prefix => Make_Identifier (Loc, Name),
475 Selector_Name => Make_Identifier (Loc, Chars (D)))));
476
477 Next_Discriminant (D);
478 end loop;
479 end if;
480 end Add_Discriminal_Declarations;
481
482 ------------------------
483 -- Add_Object_Pointer --
484 ------------------------
485
486 procedure Add_Object_Pointer
487 (Decls : List_Id;
488 Pid : Entity_Id;
489 Loc : Source_Ptr)
490 is
491 Obj_Ptr : Node_Id;
492
493 begin
494 -- Prepend the declaration of _object. This must be first in the
495 -- declaration list, since it is used by the discriminal and
496 -- prival declarations.
497 -- ??? An attempt to make this a renaming was unsuccessful.
498 --
499 -- type poVP is access poV;
500 -- _object : poVP := poVP!O;
501
502 Obj_Ptr :=
503 Make_Defining_Identifier (Loc,
504 Chars =>
505 New_External_Name
506 (Chars (Corresponding_Record_Type (Pid)), 'P'));
507
508 Prepend_To (Decls,
509 Make_Object_Declaration (Loc,
510 Defining_Identifier =>
511 Make_Defining_Identifier (Loc, Name_uObject),
512 Object_Definition => New_Reference_To (Obj_Ptr, Loc),
513 Expression =>
514 Unchecked_Convert_To (Obj_Ptr,
515 Make_Identifier (Loc, Name_uO))));
516
517 Prepend_To (Decls,
518 Make_Full_Type_Declaration (Loc,
519 Defining_Identifier => Obj_Ptr,
520 Type_Definition => Make_Access_To_Object_Definition (Loc,
521 Subtype_Indication =>
522 New_Reference_To (Corresponding_Record_Type (Pid), Loc))));
523 end Add_Object_Pointer;
524
525 ------------------------------
526 -- Add_Private_Declarations --
527 ------------------------------
528
529 procedure Add_Private_Declarations
530 (Decls : List_Id;
531 Typ : Entity_Id;
532 Name : Name_Id;
533 Loc : Source_Ptr)
534 is
535 Def : constant Node_Id := Protected_Definition (Parent (Typ));
536 Body_Ent : constant Entity_Id := Corresponding_Body (Parent (Typ));
537 P : Node_Id;
538 Pdef : Entity_Id;
539
540 begin
541 pragma Assert (Nkind (Def) = N_Protected_Definition);
542
543 if Present (Private_Declarations (Def)) then
544 P := First (Private_Declarations (Def));
545
546 while Present (P) loop
547 if Nkind (P) = N_Component_Declaration then
548 Pdef := Defining_Identifier (P);
549 Prepend_To (Decls,
550 Make_Object_Renaming_Declaration (Loc,
551 Defining_Identifier => Prival (Pdef),
552 Subtype_Mark => New_Reference_To (Etype (Pdef), Loc),
553 Name =>
554 Make_Selected_Component (Loc,
555 Prefix => Make_Identifier (Loc, Name),
556 Selector_Name => Make_Identifier (Loc, Chars (Pdef)))));
557 end if;
558 Next (P);
559 end loop;
560 end if;
561
562 -- One more "prival" for the object itself, with the right protection
563 -- type.
564
565 declare
566 Protection_Type : RE_Id;
567 begin
568 if Has_Attach_Handler (Typ) then
569 if Restricted_Profile then
570 if Has_Entries (Typ) then
571 Protection_Type := RE_Protection_Entry;
572 else
573 Protection_Type := RE_Protection;
574 end if;
575 else
576 Protection_Type := RE_Static_Interrupt_Protection;
577 end if;
578
579 elsif Has_Interrupt_Handler (Typ) then
580 Protection_Type := RE_Dynamic_Interrupt_Protection;
581
582 elsif Has_Entries (Typ) then
583 if Abort_Allowed
584 or else Restriction_Active (No_Entry_Queue) = False
585 or else Number_Entries (Typ) > 1
586 then
587 Protection_Type := RE_Protection_Entries;
588 else
589 Protection_Type := RE_Protection_Entry;
590 end if;
591
592 else
593 Protection_Type := RE_Protection;
594 end if;
595
596 Prepend_To (Decls,
597 Make_Object_Renaming_Declaration (Loc,
598 Defining_Identifier => Object_Ref (Body_Ent),
599 Subtype_Mark => New_Reference_To (RTE (Protection_Type), Loc),
600 Name =>
601 Make_Selected_Component (Loc,
602 Prefix => Make_Identifier (Loc, Name),
603 Selector_Name => Make_Identifier (Loc, Name_uObject))));
604 end;
605 end Add_Private_Declarations;
606
607 -----------------------
608 -- Build_Accept_Body --
609 -----------------------
610
611 function Build_Accept_Body (Astat : Node_Id) return Node_Id is
612 Loc : constant Source_Ptr := Sloc (Astat);
613 Stats : constant Node_Id := Handled_Statement_Sequence (Astat);
614 New_S : Node_Id;
615 Hand : Node_Id;
616 Call : Node_Id;
617 Ohandle : Node_Id;
618
619 begin
620 -- At the end of the statement sequence, Complete_Rendezvous is called.
621 -- A label skipping the Complete_Rendezvous, and all other
622 -- accept processing, has already been added for the expansion
623 -- of requeue statements.
624
625 Call := Build_Runtime_Call (Loc, RE_Complete_Rendezvous);
626 Insert_Before (Last (Statements (Stats)), Call);
627 Analyze (Call);
628
629 -- If exception handlers are present, then append Complete_Rendezvous
630 -- calls to the handlers, and construct the required outer block.
631
632 if Present (Exception_Handlers (Stats)) then
633 Hand := First (Exception_Handlers (Stats));
634
635 while Present (Hand) loop
636 Call := Build_Runtime_Call (Loc, RE_Complete_Rendezvous);
637 Append (Call, Statements (Hand));
638 Analyze (Call);
639 Next (Hand);
640 end loop;
641
642 New_S :=
643 Make_Handled_Sequence_Of_Statements (Loc,
644 Statements => New_List (
645 Make_Block_Statement (Loc,
646 Handled_Statement_Sequence => Stats)));
647
648 else
649 New_S := Stats;
650 end if;
651
652 -- At this stage we know that the new statement sequence does not
653 -- have an exception handler part, so we supply one to call
654 -- Exceptional_Complete_Rendezvous. This handler is
655
656 -- when all others =>
657 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
658
659 -- We handle Abort_Signal to make sure that we properly catch the abort
660 -- case and wake up the caller.
661
662 Ohandle := Make_Others_Choice (Loc);
663 Set_All_Others (Ohandle);
664
665 Set_Exception_Handlers (New_S,
666 New_List (
667 Make_Exception_Handler (Loc,
668 Exception_Choices => New_List (Ohandle),
669
670 Statements => New_List (
671 Make_Procedure_Call_Statement (Loc,
672 Name => New_Reference_To (
673 RTE (RE_Exceptional_Complete_Rendezvous), Loc),
674 Parameter_Associations => New_List (
675 Make_Function_Call (Loc,
676 Name => New_Reference_To (
677 RTE (RE_Get_GNAT_Exception), Loc))))))));
678
679 Set_Parent (New_S, Astat); -- temp parent for Analyze call
680 Analyze_Exception_Handlers (Exception_Handlers (New_S));
681 Expand_Exception_Handlers (New_S);
682
683 -- Exceptional_Complete_Rendezvous must be called with abort
684 -- still deferred, which is the case for a "when all others" handler.
685
686 return New_S;
687 end Build_Accept_Body;
688
689 -----------------------------------
690 -- Build_Activation_Chain_Entity --
691 -----------------------------------
692
693 procedure Build_Activation_Chain_Entity (N : Node_Id) is
694 P : Node_Id;
695 B : Node_Id;
696 Decls : List_Id;
697
698 begin
699 -- Loop to find enclosing construct containing activation chain variable
700
701 P := Parent (N);
702
703 while Nkind (P) /= N_Subprogram_Body
704 and then Nkind (P) /= N_Package_Declaration
705 and then Nkind (P) /= N_Package_Body
706 and then Nkind (P) /= N_Block_Statement
707 and then Nkind (P) /= N_Task_Body
708 loop
709 P := Parent (P);
710 end loop;
711
712 -- If we are in a package body, the activation chain variable is
713 -- allocated in the corresponding spec. First, we save the package
714 -- body node because we enter the new entity in its Declarations list.
715
716 B := P;
717
718 if Nkind (P) = N_Package_Body then
719 P := Unit_Declaration_Node (Corresponding_Spec (P));
720 Decls := Declarations (B);
721
722 elsif Nkind (P) = N_Package_Declaration then
723 Decls := Visible_Declarations (Specification (B));
724
725 else
726 Decls := Declarations (B);
727 end if;
728
729 -- If activation chain entity not already declared, declare it
730
731 if No (Activation_Chain_Entity (P)) then
732 Set_Activation_Chain_Entity
733 (P, Make_Defining_Identifier (Sloc (N), Name_uChain));
734
735 Prepend_To (Decls,
736 Make_Object_Declaration (Sloc (P),
737 Defining_Identifier => Activation_Chain_Entity (P),
738 Aliased_Present => True,
739 Object_Definition =>
740 New_Reference_To (RTE (RE_Activation_Chain), Sloc (P))));
741
742 Analyze (First (Decls));
743 end if;
744 end Build_Activation_Chain_Entity;
745
746 ----------------------------
747 -- Build_Barrier_Function --
748 ----------------------------
749
750 function Build_Barrier_Function
751 (N : Node_Id;
752 Ent : Entity_Id;
753 Pid : Node_Id) return Node_Id
754 is
755 Loc : constant Source_Ptr := Sloc (N);
756 Ent_Formals : constant Node_Id := Entry_Body_Formal_Part (N);
757 Index_Spec : constant Node_Id := Entry_Index_Specification
758 (Ent_Formals);
759 Op_Decls : constant List_Id := New_List;
760 Bdef : Entity_Id;
761 Bspec : Node_Id;
762
763 begin
764 Bdef :=
765 Make_Defining_Identifier (Loc, Chars (Barrier_Function (Ent)));
766 Bspec := Build_Barrier_Function_Specification (Bdef, Loc);
767
768 -- <object pointer declaration>
769 -- <discriminant renamings>
770 -- <private object renamings>
771 -- Add discriminal and private renamings. These names have
772 -- already been used to expand references to discriminants
773 -- and private data.
774
775 Add_Discriminal_Declarations (Op_Decls, Pid, Name_uObject, Loc);
776 Add_Private_Declarations (Op_Decls, Pid, Name_uObject, Loc);
777 Add_Object_Pointer (Op_Decls, Pid, Loc);
778
779 -- If this is the barrier for an entry family, the entry index is
780 -- visible in the body of the barrier. Create a local variable that
781 -- converts the entry index (which is the last formal of the barrier
782 -- function) into the appropriate offset into the entry array. The
783 -- entry index constant must be set, as for the entry body, so that
784 -- local references to the entry index are correctly replaced with
785 -- the local variable. This parallels what is done for entry bodies.
786
787 if Present (Index_Spec) then
788 declare
789 Index_Id : constant Entity_Id := Defining_Identifier (Index_Spec);
790 Index_Con : constant Entity_Id :=
791 Make_Defining_Identifier (Loc,
792 Chars => New_Internal_Name ('J'));
793
794 begin
795 Set_Entry_Index_Constant (Index_Id, Index_Con);
796 Append_List_To (Op_Decls,
797 Index_Constant_Declaration (N, Index_Id, Pid));
798 end;
799 end if;
800
801 -- Note: the condition in the barrier function needs to be properly
802 -- processed for the C/Fortran boolean possibility, but this happens
803 -- automatically since the return statement does this normalization.
804
805 return
806 Make_Subprogram_Body (Loc,
807 Specification => Bspec,
808 Declarations => Op_Decls,
809 Handled_Statement_Sequence =>
810 Make_Handled_Sequence_Of_Statements (Loc,
811 Statements => New_List (
812 Make_Return_Statement (Loc,
813 Expression => Condition (Ent_Formals)))));
814 end Build_Barrier_Function;
815
816 ------------------------------------------
817 -- Build_Barrier_Function_Specification --
818 ------------------------------------------
819
820 function Build_Barrier_Function_Specification
821 (Def_Id : Entity_Id;
822 Loc : Source_Ptr) return Node_Id
823 is
824 begin
825 Set_Needs_Debug_Info (Def_Id);
826 return Make_Function_Specification (Loc,
827 Defining_Unit_Name => Def_Id,
828 Parameter_Specifications => New_List (
829 Make_Parameter_Specification (Loc,
830 Defining_Identifier => Make_Defining_Identifier (Loc, Name_uO),
831 Parameter_Type =>
832 New_Reference_To (RTE (RE_Address), Loc)),
833
834 Make_Parameter_Specification (Loc,
835 Defining_Identifier => Make_Defining_Identifier (Loc, Name_uE),
836 Parameter_Type =>
837 New_Reference_To (RTE (RE_Protected_Entry_Index), Loc))),
838
839 Subtype_Mark => New_Reference_To (Standard_Boolean, Loc));
840 end Build_Barrier_Function_Specification;
841
842 --------------------------
843 -- Build_Call_With_Task --
844 --------------------------
845
846 function Build_Call_With_Task
847 (N : Node_Id;
848 E : Entity_Id) return Node_Id
849 is
850 Loc : constant Source_Ptr := Sloc (N);
851
852 begin
853 return
854 Make_Function_Call (Loc,
855 Name => New_Reference_To (E, Loc),
856 Parameter_Associations => New_List (Concurrent_Ref (N)));
857 end Build_Call_With_Task;
858
859 --------------------------------
860 -- Build_Corresponding_Record --
861 --------------------------------
862
863 function Build_Corresponding_Record
864 (N : Node_Id;
865 Ctyp : Entity_Id;
866 Loc : Source_Ptr) return Node_Id
867 is
868 Rec_Ent : constant Entity_Id :=
869 Make_Defining_Identifier
870 (Loc, New_External_Name (Chars (Ctyp), 'V'));
871 Disc : Entity_Id;
872 Dlist : List_Id;
873 New_Disc : Entity_Id;
874 Cdecls : List_Id;
875
876 begin
877 Set_Corresponding_Record_Type (Ctyp, Rec_Ent);
878 Set_Ekind (Rec_Ent, E_Record_Type);
879 Set_Has_Delayed_Freeze (Rec_Ent, Has_Delayed_Freeze (Ctyp));
880 Set_Is_Concurrent_Record_Type (Rec_Ent, True);
881 Set_Corresponding_Concurrent_Type (Rec_Ent, Ctyp);
882 Set_Stored_Constraint (Rec_Ent, No_Elist);
883 Cdecls := New_List;
884
885 -- Use discriminals to create list of discriminants for record, and
886 -- create new discriminals for use in default expressions, etc. It is
887 -- worth noting that a task discriminant gives rise to 5 entities;
888
889 -- a) The original discriminant.
890 -- b) The discriminal for use in the task.
891 -- c) The discriminant of the corresponding record.
892 -- d) The discriminal for the init proc of the corresponding record.
893 -- e) The local variable that renames the discriminant in the procedure
894 -- for the task body.
895
896 -- In fact the discriminals b) are used in the renaming declarations
897 -- for e). See details in einfo (Handling of Discriminants).
898
899 if Present (Discriminant_Specifications (N)) then
900 Dlist := New_List;
901 Disc := First_Discriminant (Ctyp);
902
903 while Present (Disc) loop
904 New_Disc := CR_Discriminant (Disc);
905
906 Append_To (Dlist,
907 Make_Discriminant_Specification (Loc,
908 Defining_Identifier => New_Disc,
909 Discriminant_Type =>
910 New_Occurrence_Of (Etype (Disc), Loc),
911 Expression =>
912 New_Copy (Discriminant_Default_Value (Disc))));
913
914 Next_Discriminant (Disc);
915 end loop;
916
917 else
918 Dlist := No_List;
919 end if;
920
921 -- Now we can construct the record type declaration. Note that this
922 -- record is "limited tagged". It is "limited" to reflect the underlying
923 -- limitedness of the task or protected object that it represents, and
924 -- ensuring for example that it is properly passed by reference. It is
925 -- "tagged" to give support to dispatching calls through interfaces (Ada
926 -- 2005: AI-345)
927
928 return
929 Make_Full_Type_Declaration (Loc,
930 Defining_Identifier => Rec_Ent,
931 Discriminant_Specifications => Dlist,
932 Type_Definition =>
933 Make_Record_Definition (Loc,
934 Component_List =>
935 Make_Component_List (Loc,
936 Component_Items => Cdecls),
937 Tagged_Present => Ada_Version >= Ada_05,
938 Limited_Present => True));
939 end Build_Corresponding_Record;
940
941 ----------------------------------
942 -- Build_Entry_Count_Expression --
943 ----------------------------------
944
945 function Build_Entry_Count_Expression
946 (Concurrent_Type : Node_Id;
947 Component_List : List_Id;
948 Loc : Source_Ptr) return Node_Id
949 is
950 Eindx : Nat;
951 Ent : Entity_Id;
952 Ecount : Node_Id;
953 Comp : Node_Id;
954 Lo : Node_Id;
955 Hi : Node_Id;
956 Typ : Entity_Id;
957
958 begin
959 Ent := First_Entity (Concurrent_Type);
960 Eindx := 0;
961
962 -- Count number of non-family entries
963
964 while Present (Ent) loop
965 if Ekind (Ent) = E_Entry then
966 Eindx := Eindx + 1;
967 end if;
968
969 Next_Entity (Ent);
970 end loop;
971
972 Ecount := Make_Integer_Literal (Loc, Eindx);
973
974 -- Loop through entry families building the addition nodes
975
976 Ent := First_Entity (Concurrent_Type);
977 Comp := First (Component_List);
978
979 while Present (Ent) loop
980 if Ekind (Ent) = E_Entry_Family then
981 while Chars (Ent) /= Chars (Defining_Identifier (Comp)) loop
982 Next (Comp);
983 end loop;
984
985 Typ := Etype (Discrete_Subtype_Definition (Parent (Ent)));
986 Hi := Type_High_Bound (Typ);
987 Lo := Type_Low_Bound (Typ);
988
989 Ecount :=
990 Make_Op_Add (Loc,
991 Left_Opnd => Ecount,
992 Right_Opnd => Family_Size (Loc, Hi, Lo, Concurrent_Type));
993 end if;
994
995 Next_Entity (Ent);
996 end loop;
997
998 return Ecount;
999 end Build_Entry_Count_Expression;
1000
1001 ------------------------------
1002 -- Build_Wrapper_Body --
1003 ------------------------------
1004
1005 function Build_Wrapper_Body
1006 (Loc : Source_Ptr;
1007 Proc_Nam : Entity_Id;
1008 Obj_Typ : Entity_Id;
1009 Formals : List_Id) return Node_Id
1010 is
1011 Actuals : List_Id := No_List;
1012 Body_Spec : Node_Id;
1013 Conv_Id : Node_Id;
1014 First_Formal : Node_Id;
1015 Formal : Node_Id;
1016
1017 begin
1018 Body_Spec := Build_Wrapper_Spec (Loc, Proc_Nam, Obj_Typ, Formals);
1019
1020 -- If we did not generate the specification do have nothing else to do
1021
1022 if Body_Spec = Empty then
1023 return Empty;
1024 end if;
1025
1026 -- Map formals to actuals. Use the list built for the wrapper spec,
1027 -- skipping the object notation parameter.
1028
1029 First_Formal := First (Parameter_Specifications (Body_Spec));
1030
1031 Formal := First_Formal;
1032 Next (Formal);
1033
1034 if Present (Formal) then
1035 Actuals := New_List;
1036
1037 while Present (Formal) loop
1038 Append_To (Actuals,
1039 Make_Identifier (Loc, Chars =>
1040 Chars (Defining_Identifier (Formal))));
1041
1042 Next (Formal);
1043 end loop;
1044 end if;
1045
1046 -- An access-to-variable first parameter will require an explicit
1047 -- dereference in the unchecked conversion. This case occurs when
1048 -- a protected entry wrapper must override an interface-level
1049 -- procedure with interface access as first parameter.
1050
1051 -- SubprgName (O.all).Proc_Nam (Formal_1 .. Formal_N)
1052
1053 if Nkind (Parameter_Type (First_Formal)) = N_Access_Definition then
1054 Conv_Id :=
1055 Make_Explicit_Dereference (Loc,
1056 Prefix =>
1057 Make_Identifier (Loc, Chars => Name_uO));
1058 else
1059 Conv_Id :=
1060 Make_Identifier (Loc, Chars => Name_uO);
1061 end if;
1062
1063 if Ekind (Proc_Nam) = E_Function then
1064 return
1065 Make_Subprogram_Body (Loc,
1066 Specification => Body_Spec,
1067 Declarations => Empty_List,
1068 Handled_Statement_Sequence =>
1069 Make_Handled_Sequence_Of_Statements (Loc,
1070 Statements =>
1071 New_List (
1072 Make_Return_Statement (Loc,
1073 Make_Function_Call (Loc,
1074 Name =>
1075 Make_Selected_Component (Loc,
1076 Prefix =>
1077 Unchecked_Convert_To (
1078 Corresponding_Concurrent_Type (Obj_Typ),
1079 Conv_Id),
1080 Selector_Name =>
1081 New_Reference_To (Proc_Nam, Loc)),
1082 Parameter_Associations => Actuals)))));
1083 else
1084 return
1085 Make_Subprogram_Body (Loc,
1086 Specification => Body_Spec,
1087 Declarations => Empty_List,
1088 Handled_Statement_Sequence =>
1089 Make_Handled_Sequence_Of_Statements (Loc,
1090 Statements =>
1091 New_List (
1092 Make_Procedure_Call_Statement (Loc,
1093 Name =>
1094 Make_Selected_Component (Loc,
1095 Prefix =>
1096 Unchecked_Convert_To (
1097 Corresponding_Concurrent_Type (Obj_Typ),
1098 Conv_Id),
1099 Selector_Name =>
1100 New_Reference_To (Proc_Nam, Loc)),
1101 Parameter_Associations => Actuals))));
1102 end if;
1103 end Build_Wrapper_Body;
1104
1105 ------------------------
1106 -- Build_Wrapper_Spec --
1107 ------------------------
1108
1109 function Build_Wrapper_Spec
1110 (Loc : Source_Ptr;
1111 Proc_Nam : Entity_Id;
1112 Obj_Typ : Entity_Id;
1113 Formals : List_Id) return Node_Id
1114 is
1115 New_Name_Id : constant Entity_Id :=
1116 Make_Defining_Identifier (Loc, Chars (Proc_Nam));
1117
1118 First_Param : Node_Id := Empty;
1119 Iface : Entity_Id;
1120 Iface_Elmt : Elmt_Id := No_Elmt;
1121 New_Formals : List_Id;
1122 Obj_Param : Node_Id;
1123 Obj_Param_Typ : Node_Id;
1124 Iface_Prim_Op : Entity_Id;
1125 Iface_Prim_Op_Elmt : Elmt_Id;
1126
1127 function Overriding_Possible
1128 (Iface_Prim_Op : Entity_Id;
1129 Proc_Nam : Entity_Id) return Boolean;
1130 -- Determine whether a primitive operation can be overriden by the
1131 -- wrapper. Iface_Prim_Op is the candidate primitive operation of an
1132 -- abstract interface type, Proc_Nam is the generated entry wrapper.
1133
1134 function Replicate_Entry_Formals
1135 (Loc : Source_Ptr;
1136 Formals : List_Id) return List_Id;
1137 -- An explicit parameter replication is required due to the
1138 -- Is_Entry_Formal flag being set for all the formals. The explicit
1139 -- replication removes the flag that would otherwise cause a different
1140 -- path of analysis.
1141
1142 -------------------------
1143 -- Overriding_Possible --
1144 -------------------------
1145
1146 function Overriding_Possible
1147 (Iface_Prim_Op : Entity_Id;
1148 Proc_Nam : Entity_Id) return Boolean
1149 is
1150 Prim_Op_Spec : constant Node_Id := Parent (Iface_Prim_Op);
1151 Proc_Spec : constant Node_Id := Parent (Proc_Nam);
1152
1153 Is_Access_To_Variable : Boolean;
1154 Is_Out_Present : Boolean;
1155
1156 function Type_Conformant_Parameters
1157 (Prim_Op_Param_Specs : List_Id;
1158 Proc_Param_Specs : List_Id) return Boolean;
1159 -- Determine whether the parameters of the generated entry wrapper
1160 -- and those of a primitive operation are type conformant. During
1161 -- this check, the first parameter of the primitive operation is
1162 -- always skipped.
1163
1164 --------------------------------
1165 -- Type_Conformant_Parameters --
1166 --------------------------------
1167
1168 function Type_Conformant_Parameters
1169 (Prim_Op_Param_Specs : List_Id;
1170 Proc_Param_Specs : List_Id) return Boolean
1171 is
1172 Prim_Op_Param : Node_Id;
1173 Proc_Param : Node_Id;
1174
1175 begin
1176 -- Skip the first parameter of the primitive operation
1177
1178 Prim_Op_Param := Next (First (Prim_Op_Param_Specs));
1179 Proc_Param := First (Proc_Param_Specs);
1180 while Present (Prim_Op_Param)
1181 and then Present (Proc_Param)
1182 loop
1183 -- The two parameters must be mode conformant and have
1184 -- the exact same types.
1185
1186 if Out_Present (Prim_Op_Param) /= Out_Present (Proc_Param)
1187 or else In_Present (Prim_Op_Param) /= In_Present (Proc_Param)
1188 or else Etype (Parameter_Type (Prim_Op_Param)) /=
1189 Etype (Parameter_Type (Proc_Param))
1190 then
1191 return False;
1192 end if;
1193
1194 Next (Prim_Op_Param);
1195 Next (Proc_Param);
1196 end loop;
1197
1198 -- One of the lists is longer than the other
1199
1200 if Present (Prim_Op_Param) or else Present (Proc_Param) then
1201 return False;
1202 end if;
1203
1204 return True;
1205 end Type_Conformant_Parameters;
1206
1207 -- Start of processing for Overriding_Possible
1208
1209 begin
1210 if Chars (Iface_Prim_Op) /= Chars (Proc_Nam) then
1211 return False;
1212 end if;
1213
1214 -- Special check for protected procedures: If an inherited subprogram
1215 -- is implemented by a protected procedure or an entry, then the
1216 -- first parameter of the inherited subprogram shall be of mode OUT
1217 -- or IN OUT, or an access-to-variable parameter.
1218
1219 if Ekind (Iface_Prim_Op) = E_Procedure then
1220
1221 Is_Out_Present :=
1222 Present (Parameter_Specifications (Prim_Op_Spec))
1223 and then
1224 Out_Present (First (Parameter_Specifications (Prim_Op_Spec)));
1225
1226 Is_Access_To_Variable :=
1227 Present (Parameter_Specifications (Prim_Op_Spec))
1228 and then
1229 Nkind (Parameter_Type
1230 (First
1231 (Parameter_Specifications (Prim_Op_Spec))))
1232 = N_Access_Definition;
1233
1234 if not Is_Out_Present
1235 and then not Is_Access_To_Variable
1236 then
1237 return False;
1238 end if;
1239 end if;
1240
1241 return Type_Conformant_Parameters (
1242 Parameter_Specifications (Prim_Op_Spec),
1243 Parameter_Specifications (Proc_Spec));
1244
1245 end Overriding_Possible;
1246
1247 -----------------------------
1248 -- Replicate_Entry_Formals --
1249 -----------------------------
1250
1251 function Replicate_Entry_Formals
1252 (Loc : Source_Ptr;
1253 Formals : List_Id) return List_Id
1254 is
1255 New_Formals : constant List_Id := New_List;
1256 Formal : Node_Id;
1257
1258 begin
1259 Formal := First (Formals);
1260
1261 if Present (Formal) then
1262 while Present (Formal) loop
1263
1264 -- Create an explicit copy of the entry parameter
1265
1266 Append_To (New_Formals,
1267 Make_Parameter_Specification (Loc,
1268 Defining_Identifier =>
1269 Make_Defining_Identifier (Loc,
1270 Chars => Chars (Defining_Identifier (Formal))),
1271 In_Present => In_Present (Formal),
1272 Out_Present => Out_Present (Formal),
1273 Parameter_Type => New_Reference_To (Etype (
1274 Parameter_Type (Formal)), Loc)));
1275
1276 Next (Formal);
1277 end loop;
1278 end if;
1279
1280 return New_Formals;
1281 end Replicate_Entry_Formals;
1282
1283 -- Start of processing for Build_Wrapper_Spec
1284
1285 begin
1286 -- The mode is determined by the first parameter of the interface-level
1287 -- procedure that the current entry is trying to override.
1288
1289 pragma Assert (Present (Abstract_Interfaces
1290 (Corresponding_Record_Type (Scope (Proc_Nam)))));
1291
1292 Iface_Elmt :=
1293 First_Elmt (Abstract_Interfaces
1294 (Corresponding_Record_Type (Scope (Proc_Nam))));
1295
1296 -- We must examine all the protected operations of the implemented
1297 -- interfaces in order to discover a possible overriding candidate.
1298
1299 Examine_Interfaces : while Present (Iface_Elmt) loop
1300 Iface := Node (Iface_Elmt);
1301
1302 if Present (Primitive_Operations (Iface)) then
1303 Iface_Prim_Op_Elmt := First_Elmt (Primitive_Operations (Iface));
1304
1305 while Present (Iface_Prim_Op_Elmt) loop
1306 Iface_Prim_Op := Node (Iface_Prim_Op_Elmt);
1307
1308 -- The current primitive operation can be overriden by the
1309 -- generated entry wrapper.
1310
1311 if Overriding_Possible (Iface_Prim_Op, Proc_Nam) then
1312 First_Param :=
1313 First (Parameter_Specifications (Parent (Iface_Prim_Op)));
1314
1315 exit Examine_Interfaces;
1316 end if;
1317
1318 Next_Elmt (Iface_Prim_Op_Elmt);
1319 end loop;
1320 end if;
1321
1322 Next_Elmt (Iface_Elmt);
1323 end loop Examine_Interfaces;
1324
1325 -- Return if no interface primitive can be overriden
1326
1327 if not Present (First_Param) then
1328 return Empty;
1329 end if;
1330
1331 New_Formals := Replicate_Entry_Formals (Loc, Formals);
1332
1333 -- ??? Certain source packages contain protected or task types that do
1334 -- not implement any interfaces and are compiled with the -gnat05
1335 -- switch. In this case, a default first parameter is created.
1336
1337 if Present (First_Param) then
1338 if Nkind (Parameter_Type (First_Param)) = N_Access_Definition then
1339 Obj_Param_Typ :=
1340 Make_Access_Definition (Loc,
1341 Subtype_Mark =>
1342 New_Reference_To (Obj_Typ, Loc));
1343 else
1344 Obj_Param_Typ := New_Reference_To (Obj_Typ, Loc);
1345 end if;
1346
1347 Obj_Param :=
1348 Make_Parameter_Specification (Loc,
1349 Defining_Identifier =>
1350 Make_Defining_Identifier (Loc, Name_uO),
1351 In_Present => In_Present (First_Param),
1352 Out_Present => Out_Present (First_Param),
1353 Parameter_Type => Obj_Param_Typ);
1354
1355 else
1356 Obj_Param :=
1357 Make_Parameter_Specification (Loc,
1358 Defining_Identifier =>
1359 Make_Defining_Identifier (Loc, Name_uO),
1360 In_Present => True,
1361 Out_Present => True,
1362 Parameter_Type => New_Reference_To (Obj_Typ, Loc));
1363 end if;
1364
1365 Prepend_To (New_Formals, Obj_Param);
1366
1367 -- Minimum decoration needed to catch the entity in
1368 -- Sem_Ch6.Override_Dispatching_Operation
1369
1370 if Ekind (Proc_Nam) = E_Procedure
1371 or else Ekind (Proc_Nam) = E_Entry
1372 then
1373 Set_Ekind (New_Name_Id, E_Procedure);
1374 return
1375 Make_Procedure_Specification (Loc,
1376 Defining_Unit_Name => New_Name_Id,
1377 Parameter_Specifications => New_Formals);
1378
1379 else pragma Assert (Ekind (Proc_Nam) = E_Function);
1380 Set_Ekind (New_Name_Id, E_Function);
1381 return
1382 Make_Function_Specification (Loc,
1383 Defining_Unit_Name => New_Name_Id,
1384 Parameter_Specifications => New_Formals,
1385 Subtype_Mark => New_Copy (Subtype_Mark (Parent (Proc_Nam))));
1386 end if;
1387 end Build_Wrapper_Spec;
1388
1389 ---------------------------
1390 -- Build_Find_Body_Index --
1391 ---------------------------
1392
1393 function Build_Find_Body_Index (Typ : Entity_Id) return Node_Id is
1394 Loc : constant Source_Ptr := Sloc (Typ);
1395 Ent : Entity_Id;
1396 E_Typ : Entity_Id;
1397 Has_F : Boolean := False;
1398 Index : Nat;
1399 If_St : Node_Id := Empty;
1400 Lo : Node_Id;
1401 Hi : Node_Id;
1402 Decls : List_Id := New_List;
1403 Ret : Node_Id;
1404 Spec : Node_Id;
1405 Siz : Node_Id := Empty;
1406
1407 procedure Add_If_Clause (Expr : Node_Id);
1408 -- Add test for range of current entry
1409
1410 function Convert_Discriminant_Ref (Bound : Node_Id) return Node_Id;
1411 -- If a bound of an entry is given by a discriminant, retrieve the
1412 -- actual value of the discriminant from the enclosing object.
1413
1414 -------------------
1415 -- Add_If_Clause --
1416 -------------------
1417
1418 procedure Add_If_Clause (Expr : Node_Id) is
1419 Cond : Node_Id;
1420 Stats : constant List_Id :=
1421 New_List (
1422 Make_Return_Statement (Loc,
1423 Expression => Make_Integer_Literal (Loc, Index + 1)));
1424
1425 begin
1426 -- Index for current entry body
1427
1428 Index := Index + 1;
1429
1430 -- Compute total length of entry queues so far
1431
1432 if No (Siz) then
1433 Siz := Expr;
1434 else
1435 Siz :=
1436 Make_Op_Add (Loc,
1437 Left_Opnd => Siz,
1438 Right_Opnd => Expr);
1439 end if;
1440
1441 Cond :=
1442 Make_Op_Le (Loc,
1443 Left_Opnd => Make_Identifier (Loc, Name_uE),
1444 Right_Opnd => Siz);
1445
1446 -- Map entry queue indices in the range of the current family
1447 -- into the current index, that designates the entry body.
1448
1449 if No (If_St) then
1450 If_St :=
1451 Make_Implicit_If_Statement (Typ,
1452 Condition => Cond,
1453 Then_Statements => Stats,
1454 Elsif_Parts => New_List);
1455
1456 Ret := If_St;
1457
1458 else
1459 Append (
1460 Make_Elsif_Part (Loc,
1461 Condition => Cond,
1462 Then_Statements => Stats),
1463 Elsif_Parts (If_St));
1464 end if;
1465 end Add_If_Clause;
1466
1467 ------------------------------
1468 -- Convert_Discriminant_Ref --
1469 ------------------------------
1470
1471 function Convert_Discriminant_Ref (Bound : Node_Id) return Node_Id is
1472 B : Node_Id;
1473
1474 begin
1475 if Is_Entity_Name (Bound)
1476 and then Ekind (Entity (Bound)) = E_Discriminant
1477 then
1478 B :=
1479 Make_Selected_Component (Loc,
1480 Prefix =>
1481 Unchecked_Convert_To (Corresponding_Record_Type (Typ),
1482 Make_Explicit_Dereference (Loc,
1483 Make_Identifier (Loc, Name_uObject))),
1484 Selector_Name => Make_Identifier (Loc, Chars (Bound)));
1485 Set_Etype (B, Etype (Entity (Bound)));
1486 else
1487 B := New_Copy_Tree (Bound);
1488 end if;
1489
1490 return B;
1491 end Convert_Discriminant_Ref;
1492
1493 -- Start of processing for Build_Find_Body_Index
1494
1495 begin
1496 Spec := Build_Find_Body_Index_Spec (Typ);
1497
1498 Ent := First_Entity (Typ);
1499
1500 while Present (Ent) loop
1501
1502 if Ekind (Ent) = E_Entry_Family then
1503 Has_F := True;
1504 exit;
1505 end if;
1506
1507 Next_Entity (Ent);
1508 end loop;
1509
1510 if not Has_F then
1511
1512 -- If the protected type has no entry families, there is a one-one
1513 -- correspondence between entry queue and entry body.
1514
1515 Ret :=
1516 Make_Return_Statement (Loc,
1517 Expression => Make_Identifier (Loc, Name_uE));
1518
1519 else
1520 -- Suppose entries e1, e2, ... have size l1, l2, ... we generate
1521 -- the following:
1522 --
1523 -- if E <= l1 then return 1;
1524 -- elsif E <= l1 + l2 then return 2;
1525 -- ...
1526
1527 Index := 0;
1528 Siz := Empty;
1529 Ent := First_Entity (Typ);
1530
1531 Add_Object_Pointer (Decls, Typ, Loc);
1532
1533 while Present (Ent) loop
1534
1535 if Ekind (Ent) = E_Entry then
1536 Add_If_Clause (Make_Integer_Literal (Loc, 1));
1537
1538 elsif Ekind (Ent) = E_Entry_Family then
1539
1540 E_Typ := Etype (Discrete_Subtype_Definition (Parent (Ent)));
1541 Hi := Convert_Discriminant_Ref (Type_High_Bound (E_Typ));
1542 Lo := Convert_Discriminant_Ref (Type_Low_Bound (E_Typ));
1543 Add_If_Clause (Family_Size (Loc, Hi, Lo, Typ));
1544 end if;
1545
1546 Next_Entity (Ent);
1547 end loop;
1548
1549 if Index = 1 then
1550 Decls := New_List;
1551 Ret :=
1552 Make_Return_Statement (Loc,
1553 Expression => Make_Integer_Literal (Loc, 1));
1554
1555 elsif Nkind (Ret) = N_If_Statement then
1556
1557 -- Ranges are in increasing order, so last one doesn't need a
1558 -- guard.
1559
1560 declare
1561 Nod : constant Node_Id := Last (Elsif_Parts (Ret));
1562
1563 begin
1564 Remove (Nod);
1565 Set_Else_Statements (Ret, Then_Statements (Nod));
1566 end;
1567 end if;
1568 end if;
1569
1570 return
1571 Make_Subprogram_Body (Loc,
1572 Specification => Spec,
1573 Declarations => Decls,
1574 Handled_Statement_Sequence =>
1575 Make_Handled_Sequence_Of_Statements (Loc,
1576 Statements => New_List (Ret)));
1577 end Build_Find_Body_Index;
1578
1579 --------------------------------
1580 -- Build_Find_Body_Index_Spec --
1581 --------------------------------
1582
1583 function Build_Find_Body_Index_Spec (Typ : Entity_Id) return Node_Id is
1584 Loc : constant Source_Ptr := Sloc (Typ);
1585 Id : constant Entity_Id :=
1586 Make_Defining_Identifier (Loc,
1587 Chars => New_External_Name (Chars (Typ), 'F'));
1588 Parm1 : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uO);
1589 Parm2 : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uE);
1590
1591 begin
1592 return
1593 Make_Function_Specification (Loc,
1594 Defining_Unit_Name => Id,
1595 Parameter_Specifications => New_List (
1596 Make_Parameter_Specification (Loc,
1597 Defining_Identifier => Parm1,
1598 Parameter_Type =>
1599 New_Reference_To (RTE (RE_Address), Loc)),
1600
1601 Make_Parameter_Specification (Loc,
1602 Defining_Identifier => Parm2,
1603 Parameter_Type =>
1604 New_Reference_To (RTE (RE_Protected_Entry_Index), Loc))),
1605 Subtype_Mark => New_Occurrence_Of (
1606 RTE (RE_Protected_Entry_Index), Loc));
1607 end Build_Find_Body_Index_Spec;
1608
1609 -------------------------
1610 -- Build_Master_Entity --
1611 -------------------------
1612
1613 procedure Build_Master_Entity (E : Entity_Id) is
1614 Loc : constant Source_Ptr := Sloc (E);
1615 P : Node_Id;
1616 Decl : Node_Id;
1617 S : Entity_Id;
1618
1619 begin
1620 S := Scope (E);
1621
1622 -- Ada 2005 (AI-287): Do not set/get the has_master_entity reminder
1623 -- in internal scopes. Required for nested limited aggregates.
1624
1625 if Ada_Version >= Ada_05 then
1626 while Is_Internal (S) loop
1627 S := Scope (S);
1628 end loop;
1629 end if;
1630
1631 -- Nothing to do if we already built a master entity for this scope
1632 -- or if there is no task hierarchy.
1633
1634 if Has_Master_Entity (S)
1635 or else Restriction_Active (No_Task_Hierarchy)
1636 then
1637 return;
1638 end if;
1639
1640 -- Otherwise first build the master entity
1641 -- _Master : constant Master_Id := Current_Master.all;
1642 -- and insert it just before the current declaration
1643
1644 Decl :=
1645 Make_Object_Declaration (Loc,
1646 Defining_Identifier =>
1647 Make_Defining_Identifier (Loc, Name_uMaster),
1648 Constant_Present => True,
1649 Object_Definition => New_Reference_To (RTE (RE_Master_Id), Loc),
1650 Expression =>
1651 Make_Explicit_Dereference (Loc,
1652 New_Reference_To (RTE (RE_Current_Master), Loc)));
1653
1654 P := Parent (E);
1655 Insert_Before (P, Decl);
1656 Analyze (Decl);
1657
1658 -- Ada 2005 (AI-287): Set the has_master_entity reminder in the
1659 -- non-internal scope selected above.
1660
1661 if Ada_Version >= Ada_05 then
1662 Set_Has_Master_Entity (S);
1663 else
1664 Set_Has_Master_Entity (Scope (E));
1665 end if;
1666
1667 -- Now mark the containing scope as a task master
1668
1669 while Nkind (P) /= N_Compilation_Unit loop
1670 P := Parent (P);
1671
1672 -- If we fall off the top, we are at the outer level, and the
1673 -- environment task is our effective master, so nothing to mark.
1674
1675 if Nkind (P) = N_Task_Body
1676 or else Nkind (P) = N_Block_Statement
1677 or else Nkind (P) = N_Subprogram_Body
1678 then
1679 Set_Is_Task_Master (P, True);
1680 return;
1681
1682 elsif Nkind (Parent (P)) = N_Subunit then
1683 P := Corresponding_Stub (Parent (P));
1684 end if;
1685 end loop;
1686 end Build_Master_Entity;
1687
1688 ---------------------------
1689 -- Build_Protected_Entry --
1690 ---------------------------
1691
1692 function Build_Protected_Entry
1693 (N : Node_Id;
1694 Ent : Entity_Id;
1695 Pid : Node_Id) return Node_Id
1696 is
1697 Loc : constant Source_Ptr := Sloc (N);
1698 Op_Decls : constant List_Id := New_List;
1699 Edef : Entity_Id;
1700 Espec : Node_Id;
1701 Op_Stats : List_Id;
1702 Ohandle : Node_Id;
1703 Complete : Node_Id;
1704
1705 begin
1706 Edef :=
1707 Make_Defining_Identifier (Loc,
1708 Chars => Chars (Protected_Body_Subprogram (Ent)));
1709 Espec := Build_Protected_Entry_Specification (Edef, Empty, Loc);
1710
1711 -- <object pointer declaration>
1712 -- Add object pointer declaration. This is needed by the
1713 -- discriminal and prival renamings, which should already
1714 -- have been inserted into the declaration list.
1715
1716 Add_Object_Pointer (Op_Decls, Pid, Loc);
1717
1718 if Abort_Allowed
1719 or else Restriction_Active (No_Entry_Queue) = False
1720 or else Number_Entries (Pid) > 1
1721 then
1722 Complete := New_Reference_To (RTE (RE_Complete_Entry_Body), Loc);
1723 else
1724 Complete :=
1725 New_Reference_To (RTE (RE_Complete_Single_Entry_Body), Loc);
1726 end if;
1727
1728 Op_Stats := New_List (
1729 Make_Block_Statement (Loc,
1730 Declarations => Declarations (N),
1731 Handled_Statement_Sequence =>
1732 Handled_Statement_Sequence (N)),
1733
1734 Make_Procedure_Call_Statement (Loc,
1735 Name => Complete,
1736 Parameter_Associations => New_List (
1737 Make_Attribute_Reference (Loc,
1738 Prefix =>
1739 Make_Selected_Component (Loc,
1740 Prefix =>
1741 Make_Identifier (Loc, Name_uObject),
1742
1743 Selector_Name =>
1744 Make_Identifier (Loc, Name_uObject)),
1745 Attribute_Name => Name_Unchecked_Access))));
1746
1747 if Restriction_Active (No_Exception_Handlers) then
1748 return
1749 Make_Subprogram_Body (Loc,
1750 Specification => Espec,
1751 Declarations => Op_Decls,
1752 Handled_Statement_Sequence =>
1753 Make_Handled_Sequence_Of_Statements (Loc, Op_Stats));
1754
1755 else
1756 Ohandle := Make_Others_Choice (Loc);
1757 Set_All_Others (Ohandle);
1758
1759 if Abort_Allowed
1760 or else Restriction_Active (No_Entry_Queue) = False
1761 or else Number_Entries (Pid) > 1
1762 then
1763 Complete :=
1764 New_Reference_To (RTE (RE_Exceptional_Complete_Entry_Body), Loc);
1765
1766 else
1767 Complete := New_Reference_To (
1768 RTE (RE_Exceptional_Complete_Single_Entry_Body), Loc);
1769 end if;
1770
1771 return
1772 Make_Subprogram_Body (Loc,
1773 Specification => Espec,
1774 Declarations => Op_Decls,
1775 Handled_Statement_Sequence =>
1776 Make_Handled_Sequence_Of_Statements (Loc,
1777 Statements => Op_Stats,
1778 Exception_Handlers => New_List (
1779 Make_Exception_Handler (Loc,
1780 Exception_Choices => New_List (Ohandle),
1781
1782 Statements => New_List (
1783 Make_Procedure_Call_Statement (Loc,
1784 Name => Complete,
1785 Parameter_Associations => New_List (
1786 Make_Attribute_Reference (Loc,
1787 Prefix =>
1788 Make_Selected_Component (Loc,
1789 Prefix =>
1790 Make_Identifier (Loc, Name_uObject),
1791 Selector_Name =>
1792 Make_Identifier (Loc, Name_uObject)),
1793 Attribute_Name => Name_Unchecked_Access),
1794
1795 Make_Function_Call (Loc,
1796 Name => New_Reference_To (
1797 RTE (RE_Get_GNAT_Exception), Loc)))))))));
1798 end if;
1799 end Build_Protected_Entry;
1800
1801 -----------------------------------------
1802 -- Build_Protected_Entry_Specification --
1803 -----------------------------------------
1804
1805 function Build_Protected_Entry_Specification
1806 (Def_Id : Entity_Id;
1807 Ent_Id : Entity_Id;
1808 Loc : Source_Ptr) return Node_Id
1809 is
1810 P : Entity_Id;
1811
1812 begin
1813 Set_Needs_Debug_Info (Def_Id);
1814 P := Make_Defining_Identifier (Loc, Name_uP);
1815
1816 if Present (Ent_Id) then
1817 Append_Elmt (P, Accept_Address (Ent_Id));
1818 end if;
1819
1820 return Make_Procedure_Specification (Loc,
1821 Defining_Unit_Name => Def_Id,
1822 Parameter_Specifications => New_List (
1823 Make_Parameter_Specification (Loc,
1824 Defining_Identifier => Make_Defining_Identifier (Loc, Name_uO),
1825 Parameter_Type =>
1826 New_Reference_To (RTE (RE_Address), Loc)),
1827
1828 Make_Parameter_Specification (Loc,
1829 Defining_Identifier => P,
1830 Parameter_Type =>
1831 New_Reference_To (RTE (RE_Address), Loc)),
1832
1833 Make_Parameter_Specification (Loc,
1834 Defining_Identifier => Make_Defining_Identifier (Loc, Name_uE),
1835 Parameter_Type =>
1836 New_Reference_To (RTE (RE_Protected_Entry_Index), Loc))));
1837 end Build_Protected_Entry_Specification;
1838
1839 --------------------------
1840 -- Build_Protected_Spec --
1841 --------------------------
1842
1843 function Build_Protected_Spec
1844 (N : Node_Id;
1845 Obj_Type : Entity_Id;
1846 Unprotected : Boolean := False;
1847 Ident : Entity_Id) return List_Id
1848 is
1849 Loc : constant Source_Ptr := Sloc (N);
1850 Formal : Entity_Id;
1851 New_Plist : List_Id;
1852 New_Param : Node_Id;
1853
1854 begin
1855 New_Plist := New_List;
1856 Formal := First_Formal (Ident);
1857
1858 while Present (Formal) loop
1859 New_Param :=
1860 Make_Parameter_Specification (Loc,
1861 Defining_Identifier =>
1862 Make_Defining_Identifier (Sloc (Formal), Chars (Formal)),
1863 In_Present => In_Present (Parent (Formal)),
1864 Out_Present => Out_Present (Parent (Formal)),
1865 Parameter_Type =>
1866 New_Reference_To (Etype (Formal), Loc));
1867
1868 if Unprotected then
1869 Set_Protected_Formal (Formal, Defining_Identifier (New_Param));
1870 end if;
1871
1872 Append (New_Param, New_Plist);
1873 Next_Formal (Formal);
1874 end loop;
1875
1876 -- If the subprogram is a procedure and the context is not an access
1877 -- to protected subprogram, the parameter is in-out. Otherwise it is
1878 -- an in parameter.
1879
1880 Prepend_To (New_Plist,
1881 Make_Parameter_Specification (Loc,
1882 Defining_Identifier =>
1883 Make_Defining_Identifier (Loc, Name_uObject),
1884 In_Present => True,
1885 Out_Present =>
1886 (Etype (Ident) = Standard_Void_Type
1887 and then not Is_RTE (Obj_Type, RE_Address)),
1888 Parameter_Type => New_Reference_To (Obj_Type, Loc)));
1889
1890 return New_Plist;
1891 end Build_Protected_Spec;
1892
1893 ---------------------------------------
1894 -- Build_Protected_Sub_Specification --
1895 ---------------------------------------
1896
1897 function Build_Protected_Sub_Specification
1898 (N : Node_Id;
1899 Prottyp : Entity_Id;
1900 Unprotected : Boolean := False) return Node_Id
1901 is
1902 Loc : constant Source_Ptr := Sloc (N);
1903 Decl : Node_Id;
1904 Protnm : constant Name_Id := Chars (Prottyp);
1905 Ident : Entity_Id;
1906 Nam : Name_Id;
1907 New_Id : Entity_Id;
1908 New_Plist : List_Id;
1909 Append_Char : Character;
1910 New_Spec : Node_Id;
1911
1912 begin
1913 if Ekind
1914 (Defining_Unit_Name (Specification (N))) = E_Subprogram_Body
1915 then
1916 Decl := Unit_Declaration_Node (Corresponding_Spec (N));
1917 else
1918 Decl := N;
1919 end if;
1920
1921 Ident := Defining_Unit_Name (Specification (Decl));
1922 Nam := Chars (Ident);
1923
1924 New_Plist := Build_Protected_Spec
1925 (Decl, Corresponding_Record_Type (Prottyp),
1926 Unprotected, Ident);
1927
1928 if Unprotected then
1929 Append_Char := 'N';
1930 else
1931 -- Ada 2005 (AI-345): The protected version no longer uses 'P'
1932 -- as suffix in order to make it a primitive operation
1933
1934 if Ada_Version >= Ada_05 then
1935 Append_Char := ' ';
1936 else
1937 Append_Char := 'P';
1938 end if;
1939 end if;
1940
1941 New_Id :=
1942 Make_Defining_Identifier (Loc,
1943 Chars => Build_Selected_Name (Protnm, Nam, Append_Char));
1944
1945 -- The unprotected operation carries the user code, and debugging
1946 -- information must be generated for it, even though this spec does
1947 -- not come from source. It is also convenient to allow gdb to step
1948 -- into the protected operation, even though it only contains lock/
1949 -- unlock calls.
1950
1951 Set_Needs_Debug_Info (New_Id);
1952
1953 if Nkind (Specification (Decl)) = N_Procedure_Specification then
1954 return
1955 Make_Procedure_Specification (Loc,
1956 Defining_Unit_Name => New_Id,
1957 Parameter_Specifications => New_Plist);
1958
1959 else
1960 New_Spec :=
1961 Make_Function_Specification (Loc,
1962 Defining_Unit_Name => New_Id,
1963 Parameter_Specifications => New_Plist,
1964 Subtype_Mark => New_Copy (Subtype_Mark (Specification (Decl))));
1965 Set_Return_Present (Defining_Unit_Name (New_Spec));
1966 return New_Spec;
1967 end if;
1968 end Build_Protected_Sub_Specification;
1969
1970 -------------------------------------
1971 -- Build_Protected_Subprogram_Body --
1972 -------------------------------------
1973
1974 function Build_Protected_Subprogram_Body
1975 (N : Node_Id;
1976 Pid : Node_Id;
1977 N_Op_Spec : Node_Id) return Node_Id
1978 is
1979 Loc : constant Source_Ptr := Sloc (N);
1980 Op_Spec : Node_Id;
1981 P_Op_Spec : Node_Id;
1982 Uactuals : List_Id;
1983 Pformal : Node_Id;
1984 Unprot_Call : Node_Id;
1985 Sub_Body : Node_Id;
1986 Lock_Name : Node_Id;
1987 Lock_Stmt : Node_Id;
1988 Service_Name : Node_Id;
1989 R : Node_Id;
1990 Return_Stmt : Node_Id := Empty; -- init to avoid gcc 3 warning
1991 Pre_Stmts : List_Id := No_List; -- init to avoid gcc 3 warning
1992 Stmts : List_Id;
1993 Object_Parm : Node_Id;
1994 Exc_Safe : Boolean;
1995
1996 function Is_Exception_Safe (Subprogram : Node_Id) return Boolean;
1997 -- Tell whether a given subprogram cannot raise an exception
1998
1999 -----------------------
2000 -- Is_Exception_Safe --
2001 -----------------------
2002
2003 function Is_Exception_Safe (Subprogram : Node_Id) return Boolean is
2004
2005 function Has_Side_Effect (N : Node_Id) return Boolean;
2006 -- Return True whenever encountering a subprogram call or a
2007 -- raise statement of any kind in the sequence of statements N
2008
2009 ---------------------
2010 -- Has_Side_Effect --
2011 ---------------------
2012
2013 -- What is this doing buried two levels down in exp_ch9. It
2014 -- seems like a generally useful function, and indeed there
2015 -- may be code duplication going on here ???
2016
2017 function Has_Side_Effect (N : Node_Id) return Boolean is
2018 Stmt : Node_Id := N;
2019 Expr : Node_Id;
2020
2021 function Is_Call_Or_Raise (N : Node_Id) return Boolean;
2022 -- Indicate whether N is a subprogram call or a raise statement
2023
2024 function Is_Call_Or_Raise (N : Node_Id) return Boolean is
2025 begin
2026 return Nkind (N) = N_Procedure_Call_Statement
2027 or else Nkind (N) = N_Function_Call
2028 or else Nkind (N) = N_Raise_Statement
2029 or else Nkind (N) = N_Raise_Constraint_Error
2030 or else Nkind (N) = N_Raise_Program_Error
2031 or else Nkind (N) = N_Raise_Storage_Error;
2032 end Is_Call_Or_Raise;
2033
2034 -- Start of processing for Has_Side_Effect
2035
2036 begin
2037 while Present (Stmt) loop
2038 if Is_Call_Or_Raise (Stmt) then
2039 return True;
2040 end if;
2041
2042 -- An object declaration can also contain a function call
2043 -- or a raise statement
2044
2045 if Nkind (Stmt) = N_Object_Declaration then
2046 Expr := Expression (Stmt);
2047
2048 if Present (Expr) and then Is_Call_Or_Raise (Expr) then
2049 return True;
2050 end if;
2051 end if;
2052
2053 Next (Stmt);
2054 end loop;
2055
2056 return False;
2057 end Has_Side_Effect;
2058
2059 -- Start of processing for Is_Exception_Safe
2060
2061 begin
2062 -- If the checks handled by the back end are not disabled, we cannot
2063 -- ensure that no exception will be raised.
2064
2065 if not Access_Checks_Suppressed (Empty)
2066 or else not Discriminant_Checks_Suppressed (Empty)
2067 or else not Range_Checks_Suppressed (Empty)
2068 or else not Index_Checks_Suppressed (Empty)
2069 or else Opt.Stack_Checking_Enabled
2070 then
2071 return False;
2072 end if;
2073
2074 if Has_Side_Effect (First (Declarations (Subprogram)))
2075 or else
2076 Has_Side_Effect (
2077 First (Statements (Handled_Statement_Sequence (Subprogram))))
2078 then
2079 return False;
2080 else
2081 return True;
2082 end if;
2083 end Is_Exception_Safe;
2084
2085 -- Start of processing for Build_Protected_Subprogram_Body
2086
2087 begin
2088 Op_Spec := Specification (N);
2089 Exc_Safe := Is_Exception_Safe (N);
2090
2091 P_Op_Spec :=
2092 Build_Protected_Sub_Specification (N,
2093 Pid, Unprotected => False);
2094
2095 -- Build a list of the formal parameters of the protected
2096 -- version of the subprogram to use as the actual parameters
2097 -- of the unprotected version.
2098
2099 Uactuals := New_List;
2100 Pformal := First (Parameter_Specifications (P_Op_Spec));
2101
2102 while Present (Pformal) loop
2103 Append (
2104 Make_Identifier (Loc, Chars (Defining_Identifier (Pformal))),
2105 Uactuals);
2106 Next (Pformal);
2107 end loop;
2108
2109 -- Make a call to the unprotected version of the subprogram
2110 -- built above for use by the protected version built below.
2111
2112 if Nkind (Op_Spec) = N_Function_Specification then
2113 if Exc_Safe then
2114 R := Make_Defining_Identifier (Loc, New_Internal_Name ('R'));
2115 Unprot_Call :=
2116 Make_Object_Declaration (Loc,
2117 Defining_Identifier => R,
2118 Constant_Present => True,
2119 Object_Definition => New_Copy (Subtype_Mark (N_Op_Spec)),
2120 Expression =>
2121 Make_Function_Call (Loc,
2122 Name => Make_Identifier (Loc,
2123 Chars (Defining_Unit_Name (N_Op_Spec))),
2124 Parameter_Associations => Uactuals));
2125 Return_Stmt := Make_Return_Statement (Loc,
2126 Expression => New_Reference_To (R, Loc));
2127
2128 else
2129 Unprot_Call := Make_Return_Statement (Loc,
2130 Expression => Make_Function_Call (Loc,
2131 Name =>
2132 Make_Identifier (Loc,
2133 Chars (Defining_Unit_Name (N_Op_Spec))),
2134 Parameter_Associations => Uactuals));
2135 end if;
2136
2137 else
2138 Unprot_Call := Make_Procedure_Call_Statement (Loc,
2139 Name =>
2140 Make_Identifier (Loc,
2141 Chars (Defining_Unit_Name (N_Op_Spec))),
2142 Parameter_Associations => Uactuals);
2143 end if;
2144
2145 -- Wrap call in block that will be covered by an at_end handler
2146
2147 if not Exc_Safe then
2148 Unprot_Call := Make_Block_Statement (Loc,
2149 Handled_Statement_Sequence =>
2150 Make_Handled_Sequence_Of_Statements (Loc,
2151 Statements => New_List (Unprot_Call)));
2152 end if;
2153
2154 -- Make the protected subprogram body. This locks the protected
2155 -- object and calls the unprotected version of the subprogram.
2156
2157 -- If the protected object is controlled (i.e it has entries or
2158 -- needs finalization for interrupt handling), call Lock_Entries,
2159 -- except if the protected object follows the Ravenscar profile, in
2160 -- which case call Lock_Entry, otherwise call the simplified version,
2161 -- Lock.
2162
2163 if Has_Entries (Pid)
2164 or else Has_Interrupt_Handler (Pid)
2165 or else (Has_Attach_Handler (Pid) and then not Restricted_Profile)
2166 then
2167 if Abort_Allowed
2168 or else Restriction_Active (No_Entry_Queue) = False
2169 or else Number_Entries (Pid) > 1
2170 then
2171 Lock_Name := New_Reference_To (RTE (RE_Lock_Entries), Loc);
2172 Service_Name := New_Reference_To (RTE (RE_Service_Entries), Loc);
2173
2174 else
2175 Lock_Name := New_Reference_To (RTE (RE_Lock_Entry), Loc);
2176 Service_Name := New_Reference_To (RTE (RE_Service_Entry), Loc);
2177 end if;
2178
2179 else
2180 Lock_Name := New_Reference_To (RTE (RE_Lock), Loc);
2181 Service_Name := New_Reference_To (RTE (RE_Unlock), Loc);
2182 end if;
2183
2184 Object_Parm :=
2185 Make_Attribute_Reference (Loc,
2186 Prefix =>
2187 Make_Selected_Component (Loc,
2188 Prefix =>
2189 Make_Identifier (Loc, Name_uObject),
2190 Selector_Name =>
2191 Make_Identifier (Loc, Name_uObject)),
2192 Attribute_Name => Name_Unchecked_Access);
2193
2194 Lock_Stmt := Make_Procedure_Call_Statement (Loc,
2195 Name => Lock_Name,
2196 Parameter_Associations => New_List (Object_Parm));
2197
2198 if Abort_Allowed then
2199 Stmts := New_List (
2200 Make_Procedure_Call_Statement (Loc,
2201 Name => New_Reference_To (RTE (RE_Abort_Defer), Loc),
2202 Parameter_Associations => Empty_List),
2203 Lock_Stmt);
2204
2205 else
2206 Stmts := New_List (Lock_Stmt);
2207 end if;
2208
2209 if not Exc_Safe then
2210 Append (Unprot_Call, Stmts);
2211 else
2212 if Nkind (Op_Spec) = N_Function_Specification then
2213 Pre_Stmts := Stmts;
2214 Stmts := Empty_List;
2215 else
2216 Append (Unprot_Call, Stmts);
2217 end if;
2218
2219 Append (
2220 Make_Procedure_Call_Statement (Loc,
2221 Name => Service_Name,
2222 Parameter_Associations =>
2223 New_List (New_Copy_Tree (Object_Parm))),
2224 Stmts);
2225
2226 if Abort_Allowed then
2227 Append (
2228 Make_Procedure_Call_Statement (Loc,
2229 Name => New_Reference_To (RTE (RE_Abort_Undefer), Loc),
2230 Parameter_Associations => Empty_List),
2231 Stmts);
2232 end if;
2233
2234 if Nkind (Op_Spec) = N_Function_Specification then
2235 Append (Return_Stmt, Stmts);
2236 Append (Make_Block_Statement (Loc,
2237 Declarations => New_List (Unprot_Call),
2238 Handled_Statement_Sequence =>
2239 Make_Handled_Sequence_Of_Statements (Loc,
2240 Statements => Stmts)), Pre_Stmts);
2241 Stmts := Pre_Stmts;
2242 end if;
2243 end if;
2244
2245 Sub_Body :=
2246 Make_Subprogram_Body (Loc,
2247 Declarations => Empty_List,
2248 Specification => P_Op_Spec,
2249 Handled_Statement_Sequence =>
2250 Make_Handled_Sequence_Of_Statements (Loc, Statements => Stmts));
2251
2252 if not Exc_Safe then
2253 Set_Is_Protected_Subprogram_Body (Sub_Body);
2254 end if;
2255
2256 return Sub_Body;
2257 end Build_Protected_Subprogram_Body;
2258
2259 -------------------------------------
2260 -- Build_Protected_Subprogram_Call --
2261 -------------------------------------
2262
2263 procedure Build_Protected_Subprogram_Call
2264 (N : Node_Id;
2265 Name : Node_Id;
2266 Rec : Node_Id;
2267 External : Boolean := True)
2268 is
2269 Loc : constant Source_Ptr := Sloc (N);
2270 Sub : constant Entity_Id := Entity (Name);
2271 New_Sub : Node_Id;
2272 Params : List_Id;
2273
2274 begin
2275 if External then
2276 New_Sub := New_Occurrence_Of (External_Subprogram (Sub), Loc);
2277 else
2278 New_Sub :=
2279 New_Occurrence_Of (Protected_Body_Subprogram (Sub), Loc);
2280 end if;
2281
2282 if Present (Parameter_Associations (N)) then
2283 Params := New_Copy_List_Tree (Parameter_Associations (N));
2284 else
2285 Params := New_List;
2286 end if;
2287
2288 Prepend (Rec, Params);
2289
2290 if Ekind (Sub) = E_Procedure then
2291 Rewrite (N,
2292 Make_Procedure_Call_Statement (Loc,
2293 Name => New_Sub,
2294 Parameter_Associations => Params));
2295
2296 else
2297 pragma Assert (Ekind (Sub) = E_Function);
2298 Rewrite (N,
2299 Make_Function_Call (Loc,
2300 Name => New_Sub,
2301 Parameter_Associations => Params));
2302 end if;
2303
2304 if External
2305 and then Nkind (Rec) = N_Unchecked_Type_Conversion
2306 and then Is_Entity_Name (Expression (Rec))
2307 and then Is_Shared_Passive (Entity (Expression (Rec)))
2308 then
2309 Add_Shared_Var_Lock_Procs (N);
2310 end if;
2311 end Build_Protected_Subprogram_Call;
2312
2313 -------------------------
2314 -- Build_Selected_Name --
2315 -------------------------
2316
2317 function Build_Selected_Name
2318 (Prefix, Selector : Name_Id;
2319 Append_Char : Character := ' ') return Name_Id
2320 is
2321 Select_Buffer : String (1 .. Hostparm.Max_Name_Length);
2322 Select_Len : Natural;
2323
2324 begin
2325 Get_Name_String (Selector);
2326 Select_Len := Name_Len;
2327 Select_Buffer (1 .. Select_Len) := Name_Buffer (1 .. Name_Len);
2328 Get_Name_String (Prefix);
2329
2330 -- If scope is anonymous type, discard suffix to recover name of
2331 -- single protected object. Otherwise use protected type name.
2332
2333 if Name_Buffer (Name_Len) = 'T' then
2334 Name_Len := Name_Len - 1;
2335 end if;
2336
2337 Name_Buffer (Name_Len + 1) := '_';
2338 Name_Buffer (Name_Len + 2) := '_';
2339
2340 Name_Len := Name_Len + 2;
2341 for J in 1 .. Select_Len loop
2342 Name_Len := Name_Len + 1;
2343 Name_Buffer (Name_Len) := Select_Buffer (J);
2344 end loop;
2345
2346 if Append_Char /= ' ' then
2347 Name_Len := Name_Len + 1;
2348 Name_Buffer (Name_Len) := Append_Char;
2349 end if;
2350
2351 return Name_Find;
2352 end Build_Selected_Name;
2353
2354 -----------------------------
2355 -- Build_Simple_Entry_Call --
2356 -----------------------------
2357
2358 -- A task entry call is converted to a call to Call_Simple
2359
2360 -- declare
2361 -- P : parms := (parm, parm, parm);
2362 -- begin
2363 -- Call_Simple (acceptor-task, entry-index, P'Address);
2364 -- parm := P.param;
2365 -- parm := P.param;
2366 -- ...
2367 -- end;
2368
2369 -- Here Pnn is an aggregate of the type constructed for the entry to hold
2370 -- the parameters, and the constructed aggregate value contains either the
2371 -- parameters or, in the case of non-elementary types, references to these
2372 -- parameters. Then the address of this aggregate is passed to the runtime
2373 -- routine, along with the task id value and the task entry index value.
2374 -- Pnn is only required if parameters are present.
2375
2376 -- The assignments after the call are present only in the case of in-out
2377 -- or out parameters for elementary types, and are used to assign back the
2378 -- resulting values of such parameters.
2379
2380 -- Note: the reason that we insert a block here is that in the context
2381 -- of selects, conditional entry calls etc. the entry call statement
2382 -- appears on its own, not as an element of a list.
2383
2384 -- A protected entry call is converted to a Protected_Entry_Call:
2385
2386 -- declare
2387 -- P : E1_Params := (param, param, param);
2388 -- Pnn : Boolean;
2389 -- Bnn : Communications_Block;
2390
2391 -- declare
2392 -- P : E1_Params := (param, param, param);
2393 -- Bnn : Communications_Block;
2394
2395 -- begin
2396 -- Protected_Entry_Call (
2397 -- Object => po._object'Access,
2398 -- E => <entry index>;
2399 -- Uninterpreted_Data => P'Address;
2400 -- Mode => Simple_Call;
2401 -- Block => Bnn);
2402 -- parm := P.param;
2403 -- parm := P.param;
2404 -- ...
2405 -- end;
2406
2407 procedure Build_Simple_Entry_Call
2408 (N : Node_Id;
2409 Concval : Node_Id;
2410 Ename : Node_Id;
2411 Index : Node_Id)
2412 is
2413 begin
2414 Expand_Call (N);
2415
2416 -- Convert entry call to Call_Simple call
2417
2418 declare
2419 Loc : constant Source_Ptr := Sloc (N);
2420 Parms : constant List_Id := Parameter_Associations (N);
2421 Stats : constant List_Id := New_List;
2422 Pdecl : Node_Id;
2423 Xdecl : Node_Id;
2424 Decls : List_Id;
2425 Conctyp : Node_Id;
2426 Ent : Entity_Id;
2427 Ent_Acc : Entity_Id;
2428 P : Entity_Id;
2429 X : Entity_Id;
2430 Plist : List_Id;
2431 Parm1 : Node_Id;
2432 Parm2 : Node_Id;
2433 Parm3 : Node_Id;
2434 Call : Node_Id;
2435 Actual : Node_Id;
2436 Formal : Node_Id;
2437 N_Node : Node_Id;
2438 N_Var : Node_Id;
2439 Comm_Name : Entity_Id;
2440
2441 begin
2442 -- Simple entry and entry family cases merge here
2443
2444 Ent := Entity (Ename);
2445 Ent_Acc := Entry_Parameters_Type (Ent);
2446 Conctyp := Etype (Concval);
2447
2448 -- If prefix is an access type, dereference to obtain the task type
2449
2450 if Is_Access_Type (Conctyp) then
2451 Conctyp := Designated_Type (Conctyp);
2452 end if;
2453
2454 -- Special case for protected subprogram calls
2455
2456 if Is_Protected_Type (Conctyp)
2457 and then Is_Subprogram (Entity (Ename))
2458 then
2459 if not Is_Eliminated (Entity (Ename)) then
2460 Build_Protected_Subprogram_Call
2461 (N, Ename, Convert_Concurrent (Concval, Conctyp));
2462 Analyze (N);
2463 end if;
2464
2465 return;
2466 end if;
2467
2468 -- First parameter is the Task_Id value from the task value or the
2469 -- Object from the protected object value, obtained by selecting
2470 -- the _Task_Id or _Object from the result of doing an unchecked
2471 -- conversion to convert the value to the corresponding record type.
2472
2473 Parm1 := Concurrent_Ref (Concval);
2474
2475 -- Second parameter is the entry index, computed by the routine
2476 -- provided for this purpose. The value of this expression is
2477 -- assigned to an intermediate variable to assure that any entry
2478 -- family index expressions are evaluated before the entry
2479 -- parameters.
2480
2481 if Abort_Allowed
2482 or else Restriction_Active (No_Entry_Queue) = False
2483 or else not Is_Protected_Type (Conctyp)
2484 or else Number_Entries (Conctyp) > 1
2485 then
2486 X := Make_Defining_Identifier (Loc, Name_uX);
2487
2488 Xdecl :=
2489 Make_Object_Declaration (Loc,
2490 Defining_Identifier => X,
2491 Object_Definition =>
2492 New_Reference_To (RTE (RE_Task_Entry_Index), Loc),
2493 Expression => Actual_Index_Expression (
2494 Loc, Entity (Ename), Index, Concval));
2495
2496 Decls := New_List (Xdecl);
2497 Parm2 := New_Reference_To (X, Loc);
2498
2499 else
2500 Xdecl := Empty;
2501 Decls := New_List;
2502 Parm2 := Empty;
2503 end if;
2504
2505 -- The third parameter is the packaged parameters. If there are
2506 -- none, then it is just the null address, since nothing is passed
2507
2508 if No (Parms) then
2509 Parm3 := New_Reference_To (RTE (RE_Null_Address), Loc);
2510 P := Empty;
2511
2512 -- Case of parameters present, where third argument is the address
2513 -- of a packaged record containing the required parameter values.
2514
2515 else
2516 -- First build a list of parameter values, which are
2517 -- references to objects of the parameter types.
2518
2519 Plist := New_List;
2520
2521 Actual := First_Actual (N);
2522 Formal := First_Formal (Ent);
2523
2524 while Present (Actual) loop
2525
2526 -- If it is a by_copy_type, copy it to a new variable. The
2527 -- packaged record has a field that points to this variable.
2528
2529 if Is_By_Copy_Type (Etype (Actual)) then
2530 N_Node :=
2531 Make_Object_Declaration (Loc,
2532 Defining_Identifier =>
2533 Make_Defining_Identifier (Loc,
2534 Chars => New_Internal_Name ('J')),
2535 Aliased_Present => True,
2536 Object_Definition =>
2537 New_Reference_To (Etype (Formal), Loc));
2538
2539 -- We have to make an assignment statement separate for
2540 -- the case of limited type. We can not assign it unless
2541 -- the Assignment_OK flag is set first.
2542
2543 if Ekind (Formal) /= E_Out_Parameter then
2544 N_Var :=
2545 New_Reference_To (Defining_Identifier (N_Node), Loc);
2546 Set_Assignment_OK (N_Var);
2547 Append_To (Stats,
2548 Make_Assignment_Statement (Loc,
2549 Name => N_Var,
2550 Expression => Relocate_Node (Actual)));
2551 end if;
2552
2553 Append (N_Node, Decls);
2554
2555 Append_To (Plist,
2556 Make_Attribute_Reference (Loc,
2557 Attribute_Name => Name_Unchecked_Access,
2558 Prefix =>
2559 New_Reference_To (Defining_Identifier (N_Node), Loc)));
2560 else
2561 Append_To (Plist,
2562 Make_Reference (Loc, Prefix => Relocate_Node (Actual)));
2563 end if;
2564
2565 Next_Actual (Actual);
2566 Next_Formal_With_Extras (Formal);
2567 end loop;
2568
2569 -- Now build the declaration of parameters initialized with the
2570 -- aggregate containing this constructed parameter list.
2571
2572 P := Make_Defining_Identifier (Loc, Name_uP);
2573
2574 Pdecl :=
2575 Make_Object_Declaration (Loc,
2576 Defining_Identifier => P,
2577 Object_Definition =>
2578 New_Reference_To (Designated_Type (Ent_Acc), Loc),
2579 Expression =>
2580 Make_Aggregate (Loc, Expressions => Plist));
2581
2582 Parm3 :=
2583 Make_Attribute_Reference (Loc,
2584 Attribute_Name => Name_Address,
2585 Prefix => New_Reference_To (P, Loc));
2586
2587 Append (Pdecl, Decls);
2588 end if;
2589
2590 -- Now we can create the call, case of protected type
2591
2592 if Is_Protected_Type (Conctyp) then
2593 if Abort_Allowed
2594 or else Restriction_Active (No_Entry_Queue) = False
2595 or else Number_Entries (Conctyp) > 1
2596 then
2597 -- Change the type of the index declaration
2598
2599 Set_Object_Definition (Xdecl,
2600 New_Reference_To (RTE (RE_Protected_Entry_Index), Loc));
2601
2602 -- Some additional declarations for protected entry calls
2603
2604 if No (Decls) then
2605 Decls := New_List;
2606 end if;
2607
2608 -- Bnn : Communications_Block;
2609
2610 Comm_Name :=
2611 Make_Defining_Identifier (Loc, New_Internal_Name ('B'));
2612
2613 Append_To (Decls,
2614 Make_Object_Declaration (Loc,
2615 Defining_Identifier => Comm_Name,
2616 Object_Definition =>
2617 New_Reference_To (RTE (RE_Communication_Block), Loc)));
2618
2619 -- Some additional statements for protected entry calls
2620
2621 -- Protected_Entry_Call (
2622 -- Object => po._object'Access,
2623 -- E => <entry index>;
2624 -- Uninterpreted_Data => P'Address;
2625 -- Mode => Simple_Call;
2626 -- Block => Bnn);
2627
2628 Call :=
2629 Make_Procedure_Call_Statement (Loc,
2630 Name =>
2631 New_Reference_To (RTE (RE_Protected_Entry_Call), Loc),
2632
2633 Parameter_Associations => New_List (
2634 Make_Attribute_Reference (Loc,
2635 Attribute_Name => Name_Unchecked_Access,
2636 Prefix => Parm1),
2637 Parm2,
2638 Parm3,
2639 New_Reference_To (RTE (RE_Simple_Call), Loc),
2640 New_Occurrence_Of (Comm_Name, Loc)));
2641
2642 else
2643 -- Protected_Single_Entry_Call (
2644 -- Object => po._object'Access,
2645 -- Uninterpreted_Data => P'Address;
2646 -- Mode => Simple_Call);
2647
2648 Call :=
2649 Make_Procedure_Call_Statement (Loc,
2650 Name => New_Reference_To (
2651 RTE (RE_Protected_Single_Entry_Call), Loc),
2652
2653 Parameter_Associations => New_List (
2654 Make_Attribute_Reference (Loc,
2655 Attribute_Name => Name_Unchecked_Access,
2656 Prefix => Parm1),
2657 Parm3,
2658 New_Reference_To (RTE (RE_Simple_Call), Loc)));
2659 end if;
2660
2661 -- Case of task type
2662
2663 else
2664 Call :=
2665 Make_Procedure_Call_Statement (Loc,
2666 Name => New_Reference_To (RTE (RE_Call_Simple), Loc),
2667 Parameter_Associations => New_List (Parm1, Parm2, Parm3));
2668
2669 end if;
2670
2671 Append_To (Stats, Call);
2672
2673 -- If there are out or in/out parameters by copy
2674 -- add assignment statements for the result values.
2675
2676 if Present (Parms) then
2677 Actual := First_Actual (N);
2678 Formal := First_Formal (Ent);
2679
2680 Set_Assignment_OK (Actual);
2681 while Present (Actual) loop
2682 if Is_By_Copy_Type (Etype (Actual))
2683 and then Ekind (Formal) /= E_In_Parameter
2684 then
2685 N_Node :=
2686 Make_Assignment_Statement (Loc,
2687 Name => New_Copy (Actual),
2688 Expression =>
2689 Make_Explicit_Dereference (Loc,
2690 Make_Selected_Component (Loc,
2691 Prefix => New_Reference_To (P, Loc),
2692 Selector_Name =>
2693 Make_Identifier (Loc, Chars (Formal)))));
2694
2695 -- In all cases (including limited private types) we
2696 -- want the assignment to be valid.
2697
2698 Set_Assignment_OK (Name (N_Node));
2699
2700 -- If the call is the triggering alternative in an
2701 -- asynchronous select, or the entry_call alternative
2702 -- of a conditional entry call, the assignments for in-out
2703 -- parameters are incorporated into the statement list
2704 -- that follows, so that there are executed only if the
2705 -- entry call succeeds.
2706
2707 if (Nkind (Parent (N)) = N_Triggering_Alternative
2708 and then N = Triggering_Statement (Parent (N)))
2709 or else
2710 (Nkind (Parent (N)) = N_Entry_Call_Alternative
2711 and then N = Entry_Call_Statement (Parent (N)))
2712 then
2713 if No (Statements (Parent (N))) then
2714 Set_Statements (Parent (N), New_List);
2715 end if;
2716
2717 Prepend (N_Node, Statements (Parent (N)));
2718
2719 else
2720 Insert_After (Call, N_Node);
2721 end if;
2722 end if;
2723
2724 Next_Actual (Actual);
2725 Next_Formal_With_Extras (Formal);
2726 end loop;
2727 end if;
2728
2729 -- Finally, create block and analyze it
2730
2731 Rewrite (N,
2732 Make_Block_Statement (Loc,
2733 Declarations => Decls,
2734 Handled_Statement_Sequence =>
2735 Make_Handled_Sequence_Of_Statements (Loc,
2736 Statements => Stats)));
2737
2738 Analyze (N);
2739 end;
2740 end Build_Simple_Entry_Call;
2741
2742 --------------------------------
2743 -- Build_Task_Activation_Call --
2744 --------------------------------
2745
2746 procedure Build_Task_Activation_Call (N : Node_Id) is
2747 Loc : constant Source_Ptr := Sloc (N);
2748 Chain : Entity_Id;
2749 Call : Node_Id;
2750 Name : Node_Id;
2751 P : Node_Id;
2752
2753 begin
2754 -- Get the activation chain entity. Except in the case of a package
2755 -- body, this is in the node that w as passed. For a package body, we
2756 -- have to find the corresponding package declaration node.
2757
2758 if Nkind (N) = N_Package_Body then
2759 P := Corresponding_Spec (N);
2760
2761 loop
2762 P := Parent (P);
2763 exit when Nkind (P) = N_Package_Declaration;
2764 end loop;
2765
2766 Chain := Activation_Chain_Entity (P);
2767
2768 else
2769 Chain := Activation_Chain_Entity (N);
2770 end if;
2771
2772 if Present (Chain) then
2773 if Restricted_Profile then
2774 Name := New_Reference_To (RTE (RE_Activate_Restricted_Tasks), Loc);
2775 else
2776 Name := New_Reference_To (RTE (RE_Activate_Tasks), Loc);
2777 end if;
2778
2779 Call :=
2780 Make_Procedure_Call_Statement (Loc,
2781 Name => Name,
2782 Parameter_Associations =>
2783 New_List (Make_Attribute_Reference (Loc,
2784 Prefix => New_Occurrence_Of (Chain, Loc),
2785 Attribute_Name => Name_Unchecked_Access)));
2786
2787 if Nkind (N) = N_Package_Declaration then
2788 if Present (Corresponding_Body (N)) then
2789 null;
2790
2791 elsif Present (Private_Declarations (Specification (N))) then
2792 Append (Call, Private_Declarations (Specification (N)));
2793
2794 else
2795 Append (Call, Visible_Declarations (Specification (N)));
2796 end if;
2797
2798 else
2799 if Present (Handled_Statement_Sequence (N)) then
2800
2801 -- The call goes at the start of the statement sequence, but
2802 -- after the start of exception range label if one is present.
2803
2804 declare
2805 Stm : Node_Id;
2806
2807 begin
2808 Stm := First (Statements (Handled_Statement_Sequence (N)));
2809
2810 if Nkind (Stm) = N_Label and then Exception_Junk (Stm) then
2811 Next (Stm);
2812 end if;
2813
2814 Insert_Before (Stm, Call);
2815 end;
2816
2817 else
2818 Set_Handled_Statement_Sequence (N,
2819 Make_Handled_Sequence_Of_Statements (Loc,
2820 Statements => New_List (Call)));
2821 end if;
2822 end if;
2823
2824 Analyze (Call);
2825 Check_Task_Activation (N);
2826 end if;
2827 end Build_Task_Activation_Call;
2828
2829 -------------------------------
2830 -- Build_Task_Allocate_Block --
2831 -------------------------------
2832
2833 procedure Build_Task_Allocate_Block
2834 (Actions : List_Id;
2835 N : Node_Id;
2836 Args : List_Id)
2837 is
2838 T : constant Entity_Id := Entity (Expression (N));
2839 Init : constant Entity_Id := Base_Init_Proc (T);
2840 Loc : constant Source_Ptr := Sloc (N);
2841 Chain : constant Entity_Id :=
2842 Make_Defining_Identifier (Loc, Name_uChain);
2843
2844 Blkent : Entity_Id;
2845 Block : Node_Id;
2846
2847 begin
2848 Blkent := Make_Defining_Identifier (Loc, New_Internal_Name ('A'));
2849
2850 Block :=
2851 Make_Block_Statement (Loc,
2852 Identifier => New_Reference_To (Blkent, Loc),
2853 Declarations => New_List (
2854
2855 -- _Chain : Activation_Chain;
2856
2857 Make_Object_Declaration (Loc,
2858 Defining_Identifier => Chain,
2859 Aliased_Present => True,
2860 Object_Definition =>
2861 New_Reference_To (RTE (RE_Activation_Chain), Loc))),
2862
2863 Handled_Statement_Sequence =>
2864 Make_Handled_Sequence_Of_Statements (Loc,
2865
2866 Statements => New_List (
2867
2868 -- Init (Args);
2869
2870 Make_Procedure_Call_Statement (Loc,
2871 Name => New_Reference_To (Init, Loc),
2872 Parameter_Associations => Args),
2873
2874 -- Activate_Tasks (_Chain);
2875
2876 Make_Procedure_Call_Statement (Loc,
2877 Name => New_Reference_To (RTE (RE_Activate_Tasks), Loc),
2878 Parameter_Associations => New_List (
2879 Make_Attribute_Reference (Loc,
2880 Prefix => New_Reference_To (Chain, Loc),
2881 Attribute_Name => Name_Unchecked_Access))))),
2882
2883 Has_Created_Identifier => True,
2884 Is_Task_Allocation_Block => True);
2885
2886 Append_To (Actions,
2887 Make_Implicit_Label_Declaration (Loc,
2888 Defining_Identifier => Blkent,
2889 Label_Construct => Block));
2890
2891 Append_To (Actions, Block);
2892
2893 Set_Activation_Chain_Entity (Block, Chain);
2894 end Build_Task_Allocate_Block;
2895
2896 -----------------------------------------------
2897 -- Build_Task_Allocate_Block_With_Init_Stmts --
2898 -----------------------------------------------
2899
2900 procedure Build_Task_Allocate_Block_With_Init_Stmts
2901 (Actions : List_Id;
2902 N : Node_Id;
2903 Init_Stmts : List_Id)
2904 is
2905 Loc : constant Source_Ptr := Sloc (N);
2906 Chain : constant Entity_Id :=
2907 Make_Defining_Identifier (Loc, Name_uChain);
2908 Blkent : Entity_Id;
2909 Block : Node_Id;
2910
2911 begin
2912 Blkent := Make_Defining_Identifier (Loc, New_Internal_Name ('A'));
2913
2914 Append_To (Init_Stmts,
2915 Make_Procedure_Call_Statement (Loc,
2916 Name => New_Reference_To (RTE (RE_Activate_Tasks), Loc),
2917 Parameter_Associations => New_List (
2918 Make_Attribute_Reference (Loc,
2919 Prefix => New_Reference_To (Chain, Loc),
2920 Attribute_Name => Name_Unchecked_Access))));
2921
2922 Block :=
2923 Make_Block_Statement (Loc,
2924 Identifier => New_Reference_To (Blkent, Loc),
2925 Declarations => New_List (
2926
2927 -- _Chain : Activation_Chain;
2928
2929 Make_Object_Declaration (Loc,
2930 Defining_Identifier => Chain,
2931 Aliased_Present => True,
2932 Object_Definition =>
2933 New_Reference_To (RTE (RE_Activation_Chain), Loc))),
2934
2935 Handled_Statement_Sequence =>
2936 Make_Handled_Sequence_Of_Statements (Loc, Init_Stmts),
2937
2938 Has_Created_Identifier => True,
2939 Is_Task_Allocation_Block => True);
2940
2941 Append_To (Actions,
2942 Make_Implicit_Label_Declaration (Loc,
2943 Defining_Identifier => Blkent,
2944 Label_Construct => Block));
2945
2946 Append_To (Actions, Block);
2947
2948 Set_Activation_Chain_Entity (Block, Chain);
2949 end Build_Task_Allocate_Block_With_Init_Stmts;
2950
2951 -----------------------------------
2952 -- Build_Task_Proc_Specification --
2953 -----------------------------------
2954
2955 function Build_Task_Proc_Specification (T : Entity_Id) return Node_Id is
2956 Loc : constant Source_Ptr := Sloc (T);
2957 Nam : constant Name_Id := Chars (T);
2958 Ent : Entity_Id;
2959
2960 begin
2961 Ent :=
2962 Make_Defining_Identifier (Loc,
2963 Chars => New_External_Name (Nam, 'B'));
2964 Set_Is_Internal (Ent);
2965
2966 -- Associate the procedure with the task, if this is the declaration
2967 -- (and not the body) of the procedure.
2968
2969 if No (Task_Body_Procedure (T)) then
2970 Set_Task_Body_Procedure (T, Ent);
2971 end if;
2972
2973 return
2974 Make_Procedure_Specification (Loc,
2975 Defining_Unit_Name => Ent,
2976 Parameter_Specifications =>
2977 New_List (
2978 Make_Parameter_Specification (Loc,
2979 Defining_Identifier =>
2980 Make_Defining_Identifier (Loc, Name_uTask),
2981 Parameter_Type =>
2982 Make_Access_Definition (Loc,
2983 Subtype_Mark =>
2984 New_Reference_To
2985 (Corresponding_Record_Type (T), Loc)))));
2986 end Build_Task_Proc_Specification;
2987
2988 ---------------------------------------
2989 -- Build_Unprotected_Subprogram_Body --
2990 ---------------------------------------
2991
2992 function Build_Unprotected_Subprogram_Body
2993 (N : Node_Id;
2994 Pid : Node_Id) return Node_Id
2995 is
2996 Loc : constant Source_Ptr := Sloc (N);
2997 N_Op_Spec : Node_Id;
2998 Op_Decls : List_Id;
2999
3000 begin
3001 -- Make an unprotected version of the subprogram for use
3002 -- within the same object, with a new name and an additional
3003 -- parameter representing the object.
3004
3005 Op_Decls := Declarations (N);
3006 N_Op_Spec :=
3007 Build_Protected_Sub_Specification
3008 (N, Pid, Unprotected => True);
3009
3010 return
3011 Make_Subprogram_Body (Loc,
3012 Specification => N_Op_Spec,
3013 Declarations => Op_Decls,
3014 Handled_Statement_Sequence =>
3015 Handled_Statement_Sequence (N));
3016 end Build_Unprotected_Subprogram_Body;
3017
3018 ----------------------------
3019 -- Collect_Entry_Families --
3020 ----------------------------
3021
3022 procedure Collect_Entry_Families
3023 (Loc : Source_Ptr;
3024 Cdecls : List_Id;
3025 Current_Node : in out Node_Id;
3026 Conctyp : Entity_Id)
3027 is
3028 Efam : Entity_Id;
3029 Efam_Decl : Node_Id;
3030 Efam_Type : Entity_Id;
3031
3032 begin
3033 Efam := First_Entity (Conctyp);
3034
3035 while Present (Efam) loop
3036
3037 if Ekind (Efam) = E_Entry_Family then
3038 Efam_Type :=
3039 Make_Defining_Identifier (Loc,
3040 Chars => New_Internal_Name ('F'));
3041
3042 Efam_Decl :=
3043 Make_Full_Type_Declaration (Loc,
3044 Defining_Identifier => Efam_Type,
3045 Type_Definition =>
3046 Make_Unconstrained_Array_Definition (Loc,
3047 Subtype_Marks => (New_List (
3048 New_Occurrence_Of (
3049 Base_Type
3050 (Etype (Discrete_Subtype_Definition
3051 (Parent (Efam)))), Loc))),
3052
3053 Component_Definition =>
3054 Make_Component_Definition (Loc,
3055 Aliased_Present => False,
3056 Subtype_Indication =>
3057 New_Reference_To (Standard_Character, Loc))));
3058
3059 Insert_After (Current_Node, Efam_Decl);
3060 Current_Node := Efam_Decl;
3061 Analyze (Efam_Decl);
3062
3063 Append_To (Cdecls,
3064 Make_Component_Declaration (Loc,
3065 Defining_Identifier =>
3066 Make_Defining_Identifier (Loc, Chars (Efam)),
3067
3068 Component_Definition =>
3069 Make_Component_Definition (Loc,
3070 Aliased_Present => False,
3071 Subtype_Indication =>
3072 Make_Subtype_Indication (Loc,
3073 Subtype_Mark =>
3074 New_Occurrence_Of (Efam_Type, Loc),
3075
3076 Constraint =>
3077 Make_Index_Or_Discriminant_Constraint (Loc,
3078 Constraints => New_List (
3079 New_Occurrence_Of
3080 (Etype (Discrete_Subtype_Definition
3081 (Parent (Efam))), Loc)))))));
3082
3083 end if;
3084
3085 Next_Entity (Efam);
3086 end loop;
3087 end Collect_Entry_Families;
3088
3089 --------------------
3090 -- Concurrent_Ref --
3091 --------------------
3092
3093 -- The expression returned for a reference to a concurrent
3094 -- object has the form:
3095
3096 -- taskV!(name)._Task_Id
3097
3098 -- for a task, and
3099
3100 -- objectV!(name)._Object
3101
3102 -- for a protected object. For the case of an access to a concurrent
3103 -- object, there is an extra explicit dereference:
3104
3105 -- taskV!(name.all)._Task_Id
3106 -- objectV!(name.all)._Object
3107
3108 -- here taskV and objectV are the types for the associated records, which
3109 -- contain the required _Task_Id and _Object fields for tasks and
3110 -- protected objects, respectively.
3111
3112 -- For the case of a task type name, the expression is
3113
3114 -- Self;
3115
3116 -- i.e. a call to the Self function which returns precisely this Task_Id
3117
3118 -- For the case of a protected type name, the expression is
3119
3120 -- objectR
3121
3122 -- which is a renaming of the _object field of the current object
3123 -- object record, passed into protected operations as a parameter.
3124
3125 function Concurrent_Ref (N : Node_Id) return Node_Id is
3126 Loc : constant Source_Ptr := Sloc (N);
3127 Ntyp : constant Entity_Id := Etype (N);
3128 Dtyp : Entity_Id;
3129 Sel : Name_Id;
3130
3131 function Is_Current_Task (T : Entity_Id) return Boolean;
3132 -- Check whether the reference is to the immediately enclosing task
3133 -- type, or to an outer one (rare but legal).
3134
3135 ---------------------
3136 -- Is_Current_Task --
3137 ---------------------
3138
3139 function Is_Current_Task (T : Entity_Id) return Boolean is
3140 Scop : Entity_Id;
3141
3142 begin
3143 Scop := Current_Scope;
3144 while Present (Scop)
3145 and then Scop /= Standard_Standard
3146 loop
3147
3148 if Scop = T then
3149 return True;
3150
3151 elsif Is_Task_Type (Scop) then
3152 return False;
3153
3154 -- If this is a procedure nested within the task type, we must
3155 -- assume that it can be called from an inner task, and therefore
3156 -- cannot treat it as a local reference.
3157
3158 elsif Is_Overloadable (Scop)
3159 and then In_Open_Scopes (T)
3160 then
3161 return False;
3162
3163 else
3164 Scop := Scope (Scop);
3165 end if;
3166 end loop;
3167
3168 -- We know that we are within the task body, so should have
3169 -- found it in scope.
3170
3171 raise Program_Error;
3172 end Is_Current_Task;
3173
3174 -- Start of processing for Concurrent_Ref
3175
3176 begin
3177 if Is_Access_Type (Ntyp) then
3178 Dtyp := Designated_Type (Ntyp);
3179
3180 if Is_Protected_Type (Dtyp) then
3181 Sel := Name_uObject;
3182 else
3183 Sel := Name_uTask_Id;
3184 end if;
3185
3186 return
3187 Make_Selected_Component (Loc,
3188 Prefix =>
3189 Unchecked_Convert_To (Corresponding_Record_Type (Dtyp),
3190 Make_Explicit_Dereference (Loc, N)),
3191 Selector_Name => Make_Identifier (Loc, Sel));
3192
3193 elsif Is_Entity_Name (N)
3194 and then Is_Concurrent_Type (Entity (N))
3195 then
3196 if Is_Task_Type (Entity (N)) then
3197
3198 if Is_Current_Task (Entity (N)) then
3199 return
3200 Make_Function_Call (Loc,
3201 Name => New_Reference_To (RTE (RE_Self), Loc));
3202
3203 else
3204 declare
3205 Decl : Node_Id;
3206 T_Self : constant Entity_Id
3207 := Make_Defining_Identifier (Loc, New_Internal_Name ('T'));
3208 T_Body : constant Node_Id
3209 := Parent (Corresponding_Body (Parent (Entity (N))));
3210
3211 begin
3212 Decl := Make_Object_Declaration (Loc,
3213 Defining_Identifier => T_Self,
3214 Object_Definition =>
3215 New_Occurrence_Of (RTE (RO_ST_Task_Id), Loc),
3216 Expression =>
3217 Make_Function_Call (Loc,
3218 Name => New_Reference_To (RTE (RE_Self), Loc)));
3219 Prepend (Decl, Declarations (T_Body));
3220 Analyze (Decl);
3221 Set_Scope (T_Self, Entity (N));
3222 return New_Occurrence_Of (T_Self, Loc);
3223 end;
3224 end if;
3225
3226 else
3227 pragma Assert (Is_Protected_Type (Entity (N)));
3228 return
3229 New_Reference_To (
3230 Object_Ref (Corresponding_Body (Parent (Base_Type (Ntyp)))),
3231 Loc);
3232 end if;
3233
3234 else
3235 pragma Assert (Is_Concurrent_Type (Ntyp));
3236
3237 if Is_Protected_Type (Ntyp) then
3238 Sel := Name_uObject;
3239 else
3240 Sel := Name_uTask_Id;
3241 end if;
3242
3243 return
3244 Make_Selected_Component (Loc,
3245 Prefix =>
3246 Unchecked_Convert_To (Corresponding_Record_Type (Ntyp),
3247 New_Copy_Tree (N)),
3248 Selector_Name => Make_Identifier (Loc, Sel));
3249 end if;
3250 end Concurrent_Ref;
3251
3252 ------------------------
3253 -- Convert_Concurrent --
3254 ------------------------
3255
3256 function Convert_Concurrent
3257 (N : Node_Id;
3258 Typ : Entity_Id) return Node_Id
3259 is
3260 begin
3261 if not Is_Concurrent_Type (Typ) then
3262 return N;
3263 else
3264 return
3265 Unchecked_Convert_To (Corresponding_Record_Type (Typ),
3266 New_Copy_Tree (N));
3267 end if;
3268 end Convert_Concurrent;
3269
3270 ----------------------------
3271 -- Entry_Index_Expression --
3272 ----------------------------
3273
3274 function Entry_Index_Expression
3275 (Sloc : Source_Ptr;
3276 Ent : Entity_Id;
3277 Index : Node_Id;
3278 Ttyp : Entity_Id) return Node_Id
3279 is
3280 Expr : Node_Id;
3281 Num : Node_Id;
3282 Lo : Node_Id;
3283 Hi : Node_Id;
3284 Prev : Entity_Id;
3285 S : Node_Id;
3286
3287 begin
3288 -- The queues of entries and entry families appear in textual
3289 -- order in the associated record. The entry index is computed as
3290 -- the sum of the number of queues for all entries that precede the
3291 -- designated one, to which is added the index expression, if this
3292 -- expression denotes a member of a family.
3293
3294 -- The following is a place holder for the count of simple entries
3295
3296 Num := Make_Integer_Literal (Sloc, 1);
3297
3298 -- We construct an expression which is a series of addition
3299 -- operations. The first operand is the number of single entries that
3300 -- precede this one, the second operand is the index value relative
3301 -- to the start of the referenced family, and the remaining operands
3302 -- are the lengths of the entry families that precede this entry, i.e.
3303 -- the constructed expression is:
3304
3305 -- number_simple_entries +
3306 -- (s'pos (index-value) - s'pos (family'first)) + 1 +
3307 -- family'length + ...
3308
3309 -- where index-value is the given index value, and s is the index
3310 -- subtype (we have to use pos because the subtype might be an
3311 -- enumeration type preventing direct subtraction).
3312 -- Note that the task entry array is one-indexed.
3313
3314 -- The upper bound of the entry family may be a discriminant, so we
3315 -- retrieve the lower bound explicitly to compute offset, rather than
3316 -- using the index subtype which may mention a discriminant.
3317
3318 if Present (Index) then
3319 S := Etype (Discrete_Subtype_Definition (Declaration_Node (Ent)));
3320
3321 Expr :=
3322 Make_Op_Add (Sloc,
3323 Left_Opnd => Num,
3324
3325 Right_Opnd =>
3326 Family_Offset (
3327 Sloc,
3328 Make_Attribute_Reference (Sloc,
3329 Attribute_Name => Name_Pos,
3330 Prefix => New_Reference_To (Base_Type (S), Sloc),
3331 Expressions => New_List (Relocate_Node (Index))),
3332 Type_Low_Bound (S),
3333 Ttyp));
3334 else
3335 Expr := Num;
3336 end if;
3337
3338 -- Now add lengths of preceding entries and entry families
3339
3340 Prev := First_Entity (Ttyp);
3341
3342 while Chars (Prev) /= Chars (Ent)
3343 or else (Ekind (Prev) /= Ekind (Ent))
3344 or else not Sem_Ch6.Type_Conformant (Ent, Prev)
3345 loop
3346 if Ekind (Prev) = E_Entry then
3347 Set_Intval (Num, Intval (Num) + 1);
3348
3349 elsif Ekind (Prev) = E_Entry_Family then
3350 S :=
3351 Etype (Discrete_Subtype_Definition (Declaration_Node (Prev)));
3352 Lo := Type_Low_Bound (S);
3353 Hi := Type_High_Bound (S);
3354
3355 Expr :=
3356 Make_Op_Add (Sloc,
3357 Left_Opnd => Expr,
3358 Right_Opnd => Family_Size (Sloc, Hi, Lo, Ttyp));
3359
3360 -- Other components are anonymous types to be ignored
3361
3362 else
3363 null;
3364 end if;
3365
3366 Next_Entity (Prev);
3367 end loop;
3368
3369 return Expr;
3370 end Entry_Index_Expression;
3371
3372 ---------------------------
3373 -- Establish_Task_Master --
3374 ---------------------------
3375
3376 procedure Establish_Task_Master (N : Node_Id) is
3377 Call : Node_Id;
3378
3379 begin
3380 if Restriction_Active (No_Task_Hierarchy) = False then
3381 Call := Build_Runtime_Call (Sloc (N), RE_Enter_Master);
3382 Prepend_To (Declarations (N), Call);
3383 Analyze (Call);
3384 end if;
3385 end Establish_Task_Master;
3386
3387 --------------------------------
3388 -- Expand_Accept_Declarations --
3389 --------------------------------
3390
3391 -- Part of the expansion of an accept statement involves the creation of
3392 -- a declaration that can be referenced from the statement sequence of
3393 -- the accept:
3394
3395 -- Ann : Address;
3396
3397 -- This declaration is inserted immediately before the accept statement
3398 -- and it is important that it be inserted before the statements of the
3399 -- statement sequence are analyzed. Thus it would be too late to create
3400 -- this declaration in the Expand_N_Accept_Statement routine, which is
3401 -- why there is a separate procedure to be called directly from Sem_Ch9.
3402
3403 -- Ann is used to hold the address of the record containing the parameters
3404 -- (see Expand_N_Entry_Call for more details on how this record is built).
3405 -- References to the parameters do an unchecked conversion of this address
3406 -- to a pointer to the required record type, and then access the field that
3407 -- holds the value of the required parameter. The entity for the address
3408 -- variable is held as the top stack element (i.e. the last element) of the
3409 -- Accept_Address stack in the corresponding entry entity, and this element
3410 -- must be set in place before the statements are processed.
3411
3412 -- The above description applies to the case of a stand alone accept
3413 -- statement, i.e. one not appearing as part of a select alternative.
3414
3415 -- For the case of an accept that appears as part of a select alternative
3416 -- of a selective accept, we must still create the declaration right away,
3417 -- since Ann is needed immediately, but there is an important difference:
3418
3419 -- The declaration is inserted before the selective accept, not before
3420 -- the accept statement (which is not part of a list anyway, and so would
3421 -- not accommodate inserted declarations)
3422
3423 -- We only need one address variable for the entire selective accept. So
3424 -- the Ann declaration is created only for the first accept alternative,
3425 -- and subsequent accept alternatives reference the same Ann variable.
3426
3427 -- We can distinguish the two cases by seeing whether the accept statement
3428 -- is part of a list. If not, then it must be in an accept alternative.
3429
3430 -- To expand the requeue statement, a label is provided at the end of
3431 -- the accept statement or alternative of which it is a part, so that
3432 -- the statement can be skipped after the requeue is complete.
3433 -- This label is created here rather than during the expansion of the
3434 -- accept statement, because it will be needed by any requeue
3435 -- statements within the accept, which are expanded before the
3436 -- accept.
3437
3438 procedure Expand_Accept_Declarations (N : Node_Id; Ent : Entity_Id) is
3439 Loc : constant Source_Ptr := Sloc (N);
3440 Ann : Entity_Id := Empty;
3441 Adecl : Node_Id;
3442 Lab_Id : Node_Id;
3443 Lab : Node_Id;
3444 Ldecl : Node_Id;
3445 Ldecl2 : Node_Id;
3446
3447 begin
3448 if Expander_Active then
3449
3450 -- If we have no handled statement sequence, then build a dummy
3451 -- sequence consisting of a null statement. This is only done if
3452 -- pragma FIFO_Within_Priorities is specified. The issue here is
3453 -- that even a null accept body has an effect on the called task
3454 -- in terms of its position in the queue, so we cannot optimize
3455 -- the context switch away. However, if FIFO_Within_Priorities
3456 -- is not active, the optimization is legitimate, since we can
3457 -- say that our dispatching policy (i.e. the default dispatching
3458 -- policy) reorders the queue to be the same as just before the
3459 -- call. In the absence of a specified dispatching policy, we are
3460 -- allowed to modify queue orders for a given priority at will!
3461
3462 if Opt.Task_Dispatching_Policy = 'F' and then
3463 not Present (Handled_Statement_Sequence (N))
3464 then
3465 Set_Handled_Statement_Sequence (N,
3466 Make_Handled_Sequence_Of_Statements (Loc,
3467 New_List (Make_Null_Statement (Loc))));
3468 end if;
3469
3470 -- Create and declare two labels to be placed at the end of the
3471 -- accept statement. The first label is used to allow requeues to
3472 -- skip the remainder of entry processing. The second label is
3473 -- used to skip the remainder of entry processing if the rendezvous
3474 -- completes in the middle of the accept body.
3475
3476 if Present (Handled_Statement_Sequence (N)) then
3477 Lab_Id := Make_Identifier (Loc, New_Internal_Name ('L'));
3478 Set_Entity (Lab_Id,
3479 Make_Defining_Identifier (Loc, Chars (Lab_Id)));
3480 Lab := Make_Label (Loc, Lab_Id);
3481 Ldecl :=
3482 Make_Implicit_Label_Declaration (Loc,
3483 Defining_Identifier => Entity (Lab_Id),
3484 Label_Construct => Lab);
3485 Append (Lab, Statements (Handled_Statement_Sequence (N)));
3486
3487 Lab_Id := Make_Identifier (Loc, New_Internal_Name ('L'));
3488 Set_Entity (Lab_Id,
3489 Make_Defining_Identifier (Loc, Chars (Lab_Id)));
3490 Lab := Make_Label (Loc, Lab_Id);
3491 Ldecl2 :=
3492 Make_Implicit_Label_Declaration (Loc,
3493 Defining_Identifier => Entity (Lab_Id),
3494 Label_Construct => Lab);
3495 Append (Lab, Statements (Handled_Statement_Sequence (N)));
3496
3497 else
3498 Ldecl := Empty;
3499 Ldecl2 := Empty;
3500 end if;
3501
3502 -- Case of stand alone accept statement
3503
3504 if Is_List_Member (N) then
3505
3506 if Present (Handled_Statement_Sequence (N)) then
3507 Ann :=
3508 Make_Defining_Identifier (Loc,
3509 Chars => New_Internal_Name ('A'));
3510
3511 Adecl :=
3512 Make_Object_Declaration (Loc,
3513 Defining_Identifier => Ann,
3514 Object_Definition =>
3515 New_Reference_To (RTE (RE_Address), Loc));
3516
3517 Insert_Before (N, Adecl);
3518 Analyze (Adecl);
3519
3520 Insert_Before (N, Ldecl);
3521 Analyze (Ldecl);
3522
3523 Insert_Before (N, Ldecl2);
3524 Analyze (Ldecl2);
3525 end if;
3526
3527 -- Case of accept statement which is in an accept alternative
3528
3529 else
3530 declare
3531 Acc_Alt : constant Node_Id := Parent (N);
3532 Sel_Acc : constant Node_Id := Parent (Acc_Alt);
3533 Alt : Node_Id;
3534
3535 begin
3536 pragma Assert (Nkind (Acc_Alt) = N_Accept_Alternative);
3537 pragma Assert (Nkind (Sel_Acc) = N_Selective_Accept);
3538
3539 -- ??? Consider a single label for select statements
3540
3541 if Present (Handled_Statement_Sequence (N)) then
3542 Prepend (Ldecl2,
3543 Statements (Handled_Statement_Sequence (N)));
3544 Analyze (Ldecl2);
3545
3546 Prepend (Ldecl,
3547 Statements (Handled_Statement_Sequence (N)));
3548 Analyze (Ldecl);
3549 end if;
3550
3551 -- Find first accept alternative of the selective accept. A
3552 -- valid selective accept must have at least one accept in it.
3553
3554 Alt := First (Select_Alternatives (Sel_Acc));
3555
3556 while Nkind (Alt) /= N_Accept_Alternative loop
3557 Next (Alt);
3558 end loop;
3559
3560 -- If we are the first accept statement, then we have to
3561 -- create the Ann variable, as for the stand alone case,
3562 -- except that it is inserted before the selective accept.
3563 -- Similarly, a label for requeue expansion must be
3564 -- declared.
3565
3566 if N = Accept_Statement (Alt) then
3567 Ann :=
3568 Make_Defining_Identifier (Loc, New_Internal_Name ('A'));
3569
3570 Adecl :=
3571 Make_Object_Declaration (Loc,
3572 Defining_Identifier => Ann,
3573 Object_Definition =>
3574 New_Reference_To (RTE (RE_Address), Loc));
3575
3576 Insert_Before (Sel_Acc, Adecl);
3577 Analyze (Adecl);
3578
3579 -- If we are not the first accept statement, then find the
3580 -- Ann variable allocated by the first accept and use it.
3581
3582 else
3583 Ann :=
3584 Node (Last_Elmt (Accept_Address
3585 (Entity (Entry_Direct_Name (Accept_Statement (Alt))))));
3586 end if;
3587 end;
3588 end if;
3589
3590 -- Merge here with Ann either created or referenced, and Adecl
3591 -- pointing to the corresponding declaration. Remaining processing
3592 -- is the same for the two cases.
3593
3594 if Present (Ann) then
3595 Append_Elmt (Ann, Accept_Address (Ent));
3596 Set_Needs_Debug_Info (Ann);
3597 end if;
3598
3599 -- Create renaming declarations for the entry formals. Each
3600 -- reference to a formal becomes a dereference of a component
3601 -- of the parameter block, whose address is held in Ann.
3602 -- These declarations are eventually inserted into the accept
3603 -- block, and analyzed there so that they have the proper scope
3604 -- for gdb and do not conflict with other declarations.
3605
3606 if Present (Parameter_Specifications (N))
3607 and then Present (Handled_Statement_Sequence (N))
3608 then
3609 declare
3610 Formal : Entity_Id;
3611 New_F : Entity_Id;
3612 Comp : Entity_Id;
3613 Decl : Node_Id;
3614
3615 begin
3616 New_Scope (Ent);
3617 Formal := First_Formal (Ent);
3618
3619 while Present (Formal) loop
3620 Comp := Entry_Component (Formal);
3621 New_F :=
3622 Make_Defining_Identifier (Sloc (Formal), Chars (Formal));
3623 Set_Etype (New_F, Etype (Formal));
3624 Set_Scope (New_F, Ent);
3625 Set_Needs_Debug_Info (New_F); -- That's the whole point.
3626
3627 if Ekind (Formal) = E_In_Parameter then
3628 Set_Ekind (New_F, E_Constant);
3629 else
3630 Set_Ekind (New_F, E_Variable);
3631 Set_Extra_Constrained (New_F, Extra_Constrained (Formal));
3632 end if;
3633
3634 Set_Actual_Subtype (New_F, Actual_Subtype (Formal));
3635
3636 Decl :=
3637 Make_Object_Renaming_Declaration (Loc,
3638 Defining_Identifier => New_F,
3639 Subtype_Mark => New_Reference_To (Etype (Formal), Loc),
3640 Name =>
3641 Make_Explicit_Dereference (Loc,
3642 Make_Selected_Component (Loc,
3643 Prefix =>
3644 Unchecked_Convert_To (Entry_Parameters_Type (Ent),
3645 New_Reference_To (Ann, Loc)),
3646 Selector_Name =>
3647 New_Reference_To (Comp, Loc))));
3648
3649 if No (Declarations (N)) then
3650 Set_Declarations (N, New_List);
3651 end if;
3652
3653 Append (Decl, Declarations (N));
3654 Set_Renamed_Object (Formal, New_F);
3655 Next_Formal (Formal);
3656 end loop;
3657
3658 End_Scope;
3659 end;
3660 end if;
3661 end if;
3662 end Expand_Accept_Declarations;
3663
3664 ---------------------------------------------
3665 -- Expand_Access_Protected_Subprogram_Type --
3666 ---------------------------------------------
3667
3668 procedure Expand_Access_Protected_Subprogram_Type (N : Node_Id) is
3669 Loc : constant Source_Ptr := Sloc (N);
3670 Comps : List_Id;
3671 T : constant Entity_Id := Defining_Identifier (N);
3672 D_T : constant Entity_Id := Designated_Type (T);
3673 D_T2 : constant Entity_Id := Make_Defining_Identifier
3674 (Loc, New_Internal_Name ('D'));
3675 E_T : constant Entity_Id := Make_Defining_Identifier
3676 (Loc, New_Internal_Name ('E'));
3677 P_List : constant List_Id := Build_Protected_Spec
3678 (N, RTE (RE_Address), False, D_T);
3679 Decl1 : Node_Id;
3680 Decl2 : Node_Id;
3681 Def1 : Node_Id;
3682
3683 begin
3684 -- Create access to protected subprogram with full signature
3685
3686 if Nkind (Type_Definition (N)) = N_Access_Function_Definition then
3687 Def1 :=
3688 Make_Access_Function_Definition (Loc,
3689 Parameter_Specifications => P_List,
3690 Subtype_Mark => New_Copy (Subtype_Mark (Type_Definition (N))));
3691
3692 else
3693 Def1 :=
3694 Make_Access_Procedure_Definition (Loc,
3695 Parameter_Specifications => P_List);
3696 end if;
3697
3698 Decl1 :=
3699 Make_Full_Type_Declaration (Loc,
3700 Defining_Identifier => D_T2,
3701 Type_Definition => Def1);
3702
3703 Analyze (Decl1);
3704 Insert_After (N, Decl1);
3705
3706 -- Create Equivalent_Type, a record with two components for an
3707 -- access to object and an access to subprogram.
3708
3709 Comps := New_List (
3710 Make_Component_Declaration (Loc,
3711 Defining_Identifier =>
3712 Make_Defining_Identifier (Loc, New_Internal_Name ('P')),
3713 Component_Definition =>
3714 Make_Component_Definition (Loc,
3715 Aliased_Present => False,
3716 Subtype_Indication =>
3717 New_Occurrence_Of (RTE (RE_Address), Loc))),
3718
3719 Make_Component_Declaration (Loc,
3720 Defining_Identifier =>
3721 Make_Defining_Identifier (Loc, New_Internal_Name ('S')),
3722 Component_Definition =>
3723 Make_Component_Definition (Loc,
3724 Aliased_Present => False,
3725 Subtype_Indication => New_Occurrence_Of (D_T2, Loc))));
3726
3727 Decl2 :=
3728 Make_Full_Type_Declaration (Loc,
3729 Defining_Identifier => E_T,
3730 Type_Definition =>
3731 Make_Record_Definition (Loc,
3732 Component_List =>
3733 Make_Component_List (Loc,
3734 Component_Items => Comps)));
3735
3736 Analyze (Decl2);
3737 Insert_After (Decl1, Decl2);
3738 Set_Equivalent_Type (T, E_T);
3739 end Expand_Access_Protected_Subprogram_Type;
3740
3741 --------------------------
3742 -- Expand_Entry_Barrier --
3743 --------------------------
3744
3745 procedure Expand_Entry_Barrier (N : Node_Id; Ent : Entity_Id) is
3746 Loc : constant Source_Ptr := Sloc (N);
3747 Prot : constant Entity_Id := Scope (Ent);
3748 Spec_Decl : constant Node_Id := Parent (Prot);
3749 Cond : constant Node_Id :=
3750 Condition (Entry_Body_Formal_Part (N));
3751 Func : Node_Id;
3752 B_F : Node_Id;
3753 Body_Decl : Node_Id;
3754
3755 begin
3756 if No_Run_Time_Mode then
3757 Error_Msg_CRT ("entry barrier", N);
3758 return;
3759 end if;
3760
3761 -- The body of the entry barrier must be analyzed in the context of
3762 -- the protected object, but its scope is external to it, just as any
3763 -- other unprotected version of a protected operation. The specification
3764 -- has been produced when the protected type declaration was elaborated.
3765 -- We build the body, insert it in the enclosing scope, but analyze it
3766 -- in the current context. A more uniform approach would be to treat a
3767 -- barrier just as a protected function, and discard the protected
3768 -- version of it because it is never called.
3769
3770 if Expander_Active then
3771 B_F := Build_Barrier_Function (N, Ent, Prot);
3772 Func := Barrier_Function (Ent);
3773 Set_Corresponding_Spec (B_F, Func);
3774
3775 Body_Decl := Parent (Corresponding_Body (Spec_Decl));
3776
3777 if Nkind (Parent (Body_Decl)) = N_Subunit then
3778 Body_Decl := Corresponding_Stub (Parent (Body_Decl));
3779 end if;
3780
3781 Insert_Before_And_Analyze (Body_Decl, B_F);
3782
3783 Update_Prival_Subtypes (B_F);
3784
3785 Set_Privals (Spec_Decl, N, Loc);
3786 Set_Discriminals (Spec_Decl);
3787 Set_Scope (Func, Scope (Prot));
3788
3789 else
3790 Analyze_And_Resolve (Cond, Any_Boolean);
3791 end if;
3792
3793 -- The Ravenscar profile restricts barriers to simple variables
3794 -- declared within the protected object. We also allow Boolean
3795 -- constants, since these appear in several published examples
3796 -- and are also allowed by the Aonix compiler.
3797
3798 -- Note that after analysis variables in this context will be
3799 -- replaced by the corresponding prival, that is to say a renaming
3800 -- of a selected component of the form _Object.Var. If expansion is
3801 -- disabled, as within a generic, we check that the entity appears in
3802 -- the current scope.
3803
3804 if Is_Entity_Name (Cond) then
3805
3806 if Entity (Cond) = Standard_False
3807 or else
3808 Entity (Cond) = Standard_True
3809 then
3810 return;
3811
3812 elsif not Expander_Active
3813 and then Scope (Entity (Cond)) = Current_Scope
3814 then
3815 return;
3816
3817 -- Check for case of _object.all.field (note that the explicit
3818 -- dereference gets inserted by analyze/expand of _object.field)
3819
3820 elsif Present (Renamed_Object (Entity (Cond)))
3821 and then
3822 Nkind (Renamed_Object (Entity (Cond))) = N_Selected_Component
3823 and then
3824 Chars
3825 (Prefix
3826 (Prefix (Renamed_Object (Entity (Cond))))) = Name_uObject
3827 then
3828 return;
3829 end if;
3830 end if;
3831
3832 -- It is not a boolean variable or literal, so check the restriction
3833
3834 Check_Restriction (Simple_Barriers, Cond);
3835 end Expand_Entry_Barrier;
3836
3837 ------------------------------------
3838 -- Expand_Entry_Body_Declarations --
3839 ------------------------------------
3840
3841 procedure Expand_Entry_Body_Declarations (N : Node_Id) is
3842 Loc : constant Source_Ptr := Sloc (N);
3843 Index_Spec : Node_Id;
3844
3845 begin
3846 if Expander_Active then
3847
3848 -- Expand entry bodies corresponding to entry families
3849 -- by assigning a placeholder for the constant that will
3850 -- be used to expand references to the entry index parameter.
3851
3852 Index_Spec :=
3853 Entry_Index_Specification (Entry_Body_Formal_Part (N));
3854
3855 if Present (Index_Spec) then
3856 Set_Entry_Index_Constant (
3857 Defining_Identifier (Index_Spec),
3858 Make_Defining_Identifier (Loc, New_Internal_Name ('J')));
3859 end if;
3860 end if;
3861 end Expand_Entry_Body_Declarations;
3862
3863 ------------------------------
3864 -- Expand_N_Abort_Statement --
3865 ------------------------------
3866
3867 -- Expand abort T1, T2, .. Tn; into:
3868 -- Abort_Tasks (Task_List'(1 => T1.Task_Id, 2 => T2.Task_Id ...))
3869
3870 procedure Expand_N_Abort_Statement (N : Node_Id) is
3871 Loc : constant Source_Ptr := Sloc (N);
3872 Tlist : constant List_Id := Names (N);
3873 Count : Nat;
3874 Aggr : Node_Id;
3875 Tasknm : Node_Id;
3876
3877 begin
3878 Aggr := Make_Aggregate (Loc, Component_Associations => New_List);
3879 Count := 0;
3880
3881 Tasknm := First (Tlist);
3882
3883 while Present (Tasknm) loop
3884 Count := Count + 1;
3885 Append_To (Component_Associations (Aggr),
3886 Make_Component_Association (Loc,
3887 Choices => New_List (
3888 Make_Integer_Literal (Loc, Count)),
3889 Expression => Concurrent_Ref (Tasknm)));
3890 Next (Tasknm);
3891 end loop;
3892
3893 Rewrite (N,
3894 Make_Procedure_Call_Statement (Loc,
3895 Name => New_Reference_To (RTE (RE_Abort_Tasks), Loc),
3896 Parameter_Associations => New_List (
3897 Make_Qualified_Expression (Loc,
3898 Subtype_Mark => New_Reference_To (RTE (RE_Task_List), Loc),
3899 Expression => Aggr))));
3900
3901 Analyze (N);
3902 end Expand_N_Abort_Statement;
3903
3904 -------------------------------
3905 -- Expand_N_Accept_Statement --
3906 -------------------------------
3907
3908 -- This procedure handles expansion of accept statements that stand
3909 -- alone, i.e. they are not part of an accept alternative. The expansion
3910 -- of accept statement in accept alternatives is handled by the routines
3911 -- Expand_N_Accept_Alternative and Expand_N_Selective_Accept. The
3912 -- following description applies only to stand alone accept statements.
3913
3914 -- If there is no handled statement sequence, or only null statements,
3915 -- then this is called a trivial accept, and the expansion is:
3916
3917 -- Accept_Trivial (entry-index)
3918
3919 -- If there is a handled statement sequence, then the expansion is:
3920
3921 -- Ann : Address;
3922 -- {Lnn : Label}
3923
3924 -- begin
3925 -- begin
3926 -- Accept_Call (entry-index, Ann);
3927 -- Renaming_Declarations for formals
3928 -- <statement sequence from N_Accept_Statement node>
3929 -- Complete_Rendezvous;
3930 -- <<Lnn>>
3931 --
3932 -- exception
3933 -- when ... =>
3934 -- <exception handler from N_Accept_Statement node>
3935 -- Complete_Rendezvous;
3936 -- when ... =>
3937 -- <exception handler from N_Accept_Statement node>
3938 -- Complete_Rendezvous;
3939 -- ...
3940 -- end;
3941
3942 -- exception
3943 -- when all others =>
3944 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
3945 -- end;
3946
3947 -- The first three declarations were already inserted ahead of the
3948 -- accept statement by the Expand_Accept_Declarations procedure, which
3949 -- was called directly from the semantics during analysis of the accept.
3950 -- statement, before analyzing its contained statements.
3951
3952 -- The declarations from the N_Accept_Statement, as noted in Sinfo, come
3953 -- from possible expansion activity (the original source of course does
3954 -- not have any declarations associated with the accept statement, since
3955 -- an accept statement has no declarative part). In particular, if the
3956 -- expander is active, the first such declaration is the declaration of
3957 -- the Accept_Params_Ptr entity (see Sem_Ch9.Analyze_Accept_Statement).
3958 --
3959 -- The two blocks are merged into a single block if the inner block has
3960 -- no exception handlers, but otherwise two blocks are required, since
3961 -- exceptions might be raised in the exception handlers of the inner
3962 -- block, and Exceptional_Complete_Rendezvous must be called.
3963
3964 procedure Expand_N_Accept_Statement (N : Node_Id) is
3965 Loc : constant Source_Ptr := Sloc (N);
3966 Stats : constant Node_Id := Handled_Statement_Sequence (N);
3967 Ename : constant Node_Id := Entry_Direct_Name (N);
3968 Eindx : constant Node_Id := Entry_Index (N);
3969 Eent : constant Entity_Id := Entity (Ename);
3970 Acstack : constant Elist_Id := Accept_Address (Eent);
3971 Ann : constant Entity_Id := Node (Last_Elmt (Acstack));
3972 Ttyp : constant Entity_Id := Etype (Scope (Eent));
3973 Blkent : Entity_Id;
3974 Call : Node_Id;
3975 Block : Node_Id;
3976
3977 function Null_Statements (Stats : List_Id) return Boolean;
3978 -- Check for null statement sequence (i.e a list of labels and
3979 -- null statements)
3980
3981 function Null_Statements (Stats : List_Id) return Boolean is
3982 Stmt : Node_Id;
3983
3984 begin
3985 Stmt := First (Stats);
3986 while Nkind (Stmt) /= N_Empty
3987 and then (Nkind (Stmt) = N_Null_Statement
3988 or else
3989 Nkind (Stmt) = N_Label)
3990 loop
3991 Next (Stmt);
3992 end loop;
3993
3994 return Nkind (Stmt) = N_Empty;
3995 end Null_Statements;
3996
3997 -- Start of processing for Expand_N_Accept_Statement
3998
3999 begin
4000 -- If accept statement is not part of a list, then its parent must be
4001 -- an accept alternative, and, as described above, we do not do any
4002 -- expansion for such accept statements at this level.
4003
4004 if not Is_List_Member (N) then
4005 pragma Assert (Nkind (Parent (N)) = N_Accept_Alternative);
4006 return;
4007
4008 -- Trivial accept case (no statement sequence, or null statements).
4009 -- If the accept statement has declarations, then just insert them
4010 -- before the procedure call.
4011
4012 -- We avoid this optimization when FIFO_Within_Priorities is active,
4013 -- since it is not correct according to annex D semantics. The problem
4014 -- is that the call is required to reorder the acceptors position on
4015 -- its ready queue, even though there is nothing to be done. However,
4016 -- if no policy is specified, then we decide that our dispatching
4017 -- policy always reorders the queue right after the RV to look the
4018 -- way they were just before the RV. Since we are allowed to freely
4019 -- reorder same-priority queues (this is part of what dispatching
4020 -- policies are all about), the optimization is legitimate.
4021
4022 elsif Opt.Task_Dispatching_Policy /= 'F'
4023 and then (No (Stats) or else Null_Statements (Statements (Stats)))
4024 then
4025 -- Remove declarations for renamings, because the parameter block
4026 -- will not be assigned.
4027
4028 declare
4029 D : Node_Id;
4030 Next_D : Node_Id;
4031
4032 begin
4033 D := First (Declarations (N));
4034
4035 while Present (D) loop
4036 Next_D := Next (D);
4037 if Nkind (D) = N_Object_Renaming_Declaration then
4038 Remove (D);
4039 end if;
4040
4041 D := Next_D;
4042 end loop;
4043 end;
4044
4045 if Present (Declarations (N)) then
4046 Insert_Actions (N, Declarations (N));
4047 end if;
4048
4049 Rewrite (N,
4050 Make_Procedure_Call_Statement (Loc,
4051 Name => New_Reference_To (RTE (RE_Accept_Trivial), Loc),
4052 Parameter_Associations => New_List (
4053 Entry_Index_Expression (Loc, Entity (Ename), Eindx, Ttyp))));
4054
4055 Analyze (N);
4056
4057 -- Discard Entry_Address that was created for it, so it will not be
4058 -- emitted if this accept statement is in the statement part of a
4059 -- delay alternative.
4060
4061 if Present (Stats) then
4062 Remove_Last_Elmt (Acstack);
4063 end if;
4064
4065 -- Case of statement sequence present
4066
4067 else
4068 -- Construct the block, using the declarations from the accept
4069 -- statement if any to initialize the declarations of the block.
4070
4071 Blkent := Make_Defining_Identifier (Loc, New_Internal_Name ('A'));
4072 Set_Ekind (Blkent, E_Block);
4073 Set_Etype (Blkent, Standard_Void_Type);
4074 Set_Scope (Blkent, Current_Scope);
4075
4076 Block :=
4077 Make_Block_Statement (Loc,
4078 Identifier => New_Reference_To (Blkent, Loc),
4079 Declarations => Declarations (N),
4080 Handled_Statement_Sequence => Build_Accept_Body (N));
4081
4082 -- Prepend call to Accept_Call to main statement sequence
4083 -- If the accept has exception handlers, the statement sequence
4084 -- is wrapped in a block. Insert call and renaming declarations
4085 -- in the declarations of the block, so they are elaborated before
4086 -- the handlers.
4087
4088 Call :=
4089 Make_Procedure_Call_Statement (Loc,
4090 Name => New_Reference_To (RTE (RE_Accept_Call), Loc),
4091 Parameter_Associations => New_List (
4092 Entry_Index_Expression (Loc, Entity (Ename), Eindx, Ttyp),
4093 New_Reference_To (Ann, Loc)));
4094
4095 if Parent (Stats) = N then
4096 Prepend (Call, Statements (Stats));
4097 else
4098 Set_Declarations
4099 (Parent (Stats),
4100 New_List (Call));
4101 end if;
4102
4103 Analyze (Call);
4104
4105 New_Scope (Blkent);
4106
4107 declare
4108 D : Node_Id;
4109 Next_D : Node_Id;
4110 Typ : Entity_Id;
4111 begin
4112 D := First (Declarations (N));
4113
4114 while Present (D) loop
4115 Next_D := Next (D);
4116
4117 if Nkind (D) = N_Object_Renaming_Declaration then
4118 -- The renaming declarations for the formals were
4119 -- created during analysis of the accept statement,
4120 -- and attached to the list of declarations. Place
4121 -- them now in the context of the accept block or
4122 -- subprogram.
4123
4124 Remove (D);
4125 Typ := Entity (Subtype_Mark (D));
4126 Insert_After (Call, D);
4127 Analyze (D);
4128
4129 -- If the formal is class_wide, it does not have an
4130 -- actual subtype. The analysis of the renaming declaration
4131 -- creates one, but we need to retain the class-wide
4132 -- nature of the entity.
4133
4134 if Is_Class_Wide_Type (Typ) then
4135 Set_Etype (Defining_Identifier (D), Typ);
4136 end if;
4137
4138 end if;
4139
4140 D := Next_D;
4141 end loop;
4142 end;
4143
4144 End_Scope;
4145
4146 -- Replace the accept statement by the new block
4147
4148 Rewrite (N, Block);
4149 Analyze (N);
4150
4151 -- Last step is to unstack the Accept_Address value
4152
4153 Remove_Last_Elmt (Acstack);
4154 end if;
4155 end Expand_N_Accept_Statement;
4156
4157 ----------------------------------
4158 -- Expand_N_Asynchronous_Select --
4159 ----------------------------------
4160
4161 -- This procedure assumes that the trigger statement is an entry call. A
4162 -- delay alternative should already have been expanded into an entry call
4163 -- to the appropriate delay object Wait entry.
4164
4165 -- If the trigger is a task entry call, the select is implemented with
4166 -- a Task_Entry_Call:
4167
4168 -- declare
4169 -- B : Boolean;
4170 -- C : Boolean;
4171 -- P : parms := (parm, parm, parm);
4172
4173 -- -- Clean is added by Exp_Ch7.Expand_Cleanup_Actions
4174
4175 -- procedure _clean is
4176 -- begin
4177 -- ...
4178 -- Cancel_Task_Entry_Call (C);
4179 -- ...
4180 -- end _clean;
4181
4182 -- begin
4183 -- Abort_Defer;
4184 -- Task_Entry_Call
4185 -- (acceptor-task,
4186 -- entry-index,
4187 -- P'Address,
4188 -- Asynchronous_Call,
4189 -- B);
4190
4191 -- begin
4192 -- begin
4193 -- Abort_Undefer;
4194 -- abortable-part
4195 -- at end
4196 -- _clean; -- Added by Exp_Ch7.Expand_Cleanup_Actions.
4197 -- end;
4198
4199 -- exception
4200 -- when Abort_Signal => Abort_Undefer;
4201 -- end;
4202 -- parm := P.param;
4203 -- parm := P.param;
4204 -- ...
4205 -- if not C then
4206 -- triggered-statements
4207 -- end if;
4208 -- end;
4209
4210 -- Note that Build_Simple_Entry_Call is used to expand the entry
4211 -- of the asynchronous entry call (by the
4212 -- Expand_N_Entry_Call_Statement procedure) as follows:
4213
4214 -- declare
4215 -- P : parms := (parm, parm, parm);
4216 -- begin
4217 -- Call_Simple (acceptor-task, entry-index, P'Address);
4218 -- parm := P.param;
4219 -- parm := P.param;
4220 -- ...
4221 -- end;
4222
4223 -- so the task at hand is to convert the latter expansion into the former
4224
4225 -- If the trigger is a protected entry call, the select is
4226 -- implemented with Protected_Entry_Call:
4227
4228 -- declare
4229 -- P : E1_Params := (param, param, param);
4230 -- Bnn : Communications_Block;
4231
4232 -- begin
4233 -- declare
4234 -- -- Clean is added by Exp_Ch7.Expand_Cleanup_Actions.
4235 -- procedure _clean is
4236 -- begin
4237 -- ...
4238 -- if Enqueued (Bnn) then
4239 -- Cancel_Protected_Entry_Call (Bnn);
4240 -- end if;
4241 -- ...
4242 -- end _clean;
4243
4244 -- begin
4245 -- begin
4246 -- Protected_Entry_Call (
4247 -- Object => po._object'Access,
4248 -- E => <entry index>;
4249 -- Uninterpreted_Data => P'Address;
4250 -- Mode => Asynchronous_Call;
4251 -- Block => Bnn);
4252 -- if Enqueued (Bnn) then
4253 -- <abortable part>
4254 -- end if;
4255 -- at end
4256 -- _clean; -- Added by Exp_Ch7.Expand_Cleanup_Actions.
4257 -- end;
4258
4259 -- exception
4260 -- when Abort_Signal =>
4261 -- Abort_Undefer;
4262 -- null;
4263 -- end;
4264
4265 -- if not Cancelled (Bnn) then
4266 -- triggered statements
4267 -- end if;
4268 -- end;
4269
4270 -- Build_Simple_Entry_Call is used to expand the all to a simple
4271 -- protected entry call:
4272
4273 -- declare
4274 -- P : E1_Params := (param, param, param);
4275 -- Bnn : Communications_Block;
4276
4277 -- begin
4278 -- Protected_Entry_Call (
4279 -- Object => po._object'Access,
4280 -- E => <entry index>;
4281 -- Uninterpreted_Data => P'Address;
4282 -- Mode => Simple_Call;
4283 -- Block => Bnn);
4284 -- parm := P.param;
4285 -- parm := P.param;
4286 -- ...
4287 -- end;
4288
4289 -- The job is to convert this to the asynchronous form
4290
4291 -- If the trigger is a delay statement, it will have been expanded into a
4292 -- call to one of the GNARL delay procedures. This routine will convert
4293 -- this into a protected entry call on a delay object and then continue
4294 -- processing as for a protected entry call trigger. This requires
4295 -- declaring a Delay_Block object and adding a pointer to this object to
4296 -- the parameter list of the delay procedure to form the parameter list of
4297 -- the entry call. This object is used by the runtime to queue the delay
4298 -- request.
4299
4300 -- For a description of the use of P and the assignments after the
4301 -- call, see Expand_N_Entry_Call_Statement.
4302
4303 procedure Expand_N_Asynchronous_Select (N : Node_Id) is
4304 Loc : constant Source_Ptr := Sloc (N);
4305 Trig : constant Node_Id := Triggering_Alternative (N);
4306 Abrt : constant Node_Id := Abortable_Part (N);
4307 Tstats : constant List_Id := Statements (Trig);
4308 Astats : constant List_Id := Statements (Abrt);
4309
4310 Ecall : Node_Id;
4311 Concval : Node_Id;
4312 Ename : Node_Id;
4313 Index : Node_Id;
4314 Hdle : List_Id;
4315 Decls : List_Id;
4316 Decl : Node_Id;
4317 Parms : List_Id;
4318 Parm : Node_Id;
4319 Call : Node_Id;
4320 Stmts : List_Id;
4321 Enqueue_Call : Node_Id;
4322 Stmt : Node_Id;
4323 B : Entity_Id;
4324 Pdef : Entity_Id;
4325 Dblock_Ent : Entity_Id;
4326 N_Orig : Node_Id;
4327 Abortable_Block : Node_Id;
4328 Cancel_Param : Entity_Id;
4329 Blkent : Entity_Id;
4330 Target_Undefer : RE_Id;
4331 Undefer_Args : List_Id := No_List;
4332
4333 begin
4334 Blkent := Make_Defining_Identifier (Loc, New_Internal_Name ('A'));
4335 Ecall := Triggering_Statement (Trig);
4336
4337 -- The arguments in the call may require dynamic allocation, and the
4338 -- call statement may have been transformed into a block. The block
4339 -- may contain additional declarations for internal entities, and the
4340 -- original call is found by sequential search.
4341
4342 if Nkind (Ecall) = N_Block_Statement then
4343 Ecall := First (Statements (Handled_Statement_Sequence (Ecall)));
4344
4345 while Nkind (Ecall) /= N_Procedure_Call_Statement
4346 and then Nkind (Ecall) /= N_Entry_Call_Statement
4347 loop
4348 Next (Ecall);
4349 end loop;
4350 end if;
4351
4352 -- If a delay was used as a trigger, it will have been expanded
4353 -- into a procedure call. Convert it to the appropriate sequence of
4354 -- statements, similar to what is done for a task entry call.
4355 -- Note that this currently supports only Duration, Real_Time.Time,
4356 -- and Calendar.Time.
4357
4358 if Nkind (Ecall) = N_Procedure_Call_Statement then
4359
4360 -- Add a Delay_Block object to the parameter list of the
4361 -- delay procedure to form the parameter list of the Wait
4362 -- entry call.
4363
4364 Dblock_Ent := Make_Defining_Identifier (Loc, New_Internal_Name ('D'));
4365
4366 Pdef := Entity (Name (Ecall));
4367
4368 if Is_RTE (Pdef, RO_CA_Delay_For) then
4369 Enqueue_Call := New_Reference_To (RTE (RE_Enqueue_Duration), Loc);
4370
4371 elsif Is_RTE (Pdef, RO_CA_Delay_Until) then
4372 Enqueue_Call := New_Reference_To (RTE (RE_Enqueue_Calendar), Loc);
4373
4374 else pragma Assert (Is_RTE (Pdef, RO_RT_Delay_Until));
4375 Enqueue_Call := New_Reference_To (RTE (RE_Enqueue_RT), Loc);
4376 end if;
4377
4378 Append_To (Parameter_Associations (Ecall),
4379 Make_Attribute_Reference (Loc,
4380 Prefix => New_Reference_To (Dblock_Ent, Loc),
4381 Attribute_Name => Name_Unchecked_Access));
4382
4383 -- Create the inner block to protect the abortable part
4384
4385 Hdle := New_List (
4386 Make_Exception_Handler (Loc,
4387 Exception_Choices =>
4388 New_List (New_Reference_To (Stand.Abort_Signal, Loc)),
4389 Statements => New_List (
4390 Make_Procedure_Call_Statement (Loc,
4391 Name => New_Reference_To (RTE (RE_Abort_Undefer), Loc)))));
4392
4393 Prepend_To (Astats,
4394 Make_Procedure_Call_Statement (Loc,
4395 Name => New_Reference_To (RTE (RE_Abort_Undefer), Loc)));
4396
4397 Abortable_Block :=
4398 Make_Block_Statement (Loc,
4399 Identifier => New_Reference_To (Blkent, Loc),
4400 Handled_Statement_Sequence =>
4401 Make_Handled_Sequence_Of_Statements (Loc,
4402 Statements => Astats),
4403 Has_Created_Identifier => True,
4404 Is_Asynchronous_Call_Block => True);
4405
4406 -- Append call to if Enqueue (When, DB'Unchecked_Access) then
4407
4408 Rewrite (Ecall,
4409 Make_Implicit_If_Statement (N,
4410 Condition => Make_Function_Call (Loc,
4411 Name => Enqueue_Call,
4412 Parameter_Associations => Parameter_Associations (Ecall)),
4413 Then_Statements =>
4414 New_List (Make_Block_Statement (Loc,
4415 Handled_Statement_Sequence =>
4416 Make_Handled_Sequence_Of_Statements (Loc,
4417 Statements => New_List (
4418 Make_Implicit_Label_Declaration (Loc,
4419 Defining_Identifier => Blkent,
4420 Label_Construct => Abortable_Block),
4421 Abortable_Block),
4422 Exception_Handlers => Hdle)))));
4423
4424 Stmts := New_List (Ecall);
4425
4426 -- Construct statement sequence for new block
4427
4428 Append_To (Stmts,
4429 Make_Implicit_If_Statement (N,
4430 Condition => Make_Function_Call (Loc,
4431 Name => New_Reference_To (
4432 RTE (RE_Timed_Out), Loc),
4433 Parameter_Associations => New_List (
4434 Make_Attribute_Reference (Loc,
4435 Prefix => New_Reference_To (Dblock_Ent, Loc),
4436 Attribute_Name => Name_Unchecked_Access))),
4437 Then_Statements => Tstats));
4438
4439 -- The result is the new block
4440
4441 Set_Entry_Cancel_Parameter (Blkent, Dblock_Ent);
4442
4443 Rewrite (N,
4444 Make_Block_Statement (Loc,
4445 Declarations => New_List (
4446 Make_Object_Declaration (Loc,
4447 Defining_Identifier => Dblock_Ent,
4448 Aliased_Present => True,
4449 Object_Definition => New_Reference_To (
4450 RTE (RE_Delay_Block), Loc))),
4451
4452 Handled_Statement_Sequence =>
4453 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
4454
4455 Analyze (N);
4456 return;
4457
4458 else
4459 N_Orig := N;
4460 end if;
4461
4462 Extract_Entry (Ecall, Concval, Ename, Index);
4463 Build_Simple_Entry_Call (Ecall, Concval, Ename, Index);
4464
4465 Stmts := Statements (Handled_Statement_Sequence (Ecall));
4466 Decls := Declarations (Ecall);
4467
4468 if Is_Protected_Type (Etype (Concval)) then
4469
4470 -- Get the declarations of the block expanded from the entry call
4471
4472 Decl := First (Decls);
4473 while Present (Decl)
4474 and then (Nkind (Decl) /= N_Object_Declaration
4475 or else not Is_RTE
4476 (Etype (Object_Definition (Decl)), RE_Communication_Block))
4477 loop
4478 Next (Decl);
4479 end loop;
4480
4481 pragma Assert (Present (Decl));
4482 Cancel_Param := Defining_Identifier (Decl);
4483
4484 -- Change the mode of the Protected_Entry_Call call.
4485 -- Protected_Entry_Call (
4486 -- Object => po._object'Access,
4487 -- E => <entry index>;
4488 -- Uninterpreted_Data => P'Address;
4489 -- Mode => Asynchronous_Call;
4490 -- Block => Bnn);
4491
4492 Stmt := First (Stmts);
4493
4494 -- Skip assignments to temporaries created for in-out parameters.
4495 -- This makes unwarranted assumptions about the shape of the expanded
4496 -- tree for the call, and should be cleaned up ???
4497
4498 while Nkind (Stmt) /= N_Procedure_Call_Statement loop
4499 Next (Stmt);
4500 end loop;
4501
4502 Call := Stmt;
4503
4504 Parm := First (Parameter_Associations (Call));
4505 while Present (Parm)
4506 and then not Is_RTE (Etype (Parm), RE_Call_Modes)
4507 loop
4508 Next (Parm);
4509 end loop;
4510
4511 pragma Assert (Present (Parm));
4512 Rewrite (Parm, New_Reference_To (RTE (RE_Asynchronous_Call), Loc));
4513 Analyze (Parm);
4514
4515 -- Append an if statement to execute the abortable part.
4516 -- if Enqueued (Bnn) then
4517
4518 Append_To (Stmts,
4519 Make_Implicit_If_Statement (N,
4520 Condition => Make_Function_Call (Loc,
4521 Name => New_Reference_To (
4522 RTE (RE_Enqueued), Loc),
4523 Parameter_Associations => New_List (
4524 New_Reference_To (Cancel_Param, Loc))),
4525 Then_Statements => Astats));
4526
4527 Abortable_Block :=
4528 Make_Block_Statement (Loc,
4529 Identifier => New_Reference_To (Blkent, Loc),
4530 Handled_Statement_Sequence =>
4531 Make_Handled_Sequence_Of_Statements (Loc,
4532 Statements => Stmts),
4533 Has_Created_Identifier => True,
4534 Is_Asynchronous_Call_Block => True);
4535
4536 -- For the JVM call Update_Exception instead of Abort_Undefer.
4537 -- See 4jexcept.ads for an explanation.
4538
4539 if Hostparm.Java_VM then
4540 Target_Undefer := RE_Update_Exception;
4541 Undefer_Args :=
4542 New_List (Make_Function_Call (Loc,
4543 Name => New_Occurrence_Of
4544 (RTE (RE_Current_Target_Exception), Loc)));
4545 else
4546 Target_Undefer := RE_Abort_Undefer;
4547 end if;
4548
4549 Stmts := New_List (
4550 Make_Block_Statement (Loc,
4551 Handled_Statement_Sequence =>
4552 Make_Handled_Sequence_Of_Statements (Loc,
4553 Statements => New_List (
4554 Make_Implicit_Label_Declaration (Loc,
4555 Defining_Identifier => Blkent,
4556 Label_Construct => Abortable_Block),
4557 Abortable_Block),
4558
4559 -- exception
4560
4561 Exception_Handlers => New_List (
4562 Make_Exception_Handler (Loc,
4563
4564 -- when Abort_Signal =>
4565 -- Abort_Undefer.all;
4566
4567 Exception_Choices =>
4568 New_List (New_Reference_To (Stand.Abort_Signal, Loc)),
4569 Statements => New_List (
4570 Make_Procedure_Call_Statement (Loc,
4571 Name => New_Reference_To (
4572 RTE (Target_Undefer), Loc),
4573 Parameter_Associations => Undefer_Args)))))),
4574
4575 -- if not Cancelled (Bnn) then
4576 -- triggered statements
4577 -- end if;
4578
4579 Make_Implicit_If_Statement (N,
4580 Condition => Make_Op_Not (Loc,
4581 Right_Opnd =>
4582 Make_Function_Call (Loc,
4583 Name => New_Occurrence_Of (RTE (RE_Cancelled), Loc),
4584 Parameter_Associations => New_List (
4585 New_Occurrence_Of (Cancel_Param, Loc)))),
4586 Then_Statements => Tstats));
4587
4588 -- Asynchronous task entry call
4589
4590 else
4591 if No (Decls) then
4592 Decls := New_List;
4593 end if;
4594
4595 B := Make_Defining_Identifier (Loc, Name_uB);
4596
4597 -- Insert declaration of B in declarations of existing block
4598
4599 Prepend_To (Decls,
4600 Make_Object_Declaration (Loc,
4601 Defining_Identifier => B,
4602 Object_Definition => New_Reference_To (Standard_Boolean, Loc)));
4603
4604 Cancel_Param := Make_Defining_Identifier (Loc, Name_uC);
4605
4606 -- Insert declaration of C in declarations of existing block
4607
4608 Prepend_To (Decls,
4609 Make_Object_Declaration (Loc,
4610 Defining_Identifier => Cancel_Param,
4611 Object_Definition => New_Reference_To (Standard_Boolean, Loc)));
4612
4613 -- Remove and save the call to Call_Simple
4614
4615 Stmt := First (Stmts);
4616
4617 -- Skip assignments to temporaries created for in-out parameters.
4618 -- This makes unwarranted assumptions about the shape of the expanded
4619 -- tree for the call, and should be cleaned up ???
4620
4621 while Nkind (Stmt) /= N_Procedure_Call_Statement loop
4622 Next (Stmt);
4623 end loop;
4624
4625 Call := Stmt;
4626
4627 -- Create the inner block to protect the abortable part
4628
4629 Hdle := New_List (
4630 Make_Exception_Handler (Loc,
4631 Exception_Choices =>
4632 New_List (New_Reference_To (Stand.Abort_Signal, Loc)),
4633 Statements => New_List (
4634 Make_Procedure_Call_Statement (Loc,
4635 Name => New_Reference_To (RTE (RE_Abort_Undefer), Loc)))));
4636
4637 Prepend_To (Astats,
4638 Make_Procedure_Call_Statement (Loc,
4639 Name => New_Reference_To (RTE (RE_Abort_Undefer), Loc)));
4640
4641 Abortable_Block :=
4642 Make_Block_Statement (Loc,
4643 Identifier => New_Reference_To (Blkent, Loc),
4644 Handled_Statement_Sequence =>
4645 Make_Handled_Sequence_Of_Statements (Loc,
4646 Statements => Astats),
4647 Has_Created_Identifier => True,
4648 Is_Asynchronous_Call_Block => True);
4649
4650 Insert_After (Call,
4651 Make_Block_Statement (Loc,
4652 Handled_Statement_Sequence =>
4653 Make_Handled_Sequence_Of_Statements (Loc,
4654 Statements => New_List (
4655 Make_Implicit_Label_Declaration (Loc,
4656 Defining_Identifier => Blkent,
4657 Label_Construct => Abortable_Block),
4658 Abortable_Block),
4659 Exception_Handlers => Hdle)));
4660
4661 -- Create new call statement
4662
4663 Parms := Parameter_Associations (Call);
4664 Append_To (Parms, New_Reference_To (RTE (RE_Asynchronous_Call), Loc));
4665 Append_To (Parms, New_Reference_To (B, Loc));
4666 Rewrite (Call,
4667 Make_Procedure_Call_Statement (Loc,
4668 Name => New_Reference_To (RTE (RE_Task_Entry_Call), Loc),
4669 Parameter_Associations => Parms));
4670
4671 -- Construct statement sequence for new block
4672
4673 Append_To (Stmts,
4674 Make_Implicit_If_Statement (N,
4675 Condition => Make_Op_Not (Loc,
4676 New_Reference_To (Cancel_Param, Loc)),
4677 Then_Statements => Tstats));
4678
4679 -- Protected the call against abort
4680
4681 Prepend_To (Stmts,
4682 Make_Procedure_Call_Statement (Loc,
4683 Name => New_Reference_To (RTE (RE_Abort_Defer), Loc),
4684 Parameter_Associations => Empty_List));
4685 end if;
4686
4687 Set_Entry_Cancel_Parameter (Blkent, Cancel_Param);
4688
4689 -- The result is the new block
4690
4691 Rewrite (N_Orig,
4692 Make_Block_Statement (Loc,
4693 Declarations => Decls,
4694 Handled_Statement_Sequence =>
4695 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
4696
4697 Analyze (N_Orig);
4698 end Expand_N_Asynchronous_Select;
4699
4700 -------------------------------------
4701 -- Expand_N_Conditional_Entry_Call --
4702 -------------------------------------
4703
4704 -- The conditional task entry call is converted to a call to
4705 -- Task_Entry_Call:
4706
4707 -- declare
4708 -- B : Boolean;
4709 -- P : parms := (parm, parm, parm);
4710
4711 -- begin
4712 -- Task_Entry_Call
4713 -- (acceptor-task,
4714 -- entry-index,
4715 -- P'Address,
4716 -- Conditional_Call,
4717 -- B);
4718 -- parm := P.param;
4719 -- parm := P.param;
4720 -- ...
4721 -- if B then
4722 -- normal-statements
4723 -- else
4724 -- else-statements
4725 -- end if;
4726 -- end;
4727
4728 -- For a description of the use of P and the assignments after the
4729 -- call, see Expand_N_Entry_Call_Statement. Note that the entry call
4730 -- of the conditional entry call has already been expanded (by the
4731 -- Expand_N_Entry_Call_Statement procedure) as follows:
4732
4733 -- declare
4734 -- P : parms := (parm, parm, parm);
4735 -- begin
4736 -- ... info for in-out parameters
4737 -- Call_Simple (acceptor-task, entry-index, P'Address);
4738 -- parm := P.param;
4739 -- parm := P.param;
4740 -- ...
4741 -- end;
4742
4743 -- so the task at hand is to convert the latter expansion into the former
4744
4745 -- The conditional protected entry call is converted to a call to
4746 -- Protected_Entry_Call:
4747
4748 -- declare
4749 -- P : parms := (parm, parm, parm);
4750 -- Bnn : Communications_Block;
4751
4752 -- begin
4753 -- Protected_Entry_Call (
4754 -- Object => po._object'Access,
4755 -- E => <entry index>;
4756 -- Uninterpreted_Data => P'Address;
4757 -- Mode => Conditional_Call;
4758 -- Block => Bnn);
4759 -- parm := P.param;
4760 -- parm := P.param;
4761 -- ...
4762 -- if Cancelled (Bnn) then
4763 -- else-statements
4764 -- else
4765 -- normal-statements
4766 -- end if;
4767 -- end;
4768
4769 -- As for tasks, the entry call of the conditional entry call has
4770 -- already been expanded (by the Expand_N_Entry_Call_Statement procedure)
4771 -- as follows:
4772
4773 -- declare
4774 -- P : E1_Params := (param, param, param);
4775 -- Bnn : Communications_Block;
4776
4777 -- begin
4778 -- Protected_Entry_Call (
4779 -- Object => po._object'Access,
4780 -- E => <entry index>;
4781 -- Uninterpreted_Data => P'Address;
4782 -- Mode => Simple_Call;
4783 -- Block => Bnn);
4784 -- parm := P.param;
4785 -- parm := P.param;
4786 -- ...
4787 -- end;
4788
4789 procedure Expand_N_Conditional_Entry_Call (N : Node_Id) is
4790 Loc : constant Source_Ptr := Sloc (N);
4791 Alt : constant Node_Id := Entry_Call_Alternative (N);
4792 Blk : Node_Id := Entry_Call_Statement (Alt);
4793 Transient_Blk : Node_Id;
4794
4795 Parms : List_Id;
4796 Parm : Node_Id;
4797 Call : Node_Id;
4798 Stmts : List_Id;
4799 B : Entity_Id;
4800 Decl : Node_Id;
4801 Stmt : Node_Id;
4802
4803 begin
4804 -- As described above, The entry alternative is transformed into a
4805 -- block that contains the gnulli call, and possibly assignment
4806 -- statements for in-out parameters. The gnulli call may itself be
4807 -- rewritten into a transient block if some unconstrained parameters
4808 -- require it. We need to retrieve the call to complete its parameter
4809 -- list.
4810
4811 Transient_Blk :=
4812 First_Real_Statement (Handled_Statement_Sequence (Blk));
4813
4814 if Present (Transient_Blk)
4815 and then
4816 Nkind (Transient_Blk) = N_Block_Statement
4817 then
4818 Blk := Transient_Blk;
4819 end if;
4820
4821 Stmts := Statements (Handled_Statement_Sequence (Blk));
4822
4823 Stmt := First (Stmts);
4824
4825 while Nkind (Stmt) /= N_Procedure_Call_Statement loop
4826 Next (Stmt);
4827 end loop;
4828
4829 Call := Stmt;
4830
4831 Parms := Parameter_Associations (Call);
4832
4833 if Is_RTE (Entity (Name (Call)), RE_Protected_Entry_Call) then
4834
4835 -- Substitute Conditional_Entry_Call for Simple_Call
4836 -- parameter.
4837
4838 Parm := First (Parms);
4839 while Present (Parm)
4840 and then not Is_RTE (Etype (Parm), RE_Call_Modes)
4841 loop
4842 Next (Parm);
4843 end loop;
4844
4845 pragma Assert (Present (Parm));
4846 Rewrite (Parm, New_Reference_To (RTE (RE_Conditional_Call), Loc));
4847
4848 Analyze (Parm);
4849
4850 -- Find the Communication_Block parameter for the call
4851 -- to the Cancelled function.
4852
4853 Decl := First (Declarations (Blk));
4854 while Present (Decl)
4855 and then not
4856 Is_RTE (Etype (Object_Definition (Decl)), RE_Communication_Block)
4857 loop
4858 Next (Decl);
4859 end loop;
4860
4861 -- Add an if statement to execute the else part if the call
4862 -- does not succeed (as indicated by the Cancelled predicate).
4863
4864 Append_To (Stmts,
4865 Make_Implicit_If_Statement (N,
4866 Condition => Make_Function_Call (Loc,
4867 Name => New_Reference_To (RTE (RE_Cancelled), Loc),
4868 Parameter_Associations => New_List (
4869 New_Reference_To (Defining_Identifier (Decl), Loc))),
4870 Then_Statements => Else_Statements (N),
4871 Else_Statements => Statements (Alt)));
4872
4873 else
4874 B := Make_Defining_Identifier (Loc, Name_uB);
4875
4876 -- Insert declaration of B in declarations of existing block
4877
4878 if No (Declarations (Blk)) then
4879 Set_Declarations (Blk, New_List);
4880 end if;
4881
4882 Prepend_To (Declarations (Blk),
4883 Make_Object_Declaration (Loc,
4884 Defining_Identifier => B,
4885 Object_Definition => New_Reference_To (Standard_Boolean, Loc)));
4886
4887 -- Create new call statement
4888
4889 Append_To (Parms, New_Reference_To (RTE (RE_Conditional_Call), Loc));
4890 Append_To (Parms, New_Reference_To (B, Loc));
4891
4892 Rewrite (Call,
4893 Make_Procedure_Call_Statement (Loc,
4894 Name => New_Reference_To (RTE (RE_Task_Entry_Call), Loc),
4895 Parameter_Associations => Parms));
4896
4897 -- Construct statement sequence for new block
4898
4899 Append_To (Stmts,
4900 Make_Implicit_If_Statement (N,
4901 Condition => New_Reference_To (B, Loc),
4902 Then_Statements => Statements (Alt),
4903 Else_Statements => Else_Statements (N)));
4904
4905 end if;
4906
4907 -- The result is the new block
4908
4909 Rewrite (N,
4910 Make_Block_Statement (Loc,
4911 Declarations => Declarations (Blk),
4912 Handled_Statement_Sequence =>
4913 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
4914
4915 Analyze (N);
4916 end Expand_N_Conditional_Entry_Call;
4917
4918 ---------------------------------------
4919 -- Expand_N_Delay_Relative_Statement --
4920 ---------------------------------------
4921
4922 -- Delay statement is implemented as a procedure call to Delay_For
4923 -- defined in Ada.Calendar.Delays in order to reduce the overhead of
4924 -- simple delays imposed by the use of Protected Objects.
4925
4926 procedure Expand_N_Delay_Relative_Statement (N : Node_Id) is
4927 Loc : constant Source_Ptr := Sloc (N);
4928
4929 begin
4930 Rewrite (N,
4931 Make_Procedure_Call_Statement (Loc,
4932 Name => New_Reference_To (RTE (RO_CA_Delay_For), Loc),
4933 Parameter_Associations => New_List (Expression (N))));
4934 Analyze (N);
4935 end Expand_N_Delay_Relative_Statement;
4936
4937 ------------------------------------
4938 -- Expand_N_Delay_Until_Statement --
4939 ------------------------------------
4940
4941 -- Delay Until statement is implemented as a procedure call to
4942 -- Delay_Until defined in Ada.Calendar.Delays and Ada.Real_Time.Delays.
4943
4944 procedure Expand_N_Delay_Until_Statement (N : Node_Id) is
4945 Loc : constant Source_Ptr := Sloc (N);
4946 Typ : Entity_Id;
4947
4948 begin
4949 if Is_RTE (Base_Type (Etype (Expression (N))), RO_CA_Time) then
4950 Typ := RTE (RO_CA_Delay_Until);
4951 else
4952 Typ := RTE (RO_RT_Delay_Until);
4953 end if;
4954
4955 Rewrite (N,
4956 Make_Procedure_Call_Statement (Loc,
4957 Name => New_Reference_To (Typ, Loc),
4958 Parameter_Associations => New_List (Expression (N))));
4959
4960 Analyze (N);
4961 end Expand_N_Delay_Until_Statement;
4962
4963 -------------------------
4964 -- Expand_N_Entry_Body --
4965 -------------------------
4966
4967 procedure Expand_N_Entry_Body (N : Node_Id) is
4968 Loc : constant Source_Ptr := Sloc (N);
4969 Dec : constant Node_Id := Parent (Current_Scope);
4970 Ent_Formals : constant Node_Id := Entry_Body_Formal_Part (N);
4971 Index_Spec : constant Node_Id :=
4972 Entry_Index_Specification (Ent_Formals);
4973 Next_Op : Node_Id;
4974 First_Decl : constant Node_Id := First (Declarations (N));
4975 Index_Decl : List_Id;
4976
4977 begin
4978 -- Add the renamings for private declarations and discriminants
4979
4980 Add_Discriminal_Declarations
4981 (Declarations (N), Defining_Identifier (Dec), Name_uObject, Loc);
4982 Add_Private_Declarations
4983 (Declarations (N), Defining_Identifier (Dec), Name_uObject, Loc);
4984
4985 if Present (Index_Spec) then
4986 Index_Decl :=
4987 Index_Constant_Declaration
4988 (N,
4989 Defining_Identifier (Index_Spec), Defining_Identifier (Dec));
4990
4991 -- If the entry has local declarations, insert index declaration
4992 -- before them, because the index may be used therein.
4993
4994 if Present (First_Decl) then
4995 Insert_List_Before (First_Decl, Index_Decl);
4996 else
4997 Append_List_To (Declarations (N), Index_Decl);
4998 end if;
4999 end if;
5000
5001 -- Associate privals and discriminals with the next protected
5002 -- operation body to be expanded. These are used to expand
5003 -- references to private data objects and discriminants,
5004 -- respectively.
5005
5006 Next_Op := Next_Protected_Operation (N);
5007
5008 if Present (Next_Op) then
5009 Set_Privals (Dec, Next_Op, Loc);
5010 Set_Discriminals (Dec);
5011 end if;
5012 end Expand_N_Entry_Body;
5013
5014 -----------------------------------
5015 -- Expand_N_Entry_Call_Statement --
5016 -----------------------------------
5017
5018 -- An entry call is expanded into GNARLI calls to implement
5019 -- a simple entry call (see Build_Simple_Entry_Call).
5020
5021 procedure Expand_N_Entry_Call_Statement (N : Node_Id) is
5022 Concval : Node_Id;
5023 Ename : Node_Id;
5024 Index : Node_Id;
5025
5026 begin
5027 if No_Run_Time_Mode then
5028 Error_Msg_CRT ("entry call", N);
5029 return;
5030 end if;
5031
5032 -- If this entry call is part of an asynchronous select, don't
5033 -- expand it here; it will be expanded with the select statement.
5034 -- Don't expand timed entry calls either, as they are translated
5035 -- into asynchronous entry calls.
5036
5037 -- ??? This whole approach is questionable; it may be better
5038 -- to go back to allowing the expansion to take place and then
5039 -- attempting to fix it up in Expand_N_Asynchronous_Select.
5040 -- The tricky part is figuring out whether the expanded
5041 -- call is on a task or protected entry.
5042
5043 if (Nkind (Parent (N)) /= N_Triggering_Alternative
5044 or else N /= Triggering_Statement (Parent (N)))
5045 and then (Nkind (Parent (N)) /= N_Entry_Call_Alternative
5046 or else N /= Entry_Call_Statement (Parent (N))
5047 or else Nkind (Parent (Parent (N))) /= N_Timed_Entry_Call)
5048 then
5049 Extract_Entry (N, Concval, Ename, Index);
5050 Build_Simple_Entry_Call (N, Concval, Ename, Index);
5051 end if;
5052 end Expand_N_Entry_Call_Statement;
5053
5054 --------------------------------
5055 -- Expand_N_Entry_Declaration --
5056 --------------------------------
5057
5058 -- If there are parameters, then first, each of the formals is marked
5059 -- by setting Is_Entry_Formal. Next a record type is built which is
5060 -- used to hold the parameter values. The name of this record type is
5061 -- entryP where entry is the name of the entry, with an additional
5062 -- corresponding access type called entryPA. The record type has matching
5063 -- components for each formal (the component names are the same as the
5064 -- formal names). For elementary types, the component type matches the
5065 -- formal type. For composite types, an access type is declared (with
5066 -- the name formalA) which designates the formal type, and the type of
5067 -- the component is this access type. Finally the Entry_Component of
5068 -- each formal is set to reference the corresponding record component.
5069
5070 procedure Expand_N_Entry_Declaration (N : Node_Id) is
5071 Loc : constant Source_Ptr := Sloc (N);
5072 Entry_Ent : constant Entity_Id := Defining_Identifier (N);
5073 Components : List_Id;
5074 Formal : Node_Id;
5075 Ftype : Entity_Id;
5076 Last_Decl : Node_Id;
5077 Component : Entity_Id;
5078 Ctype : Entity_Id;
5079 Decl : Node_Id;
5080 Rec_Ent : Entity_Id;
5081 Acc_Ent : Entity_Id;
5082
5083 begin
5084 Formal := First_Formal (Entry_Ent);
5085 Last_Decl := N;
5086
5087 -- Most processing is done only if parameters are present
5088
5089 if Present (Formal) then
5090 Components := New_List;
5091
5092 -- Loop through formals
5093
5094 while Present (Formal) loop
5095 Set_Is_Entry_Formal (Formal);
5096 Component :=
5097 Make_Defining_Identifier (Sloc (Formal), Chars (Formal));
5098 Set_Entry_Component (Formal, Component);
5099 Set_Entry_Formal (Component, Formal);
5100 Ftype := Etype (Formal);
5101
5102 -- Declare new access type and then append
5103
5104 Ctype :=
5105 Make_Defining_Identifier (Loc, New_Internal_Name ('A'));
5106
5107 Decl :=
5108 Make_Full_Type_Declaration (Loc,
5109 Defining_Identifier => Ctype,
5110 Type_Definition =>
5111 Make_Access_To_Object_Definition (Loc,
5112 All_Present => True,
5113 Constant_Present => Ekind (Formal) = E_In_Parameter,
5114 Subtype_Indication => New_Reference_To (Ftype, Loc)));
5115
5116 Insert_After (Last_Decl, Decl);
5117 Last_Decl := Decl;
5118
5119 Append_To (Components,
5120 Make_Component_Declaration (Loc,
5121 Defining_Identifier => Component,
5122 Component_Definition =>
5123 Make_Component_Definition (Loc,
5124 Aliased_Present => False,
5125 Subtype_Indication => New_Reference_To (Ctype, Loc))));
5126
5127 Next_Formal_With_Extras (Formal);
5128 end loop;
5129
5130 -- Create the Entry_Parameter_Record declaration
5131
5132 Rec_Ent :=
5133 Make_Defining_Identifier (Loc, New_Internal_Name ('P'));
5134
5135 Decl :=
5136 Make_Full_Type_Declaration (Loc,
5137 Defining_Identifier => Rec_Ent,
5138 Type_Definition =>
5139 Make_Record_Definition (Loc,
5140 Component_List =>
5141 Make_Component_List (Loc,
5142 Component_Items => Components)));
5143
5144 Insert_After (Last_Decl, Decl);
5145 Last_Decl := Decl;
5146
5147 -- Construct and link in the corresponding access type
5148
5149 Acc_Ent :=
5150 Make_Defining_Identifier (Loc, New_Internal_Name ('A'));
5151
5152 Set_Entry_Parameters_Type (Entry_Ent, Acc_Ent);
5153
5154 Decl :=
5155 Make_Full_Type_Declaration (Loc,
5156 Defining_Identifier => Acc_Ent,
5157 Type_Definition =>
5158 Make_Access_To_Object_Definition (Loc,
5159 All_Present => True,
5160 Subtype_Indication => New_Reference_To (Rec_Ent, Loc)));
5161
5162 Insert_After (Last_Decl, Decl);
5163 Last_Decl := Decl;
5164 end if;
5165 end Expand_N_Entry_Declaration;
5166
5167 -----------------------------
5168 -- Expand_N_Protected_Body --
5169 -----------------------------
5170
5171 -- Protected bodies are expanded to the completion of the subprograms
5172 -- created for the corresponding protected type. These are a protected
5173 -- and unprotected version of each protected subprogram in the object,
5174 -- a function to calculate each entry barrier, and a procedure to
5175 -- execute the sequence of statements of each protected entry body.
5176 -- For example, for protected type ptype:
5177
5178 -- function entB
5179 -- (O : System.Address;
5180 -- E : Protected_Entry_Index)
5181 -- return Boolean
5182 -- is
5183 -- <discriminant renamings>
5184 -- <private object renamings>
5185 -- begin
5186 -- return <barrier expression>;
5187 -- end entB;
5188
5189 -- procedure pprocN (_object : in out poV;...) is
5190 -- <discriminant renamings>
5191 -- <private object renamings>
5192 -- begin
5193 -- <sequence of statements>
5194 -- end pprocN;
5195
5196 -- procedure pproc (_object : in out poV;...) is
5197 -- procedure _clean is
5198 -- Pn : Boolean;
5199 -- begin
5200 -- ptypeS (_object, Pn);
5201 -- Unlock (_object._object'Access);
5202 -- Abort_Undefer.all;
5203 -- end _clean;
5204
5205 -- begin
5206 -- Abort_Defer.all;
5207 -- Lock (_object._object'Access);
5208 -- pprocN (_object;...);
5209 -- at end
5210 -- _clean;
5211 -- end pproc;
5212
5213 -- function pfuncN (_object : poV;...) return Return_Type is
5214 -- <discriminant renamings>
5215 -- <private object renamings>
5216 -- begin
5217 -- <sequence of statements>
5218 -- end pfuncN;
5219
5220 -- function pfunc (_object : poV) return Return_Type is
5221 -- procedure _clean is
5222 -- begin
5223 -- Unlock (_object._object'Access);
5224 -- Abort_Undefer.all;
5225 -- end _clean;
5226
5227 -- begin
5228 -- Abort_Defer.all;
5229 -- Lock (_object._object'Access);
5230 -- return pfuncN (_object);
5231
5232 -- at end
5233 -- _clean;
5234 -- end pfunc;
5235
5236 -- procedure entE
5237 -- (O : System.Address;
5238 -- P : System.Address;
5239 -- E : Protected_Entry_Index)
5240 -- is
5241 -- <discriminant renamings>
5242 -- <private object renamings>
5243 -- type poVP is access poV;
5244 -- _Object : ptVP := ptVP!(O);
5245
5246 -- begin
5247 -- begin
5248 -- <statement sequence>
5249 -- Complete_Entry_Body (_Object._Object);
5250 -- exception
5251 -- when all others =>
5252 -- Exceptional_Complete_Entry_Body (
5253 -- _Object._Object, Get_GNAT_Exception);
5254 -- end;
5255 -- end entE;
5256
5257 -- The type poV is the record created for the protected type to hold
5258 -- the state of the protected object.
5259
5260 procedure Expand_N_Protected_Body (N : Node_Id) is
5261 Loc : constant Source_Ptr := Sloc (N);
5262 Pid : constant Entity_Id := Corresponding_Spec (N);
5263 Has_Entries : Boolean := False;
5264 Op_Decl : Node_Id;
5265 Op_Body : Node_Id;
5266 Op_Id : Entity_Id;
5267 New_Op_Body : Node_Id;
5268 Current_Node : Node_Id;
5269 Num_Entries : Natural := 0;
5270
5271 begin
5272 if No_Run_Time_Mode then
5273 Error_Msg_CRT ("protected body", N);
5274 return;
5275 end if;
5276
5277 if Nkind (Parent (N)) = N_Subunit then
5278
5279 -- This is the proper body corresponding to a stub. The declarations
5280 -- must be inserted at the point of the stub, which is in the decla-
5281 -- rative part of the parent unit.
5282
5283 Current_Node := Corresponding_Stub (Parent (N));
5284
5285 else
5286 Current_Node := N;
5287 end if;
5288
5289 Op_Body := First (Declarations (N));
5290
5291 -- The protected body is replaced with the bodies of its
5292 -- protected operations, and the declarations for internal objects
5293 -- that may have been created for entry family bounds.
5294
5295 Rewrite (N, Make_Null_Statement (Sloc (N)));
5296 Analyze (N);
5297
5298 while Present (Op_Body) loop
5299 case Nkind (Op_Body) is
5300 when N_Subprogram_Declaration =>
5301 null;
5302
5303 when N_Subprogram_Body =>
5304
5305 -- Exclude functions created to analyze defaults
5306
5307 if not Is_Eliminated (Defining_Entity (Op_Body))
5308 and then not Is_Eliminated (Corresponding_Spec (Op_Body))
5309 then
5310 New_Op_Body :=
5311 Build_Unprotected_Subprogram_Body (Op_Body, Pid);
5312
5313 Insert_After (Current_Node, New_Op_Body);
5314 Current_Node := New_Op_Body;
5315 Analyze (New_Op_Body);
5316
5317 Update_Prival_Subtypes (New_Op_Body);
5318
5319 -- Build the corresponding protected operation only if
5320 -- this is a visible operation of the type, or if it is
5321 -- an interrupt handler. Otherwise it is only callable
5322 -- from within the object, and the unprotected version
5323 -- is sufficient.
5324
5325 if Present (Corresponding_Spec (Op_Body)) then
5326 Op_Decl :=
5327 Unit_Declaration_Node (Corresponding_Spec (Op_Body));
5328
5329 if Nkind (Parent (Op_Decl)) = N_Protected_Definition
5330 and then
5331 (List_Containing (Op_Decl) =
5332 Visible_Declarations (Parent (Op_Decl))
5333 or else
5334 Is_Interrupt_Handler
5335 (Corresponding_Spec (Op_Body)))
5336 then
5337 New_Op_Body :=
5338 Build_Protected_Subprogram_Body (
5339 Op_Body, Pid, Specification (New_Op_Body));
5340
5341 Insert_After (Current_Node, New_Op_Body);
5342 Analyze (New_Op_Body);
5343 end if;
5344 end if;
5345 end if;
5346
5347 when N_Entry_Body =>
5348 Op_Id := Defining_Identifier (Op_Body);
5349 Has_Entries := True;
5350 Num_Entries := Num_Entries + 1;
5351
5352 New_Op_Body := Build_Protected_Entry (Op_Body, Op_Id, Pid);
5353
5354 Insert_After (Current_Node, New_Op_Body);
5355 Current_Node := New_Op_Body;
5356 Analyze (New_Op_Body);
5357
5358 Update_Prival_Subtypes (New_Op_Body);
5359
5360 when N_Implicit_Label_Declaration =>
5361 null;
5362
5363 when N_Itype_Reference =>
5364 Insert_After (Current_Node, New_Copy (Op_Body));
5365
5366 when N_Freeze_Entity =>
5367 New_Op_Body := New_Copy (Op_Body);
5368
5369 if Present (Entity (Op_Body))
5370 and then Freeze_Node (Entity (Op_Body)) = Op_Body
5371 then
5372 Set_Freeze_Node (Entity (Op_Body), New_Op_Body);
5373 end if;
5374
5375 Insert_After (Current_Node, New_Op_Body);
5376 Current_Node := New_Op_Body;
5377 Analyze (New_Op_Body);
5378
5379 when N_Pragma =>
5380 New_Op_Body := New_Copy (Op_Body);
5381 Insert_After (Current_Node, New_Op_Body);
5382 Current_Node := New_Op_Body;
5383 Analyze (New_Op_Body);
5384
5385 when N_Object_Declaration =>
5386 pragma Assert (not Comes_From_Source (Op_Body));
5387 New_Op_Body := New_Copy (Op_Body);
5388 Insert_After (Current_Node, New_Op_Body);
5389 Current_Node := New_Op_Body;
5390 Analyze (New_Op_Body);
5391
5392 when others =>
5393 raise Program_Error;
5394
5395 end case;
5396
5397 Next (Op_Body);
5398 end loop;
5399
5400 -- Finally, create the body of the function that maps an entry index
5401 -- into the corresponding body index, except when there is no entry,
5402 -- or in a ravenscar-like profile (no abort, no entry queue, 1 entry)
5403
5404 if Has_Entries
5405 and then (Abort_Allowed
5406 or else Restriction_Active (No_Entry_Queue) = False
5407 or else Num_Entries > 1)
5408 then
5409 New_Op_Body := Build_Find_Body_Index (Pid);
5410 Insert_After (Current_Node, New_Op_Body);
5411 Current_Node := New_Op_Body;
5412 Analyze (New_Op_Body);
5413 end if;
5414
5415 -- Ada 2005 (AI-345): Construct the primitive entry wrapper bodies
5416 -- after the protected body. At this point the entry specs have been
5417 -- created, frozen and included in the dispatch table for the
5418 -- protected type.
5419
5420 pragma Assert (Present (Corresponding_Record_Type (Pid)));
5421
5422 if Ada_Version >= Ada_05
5423 and then Present (Protected_Definition (Parent (Pid)))
5424 and then Present (Abstract_Interfaces
5425 (Corresponding_Record_Type (Pid)))
5426 then
5427 declare
5428 Vis_Decl : Node_Id :=
5429 First (Visible_Declarations
5430 (Protected_Definition (Parent (Pid))));
5431 Wrap_Body : Node_Id;
5432
5433 begin
5434 -- Examine the visible declarations of the protected type,
5435 -- looking for an entry declaration. We do not consider
5436 -- entry families since they can not have dispatching
5437 -- operations, thus they do not need entry wrappers.
5438
5439 while Present (Vis_Decl) loop
5440 if Nkind (Vis_Decl) = N_Entry_Declaration then
5441 Wrap_Body :=
5442 Build_Wrapper_Body (Loc,
5443 Proc_Nam => Defining_Identifier (Vis_Decl),
5444 Obj_Typ => Corresponding_Record_Type (Pid),
5445 Formals => Parameter_Specifications (Vis_Decl));
5446
5447 if Wrap_Body /= Empty then
5448 Insert_After (Current_Node, Wrap_Body);
5449 Current_Node := Wrap_Body;
5450
5451 Analyze (Wrap_Body);
5452 end if;
5453
5454 elsif Nkind (Vis_Decl) = N_Subprogram_Declaration then
5455 Wrap_Body :=
5456 Build_Wrapper_Body (Loc,
5457 Proc_Nam => Defining_Unit_Name
5458 (Specification (Vis_Decl)),
5459 Obj_Typ => Corresponding_Record_Type (Pid),
5460 Formals => Parameter_Specifications
5461 (Specification (Vis_Decl)));
5462
5463 if Wrap_Body /= Empty then
5464 Insert_After (Current_Node, Wrap_Body);
5465 Current_Node := Wrap_Body;
5466
5467 Analyze (Wrap_Body);
5468 end if;
5469 end if;
5470
5471 Next (Vis_Decl);
5472 end loop;
5473 end;
5474 end if;
5475 end Expand_N_Protected_Body;
5476
5477 -----------------------------------------
5478 -- Expand_N_Protected_Type_Declaration --
5479 -----------------------------------------
5480
5481 -- First we create a corresponding record type declaration used to
5482 -- represent values of this protected type.
5483 -- The general form of this type declaration is
5484
5485 -- type poV (discriminants) is record
5486 -- _Object : aliased <kind>Protection
5487 -- [(<entry count> [, <handler count>])];
5488 -- [entry_family : array (bounds) of Void;]
5489 -- <private data fields>
5490 -- end record;
5491
5492 -- The discriminants are present only if the corresponding protected
5493 -- type has discriminants, and they exactly mirror the protected type
5494 -- discriminants. The private data fields similarly mirror the
5495 -- private declarations of the protected type.
5496
5497 -- The Object field is always present. It contains RTS specific data
5498 -- used to control the protected object. It is declared as Aliased
5499 -- so that it can be passed as a pointer to the RTS. This allows the
5500 -- protected record to be referenced within RTS data structures.
5501 -- An appropriate Protection type and discriminant are generated.
5502
5503 -- The Service field is present for protected objects with entries. It
5504 -- contains sufficient information to allow the entry service procedure
5505 -- for this object to be called when the object is not known till runtime.
5506
5507 -- One entry_family component is present for each entry family in the
5508 -- task definition (see Expand_N_Task_Type_Declaration).
5509
5510 -- When a protected object is declared, an instance of the protected type
5511 -- value record is created. The elaboration of this declaration creates
5512 -- the correct bounds for the entry families, and also evaluates the
5513 -- priority expression if needed. The initialization routine for
5514 -- the protected type itself then calls Initialize_Protection with
5515 -- appropriate parameters to initialize the value of the Task_Id field.
5516 -- Install_Handlers may be also called if a pragma Attach_Handler applies.
5517
5518 -- Note: this record is passed to the subprograms created by the
5519 -- expansion of protected subprograms and entries. It is an in parameter
5520 -- to protected functions and an in out parameter to procedures and
5521 -- entry bodies. The Entity_Id for this created record type is placed
5522 -- in the Corresponding_Record_Type field of the associated protected
5523 -- type entity.
5524
5525 -- Next we create a procedure specifications for protected subprograms
5526 -- and entry bodies. For each protected subprograms two subprograms are
5527 -- created, an unprotected and a protected version. The unprotected
5528 -- version is called from within other operations of the same protected
5529 -- object.
5530
5531 -- We also build the call to register the procedure if a pragma
5532 -- Interrupt_Handler applies.
5533
5534 -- A single subprogram is created to service all entry bodies; it has an
5535 -- additional boolean out parameter indicating that the previous entry
5536 -- call made by the current task was serviced immediately, i.e. not by
5537 -- proxy. The O parameter contains a pointer to a record object of the
5538 -- type described above. An untyped interface is used here to allow this
5539 -- procedure to be called in places where the type of the object to be
5540 -- serviced is not known. This must be done, for example, when a call
5541 -- that may have been requeued is cancelled; the corresponding object
5542 -- must be serviced, but which object that is not known till runtime.
5543
5544 -- procedure ptypeS
5545 -- (O : System.Address; P : out Boolean);
5546 -- procedure pprocN (_object : in out poV);
5547 -- procedure pproc (_object : in out poV);
5548 -- function pfuncN (_object : poV);
5549 -- function pfunc (_object : poV);
5550 -- ...
5551
5552 -- Note that this must come after the record type declaration, since
5553 -- the specs refer to this type.
5554
5555 procedure Expand_N_Protected_Type_Declaration (N : Node_Id) is
5556 Loc : constant Source_Ptr := Sloc (N);
5557 Prottyp : constant Entity_Id := Defining_Identifier (N);
5558 Protnm : constant Name_Id := Chars (Prottyp);
5559
5560 Pdef : constant Node_Id := Protected_Definition (N);
5561 -- This contains two lists; one for visible and one for private decls
5562
5563 Rec_Decl : Node_Id;
5564 Cdecls : List_Id;
5565 Discr_Map : constant Elist_Id := New_Elmt_List;
5566 Priv : Node_Id;
5567 Pent : Entity_Id;
5568 New_Priv : Node_Id;
5569 Comp : Node_Id;
5570 Comp_Id : Entity_Id;
5571 Sub : Node_Id;
5572 Current_Node : Node_Id := N;
5573 Bdef : Entity_Id := Empty; -- avoid uninit warning
5574 Edef : Entity_Id := Empty; -- avoid uninit warning
5575 Entries_Aggr : Node_Id;
5576 Body_Id : Entity_Id;
5577 Body_Arr : Node_Id;
5578 E_Count : Int;
5579 Object_Comp : Node_Id;
5580
5581 procedure Register_Handler;
5582 -- for a protected operation that is an interrupt handler, add the
5583 -- freeze action that will register it as such.
5584
5585 ----------------------
5586 -- Register_Handler --
5587 ----------------------
5588
5589 procedure Register_Handler is
5590
5591 -- All semantic checks already done in Sem_Prag
5592
5593 Prot_Proc : constant Entity_Id :=
5594 Defining_Unit_Name
5595 (Specification (Current_Node));
5596
5597 Proc_Address : constant Node_Id :=
5598 Make_Attribute_Reference (Loc,
5599 Prefix => New_Reference_To (Prot_Proc, Loc),
5600 Attribute_Name => Name_Address);
5601
5602 RTS_Call : constant Entity_Id :=
5603 Make_Procedure_Call_Statement (Loc,
5604 Name =>
5605 New_Reference_To (
5606 RTE (RE_Register_Interrupt_Handler), Loc),
5607 Parameter_Associations =>
5608 New_List (Proc_Address));
5609 begin
5610 Append_Freeze_Action (Prot_Proc, RTS_Call);
5611 end Register_Handler;
5612
5613 -- Start of processing for Expand_N_Protected_Type_Declaration
5614
5615 begin
5616 if Present (Corresponding_Record_Type (Prottyp)) then
5617 return;
5618 else
5619 Rec_Decl := Build_Corresponding_Record (N, Prottyp, Loc);
5620 Cdecls := Component_Items
5621 (Component_List (Type_Definition (Rec_Decl)));
5622 end if;
5623
5624 -- Ada 2005 (AI-345): Propagate the attribute that contains the list
5625 -- of implemented interfaces.
5626
5627 Set_Interface_List (Type_Definition (Rec_Decl), Interface_List (N));
5628
5629 Qualify_Entity_Names (N);
5630
5631 -- If the type has discriminants, their occurrences in the declaration
5632 -- have been replaced by the corresponding discriminals. For components
5633 -- that are constrained by discriminants, their homologues in the
5634 -- corresponding record type must refer to the discriminants of that
5635 -- record, so we must apply a new renaming to subtypes_indications:
5636
5637 -- protected discriminant => discriminal => record discriminant.
5638 -- This replacement is not applied to default expressions, for which
5639 -- the discriminal is correct.
5640
5641 if Has_Discriminants (Prottyp) then
5642 declare
5643 Disc : Entity_Id;
5644 Decl : Node_Id;
5645
5646 begin
5647 Disc := First_Discriminant (Prottyp);
5648 Decl := First (Discriminant_Specifications (Rec_Decl));
5649
5650 while Present (Disc) loop
5651 Append_Elmt (Discriminal (Disc), Discr_Map);
5652 Append_Elmt (Defining_Identifier (Decl), Discr_Map);
5653 Next_Discriminant (Disc);
5654 Next (Decl);
5655 end loop;
5656 end;
5657 end if;
5658
5659 -- Fill in the component declarations
5660
5661 -- Add components for entry families. For each entry family,
5662 -- create an anonymous type declaration with the same size, and
5663 -- analyze the type.
5664
5665 Collect_Entry_Families (Loc, Cdecls, Current_Node, Prottyp);
5666
5667 -- Prepend the _Object field with the right type to the component
5668 -- list. We need to compute the number of entries, and in some cases
5669 -- the number of Attach_Handler pragmas.
5670
5671 declare
5672 Ritem : Node_Id;
5673 Num_Attach_Handler : Int := 0;
5674 Protection_Subtype : Node_Id;
5675 Entry_Count_Expr : constant Node_Id :=
5676 Build_Entry_Count_Expression
5677 (Prottyp, Cdecls, Loc);
5678
5679 begin
5680 if Has_Attach_Handler (Prottyp) then
5681 Ritem := First_Rep_Item (Prottyp);
5682 while Present (Ritem) loop
5683 if Nkind (Ritem) = N_Pragma
5684 and then Chars (Ritem) = Name_Attach_Handler
5685 then
5686 Num_Attach_Handler := Num_Attach_Handler + 1;
5687 end if;
5688
5689 Next_Rep_Item (Ritem);
5690 end loop;
5691
5692 if Restricted_Profile then
5693 if Has_Entries (Prottyp) then
5694 Protection_Subtype :=
5695 New_Reference_To (RTE (RE_Protection_Entry), Loc);
5696 else
5697 Protection_Subtype :=
5698 New_Reference_To (RTE (RE_Protection), Loc);
5699 end if;
5700 else
5701 Protection_Subtype :=
5702 Make_Subtype_Indication
5703 (Sloc => Loc,
5704 Subtype_Mark =>
5705 New_Reference_To
5706 (RTE (RE_Static_Interrupt_Protection), Loc),
5707 Constraint =>
5708 Make_Index_Or_Discriminant_Constraint (
5709 Sloc => Loc,
5710 Constraints => New_List (
5711 Entry_Count_Expr,
5712 Make_Integer_Literal (Loc, Num_Attach_Handler))));
5713 end if;
5714
5715 elsif Has_Interrupt_Handler (Prottyp) then
5716 Protection_Subtype :=
5717 Make_Subtype_Indication (
5718 Sloc => Loc,
5719 Subtype_Mark => New_Reference_To
5720 (RTE (RE_Dynamic_Interrupt_Protection), Loc),
5721 Constraint =>
5722 Make_Index_Or_Discriminant_Constraint (
5723 Sloc => Loc,
5724 Constraints => New_List (Entry_Count_Expr)));
5725
5726 elsif Has_Entries (Prottyp) then
5727 if Abort_Allowed
5728 or else Restriction_Active (No_Entry_Queue) = False
5729 or else Number_Entries (Prottyp) > 1
5730 then
5731 Protection_Subtype :=
5732 Make_Subtype_Indication (
5733 Sloc => Loc,
5734 Subtype_Mark =>
5735 New_Reference_To (RTE (RE_Protection_Entries), Loc),
5736 Constraint =>
5737 Make_Index_Or_Discriminant_Constraint (
5738 Sloc => Loc,
5739 Constraints => New_List (Entry_Count_Expr)));
5740
5741 else
5742 Protection_Subtype :=
5743 New_Reference_To (RTE (RE_Protection_Entry), Loc);
5744 end if;
5745
5746 else
5747 Protection_Subtype := New_Reference_To (RTE (RE_Protection), Loc);
5748 end if;
5749
5750 Object_Comp :=
5751 Make_Component_Declaration (Loc,
5752 Defining_Identifier =>
5753 Make_Defining_Identifier (Loc, Name_uObject),
5754 Component_Definition =>
5755 Make_Component_Definition (Loc,
5756 Aliased_Present => True,
5757 Subtype_Indication => Protection_Subtype));
5758 end;
5759
5760 pragma Assert (Present (Pdef));
5761
5762 -- Add private field components
5763
5764 if Present (Private_Declarations (Pdef)) then
5765 Priv := First (Private_Declarations (Pdef));
5766
5767 while Present (Priv) loop
5768
5769 if Nkind (Priv) = N_Component_Declaration then
5770 Pent := Defining_Identifier (Priv);
5771 New_Priv :=
5772 Make_Component_Declaration (Loc,
5773 Defining_Identifier =>
5774 Make_Defining_Identifier (Sloc (Pent), Chars (Pent)),
5775 Component_Definition =>
5776 Make_Component_Definition (Sloc (Pent),
5777 Aliased_Present => False,
5778 Subtype_Indication =>
5779 New_Copy_Tree (Subtype_Indication
5780 (Component_Definition (Priv)),
5781 Discr_Map)),
5782 Expression => Expression (Priv));
5783
5784 Append_To (Cdecls, New_Priv);
5785
5786 elsif Nkind (Priv) = N_Subprogram_Declaration then
5787
5788 -- Make the unprotected version of the subprogram available
5789 -- for expansion of intra object calls. There is need for
5790 -- a protected version only if the subprogram is an interrupt
5791 -- handler, otherwise this operation can only be called from
5792 -- within the body.
5793
5794 Sub :=
5795 Make_Subprogram_Declaration (Loc,
5796 Specification =>
5797 Build_Protected_Sub_Specification
5798 (Priv, Prottyp, Unprotected => True));
5799
5800 Insert_After (Current_Node, Sub);
5801 Analyze (Sub);
5802
5803 Set_Protected_Body_Subprogram
5804 (Defining_Unit_Name (Specification (Priv)),
5805 Defining_Unit_Name (Specification (Sub)));
5806
5807 Current_Node := Sub;
5808 if Is_Interrupt_Handler
5809 (Defining_Unit_Name (Specification (Priv)))
5810 then
5811 Sub :=
5812 Make_Subprogram_Declaration (Loc,
5813 Specification =>
5814 Build_Protected_Sub_Specification
5815 (Priv, Prottyp, Unprotected => False));
5816
5817 Insert_After (Current_Node, Sub);
5818 Analyze (Sub);
5819 Current_Node := Sub;
5820
5821 if not Restricted_Profile then
5822 Register_Handler;
5823 end if;
5824 end if;
5825 end if;
5826
5827 Next (Priv);
5828 end loop;
5829 end if;
5830
5831 -- Put the _Object component after the private component so that it
5832 -- be finalized early as required by 9.4 (20)
5833
5834 Append_To (Cdecls, Object_Comp);
5835
5836 Insert_After (Current_Node, Rec_Decl);
5837 Current_Node := Rec_Decl;
5838
5839 -- Analyze the record declaration immediately after construction,
5840 -- because the initialization procedure is needed for single object
5841 -- declarations before the next entity is analyzed (the freeze call
5842 -- that generates this initialization procedure is found below).
5843
5844 Analyze (Rec_Decl, Suppress => All_Checks);
5845
5846 -- Ada 2005 (AI-345): Construct the primitive entry wrappers before
5847 -- the corresponding record is frozen
5848
5849 if Ada_Version >= Ada_05
5850 and then Present (Visible_Declarations (Pdef))
5851 and then Present (Corresponding_Record_Type
5852 (Defining_Identifier (Parent (Pdef))))
5853 and then Present (Abstract_Interfaces
5854 (Corresponding_Record_Type
5855 (Defining_Identifier (Parent (Pdef)))))
5856 then
5857 declare
5858 Current_Node : Node_Id := Rec_Decl;
5859 Vis_Decl : Node_Id;
5860 Wrap_Spec : Node_Id;
5861 New_N : Node_Id;
5862
5863 begin
5864 -- Examine the visible declarations of the protected type, looking
5865 -- for declarations of entries, and subprograms. We do not
5866 -- consider entry families since they can not have dispatching
5867 -- operations, thus they do not need entry wrappers.
5868
5869 Vis_Decl := First (Visible_Declarations (Pdef));
5870
5871 while Present (Vis_Decl) loop
5872
5873 Wrap_Spec := Empty;
5874
5875 if Nkind (Vis_Decl) = N_Entry_Declaration
5876 and then not Present (Discrete_Subtype_Definition (Vis_Decl))
5877 then
5878 Wrap_Spec :=
5879 Build_Wrapper_Spec (Loc,
5880 Proc_Nam => Defining_Identifier (Vis_Decl),
5881 Obj_Typ => Defining_Identifier (Rec_Decl),
5882 Formals => Parameter_Specifications (Vis_Decl));
5883
5884 elsif Nkind (Vis_Decl) = N_Subprogram_Declaration then
5885 Wrap_Spec :=
5886 Build_Wrapper_Spec (Loc,
5887 Proc_Nam => Defining_Unit_Name
5888 (Specification (Vis_Decl)),
5889 Obj_Typ => Defining_Identifier (Rec_Decl),
5890 Formals => Parameter_Specifications
5891 (Specification (Vis_Decl)));
5892
5893 end if;
5894
5895 if Wrap_Spec /= Empty then
5896 New_N := Make_Subprogram_Declaration (Loc,
5897 Specification => Wrap_Spec);
5898
5899 Insert_After (Current_Node, New_N);
5900 Current_Node := New_N;
5901
5902 Analyze (New_N);
5903 end if;
5904
5905 Next (Vis_Decl);
5906 end loop;
5907 end;
5908 end if;
5909
5910 -- Collect pointers to entry bodies and their barriers, to be placed
5911 -- in the Entry_Bodies_Array for the type. For each entry/family we
5912 -- add an expression to the aggregate which is the initial value of
5913 -- this array. The array is declared after all protected subprograms.
5914
5915 if Has_Entries (Prottyp) then
5916 Entries_Aggr :=
5917 Make_Aggregate (Loc, Expressions => New_List);
5918
5919 else
5920 Entries_Aggr := Empty;
5921 end if;
5922
5923 -- Build two new procedure specifications for each protected
5924 -- subprogram; one to call from outside the object and one to
5925 -- call from inside. Build a barrier function and an entry
5926 -- body action procedure specification for each protected entry.
5927 -- Initialize the entry body array. If subprogram is flagged as
5928 -- eliminated, do not generate any internal operations.
5929
5930 E_Count := 0;
5931
5932 Comp := First (Visible_Declarations (Pdef));
5933
5934 while Present (Comp) loop
5935 if Nkind (Comp) = N_Subprogram_Declaration
5936 and then not Is_Eliminated (Defining_Entity (Comp))
5937 then
5938 Sub :=
5939 Make_Subprogram_Declaration (Loc,
5940 Specification =>
5941 Build_Protected_Sub_Specification
5942 (Comp, Prottyp, Unprotected => True));
5943
5944 Insert_After (Current_Node, Sub);
5945 Analyze (Sub);
5946
5947 Set_Protected_Body_Subprogram
5948 (Defining_Unit_Name (Specification (Comp)),
5949 Defining_Unit_Name (Specification (Sub)));
5950
5951 -- Make the protected version of the subprogram available
5952 -- for expansion of external calls.
5953
5954 Current_Node := Sub;
5955
5956 Sub :=
5957 Make_Subprogram_Declaration (Loc,
5958 Specification =>
5959 Build_Protected_Sub_Specification
5960 (Comp, Prottyp, Unprotected => False));
5961
5962 Insert_After (Current_Node, Sub);
5963 Analyze (Sub);
5964 Current_Node := Sub;
5965
5966 -- If a pragma Interrupt_Handler applies, build and add
5967 -- a call to Register_Interrupt_Handler to the freezing actions
5968 -- of the protected version (Current_Node) of the subprogram:
5969 -- system.interrupts.register_interrupt_handler
5970 -- (prot_procP'address);
5971
5972 if not Restricted_Profile
5973 and then Is_Interrupt_Handler
5974 (Defining_Unit_Name (Specification (Comp)))
5975 then
5976 Register_Handler;
5977 end if;
5978
5979 elsif Nkind (Comp) = N_Entry_Declaration then
5980 E_Count := E_Count + 1;
5981 Comp_Id := Defining_Identifier (Comp);
5982 Set_Privals_Chain (Comp_Id, New_Elmt_List);
5983 Edef :=
5984 Make_Defining_Identifier (Loc,
5985 Build_Selected_Name
5986 (Protnm,
5987 New_External_Name (Chars (Comp_Id), Suffix_Index => -1),
5988 'E'));
5989 Sub :=
5990 Make_Subprogram_Declaration (Loc,
5991 Specification =>
5992 Build_Protected_Entry_Specification (Edef, Comp_Id, Loc));
5993
5994 Insert_After (Current_Node, Sub);
5995 Analyze (Sub);
5996
5997 Set_Protected_Body_Subprogram (
5998 Defining_Identifier (Comp),
5999 Defining_Unit_Name (Specification (Sub)));
6000
6001 Current_Node := Sub;
6002
6003 Bdef :=
6004 Make_Defining_Identifier (Loc,
6005 Build_Selected_Name
6006 (Protnm,
6007 New_External_Name (Chars (Comp_Id), Suffix_Index => -1),
6008 'B'));
6009 Sub :=
6010 Make_Subprogram_Declaration (Loc,
6011 Specification =>
6012 Build_Barrier_Function_Specification (Bdef, Loc));
6013
6014 Insert_After (Current_Node, Sub);
6015 Analyze (Sub);
6016 Set_Protected_Body_Subprogram (Bdef, Bdef);
6017 Set_Barrier_Function (Comp_Id, Bdef);
6018 Set_Scope (Bdef, Scope (Comp_Id));
6019 Current_Node := Sub;
6020
6021 -- Collect pointers to the protected subprogram and the barrier
6022 -- of the current entry, for insertion into Entry_Bodies_Array.
6023
6024 Append (
6025 Make_Aggregate (Loc,
6026 Expressions => New_List (
6027 Make_Attribute_Reference (Loc,
6028 Prefix => New_Reference_To (Bdef, Loc),
6029 Attribute_Name => Name_Unrestricted_Access),
6030 Make_Attribute_Reference (Loc,
6031 Prefix => New_Reference_To (Edef, Loc),
6032 Attribute_Name => Name_Unrestricted_Access))),
6033 Expressions (Entries_Aggr));
6034
6035 end if;
6036
6037 Next (Comp);
6038 end loop;
6039
6040 -- If there are some private entry declarations, expand it as if they
6041 -- were visible entries.
6042
6043 if Present (Private_Declarations (Pdef)) then
6044 Comp := First (Private_Declarations (Pdef));
6045
6046 while Present (Comp) loop
6047 if Nkind (Comp) = N_Entry_Declaration then
6048 E_Count := E_Count + 1;
6049 Comp_Id := Defining_Identifier (Comp);
6050 Set_Privals_Chain (Comp_Id, New_Elmt_List);
6051 Edef :=
6052 Make_Defining_Identifier (Loc,
6053 Build_Selected_Name
6054 (Protnm,
6055 New_External_Name (Chars (Comp_Id), Suffix_Index => -1),
6056 'E'));
6057
6058 Sub :=
6059 Make_Subprogram_Declaration (Loc,
6060 Specification =>
6061 Build_Protected_Entry_Specification (Edef, Comp_Id, Loc));
6062
6063 Insert_After (Current_Node, Sub);
6064 Analyze (Sub);
6065
6066 Set_Protected_Body_Subprogram (
6067 Defining_Identifier (Comp),
6068 Defining_Unit_Name (Specification (Sub)));
6069
6070 Current_Node := Sub;
6071
6072 Bdef :=
6073 Make_Defining_Identifier (Loc,
6074 Build_Selected_Name
6075 (Protnm,
6076 New_External_Name (Chars (Comp_Id), Suffix_Index => -1),
6077 'B'));
6078 Sub :=
6079 Make_Subprogram_Declaration (Loc,
6080 Specification =>
6081 Build_Barrier_Function_Specification (Bdef, Loc));
6082
6083 Insert_After (Current_Node, Sub);
6084 Analyze (Sub);
6085 Set_Protected_Body_Subprogram (Bdef, Bdef);
6086 Set_Barrier_Function (Comp_Id, Bdef);
6087 Set_Scope (Bdef, Scope (Comp_Id));
6088 Current_Node := Sub;
6089
6090 -- Collect pointers to the protected subprogram and the
6091 -- barrier of the current entry, for insertion into
6092 -- Entry_Bodies_Array.
6093
6094 Append (
6095 Make_Aggregate (Loc,
6096 Expressions => New_List (
6097 Make_Attribute_Reference (Loc,
6098 Prefix => New_Reference_To (Bdef, Loc),
6099 Attribute_Name => Name_Unrestricted_Access),
6100 Make_Attribute_Reference (Loc,
6101 Prefix => New_Reference_To (Edef, Loc),
6102 Attribute_Name => Name_Unrestricted_Access))),
6103 Expressions (Entries_Aggr));
6104 end if;
6105
6106 Next (Comp);
6107 end loop;
6108 end if;
6109
6110 -- Emit declaration for Entry_Bodies_Array, now that the addresses of
6111 -- all protected subprograms have been collected.
6112
6113 if Has_Entries (Prottyp) then
6114 Body_Id := Make_Defining_Identifier (Sloc (Prottyp),
6115 New_External_Name (Chars (Prottyp), 'A'));
6116
6117 if Abort_Allowed
6118 or else Restriction_Active (No_Entry_Queue) = False
6119 or else E_Count > 1
6120 then
6121 Body_Arr := Make_Object_Declaration (Loc,
6122 Defining_Identifier => Body_Id,
6123 Aliased_Present => True,
6124 Object_Definition =>
6125 Make_Subtype_Indication (Loc,
6126 Subtype_Mark => New_Reference_To (
6127 RTE (RE_Protected_Entry_Body_Array), Loc),
6128 Constraint =>
6129 Make_Index_Or_Discriminant_Constraint (Loc,
6130 Constraints => New_List (
6131 Make_Range (Loc,
6132 Make_Integer_Literal (Loc, 1),
6133 Make_Integer_Literal (Loc, E_Count))))),
6134 Expression => Entries_Aggr);
6135
6136 else
6137 Body_Arr := Make_Object_Declaration (Loc,
6138 Defining_Identifier => Body_Id,
6139 Aliased_Present => True,
6140 Object_Definition => New_Reference_To (RTE (RE_Entry_Body), Loc),
6141 Expression =>
6142 Make_Aggregate (Loc,
6143 Expressions => New_List (
6144 Make_Attribute_Reference (Loc,
6145 Prefix => New_Reference_To (Bdef, Loc),
6146 Attribute_Name => Name_Unrestricted_Access),
6147 Make_Attribute_Reference (Loc,
6148 Prefix => New_Reference_To (Edef, Loc),
6149 Attribute_Name => Name_Unrestricted_Access))));
6150 end if;
6151
6152 -- A pointer to this array will be placed in the corresponding
6153 -- record by its initialization procedure, so this needs to be
6154 -- analyzed here.
6155
6156 Insert_After (Current_Node, Body_Arr);
6157 Current_Node := Body_Arr;
6158 Analyze (Body_Arr);
6159
6160 Set_Entry_Bodies_Array (Prottyp, Body_Id);
6161
6162 -- Finally, build the function that maps an entry index into the
6163 -- corresponding body. A pointer to this function is placed in each
6164 -- object of the type. Except for a ravenscar-like profile (no abort,
6165 -- no entry queue, 1 entry)
6166
6167 if Abort_Allowed
6168 or else Restriction_Active (No_Entry_Queue) = False
6169 or else E_Count > 1
6170 then
6171 Sub :=
6172 Make_Subprogram_Declaration (Loc,
6173 Specification => Build_Find_Body_Index_Spec (Prottyp));
6174 Insert_After (Current_Node, Sub);
6175 Analyze (Sub);
6176 end if;
6177 end if;
6178 end Expand_N_Protected_Type_Declaration;
6179
6180 --------------------------------
6181 -- Expand_N_Requeue_Statement --
6182 --------------------------------
6183
6184 -- A requeue statement is expanded into one of four GNARLI operations,
6185 -- depending on the source and destination (task or protected object).
6186 -- In addition, code must be generated to jump around the remainder of
6187 -- processing for the original entry and, if the destination is a
6188 -- (different) protected object, to attempt to service it.
6189 -- The following illustrates the various cases:
6190
6191 -- procedure entE
6192 -- (O : System.Address;
6193 -- P : System.Address;
6194 -- E : Protected_Entry_Index)
6195 -- is
6196 -- <discriminant renamings>
6197 -- <private object renamings>
6198 -- type poVP is access poV;
6199 -- _Object : ptVP := ptVP!(O);
6200
6201 -- begin
6202 -- begin
6203 -- <start of statement sequence for entry>
6204
6205 -- -- Requeue from one protected entry body to another protected
6206 -- -- entry.
6207
6208 -- Requeue_Protected_Entry (
6209 -- _object._object'Access,
6210 -- new._object'Access,
6211 -- E,
6212 -- Abort_Present);
6213 -- return;
6214
6215 -- <some more of the statement sequence for entry>
6216
6217 -- -- Requeue from an entry body to a task entry
6218
6219 -- Requeue_Protected_To_Task_Entry (
6220 -- New._task_id,
6221 -- E,
6222 -- Abort_Present);
6223 -- return;
6224
6225 -- <rest of statement sequence for entry>
6226 -- Complete_Entry_Body (_Object._Object);
6227
6228 -- exception
6229 -- when all others =>
6230 -- Exceptional_Complete_Entry_Body (
6231 -- _Object._Object, Get_GNAT_Exception);
6232 -- end;
6233 -- end entE;
6234
6235 -- Requeue of a task entry call to a task entry
6236
6237 -- Accept_Call (E, Ann);
6238 -- <start of statement sequence for accept statement>
6239 -- Requeue_Task_Entry (New._task_id, E, Abort_Present);
6240 -- goto Lnn;
6241 -- <rest of statement sequence for accept statement>
6242 -- <<Lnn>>
6243 -- Complete_Rendezvous;
6244
6245 -- exception
6246 -- when all others =>
6247 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
6248
6249 -- Requeue of a task entry call to a protected entry
6250
6251 -- Accept_Call (E, Ann);
6252 -- <start of statement sequence for accept statement>
6253 -- Requeue_Task_To_Protected_Entry (
6254 -- new._object'Access,
6255 -- E,
6256 -- Abort_Present);
6257 -- newS (new, Pnn);
6258 -- goto Lnn;
6259 -- <rest of statement sequence for accept statement>
6260 -- <<Lnn>>
6261 -- Complete_Rendezvous;
6262
6263 -- exception
6264 -- when all others =>
6265 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
6266
6267 -- Further details on these expansions can be found in
6268 -- Expand_N_Protected_Body and Expand_N_Accept_Statement.
6269
6270 procedure Expand_N_Requeue_Statement (N : Node_Id) is
6271 Loc : constant Source_Ptr := Sloc (N);
6272 Acc_Stat : Node_Id;
6273 Concval : Node_Id;
6274 Ename : Node_Id;
6275 Index : Node_Id;
6276 Conctyp : Entity_Id;
6277 Oldtyp : Entity_Id;
6278 Lab_Node : Node_Id;
6279 Rcall : Node_Id;
6280 Abortable : Node_Id;
6281 Skip_Stat : Node_Id;
6282 Self_Param : Node_Id;
6283 New_Param : Node_Id;
6284 Params : List_Id;
6285 RTS_Call : Entity_Id;
6286
6287 begin
6288 Abortable :=
6289 New_Occurrence_Of (Boolean_Literals (Abort_Present (N)), Loc);
6290
6291 -- Set up the target object
6292
6293 Extract_Entry (N, Concval, Ename, Index);
6294 Conctyp := Etype (Concval);
6295 New_Param := Concurrent_Ref (Concval);
6296
6297 -- The target entry index and abortable flag are the same for all cases
6298
6299 Params := New_List (
6300 Entry_Index_Expression (Loc, Entity (Ename), Index, Conctyp),
6301 Abortable);
6302
6303 -- Determine proper GNARLI call and required additional parameters
6304 -- Loop to find nearest enclosing task type or protected type
6305
6306 Oldtyp := Current_Scope;
6307 loop
6308 if Is_Task_Type (Oldtyp) then
6309 if Is_Task_Type (Conctyp) then
6310 RTS_Call := RTE (RE_Requeue_Task_Entry);
6311
6312 else
6313 pragma Assert (Is_Protected_Type (Conctyp));
6314 RTS_Call := RTE (RE_Requeue_Task_To_Protected_Entry);
6315 New_Param :=
6316 Make_Attribute_Reference (Loc,
6317 Prefix => New_Param,
6318 Attribute_Name => Name_Unchecked_Access);
6319 end if;
6320
6321 Prepend (New_Param, Params);
6322 exit;
6323
6324 elsif Is_Protected_Type (Oldtyp) then
6325 Self_Param :=
6326 Make_Attribute_Reference (Loc,
6327 Prefix => Concurrent_Ref (New_Occurrence_Of (Oldtyp, Loc)),
6328 Attribute_Name => Name_Unchecked_Access);
6329
6330 if Is_Task_Type (Conctyp) then
6331 RTS_Call := RTE (RE_Requeue_Protected_To_Task_Entry);
6332
6333 else
6334 pragma Assert (Is_Protected_Type (Conctyp));
6335 RTS_Call := RTE (RE_Requeue_Protected_Entry);
6336 New_Param :=
6337 Make_Attribute_Reference (Loc,
6338 Prefix => New_Param,
6339 Attribute_Name => Name_Unchecked_Access);
6340 end if;
6341
6342 Prepend (New_Param, Params);
6343 Prepend (Self_Param, Params);
6344 exit;
6345
6346 -- If neither task type or protected type, must be in some
6347 -- inner enclosing block, so move on out
6348
6349 else
6350 Oldtyp := Scope (Oldtyp);
6351 end if;
6352 end loop;
6353
6354 -- Create the GNARLI call
6355
6356 Rcall := Make_Procedure_Call_Statement (Loc,
6357 Name =>
6358 New_Occurrence_Of (RTS_Call, Loc),
6359 Parameter_Associations => Params);
6360
6361 Rewrite (N, Rcall);
6362 Analyze (N);
6363
6364 if Is_Protected_Type (Oldtyp) then
6365
6366 -- Build the return statement to skip the rest of the entry body
6367
6368 Skip_Stat := Make_Return_Statement (Loc);
6369
6370 else
6371 -- If the requeue is within a task, find the end label of the
6372 -- enclosing accept statement.
6373
6374 Acc_Stat := Parent (N);
6375 while Nkind (Acc_Stat) /= N_Accept_Statement loop
6376 Acc_Stat := Parent (Acc_Stat);
6377 end loop;
6378
6379 -- The last statement is the second label, used for completing the
6380 -- rendezvous the usual way.
6381 -- The label we are looking for is right before it.
6382
6383 Lab_Node :=
6384 Prev (Last (Statements (Handled_Statement_Sequence (Acc_Stat))));
6385
6386 pragma Assert (Nkind (Lab_Node) = N_Label);
6387
6388 -- Build the goto statement to skip the rest of the accept
6389 -- statement.
6390
6391 Skip_Stat :=
6392 Make_Goto_Statement (Loc,
6393 Name => New_Occurrence_Of (Entity (Identifier (Lab_Node)), Loc));
6394 end if;
6395
6396 Set_Analyzed (Skip_Stat);
6397
6398 Insert_After (N, Skip_Stat);
6399 end Expand_N_Requeue_Statement;
6400
6401 -------------------------------
6402 -- Expand_N_Selective_Accept --
6403 -------------------------------
6404
6405 procedure Expand_N_Selective_Accept (N : Node_Id) is
6406 Loc : constant Source_Ptr := Sloc (N);
6407 Alts : constant List_Id := Select_Alternatives (N);
6408
6409 -- Note: in the below declarations a lot of new lists are allocated
6410 -- unconditionally which may well not end up being used. That's
6411 -- not a good idea since it wastes space gratuitously ???
6412
6413 Accept_Case : List_Id;
6414 Accept_List : constant List_Id := New_List;
6415
6416 Alt : Node_Id;
6417 Alt_List : constant List_Id := New_List;
6418 Alt_Stats : List_Id;
6419 Ann : Entity_Id := Empty;
6420
6421 Block : Node_Id;
6422 Check_Guard : Boolean := True;
6423
6424 Decls : constant List_Id := New_List;
6425 Stats : constant List_Id := New_List;
6426 Body_List : constant List_Id := New_List;
6427 Trailing_List : constant List_Id := New_List;
6428
6429 Choices : List_Id;
6430 Else_Present : Boolean := False;
6431 Terminate_Alt : Node_Id := Empty;
6432 Select_Mode : Node_Id;
6433
6434 Delay_Case : List_Id;
6435 Delay_Count : Integer := 0;
6436 Delay_Val : Entity_Id;
6437 Delay_Index : Entity_Id;
6438 Delay_Min : Entity_Id;
6439 Delay_Num : Int := 1;
6440 Delay_Alt_List : List_Id := New_List;
6441 Delay_List : constant List_Id := New_List;
6442 D : Entity_Id;
6443 M : Entity_Id;
6444
6445 First_Delay : Boolean := True;
6446 Guard_Open : Entity_Id;
6447
6448 End_Lab : Node_Id;
6449 Index : Int := 1;
6450 Lab : Node_Id;
6451 Num_Alts : Int;
6452 Num_Accept : Nat := 0;
6453 Proc : Node_Id;
6454 Q : Node_Id;
6455 Time_Type : Entity_Id;
6456 X : Node_Id;
6457 Select_Call : Node_Id;
6458
6459 Qnam : constant Entity_Id :=
6460 Make_Defining_Identifier (Loc, New_External_Name ('S', 0));
6461
6462 Xnam : constant Entity_Id :=
6463 Make_Defining_Identifier (Loc, New_External_Name ('J', 1));
6464
6465 -----------------------
6466 -- Local subprograms --
6467 -----------------------
6468
6469 function Accept_Or_Raise return List_Id;
6470 -- For the rare case where delay alternatives all have guards, and
6471 -- all of them are closed, it is still possible that there were open
6472 -- accept alternatives with no callers. We must reexamine the
6473 -- Accept_List, and execute a selective wait with no else if some
6474 -- accept is open. If none, we raise program_error.
6475
6476 procedure Add_Accept (Alt : Node_Id);
6477 -- Process a single accept statement in a select alternative. Build
6478 -- procedure for body of accept, and add entry to dispatch table with
6479 -- expression for guard, in preparation for call to run time select.
6480
6481 function Make_And_Declare_Label (Num : Int) return Node_Id;
6482 -- Manufacture a label using Num as a serial number and declare it.
6483 -- The declaration is appended to Decls. The label marks the trailing
6484 -- statements of an accept or delay alternative.
6485
6486 function Make_Select_Call (Select_Mode : Entity_Id) return Node_Id;
6487 -- Build call to Selective_Wait runtime routine
6488
6489 procedure Process_Delay_Alternative (Alt : Node_Id; Index : Int);
6490 -- Add code to compare value of delay with previous values, and
6491 -- generate case entry for trailing statements.
6492
6493 procedure Process_Accept_Alternative
6494 (Alt : Node_Id;
6495 Index : Int;
6496 Proc : Node_Id);
6497 -- Add code to call corresponding procedure, and branch to
6498 -- trailing statements, if any.
6499
6500 ---------------------
6501 -- Accept_Or_Raise --
6502 ---------------------
6503
6504 function Accept_Or_Raise return List_Id is
6505 Cond : Node_Id;
6506 Stats : List_Id;
6507 J : constant Entity_Id := Make_Defining_Identifier (Loc,
6508 New_Internal_Name ('J'));
6509
6510 begin
6511 -- We generate the following:
6512
6513 -- for J in q'range loop
6514 -- if q(J).S /=null_task_entry then
6515 -- selective_wait (simple_mode,...);
6516 -- done := True;
6517 -- exit;
6518 -- end if;
6519 -- end loop;
6520 --
6521 -- if no rendez_vous then
6522 -- raise program_error;
6523 -- end if;
6524
6525 -- Note that the code needs to know that the selector name
6526 -- in an Accept_Alternative is named S.
6527
6528 Cond := Make_Op_Ne (Loc,
6529 Left_Opnd =>
6530 Make_Selected_Component (Loc,
6531 Prefix => Make_Indexed_Component (Loc,
6532 Prefix => New_Reference_To (Qnam, Loc),
6533 Expressions => New_List (New_Reference_To (J, Loc))),
6534 Selector_Name => Make_Identifier (Loc, Name_S)),
6535 Right_Opnd =>
6536 New_Reference_To (RTE (RE_Null_Task_Entry), Loc));
6537
6538 Stats := New_List (
6539 Make_Implicit_Loop_Statement (N,
6540 Identifier => Empty,
6541 Iteration_Scheme =>
6542 Make_Iteration_Scheme (Loc,
6543 Loop_Parameter_Specification =>
6544 Make_Loop_Parameter_Specification (Loc,
6545 Defining_Identifier => J,
6546 Discrete_Subtype_Definition =>
6547 Make_Attribute_Reference (Loc,
6548 Prefix => New_Reference_To (Qnam, Loc),
6549 Attribute_Name => Name_Range,
6550 Expressions => New_List (
6551 Make_Integer_Literal (Loc, 1))))),
6552
6553 Statements => New_List (
6554 Make_Implicit_If_Statement (N,
6555 Condition => Cond,
6556 Then_Statements => New_List (
6557 Make_Select_Call (
6558 New_Reference_To (RTE (RE_Simple_Mode), Loc)),
6559 Make_Exit_Statement (Loc))))));
6560
6561 Append_To (Stats,
6562 Make_Raise_Program_Error (Loc,
6563 Condition => Make_Op_Eq (Loc,
6564 Left_Opnd => New_Reference_To (Xnam, Loc),
6565 Right_Opnd =>
6566 New_Reference_To (RTE (RE_No_Rendezvous), Loc)),
6567 Reason => PE_All_Guards_Closed));
6568
6569 return Stats;
6570 end Accept_Or_Raise;
6571
6572 ----------------
6573 -- Add_Accept --
6574 ----------------
6575
6576 procedure Add_Accept (Alt : Node_Id) is
6577 Acc_Stm : constant Node_Id := Accept_Statement (Alt);
6578 Ename : constant Node_Id := Entry_Direct_Name (Acc_Stm);
6579 Eent : constant Entity_Id := Entity (Ename);
6580 Index : constant Node_Id := Entry_Index (Acc_Stm);
6581 Null_Body : Node_Id;
6582 Proc_Body : Node_Id;
6583 PB_Ent : Entity_Id;
6584 Expr : Node_Id;
6585 Call : Node_Id;
6586
6587 begin
6588 if No (Ann) then
6589 Ann := Node (Last_Elmt (Accept_Address (Eent)));
6590 end if;
6591
6592 if Present (Condition (Alt)) then
6593 Expr :=
6594 Make_Conditional_Expression (Loc, New_List (
6595 Condition (Alt),
6596 Entry_Index_Expression (Loc, Eent, Index, Scope (Eent)),
6597 New_Reference_To (RTE (RE_Null_Task_Entry), Loc)));
6598 else
6599 Expr :=
6600 Entry_Index_Expression
6601 (Loc, Eent, Index, Scope (Eent));
6602 end if;
6603
6604 if Present (Handled_Statement_Sequence (Accept_Statement (Alt))) then
6605 Null_Body := New_Reference_To (Standard_False, Loc);
6606
6607 if Abort_Allowed then
6608 Call := Make_Procedure_Call_Statement (Loc,
6609 Name => New_Reference_To (RTE (RE_Abort_Undefer), Loc));
6610 Insert_Before (First (Statements (Handled_Statement_Sequence (
6611 Accept_Statement (Alt)))), Call);
6612 Analyze (Call);
6613 end if;
6614
6615 PB_Ent :=
6616 Make_Defining_Identifier (Sloc (Ename),
6617 New_External_Name (Chars (Ename), 'A', Num_Accept));
6618
6619 Set_Needs_Debug_Info (PB_Ent, Comes_From_Source (Alt));
6620
6621 Proc_Body :=
6622 Make_Subprogram_Body (Loc,
6623 Specification =>
6624 Make_Procedure_Specification (Loc,
6625 Defining_Unit_Name => PB_Ent),
6626 Declarations => Declarations (Acc_Stm),
6627 Handled_Statement_Sequence =>
6628 Build_Accept_Body (Accept_Statement (Alt)));
6629
6630 -- During the analysis of the body of the accept statement, any
6631 -- zero cost exception handler records were collected in the
6632 -- Accept_Handler_Records field of the N_Accept_Alternative
6633 -- node. This is where we move them to where they belong,
6634 -- namely the newly created procedure.
6635
6636 Set_Handler_Records (PB_Ent, Accept_Handler_Records (Alt));
6637 Append (Proc_Body, Body_List);
6638
6639 else
6640 Null_Body := New_Reference_To (Standard_True, Loc);
6641
6642 -- if accept statement has declarations, insert above, given
6643 -- that we are not creating a body for the accept.
6644
6645 if Present (Declarations (Acc_Stm)) then
6646 Insert_Actions (N, Declarations (Acc_Stm));
6647 end if;
6648 end if;
6649
6650 Append_To (Accept_List,
6651 Make_Aggregate (Loc, Expressions => New_List (Null_Body, Expr)));
6652
6653 Num_Accept := Num_Accept + 1;
6654 end Add_Accept;
6655
6656 ----------------------------
6657 -- Make_And_Declare_Label --
6658 ----------------------------
6659
6660 function Make_And_Declare_Label (Num : Int) return Node_Id is
6661 Lab_Id : Node_Id;
6662
6663 begin
6664 Lab_Id := Make_Identifier (Loc, New_External_Name ('L', Num));
6665 Lab :=
6666 Make_Label (Loc, Lab_Id);
6667
6668 Append_To (Decls,
6669 Make_Implicit_Label_Declaration (Loc,
6670 Defining_Identifier =>
6671 Make_Defining_Identifier (Loc, Chars (Lab_Id)),
6672 Label_Construct => Lab));
6673
6674 return Lab;
6675 end Make_And_Declare_Label;
6676
6677 ----------------------
6678 -- Make_Select_Call --
6679 ----------------------
6680
6681 function Make_Select_Call (Select_Mode : Entity_Id) return Node_Id is
6682 Params : constant List_Id := New_List;
6683
6684 begin
6685 Append (
6686 Make_Attribute_Reference (Loc,
6687 Prefix => New_Reference_To (Qnam, Loc),
6688 Attribute_Name => Name_Unchecked_Access),
6689 Params);
6690 Append (Select_Mode, Params);
6691 Append (New_Reference_To (Ann, Loc), Params);
6692 Append (New_Reference_To (Xnam, Loc), Params);
6693
6694 return
6695 Make_Procedure_Call_Statement (Loc,
6696 Name => New_Reference_To (RTE (RE_Selective_Wait), Loc),
6697 Parameter_Associations => Params);
6698 end Make_Select_Call;
6699
6700 --------------------------------
6701 -- Process_Accept_Alternative --
6702 --------------------------------
6703
6704 procedure Process_Accept_Alternative
6705 (Alt : Node_Id;
6706 Index : Int;
6707 Proc : Node_Id)
6708 is
6709 Choices : List_Id := No_List;
6710 Alt_Stats : List_Id;
6711
6712 begin
6713 Adjust_Condition (Condition (Alt));
6714 Alt_Stats := No_List;
6715
6716 if Present (Handled_Statement_Sequence (Accept_Statement (Alt))) then
6717 Choices := New_List (
6718 Make_Integer_Literal (Loc, Index));
6719
6720 Alt_Stats := New_List (
6721 Make_Procedure_Call_Statement (Loc,
6722 Name => New_Reference_To (
6723 Defining_Unit_Name (Specification (Proc)), Loc)));
6724 end if;
6725
6726 if Statements (Alt) /= Empty_List then
6727
6728 if No (Alt_Stats) then
6729
6730 -- Accept with no body, followed by trailing statements
6731
6732 Choices := New_List (
6733 Make_Integer_Literal (Loc, Index));
6734
6735 Alt_Stats := New_List;
6736 end if;
6737
6738 -- After the call, if any, branch to to trailing statements.
6739 -- We create a label for each, as well as the corresponding
6740 -- label declaration.
6741
6742 Lab := Make_And_Declare_Label (Index);
6743 Append_To (Alt_Stats,
6744 Make_Goto_Statement (Loc,
6745 Name => New_Copy (Identifier (Lab))));
6746
6747 Append (Lab, Trailing_List);
6748 Append_List (Statements (Alt), Trailing_List);
6749 Append_To (Trailing_List,
6750 Make_Goto_Statement (Loc,
6751 Name => New_Copy (Identifier (End_Lab))));
6752 end if;
6753
6754 if Present (Alt_Stats) then
6755
6756 -- Procedure call. and/or trailing statements
6757
6758 Append_To (Alt_List,
6759 Make_Case_Statement_Alternative (Loc,
6760 Discrete_Choices => Choices,
6761 Statements => Alt_Stats));
6762 end if;
6763 end Process_Accept_Alternative;
6764
6765 -------------------------------
6766 -- Process_Delay_Alternative --
6767 -------------------------------
6768
6769 procedure Process_Delay_Alternative (Alt : Node_Id; Index : Int) is
6770 Choices : List_Id;
6771 Cond : Node_Id;
6772 Delay_Alt : List_Id;
6773
6774 begin
6775 -- Deal with C/Fortran boolean as delay condition
6776
6777 Adjust_Condition (Condition (Alt));
6778
6779 -- Determine the smallest specified delay
6780
6781 -- for each delay alternative generate:
6782
6783 -- if guard-expression then
6784 -- Delay_Val := delay-expression;
6785 -- Guard_Open := True;
6786 -- if Delay_Val < Delay_Min then
6787 -- Delay_Min := Delay_Val;
6788 -- Delay_Index := Index;
6789 -- end if;
6790 -- end if;
6791
6792 -- The enclosing if-statement is omitted if there is no guard
6793
6794 if Delay_Count = 1
6795 or else First_Delay
6796 then
6797 First_Delay := False;
6798
6799 Delay_Alt := New_List (
6800 Make_Assignment_Statement (Loc,
6801 Name => New_Reference_To (Delay_Min, Loc),
6802 Expression => Expression (Delay_Statement (Alt))));
6803
6804 if Delay_Count > 1 then
6805 Append_To (Delay_Alt,
6806 Make_Assignment_Statement (Loc,
6807 Name => New_Reference_To (Delay_Index, Loc),
6808 Expression => Make_Integer_Literal (Loc, Index)));
6809 end if;
6810
6811 else
6812 Delay_Alt := New_List (
6813 Make_Assignment_Statement (Loc,
6814 Name => New_Reference_To (Delay_Val, Loc),
6815 Expression => Expression (Delay_Statement (Alt))));
6816
6817 if Time_Type = Standard_Duration then
6818 Cond :=
6819 Make_Op_Lt (Loc,
6820 Left_Opnd => New_Reference_To (Delay_Val, Loc),
6821 Right_Opnd => New_Reference_To (Delay_Min, Loc));
6822
6823 else
6824 -- The scope of the time type must define a comparison
6825 -- operator. The scope itself may not be visible, so we
6826 -- construct a node with entity information to insure that
6827 -- semantic analysis can find the proper operator.
6828
6829 Cond :=
6830 Make_Function_Call (Loc,
6831 Name => Make_Selected_Component (Loc,
6832 Prefix => New_Reference_To (Scope (Time_Type), Loc),
6833 Selector_Name =>
6834 Make_Operator_Symbol (Loc,
6835 Chars => Name_Op_Lt,
6836 Strval => No_String)),
6837 Parameter_Associations =>
6838 New_List (
6839 New_Reference_To (Delay_Val, Loc),
6840 New_Reference_To (Delay_Min, Loc)));
6841
6842 Set_Entity (Prefix (Name (Cond)), Scope (Time_Type));
6843 end if;
6844
6845 Append_To (Delay_Alt,
6846 Make_Implicit_If_Statement (N,
6847 Condition => Cond,
6848 Then_Statements => New_List (
6849 Make_Assignment_Statement (Loc,
6850 Name => New_Reference_To (Delay_Min, Loc),
6851 Expression => New_Reference_To (Delay_Val, Loc)),
6852
6853 Make_Assignment_Statement (Loc,
6854 Name => New_Reference_To (Delay_Index, Loc),
6855 Expression => Make_Integer_Literal (Loc, Index)))));
6856 end if;
6857
6858 if Check_Guard then
6859 Append_To (Delay_Alt,
6860 Make_Assignment_Statement (Loc,
6861 Name => New_Reference_To (Guard_Open, Loc),
6862 Expression => New_Reference_To (Standard_True, Loc)));
6863 end if;
6864
6865 if Present (Condition (Alt)) then
6866 Delay_Alt := New_List (
6867 Make_Implicit_If_Statement (N,
6868 Condition => Condition (Alt),
6869 Then_Statements => Delay_Alt));
6870 end if;
6871
6872 Append_List (Delay_Alt, Delay_List);
6873
6874 -- If the delay alternative has a statement part, add a
6875 -- choice to the case statements for delays.
6876
6877 if Present (Statements (Alt)) then
6878
6879 if Delay_Count = 1 then
6880 Append_List (Statements (Alt), Delay_Alt_List);
6881
6882 else
6883 Choices := New_List (
6884 Make_Integer_Literal (Loc, Index));
6885
6886 Append_To (Delay_Alt_List,
6887 Make_Case_Statement_Alternative (Loc,
6888 Discrete_Choices => Choices,
6889 Statements => Statements (Alt)));
6890 end if;
6891
6892 elsif Delay_Count = 1 then
6893
6894 -- If the single delay has no trailing statements, add a branch
6895 -- to the exit label to the selective wait.
6896
6897 Delay_Alt_List := New_List (
6898 Make_Goto_Statement (Loc,
6899 Name => New_Copy (Identifier (End_Lab))));
6900
6901 end if;
6902 end Process_Delay_Alternative;
6903
6904 -- Start of processing for Expand_N_Selective_Accept
6905
6906 begin
6907 -- First insert some declarations before the select. The first is:
6908
6909 -- Ann : Address
6910
6911 -- This variable holds the parameters passed to the accept body. This
6912 -- declaration has already been inserted by the time we get here by
6913 -- a call to Expand_Accept_Declarations made from the semantics when
6914 -- processing the first accept statement contained in the select. We
6915 -- can find this entity as Accept_Address (E), where E is any of the
6916 -- entries references by contained accept statements.
6917
6918 -- The first step is to scan the list of Selective_Accept_Statements
6919 -- to find this entity, and also count the number of accepts, and
6920 -- determine if terminated, delay or else is present:
6921
6922 Num_Alts := 0;
6923
6924 Alt := First (Alts);
6925 while Present (Alt) loop
6926
6927 if Nkind (Alt) = N_Accept_Alternative then
6928 Add_Accept (Alt);
6929
6930 elsif Nkind (Alt) = N_Delay_Alternative then
6931 Delay_Count := Delay_Count + 1;
6932
6933 -- If the delays are relative delays, the delay expressions have
6934 -- type Standard_Duration. Otherwise they must have some time type
6935 -- recognized by GNAT.
6936
6937 if Nkind (Delay_Statement (Alt)) = N_Delay_Relative_Statement then
6938 Time_Type := Standard_Duration;
6939 else
6940 Time_Type := Etype (Expression (Delay_Statement (Alt)));
6941
6942 if Is_RTE (Base_Type (Etype (Time_Type)), RO_CA_Time)
6943 or else Is_RTE (Base_Type (Etype (Time_Type)), RO_RT_Time)
6944 then
6945 null;
6946 else
6947 Error_Msg_NE (
6948 "& is not a time type ('R'M 9.6(6))",
6949 Expression (Delay_Statement (Alt)), Time_Type);
6950 Time_Type := Standard_Duration;
6951 Set_Etype (Expression (Delay_Statement (Alt)), Any_Type);
6952 end if;
6953 end if;
6954
6955 if No (Condition (Alt)) then
6956
6957 -- This guard will always be open
6958
6959 Check_Guard := False;
6960 end if;
6961
6962 elsif Nkind (Alt) = N_Terminate_Alternative then
6963 Adjust_Condition (Condition (Alt));
6964 Terminate_Alt := Alt;
6965 end if;
6966
6967 Num_Alts := Num_Alts + 1;
6968 Next (Alt);
6969 end loop;
6970
6971 Else_Present := Present (Else_Statements (N));
6972
6973 -- At the same time (see procedure Add_Accept) we build the accept list:
6974
6975 -- Qnn : Accept_List (1 .. num-select) := (
6976 -- (null-body, entry-index),
6977 -- (null-body, entry-index),
6978 -- ..
6979 -- (null_body, entry-index));
6980
6981 -- In the above declaration, null-body is True if the corresponding
6982 -- accept has no body, and false otherwise. The entry is either the
6983 -- entry index expression if there is no guard, or if a guard is
6984 -- present, then a conditional expression of the form:
6985
6986 -- (if guard then entry-index else Null_Task_Entry)
6987
6988 -- If a guard is statically known to be false, the entry can simply
6989 -- be omitted from the accept list.
6990
6991 Q :=
6992 Make_Object_Declaration (Loc,
6993 Defining_Identifier => Qnam,
6994 Object_Definition =>
6995 New_Reference_To (RTE (RE_Accept_List), Loc),
6996 Aliased_Present => True,
6997
6998 Expression =>
6999 Make_Qualified_Expression (Loc,
7000 Subtype_Mark =>
7001 New_Reference_To (RTE (RE_Accept_List), Loc),
7002 Expression =>
7003 Make_Aggregate (Loc, Expressions => Accept_List)));
7004
7005 Append (Q, Decls);
7006
7007 -- Then we declare the variable that holds the index for the accept
7008 -- that will be selected for service:
7009
7010 -- Xnn : Select_Index;
7011
7012 X :=
7013 Make_Object_Declaration (Loc,
7014 Defining_Identifier => Xnam,
7015 Object_Definition =>
7016 New_Reference_To (RTE (RE_Select_Index), Loc),
7017 Expression =>
7018 New_Reference_To (RTE (RE_No_Rendezvous), Loc));
7019
7020 Append (X, Decls);
7021
7022 -- After this follow procedure declarations for each accept body
7023
7024 -- procedure Pnn is
7025 -- begin
7026 -- ...
7027 -- end;
7028
7029 -- where the ... are statements from the corresponding procedure body.
7030 -- No parameters are involved, since the parameters are passed via Ann
7031 -- and the parameter references have already been expanded to be direct
7032 -- references to Ann (see Exp_Ch2.Expand_Entry_Parameter). Furthermore,
7033 -- any embedded tasking statements (which would normally be illegal in
7034 -- procedures, have been converted to calls to the tasking runtime so
7035 -- there is no problem in putting them into procedures.
7036
7037 -- The original accept statement has been expanded into a block in
7038 -- the same fashion as for simple accepts (see Build_Accept_Body).
7039
7040 -- Note: we don't really need to build these procedures for the case
7041 -- where no delay statement is present, but it is just as easy to
7042 -- build them unconditionally, and not significantly inefficient,
7043 -- since if they are short they will be inlined anyway.
7044
7045 -- The procedure declarations have been assembled in Body_List
7046
7047 -- If delays are present, we must compute the required delay.
7048 -- We first generate the declarations:
7049
7050 -- Delay_Index : Boolean := 0;
7051 -- Delay_Min : Some_Time_Type.Time;
7052 -- Delay_Val : Some_Time_Type.Time;
7053
7054 -- Delay_Index will be set to the index of the minimum delay, i.e. the
7055 -- active delay that is actually chosen as the basis for the possible
7056 -- delay if an immediate rendez-vous is not possible.
7057
7058 -- In the most common case there is a single delay statement, and this
7059 -- is handled specially.
7060
7061 if Delay_Count > 0 then
7062
7063 -- Generate the required declarations
7064
7065 Delay_Val :=
7066 Make_Defining_Identifier (Loc, New_External_Name ('D', 1));
7067 Delay_Index :=
7068 Make_Defining_Identifier (Loc, New_External_Name ('D', 2));
7069 Delay_Min :=
7070 Make_Defining_Identifier (Loc, New_External_Name ('D', 3));
7071
7072 Append_To (Decls,
7073 Make_Object_Declaration (Loc,
7074 Defining_Identifier => Delay_Val,
7075 Object_Definition => New_Reference_To (Time_Type, Loc)));
7076
7077 Append_To (Decls,
7078 Make_Object_Declaration (Loc,
7079 Defining_Identifier => Delay_Index,
7080 Object_Definition => New_Reference_To (Standard_Integer, Loc),
7081 Expression => Make_Integer_Literal (Loc, 0)));
7082
7083 Append_To (Decls,
7084 Make_Object_Declaration (Loc,
7085 Defining_Identifier => Delay_Min,
7086 Object_Definition => New_Reference_To (Time_Type, Loc),
7087 Expression =>
7088 Unchecked_Convert_To (Time_Type,
7089 Make_Attribute_Reference (Loc,
7090 Prefix =>
7091 New_Occurrence_Of (Underlying_Type (Time_Type), Loc),
7092 Attribute_Name => Name_Last))));
7093
7094 -- Create Duration and Delay_Mode objects used for passing a delay
7095 -- value to RTS
7096
7097 D := Make_Defining_Identifier (Loc, New_Internal_Name ('D'));
7098 M := Make_Defining_Identifier (Loc, New_Internal_Name ('M'));
7099
7100 declare
7101 Discr : Entity_Id;
7102
7103 begin
7104 -- Note that these values are defined in s-osprim.ads and must
7105 -- be kept in sync:
7106 --
7107 -- Relative : constant := 0;
7108 -- Absolute_Calendar : constant := 1;
7109 -- Absolute_RT : constant := 2;
7110
7111 if Time_Type = Standard_Duration then
7112 Discr := Make_Integer_Literal (Loc, 0);
7113
7114 elsif Is_RTE (Base_Type (Etype (Time_Type)), RO_CA_Time) then
7115 Discr := Make_Integer_Literal (Loc, 1);
7116
7117 else
7118 pragma Assert
7119 (Is_RTE (Base_Type (Etype (Time_Type)), RO_RT_Time));
7120 Discr := Make_Integer_Literal (Loc, 2);
7121 end if;
7122
7123 Append_To (Decls,
7124 Make_Object_Declaration (Loc,
7125 Defining_Identifier => D,
7126 Object_Definition =>
7127 New_Reference_To (Standard_Duration, Loc)));
7128
7129 Append_To (Decls,
7130 Make_Object_Declaration (Loc,
7131 Defining_Identifier => M,
7132 Object_Definition =>
7133 New_Reference_To (Standard_Integer, Loc),
7134 Expression => Discr));
7135 end;
7136
7137 if Check_Guard then
7138 Guard_Open :=
7139 Make_Defining_Identifier (Loc, New_External_Name ('G', 1));
7140
7141 Append_To (Decls,
7142 Make_Object_Declaration (Loc,
7143 Defining_Identifier => Guard_Open,
7144 Object_Definition => New_Reference_To (Standard_Boolean, Loc),
7145 Expression => New_Reference_To (Standard_False, Loc)));
7146 end if;
7147
7148 -- Delay_Count is zero, don't need M and D set (suppress warning)
7149
7150 else
7151 M := Empty;
7152 D := Empty;
7153 end if;
7154
7155 if Present (Terminate_Alt) then
7156
7157 -- If the terminate alternative guard is False, use
7158 -- Simple_Mode; otherwise use Terminate_Mode.
7159
7160 if Present (Condition (Terminate_Alt)) then
7161 Select_Mode := Make_Conditional_Expression (Loc,
7162 New_List (Condition (Terminate_Alt),
7163 New_Reference_To (RTE (RE_Terminate_Mode), Loc),
7164 New_Reference_To (RTE (RE_Simple_Mode), Loc)));
7165 else
7166 Select_Mode := New_Reference_To (RTE (RE_Terminate_Mode), Loc);
7167 end if;
7168
7169 elsif Else_Present or Delay_Count > 0 then
7170 Select_Mode := New_Reference_To (RTE (RE_Else_Mode), Loc);
7171
7172 else
7173 Select_Mode := New_Reference_To (RTE (RE_Simple_Mode), Loc);
7174 end if;
7175
7176 Select_Call := Make_Select_Call (Select_Mode);
7177 Append (Select_Call, Stats);
7178
7179 -- Now generate code to act on the result. There is an entry
7180 -- in this case for each accept statement with a non-null body,
7181 -- followed by a branch to the statements that follow the Accept.
7182 -- In the absence of delay alternatives, we generate:
7183
7184 -- case X is
7185 -- when No_Rendezvous => -- omitted if simple mode
7186 -- goto Lab0;
7187
7188 -- when 1 =>
7189 -- P1n;
7190 -- goto Lab1;
7191
7192 -- when 2 =>
7193 -- P2n;
7194 -- goto Lab2;
7195
7196 -- when others =>
7197 -- goto Exit;
7198 -- end case;
7199 --
7200 -- Lab0: Else_Statements;
7201 -- goto exit;
7202
7203 -- Lab1: Trailing_Statements1;
7204 -- goto Exit;
7205 --
7206 -- Lab2: Trailing_Statements2;
7207 -- goto Exit;
7208 -- ...
7209 -- Exit:
7210
7211 -- Generate label for common exit
7212
7213 End_Lab := Make_And_Declare_Label (Num_Alts + 1);
7214
7215 -- First entry is the default case, when no rendezvous is possible
7216
7217 Choices := New_List (New_Reference_To (RTE (RE_No_Rendezvous), Loc));
7218
7219 if Else_Present then
7220
7221 -- If no rendezvous is possible, the else part is executed
7222
7223 Lab := Make_And_Declare_Label (0);
7224 Alt_Stats := New_List (
7225 Make_Goto_Statement (Loc,
7226 Name => New_Copy (Identifier (Lab))));
7227
7228 Append (Lab, Trailing_List);
7229 Append_List (Else_Statements (N), Trailing_List);
7230 Append_To (Trailing_List,
7231 Make_Goto_Statement (Loc,
7232 Name => New_Copy (Identifier (End_Lab))));
7233 else
7234 Alt_Stats := New_List (
7235 Make_Goto_Statement (Loc,
7236 Name => New_Copy (Identifier (End_Lab))));
7237 end if;
7238
7239 Append_To (Alt_List,
7240 Make_Case_Statement_Alternative (Loc,
7241 Discrete_Choices => Choices,
7242 Statements => Alt_Stats));
7243
7244 -- We make use of the fact that Accept_Index is an integer type,
7245 -- and generate successive literals for entries for each accept.
7246 -- Only those for which there is a body or trailing statements are
7247 -- given a case entry.
7248
7249 Alt := First (Select_Alternatives (N));
7250 Proc := First (Body_List);
7251
7252 while Present (Alt) loop
7253
7254 if Nkind (Alt) = N_Accept_Alternative then
7255 Process_Accept_Alternative (Alt, Index, Proc);
7256 Index := Index + 1;
7257
7258 if Present
7259 (Handled_Statement_Sequence (Accept_Statement (Alt)))
7260 then
7261 Next (Proc);
7262 end if;
7263
7264 elsif Nkind (Alt) = N_Delay_Alternative then
7265 Process_Delay_Alternative (Alt, Delay_Num);
7266 Delay_Num := Delay_Num + 1;
7267 end if;
7268
7269 Next (Alt);
7270 end loop;
7271
7272 -- An others choice is always added to the main case, as well
7273 -- as the delay case (to satisfy the compiler).
7274
7275 Append_To (Alt_List,
7276 Make_Case_Statement_Alternative (Loc,
7277 Discrete_Choices =>
7278 New_List (Make_Others_Choice (Loc)),
7279 Statements =>
7280 New_List (Make_Goto_Statement (Loc,
7281 Name => New_Copy (Identifier (End_Lab))))));
7282
7283 Accept_Case := New_List (
7284 Make_Case_Statement (Loc,
7285 Expression => New_Reference_To (Xnam, Loc),
7286 Alternatives => Alt_List));
7287
7288 Append_List (Trailing_List, Accept_Case);
7289 Append (End_Lab, Accept_Case);
7290 Append_List (Body_List, Decls);
7291
7292 -- Construct case statement for trailing statements of delay
7293 -- alternatives, if there are several of them.
7294
7295 if Delay_Count > 1 then
7296 Append_To (Delay_Alt_List,
7297 Make_Case_Statement_Alternative (Loc,
7298 Discrete_Choices =>
7299 New_List (Make_Others_Choice (Loc)),
7300 Statements =>
7301 New_List (Make_Null_Statement (Loc))));
7302
7303 Delay_Case := New_List (
7304 Make_Case_Statement (Loc,
7305 Expression => New_Reference_To (Delay_Index, Loc),
7306 Alternatives => Delay_Alt_List));
7307 else
7308 Delay_Case := Delay_Alt_List;
7309 end if;
7310
7311 -- If there are no delay alternatives, we append the case statement
7312 -- to the statement list.
7313
7314 if Delay_Count = 0 then
7315 Append_List (Accept_Case, Stats);
7316
7317 -- Delay alternatives present
7318
7319 else
7320 -- If delay alternatives are present we generate:
7321
7322 -- find minimum delay.
7323 -- DX := minimum delay;
7324 -- M := <delay mode>;
7325 -- Timed_Selective_Wait (Q'Unchecked_Access, Delay_Mode, P,
7326 -- DX, MX, X);
7327 --
7328 -- if X = No_Rendezvous then
7329 -- case statement for delay statements.
7330 -- else
7331 -- case statement for accept alternatives.
7332 -- end if;
7333
7334 declare
7335 Cases : Node_Id;
7336 Stmt : Node_Id;
7337 Parms : List_Id;
7338 Parm : Node_Id;
7339 Conv : Node_Id;
7340
7341 begin
7342 -- The type of the delay expression is known to be legal
7343
7344 if Time_Type = Standard_Duration then
7345 Conv := New_Reference_To (Delay_Min, Loc);
7346
7347 elsif Is_RTE (Base_Type (Etype (Time_Type)), RO_CA_Time) then
7348 Conv := Make_Function_Call (Loc,
7349 New_Reference_To (RTE (RO_CA_To_Duration), Loc),
7350 New_List (New_Reference_To (Delay_Min, Loc)));
7351
7352 else
7353 pragma Assert
7354 (Is_RTE (Base_Type (Etype (Time_Type)), RO_RT_Time));
7355
7356 Conv := Make_Function_Call (Loc,
7357 New_Reference_To (RTE (RO_RT_To_Duration), Loc),
7358 New_List (New_Reference_To (Delay_Min, Loc)));
7359 end if;
7360
7361 Stmt := Make_Assignment_Statement (Loc,
7362 Name => New_Reference_To (D, Loc),
7363 Expression => Conv);
7364
7365 -- Change the value for Accept_Modes. (Else_Mode -> Delay_Mode)
7366
7367 Parms := Parameter_Associations (Select_Call);
7368 Parm := First (Parms);
7369
7370 while Present (Parm)
7371 and then Parm /= Select_Mode
7372 loop
7373 Next (Parm);
7374 end loop;
7375
7376 pragma Assert (Present (Parm));
7377 Rewrite (Parm, New_Reference_To (RTE (RE_Delay_Mode), Loc));
7378 Analyze (Parm);
7379
7380 -- Prepare two new parameters of Duration and Delay_Mode type
7381 -- which represent the value and the mode of the minimum delay.
7382
7383 Next (Parm);
7384 Insert_After (Parm, New_Reference_To (M, Loc));
7385 Insert_After (Parm, New_Reference_To (D, Loc));
7386
7387 -- Create a call to RTS
7388
7389 Rewrite (Select_Call,
7390 Make_Procedure_Call_Statement (Loc,
7391 Name => New_Reference_To (RTE (RE_Timed_Selective_Wait), Loc),
7392 Parameter_Associations => Parms));
7393
7394 -- This new call should follow the calculation of the
7395 -- minimum delay.
7396
7397 Insert_List_Before (Select_Call, Delay_List);
7398
7399 if Check_Guard then
7400 Stmt :=
7401 Make_Implicit_If_Statement (N,
7402 Condition => New_Reference_To (Guard_Open, Loc),
7403 Then_Statements =>
7404 New_List (New_Copy_Tree (Stmt),
7405 New_Copy_Tree (Select_Call)),
7406 Else_Statements => Accept_Or_Raise);
7407 Rewrite (Select_Call, Stmt);
7408 else
7409 Insert_Before (Select_Call, Stmt);
7410 end if;
7411
7412 Cases :=
7413 Make_Implicit_If_Statement (N,
7414 Condition => Make_Op_Eq (Loc,
7415 Left_Opnd => New_Reference_To (Xnam, Loc),
7416 Right_Opnd =>
7417 New_Reference_To (RTE (RE_No_Rendezvous), Loc)),
7418
7419 Then_Statements => Delay_Case,
7420 Else_Statements => Accept_Case);
7421
7422 Append (Cases, Stats);
7423 end;
7424 end if;
7425
7426 -- Replace accept statement with appropriate block
7427
7428 Block :=
7429 Make_Block_Statement (Loc,
7430 Declarations => Decls,
7431 Handled_Statement_Sequence =>
7432 Make_Handled_Sequence_Of_Statements (Loc,
7433 Statements => Stats));
7434
7435 Rewrite (N, Block);
7436 Analyze (N);
7437
7438 -- Note: have to worry more about abort deferral in above code ???
7439
7440 -- Final step is to unstack the Accept_Address entries for all accept
7441 -- statements appearing in accept alternatives in the select statement
7442
7443 Alt := First (Alts);
7444 while Present (Alt) loop
7445 if Nkind (Alt) = N_Accept_Alternative then
7446 Remove_Last_Elmt (Accept_Address
7447 (Entity (Entry_Direct_Name (Accept_Statement (Alt)))));
7448 end if;
7449
7450 Next (Alt);
7451 end loop;
7452 end Expand_N_Selective_Accept;
7453
7454 --------------------------------------
7455 -- Expand_N_Single_Task_Declaration --
7456 --------------------------------------
7457
7458 -- Single task declarations should never be present after semantic
7459 -- analysis, since we expect them to be replaced by a declaration of
7460 -- an anonymous task type, followed by a declaration of the task
7461 -- object. We include this routine to make sure that is happening!
7462
7463 procedure Expand_N_Single_Task_Declaration (N : Node_Id) is
7464 begin
7465 raise Program_Error;
7466 end Expand_N_Single_Task_Declaration;
7467
7468 ------------------------
7469 -- Expand_N_Task_Body --
7470 ------------------------
7471
7472 -- Given a task body
7473
7474 -- task body tname is
7475 -- <declarations>
7476 -- begin
7477 -- <statements>
7478 -- end x;
7479
7480 -- This expansion routine converts it into a procedure and sets the
7481 -- elaboration flag for the procedure to true, to represent the fact
7482 -- that the task body is now elaborated:
7483
7484 -- procedure tnameB (_Task : access tnameV) is
7485 -- discriminal : dtype renames _Task.discriminant;
7486
7487 -- procedure _clean is
7488 -- begin
7489 -- Abort_Defer.all;
7490 -- Complete_Task;
7491 -- Abort_Undefer.all;
7492 -- return;
7493 -- end _clean;
7494
7495 -- begin
7496 -- Abort_Undefer.all;
7497 -- <declarations>
7498 -- System.Task_Stages.Complete_Activation;
7499 -- <statements>
7500 -- at end
7501 -- _clean;
7502 -- end tnameB;
7503
7504 -- tnameE := True;
7505
7506 -- In addition, if the task body is an activator, then a call to
7507 -- activate tasks is added at the start of the statements, before
7508 -- the call to Complete_Activation, and if in addition the task is
7509 -- a master then it must be established as a master. These calls are
7510 -- inserted and analyzed in Expand_Cleanup_Actions, when the
7511 -- Handled_Sequence_Of_Statements is expanded.
7512
7513 -- There is one discriminal declaration line generated for each
7514 -- discriminant that is present to provide an easy reference point
7515 -- for discriminant references inside the body (see Exp_Ch2.Expand_Name).
7516
7517 -- Note on relationship to GNARLI definition. In the GNARLI definition,
7518 -- task body procedures have a profile (Arg : System.Address). That is
7519 -- needed because GNARLI has to use the same access-to-subprogram type
7520 -- for all task types. We depend here on knowing that in GNAT, passing
7521 -- an address argument by value is identical to passing a record value
7522 -- by access (in either case a single pointer is passed), so even though
7523 -- this procedure has the wrong profile. In fact it's all OK, since the
7524 -- callings sequence is identical.
7525
7526 procedure Expand_N_Task_Body (N : Node_Id) is
7527 Loc : constant Source_Ptr := Sloc (N);
7528 Ttyp : constant Entity_Id := Corresponding_Spec (N);
7529 Call : Node_Id;
7530 New_N : Node_Id;
7531
7532 begin
7533 -- Here we start the expansion by generating discriminal declarations
7534
7535 Add_Discriminal_Declarations (Declarations (N), Ttyp, Name_uTask, Loc);
7536
7537 -- Add a call to Abort_Undefer at the very beginning of the task
7538 -- body since this body is called with abort still deferred.
7539
7540 if Abort_Allowed then
7541 Call := Build_Runtime_Call (Loc, RE_Abort_Undefer);
7542 Insert_Before
7543 (First (Statements (Handled_Statement_Sequence (N))), Call);
7544 Analyze (Call);
7545 end if;
7546
7547 -- The statement part has already been protected with an at_end and
7548 -- cleanup actions. The call to Complete_Activation must be placed
7549 -- at the head of the sequence of statements of that block. The
7550 -- declarations have been merged in this sequence of statements but
7551 -- the first real statement is accessible from the First_Real_Statement
7552 -- field (which was set for exactly this purpose).
7553
7554 if Restricted_Profile then
7555 Call := Build_Runtime_Call (Loc, RE_Complete_Restricted_Activation);
7556 else
7557 Call := Build_Runtime_Call (Loc, RE_Complete_Activation);
7558 end if;
7559
7560 Insert_Before
7561 (First_Real_Statement (Handled_Statement_Sequence (N)), Call);
7562 Analyze (Call);
7563
7564 New_N :=
7565 Make_Subprogram_Body (Loc,
7566 Specification => Build_Task_Proc_Specification (Ttyp),
7567 Declarations => Declarations (N),
7568 Handled_Statement_Sequence => Handled_Statement_Sequence (N));
7569
7570 -- If the task contains generic instantiations, cleanup actions
7571 -- are delayed until after instantiation. Transfer the activation
7572 -- chain to the subprogram, to insure that the activation call is
7573 -- properly generated. It the task body contains inner tasks, indicate
7574 -- that the subprogram is a task master.
7575
7576 if Delay_Cleanups (Ttyp) then
7577 Set_Activation_Chain_Entity (New_N, Activation_Chain_Entity (N));
7578 Set_Is_Task_Master (New_N, Is_Task_Master (N));
7579 end if;
7580
7581 Rewrite (N, New_N);
7582 Analyze (N);
7583
7584 -- Set elaboration flag immediately after task body. If the body
7585 -- is a subunit, the flag is set in the declarative part that
7586 -- contains the stub.
7587
7588 if Nkind (Parent (N)) /= N_Subunit then
7589 Insert_After (N,
7590 Make_Assignment_Statement (Loc,
7591 Name =>
7592 Make_Identifier (Loc, New_External_Name (Chars (Ttyp), 'E')),
7593 Expression => New_Reference_To (Standard_True, Loc)));
7594 end if;
7595
7596 -- Ada 2005 (AI-345): Construct the primitive entry wrapper bodies
7597 -- after the task body. At this point the entry specs have been
7598 -- created, frozen and included in the dispatch table for the task
7599 -- type.
7600
7601 pragma Assert (Present (Corresponding_Record_Type (Ttyp)));
7602
7603 if Ada_Version >= Ada_05
7604 and then Present (Task_Definition (Parent (Ttyp)))
7605 and then Present (Abstract_Interfaces
7606 (Corresponding_Record_Type (Ttyp)))
7607 then
7608 declare
7609 Current_Node : Node_Id;
7610 Vis_Decl : Node_Id :=
7611 First (Visible_Declarations (Task_Definition (Parent (Ttyp))));
7612 Wrap_Body : Node_Id;
7613
7614 begin
7615 if Nkind (Parent (N)) = N_Subunit then
7616 Current_Node := Corresponding_Stub (Parent (N));
7617 else
7618 Current_Node := N;
7619 end if;
7620
7621 -- Examine the visible declarations of the task type,
7622 -- looking for an entry declaration. We do not consider
7623 -- entry families since they can not have dispatching
7624 -- operations, thus they do not need entry wrappers.
7625
7626 while Present (Vis_Decl) loop
7627 if Nkind (Vis_Decl) = N_Entry_Declaration
7628 and then Ekind (Defining_Identifier (Vis_Decl)) = E_Entry
7629 then
7630
7631 -- Create the specification of the wrapper
7632
7633 Wrap_Body :=
7634 Build_Wrapper_Body (Loc,
7635 Proc_Nam => Defining_Identifier (Vis_Decl),
7636 Obj_Typ => Corresponding_Record_Type (Ttyp),
7637 Formals => Parameter_Specifications (Vis_Decl));
7638
7639 if Wrap_Body /= Empty then
7640 Insert_After (Current_Node, Wrap_Body);
7641 Current_Node := Wrap_Body;
7642
7643 Analyze (Wrap_Body);
7644 end if;
7645 end if;
7646
7647 Next (Vis_Decl);
7648 end loop;
7649 end;
7650 end if;
7651 end Expand_N_Task_Body;
7652
7653 ------------------------------------
7654 -- Expand_N_Task_Type_Declaration --
7655 ------------------------------------
7656
7657 -- We have several things to do. First we must create a Boolean flag used
7658 -- to mark if the body is elaborated yet. This variable gets set to True
7659 -- when the body of the task is elaborated (we can't rely on the normal
7660 -- ABE mechanism for the task body, since we need to pass an access to
7661 -- this elaboration boolean to the runtime routines).
7662
7663 -- taskE : aliased Boolean := False;
7664
7665 -- Next a variable is declared to hold the task stack size (either
7666 -- the default : Unspecified_Size, or a value that is set by a pragma
7667 -- Storage_Size). If the value of the pragma Storage_Size is static, then
7668 -- the variable is initialized with this value:
7669
7670 -- taskZ : Size_Type := Unspecified_Size;
7671 -- or
7672 -- taskZ : Size_Type := Size_Type (size_expression);
7673
7674 -- Next we create a corresponding record type declaration used to represent
7675 -- values of this task. The general form of this type declaration is
7676
7677 -- type taskV (discriminants) is record
7678 -- _Task_Id : Task_Id;
7679 -- entry_family : array (bounds) of Void;
7680 -- _Priority : Integer := priority_expression;
7681 -- _Size : Size_Type := Size_Type (size_expression);
7682 -- _Task_Info : Task_Info_Type := task_info_expression;
7683 -- end record;
7684
7685 -- The discriminants are present only if the corresponding task type has
7686 -- discriminants, and they exactly mirror the task type discriminants.
7687
7688 -- The Id field is always present. It contains the Task_Id value, as
7689 -- set by the call to Create_Task. Note that although the task is
7690 -- limited, the task value record type is not limited, so there is no
7691 -- problem in passing this field as an out parameter to Create_Task.
7692
7693 -- One entry_family component is present for each entry family in the
7694 -- task definition. The bounds correspond to the bounds of the entry
7695 -- family (which may depend on discriminants). The element type is
7696 -- void, since we only need the bounds information for determining
7697 -- the entry index. Note that the use of an anonymous array would
7698 -- normally be illegal in this context, but this is a parser check,
7699 -- and the semantics is quite prepared to handle such a case.
7700
7701 -- The _Size field is present only if a Storage_Size pragma appears in
7702 -- the task definition. The expression captures the argument that was
7703 -- present in the pragma, and is used to override the task stack size
7704 -- otherwise associated with the task type.
7705
7706 -- The _Priority field is present only if a Priority or Interrupt_Priority
7707 -- pragma appears in the task definition. The expression captures the
7708 -- argument that was present in the pragma, and is used to provide
7709 -- the Size parameter to the call to Create_Task.
7710
7711 -- The _Task_Info field is present only if a Task_Info pragma appears in
7712 -- the task definition. The expression captures the argument that was
7713 -- present in the pragma, and is used to provide the Task_Image parameter
7714 -- to the call to Create_Task.
7715
7716 -- When a task is declared, an instance of the task value record is
7717 -- created. The elaboration of this declaration creates the correct
7718 -- bounds for the entry families, and also evaluates the size, priority,
7719 -- and task_Info expressions if needed. The initialization routine for
7720 -- the task type itself then calls Create_Task with appropriate
7721 -- parameters to initialize the value of the Task_Id field.
7722
7723 -- Note: the address of this record is passed as the "Discriminants"
7724 -- parameter for Create_Task. Since Create_Task merely passes this onto
7725 -- the body procedure, it does not matter that it does not quite match
7726 -- the GNARLI model of what is being passed (the record contains more
7727 -- than just the discriminants, but the discriminants can be found from
7728 -- the record value).
7729
7730 -- The Entity_Id for this created record type is placed in the
7731 -- Corresponding_Record_Type field of the associated task type entity.
7732
7733 -- Next we create a procedure specification for the task body procedure:
7734
7735 -- procedure taskB (_Task : access taskV);
7736
7737 -- Note that this must come after the record type declaration, since
7738 -- the spec refers to this type. It turns out that the initialization
7739 -- procedure for the value type references the task body spec, but that's
7740 -- fine, since it won't be generated till the freeze point for the type,
7741 -- which is certainly after the task body spec declaration.
7742
7743 -- Finally, we set the task index value field of the entry attribute in
7744 -- the case of a simple entry.
7745
7746 procedure Expand_N_Task_Type_Declaration (N : Node_Id) is
7747 Loc : constant Source_Ptr := Sloc (N);
7748 Tasktyp : constant Entity_Id := Etype (Defining_Identifier (N));
7749 Tasknm : constant Name_Id := Chars (Tasktyp);
7750 Taskdef : constant Node_Id := Task_Definition (N);
7751
7752 Proc_Spec : Node_Id;
7753 Rec_Decl : Node_Id;
7754 Rec_Ent : Entity_Id;
7755 Cdecls : List_Id;
7756 Elab_Decl : Node_Id;
7757 Size_Decl : Node_Id;
7758 Body_Decl : Node_Id;
7759 Task_Size : Node_Id;
7760 Ent_Stack : Entity_Id;
7761 Decl_Stack : Node_Id;
7762
7763 begin
7764 -- If already expanded, nothing to do
7765
7766 if Present (Corresponding_Record_Type (Tasktyp)) then
7767 return;
7768 end if;
7769
7770 -- Here we will do the expansion
7771
7772 Rec_Decl := Build_Corresponding_Record (N, Tasktyp, Loc);
7773
7774 -- Ada 2005 (AI-345): Propagate the attribute that contains the list
7775 -- of implemented interfaces.
7776
7777 Set_Interface_List (Type_Definition (Rec_Decl), Interface_List (N));
7778
7779 Rec_Ent := Defining_Identifier (Rec_Decl);
7780 Cdecls := Component_Items (Component_List
7781 (Type_Definition (Rec_Decl)));
7782
7783 Qualify_Entity_Names (N);
7784
7785 -- First create the elaboration variable
7786
7787 Elab_Decl :=
7788 Make_Object_Declaration (Loc,
7789 Defining_Identifier =>
7790 Make_Defining_Identifier (Sloc (Tasktyp),
7791 Chars => New_External_Name (Tasknm, 'E')),
7792 Aliased_Present => True,
7793 Object_Definition => New_Reference_To (Standard_Boolean, Loc),
7794 Expression => New_Reference_To (Standard_False, Loc));
7795 Insert_After (N, Elab_Decl);
7796
7797 -- Next create the declaration of the size variable (tasknmZ)
7798
7799 Set_Storage_Size_Variable (Tasktyp,
7800 Make_Defining_Identifier (Sloc (Tasktyp),
7801 Chars => New_External_Name (Tasknm, 'Z')));
7802
7803 if Present (Taskdef) and then Has_Storage_Size_Pragma (Taskdef) and then
7804 Is_Static_Expression (Expression (First (
7805 Pragma_Argument_Associations (Find_Task_Or_Protected_Pragma (
7806 Taskdef, Name_Storage_Size)))))
7807 then
7808 Size_Decl :=
7809 Make_Object_Declaration (Loc,
7810 Defining_Identifier => Storage_Size_Variable (Tasktyp),
7811 Object_Definition => New_Reference_To (RTE (RE_Size_Type), Loc),
7812 Expression =>
7813 Convert_To (RTE (RE_Size_Type),
7814 Relocate_Node (
7815 Expression (First (
7816 Pragma_Argument_Associations (
7817 Find_Task_Or_Protected_Pragma
7818 (Taskdef, Name_Storage_Size)))))));
7819
7820 else
7821 Size_Decl :=
7822 Make_Object_Declaration (Loc,
7823 Defining_Identifier => Storage_Size_Variable (Tasktyp),
7824 Object_Definition => New_Reference_To (RTE (RE_Size_Type), Loc),
7825 Expression => New_Reference_To (RTE (RE_Unspecified_Size), Loc));
7826 end if;
7827
7828 Insert_After (Elab_Decl, Size_Decl);
7829
7830 -- Next build the rest of the corresponding record declaration.
7831 -- This is done last, since the corresponding record initialization
7832 -- procedure will reference the previously created entities.
7833
7834 -- Fill in the component declarations -- first the _Task_Id field
7835
7836 Append_To (Cdecls,
7837 Make_Component_Declaration (Loc,
7838 Defining_Identifier =>
7839 Make_Defining_Identifier (Loc, Name_uTask_Id),
7840 Component_Definition =>
7841 Make_Component_Definition (Loc,
7842 Aliased_Present => False,
7843 Subtype_Indication => New_Reference_To (RTE (RO_ST_Task_Id),
7844 Loc))));
7845
7846 -- Declare static ATCB (that is, created by the expander) if we
7847 -- are using the Restricted run time.
7848
7849 if Restricted_Profile then
7850 Append_To (Cdecls,
7851 Make_Component_Declaration (Loc,
7852 Defining_Identifier =>
7853 Make_Defining_Identifier (Loc, Name_uATCB),
7854
7855 Component_Definition =>
7856 Make_Component_Definition (Loc,
7857 Aliased_Present => True,
7858 Subtype_Indication => Make_Subtype_Indication (Loc,
7859 Subtype_Mark => New_Occurrence_Of
7860 (RTE (RE_Ada_Task_Control_Block), Loc),
7861
7862 Constraint =>
7863 Make_Index_Or_Discriminant_Constraint (Loc,
7864 Constraints =>
7865 New_List (Make_Integer_Literal (Loc, 0)))))));
7866
7867 end if;
7868
7869 -- Declare static stack (that is, created by the expander) if we
7870 -- are using the Restricted run time on a bare board configuration.
7871
7872 if Restricted_Profile
7873 and then Preallocated_Stacks_On_Target
7874 then
7875 -- First we need to extract the appropriate stack size
7876
7877 Ent_Stack := Make_Defining_Identifier (Loc, Name_uStack);
7878
7879 if Present (Taskdef) and then Has_Storage_Size_Pragma (Taskdef) then
7880 Task_Size := Relocate_Node (
7881 Expression (First (
7882 Pragma_Argument_Associations (
7883 Find_Task_Or_Protected_Pragma
7884 (Taskdef, Name_Storage_Size)))));
7885 else
7886 Task_Size :=
7887 New_Reference_To (RTE (RE_Default_Stack_Size), Loc);
7888 end if;
7889
7890 Decl_Stack := Make_Component_Declaration (Loc,
7891 Defining_Identifier => Ent_Stack,
7892
7893 Component_Definition =>
7894 Make_Component_Definition (Loc,
7895 Aliased_Present => True,
7896 Subtype_Indication => Make_Subtype_Indication (Loc,
7897 Subtype_Mark =>
7898 New_Occurrence_Of (RTE (RE_Storage_Array), Loc),
7899
7900 Constraint =>
7901 Make_Index_Or_Discriminant_Constraint (Loc,
7902 Constraints => New_List (Make_Range (Loc,
7903 Low_Bound => Make_Integer_Literal (Loc, 1),
7904 High_Bound => Convert_To (RTE (RE_Storage_Offset),
7905 Task_Size)))))));
7906
7907 Append_To (Cdecls, Decl_Stack);
7908
7909 -- The appropriate alignment for the stack is ensured by the
7910 -- run-time code in charge of task creation.
7911
7912 end if;
7913
7914 -- Add components for entry families
7915
7916 Collect_Entry_Families (Loc, Cdecls, Size_Decl, Tasktyp);
7917
7918 -- Add the _Priority component if a Priority pragma is present
7919
7920 if Present (Taskdef) and then Has_Priority_Pragma (Taskdef) then
7921 declare
7922 Prag : constant Node_Id :=
7923 Find_Task_Or_Protected_Pragma (Taskdef, Name_Priority);
7924 Expr : Node_Id;
7925
7926 begin
7927 Expr := First (Pragma_Argument_Associations (Prag));
7928
7929 if Nkind (Expr) = N_Pragma_Argument_Association then
7930 Expr := Expression (Expr);
7931 end if;
7932
7933 Expr := New_Copy_Tree (Expr);
7934
7935 -- Add conversion to proper type to do range check if required
7936 -- Note that for runtime units, we allow out of range interrupt
7937 -- priority values to be used in a priority pragma. This is for
7938 -- the benefit of some versions of System.Interrupts which use
7939 -- a special server task with maximum interrupt priority.
7940
7941 if Chars (Prag) = Name_Priority
7942 and then not GNAT_Mode
7943 then
7944 Rewrite (Expr, Convert_To (RTE (RE_Priority), Expr));
7945 else
7946 Rewrite (Expr, Convert_To (RTE (RE_Any_Priority), Expr));
7947 end if;
7948
7949 Append_To (Cdecls,
7950 Make_Component_Declaration (Loc,
7951 Defining_Identifier =>
7952 Make_Defining_Identifier (Loc, Name_uPriority),
7953 Component_Definition =>
7954 Make_Component_Definition (Loc,
7955 Aliased_Present => False,
7956 Subtype_Indication => New_Reference_To (Standard_Integer,
7957 Loc)),
7958 Expression => Expr));
7959 end;
7960 end if;
7961
7962 -- Add the _Task_Size component if a Storage_Size pragma is present
7963
7964 if Present (Taskdef)
7965 and then Has_Storage_Size_Pragma (Taskdef)
7966 then
7967 Append_To (Cdecls,
7968 Make_Component_Declaration (Loc,
7969 Defining_Identifier =>
7970 Make_Defining_Identifier (Loc, Name_uSize),
7971
7972 Component_Definition =>
7973 Make_Component_Definition (Loc,
7974 Aliased_Present => False,
7975 Subtype_Indication => New_Reference_To (RTE (RE_Size_Type),
7976 Loc)),
7977
7978 Expression =>
7979 Convert_To (RTE (RE_Size_Type),
7980 Relocate_Node (
7981 Expression (First (
7982 Pragma_Argument_Associations (
7983 Find_Task_Or_Protected_Pragma
7984 (Taskdef, Name_Storage_Size))))))));
7985 end if;
7986
7987 -- Add the _Task_Info component if a Task_Info pragma is present
7988
7989 if Present (Taskdef) and then Has_Task_Info_Pragma (Taskdef) then
7990 Append_To (Cdecls,
7991 Make_Component_Declaration (Loc,
7992 Defining_Identifier =>
7993 Make_Defining_Identifier (Loc, Name_uTask_Info),
7994
7995 Component_Definition =>
7996 Make_Component_Definition (Loc,
7997 Aliased_Present => False,
7998 Subtype_Indication =>
7999 New_Reference_To (RTE (RE_Task_Info_Type), Loc)),
8000
8001 Expression => New_Copy (
8002 Expression (First (
8003 Pragma_Argument_Associations (
8004 Find_Task_Or_Protected_Pragma
8005 (Taskdef, Name_Task_Info)))))));
8006 end if;
8007
8008 Insert_After (Size_Decl, Rec_Decl);
8009
8010 -- Analyze the record declaration immediately after construction,
8011 -- because the initialization procedure is needed for single task
8012 -- declarations before the next entity is analyzed.
8013
8014 Analyze (Rec_Decl);
8015
8016 -- Create the declaration of the task body procedure
8017
8018 Proc_Spec := Build_Task_Proc_Specification (Tasktyp);
8019 Body_Decl :=
8020 Make_Subprogram_Declaration (Loc,
8021 Specification => Proc_Spec);
8022
8023 Insert_After (Rec_Decl, Body_Decl);
8024
8025 -- The subprogram does not comes from source, so we have to indicate
8026 -- the need for debugging information explicitly.
8027
8028 Set_Needs_Debug_Info
8029 (Defining_Entity (Proc_Spec), Comes_From_Source (Original_Node (N)));
8030
8031 -- Ada 2005 (AI-345): Construct the primitive entry wrapper specs
8032 -- before the corresponding record has been frozen.
8033
8034 if Ada_Version >= Ada_05
8035 and then Present (Taskdef)
8036 and then Present (Corresponding_Record_Type
8037 (Defining_Identifier (Parent (Taskdef))))
8038 and then Present (Abstract_Interfaces
8039 (Corresponding_Record_Type
8040 (Defining_Identifier (Parent (Taskdef)))))
8041 then
8042 declare
8043 Current_Node : Node_Id := Rec_Decl;
8044 Vis_Decl : Node_Id := First (Visible_Declarations (Taskdef));
8045 Wrap_Spec : Node_Id;
8046 New_N : Node_Id;
8047
8048 begin
8049 -- Examine the visible declarations of the task type,
8050 -- looking for an entry declaration. We do not consider
8051 -- entry families since they can not have dispatching
8052 -- operations, thus they do not need entry wrappers.
8053
8054 while Present (Vis_Decl) loop
8055 if Nkind (Vis_Decl) = N_Entry_Declaration
8056 and then Ekind (Defining_Identifier (Vis_Decl)) = E_Entry
8057 then
8058 Wrap_Spec :=
8059 Build_Wrapper_Spec (Loc,
8060 Proc_Nam => Defining_Identifier (Vis_Decl),
8061 Obj_Typ => Etype (Rec_Ent),
8062 Formals => Parameter_Specifications (Vis_Decl));
8063
8064 if Wrap_Spec /= Empty then
8065 New_N :=
8066 Make_Subprogram_Declaration (Loc,
8067 Specification => Wrap_Spec);
8068
8069 Insert_After (Current_Node, New_N);
8070 Current_Node := New_N;
8071
8072 Analyze (New_N);
8073 end if;
8074 end if;
8075
8076 Next (Vis_Decl);
8077 end loop;
8078 end;
8079 end if;
8080
8081 -- Ada 2005 (AI-345): We must defer freezing to allow further
8082 -- declaration of primitive subprograms covering task interfaces
8083
8084 if Ada_Version <= Ada_95 then
8085
8086 -- Now we can freeze the corresponding record. This needs manually
8087 -- freezing, since it is really part of the task type, and the task
8088 -- type is frozen at this stage. We of course need the initialization
8089 -- procedure for this corresponding record type and we won't get it
8090 -- in time if we don't freeze now.
8091
8092 declare
8093 L : constant List_Id := Freeze_Entity (Rec_Ent, Loc);
8094
8095 begin
8096 if Is_Non_Empty_List (L) then
8097 Insert_List_After (Body_Decl, L);
8098 end if;
8099 end;
8100 end if;
8101
8102 -- Complete the expansion of access types to the current task
8103 -- type, if any were declared.
8104
8105 Expand_Previous_Access_Type (Tasktyp);
8106 end Expand_N_Task_Type_Declaration;
8107
8108 -------------------------------
8109 -- Expand_N_Timed_Entry_Call --
8110 -------------------------------
8111
8112 -- A timed entry call in normal case is not implemented using ATC
8113 -- mechanism anymore for efficiency reason.
8114
8115 -- select
8116 -- T.E;
8117 -- S1;
8118 -- or
8119 -- Delay D;
8120 -- S2;
8121 -- end select;
8122
8123 -- is expanded as follow:
8124
8125 -- 1) When T.E is a task entry_call;
8126
8127 -- declare
8128 -- B : Boolean;
8129 -- X : Task_Entry_Index := <entry index>;
8130 -- DX : Duration := To_Duration (D);
8131 -- M : Delay_Mode := <discriminant>;
8132 -- P : parms := (parm, parm, parm);
8133
8134 -- begin
8135 -- Timed_Protected_Entry_Call (<acceptor-task>, X, P'Address,
8136 -- DX, M, B);
8137 -- if B then
8138 -- S1;
8139 -- else
8140 -- S2;
8141 -- end if;
8142 -- end;
8143
8144 -- 2) When T.E is a protected entry_call;
8145
8146 -- declare
8147 -- B : Boolean;
8148 -- X : Protected_Entry_Index := <entry index>;
8149 -- DX : Duration := To_Duration (D);
8150 -- M : Delay_Mode := <discriminant>;
8151 -- P : parms := (parm, parm, parm);
8152
8153 -- begin
8154 -- Timed_Protected_Entry_Call (<object>'unchecked_access, X,
8155 -- P'Address, DX, M, B);
8156 -- if B then
8157 -- S1;
8158 -- else
8159 -- S2;
8160 -- end if;
8161 -- end;
8162
8163 procedure Expand_N_Timed_Entry_Call (N : Node_Id) is
8164 Loc : constant Source_Ptr := Sloc (N);
8165
8166 E_Call : Node_Id :=
8167 Entry_Call_Statement (Entry_Call_Alternative (N));
8168 E_Stats : constant List_Id :=
8169 Statements (Entry_Call_Alternative (N));
8170 D_Stat : constant Node_Id :=
8171 Delay_Statement (Delay_Alternative (N));
8172 D_Stats : constant List_Id :=
8173 Statements (Delay_Alternative (N));
8174
8175 Stmts : List_Id;
8176 Stmt : Node_Id;
8177 Parms : List_Id;
8178 Parm : Node_Id;
8179
8180 Concval : Node_Id;
8181 Ename : Node_Id;
8182 Index : Node_Id;
8183
8184 Decls : List_Id;
8185 Disc : Node_Id;
8186 Conv : Node_Id;
8187 B : Entity_Id;
8188 D : Entity_Id;
8189 Dtyp : Entity_Id;
8190 M : Entity_Id;
8191
8192 Call : Node_Id;
8193 Dummy : Node_Id;
8194
8195 begin
8196 -- The arguments in the call may require dynamic allocation, and the
8197 -- call statement may have been transformed into a block. The block
8198 -- may contain additional declarations for internal entities, and the
8199 -- original call is found by sequential search.
8200
8201 if Nkind (E_Call) = N_Block_Statement then
8202 E_Call := First (Statements (Handled_Statement_Sequence (E_Call)));
8203
8204 while Nkind (E_Call) /= N_Procedure_Call_Statement
8205 and then Nkind (E_Call) /= N_Entry_Call_Statement
8206 loop
8207 Next (E_Call);
8208 end loop;
8209 end if;
8210
8211 -- Build an entry call using Simple_Entry_Call. We will use this as the
8212 -- base for creating appropriate calls.
8213
8214 Extract_Entry (E_Call, Concval, Ename, Index);
8215 Build_Simple_Entry_Call (E_Call, Concval, Ename, Index);
8216
8217 Stmts := Statements (Handled_Statement_Sequence (E_Call));
8218 Decls := Declarations (E_Call);
8219
8220 if No (Decls) then
8221 Decls := New_List;
8222 end if;
8223
8224 Dtyp := Base_Type (Etype (Expression (D_Stat)));
8225
8226 -- Use the type of the delay expression (Calendar or Real_Time)
8227 -- to generate the appropriate conversion.
8228
8229 if Nkind (D_Stat) = N_Delay_Relative_Statement then
8230 Disc := Make_Integer_Literal (Loc, 0);
8231 Conv := Relocate_Node (Expression (D_Stat));
8232
8233 elsif Is_RTE (Dtyp, RO_CA_Time) then
8234 Disc := Make_Integer_Literal (Loc, 1);
8235 Conv := Make_Function_Call (Loc,
8236 New_Reference_To (RTE (RO_CA_To_Duration), Loc),
8237 New_List (New_Copy (Expression (D_Stat))));
8238
8239 else pragma Assert (Is_RTE (Dtyp, RO_RT_Time));
8240 Disc := Make_Integer_Literal (Loc, 2);
8241 Conv := Make_Function_Call (Loc,
8242 New_Reference_To (RTE (RO_RT_To_Duration), Loc),
8243 New_List (New_Copy (Expression (D_Stat))));
8244 end if;
8245
8246 -- Create Duration and Delay_Mode objects for passing a delay value
8247
8248 D := Make_Defining_Identifier (Loc, New_Internal_Name ('D'));
8249 M := Make_Defining_Identifier (Loc, New_Internal_Name ('M'));
8250
8251 Append_To (Decls,
8252 Make_Object_Declaration (Loc,
8253 Defining_Identifier => D,
8254 Object_Definition => New_Reference_To (Standard_Duration, Loc)));
8255
8256 Append_To (Decls,
8257 Make_Object_Declaration (Loc,
8258 Defining_Identifier => M,
8259 Object_Definition => New_Reference_To (Standard_Integer, Loc),
8260 Expression => Disc));
8261
8262 B := Make_Defining_Identifier (Loc, Name_uB);
8263
8264 -- Create a boolean object used for a return parameter
8265
8266 Prepend_To (Decls,
8267 Make_Object_Declaration (Loc,
8268 Defining_Identifier => B,
8269 Object_Definition => New_Reference_To (Standard_Boolean, Loc)));
8270
8271 Stmt := First (Stmts);
8272
8273 -- Skip assignments to temporaries created for in-out parameters.
8274 -- This makes unwarranted assumptions about the shape of the expanded
8275 -- tree for the call, and should be cleaned up ???
8276
8277 while Nkind (Stmt) /= N_Procedure_Call_Statement loop
8278 Next (Stmt);
8279 end loop;
8280
8281 -- Do the assignement at this stage only because the evaluation of the
8282 -- expression must not occur before (see ACVC C97302A).
8283
8284 Insert_Before (Stmt,
8285 Make_Assignment_Statement (Loc,
8286 Name => New_Reference_To (D, Loc),
8287 Expression => Conv));
8288
8289 Call := Stmt;
8290
8291 Parms := Parameter_Associations (Call);
8292
8293 -- For a protected type, we build a Timed_Protected_Entry_Call
8294
8295 if Is_Protected_Type (Etype (Concval)) then
8296
8297 -- Create a new call statement
8298
8299 Parm := First (Parms);
8300
8301 while Present (Parm)
8302 and then not Is_RTE (Etype (Parm), RE_Call_Modes)
8303 loop
8304 Next (Parm);
8305 end loop;
8306
8307 Dummy := Remove_Next (Next (Parm));
8308
8309 -- Remove garbage is following the Cancel_Param if present
8310
8311 Dummy := Next (Parm);
8312
8313 -- Remove the mode of the Protected_Entry_Call call, then remove the
8314 -- Communication_Block of the Protected_Entry_Call call, and finally
8315 -- add Duration and a Delay_Mode parameter
8316
8317 pragma Assert (Present (Parm));
8318 Rewrite (Parm, New_Reference_To (D, Loc));
8319
8320 Rewrite (Dummy, New_Reference_To (M, Loc));
8321
8322 -- Add a Boolean flag for successful entry call
8323
8324 Append_To (Parms, New_Reference_To (B, Loc));
8325
8326 if Abort_Allowed
8327 or else Restriction_Active (No_Entry_Queue) = False
8328 or else Number_Entries (Etype (Concval)) > 1
8329 then
8330 Rewrite (Call,
8331 Make_Procedure_Call_Statement (Loc,
8332 Name =>
8333 New_Reference_To (RTE (RE_Timed_Protected_Entry_Call), Loc),
8334 Parameter_Associations => Parms));
8335
8336 else
8337 Parm := First (Parms);
8338
8339 while Present (Parm)
8340 and then not Is_RTE (Etype (Parm), RE_Protected_Entry_Index)
8341 loop
8342 Next (Parm);
8343 end loop;
8344
8345 Remove (Parm);
8346
8347 Rewrite (Call,
8348 Make_Procedure_Call_Statement (Loc,
8349 Name => New_Reference_To (
8350 RTE (RE_Timed_Protected_Single_Entry_Call), Loc),
8351 Parameter_Associations => Parms));
8352 end if;
8353
8354 -- For the task case, build a Timed_Task_Entry_Call
8355
8356 else
8357 -- Create a new call statement
8358
8359 Append_To (Parms, New_Reference_To (D, Loc));
8360 Append_To (Parms, New_Reference_To (M, Loc));
8361 Append_To (Parms, New_Reference_To (B, Loc));
8362
8363 Rewrite (Call,
8364 Make_Procedure_Call_Statement (Loc,
8365 Name => New_Reference_To (RTE (RE_Timed_Task_Entry_Call), Loc),
8366 Parameter_Associations => Parms));
8367
8368 end if;
8369
8370 Append_To (Stmts,
8371 Make_Implicit_If_Statement (N,
8372 Condition => New_Reference_To (B, Loc),
8373 Then_Statements => E_Stats,
8374 Else_Statements => D_Stats));
8375
8376 Rewrite (N,
8377 Make_Block_Statement (Loc,
8378 Declarations => Decls,
8379 Handled_Statement_Sequence =>
8380 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
8381
8382 Analyze (N);
8383 end Expand_N_Timed_Entry_Call;
8384
8385 ----------------------------------------
8386 -- Expand_Protected_Body_Declarations --
8387 ----------------------------------------
8388
8389 -- Part of the expansion of a protected body involves the creation of
8390 -- a declaration that can be referenced from the statement sequences of
8391 -- the entry bodies:
8392
8393 -- A : Address;
8394
8395 -- This declaration is inserted in the declarations of the service
8396 -- entries procedure for the protected body, and it is important that
8397 -- it be inserted before the statements of the entry body statement
8398 -- sequences are analyzed. Thus it would be too late to create this
8399 -- declaration in the Expand_N_Protected_Body routine, which is why
8400 -- there is a separate procedure to be called directly from Sem_Ch9.
8401
8402 -- Ann is used to hold the address of the record containing the parameters
8403 -- (see Expand_N_Entry_Call for more details on how this record is built).
8404 -- References to the parameters do an unchecked conversion of this address
8405 -- to a pointer to the required record type, and then access the field that
8406 -- holds the value of the required parameter. The entity for the address
8407 -- variable is held as the top stack element (i.e. the last element) of the
8408 -- Accept_Address stack in the corresponding entry entity, and this element
8409 -- must be set in place before the statements are processed.
8410
8411 -- No stack is needed for entry bodies, since they cannot be nested, but
8412 -- it is kept for consistency between protected and task entries. The
8413 -- stack will never contain more than one element. There is also only one
8414 -- such variable for a given protected body, but this is placed on the
8415 -- Accept_Address stack of all of the entries, again for consistency.
8416
8417 -- To expand the requeue statement, a label is provided at the end of
8418 -- the loop in the entry service routine created by the expander (see
8419 -- Expand_N_Protected_Body for details), so that the statement can be
8420 -- skipped after the requeue is complete. This label is created during the
8421 -- expansion of the entry body, which will take place after the expansion
8422 -- of the requeue statements that it contains, so a placeholder defining
8423 -- identifier is associated with the task type here.
8424
8425 -- Another label is provided following case statement created by the
8426 -- expander. This label is need for implementing return statement from
8427 -- entry body so that a return can be expanded as a goto to this label.
8428 -- This label is created during the expansion of the entry body, which
8429 -- will take place after the expansion of the return statements that it
8430 -- contains. Therefore, just like the label for expanding requeues, we
8431 -- need another placeholder for the label.
8432
8433 procedure Expand_Protected_Body_Declarations
8434 (N : Node_Id;
8435 Spec_Id : Entity_Id)
8436 is
8437 Op : Node_Id;
8438
8439 begin
8440 if No_Run_Time_Mode then
8441 Error_Msg_CRT ("protected body", N);
8442 return;
8443
8444 elsif Expander_Active then
8445
8446 -- Associate privals with the first subprogram or entry
8447 -- body to be expanded. These are used to expand references
8448 -- to private data objects.
8449
8450 Op := First_Protected_Operation (Declarations (N));
8451
8452 if Present (Op) then
8453 Set_Discriminals (Parent (Spec_Id));
8454 Set_Privals (Parent (Spec_Id), Op, Sloc (N));
8455 end if;
8456 end if;
8457 end Expand_Protected_Body_Declarations;
8458
8459 -------------------------
8460 -- External_Subprogram --
8461 -------------------------
8462
8463 function External_Subprogram (E : Entity_Id) return Entity_Id is
8464 Subp : constant Entity_Id := Protected_Body_Subprogram (E);
8465 Decl : constant Node_Id := Unit_Declaration_Node (E);
8466
8467 begin
8468 -- If the protected operation is defined in the visible part of the
8469 -- protected type, or if it is an interrupt handler, the internal and
8470 -- external subprograms follow each other on the entity chain. If the
8471 -- operation is defined in the private part of the type, there is no
8472 -- need for a separate locking version of the operation, and internal
8473 -- calls use the protected_body_subprogram directly.
8474
8475 if List_Containing (Decl) = Visible_Declarations (Parent (Decl))
8476 or else Is_Interrupt_Handler (E)
8477 then
8478 return Next_Entity (Subp);
8479 else
8480 return (Subp);
8481 end if;
8482 end External_Subprogram;
8483
8484 -------------------
8485 -- Extract_Entry --
8486 -------------------
8487
8488 procedure Extract_Entry
8489 (N : Node_Id;
8490 Concval : out Node_Id;
8491 Ename : out Node_Id;
8492 Index : out Node_Id)
8493 is
8494 Nam : constant Node_Id := Name (N);
8495
8496 begin
8497 -- For a simple entry, the name is a selected component, with the
8498 -- prefix being the task value, and the selector being the entry.
8499
8500 if Nkind (Nam) = N_Selected_Component then
8501 Concval := Prefix (Nam);
8502 Ename := Selector_Name (Nam);
8503 Index := Empty;
8504
8505 -- For a member of an entry family, the name is an indexed
8506 -- component where the prefix is a selected component,
8507 -- whose prefix in turn is the task value, and whose
8508 -- selector is the entry family. The single expression in
8509 -- the expressions list of the indexed component is the
8510 -- subscript for the family.
8511
8512 else
8513 pragma Assert (Nkind (Nam) = N_Indexed_Component);
8514 Concval := Prefix (Prefix (Nam));
8515 Ename := Selector_Name (Prefix (Nam));
8516 Index := First (Expressions (Nam));
8517 end if;
8518 end Extract_Entry;
8519
8520 -------------------
8521 -- Family_Offset --
8522 -------------------
8523
8524 function Family_Offset
8525 (Loc : Source_Ptr;
8526 Hi : Node_Id;
8527 Lo : Node_Id;
8528 Ttyp : Entity_Id) return Node_Id
8529 is
8530 function Convert_Discriminant_Ref (Bound : Node_Id) return Node_Id;
8531 -- If one of the bounds is a reference to a discriminant, replace
8532 -- with corresponding discriminal of type. Within the body of a task
8533 -- retrieve the renamed discriminant by simple visibility, using its
8534 -- generated name. Within a protected object, find the original dis-
8535 -- criminant and replace it with the discriminal of the current prot-
8536 -- ected operation.
8537
8538 ------------------------------
8539 -- Convert_Discriminant_Ref --
8540 ------------------------------
8541
8542 function Convert_Discriminant_Ref (Bound : Node_Id) return Node_Id is
8543 Loc : constant Source_Ptr := Sloc (Bound);
8544 B : Node_Id;
8545 D : Entity_Id;
8546
8547 begin
8548 if Is_Entity_Name (Bound)
8549 and then Ekind (Entity (Bound)) = E_Discriminant
8550 then
8551 if Is_Task_Type (Ttyp)
8552 and then Has_Completion (Ttyp)
8553 then
8554 B := Make_Identifier (Loc, Chars (Entity (Bound)));
8555 Find_Direct_Name (B);
8556
8557 elsif Is_Protected_Type (Ttyp) then
8558 D := First_Discriminant (Ttyp);
8559
8560 while Chars (D) /= Chars (Entity (Bound)) loop
8561 Next_Discriminant (D);
8562 end loop;
8563
8564 B := New_Reference_To (Discriminal (D), Loc);
8565
8566 else
8567 B := New_Reference_To (Discriminal (Entity (Bound)), Loc);
8568 end if;
8569
8570 elsif Nkind (Bound) = N_Attribute_Reference then
8571 return Bound;
8572
8573 else
8574 B := New_Copy_Tree (Bound);
8575 end if;
8576
8577 return
8578 Make_Attribute_Reference (Loc,
8579 Attribute_Name => Name_Pos,
8580 Prefix => New_Occurrence_Of (Etype (Bound), Loc),
8581 Expressions => New_List (B));
8582 end Convert_Discriminant_Ref;
8583
8584 -- Start of processing for Family_Offset
8585
8586 begin
8587 return
8588 Make_Op_Subtract (Loc,
8589 Left_Opnd => Convert_Discriminant_Ref (Hi),
8590 Right_Opnd => Convert_Discriminant_Ref (Lo));
8591 end Family_Offset;
8592
8593 -----------------
8594 -- Family_Size --
8595 -----------------
8596
8597 function Family_Size
8598 (Loc : Source_Ptr;
8599 Hi : Node_Id;
8600 Lo : Node_Id;
8601 Ttyp : Entity_Id) return Node_Id
8602 is
8603 Ityp : Entity_Id;
8604
8605 begin
8606 if Is_Task_Type (Ttyp) then
8607 Ityp := RTE (RE_Task_Entry_Index);
8608 else
8609 Ityp := RTE (RE_Protected_Entry_Index);
8610 end if;
8611
8612 return
8613 Make_Attribute_Reference (Loc,
8614 Prefix => New_Reference_To (Ityp, Loc),
8615 Attribute_Name => Name_Max,
8616 Expressions => New_List (
8617 Make_Op_Add (Loc,
8618 Left_Opnd =>
8619 Family_Offset (Loc, Hi, Lo, Ttyp),
8620 Right_Opnd =>
8621 Make_Integer_Literal (Loc, 1)),
8622 Make_Integer_Literal (Loc, 0)));
8623 end Family_Size;
8624
8625 -----------------------------------
8626 -- Find_Task_Or_Protected_Pragma --
8627 -----------------------------------
8628
8629 function Find_Task_Or_Protected_Pragma
8630 (T : Node_Id;
8631 P : Name_Id) return Node_Id
8632 is
8633 N : Node_Id;
8634
8635 begin
8636 N := First (Visible_Declarations (T));
8637
8638 while Present (N) loop
8639 if Nkind (N) = N_Pragma then
8640 if Chars (N) = P then
8641 return N;
8642
8643 elsif P = Name_Priority
8644 and then Chars (N) = Name_Interrupt_Priority
8645 then
8646 return N;
8647
8648 else
8649 Next (N);
8650 end if;
8651
8652 else
8653 Next (N);
8654 end if;
8655 end loop;
8656
8657 N := First (Private_Declarations (T));
8658
8659 while Present (N) loop
8660 if Nkind (N) = N_Pragma then
8661 if Chars (N) = P then
8662 return N;
8663
8664 elsif P = Name_Priority
8665 and then Chars (N) = Name_Interrupt_Priority
8666 then
8667 return N;
8668
8669 else
8670 Next (N);
8671 end if;
8672
8673 else
8674 Next (N);
8675 end if;
8676 end loop;
8677
8678 raise Program_Error;
8679 end Find_Task_Or_Protected_Pragma;
8680
8681 -------------------------------
8682 -- First_Protected_Operation --
8683 -------------------------------
8684
8685 function First_Protected_Operation (D : List_Id) return Node_Id is
8686 First_Op : Node_Id;
8687
8688 begin
8689 First_Op := First (D);
8690 while Present (First_Op)
8691 and then Nkind (First_Op) /= N_Subprogram_Body
8692 and then Nkind (First_Op) /= N_Entry_Body
8693 loop
8694 Next (First_Op);
8695 end loop;
8696
8697 return First_Op;
8698 end First_Protected_Operation;
8699
8700 --------------------------------
8701 -- Index_Constant_Declaration --
8702 --------------------------------
8703
8704 function Index_Constant_Declaration
8705 (N : Node_Id;
8706 Index_Id : Entity_Id;
8707 Prot : Entity_Id) return List_Id
8708 is
8709 Loc : constant Source_Ptr := Sloc (N);
8710 Decls : constant List_Id := New_List;
8711 Index_Con : constant Entity_Id := Entry_Index_Constant (Index_Id);
8712 Index_Typ : Entity_Id;
8713
8714 Hi : Node_Id := Type_High_Bound (Etype (Index_Id));
8715 Lo : Node_Id := Type_Low_Bound (Etype (Index_Id));
8716
8717 function Replace_Discriminant (Bound : Node_Id) return Node_Id;
8718 -- The bounds of the entry index may depend on discriminants, so
8719 -- each declaration of an entry_index_constant must have its own
8720 -- subtype declaration, using the local renaming of the object discri-
8721 -- minant.
8722
8723 --------------------------
8724 -- Replace_Discriminant --
8725 --------------------------
8726
8727 function Replace_Discriminant (Bound : Node_Id) return Node_Id is
8728 begin
8729 if Nkind (Bound) = N_Identifier
8730 and then Ekind (Entity (Bound)) = E_Constant
8731 and then Present (Discriminal_Link (Entity (Bound)))
8732 then
8733 return Make_Identifier (Loc, Chars (Entity (Bound)));
8734 else
8735 return Duplicate_Subexpr (Bound);
8736 end if;
8737 end Replace_Discriminant;
8738
8739 -- Start of processing for Index_Constant_Declaration
8740
8741 begin
8742 Set_Discriminal_Link (Index_Con, Index_Id);
8743
8744 if Is_Entity_Name (
8745 Original_Node (Discrete_Subtype_Definition (Parent (Index_Id))))
8746 then
8747 -- Simple case: entry family is given by a subtype mark, and index
8748 -- constant has the same type, no replacement needed.
8749
8750 Index_Typ := Etype (Index_Id);
8751
8752 else
8753 Hi := Replace_Discriminant (Hi);
8754 Lo := Replace_Discriminant (Lo);
8755
8756 Index_Typ := Make_Defining_Identifier (Loc, New_Internal_Name ('J'));
8757
8758 Append (
8759 Make_Subtype_Declaration (Loc,
8760 Defining_Identifier => Index_Typ,
8761 Subtype_Indication =>
8762 Make_Subtype_Indication (Loc,
8763 Subtype_Mark =>
8764 New_Occurrence_Of (Base_Type (Etype (Index_Id)), Loc),
8765 Constraint =>
8766 Make_Range_Constraint (Loc,
8767 Range_Expression => Make_Range (Loc, Lo, Hi)))),
8768 Decls);
8769
8770 end if;
8771
8772 Append (
8773 Make_Object_Declaration (Loc,
8774 Defining_Identifier => Index_Con,
8775 Constant_Present => True,
8776 Object_Definition => New_Occurrence_Of (Index_Typ, Loc),
8777
8778 Expression =>
8779 Make_Attribute_Reference (Loc,
8780 Prefix => New_Reference_To (Index_Typ, Loc),
8781 Attribute_Name => Name_Val,
8782
8783 Expressions => New_List (
8784
8785 Make_Op_Add (Loc,
8786 Left_Opnd =>
8787 Make_Op_Subtract (Loc,
8788 Left_Opnd => Make_Identifier (Loc, Name_uE),
8789 Right_Opnd =>
8790 Entry_Index_Expression (Loc,
8791 Defining_Identifier (N), Empty, Prot)),
8792
8793 Right_Opnd =>
8794 Make_Attribute_Reference (Loc,
8795 Prefix => New_Reference_To (Index_Typ, Loc),
8796 Attribute_Name => Name_Pos,
8797 Expressions => New_List (
8798 Make_Attribute_Reference (Loc,
8799 Prefix => New_Reference_To (Index_Typ, Loc),
8800 Attribute_Name => Name_First))))))),
8801 Decls);
8802
8803 return Decls;
8804 end Index_Constant_Declaration;
8805
8806 --------------------------------
8807 -- Make_Initialize_Protection --
8808 --------------------------------
8809
8810 function Make_Initialize_Protection
8811 (Protect_Rec : Entity_Id) return List_Id
8812 is
8813 Loc : constant Source_Ptr := Sloc (Protect_Rec);
8814 P_Arr : Entity_Id;
8815 Pdef : Node_Id;
8816 Pdec : Node_Id;
8817 Ptyp : constant Node_Id :=
8818 Corresponding_Concurrent_Type (Protect_Rec);
8819 Args : List_Id;
8820 L : constant List_Id := New_List;
8821 Has_Entry : constant Boolean := Has_Entries (Ptyp);
8822 Restricted : constant Boolean := Restricted_Profile;
8823
8824 begin
8825 -- We may need two calls to properly initialize the object, one
8826 -- to Initialize_Protection, and possibly one to Install_Handlers
8827 -- if we have a pragma Attach_Handler.
8828
8829 -- Get protected declaration. In the case of a task type declaration,
8830 -- this is simply the parent of the protected type entity.
8831 -- In the single protected object
8832 -- declaration, this parent will be the implicit type, and we can find
8833 -- the corresponding single protected object declaration by
8834 -- searching forward in the declaration list in the tree.
8835 -- ??? I am not sure that the test for N_Single_Protected_Declaration
8836 -- is needed here. Nodes of this type should have been removed
8837 -- during semantic analysis.
8838
8839 Pdec := Parent (Ptyp);
8840
8841 while Nkind (Pdec) /= N_Protected_Type_Declaration
8842 and then Nkind (Pdec) /= N_Single_Protected_Declaration
8843 loop
8844 Next (Pdec);
8845 end loop;
8846
8847 -- Now we can find the object definition from this declaration
8848
8849 Pdef := Protected_Definition (Pdec);
8850
8851 -- Build the parameter list for the call. Note that _Init is the name
8852 -- of the formal for the object to be initialized, which is the task
8853 -- value record itself.
8854
8855 Args := New_List;
8856
8857 -- Object parameter. This is a pointer to the object of type
8858 -- Protection used by the GNARL to control the protected object.
8859
8860 Append_To (Args,
8861 Make_Attribute_Reference (Loc,
8862 Prefix =>
8863 Make_Selected_Component (Loc,
8864 Prefix => Make_Identifier (Loc, Name_uInit),
8865 Selector_Name => Make_Identifier (Loc, Name_uObject)),
8866 Attribute_Name => Name_Unchecked_Access));
8867
8868 -- Priority parameter. Set to Unspecified_Priority unless there is a
8869 -- priority pragma, in which case we take the value from the pragma,
8870 -- or there is an interrupt pragma and no priority pragma, and we
8871 -- set the ceiling to Interrupt_Priority'Last, an implementation-
8872 -- defined value, see D.3(10).
8873
8874 if Present (Pdef)
8875 and then Has_Priority_Pragma (Pdef)
8876 then
8877 Append_To (Args,
8878 Duplicate_Subexpr_No_Checks
8879 (Expression
8880 (First
8881 (Pragma_Argument_Associations
8882 (Find_Task_Or_Protected_Pragma (Pdef, Name_Priority))))));
8883
8884 elsif Has_Interrupt_Handler (Ptyp)
8885 or else Has_Attach_Handler (Ptyp)
8886 then
8887 -- When no priority is specified but an xx_Handler pragma is,
8888 -- we default to System.Interrupts.Default_Interrupt_Priority,
8889 -- see D.3(10).
8890
8891 Append_To (Args,
8892 New_Reference_To (RTE (RE_Default_Interrupt_Priority), Loc));
8893
8894 else
8895 Append_To (Args,
8896 New_Reference_To (RTE (RE_Unspecified_Priority), Loc));
8897 end if;
8898
8899 if Has_Entry
8900 or else Has_Interrupt_Handler (Ptyp)
8901 or else Has_Attach_Handler (Ptyp)
8902 then
8903 -- Compiler_Info parameter. This parameter allows entry body
8904 -- procedures and barrier functions to be called from the runtime.
8905 -- It is a pointer to the record generated by the compiler to
8906 -- represent the protected object.
8907
8908 if Has_Entry or else not Restricted then
8909 Append_To (Args,
8910 Make_Attribute_Reference (Loc,
8911 Prefix => Make_Identifier (Loc, Name_uInit),
8912 Attribute_Name => Name_Address));
8913 end if;
8914
8915 if Has_Entry then
8916 -- Entry_Bodies parameter. This is a pointer to an array of
8917 -- pointers to the entry body procedures and barrier functions
8918 -- of the object. If the protected type has no entries this
8919 -- object will not exist; in this case, pass a null.
8920
8921 P_Arr := Entry_Bodies_Array (Ptyp);
8922
8923 Append_To (Args,
8924 Make_Attribute_Reference (Loc,
8925 Prefix => New_Reference_To (P_Arr, Loc),
8926 Attribute_Name => Name_Unrestricted_Access));
8927
8928 if Abort_Allowed
8929 or else Restriction_Active (No_Entry_Queue) = False
8930 or else Number_Entries (Ptyp) > 1
8931 then
8932 -- Find index mapping function (clumsy but ok for now)
8933
8934 while Ekind (P_Arr) /= E_Function loop
8935 Next_Entity (P_Arr);
8936 end loop;
8937
8938 Append_To (Args,
8939 Make_Attribute_Reference (Loc,
8940 Prefix =>
8941 New_Reference_To (P_Arr, Loc),
8942 Attribute_Name => Name_Unrestricted_Access));
8943 end if;
8944
8945 elsif not Restricted then
8946 Append_To (Args, Make_Null (Loc));
8947 Append_To (Args, Make_Null (Loc));
8948 end if;
8949
8950 if Abort_Allowed
8951 or else Restriction_Active (No_Entry_Queue) = False
8952 or else Number_Entries (Ptyp) > 1
8953 then
8954 Append_To (L,
8955 Make_Procedure_Call_Statement (Loc,
8956 Name => New_Reference_To (
8957 RTE (RE_Initialize_Protection_Entries), Loc),
8958 Parameter_Associations => Args));
8959
8960 elsif not Has_Entry and then Restricted then
8961 Append_To (L,
8962 Make_Procedure_Call_Statement (Loc,
8963 Name => New_Reference_To (
8964 RTE (RE_Initialize_Protection), Loc),
8965 Parameter_Associations => Args));
8966
8967 else
8968 Append_To (L,
8969 Make_Procedure_Call_Statement (Loc,
8970 Name => New_Reference_To (
8971 RTE (RE_Initialize_Protection_Entry), Loc),
8972 Parameter_Associations => Args));
8973 end if;
8974
8975 else
8976 Append_To (L,
8977 Make_Procedure_Call_Statement (Loc,
8978 Name => New_Reference_To (RTE (RE_Initialize_Protection), Loc),
8979 Parameter_Associations => Args));
8980 end if;
8981
8982 if Has_Attach_Handler (Ptyp) then
8983
8984 -- We have a list of N Attach_Handler (ProcI, ExprI),
8985 -- and we have to make the following call:
8986 -- Install_Handlers (_object,
8987 -- ((Expr1, Proc1'access), ...., (ExprN, ProcN'access));
8988 -- or, in the case of Ravenscar:
8989 -- Install_Handlers
8990 -- ((Expr1, Proc1'access), ...., (ExprN, ProcN'access));
8991
8992 declare
8993 Args : constant List_Id := New_List;
8994 Table : constant List_Id := New_List;
8995 Ritem : Node_Id := First_Rep_Item (Ptyp);
8996
8997 begin
8998 if not Restricted then
8999 -- Appends the _object argument
9000
9001 Append_To (Args,
9002 Make_Attribute_Reference (Loc,
9003 Prefix =>
9004 Make_Selected_Component (Loc,
9005 Prefix => Make_Identifier (Loc, Name_uInit),
9006 Selector_Name => Make_Identifier (Loc, Name_uObject)),
9007 Attribute_Name => Name_Unchecked_Access));
9008 end if;
9009
9010 -- Build the Attach_Handler table argument
9011
9012 while Present (Ritem) loop
9013 if Nkind (Ritem) = N_Pragma
9014 and then Chars (Ritem) = Name_Attach_Handler
9015 then
9016 declare
9017 Handler : constant Node_Id :=
9018 First (Pragma_Argument_Associations (Ritem));
9019
9020 Interrupt : constant Node_Id := Next (Handler);
9021 Expr : constant Node_Id := Expression (Interrupt);
9022
9023 begin
9024 Append_To (Table,
9025 Make_Aggregate (Loc, Expressions => New_List (
9026 Unchecked_Convert_To
9027 (RTE (RE_System_Interrupt_Id), Expr),
9028 Make_Attribute_Reference (Loc,
9029 Prefix => Make_Selected_Component (Loc,
9030 Make_Identifier (Loc, Name_uInit),
9031 Duplicate_Subexpr_No_Checks
9032 (Expression (Handler))),
9033 Attribute_Name => Name_Access))));
9034 end;
9035 end if;
9036
9037 Next_Rep_Item (Ritem);
9038 end loop;
9039
9040 -- Append the table argument we just built
9041
9042 Append_To (Args, Make_Aggregate (Loc, Table));
9043
9044 -- Append the Install_Handler call to the statements
9045
9046 Append_To (L,
9047 Make_Procedure_Call_Statement (Loc,
9048 Name => New_Reference_To (RTE (RE_Install_Handlers), Loc),
9049 Parameter_Associations => Args));
9050 end;
9051 end if;
9052
9053 return L;
9054 end Make_Initialize_Protection;
9055
9056 ---------------------------
9057 -- Make_Task_Create_Call --
9058 ---------------------------
9059
9060 function Make_Task_Create_Call (Task_Rec : Entity_Id) return Node_Id is
9061 Loc : constant Source_Ptr := Sloc (Task_Rec);
9062 Name : Node_Id;
9063 Tdef : Node_Id;
9064 Tdec : Node_Id;
9065 Ttyp : Node_Id;
9066 Tnam : Name_Id;
9067 Args : List_Id;
9068 Ecount : Node_Id;
9069
9070 begin
9071 Ttyp := Corresponding_Concurrent_Type (Task_Rec);
9072 Tnam := Chars (Ttyp);
9073
9074 -- Get task declaration. In the case of a task type declaration, this
9075 -- is simply the parent of the task type entity. In the single task
9076 -- declaration, this parent will be the implicit type, and we can find
9077 -- the corresponding single task declaration by searching forward in
9078 -- the declaration list in the tree.
9079 -- ??? I am not sure that the test for N_Single_Task_Declaration
9080 -- is needed here. Nodes of this type should have been removed
9081 -- during semantic analysis.
9082
9083 Tdec := Parent (Ttyp);
9084
9085 while Nkind (Tdec) /= N_Task_Type_Declaration
9086 and then Nkind (Tdec) /= N_Single_Task_Declaration
9087 loop
9088 Next (Tdec);
9089 end loop;
9090
9091 -- Now we can find the task definition from this declaration
9092
9093 Tdef := Task_Definition (Tdec);
9094
9095 -- Build the parameter list for the call. Note that _Init is the name
9096 -- of the formal for the object to be initialized, which is the task
9097 -- value record itself.
9098
9099 Args := New_List;
9100
9101 -- Priority parameter. Set to Unspecified_Priority unless there is a
9102 -- priority pragma, in which case we take the value from the pragma.
9103
9104 if Present (Tdef) and then Has_Priority_Pragma (Tdef) then
9105 Append_To (Args,
9106 Make_Selected_Component (Loc,
9107 Prefix => Make_Identifier (Loc, Name_uInit),
9108 Selector_Name => Make_Identifier (Loc, Name_uPriority)));
9109 else
9110 Append_To (Args,
9111 New_Reference_To (RTE (RE_Unspecified_Priority), Loc));
9112 end if;
9113
9114 -- Optional Stack parameter
9115
9116 if Restricted_Profile then
9117
9118 -- If the stack has been preallocated by the expander then
9119 -- pass its address. Otherwise, pass a null address.
9120
9121 if Preallocated_Stacks_On_Target then
9122 Append_To (Args,
9123 Make_Attribute_Reference (Loc,
9124 Prefix => Make_Selected_Component (Loc,
9125 Prefix => Make_Identifier (Loc, Name_uInit),
9126 Selector_Name =>
9127 Make_Identifier (Loc, Name_uStack)),
9128 Attribute_Name => Name_Address));
9129
9130 else
9131 Append_To (Args,
9132 New_Reference_To (RTE (RE_Null_Address), Loc));
9133 end if;
9134 end if;
9135
9136 -- Size parameter. If no Storage_Size pragma is present, then
9137 -- the size is taken from the taskZ variable for the type, which
9138 -- is either Unspecified_Size, or has been reset by the use of
9139 -- a Storage_Size attribute definition clause. If a pragma is
9140 -- present, then the size is taken from the _Size field of the
9141 -- task value record, which was set from the pragma value.
9142
9143 if Present (Tdef)
9144 and then Has_Storage_Size_Pragma (Tdef)
9145 then
9146 Append_To (Args,
9147 Make_Selected_Component (Loc,
9148 Prefix => Make_Identifier (Loc, Name_uInit),
9149 Selector_Name => Make_Identifier (Loc, Name_uSize)));
9150
9151 else
9152 Append_To (Args,
9153 New_Reference_To (Storage_Size_Variable (Ttyp), Loc));
9154 end if;
9155
9156 -- Task_Info parameter. Set to Unspecified_Task_Info unless there is a
9157 -- Task_Info pragma, in which case we take the value from the pragma.
9158
9159 if Present (Tdef)
9160 and then Has_Task_Info_Pragma (Tdef)
9161 then
9162 Append_To (Args,
9163 Make_Selected_Component (Loc,
9164 Prefix => Make_Identifier (Loc, Name_uInit),
9165 Selector_Name => Make_Identifier (Loc, Name_uTask_Info)));
9166
9167 else
9168 Append_To (Args,
9169 New_Reference_To (RTE (RE_Unspecified_Task_Info), Loc));
9170 end if;
9171
9172 if not Restricted_Profile then
9173
9174 -- Number of entries. This is an expression of the form:
9175 --
9176 -- n + _Init.a'Length + _Init.a'B'Length + ...
9177 --
9178 -- where a,b... are the entry family names for the task definition
9179
9180 Ecount := Build_Entry_Count_Expression (
9181 Ttyp,
9182 Component_Items (Component_List (
9183 Type_Definition (Parent (
9184 Corresponding_Record_Type (Ttyp))))),
9185 Loc);
9186 Append_To (Args, Ecount);
9187
9188 -- Master parameter. This is a reference to the _Master parameter of
9189 -- the initialization procedure, except in the case of the pragma
9190 -- Restrictions (No_Task_Hierarchy) where the value is fixed to 3.
9191 -- See comments in System.Tasking.Initialization.Init_RTS for the
9192 -- value 3.
9193
9194 if Restriction_Active (No_Task_Hierarchy) = False then
9195 Append_To (Args, Make_Identifier (Loc, Name_uMaster));
9196 else
9197 Append_To (Args, Make_Integer_Literal (Loc, 3));
9198 end if;
9199 end if;
9200
9201 -- State parameter. This is a pointer to the task body procedure. The
9202 -- required value is obtained by taking the address of the task body
9203 -- procedure and converting it (with an unchecked conversion) to the
9204 -- type required by the task kernel. For further details, see the
9205 -- description of Expand_Task_Body
9206
9207 Append_To (Args,
9208 Unchecked_Convert_To (RTE (RE_Task_Procedure_Access),
9209 Make_Attribute_Reference (Loc,
9210 Prefix =>
9211 New_Occurrence_Of (Get_Task_Body_Procedure (Ttyp), Loc),
9212 Attribute_Name => Name_Address)));
9213
9214 -- Discriminants parameter. This is just the address of the task
9215 -- value record itself (which contains the discriminant values
9216
9217 Append_To (Args,
9218 Make_Attribute_Reference (Loc,
9219 Prefix => Make_Identifier (Loc, Name_uInit),
9220 Attribute_Name => Name_Address));
9221
9222 -- Elaborated parameter. This is an access to the elaboration Boolean
9223
9224 Append_To (Args,
9225 Make_Attribute_Reference (Loc,
9226 Prefix => Make_Identifier (Loc, New_External_Name (Tnam, 'E')),
9227 Attribute_Name => Name_Unchecked_Access));
9228
9229 -- Chain parameter. This is a reference to the _Chain parameter of
9230 -- the initialization procedure.
9231
9232 Append_To (Args, Make_Identifier (Loc, Name_uChain));
9233
9234 -- Task name parameter. Take this from the _Task_Id parameter to the
9235 -- init call unless there is a Task_Name pragma, in which case we take
9236 -- the value from the pragma.
9237
9238 if Present (Tdef)
9239 and then Has_Task_Name_Pragma (Tdef)
9240 then
9241 Append_To (Args,
9242 New_Copy (
9243 Expression (First (
9244 Pragma_Argument_Associations (
9245 Find_Task_Or_Protected_Pragma
9246 (Tdef, Name_Task_Name))))));
9247
9248 else
9249 Append_To (Args, Make_Identifier (Loc, Name_uTask_Name));
9250 end if;
9251
9252 -- Created_Task parameter. This is the _Task_Id field of the task
9253 -- record value
9254
9255 Append_To (Args,
9256 Make_Selected_Component (Loc,
9257 Prefix => Make_Identifier (Loc, Name_uInit),
9258 Selector_Name => Make_Identifier (Loc, Name_uTask_Id)));
9259
9260 if Restricted_Profile then
9261 Name := New_Reference_To (RTE (RE_Create_Restricted_Task), Loc);
9262 else
9263 Name := New_Reference_To (RTE (RE_Create_Task), Loc);
9264 end if;
9265
9266 return Make_Procedure_Call_Statement (Loc,
9267 Name => Name, Parameter_Associations => Args);
9268 end Make_Task_Create_Call;
9269
9270 ------------------------------
9271 -- Next_Protected_Operation --
9272 ------------------------------
9273
9274 function Next_Protected_Operation (N : Node_Id) return Node_Id is
9275 Next_Op : Node_Id;
9276
9277 begin
9278 Next_Op := Next (N);
9279
9280 while Present (Next_Op)
9281 and then Nkind (Next_Op) /= N_Subprogram_Body
9282 and then Nkind (Next_Op) /= N_Entry_Body
9283 loop
9284 Next (Next_Op);
9285 end loop;
9286
9287 return Next_Op;
9288 end Next_Protected_Operation;
9289
9290 ----------------------
9291 -- Set_Discriminals --
9292 ----------------------
9293
9294 procedure Set_Discriminals (Dec : Node_Id) is
9295 D : Entity_Id;
9296 Pdef : Entity_Id;
9297 D_Minal : Entity_Id;
9298
9299 begin
9300 pragma Assert (Nkind (Dec) = N_Protected_Type_Declaration);
9301 Pdef := Defining_Identifier (Dec);
9302
9303 if Has_Discriminants (Pdef) then
9304 D := First_Discriminant (Pdef);
9305
9306 while Present (D) loop
9307 D_Minal :=
9308 Make_Defining_Identifier (Sloc (D),
9309 Chars => New_External_Name (Chars (D), 'D'));
9310
9311 Set_Ekind (D_Minal, E_Constant);
9312 Set_Etype (D_Minal, Etype (D));
9313 Set_Scope (D_Minal, Pdef);
9314 Set_Discriminal (D, D_Minal);
9315 Set_Discriminal_Link (D_Minal, D);
9316
9317 Next_Discriminant (D);
9318 end loop;
9319 end if;
9320 end Set_Discriminals;
9321
9322 -----------------
9323 -- Set_Privals --
9324 -----------------
9325
9326 procedure Set_Privals
9327 (Dec : Node_Id;
9328 Op : Node_Id;
9329 Loc : Source_Ptr)
9330 is
9331 P_Decl : Node_Id;
9332 P_Id : Entity_Id;
9333 Priv : Entity_Id;
9334 Def : Node_Id;
9335 Body_Ent : Entity_Id;
9336 Prec_Decl : constant Node_Id :=
9337 Parent (Corresponding_Record_Type
9338 (Defining_Identifier (Dec)));
9339 Prec_Def : constant Entity_Id := Type_Definition (Prec_Decl);
9340 Obj_Decl : Node_Id;
9341 P_Subtype : Entity_Id;
9342 Assoc_L : constant Elist_Id := New_Elmt_List;
9343 Op_Id : Entity_Id;
9344
9345 begin
9346 pragma Assert (Nkind (Dec) = N_Protected_Type_Declaration);
9347 pragma Assert
9348 (Nkind (Op) = N_Subprogram_Body or else Nkind (Op) = N_Entry_Body);
9349
9350 Def := Protected_Definition (Dec);
9351
9352 if Present (Private_Declarations (Def)) then
9353
9354 P_Decl := First (Private_Declarations (Def));
9355
9356 while Present (P_Decl) loop
9357 if Nkind (P_Decl) = N_Component_Declaration then
9358 P_Id := Defining_Identifier (P_Decl);
9359 Priv :=
9360 Make_Defining_Identifier (Loc,
9361 New_External_Name (Chars (P_Id), 'P'));
9362
9363 Set_Ekind (Priv, E_Variable);
9364 Set_Etype (Priv, Etype (P_Id));
9365 Set_Scope (Priv, Scope (P_Id));
9366 Set_Esize (Priv, Esize (Etype (P_Id)));
9367 Set_Alignment (Priv, Alignment (Etype (P_Id)));
9368
9369 -- If the type of the component is an itype, we must
9370 -- create a new itype for the corresponding prival in
9371 -- each protected operation, to avoid scoping problems.
9372 -- We create new itypes by copying the tree for the
9373 -- component definition.
9374
9375 if Is_Itype (Etype (P_Id)) then
9376 Append_Elmt (P_Id, Assoc_L);
9377 Append_Elmt (Priv, Assoc_L);
9378
9379 if Nkind (Op) = N_Entry_Body then
9380 Op_Id := Defining_Identifier (Op);
9381 else
9382 Op_Id := Defining_Unit_Name (Specification (Op));
9383 end if;
9384
9385 Discard_Node
9386 (New_Copy_Tree (P_Decl, Assoc_L, New_Scope => Op_Id));
9387 end if;
9388
9389 Set_Protected_Operation (P_Id, Op);
9390 Set_Prival (P_Id, Priv);
9391 end if;
9392
9393 Next (P_Decl);
9394 end loop;
9395 end if;
9396
9397 -- There is one more implicit private declaration: the object
9398 -- itself. A "prival" for this is attached to the protected
9399 -- body defining identifier.
9400
9401 Body_Ent := Corresponding_Body (Dec);
9402
9403 Priv :=
9404 Make_Defining_Identifier (Sloc (Body_Ent),
9405 Chars => New_External_Name (Chars (Body_Ent), 'R'));
9406
9407 -- Set the Etype to the implicit subtype of Protection created when
9408 -- the protected type declaration was expanded. This node will not
9409 -- be analyzed until it is used as the defining identifier for the
9410 -- renaming declaration in the protected operation body, and it will
9411 -- be needed in the references expanded before that body is expanded.
9412 -- Since the Protection field is aliased, set Is_Aliased as well.
9413
9414 Obj_Decl := First (Component_Items (Component_List (Prec_Def)));
9415 while Chars (Defining_Identifier (Obj_Decl)) /= Name_uObject loop
9416 Next (Obj_Decl);
9417 end loop;
9418
9419 P_Subtype := Etype (Defining_Identifier (Obj_Decl));
9420 Set_Ekind (Priv, E_Variable);
9421 Set_Etype (Priv, P_Subtype);
9422 Set_Is_Aliased (Priv);
9423 Set_Object_Ref (Body_Ent, Priv);
9424 end Set_Privals;
9425
9426 ----------------------------
9427 -- Update_Prival_Subtypes --
9428 ----------------------------
9429
9430 procedure Update_Prival_Subtypes (N : Node_Id) is
9431
9432 function Process (N : Node_Id) return Traverse_Result;
9433 -- Update the etype of occurrences of privals whose etype does not
9434 -- match the current Etype of the prival entity itself.
9435
9436 procedure Update_Array_Bounds (E : Entity_Id);
9437 -- Itypes generated for array expressions may depend on the
9438 -- determinants of the protected object, and need to be processed
9439 -- separately because they are not attached to the tree.
9440
9441 procedure Update_Index_Types (N : Node_Id);
9442 -- Similarly, update the types of expressions in indexed components
9443 -- which may depend on other discriminants.
9444
9445 -------------
9446 -- Process --
9447 -------------
9448
9449 function Process (N : Node_Id) return Traverse_Result is
9450 begin
9451 if Is_Entity_Name (N) then
9452 declare
9453 E : constant Entity_Id := Entity (N);
9454
9455 begin
9456 if Present (E)
9457 and then (Ekind (E) = E_Constant
9458 or else Ekind (E) = E_Variable)
9459 and then Nkind (Parent (E)) = N_Object_Renaming_Declaration
9460 and then not Is_Scalar_Type (Etype (E))
9461 and then Etype (N) /= Etype (E)
9462 then
9463 Set_Etype (N, Etype (Entity (Original_Node (N))));
9464 Update_Index_Types (N);
9465
9466 elsif Present (E)
9467 and then Ekind (E) = E_Constant
9468 and then Present (Discriminal_Link (E))
9469 then
9470 Set_Etype (N, Etype (E));
9471 end if;
9472 end;
9473
9474 return OK;
9475
9476 elsif Nkind (N) = N_Defining_Identifier
9477 or else Nkind (N) = N_Defining_Operator_Symbol
9478 or else Nkind (N) = N_Defining_Character_Literal
9479 then
9480 return Skip;
9481
9482 elsif Nkind (N) = N_String_Literal then
9483
9484 -- Array type, but bounds are constant
9485
9486 return OK;
9487
9488 elsif Nkind (N) = N_Object_Declaration
9489 and then Is_Itype (Etype (Defining_Identifier (N)))
9490 and then Is_Array_Type (Etype (Defining_Identifier (N)))
9491 then
9492 Update_Array_Bounds (Etype (Defining_Identifier (N)));
9493 return OK;
9494
9495 -- For array components of discriminated records, use the
9496 -- base type directly, because it may depend indirectly
9497 -- on the discriminants of the protected type. Cleaner would
9498 -- be a systematic mechanism to compute actual subtypes of
9499 -- private components ???
9500
9501 elsif Nkind (N) in N_Has_Etype
9502 and then Present (Etype (N))
9503 and then Is_Array_Type (Etype (N))
9504 and then Nkind (N) = N_Selected_Component
9505 and then Has_Discriminants (Etype (Prefix (N)))
9506 then
9507 Set_Etype (N, Base_Type (Etype (N)));
9508 Update_Index_Types (N);
9509 return OK;
9510
9511 else
9512 if Nkind (N) in N_Has_Etype
9513 and then Present (Etype (N))
9514 and then Is_Itype (Etype (N)) then
9515
9516 if Is_Array_Type (Etype (N)) then
9517 Update_Array_Bounds (Etype (N));
9518
9519 elsif Is_Scalar_Type (Etype (N)) then
9520 Update_Prival_Subtypes (Type_Low_Bound (Etype (N)));
9521 Update_Prival_Subtypes (Type_High_Bound (Etype (N)));
9522 end if;
9523 end if;
9524
9525 return OK;
9526 end if;
9527 end Process;
9528
9529 -------------------------
9530 -- Update_Array_Bounds --
9531 -------------------------
9532
9533 procedure Update_Array_Bounds (E : Entity_Id) is
9534 Ind : Node_Id;
9535
9536 begin
9537 Ind := First_Index (E);
9538
9539 while Present (Ind) loop
9540 Update_Prival_Subtypes (Type_Low_Bound (Etype (Ind)));
9541 Update_Prival_Subtypes (Type_High_Bound (Etype (Ind)));
9542 Next_Index (Ind);
9543 end loop;
9544 end Update_Array_Bounds;
9545
9546 ------------------------
9547 -- Update_Index_Types --
9548 ------------------------
9549
9550 procedure Update_Index_Types (N : Node_Id) is
9551 Indx1 : Node_Id;
9552 I_Typ : Node_Id;
9553 begin
9554 -- If the prefix has an actual subtype that is different
9555 -- from the nominal one, update the types of the indices,
9556 -- so that the proper constraints are applied. Do not
9557 -- apply this transformation to a packed array, where the
9558 -- index type is computed for a byte array and is different
9559 -- from the source index.
9560
9561 if Nkind (Parent (N)) = N_Indexed_Component
9562 and then
9563 not Is_Bit_Packed_Array (Etype (Prefix (Parent (N))))
9564 then
9565 Indx1 := First (Expressions (Parent (N)));
9566 I_Typ := First_Index (Etype (N));
9567
9568 while Present (Indx1) and then Present (I_Typ) loop
9569
9570 if not Is_Entity_Name (Indx1) then
9571 Set_Etype (Indx1, Base_Type (Etype (I_Typ)));
9572 end if;
9573
9574 Next (Indx1);
9575 Next_Index (I_Typ);
9576 end loop;
9577 end if;
9578 end Update_Index_Types;
9579
9580 procedure Traverse is new Traverse_Proc;
9581
9582 -- Start of processing for Update_Prival_Subtypes
9583
9584 begin
9585 Traverse (N);
9586 end Update_Prival_Subtypes;
9587
9588 end Exp_Ch9;