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