Fix GNU coding style for G_.
[official-gcc.git] / gcc / ada / exp_ch9.adb
bloba3234fbb94a9ada6b70c2a2fb966d2fa0b6d7044
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- E X P _ C H 9 --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2018, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, 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 COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
20 -- --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
23 -- --
24 ------------------------------------------------------------------------------
26 with Atree; use Atree;
27 with Einfo; use Einfo;
28 with Elists; use Elists;
29 with Errout; use Errout;
30 with Exp_Ch3; use Exp_Ch3;
31 with Exp_Ch6; use Exp_Ch6;
32 with Exp_Ch11; use Exp_Ch11;
33 with Exp_Dbug; use Exp_Dbug;
34 with Exp_Disp; use Exp_Disp;
35 with Exp_Sel; use Exp_Sel;
36 with Exp_Smem; use Exp_Smem;
37 with Exp_Tss; use Exp_Tss;
38 with Exp_Util; use Exp_Util;
39 with Freeze; use Freeze;
40 with Hostparm;
41 with Itypes; use Itypes;
42 with Namet; use Namet;
43 with Nlists; use Nlists;
44 with Nmake; use Nmake;
45 with Opt; use Opt;
46 with Restrict; use Restrict;
47 with Rident; use Rident;
48 with Rtsfind; use Rtsfind;
49 with Sem; use Sem;
50 with Sem_Aux; use Sem_Aux;
51 with Sem_Ch6; use Sem_Ch6;
52 with Sem_Ch8; use Sem_Ch8;
53 with Sem_Ch9; use Sem_Ch9;
54 with Sem_Ch11; use Sem_Ch11;
55 with Sem_Elab; use Sem_Elab;
56 with Sem_Eval; use Sem_Eval;
57 with Sem_Res; use Sem_Res;
58 with Sem_Util; use Sem_Util;
59 with Sinfo; use Sinfo;
60 with Snames; use Snames;
61 with Stand; use Stand;
62 with Targparm; use Targparm;
63 with Tbuild; use Tbuild;
64 with Uintp; use Uintp;
65 with Validsw; use Validsw;
67 package body Exp_Ch9 is
69 -- The following constant establishes the upper bound for the index of
70 -- an entry family. It is used to limit the allocated size of protected
71 -- types with defaulted discriminant of an integer type, when the bound
72 -- of some entry family depends on a discriminant. The limitation to entry
73 -- families of 128K should be reasonable in all cases, and is a documented
74 -- implementation restriction.
76 Entry_Family_Bound : constant Pos := 2**16;
78 -----------------------
79 -- Local Subprograms --
80 -----------------------
82 function Actual_Index_Expression
83 (Sloc : Source_Ptr;
84 Ent : Entity_Id;
85 Index : Node_Id;
86 Tsk : Entity_Id) return Node_Id;
87 -- Compute the index position for an entry call. Tsk is the target task. If
88 -- the bounds of some entry family depend on discriminants, the expression
89 -- computed by this function uses the discriminants of the target task.
91 procedure Add_Object_Pointer
92 (Loc : Source_Ptr;
93 Conc_Typ : Entity_Id;
94 Decls : List_Id);
95 -- Prepend an object pointer declaration to the declaration list Decls.
96 -- This object pointer is initialized to a type conversion of the System.
97 -- Address pointer passed to entry barrier functions and entry body
98 -- procedures.
100 procedure Add_Formal_Renamings
101 (Spec : Node_Id;
102 Decls : List_Id;
103 Ent : Entity_Id;
104 Loc : Source_Ptr);
105 -- Create renaming declarations for the formals, inside the procedure that
106 -- implements an entry body. The renamings make the original names of the
107 -- formals accessible to gdb, and serve no other purpose.
108 -- Spec is the specification of the procedure being built.
109 -- Decls is the list of declarations to be enhanced.
110 -- Ent is the entity for the original entry body.
112 function Build_Accept_Body (Astat : Node_Id) return Node_Id;
113 -- Transform accept statement into a block with added exception handler.
114 -- Used both for simple accept statements and for accept alternatives in
115 -- select statements. Astat is the accept statement.
117 function Build_Barrier_Function
118 (N : Node_Id;
119 Ent : Entity_Id;
120 Pid : Node_Id) return Node_Id;
121 -- Build the function body returning the value of the barrier expression
122 -- for the specified entry body.
124 function Build_Barrier_Function_Specification
125 (Loc : Source_Ptr;
126 Def_Id : Entity_Id) return Node_Id;
127 -- Build a specification for a function implementing the protected entry
128 -- barrier of the specified entry body.
130 procedure Build_Contract_Wrapper (E : Entity_Id; Decl : Node_Id);
131 -- Build the body of a wrapper procedure for an entry or entry family that
132 -- has contract cases, preconditions, or postconditions. The body gathers
133 -- the executable contract items and expands them in the usual way, and
134 -- performs the entry call itself. This way preconditions are evaluated
135 -- before the call is queued. E is the entry in question, and Decl is the
136 -- enclosing synchronized type declaration at whose freeze point the
137 -- generated body is analyzed.
139 function Build_Corresponding_Record
140 (N : Node_Id;
141 Ctyp : Node_Id;
142 Loc : Source_Ptr) return Node_Id;
143 -- Common to tasks and protected types. Copy discriminant specifications,
144 -- build record declaration. N is the type declaration, Ctyp is the
145 -- concurrent entity (task type or protected type).
147 function Build_Dispatching_Tag_Check
148 (K : Entity_Id;
149 N : Node_Id) return Node_Id;
150 -- Utility to create the tree to check whether the dispatching call in
151 -- a timed entry call, a conditional entry call, or an asynchronous
152 -- transfer of control is a call to a primitive of a non-synchronized type.
153 -- K is the temporary that holds the tagged kind of the target object, and
154 -- N is the enclosing construct.
156 function Build_Entry_Count_Expression
157 (Concurrent_Type : Node_Id;
158 Component_List : List_Id;
159 Loc : Source_Ptr) return Node_Id;
160 -- Compute number of entries for concurrent object. This is a count of
161 -- simple entries, followed by an expression that computes the length
162 -- of the range of each entry family. A single array with that size is
163 -- allocated for each concurrent object of the type.
165 function Build_Find_Body_Index (Typ : Entity_Id) return Node_Id;
166 -- Build the function that translates the entry index in the call
167 -- (which depends on the size of entry families) into an index into the
168 -- Entry_Bodies_Array, to determine the body and barrier function used
169 -- in a protected entry call. A pointer to this function appears in every
170 -- protected object.
172 function Build_Find_Body_Index_Spec (Typ : Entity_Id) return Node_Id;
173 -- Build subprogram declaration for previous one
175 function Build_Lock_Free_Protected_Subprogram_Body
176 (N : Node_Id;
177 Prot_Typ : Node_Id;
178 Unprot_Spec : Node_Id) return Node_Id;
179 -- N denotes a subprogram body of protected type Prot_Typ. Unprot_Spec is
180 -- the subprogram specification of the unprotected version of N. Transform
181 -- N such that it invokes the unprotected version of the body.
183 function Build_Lock_Free_Unprotected_Subprogram_Body
184 (N : Node_Id;
185 Prot_Typ : Node_Id) return Node_Id;
186 -- N denotes a subprogram body of protected type Prot_Typ. Build a version
187 -- of N where the original statements of N are synchronized through atomic
188 -- actions such as compare and exchange. Prior to invoking this routine, it
189 -- has been established that N can be implemented in a lock-free fashion.
191 function Build_Parameter_Block
192 (Loc : Source_Ptr;
193 Actuals : List_Id;
194 Formals : List_Id;
195 Decls : List_Id) return Entity_Id;
196 -- Generate an access type for each actual parameter in the list Actuals.
197 -- Create an encapsulating record that contains all the actuals and return
198 -- its type. Generate:
199 -- type Ann1 is access all <actual1-type>
200 -- ...
201 -- type AnnN is access all <actualN-type>
202 -- type Pnn is record
203 -- <formal1> : Ann1;
204 -- ...
205 -- <formalN> : AnnN;
206 -- end record;
208 function Build_Protected_Entry
209 (N : Node_Id;
210 Ent : Entity_Id;
211 Pid : Node_Id) return Node_Id;
212 -- Build the procedure implementing the statement sequence of the specified
213 -- entry body.
215 function Build_Protected_Entry_Specification
216 (Loc : Source_Ptr;
217 Def_Id : Entity_Id;
218 Ent_Id : Entity_Id) return Node_Id;
219 -- Build a specification for the procedure implementing the statements of
220 -- the specified entry body. Add attributes associating it with the entry
221 -- defining identifier Ent_Id.
223 function Build_Protected_Spec
224 (N : Node_Id;
225 Obj_Type : Entity_Id;
226 Ident : Entity_Id;
227 Unprotected : Boolean := False) return List_Id;
228 -- Utility shared by Build_Protected_Sub_Spec and Expand_Access_Protected_
229 -- Subprogram_Type. Builds signature of protected subprogram, adding the
230 -- formal that corresponds to the object itself. For an access to protected
231 -- subprogram, there is no object type to specify, so the parameter has
232 -- type Address and mode In. An indirect call through such a pointer will
233 -- convert the address to a reference to the actual object. The object is
234 -- a limited record and therefore a by_reference type.
236 function Build_Protected_Subprogram_Body
237 (N : Node_Id;
238 Pid : Node_Id;
239 N_Op_Spec : Node_Id) return Node_Id;
240 -- This function is used to construct the protected version of a protected
241 -- subprogram. Its statement sequence first defers abort, then locks the
242 -- associated protected object, and then enters a block that contains a
243 -- call to the unprotected version of the subprogram (for details, see
244 -- Build_Unprotected_Subprogram_Body). This block statement requires a
245 -- cleanup handler that unlocks the object in all cases. For details,
246 -- see Exp_Ch7.Expand_Cleanup_Actions.
248 function Build_Renamed_Formal_Declaration
249 (New_F : Entity_Id;
250 Formal : Entity_Id;
251 Comp : Entity_Id;
252 Renamed_Formal : Node_Id) return Node_Id;
253 -- Create a renaming declaration for a formal, within a protected entry
254 -- body or an accept body. The renamed object is a component of the
255 -- parameter block that is a parameter in the entry call.
257 -- In Ada 2012, if the formal is an incomplete tagged type, the renaming
258 -- does not dereference the corresponding component to prevent an illegal
259 -- use of the incomplete type (AI05-0151).
261 function Build_Selected_Name
262 (Prefix : Entity_Id;
263 Selector : Entity_Id;
264 Append_Char : Character := ' ') return Name_Id;
265 -- Build a name in the form of Prefix__Selector, with an optional character
266 -- appended. This is used for internal subprograms generated for operations
267 -- of protected types, including barrier functions. For the subprograms
268 -- generated for entry bodies and entry barriers, the generated name
269 -- includes a sequence number that makes names unique in the presence of
270 -- entry overloading. This is necessary because entry body procedures and
271 -- barrier functions all have the same signature.
273 procedure Build_Simple_Entry_Call
274 (N : Node_Id;
275 Concval : Node_Id;
276 Ename : Node_Id;
277 Index : Node_Id);
278 -- Some comments here would be useful ???
280 function Build_Task_Proc_Specification (T : Entity_Id) return Node_Id;
281 -- This routine constructs a specification for the procedure that we will
282 -- build for the task body for task type T. The spec has the form:
284 -- procedure tnameB (_Task : access tnameV);
286 -- where name is the character name taken from the task type entity that
287 -- is passed as the argument to the procedure, and tnameV is the task
288 -- value type that is associated with the task type.
290 function Build_Unprotected_Subprogram_Body
291 (N : Node_Id;
292 Pid : Node_Id) return Node_Id;
293 -- This routine constructs the unprotected version of a protected
294 -- subprogram body, which is contains all of the code in the original,
295 -- unexpanded body. This is the version of the protected subprogram that is
296 -- called from all protected operations on the same object, including the
297 -- protected version of the same subprogram.
299 procedure Build_Wrapper_Bodies
300 (Loc : Source_Ptr;
301 Typ : Entity_Id;
302 N : Node_Id);
303 -- Ada 2005 (AI-345): Typ is either a concurrent type or the corresponding
304 -- record of a concurrent type. N is the insertion node where all bodies
305 -- will be placed. This routine builds the bodies of the subprograms which
306 -- serve as an indirection mechanism to overriding primitives of concurrent
307 -- types, entries and protected procedures. Any new body is analyzed.
309 procedure Build_Wrapper_Specs
310 (Loc : Source_Ptr;
311 Typ : Entity_Id;
312 N : in out Node_Id);
313 -- Ada 2005 (AI-345): Typ is either a concurrent type or the corresponding
314 -- record of a concurrent type. N is the insertion node where all specs
315 -- will be placed. This routine builds the specs of the subprograms which
316 -- serve as an indirection mechanism to overriding primitives of concurrent
317 -- types, entries and protected procedures. Any new spec is analyzed.
319 procedure Collect_Entry_Families
320 (Loc : Source_Ptr;
321 Cdecls : List_Id;
322 Current_Node : in out Node_Id;
323 Conctyp : Entity_Id);
324 -- For each entry family in a concurrent type, create an anonymous array
325 -- type of the right size, and add a component to the corresponding_record.
327 function Concurrent_Object
328 (Spec_Id : Entity_Id;
329 Conc_Typ : Entity_Id) return Entity_Id;
330 -- Given a subprogram entity Spec_Id and concurrent type Conc_Typ, return
331 -- the entity associated with the concurrent object in the Protected_Body_
332 -- Subprogram or the Task_Body_Procedure of Spec_Id. The returned entity
333 -- denotes formal parameter _O, _object or _task.
335 function Copy_Result_Type (Res : Node_Id) return Node_Id;
336 -- Copy the result type of a function specification, when building the
337 -- internal operation corresponding to a protected function, or when
338 -- expanding an access to protected function. If the result is an anonymous
339 -- access to subprogram itself, we need to create a new signature with the
340 -- same parameter names and the same resolved types, but with new entities
341 -- for the formals.
343 function Create_Secondary_Stack_For_Task (T : Node_Id) return Boolean;
344 -- Return whether a secondary stack for the task T should be created by the
345 -- expander. The secondary stack for a task will be created by the expander
346 -- if the size of the stack has been specified by the Secondary_Stack_Size
347 -- representation aspect and either the No_Implicit_Heap_Allocations or
348 -- No_Implicit_Task_Allocations restrictions are in effect and the
349 -- No_Secondary_Stack restriction is not.
351 procedure Debug_Private_Data_Declarations (Decls : List_Id);
352 -- Decls is a list which may contain the declarations created by Install_
353 -- Private_Data_Declarations. All generated entities are marked as needing
354 -- debug info and debug nodes are manually generation where necessary. This
355 -- step of the expansion must to be done after private data has been moved
356 -- to its final resting scope to ensure proper visibility of debug objects.
358 procedure Ensure_Statement_Present (Loc : Source_Ptr; Alt : Node_Id);
359 -- If control flow optimizations are suppressed, and Alt is an accept,
360 -- delay, or entry call alternative with no trailing statements, insert
361 -- a null trailing statement with the given Loc (which is the sloc of
362 -- the accept, delay, or entry call statement). There might not be any
363 -- generated code for the accept, delay, or entry call itself (the effect
364 -- of these statements is part of the general processsing done for the
365 -- enclosing selective accept, timed entry call, or asynchronous select),
366 -- and the null statement is there to carry the sloc of that statement to
367 -- the back-end for trace-based coverage analysis purposes.
369 procedure Extract_Dispatching_Call
370 (N : Node_Id;
371 Call_Ent : out Entity_Id;
372 Object : out Entity_Id;
373 Actuals : out List_Id;
374 Formals : out List_Id);
375 -- Given a dispatching call, extract the entity of the name of the call,
376 -- its actual dispatching object, its actual parameters and the formal
377 -- parameters of the overridden interface-level version. If the type of
378 -- the dispatching object is an access type then an explicit dereference
379 -- is returned in Object.
381 procedure Extract_Entry
382 (N : Node_Id;
383 Concval : out Node_Id;
384 Ename : out Node_Id;
385 Index : out Node_Id);
386 -- Given an entry call, returns the associated concurrent object, the entry
387 -- name, and the entry family index.
389 function Family_Offset
390 (Loc : Source_Ptr;
391 Hi : Node_Id;
392 Lo : Node_Id;
393 Ttyp : Entity_Id;
394 Cap : Boolean) return Node_Id;
395 -- Compute (Hi - Lo) for two entry family indexes. Hi is the index in an
396 -- accept statement, or the upper bound in the discrete subtype of an entry
397 -- declaration. Lo is the corresponding lower bound. Ttyp is the concurrent
398 -- type of the entry. If Cap is true, the result is capped according to
399 -- Entry_Family_Bound.
401 function Family_Size
402 (Loc : Source_Ptr;
403 Hi : Node_Id;
404 Lo : Node_Id;
405 Ttyp : Entity_Id;
406 Cap : Boolean) return Node_Id;
407 -- Compute (Hi - Lo) + 1 Max 0, to determine the number of entries in a
408 -- family, and handle properly the superflat case. This is equivalent to
409 -- the use of 'Length on the index type, but must use Family_Offset to
410 -- handle properly the case of bounds that depend on discriminants. If
411 -- Cap is true, the result is capped according to Entry_Family_Bound.
413 procedure Find_Enclosing_Context
414 (N : Node_Id;
415 Context : out Node_Id;
416 Context_Id : out Entity_Id;
417 Context_Decls : out List_Id);
418 -- Subsidiary routine to procedures Build_Activation_Chain_Entity and
419 -- Build_Master_Entity. Given an arbitrary node in the tree, find the
420 -- nearest enclosing body, block, package, or return statement and return
421 -- its constituents. Context is the enclosing construct, Context_Id is
422 -- the scope of Context_Id and Context_Decls is the declarative list of
423 -- Context.
425 function Index_Object (Spec_Id : Entity_Id) return Entity_Id;
426 -- Given a subprogram identifier, return the entity which is associated
427 -- with the protection entry index in the Protected_Body_Subprogram or
428 -- the Task_Body_Procedure of Spec_Id. The returned entity denotes formal
429 -- parameter _E.
431 function Is_Potentially_Large_Family
432 (Base_Index : Entity_Id;
433 Conctyp : Entity_Id;
434 Lo : Node_Id;
435 Hi : Node_Id) return Boolean;
437 function Is_Private_Primitive_Subprogram (Id : Entity_Id) return Boolean;
438 -- Determine whether Id is a function or a procedure and is marked as a
439 -- private primitive.
441 function Null_Statements (Stats : List_Id) return Boolean;
442 -- Used to check DO-END sequence. Checks for equivalent of DO NULL; END.
443 -- Allows labels, and pragma Warnings/Unreferenced in the sequence as well
444 -- to still count as null. Returns True for a null sequence. The argument
445 -- is the list of statements from the DO-END sequence.
447 function Parameter_Block_Pack
448 (Loc : Source_Ptr;
449 Blk_Typ : Entity_Id;
450 Actuals : List_Id;
451 Formals : List_Id;
452 Decls : List_Id;
453 Stmts : List_Id) return Entity_Id;
454 -- Set the components of the generated parameter block with the values
455 -- of the actual parameters. Generate aliased temporaries to capture the
456 -- values for types that are passed by copy. Otherwise generate a reference
457 -- to the actual's value. Return the address of the aggregate block.
458 -- Generate:
459 -- Jnn1 : alias <formal-type1>;
460 -- Jnn1 := <actual1>;
461 -- ...
462 -- P : Blk_Typ := (
463 -- Jnn1'unchecked_access;
464 -- <actual2>'reference;
465 -- ...);
467 function Parameter_Block_Unpack
468 (Loc : Source_Ptr;
469 P : Entity_Id;
470 Actuals : List_Id;
471 Formals : List_Id) return List_Id;
472 -- Retrieve the values of the components from the parameter block and
473 -- assign then to the original actual parameters. Generate:
474 -- <actual1> := P.<formal1>;
475 -- ...
476 -- <actualN> := P.<formalN>;
478 function Trivial_Accept_OK return Boolean;
479 -- If there is no DO-END block for an accept, or if the DO-END block has
480 -- only null statements, then it is possible to do the Rendezvous with much
481 -- less overhead using the Accept_Trivial routine in the run-time library.
482 -- However, this is not always a valid optimization. Whether it is valid or
483 -- not depends on the Task_Dispatching_Policy. The issue is whether a full
484 -- rescheduling action is required or not. In FIFO_Within_Priorities, such
485 -- a rescheduling is required, so this optimization is not allowed. This
486 -- function returns True if the optimization is permitted.
488 -----------------------------
489 -- Actual_Index_Expression --
490 -----------------------------
492 function Actual_Index_Expression
493 (Sloc : Source_Ptr;
494 Ent : Entity_Id;
495 Index : Node_Id;
496 Tsk : Entity_Id) return Node_Id
498 Ttyp : constant Entity_Id := Etype (Tsk);
499 Expr : Node_Id;
500 Num : Node_Id;
501 Lo : Node_Id;
502 Hi : Node_Id;
503 Prev : Entity_Id;
504 S : Node_Id;
506 function Actual_Family_Offset (Hi, Lo : Node_Id) return Node_Id;
507 -- Compute difference between bounds of entry family
509 --------------------------
510 -- Actual_Family_Offset --
511 --------------------------
513 function Actual_Family_Offset (Hi, Lo : Node_Id) return Node_Id is
515 function Actual_Discriminant_Ref (Bound : Node_Id) return Node_Id;
516 -- Replace a reference to a discriminant with a selected component
517 -- denoting the discriminant of the target task.
519 -----------------------------
520 -- Actual_Discriminant_Ref --
521 -----------------------------
523 function Actual_Discriminant_Ref (Bound : Node_Id) return Node_Id is
524 Typ : constant Entity_Id := Etype (Bound);
525 B : Node_Id;
527 begin
528 if not Is_Entity_Name (Bound)
529 or else Ekind (Entity (Bound)) /= E_Discriminant
530 then
531 if Nkind (Bound) = N_Attribute_Reference then
532 return Bound;
533 else
534 B := New_Copy_Tree (Bound);
535 end if;
537 else
538 B :=
539 Make_Selected_Component (Sloc,
540 Prefix => New_Copy_Tree (Tsk),
541 Selector_Name => New_Occurrence_Of (Entity (Bound), Sloc));
543 Analyze_And_Resolve (B, Typ);
544 end if;
546 return
547 Make_Attribute_Reference (Sloc,
548 Attribute_Name => Name_Pos,
549 Prefix => New_Occurrence_Of (Etype (Bound), Sloc),
550 Expressions => New_List (B));
551 end Actual_Discriminant_Ref;
553 -- Start of processing for Actual_Family_Offset
555 begin
556 return
557 Make_Op_Subtract (Sloc,
558 Left_Opnd => Actual_Discriminant_Ref (Hi),
559 Right_Opnd => Actual_Discriminant_Ref (Lo));
560 end Actual_Family_Offset;
562 -- Start of processing for Actual_Index_Expression
564 begin
565 -- The queues of entries and entry families appear in textual order in
566 -- the associated record. The entry index is computed as the sum of the
567 -- number of queues for all entries that precede the designated one, to
568 -- which is added the index expression, if this expression denotes a
569 -- member of a family.
571 -- The following is a place holder for the count of simple entries
573 Num := Make_Integer_Literal (Sloc, 1);
575 -- We construct an expression which is a series of addition operations.
576 -- See comments in Entry_Index_Expression, which is identical in
577 -- structure.
579 if Present (Index) then
580 S := Etype (Discrete_Subtype_Definition (Declaration_Node (Ent)));
582 Expr :=
583 Make_Op_Add (Sloc,
584 Left_Opnd => Num,
585 Right_Opnd =>
586 Actual_Family_Offset (
587 Make_Attribute_Reference (Sloc,
588 Attribute_Name => Name_Pos,
589 Prefix => New_Occurrence_Of (Base_Type (S), Sloc),
590 Expressions => New_List (Relocate_Node (Index))),
591 Type_Low_Bound (S)));
592 else
593 Expr := Num;
594 end if;
596 -- Now add lengths of preceding entries and entry families
598 Prev := First_Entity (Ttyp);
599 while Chars (Prev) /= Chars (Ent)
600 or else (Ekind (Prev) /= Ekind (Ent))
601 or else not Sem_Ch6.Type_Conformant (Ent, Prev)
602 loop
603 if Ekind (Prev) = E_Entry then
604 Set_Intval (Num, Intval (Num) + 1);
606 elsif Ekind (Prev) = E_Entry_Family then
607 S :=
608 Etype (Discrete_Subtype_Definition (Declaration_Node (Prev)));
610 -- The need for the following full view retrieval stems from this
611 -- complex case of nested generics and tasking:
613 -- generic
614 -- type Formal_Index is range <>;
615 -- ...
616 -- package Outer is
617 -- type Index is private;
618 -- generic
619 -- ...
620 -- package Inner is
621 -- procedure P;
622 -- end Inner;
623 -- private
624 -- type Index is new Formal_Index range 1 .. 10;
625 -- end Outer;
627 -- package body Outer is
628 -- task type T is
629 -- entry Fam (Index); -- (2)
630 -- entry E;
631 -- end T;
632 -- package body Inner is -- (3)
633 -- procedure P is
634 -- begin
635 -- T.E; -- (1)
636 -- end P;
637 -- end Inner;
638 -- ...
640 -- We are currently building the index expression for the entry
641 -- call "T.E" (1). Part of the expansion must mention the range
642 -- of the discrete type "Index" (2) of entry family "Fam".
644 -- However only the private view of type "Index" is available to
645 -- the inner generic (3) because there was no prior mention of
646 -- the type inside "Inner". This visibility requirement is
647 -- implicit and cannot be detected during the construction of
648 -- the generic trees and needs special handling.
650 if In_Instance_Body
651 and then Is_Private_Type (S)
652 and then Present (Full_View (S))
653 then
654 S := Full_View (S);
655 end if;
657 Lo := Type_Low_Bound (S);
658 Hi := Type_High_Bound (S);
660 Expr :=
661 Make_Op_Add (Sloc,
662 Left_Opnd => Expr,
663 Right_Opnd =>
664 Make_Op_Add (Sloc,
665 Left_Opnd => Actual_Family_Offset (Hi, Lo),
666 Right_Opnd => Make_Integer_Literal (Sloc, 1)));
668 -- Other components are anonymous types to be ignored
670 else
671 null;
672 end if;
674 Next_Entity (Prev);
675 end loop;
677 return Expr;
678 end Actual_Index_Expression;
680 --------------------------
681 -- Add_Formal_Renamings --
682 --------------------------
684 procedure Add_Formal_Renamings
685 (Spec : Node_Id;
686 Decls : List_Id;
687 Ent : Entity_Id;
688 Loc : Source_Ptr)
690 Ptr : constant Entity_Id :=
691 Defining_Identifier
692 (Next (First (Parameter_Specifications (Spec))));
693 -- The name of the formal that holds the address of the parameter block
694 -- for the call.
696 Comp : Entity_Id;
697 Decl : Node_Id;
698 Formal : Entity_Id;
699 New_F : Entity_Id;
700 Renamed_Formal : Node_Id;
702 begin
703 Formal := First_Formal (Ent);
704 while Present (Formal) loop
705 Comp := Entry_Component (Formal);
706 New_F :=
707 Make_Defining_Identifier (Sloc (Formal),
708 Chars => Chars (Formal));
709 Set_Etype (New_F, Etype (Formal));
710 Set_Scope (New_F, Ent);
712 -- Now we set debug info needed on New_F even though it does not come
713 -- from source, so that the debugger will get the right information
714 -- for these generated names.
716 Set_Debug_Info_Needed (New_F);
718 if Ekind (Formal) = E_In_Parameter then
719 Set_Ekind (New_F, E_Constant);
720 else
721 Set_Ekind (New_F, E_Variable);
722 Set_Extra_Constrained (New_F, Extra_Constrained (Formal));
723 end if;
725 Set_Actual_Subtype (New_F, Actual_Subtype (Formal));
727 Renamed_Formal :=
728 Make_Selected_Component (Loc,
729 Prefix =>
730 Unchecked_Convert_To (Entry_Parameters_Type (Ent),
731 Make_Identifier (Loc, Chars (Ptr))),
732 Selector_Name => New_Occurrence_Of (Comp, Loc));
734 Decl :=
735 Build_Renamed_Formal_Declaration
736 (New_F, Formal, Comp, Renamed_Formal);
738 Append (Decl, Decls);
739 Set_Renamed_Object (Formal, New_F);
740 Next_Formal (Formal);
741 end loop;
742 end Add_Formal_Renamings;
744 ------------------------
745 -- Add_Object_Pointer --
746 ------------------------
748 procedure Add_Object_Pointer
749 (Loc : Source_Ptr;
750 Conc_Typ : Entity_Id;
751 Decls : List_Id)
753 Rec_Typ : constant Entity_Id := Corresponding_Record_Type (Conc_Typ);
754 Decl : Node_Id;
755 Obj_Ptr : Node_Id;
757 begin
758 -- Create the renaming declaration for the Protection object of a
759 -- protected type. _Object is used by Complete_Entry_Body.
760 -- ??? An attempt to make this a renaming was unsuccessful.
762 -- Build the entity for the access type
764 Obj_Ptr :=
765 Make_Defining_Identifier (Loc,
766 New_External_Name (Chars (Rec_Typ), 'P'));
768 -- Generate:
769 -- _object : poVP := poVP!O;
771 Decl :=
772 Make_Object_Declaration (Loc,
773 Defining_Identifier => Make_Defining_Identifier (Loc, Name_uObject),
774 Object_Definition => New_Occurrence_Of (Obj_Ptr, Loc),
775 Expression =>
776 Unchecked_Convert_To (Obj_Ptr, Make_Identifier (Loc, Name_uO)));
777 Set_Debug_Info_Needed (Defining_Identifier (Decl));
778 Prepend_To (Decls, Decl);
780 -- Generate:
781 -- type poVP is access poV;
783 Decl :=
784 Make_Full_Type_Declaration (Loc,
785 Defining_Identifier =>
786 Obj_Ptr,
787 Type_Definition =>
788 Make_Access_To_Object_Definition (Loc,
789 Subtype_Indication =>
790 New_Occurrence_Of (Rec_Typ, Loc)));
791 Set_Debug_Info_Needed (Defining_Identifier (Decl));
792 Prepend_To (Decls, Decl);
793 end Add_Object_Pointer;
795 -----------------------
796 -- Build_Accept_Body --
797 -----------------------
799 function Build_Accept_Body (Astat : Node_Id) return Node_Id is
800 Loc : constant Source_Ptr := Sloc (Astat);
801 Stats : constant Node_Id := Handled_Statement_Sequence (Astat);
802 New_S : Node_Id;
803 Hand : Node_Id;
804 Call : Node_Id;
805 Ohandle : Node_Id;
807 begin
808 -- At the end of the statement sequence, Complete_Rendezvous is called.
809 -- A label skipping the Complete_Rendezvous, and all other accept
810 -- processing, has already been added for the expansion of requeue
811 -- statements. The Sloc is copied from the last statement since it
812 -- is really part of this last statement.
814 Call :=
815 Build_Runtime_Call
816 (Sloc (Last (Statements (Stats))), RE_Complete_Rendezvous);
817 Insert_Before (Last (Statements (Stats)), Call);
818 Analyze (Call);
820 -- If exception handlers are present, then append Complete_Rendezvous
821 -- calls to the handlers, and construct the required outer block. As
822 -- above, the Sloc is copied from the last statement in the sequence.
824 if Present (Exception_Handlers (Stats)) then
825 Hand := First (Exception_Handlers (Stats));
826 while Present (Hand) loop
827 Call :=
828 Build_Runtime_Call
829 (Sloc (Last (Statements (Hand))), RE_Complete_Rendezvous);
830 Append (Call, Statements (Hand));
831 Analyze (Call);
832 Next (Hand);
833 end loop;
835 New_S :=
836 Make_Handled_Sequence_Of_Statements (Loc,
837 Statements => New_List (
838 Make_Block_Statement (Loc,
839 Handled_Statement_Sequence => Stats)));
841 else
842 New_S := Stats;
843 end if;
845 -- At this stage we know that the new statement sequence does
846 -- not have an exception handler part, so we supply one to call
847 -- Exceptional_Complete_Rendezvous. This handler is
849 -- when all others =>
850 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
852 -- We handle Abort_Signal to make sure that we properly catch the abort
853 -- case and wake up the caller.
855 Ohandle := Make_Others_Choice (Loc);
856 Set_All_Others (Ohandle);
858 Set_Exception_Handlers (New_S,
859 New_List (
860 Make_Implicit_Exception_Handler (Loc,
861 Exception_Choices => New_List (Ohandle),
863 Statements => New_List (
864 Make_Procedure_Call_Statement (Sloc (Stats),
865 Name => New_Occurrence_Of (
866 RTE (RE_Exceptional_Complete_Rendezvous), Sloc (Stats)),
867 Parameter_Associations => New_List (
868 Make_Function_Call (Sloc (Stats),
869 Name =>
870 New_Occurrence_Of
871 (RTE (RE_Get_GNAT_Exception), Sloc (Stats)))))))));
873 Set_Parent (New_S, Astat); -- temp parent for Analyze call
874 Analyze_Exception_Handlers (Exception_Handlers (New_S));
875 Expand_Exception_Handlers (New_S);
877 -- Exceptional_Complete_Rendezvous must be called with abort still
878 -- deferred, which is the case for a "when all others" handler.
880 return New_S;
881 end Build_Accept_Body;
883 -----------------------------------
884 -- Build_Activation_Chain_Entity --
885 -----------------------------------
887 procedure Build_Activation_Chain_Entity (N : Node_Id) is
888 function Has_Activation_Chain (Stmt : Node_Id) return Boolean;
889 -- Determine whether an extended return statement has activation chain
891 --------------------------
892 -- Has_Activation_Chain --
893 --------------------------
895 function Has_Activation_Chain (Stmt : Node_Id) return Boolean is
896 Decl : Node_Id;
898 begin
899 Decl := First (Return_Object_Declarations (Stmt));
900 while Present (Decl) loop
901 if Nkind (Decl) = N_Object_Declaration
902 and then Chars (Defining_Identifier (Decl)) = Name_uChain
903 then
904 return True;
905 end if;
907 Next (Decl);
908 end loop;
910 return False;
911 end Has_Activation_Chain;
913 -- Local variables
915 Context : Node_Id;
916 Context_Id : Entity_Id;
917 Decls : List_Id;
919 -- Start of processing for Build_Activation_Chain_Entity
921 begin
922 -- Activation chain is never used for sequential elaboration policy, see
923 -- comment for Create_Restricted_Task_Sequential in s-tarest.ads).
925 if Partition_Elaboration_Policy = 'S' then
926 return;
927 end if;
929 Find_Enclosing_Context (N, Context, Context_Id, Decls);
931 -- If activation chain entity has not been declared already, create one
933 if Nkind (Context) = N_Extended_Return_Statement
934 or else No (Activation_Chain_Entity (Context))
935 then
936 -- Since extended return statements do not store the entity of the
937 -- chain, examine the return object declarations to avoid creating
938 -- a duplicate.
940 if Nkind (Context) = N_Extended_Return_Statement
941 and then Has_Activation_Chain (Context)
942 then
943 return;
944 end if;
946 declare
947 Loc : constant Source_Ptr := Sloc (Context);
948 Chain : Entity_Id;
949 Decl : Node_Id;
951 begin
952 Chain := Make_Defining_Identifier (Sloc (N), Name_uChain);
954 -- Note: An extended return statement is not really a task
955 -- activator, but it does have an activation chain on which to
956 -- store the tasks temporarily. On successful return, the tasks
957 -- on this chain are moved to the chain passed in by the caller.
958 -- We do not build an Activation_Chain_Entity for an extended
959 -- return statement, because we do not want to build a call to
960 -- Activate_Tasks. Task activation is the responsibility of the
961 -- caller.
963 if Nkind (Context) /= N_Extended_Return_Statement then
964 Set_Activation_Chain_Entity (Context, Chain);
965 end if;
967 Decl :=
968 Make_Object_Declaration (Loc,
969 Defining_Identifier => Chain,
970 Aliased_Present => True,
971 Object_Definition =>
972 New_Occurrence_Of (RTE (RE_Activation_Chain), Loc));
974 Prepend_To (Decls, Decl);
976 -- Ensure that _chain appears in the proper scope of the context
978 if Context_Id /= Current_Scope then
979 Push_Scope (Context_Id);
980 Analyze (Decl);
981 Pop_Scope;
982 else
983 Analyze (Decl);
984 end if;
985 end;
986 end if;
987 end Build_Activation_Chain_Entity;
989 ----------------------------
990 -- Build_Barrier_Function --
991 ----------------------------
993 function Build_Barrier_Function
994 (N : Node_Id;
995 Ent : Entity_Id;
996 Pid : Node_Id) return Node_Id
998 Ent_Formals : constant Node_Id := Entry_Body_Formal_Part (N);
999 Cond : constant Node_Id := Condition (Ent_Formals);
1000 Loc : constant Source_Ptr := Sloc (Cond);
1001 Func_Id : constant Entity_Id := Barrier_Function (Ent);
1002 Op_Decls : constant List_Id := New_List;
1003 Stmt : Node_Id;
1004 Func_Body : Node_Id;
1006 begin
1007 -- Add a declaration for the Protection object, renaming declarations
1008 -- for the discriminals and privals and finally a declaration for the
1009 -- entry family index (if applicable).
1011 Install_Private_Data_Declarations (Sloc (N),
1012 Spec_Id => Func_Id,
1013 Conc_Typ => Pid,
1014 Body_Nod => N,
1015 Decls => Op_Decls,
1016 Barrier => True,
1017 Family => Ekind (Ent) = E_Entry_Family);
1019 -- If compiling with -fpreserve-control-flow, make sure we insert an
1020 -- IF statement so that the back-end knows to generate a conditional
1021 -- branch instruction, even if the condition is just the name of a
1022 -- boolean object. Note that Expand_N_If_Statement knows to preserve
1023 -- such redundant IF statements under -fpreserve-control-flow
1024 -- (whether coming from this routine, or directly from source).
1026 if Opt.Suppress_Control_Flow_Optimizations then
1027 Stmt :=
1028 Make_Implicit_If_Statement (Cond,
1029 Condition => Cond,
1030 Then_Statements => New_List (
1031 Make_Simple_Return_Statement (Loc,
1032 New_Occurrence_Of (Standard_True, Loc))),
1034 Else_Statements => New_List (
1035 Make_Simple_Return_Statement (Loc,
1036 New_Occurrence_Of (Standard_False, Loc))));
1038 else
1039 Stmt := Make_Simple_Return_Statement (Loc, Cond);
1040 end if;
1042 -- Note: the condition in the barrier function needs to be properly
1043 -- processed for the C/Fortran boolean possibility, but this happens
1044 -- automatically since the return statement does this normalization.
1046 Func_Body :=
1047 Make_Subprogram_Body (Loc,
1048 Specification =>
1049 Build_Barrier_Function_Specification (Loc,
1050 Make_Defining_Identifier (Loc, Chars (Func_Id))),
1051 Declarations => Op_Decls,
1052 Handled_Statement_Sequence =>
1053 Make_Handled_Sequence_Of_Statements (Loc,
1054 Statements => New_List (Stmt)));
1055 Set_Is_Entry_Barrier_Function (Func_Body);
1057 return Func_Body;
1058 end Build_Barrier_Function;
1060 ------------------------------------------
1061 -- Build_Barrier_Function_Specification --
1062 ------------------------------------------
1064 function Build_Barrier_Function_Specification
1065 (Loc : Source_Ptr;
1066 Def_Id : Entity_Id) return Node_Id
1068 begin
1069 Set_Debug_Info_Needed (Def_Id);
1071 return
1072 Make_Function_Specification (Loc,
1073 Defining_Unit_Name => Def_Id,
1074 Parameter_Specifications => New_List (
1075 Make_Parameter_Specification (Loc,
1076 Defining_Identifier =>
1077 Make_Defining_Identifier (Loc, Name_uO),
1078 Parameter_Type =>
1079 New_Occurrence_Of (RTE (RE_Address), Loc)),
1081 Make_Parameter_Specification (Loc,
1082 Defining_Identifier =>
1083 Make_Defining_Identifier (Loc, Name_uE),
1084 Parameter_Type =>
1085 New_Occurrence_Of (RTE (RE_Protected_Entry_Index), Loc))),
1087 Result_Definition =>
1088 New_Occurrence_Of (Standard_Boolean, Loc));
1089 end Build_Barrier_Function_Specification;
1091 --------------------------
1092 -- Build_Call_With_Task --
1093 --------------------------
1095 function Build_Call_With_Task
1096 (N : Node_Id;
1097 E : Entity_Id) return Node_Id
1099 Loc : constant Source_Ptr := Sloc (N);
1100 begin
1101 return
1102 Make_Function_Call (Loc,
1103 Name => New_Occurrence_Of (E, Loc),
1104 Parameter_Associations => New_List (Concurrent_Ref (N)));
1105 end Build_Call_With_Task;
1107 -----------------------------
1108 -- Build_Class_Wide_Master --
1109 -----------------------------
1111 procedure Build_Class_Wide_Master (Typ : Entity_Id) is
1112 Loc : constant Source_Ptr := Sloc (Typ);
1113 Master_Decl : Node_Id;
1114 Master_Id : Entity_Id;
1115 Master_Scope : Entity_Id;
1116 Name_Id : Node_Id;
1117 Related_Node : Node_Id;
1118 Ren_Decl : Node_Id;
1120 begin
1121 -- Nothing to do if there is no task hierarchy
1123 if Restriction_Active (No_Task_Hierarchy) then
1124 return;
1125 end if;
1127 -- Find the declaration that created the access type, which is either a
1128 -- type declaration, or an object declaration with an access definition,
1129 -- in which case the type is anonymous.
1131 if Is_Itype (Typ) then
1132 Related_Node := Associated_Node_For_Itype (Typ);
1133 else
1134 Related_Node := Parent (Typ);
1135 end if;
1137 Master_Scope := Find_Master_Scope (Typ);
1139 -- Nothing to do if the master scope already contains a _master entity.
1140 -- The only exception to this is the following scenario:
1142 -- Source_Scope
1143 -- Transient_Scope_1
1144 -- _master
1146 -- Transient_Scope_2
1147 -- use of master
1149 -- In this case the source scope is marked as having the master entity
1150 -- even though the actual declaration appears inside an inner scope. If
1151 -- the second transient scope requires a _master, it cannot use the one
1152 -- already declared because the entity is not visible.
1154 Name_Id := Make_Identifier (Loc, Name_uMaster);
1155 Master_Decl := Empty;
1157 if not Has_Master_Entity (Master_Scope)
1158 or else No (Current_Entity_In_Scope (Name_Id))
1159 then
1160 begin
1161 Set_Has_Master_Entity (Master_Scope);
1163 -- Generate:
1164 -- _master : constant Integer := Current_Master.all;
1166 Master_Decl :=
1167 Make_Object_Declaration (Loc,
1168 Defining_Identifier =>
1169 Make_Defining_Identifier (Loc, Name_uMaster),
1170 Constant_Present => True,
1171 Object_Definition =>
1172 New_Occurrence_Of (Standard_Integer, Loc),
1173 Expression =>
1174 Make_Explicit_Dereference (Loc,
1175 New_Occurrence_Of (RTE (RE_Current_Master), Loc)));
1177 Insert_Action (Find_Hook_Context (Related_Node), Master_Decl);
1178 Analyze (Master_Decl);
1180 -- Mark the containing scope as a task master. Masters associated
1181 -- with return statements are already marked at this stage (see
1182 -- Analyze_Subprogram_Body).
1184 if Ekind (Current_Scope) /= E_Return_Statement then
1185 declare
1186 Par : Node_Id := Related_Node;
1188 begin
1189 while Nkind (Par) /= N_Compilation_Unit loop
1190 Par := Parent (Par);
1192 -- If we fall off the top, we are at the outer level,
1193 -- and the environment task is our effective master,
1194 -- so nothing to mark.
1196 if Nkind_In (Par, N_Block_Statement,
1197 N_Subprogram_Body,
1198 N_Task_Body)
1199 then
1200 Set_Is_Task_Master (Par);
1201 exit;
1202 end if;
1203 end loop;
1204 end;
1205 end if;
1206 end;
1207 end if;
1209 Master_Id :=
1210 Make_Defining_Identifier (Loc, New_External_Name (Chars (Typ), 'M'));
1212 -- Generate:
1213 -- typeMnn renames _master;
1215 Ren_Decl :=
1216 Make_Object_Renaming_Declaration (Loc,
1217 Defining_Identifier => Master_Id,
1218 Subtype_Mark => New_Occurrence_Of (Standard_Integer, Loc),
1219 Name => Name_Id);
1221 -- If the master is declared locally, add the renaming declaration
1222 -- immediately after it, to prevent access-before-elaboration in the
1223 -- back-end.
1225 if Present (Master_Decl) then
1226 Insert_After (Master_Decl, Ren_Decl);
1227 Analyze (Ren_Decl);
1229 else
1230 Insert_Action (Related_Node, Ren_Decl);
1231 end if;
1233 Set_Master_Id (Typ, Master_Id);
1234 end Build_Class_Wide_Master;
1236 ----------------------------
1237 -- Build_Contract_Wrapper --
1238 ----------------------------
1240 procedure Build_Contract_Wrapper (E : Entity_Id; Decl : Node_Id) is
1241 Conc_Typ : constant Entity_Id := Scope (E);
1242 Loc : constant Source_Ptr := Sloc (E);
1244 procedure Add_Discriminant_Renamings
1245 (Obj_Id : Entity_Id;
1246 Decls : List_Id);
1247 -- Add renaming declarations for all discriminants of concurrent type
1248 -- Conc_Typ. Obj_Id is the entity of the wrapper formal parameter which
1249 -- represents the concurrent object.
1251 procedure Add_Matching_Formals
1252 (Formals : List_Id;
1253 Actuals : in out List_Id);
1254 -- Add formal parameters that match those of entry E to list Formals.
1255 -- The routine also adds matching actuals for the new formals to list
1256 -- Actuals.
1258 procedure Transfer_Pragma (Prag : Node_Id; To : in out List_Id);
1259 -- Relocate pragma Prag to list To. The routine creates a new list if
1260 -- To does not exist.
1262 --------------------------------
1263 -- Add_Discriminant_Renamings --
1264 --------------------------------
1266 procedure Add_Discriminant_Renamings
1267 (Obj_Id : Entity_Id;
1268 Decls : List_Id)
1270 Discr : Entity_Id;
1272 begin
1273 -- Inspect the discriminants of the concurrent type and generate a
1274 -- renaming for each one.
1276 if Has_Discriminants (Conc_Typ) then
1277 Discr := First_Discriminant (Conc_Typ);
1278 while Present (Discr) loop
1279 Prepend_To (Decls,
1280 Make_Object_Renaming_Declaration (Loc,
1281 Defining_Identifier =>
1282 Make_Defining_Identifier (Loc, Chars (Discr)),
1283 Subtype_Mark =>
1284 New_Occurrence_Of (Etype (Discr), Loc),
1285 Name =>
1286 Make_Selected_Component (Loc,
1287 Prefix => New_Occurrence_Of (Obj_Id, Loc),
1288 Selector_Name =>
1289 Make_Identifier (Loc, Chars (Discr)))));
1291 Next_Discriminant (Discr);
1292 end loop;
1293 end if;
1294 end Add_Discriminant_Renamings;
1296 --------------------------
1297 -- Add_Matching_Formals --
1298 --------------------------
1300 procedure Add_Matching_Formals
1301 (Formals : List_Id;
1302 Actuals : in out List_Id)
1304 Formal : Entity_Id;
1305 New_Formal : Entity_Id;
1307 begin
1308 -- Inspect the formal parameters of the entry and generate a new
1309 -- matching formal with the same name for the wrapper. A reference
1310 -- to the new formal becomes an actual in the entry call.
1312 Formal := First_Formal (E);
1313 while Present (Formal) loop
1314 New_Formal := Make_Defining_Identifier (Loc, Chars (Formal));
1315 Append_To (Formals,
1316 Make_Parameter_Specification (Loc,
1317 Defining_Identifier => New_Formal,
1318 In_Present => In_Present (Parent (Formal)),
1319 Out_Present => Out_Present (Parent (Formal)),
1320 Parameter_Type =>
1321 New_Occurrence_Of (Etype (Formal), Loc)));
1323 if No (Actuals) then
1324 Actuals := New_List;
1325 end if;
1327 Append_To (Actuals, New_Occurrence_Of (New_Formal, Loc));
1328 Next_Formal (Formal);
1329 end loop;
1330 end Add_Matching_Formals;
1332 ---------------------
1333 -- Transfer_Pragma --
1334 ---------------------
1336 procedure Transfer_Pragma (Prag : Node_Id; To : in out List_Id) is
1337 New_Prag : Node_Id;
1339 begin
1340 if No (To) then
1341 To := New_List;
1342 end if;
1344 New_Prag := Relocate_Node (Prag);
1346 Set_Analyzed (New_Prag, False);
1347 Append (New_Prag, To);
1348 end Transfer_Pragma;
1350 -- Local variables
1352 Items : constant Node_Id := Contract (E);
1353 Actuals : List_Id := No_List;
1354 Call : Node_Id;
1355 Call_Nam : Node_Id;
1356 Decls : List_Id := No_List;
1357 Formals : List_Id;
1358 Has_Pragma : Boolean := False;
1359 Index_Id : Entity_Id;
1360 Obj_Id : Entity_Id;
1361 Prag : Node_Id;
1362 Wrapper_Id : Entity_Id;
1364 -- Start of processing for Build_Contract_Wrapper
1366 begin
1367 -- This routine generates a specialized wrapper for a protected or task
1368 -- entry [family] which implements precondition/postcondition semantics.
1369 -- Preconditions and case guards of contract cases are checked before
1370 -- the protected action or rendezvous takes place. Postconditions and
1371 -- consequences of contract cases are checked after the protected action
1372 -- or rendezvous takes place. The structure of the generated wrapper is
1373 -- as follows:
1375 -- procedure Wrapper
1376 -- (Obj_Id : Conc_Typ; -- concurrent object
1377 -- [Index : Index_Typ;] -- index of entry family
1378 -- [Formal_1 : ...; -- parameters of original entry
1379 -- Formal_N : ...])
1380 -- is
1381 -- [Discr_1 : ... renames Obj_Id.Discr_1; -- discriminant
1382 -- Discr_N : ... renames Obj_Id.Discr_N;] -- renamings
1384 -- <precondition checks>
1385 -- <case guard checks>
1387 -- procedure _Postconditions is
1388 -- begin
1389 -- <postcondition checks>
1390 -- <consequence checks>
1391 -- end _Postconditions;
1393 -- begin
1394 -- Entry_Call (Obj_Id, [Index,] [Formal_1, Formal_N]);
1395 -- _Postconditions;
1396 -- end Wrapper;
1398 -- Create the wrapper only when the entry has at least one executable
1399 -- contract item such as contract cases, precondition or postcondition.
1401 if Present (Items) then
1403 -- Inspect the list of pre/postconditions and transfer all available
1404 -- pragmas to the declarative list of the wrapper.
1406 Prag := Pre_Post_Conditions (Items);
1407 while Present (Prag) loop
1408 if Nam_In (Pragma_Name_Unmapped (Prag),
1409 Name_Postcondition, Name_Precondition)
1410 and then Is_Checked (Prag)
1411 then
1412 Has_Pragma := True;
1413 Transfer_Pragma (Prag, To => Decls);
1414 end if;
1416 Prag := Next_Pragma (Prag);
1417 end loop;
1419 -- Inspect the list of test/contract cases and transfer only contract
1420 -- cases pragmas to the declarative part of the wrapper.
1422 Prag := Contract_Test_Cases (Items);
1423 while Present (Prag) loop
1424 if Pragma_Name (Prag) = Name_Contract_Cases
1425 and then Is_Checked (Prag)
1426 then
1427 Has_Pragma := True;
1428 Transfer_Pragma (Prag, To => Decls);
1429 end if;
1431 Prag := Next_Pragma (Prag);
1432 end loop;
1433 end if;
1435 -- The entry lacks executable contract items and a wrapper is not needed
1437 if not Has_Pragma then
1438 return;
1439 end if;
1441 -- Create the profile of the wrapper. The first formal parameter is the
1442 -- concurrent object.
1444 Obj_Id :=
1445 Make_Defining_Identifier (Loc,
1446 Chars => New_External_Name (Chars (Conc_Typ), 'A'));
1448 Formals := New_List (
1449 Make_Parameter_Specification (Loc,
1450 Defining_Identifier => Obj_Id,
1451 Out_Present => True,
1452 In_Present => True,
1453 Parameter_Type => New_Occurrence_Of (Conc_Typ, Loc)));
1455 -- Construct the call to the original entry. The call will be gradually
1456 -- augmented with an optional entry index and extra parameters.
1458 Call_Nam :=
1459 Make_Selected_Component (Loc,
1460 Prefix => New_Occurrence_Of (Obj_Id, Loc),
1461 Selector_Name => New_Occurrence_Of (E, Loc));
1463 -- When creating a wrapper for an entry family, the second formal is the
1464 -- entry index.
1466 if Ekind (E) = E_Entry_Family then
1467 Index_Id := Make_Defining_Identifier (Loc, Name_I);
1469 Append_To (Formals,
1470 Make_Parameter_Specification (Loc,
1471 Defining_Identifier => Index_Id,
1472 Parameter_Type =>
1473 New_Occurrence_Of (Entry_Index_Type (E), Loc)));
1475 -- The call to the original entry becomes an indexed component to
1476 -- accommodate the entry index.
1478 Call_Nam :=
1479 Make_Indexed_Component (Loc,
1480 Prefix => Call_Nam,
1481 Expressions => New_List (New_Occurrence_Of (Index_Id, Loc)));
1482 end if;
1484 -- Add formal parameters to match those of the entry and build actuals
1485 -- for the entry call.
1487 Add_Matching_Formals (Formals, Actuals);
1489 Call :=
1490 Make_Procedure_Call_Statement (Loc,
1491 Name => Call_Nam,
1492 Parameter_Associations => Actuals);
1494 -- Add renaming declarations for the discriminants of the enclosing type
1495 -- as the various contract items may reference them.
1497 Add_Discriminant_Renamings (Obj_Id, Decls);
1499 Wrapper_Id :=
1500 Make_Defining_Identifier (Loc, New_External_Name (Chars (E), 'E'));
1501 Set_Contract_Wrapper (E, Wrapper_Id);
1502 Set_Is_Entry_Wrapper (Wrapper_Id);
1504 -- The wrapper body is analyzed when the enclosing type is frozen
1506 Append_Freeze_Action (Defining_Entity (Decl),
1507 Make_Subprogram_Body (Loc,
1508 Specification =>
1509 Make_Procedure_Specification (Loc,
1510 Defining_Unit_Name => Wrapper_Id,
1511 Parameter_Specifications => Formals),
1512 Declarations => Decls,
1513 Handled_Statement_Sequence =>
1514 Make_Handled_Sequence_Of_Statements (Loc,
1515 Statements => New_List (Call))));
1516 end Build_Contract_Wrapper;
1518 --------------------------------
1519 -- Build_Corresponding_Record --
1520 --------------------------------
1522 function Build_Corresponding_Record
1523 (N : Node_Id;
1524 Ctyp : Entity_Id;
1525 Loc : Source_Ptr) return Node_Id
1527 Rec_Ent : constant Entity_Id :=
1528 Make_Defining_Identifier
1529 (Loc, New_External_Name (Chars (Ctyp), 'V'));
1530 Disc : Entity_Id;
1531 Dlist : List_Id;
1532 New_Disc : Entity_Id;
1533 Cdecls : List_Id;
1535 begin
1536 Set_Corresponding_Record_Type (Ctyp, Rec_Ent);
1537 Set_Ekind (Rec_Ent, E_Record_Type);
1538 Set_Has_Delayed_Freeze (Rec_Ent, Has_Delayed_Freeze (Ctyp));
1539 Set_Is_Concurrent_Record_Type (Rec_Ent, True);
1540 Set_Corresponding_Concurrent_Type (Rec_Ent, Ctyp);
1541 Set_Stored_Constraint (Rec_Ent, No_Elist);
1542 Cdecls := New_List;
1544 -- Use discriminals to create list of discriminants for record, and
1545 -- create new discriminals for use in default expressions, etc. It is
1546 -- worth noting that a task discriminant gives rise to 5 entities;
1548 -- a) The original discriminant.
1549 -- b) The discriminal for use in the task.
1550 -- c) The discriminant of the corresponding record.
1551 -- d) The discriminal for the init proc of the corresponding record.
1552 -- e) The local variable that renames the discriminant in the procedure
1553 -- for the task body.
1555 -- In fact the discriminals b) are used in the renaming declarations
1556 -- for e). See details in einfo (Handling of Discriminants).
1558 if Present (Discriminant_Specifications (N)) then
1559 Dlist := New_List;
1560 Disc := First_Discriminant (Ctyp);
1562 while Present (Disc) loop
1563 New_Disc := CR_Discriminant (Disc);
1565 Append_To (Dlist,
1566 Make_Discriminant_Specification (Loc,
1567 Defining_Identifier => New_Disc,
1568 Discriminant_Type =>
1569 New_Occurrence_Of (Etype (Disc), Loc),
1570 Expression =>
1571 New_Copy (Discriminant_Default_Value (Disc))));
1573 Next_Discriminant (Disc);
1574 end loop;
1576 else
1577 Dlist := No_List;
1578 end if;
1580 -- Now we can construct the record type declaration. Note that this
1581 -- record is "limited tagged". It is "limited" to reflect the underlying
1582 -- limitedness of the task or protected object that it represents, and
1583 -- ensuring for example that it is properly passed by reference. It is
1584 -- "tagged" to give support to dispatching calls through interfaces. We
1585 -- propagate here the list of interfaces covered by the concurrent type
1586 -- (Ada 2005: AI-345).
1588 return
1589 Make_Full_Type_Declaration (Loc,
1590 Defining_Identifier => Rec_Ent,
1591 Discriminant_Specifications => Dlist,
1592 Type_Definition =>
1593 Make_Record_Definition (Loc,
1594 Component_List =>
1595 Make_Component_List (Loc, Component_Items => Cdecls),
1596 Tagged_Present =>
1597 Ada_Version >= Ada_2005 and then Is_Tagged_Type (Ctyp),
1598 Interface_List => Interface_List (N),
1599 Limited_Present => True));
1600 end Build_Corresponding_Record;
1602 ---------------------------------
1603 -- Build_Dispatching_Tag_Check --
1604 ---------------------------------
1606 function Build_Dispatching_Tag_Check
1607 (K : Entity_Id;
1608 N : Node_Id) return Node_Id
1610 Loc : constant Source_Ptr := Sloc (N);
1612 begin
1613 return
1614 Make_Op_Or (Loc,
1615 Make_Op_Eq (Loc,
1616 Left_Opnd =>
1617 New_Occurrence_Of (K, Loc),
1618 Right_Opnd =>
1619 New_Occurrence_Of (RTE (RE_TK_Limited_Tagged), Loc)),
1621 Make_Op_Eq (Loc,
1622 Left_Opnd =>
1623 New_Occurrence_Of (K, Loc),
1624 Right_Opnd =>
1625 New_Occurrence_Of (RTE (RE_TK_Tagged), Loc)));
1626 end Build_Dispatching_Tag_Check;
1628 ----------------------------------
1629 -- Build_Entry_Count_Expression --
1630 ----------------------------------
1632 function Build_Entry_Count_Expression
1633 (Concurrent_Type : Node_Id;
1634 Component_List : List_Id;
1635 Loc : Source_Ptr) return Node_Id
1637 Eindx : Nat;
1638 Ent : Entity_Id;
1639 Ecount : Node_Id;
1640 Comp : Node_Id;
1641 Lo : Node_Id;
1642 Hi : Node_Id;
1643 Typ : Entity_Id;
1644 Large : Boolean;
1646 begin
1647 -- Count number of non-family entries
1649 Eindx := 0;
1650 Ent := First_Entity (Concurrent_Type);
1651 while Present (Ent) loop
1652 if Ekind (Ent) = E_Entry then
1653 Eindx := Eindx + 1;
1654 end if;
1656 Next_Entity (Ent);
1657 end loop;
1659 Ecount := Make_Integer_Literal (Loc, Eindx);
1661 -- Loop through entry families building the addition nodes
1663 Ent := First_Entity (Concurrent_Type);
1664 Comp := First (Component_List);
1665 while Present (Ent) loop
1666 if Ekind (Ent) = E_Entry_Family then
1667 while Chars (Ent) /= Chars (Defining_Identifier (Comp)) loop
1668 Next (Comp);
1669 end loop;
1671 Typ := Etype (Discrete_Subtype_Definition (Parent (Ent)));
1672 Hi := Type_High_Bound (Typ);
1673 Lo := Type_Low_Bound (Typ);
1674 Large := Is_Potentially_Large_Family
1675 (Base_Type (Typ), Concurrent_Type, Lo, Hi);
1676 Ecount :=
1677 Make_Op_Add (Loc,
1678 Left_Opnd => Ecount,
1679 Right_Opnd =>
1680 Family_Size (Loc, Hi, Lo, Concurrent_Type, Large));
1681 end if;
1683 Next_Entity (Ent);
1684 end loop;
1686 return Ecount;
1687 end Build_Entry_Count_Expression;
1689 ---------------------------
1690 -- Build_Parameter_Block --
1691 ---------------------------
1693 function Build_Parameter_Block
1694 (Loc : Source_Ptr;
1695 Actuals : List_Id;
1696 Formals : List_Id;
1697 Decls : List_Id) return Entity_Id
1699 Actual : Entity_Id;
1700 Comp_Nam : Node_Id;
1701 Comps : List_Id;
1702 Formal : Entity_Id;
1703 Has_Comp : Boolean := False;
1704 Rec_Nam : Node_Id;
1706 begin
1707 Actual := First (Actuals);
1708 Comps := New_List;
1709 Formal := Defining_Identifier (First (Formals));
1711 while Present (Actual) loop
1712 if not Is_Controlling_Actual (Actual) then
1714 -- Generate:
1715 -- type Ann is access all <actual-type>
1717 Comp_Nam := Make_Temporary (Loc, 'A');
1718 Set_Is_Param_Block_Component_Type (Comp_Nam);
1720 Append_To (Decls,
1721 Make_Full_Type_Declaration (Loc,
1722 Defining_Identifier => Comp_Nam,
1723 Type_Definition =>
1724 Make_Access_To_Object_Definition (Loc,
1725 All_Present => True,
1726 Constant_Present => Ekind (Formal) = E_In_Parameter,
1727 Subtype_Indication =>
1728 New_Occurrence_Of (Etype (Actual), Loc))));
1730 -- Generate:
1731 -- Param : Ann;
1733 Append_To (Comps,
1734 Make_Component_Declaration (Loc,
1735 Defining_Identifier =>
1736 Make_Defining_Identifier (Loc, Chars (Formal)),
1737 Component_Definition =>
1738 Make_Component_Definition (Loc,
1739 Aliased_Present =>
1740 False,
1741 Subtype_Indication =>
1742 New_Occurrence_Of (Comp_Nam, Loc))));
1744 Has_Comp := True;
1745 end if;
1747 Next_Actual (Actual);
1748 Next_Formal_With_Extras (Formal);
1749 end loop;
1751 Rec_Nam := Make_Temporary (Loc, 'P');
1753 if Has_Comp then
1755 -- Generate:
1756 -- type Pnn is record
1757 -- Param1 : Ann1;
1758 -- ...
1759 -- ParamN : AnnN;
1761 -- where Pnn is a parameter wrapping record, Param1 .. ParamN are
1762 -- the original parameter names and Ann1 .. AnnN are the access to
1763 -- actual types.
1765 Append_To (Decls,
1766 Make_Full_Type_Declaration (Loc,
1767 Defining_Identifier =>
1768 Rec_Nam,
1769 Type_Definition =>
1770 Make_Record_Definition (Loc,
1771 Component_List =>
1772 Make_Component_List (Loc, Comps))));
1773 else
1774 -- Generate:
1775 -- type Pnn is null record;
1777 Append_To (Decls,
1778 Make_Full_Type_Declaration (Loc,
1779 Defining_Identifier =>
1780 Rec_Nam,
1781 Type_Definition =>
1782 Make_Record_Definition (Loc,
1783 Null_Present => True,
1784 Component_List => Empty)));
1785 end if;
1787 return Rec_Nam;
1788 end Build_Parameter_Block;
1790 --------------------------------------
1791 -- Build_Renamed_Formal_Declaration --
1792 --------------------------------------
1794 function Build_Renamed_Formal_Declaration
1795 (New_F : Entity_Id;
1796 Formal : Entity_Id;
1797 Comp : Entity_Id;
1798 Renamed_Formal : Node_Id) return Node_Id
1800 Loc : constant Source_Ptr := Sloc (New_F);
1801 Decl : Node_Id;
1803 begin
1804 -- If the formal is a tagged incomplete type, it is already passed
1805 -- by reference, so it is sufficient to rename the pointer component
1806 -- that corresponds to the actual. Otherwise we need to dereference
1807 -- the pointer component to obtain the actual.
1809 if Is_Incomplete_Type (Etype (Formal))
1810 and then Is_Tagged_Type (Etype (Formal))
1811 then
1812 Decl :=
1813 Make_Object_Renaming_Declaration (Loc,
1814 Defining_Identifier => New_F,
1815 Subtype_Mark => New_Occurrence_Of (Etype (Comp), Loc),
1816 Name => Renamed_Formal);
1818 else
1819 Decl :=
1820 Make_Object_Renaming_Declaration (Loc,
1821 Defining_Identifier => New_F,
1822 Subtype_Mark => New_Occurrence_Of (Etype (Formal), Loc),
1823 Name =>
1824 Make_Explicit_Dereference (Loc, Renamed_Formal));
1825 end if;
1827 return Decl;
1828 end Build_Renamed_Formal_Declaration;
1830 --------------------------
1831 -- Build_Wrapper_Bodies --
1832 --------------------------
1834 procedure Build_Wrapper_Bodies
1835 (Loc : Source_Ptr;
1836 Typ : Entity_Id;
1837 N : Node_Id)
1839 Rec_Typ : Entity_Id;
1841 function Build_Wrapper_Body
1842 (Loc : Source_Ptr;
1843 Subp_Id : Entity_Id;
1844 Obj_Typ : Entity_Id;
1845 Formals : List_Id) return Node_Id;
1846 -- Ada 2005 (AI-345): Build the body that wraps a primitive operation
1847 -- associated with a protected or task type. Subp_Id is the subprogram
1848 -- name which will be wrapped. Obj_Typ is the type of the new formal
1849 -- parameter which handles dispatching and object notation. Formals are
1850 -- the original formals of Subp_Id which will be explicitly replicated.
1852 ------------------------
1853 -- Build_Wrapper_Body --
1854 ------------------------
1856 function Build_Wrapper_Body
1857 (Loc : Source_Ptr;
1858 Subp_Id : Entity_Id;
1859 Obj_Typ : Entity_Id;
1860 Formals : List_Id) return Node_Id
1862 Body_Spec : Node_Id;
1864 begin
1865 Body_Spec := Build_Wrapper_Spec (Subp_Id, Obj_Typ, Formals);
1867 -- The subprogram is not overriding or is not a primitive declared
1868 -- between two views.
1870 if No (Body_Spec) then
1871 return Empty;
1872 end if;
1874 declare
1875 Actuals : List_Id := No_List;
1876 Conv_Id : Node_Id;
1877 First_Form : Node_Id;
1878 Formal : Node_Id;
1879 Nam : Node_Id;
1881 begin
1882 -- Map formals to actuals. Use the list built for the wrapper
1883 -- spec, skipping the object notation parameter.
1885 First_Form := First (Parameter_Specifications (Body_Spec));
1887 Formal := First_Form;
1888 Next (Formal);
1890 if Present (Formal) then
1891 Actuals := New_List;
1892 while Present (Formal) loop
1893 Append_To (Actuals,
1894 Make_Identifier (Loc,
1895 Chars => Chars (Defining_Identifier (Formal))));
1896 Next (Formal);
1897 end loop;
1898 end if;
1900 -- Special processing for primitives declared between a private
1901 -- type and its completion: the wrapper needs a properly typed
1902 -- parameter if the wrapped operation has a controlling first
1903 -- parameter. Note that this might not be the case for a function
1904 -- with a controlling result.
1906 if Is_Private_Primitive_Subprogram (Subp_Id) then
1907 if No (Actuals) then
1908 Actuals := New_List;
1909 end if;
1911 if Is_Controlling_Formal (First_Formal (Subp_Id)) then
1912 Prepend_To (Actuals,
1913 Unchecked_Convert_To
1914 (Corresponding_Concurrent_Type (Obj_Typ),
1915 Make_Identifier (Loc, Name_uO)));
1917 else
1918 Prepend_To (Actuals,
1919 Make_Identifier (Loc,
1920 Chars => Chars (Defining_Identifier (First_Form))));
1921 end if;
1923 Nam := New_Occurrence_Of (Subp_Id, Loc);
1924 else
1925 -- An access-to-variable object parameter requires an explicit
1926 -- dereference in the unchecked conversion. This case occurs
1927 -- when a protected entry wrapper must override an interface
1928 -- level procedure with interface access as first parameter.
1930 -- O.all.Subp_Id (Formal_1, ..., Formal_N)
1932 if Nkind (Parameter_Type (First_Form)) =
1933 N_Access_Definition
1934 then
1935 Conv_Id :=
1936 Make_Explicit_Dereference (Loc,
1937 Prefix => Make_Identifier (Loc, Name_uO));
1938 else
1939 Conv_Id := Make_Identifier (Loc, Name_uO);
1940 end if;
1942 Nam :=
1943 Make_Selected_Component (Loc,
1944 Prefix =>
1945 Unchecked_Convert_To
1946 (Corresponding_Concurrent_Type (Obj_Typ), Conv_Id),
1947 Selector_Name => New_Occurrence_Of (Subp_Id, Loc));
1948 end if;
1950 -- Create the subprogram body. For a function, the call to the
1951 -- actual subprogram has to be converted to the corresponding
1952 -- record if it is a controlling result.
1954 if Ekind (Subp_Id) = E_Function then
1955 declare
1956 Res : Node_Id;
1958 begin
1959 Res :=
1960 Make_Function_Call (Loc,
1961 Name => Nam,
1962 Parameter_Associations => Actuals);
1964 if Has_Controlling_Result (Subp_Id) then
1965 Res :=
1966 Unchecked_Convert_To
1967 (Corresponding_Record_Type (Etype (Subp_Id)), Res);
1968 end if;
1970 return
1971 Make_Subprogram_Body (Loc,
1972 Specification => Body_Spec,
1973 Declarations => Empty_List,
1974 Handled_Statement_Sequence =>
1975 Make_Handled_Sequence_Of_Statements (Loc,
1976 Statements => New_List (
1977 Make_Simple_Return_Statement (Loc, Res))));
1978 end;
1980 else
1981 return
1982 Make_Subprogram_Body (Loc,
1983 Specification => Body_Spec,
1984 Declarations => Empty_List,
1985 Handled_Statement_Sequence =>
1986 Make_Handled_Sequence_Of_Statements (Loc,
1987 Statements => New_List (
1988 Make_Procedure_Call_Statement (Loc,
1989 Name => Nam,
1990 Parameter_Associations => Actuals))));
1991 end if;
1992 end;
1993 end Build_Wrapper_Body;
1995 -- Start of processing for Build_Wrapper_Bodies
1997 begin
1998 if Is_Concurrent_Type (Typ) then
1999 Rec_Typ := Corresponding_Record_Type (Typ);
2000 else
2001 Rec_Typ := Typ;
2002 end if;
2004 -- Generate wrapper bodies for a concurrent type which implements an
2005 -- interface.
2007 if Present (Interfaces (Rec_Typ)) then
2008 declare
2009 Insert_Nod : Node_Id;
2010 Prim : Entity_Id;
2011 Prim_Elmt : Elmt_Id;
2012 Prim_Decl : Node_Id;
2013 Subp : Entity_Id;
2014 Wrap_Body : Node_Id;
2015 Wrap_Id : Entity_Id;
2017 begin
2018 Insert_Nod := N;
2020 -- Examine all primitive operations of the corresponding record
2021 -- type, looking for wrapper specs. Generate bodies in order to
2022 -- complete them.
2024 Prim_Elmt := First_Elmt (Primitive_Operations (Rec_Typ));
2025 while Present (Prim_Elmt) loop
2026 Prim := Node (Prim_Elmt);
2028 if (Ekind (Prim) = E_Function
2029 or else Ekind (Prim) = E_Procedure)
2030 and then Is_Primitive_Wrapper (Prim)
2031 then
2032 Subp := Wrapped_Entity (Prim);
2033 Prim_Decl := Parent (Parent (Prim));
2035 Wrap_Body :=
2036 Build_Wrapper_Body (Loc,
2037 Subp_Id => Subp,
2038 Obj_Typ => Rec_Typ,
2039 Formals => Parameter_Specifications (Parent (Subp)));
2040 Wrap_Id := Defining_Unit_Name (Specification (Wrap_Body));
2042 Set_Corresponding_Spec (Wrap_Body, Prim);
2043 Set_Corresponding_Body (Prim_Decl, Wrap_Id);
2045 Insert_After (Insert_Nod, Wrap_Body);
2046 Insert_Nod := Wrap_Body;
2048 Analyze (Wrap_Body);
2049 end if;
2051 Next_Elmt (Prim_Elmt);
2052 end loop;
2053 end;
2054 end if;
2055 end Build_Wrapper_Bodies;
2057 ------------------------
2058 -- Build_Wrapper_Spec --
2059 ------------------------
2061 function Build_Wrapper_Spec
2062 (Subp_Id : Entity_Id;
2063 Obj_Typ : Entity_Id;
2064 Formals : List_Id) return Node_Id
2066 function Overriding_Possible
2067 (Iface_Op : Entity_Id;
2068 Wrapper : Entity_Id) return Boolean;
2069 -- Determine whether a primitive operation can be overridden by Wrapper.
2070 -- Iface_Op is the candidate primitive operation of an interface type,
2071 -- Wrapper is the generated entry wrapper.
2073 function Replicate_Formals
2074 (Loc : Source_Ptr;
2075 Formals : List_Id) return List_Id;
2076 -- An explicit parameter replication is required due to the Is_Entry_
2077 -- Formal flag being set for all the formals of an entry. The explicit
2078 -- replication removes the flag that would otherwise cause a different
2079 -- path of analysis.
2081 -------------------------
2082 -- Overriding_Possible --
2083 -------------------------
2085 function Overriding_Possible
2086 (Iface_Op : Entity_Id;
2087 Wrapper : Entity_Id) return Boolean
2089 Iface_Op_Spec : constant Node_Id := Parent (Iface_Op);
2090 Wrapper_Spec : constant Node_Id := Parent (Wrapper);
2092 function Type_Conformant_Parameters
2093 (Iface_Op_Params : List_Id;
2094 Wrapper_Params : List_Id) return Boolean;
2095 -- Determine whether the parameters of the generated entry wrapper
2096 -- and those of a primitive operation are type conformant. During
2097 -- this check, the first parameter of the primitive operation is
2098 -- skipped if it is a controlling argument: protected functions
2099 -- may have a controlling result.
2101 --------------------------------
2102 -- Type_Conformant_Parameters --
2103 --------------------------------
2105 function Type_Conformant_Parameters
2106 (Iface_Op_Params : List_Id;
2107 Wrapper_Params : List_Id) return Boolean
2109 Iface_Op_Param : Node_Id;
2110 Iface_Op_Typ : Entity_Id;
2111 Wrapper_Param : Node_Id;
2112 Wrapper_Typ : Entity_Id;
2114 begin
2115 -- Skip the first (controlling) parameter of primitive operation
2117 Iface_Op_Param := First (Iface_Op_Params);
2119 if Present (First_Formal (Iface_Op))
2120 and then Is_Controlling_Formal (First_Formal (Iface_Op))
2121 then
2122 Iface_Op_Param := Next (Iface_Op_Param);
2123 end if;
2125 Wrapper_Param := First (Wrapper_Params);
2126 while Present (Iface_Op_Param)
2127 and then Present (Wrapper_Param)
2128 loop
2129 Iface_Op_Typ := Find_Parameter_Type (Iface_Op_Param);
2130 Wrapper_Typ := Find_Parameter_Type (Wrapper_Param);
2132 -- The two parameters must be mode conformant
2134 if not Conforming_Types
2135 (Iface_Op_Typ, Wrapper_Typ, Mode_Conformant)
2136 then
2137 return False;
2138 end if;
2140 Next (Iface_Op_Param);
2141 Next (Wrapper_Param);
2142 end loop;
2144 -- One of the lists is longer than the other
2146 if Present (Iface_Op_Param) or else Present (Wrapper_Param) then
2147 return False;
2148 end if;
2150 return True;
2151 end Type_Conformant_Parameters;
2153 -- Start of processing for Overriding_Possible
2155 begin
2156 if Chars (Iface_Op) /= Chars (Wrapper) then
2157 return False;
2158 end if;
2160 -- If an inherited subprogram is implemented by a protected procedure
2161 -- or an entry, then the first parameter of the inherited subprogram
2162 -- must be of mode OUT or IN OUT, or access-to-variable parameter.
2164 if Ekind (Iface_Op) = E_Procedure
2165 and then Present (Parameter_Specifications (Iface_Op_Spec))
2166 then
2167 declare
2168 Obj_Param : constant Node_Id :=
2169 First (Parameter_Specifications (Iface_Op_Spec));
2170 begin
2171 if not Out_Present (Obj_Param)
2172 and then Nkind (Parameter_Type (Obj_Param)) /=
2173 N_Access_Definition
2174 then
2175 return False;
2176 end if;
2177 end;
2178 end if;
2180 return
2181 Type_Conformant_Parameters
2182 (Parameter_Specifications (Iface_Op_Spec),
2183 Parameter_Specifications (Wrapper_Spec));
2184 end Overriding_Possible;
2186 -----------------------
2187 -- Replicate_Formals --
2188 -----------------------
2190 function Replicate_Formals
2191 (Loc : Source_Ptr;
2192 Formals : List_Id) return List_Id
2194 New_Formals : constant List_Id := New_List;
2195 Formal : Node_Id;
2196 Param_Type : Node_Id;
2198 begin
2199 Formal := First (Formals);
2201 -- Skip the object parameter when dealing with primitives declared
2202 -- between two views.
2204 if Is_Private_Primitive_Subprogram (Subp_Id)
2205 and then not Has_Controlling_Result (Subp_Id)
2206 then
2207 Formal := Next (Formal);
2208 end if;
2210 while Present (Formal) loop
2212 -- Create an explicit copy of the entry parameter
2214 -- When creating the wrapper subprogram for a primitive operation
2215 -- of a protected interface we must construct an equivalent
2216 -- signature to that of the overriding operation. For regular
2217 -- parameters we can just use the type of the formal, but for
2218 -- access to subprogram parameters we need to reanalyze the
2219 -- parameter type to create local entities for the signature of
2220 -- the subprogram type. Using the entities of the overriding
2221 -- subprogram will result in out-of-scope errors in the back-end.
2223 if Nkind (Parameter_Type (Formal)) = N_Access_Definition then
2224 Param_Type := Copy_Separate_Tree (Parameter_Type (Formal));
2225 else
2226 Param_Type :=
2227 New_Occurrence_Of (Etype (Parameter_Type (Formal)), Loc);
2228 end if;
2230 Append_To (New_Formals,
2231 Make_Parameter_Specification (Loc,
2232 Defining_Identifier =>
2233 Make_Defining_Identifier (Loc,
2234 Chars => Chars (Defining_Identifier (Formal))),
2235 In_Present => In_Present (Formal),
2236 Out_Present => Out_Present (Formal),
2237 Null_Exclusion_Present => Null_Exclusion_Present (Formal),
2238 Parameter_Type => Param_Type));
2240 Next (Formal);
2241 end loop;
2243 return New_Formals;
2244 end Replicate_Formals;
2246 -- Local variables
2248 Loc : constant Source_Ptr := Sloc (Subp_Id);
2249 First_Param : Node_Id := Empty;
2250 Iface : Entity_Id;
2251 Iface_Elmt : Elmt_Id;
2252 Iface_Op : Entity_Id;
2253 Iface_Op_Elmt : Elmt_Id;
2254 Overridden_Subp : Entity_Id;
2256 -- Start of processing for Build_Wrapper_Spec
2258 begin
2259 -- No point in building wrappers for untagged concurrent types
2261 pragma Assert (Is_Tagged_Type (Obj_Typ));
2263 -- Check if this subprogram has a profile that matches some interface
2264 -- primitive.
2266 Check_Synchronized_Overriding (Subp_Id, Overridden_Subp);
2268 if Present (Overridden_Subp) then
2269 First_Param :=
2270 First (Parameter_Specifications (Parent (Overridden_Subp)));
2272 -- An entry or a protected procedure can override a routine where the
2273 -- controlling formal is either IN OUT, OUT or is of access-to-variable
2274 -- type. Since the wrapper must have the exact same signature as that of
2275 -- the overridden subprogram, we try to find the overriding candidate
2276 -- and use its controlling formal.
2278 -- Check every implemented interface
2280 elsif Present (Interfaces (Obj_Typ)) then
2281 Iface_Elmt := First_Elmt (Interfaces (Obj_Typ));
2282 Search : while Present (Iface_Elmt) loop
2283 Iface := Node (Iface_Elmt);
2285 -- Check every interface primitive
2287 if Present (Primitive_Operations (Iface)) then
2288 Iface_Op_Elmt := First_Elmt (Primitive_Operations (Iface));
2289 while Present (Iface_Op_Elmt) loop
2290 Iface_Op := Node (Iface_Op_Elmt);
2292 -- Ignore predefined primitives
2294 if not Is_Predefined_Dispatching_Operation (Iface_Op) then
2295 Iface_Op := Ultimate_Alias (Iface_Op);
2297 -- The current primitive operation can be overridden by
2298 -- the generated entry wrapper.
2300 if Overriding_Possible (Iface_Op, Subp_Id) then
2301 First_Param :=
2302 First (Parameter_Specifications (Parent (Iface_Op)));
2304 exit Search;
2305 end if;
2306 end if;
2308 Next_Elmt (Iface_Op_Elmt);
2309 end loop;
2310 end if;
2312 Next_Elmt (Iface_Elmt);
2313 end loop Search;
2314 end if;
2316 -- Do not generate the wrapper if no interface primitive is covered by
2317 -- the subprogram and it is not a primitive declared between two views
2318 -- (see Process_Full_View).
2320 if No (First_Param)
2321 and then not Is_Private_Primitive_Subprogram (Subp_Id)
2322 then
2323 return Empty;
2324 end if;
2326 declare
2327 Wrapper_Id : constant Entity_Id :=
2328 Make_Defining_Identifier (Loc, Chars (Subp_Id));
2329 New_Formals : List_Id;
2330 Obj_Param : Node_Id;
2331 Obj_Param_Typ : Entity_Id;
2333 begin
2334 -- Minimum decoration is needed to catch the entity in
2335 -- Sem_Ch6.Override_Dispatching_Operation.
2337 if Ekind (Subp_Id) = E_Function then
2338 Set_Ekind (Wrapper_Id, E_Function);
2339 else
2340 Set_Ekind (Wrapper_Id, E_Procedure);
2341 end if;
2343 Set_Is_Primitive_Wrapper (Wrapper_Id);
2344 Set_Wrapped_Entity (Wrapper_Id, Subp_Id);
2345 Set_Is_Private_Primitive (Wrapper_Id,
2346 Is_Private_Primitive_Subprogram (Subp_Id));
2348 -- Process the formals
2350 New_Formals := Replicate_Formals (Loc, Formals);
2352 -- A function with a controlling result and no first controlling
2353 -- formal needs no additional parameter.
2355 if Has_Controlling_Result (Subp_Id)
2356 and then
2357 (No (First_Formal (Subp_Id))
2358 or else not Is_Controlling_Formal (First_Formal (Subp_Id)))
2359 then
2360 null;
2362 -- Routine Subp_Id has been found to override an interface primitive.
2363 -- If the interface operation has an access parameter, create a copy
2364 -- of it, with the same null exclusion indicator if present.
2366 elsif Present (First_Param) then
2367 if Nkind (Parameter_Type (First_Param)) = N_Access_Definition then
2368 Obj_Param_Typ :=
2369 Make_Access_Definition (Loc,
2370 Subtype_Mark =>
2371 New_Occurrence_Of (Obj_Typ, Loc),
2372 Null_Exclusion_Present =>
2373 Null_Exclusion_Present (Parameter_Type (First_Param)),
2374 Constant_Present =>
2375 Constant_Present (Parameter_Type (First_Param)));
2376 else
2377 Obj_Param_Typ := New_Occurrence_Of (Obj_Typ, Loc);
2378 end if;
2380 Obj_Param :=
2381 Make_Parameter_Specification (Loc,
2382 Defining_Identifier =>
2383 Make_Defining_Identifier (Loc,
2384 Chars => Name_uO),
2385 In_Present => In_Present (First_Param),
2386 Out_Present => Out_Present (First_Param),
2387 Parameter_Type => Obj_Param_Typ);
2389 Prepend_To (New_Formals, Obj_Param);
2391 -- If we are dealing with a primitive declared between two views,
2392 -- implemented by a synchronized operation, we need to create
2393 -- a default parameter. The mode of the parameter must match that
2394 -- of the primitive operation.
2396 else
2397 pragma Assert (Is_Private_Primitive_Subprogram (Subp_Id));
2399 Obj_Param :=
2400 Make_Parameter_Specification (Loc,
2401 Defining_Identifier =>
2402 Make_Defining_Identifier (Loc, Name_uO),
2403 In_Present =>
2404 In_Present (Parent (First_Entity (Subp_Id))),
2405 Out_Present => Ekind (Subp_Id) /= E_Function,
2406 Parameter_Type => New_Occurrence_Of (Obj_Typ, Loc));
2408 Prepend_To (New_Formals, Obj_Param);
2409 end if;
2411 -- Build the final spec. If it is a function with a controlling
2412 -- result, it is a primitive operation of the corresponding
2413 -- record type, so mark the spec accordingly.
2415 if Ekind (Subp_Id) = E_Function then
2416 declare
2417 Res_Def : Node_Id;
2419 begin
2420 if Has_Controlling_Result (Subp_Id) then
2421 Res_Def :=
2422 New_Occurrence_Of
2423 (Corresponding_Record_Type (Etype (Subp_Id)), Loc);
2424 else
2425 Res_Def := New_Copy (Result_Definition (Parent (Subp_Id)));
2426 end if;
2428 return
2429 Make_Function_Specification (Loc,
2430 Defining_Unit_Name => Wrapper_Id,
2431 Parameter_Specifications => New_Formals,
2432 Result_Definition => Res_Def);
2433 end;
2434 else
2435 return
2436 Make_Procedure_Specification (Loc,
2437 Defining_Unit_Name => Wrapper_Id,
2438 Parameter_Specifications => New_Formals);
2439 end if;
2440 end;
2441 end Build_Wrapper_Spec;
2443 -------------------------
2444 -- Build_Wrapper_Specs --
2445 -------------------------
2447 procedure Build_Wrapper_Specs
2448 (Loc : Source_Ptr;
2449 Typ : Entity_Id;
2450 N : in out Node_Id)
2452 Def : Node_Id;
2453 Rec_Typ : Entity_Id;
2454 procedure Scan_Declarations (L : List_Id);
2455 -- Common processing for visible and private declarations
2456 -- of a protected type.
2458 procedure Scan_Declarations (L : List_Id) is
2459 Decl : Node_Id;
2460 Wrap_Decl : Node_Id;
2461 Wrap_Spec : Node_Id;
2463 begin
2464 if No (L) then
2465 return;
2466 end if;
2468 Decl := First (L);
2469 while Present (Decl) loop
2470 Wrap_Spec := Empty;
2472 if Nkind (Decl) = N_Entry_Declaration
2473 and then Ekind (Defining_Identifier (Decl)) = E_Entry
2474 then
2475 Wrap_Spec :=
2476 Build_Wrapper_Spec
2477 (Subp_Id => Defining_Identifier (Decl),
2478 Obj_Typ => Rec_Typ,
2479 Formals => Parameter_Specifications (Decl));
2481 elsif Nkind (Decl) = N_Subprogram_Declaration then
2482 Wrap_Spec :=
2483 Build_Wrapper_Spec
2484 (Subp_Id => Defining_Unit_Name (Specification (Decl)),
2485 Obj_Typ => Rec_Typ,
2486 Formals =>
2487 Parameter_Specifications (Specification (Decl)));
2488 end if;
2490 if Present (Wrap_Spec) then
2491 Wrap_Decl :=
2492 Make_Subprogram_Declaration (Loc,
2493 Specification => Wrap_Spec);
2495 Insert_After (N, Wrap_Decl);
2496 N := Wrap_Decl;
2498 Analyze (Wrap_Decl);
2499 end if;
2501 Next (Decl);
2502 end loop;
2503 end Scan_Declarations;
2505 -- start of processing for Build_Wrapper_Specs
2507 begin
2508 if Is_Protected_Type (Typ) then
2509 Def := Protected_Definition (Parent (Typ));
2510 else pragma Assert (Is_Task_Type (Typ));
2511 Def := Task_Definition (Parent (Typ));
2512 end if;
2514 Rec_Typ := Corresponding_Record_Type (Typ);
2516 -- Generate wrapper specs for a concurrent type which implements an
2517 -- interface. Operations in both the visible and private parts may
2518 -- implement progenitor operations.
2520 if Present (Interfaces (Rec_Typ)) and then Present (Def) then
2521 Scan_Declarations (Visible_Declarations (Def));
2522 Scan_Declarations (Private_Declarations (Def));
2523 end if;
2524 end Build_Wrapper_Specs;
2526 ---------------------------
2527 -- Build_Find_Body_Index --
2528 ---------------------------
2530 function Build_Find_Body_Index (Typ : Entity_Id) return Node_Id is
2531 Loc : constant Source_Ptr := Sloc (Typ);
2532 Ent : Entity_Id;
2533 E_Typ : Entity_Id;
2534 Has_F : Boolean := False;
2535 Index : Nat;
2536 If_St : Node_Id := Empty;
2537 Lo : Node_Id;
2538 Hi : Node_Id;
2539 Decls : List_Id := New_List;
2540 Ret : Node_Id;
2541 Spec : Node_Id;
2542 Siz : Node_Id := Empty;
2544 procedure Add_If_Clause (Expr : Node_Id);
2545 -- Add test for range of current entry
2547 function Convert_Discriminant_Ref (Bound : Node_Id) return Node_Id;
2548 -- If a bound of an entry is given by a discriminant, retrieve the
2549 -- actual value of the discriminant from the enclosing object.
2551 -------------------
2552 -- Add_If_Clause --
2553 -------------------
2555 procedure Add_If_Clause (Expr : Node_Id) is
2556 Cond : Node_Id;
2557 Stats : constant List_Id :=
2558 New_List (
2559 Make_Simple_Return_Statement (Loc,
2560 Expression => Make_Integer_Literal (Loc, Index + 1)));
2562 begin
2563 -- Index for current entry body
2565 Index := Index + 1;
2567 -- Compute total length of entry queues so far
2569 if No (Siz) then
2570 Siz := Expr;
2571 else
2572 Siz :=
2573 Make_Op_Add (Loc,
2574 Left_Opnd => Siz,
2575 Right_Opnd => Expr);
2576 end if;
2578 Cond :=
2579 Make_Op_Le (Loc,
2580 Left_Opnd => Make_Identifier (Loc, Name_uE),
2581 Right_Opnd => Siz);
2583 -- Map entry queue indexes in the range of the current family
2584 -- into the current index, that designates the entry body.
2586 if No (If_St) then
2587 If_St :=
2588 Make_Implicit_If_Statement (Typ,
2589 Condition => Cond,
2590 Then_Statements => Stats,
2591 Elsif_Parts => New_List);
2592 Ret := If_St;
2594 else
2595 Append_To (Elsif_Parts (If_St),
2596 Make_Elsif_Part (Loc,
2597 Condition => Cond,
2598 Then_Statements => Stats));
2599 end if;
2600 end Add_If_Clause;
2602 ------------------------------
2603 -- Convert_Discriminant_Ref --
2604 ------------------------------
2606 function Convert_Discriminant_Ref (Bound : Node_Id) return Node_Id is
2607 B : Node_Id;
2609 begin
2610 if Is_Entity_Name (Bound)
2611 and then Ekind (Entity (Bound)) = E_Discriminant
2612 then
2613 B :=
2614 Make_Selected_Component (Loc,
2615 Prefix =>
2616 Unchecked_Convert_To (Corresponding_Record_Type (Typ),
2617 Make_Explicit_Dereference (Loc,
2618 Make_Identifier (Loc, Name_uObject))),
2619 Selector_Name => Make_Identifier (Loc, Chars (Bound)));
2620 Set_Etype (B, Etype (Entity (Bound)));
2621 else
2622 B := New_Copy_Tree (Bound);
2623 end if;
2625 return B;
2626 end Convert_Discriminant_Ref;
2628 -- Start of processing for Build_Find_Body_Index
2630 begin
2631 Spec := Build_Find_Body_Index_Spec (Typ);
2633 Ent := First_Entity (Typ);
2634 while Present (Ent) loop
2635 if Ekind (Ent) = E_Entry_Family then
2636 Has_F := True;
2637 exit;
2638 end if;
2640 Next_Entity (Ent);
2641 end loop;
2643 if not Has_F then
2645 -- If the protected type has no entry families, there is a one-one
2646 -- correspondence between entry queue and entry body.
2648 Ret :=
2649 Make_Simple_Return_Statement (Loc,
2650 Expression => Make_Identifier (Loc, Name_uE));
2652 else
2653 -- Suppose entries e1, e2, ... have size l1, l2, ... we generate
2654 -- the following:
2656 -- if E <= l1 then return 1;
2657 -- elsif E <= l1 + l2 then return 2;
2658 -- ...
2660 Index := 0;
2661 Siz := Empty;
2662 Ent := First_Entity (Typ);
2664 Add_Object_Pointer (Loc, Typ, Decls);
2666 while Present (Ent) loop
2667 if Ekind (Ent) = E_Entry then
2668 Add_If_Clause (Make_Integer_Literal (Loc, 1));
2670 elsif Ekind (Ent) = E_Entry_Family then
2671 E_Typ := Etype (Discrete_Subtype_Definition (Parent (Ent)));
2672 Hi := Convert_Discriminant_Ref (Type_High_Bound (E_Typ));
2673 Lo := Convert_Discriminant_Ref (Type_Low_Bound (E_Typ));
2674 Add_If_Clause (Family_Size (Loc, Hi, Lo, Typ, False));
2675 end if;
2677 Next_Entity (Ent);
2678 end loop;
2680 if Index = 1 then
2681 Decls := New_List;
2682 Ret :=
2683 Make_Simple_Return_Statement (Loc,
2684 Expression => Make_Integer_Literal (Loc, 1));
2686 elsif Nkind (Ret) = N_If_Statement then
2688 -- Ranges are in increasing order, so last one doesn't need guard
2690 declare
2691 Nod : constant Node_Id := Last (Elsif_Parts (Ret));
2692 begin
2693 Remove (Nod);
2694 Set_Else_Statements (Ret, Then_Statements (Nod));
2695 end;
2696 end if;
2697 end if;
2699 return
2700 Make_Subprogram_Body (Loc,
2701 Specification => Spec,
2702 Declarations => Decls,
2703 Handled_Statement_Sequence =>
2704 Make_Handled_Sequence_Of_Statements (Loc,
2705 Statements => New_List (Ret)));
2706 end Build_Find_Body_Index;
2708 --------------------------------
2709 -- Build_Find_Body_Index_Spec --
2710 --------------------------------
2712 function Build_Find_Body_Index_Spec (Typ : Entity_Id) return Node_Id is
2713 Loc : constant Source_Ptr := Sloc (Typ);
2714 Id : constant Entity_Id :=
2715 Make_Defining_Identifier (Loc,
2716 Chars => New_External_Name (Chars (Typ), 'F'));
2717 Parm1 : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uO);
2718 Parm2 : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uE);
2720 begin
2721 return
2722 Make_Function_Specification (Loc,
2723 Defining_Unit_Name => Id,
2724 Parameter_Specifications => New_List (
2725 Make_Parameter_Specification (Loc,
2726 Defining_Identifier => Parm1,
2727 Parameter_Type =>
2728 New_Occurrence_Of (RTE (RE_Address), Loc)),
2730 Make_Parameter_Specification (Loc,
2731 Defining_Identifier => Parm2,
2732 Parameter_Type =>
2733 New_Occurrence_Of (RTE (RE_Protected_Entry_Index), Loc))),
2735 Result_Definition => New_Occurrence_Of (
2736 RTE (RE_Protected_Entry_Index), Loc));
2737 end Build_Find_Body_Index_Spec;
2739 -----------------------------------------------
2740 -- Build_Lock_Free_Protected_Subprogram_Body --
2741 -----------------------------------------------
2743 function Build_Lock_Free_Protected_Subprogram_Body
2744 (N : Node_Id;
2745 Prot_Typ : Node_Id;
2746 Unprot_Spec : Node_Id) return Node_Id
2748 Actuals : constant List_Id := New_List;
2749 Loc : constant Source_Ptr := Sloc (N);
2750 Spec : constant Node_Id := Specification (N);
2751 Unprot_Id : constant Entity_Id := Defining_Unit_Name (Unprot_Spec);
2752 Formal : Node_Id;
2753 Prot_Spec : Node_Id;
2754 Stmt : Node_Id;
2756 begin
2757 -- Create the protected version of the body
2759 Prot_Spec :=
2760 Build_Protected_Sub_Specification (N, Prot_Typ, Protected_Mode);
2762 -- Build the actual parameters which appear in the call to the
2763 -- unprotected version of the body.
2765 Formal := First (Parameter_Specifications (Prot_Spec));
2766 while Present (Formal) loop
2767 Append_To (Actuals,
2768 Make_Identifier (Loc, Chars (Defining_Identifier (Formal))));
2770 Next (Formal);
2771 end loop;
2773 -- Function case, generate:
2774 -- return <Unprot_Func_Call>;
2776 if Nkind (Spec) = N_Function_Specification then
2777 Stmt :=
2778 Make_Simple_Return_Statement (Loc,
2779 Expression =>
2780 Make_Function_Call (Loc,
2781 Name =>
2782 Make_Identifier (Loc, Chars (Unprot_Id)),
2783 Parameter_Associations => Actuals));
2785 -- Procedure case, call the unprotected version
2787 else
2788 Stmt :=
2789 Make_Procedure_Call_Statement (Loc,
2790 Name =>
2791 Make_Identifier (Loc, Chars (Unprot_Id)),
2792 Parameter_Associations => Actuals);
2793 end if;
2795 return
2796 Make_Subprogram_Body (Loc,
2797 Declarations => Empty_List,
2798 Specification => Prot_Spec,
2799 Handled_Statement_Sequence =>
2800 Make_Handled_Sequence_Of_Statements (Loc,
2801 Statements => New_List (Stmt)));
2802 end Build_Lock_Free_Protected_Subprogram_Body;
2804 -------------------------------------------------
2805 -- Build_Lock_Free_Unprotected_Subprogram_Body --
2806 -------------------------------------------------
2808 -- Procedures which meet the lock-free implementation requirements and
2809 -- reference a unique scalar component Comp are expanded in the following
2810 -- manner:
2812 -- procedure P (...) is
2813 -- Expected_Comp : constant Comp_Type :=
2814 -- Comp_Type
2815 -- (System.Atomic_Primitives.Lock_Free_Read_N
2816 -- (_Object.Comp'Address));
2817 -- begin
2818 -- loop
2819 -- declare
2820 -- <original declarations before the object renaming declaration
2821 -- of Comp>
2823 -- Desired_Comp : Comp_Type := Expected_Comp;
2824 -- Comp : Comp_Type renames Desired_Comp;
2826 -- <original delarations after the object renaming declaration
2827 -- of Comp>
2829 -- begin
2830 -- <original statements>
2831 -- exit when System.Atomic_Primitives.Lock_Free_Try_Write_N
2832 -- (_Object.Comp'Address,
2833 -- Interfaces.Unsigned_N (Expected_Comp),
2834 -- Interfaces.Unsigned_N (Desired_Comp));
2835 -- end;
2836 -- end loop;
2837 -- end P;
2839 -- Each return and raise statement of P is transformed into an atomic
2840 -- status check:
2842 -- if System.Atomic_Primitives.Lock_Free_Try_Write_N
2843 -- (_Object.Comp'Address,
2844 -- Interfaces.Unsigned_N (Expected_Comp),
2845 -- Interfaces.Unsigned_N (Desired_Comp));
2846 -- then
2847 -- <original statement>
2848 -- else
2849 -- goto L0;
2850 -- end if;
2852 -- Functions which meet the lock-free implementation requirements and
2853 -- reference a unique scalar component Comp are expanded in the following
2854 -- manner:
2856 -- function F (...) return ... is
2857 -- <original declarations before the object renaming declaration
2858 -- of Comp>
2860 -- Expected_Comp : constant Comp_Type :=
2861 -- Comp_Type
2862 -- (System.Atomic_Primitives.Lock_Free_Read_N
2863 -- (_Object.Comp'Address));
2864 -- Comp : Comp_Type renames Expected_Comp;
2866 -- <original delarations after the object renaming declaration of
2867 -- Comp>
2869 -- begin
2870 -- <original statements>
2871 -- end F;
2873 function Build_Lock_Free_Unprotected_Subprogram_Body
2874 (N : Node_Id;
2875 Prot_Typ : Node_Id) return Node_Id
2877 function Referenced_Component (N : Node_Id) return Entity_Id;
2878 -- Subprograms which meet the lock-free implementation criteria are
2879 -- allowed to reference only one unique component. Return the prival
2880 -- of the said component.
2882 --------------------------
2883 -- Referenced_Component --
2884 --------------------------
2886 function Referenced_Component (N : Node_Id) return Entity_Id is
2887 Comp : Entity_Id;
2888 Decl : Node_Id;
2889 Source_Comp : Entity_Id := Empty;
2891 begin
2892 -- Find the unique source component which N references in its
2893 -- statements.
2895 for Index in 1 .. Lock_Free_Subprogram_Table.Last loop
2896 declare
2897 Element : Lock_Free_Subprogram renames
2898 Lock_Free_Subprogram_Table.Table (Index);
2899 begin
2900 if Element.Sub_Body = N then
2901 Source_Comp := Element.Comp_Id;
2902 exit;
2903 end if;
2904 end;
2905 end loop;
2907 if No (Source_Comp) then
2908 return Empty;
2909 end if;
2911 -- Find the prival which corresponds to the source component within
2912 -- the declarations of N.
2914 Decl := First (Declarations (N));
2915 while Present (Decl) loop
2917 -- Privals appear as object renamings
2919 if Nkind (Decl) = N_Object_Renaming_Declaration then
2920 Comp := Defining_Identifier (Decl);
2922 if Present (Prival_Link (Comp))
2923 and then Prival_Link (Comp) = Source_Comp
2924 then
2925 return Comp;
2926 end if;
2927 end if;
2929 Next (Decl);
2930 end loop;
2932 return Empty;
2933 end Referenced_Component;
2935 -- Local variables
2937 Comp : constant Entity_Id := Referenced_Component (N);
2938 Loc : constant Source_Ptr := Sloc (N);
2939 Hand_Stmt_Seq : Node_Id := Handled_Statement_Sequence (N);
2940 Decls : List_Id := Declarations (N);
2942 -- Start of processing for Build_Lock_Free_Unprotected_Subprogram_Body
2944 begin
2945 -- Add renamings for the protection object, discriminals, privals, and
2946 -- the entry index constant for use by debugger.
2948 Debug_Private_Data_Declarations (Decls);
2950 -- Perform the lock-free expansion when the subprogram references a
2951 -- protected component.
2953 if Present (Comp) then
2954 Protected_Component_Ref : declare
2955 Comp_Decl : constant Node_Id := Parent (Comp);
2956 Comp_Sel_Nam : constant Node_Id := Name (Comp_Decl);
2957 Comp_Type : constant Entity_Id := Etype (Comp);
2959 Is_Procedure : constant Boolean :=
2960 Ekind (Corresponding_Spec (N)) = E_Procedure;
2961 -- Indicates if N is a protected procedure body
2963 Block_Decls : List_Id := No_List;
2964 Try_Write : Entity_Id;
2965 Desired_Comp : Entity_Id;
2966 Decl : Node_Id;
2967 Label : Node_Id;
2968 Label_Id : Entity_Id := Empty;
2969 Read : Entity_Id;
2970 Expected_Comp : Entity_Id;
2971 Stmt : Node_Id;
2972 Stmts : List_Id :=
2973 New_Copy_List (Statements (Hand_Stmt_Seq));
2974 Typ_Size : Int;
2975 Unsigned : Entity_Id;
2977 function Process_Node (N : Node_Id) return Traverse_Result;
2978 -- Transform a single node if it is a return statement, a raise
2979 -- statement or a reference to Comp.
2981 procedure Process_Stmts (Stmts : List_Id);
2982 -- Given a statement sequence Stmts, wrap any return or raise
2983 -- statements in the following manner:
2985 -- if System.Atomic_Primitives.Lock_Free_Try_Write_N
2986 -- (_Object.Comp'Address,
2987 -- Interfaces.Unsigned_N (Expected_Comp),
2988 -- Interfaces.Unsigned_N (Desired_Comp))
2989 -- then
2990 -- <Stmt>;
2991 -- else
2992 -- goto L0;
2993 -- end if;
2995 ------------------
2996 -- Process_Node --
2997 ------------------
2999 function Process_Node (N : Node_Id) return Traverse_Result is
3001 procedure Wrap_Statement (Stmt : Node_Id);
3002 -- Wrap an arbitrary statement inside an if statement where the
3003 -- condition does an atomic check on the state of the object.
3005 --------------------
3006 -- Wrap_Statement --
3007 --------------------
3009 procedure Wrap_Statement (Stmt : Node_Id) is
3010 begin
3011 -- The first time through, create the declaration of a label
3012 -- which is used to skip the remainder of source statements
3013 -- if the state of the object has changed.
3015 if No (Label_Id) then
3016 Label_Id :=
3017 Make_Identifier (Loc, New_External_Name ('L', 0));
3018 Set_Entity (Label_Id,
3019 Make_Defining_Identifier (Loc, Chars (Label_Id)));
3020 end if;
3022 -- Generate:
3023 -- if System.Atomic_Primitives.Lock_Free_Try_Write_N
3024 -- (_Object.Comp'Address,
3025 -- Interfaces.Unsigned_N (Expected_Comp),
3026 -- Interfaces.Unsigned_N (Desired_Comp))
3027 -- then
3028 -- <Stmt>;
3029 -- else
3030 -- goto L0;
3031 -- end if;
3033 Rewrite (Stmt,
3034 Make_Implicit_If_Statement (N,
3035 Condition =>
3036 Make_Function_Call (Loc,
3037 Name =>
3038 New_Occurrence_Of (Try_Write, Loc),
3039 Parameter_Associations => New_List (
3040 Make_Attribute_Reference (Loc,
3041 Prefix => Relocate_Node (Comp_Sel_Nam),
3042 Attribute_Name => Name_Address),
3044 Unchecked_Convert_To (Unsigned,
3045 New_Occurrence_Of (Expected_Comp, Loc)),
3047 Unchecked_Convert_To (Unsigned,
3048 New_Occurrence_Of (Desired_Comp, Loc)))),
3050 Then_Statements => New_List (Relocate_Node (Stmt)),
3052 Else_Statements => New_List (
3053 Make_Goto_Statement (Loc,
3054 Name =>
3055 New_Occurrence_Of (Entity (Label_Id), Loc)))));
3056 end Wrap_Statement;
3058 -- Start of processing for Process_Node
3060 begin
3061 -- Wrap each return and raise statement that appear inside a
3062 -- procedure. Skip the last return statement which is added by
3063 -- default since it is transformed into an exit statement.
3065 if Is_Procedure
3066 and then ((Nkind (N) = N_Simple_Return_Statement
3067 and then N /= Last (Stmts))
3068 or else Nkind (N) = N_Extended_Return_Statement
3069 or else (Nkind_In (N, N_Raise_Constraint_Error,
3070 N_Raise_Program_Error,
3071 N_Raise_Statement,
3072 N_Raise_Storage_Error)
3073 and then Comes_From_Source (N)))
3074 then
3075 Wrap_Statement (N);
3076 return Skip;
3077 end if;
3079 -- Force reanalysis
3081 Set_Analyzed (N, False);
3083 return OK;
3084 end Process_Node;
3086 procedure Process_Nodes is new Traverse_Proc (Process_Node);
3088 -------------------
3089 -- Process_Stmts --
3090 -------------------
3092 procedure Process_Stmts (Stmts : List_Id) is
3093 Stmt : Node_Id;
3094 begin
3095 Stmt := First (Stmts);
3096 while Present (Stmt) loop
3097 Process_Nodes (Stmt);
3098 Next (Stmt);
3099 end loop;
3100 end Process_Stmts;
3102 -- Start of processing for Protected_Component_Ref
3104 begin
3105 -- Get the type size
3107 if Known_Static_Esize (Comp_Type) then
3108 Typ_Size := UI_To_Int (Esize (Comp_Type));
3110 -- If the Esize (Object_Size) is unknown at compile time, look at
3111 -- the RM_Size (Value_Size) since it may have been set by an
3112 -- explicit representation clause.
3114 elsif Known_Static_RM_Size (Comp_Type) then
3115 Typ_Size := UI_To_Int (RM_Size (Comp_Type));
3117 -- Should not happen since this has already been checked in
3118 -- Allows_Lock_Free_Implementation (see Sem_Ch9).
3120 else
3121 raise Program_Error;
3122 end if;
3124 -- Retrieve all relevant atomic routines and types
3126 case Typ_Size is
3127 when 8 =>
3128 Try_Write := RTE (RE_Lock_Free_Try_Write_8);
3129 Read := RTE (RE_Lock_Free_Read_8);
3130 Unsigned := RTE (RE_Uint8);
3132 when 16 =>
3133 Try_Write := RTE (RE_Lock_Free_Try_Write_16);
3134 Read := RTE (RE_Lock_Free_Read_16);
3135 Unsigned := RTE (RE_Uint16);
3137 when 32 =>
3138 Try_Write := RTE (RE_Lock_Free_Try_Write_32);
3139 Read := RTE (RE_Lock_Free_Read_32);
3140 Unsigned := RTE (RE_Uint32);
3142 when 64 =>
3143 Try_Write := RTE (RE_Lock_Free_Try_Write_64);
3144 Read := RTE (RE_Lock_Free_Read_64);
3145 Unsigned := RTE (RE_Uint64);
3147 when others =>
3148 raise Program_Error;
3149 end case;
3151 -- Generate:
3152 -- Expected_Comp : constant Comp_Type :=
3153 -- Comp_Type
3154 -- (System.Atomic_Primitives.Lock_Free_Read_N
3155 -- (_Object.Comp'Address));
3157 Expected_Comp :=
3158 Make_Defining_Identifier (Loc,
3159 New_External_Name (Chars (Comp), Suffix => "_saved"));
3161 Decl :=
3162 Make_Object_Declaration (Loc,
3163 Defining_Identifier => Expected_Comp,
3164 Object_Definition => New_Occurrence_Of (Comp_Type, Loc),
3165 Constant_Present => True,
3166 Expression =>
3167 Unchecked_Convert_To (Comp_Type,
3168 Make_Function_Call (Loc,
3169 Name => New_Occurrence_Of (Read, Loc),
3170 Parameter_Associations => New_List (
3171 Make_Attribute_Reference (Loc,
3172 Prefix => Relocate_Node (Comp_Sel_Nam),
3173 Attribute_Name => Name_Address)))));
3175 -- Protected procedures
3177 if Is_Procedure then
3178 -- Move the original declarations inside the generated block
3180 Block_Decls := Decls;
3182 -- Reset the declarations list of the protected procedure to
3183 -- contain only Decl.
3185 Decls := New_List (Decl);
3187 -- Generate:
3188 -- Desired_Comp : Comp_Type := Expected_Comp;
3190 Desired_Comp :=
3191 Make_Defining_Identifier (Loc,
3192 New_External_Name (Chars (Comp), Suffix => "_current"));
3194 -- Insert the declarations of Expected_Comp and Desired_Comp in
3195 -- the block declarations right before the renaming of the
3196 -- protected component.
3198 Insert_Before (Comp_Decl,
3199 Make_Object_Declaration (Loc,
3200 Defining_Identifier => Desired_Comp,
3201 Object_Definition => New_Occurrence_Of (Comp_Type, Loc),
3202 Expression =>
3203 New_Occurrence_Of (Expected_Comp, Loc)));
3205 -- Protected function
3207 else
3208 Desired_Comp := Expected_Comp;
3210 -- Insert the declaration of Expected_Comp in the function
3211 -- declarations right before the renaming of the protected
3212 -- component.
3214 Insert_Before (Comp_Decl, Decl);
3215 end if;
3217 -- Rewrite the protected component renaming declaration to be a
3218 -- renaming of Desired_Comp.
3220 -- Generate:
3221 -- Comp : Comp_Type renames Desired_Comp;
3223 Rewrite (Comp_Decl,
3224 Make_Object_Renaming_Declaration (Loc,
3225 Defining_Identifier =>
3226 Defining_Identifier (Comp_Decl),
3227 Subtype_Mark =>
3228 New_Occurrence_Of (Comp_Type, Loc),
3229 Name =>
3230 New_Occurrence_Of (Desired_Comp, Loc)));
3232 -- Wrap any return or raise statements in Stmts in same the manner
3233 -- described in Process_Stmts.
3235 Process_Stmts (Stmts);
3237 -- Generate:
3238 -- exit when System.Atomic_Primitives.Lock_Free_Try_Write_N
3239 -- (_Object.Comp'Address,
3240 -- Interfaces.Unsigned_N (Expected_Comp),
3241 -- Interfaces.Unsigned_N (Desired_Comp))
3243 if Is_Procedure then
3244 Stmt :=
3245 Make_Exit_Statement (Loc,
3246 Condition =>
3247 Make_Function_Call (Loc,
3248 Name =>
3249 New_Occurrence_Of (Try_Write, Loc),
3250 Parameter_Associations => New_List (
3251 Make_Attribute_Reference (Loc,
3252 Prefix => Relocate_Node (Comp_Sel_Nam),
3253 Attribute_Name => Name_Address),
3255 Unchecked_Convert_To (Unsigned,
3256 New_Occurrence_Of (Expected_Comp, Loc)),
3258 Unchecked_Convert_To (Unsigned,
3259 New_Occurrence_Of (Desired_Comp, Loc)))));
3261 -- Small optimization: transform the default return statement
3262 -- of a procedure into the atomic exit statement.
3264 if Nkind (Last (Stmts)) = N_Simple_Return_Statement then
3265 Rewrite (Last (Stmts), Stmt);
3266 else
3267 Append_To (Stmts, Stmt);
3268 end if;
3269 end if;
3271 -- Create the declaration of the label used to skip the rest of
3272 -- the source statements when the object state changes.
3274 if Present (Label_Id) then
3275 Label := Make_Label (Loc, Label_Id);
3276 Append_To (Decls,
3277 Make_Implicit_Label_Declaration (Loc,
3278 Defining_Identifier => Entity (Label_Id),
3279 Label_Construct => Label));
3280 Append_To (Stmts, Label);
3281 end if;
3283 -- Generate:
3284 -- loop
3285 -- declare
3286 -- <Decls>
3287 -- begin
3288 -- <Stmts>
3289 -- end;
3290 -- end loop;
3292 if Is_Procedure then
3293 Stmts :=
3294 New_List (
3295 Make_Loop_Statement (Loc,
3296 Statements => New_List (
3297 Make_Block_Statement (Loc,
3298 Declarations => Block_Decls,
3299 Handled_Statement_Sequence =>
3300 Make_Handled_Sequence_Of_Statements (Loc,
3301 Statements => Stmts))),
3302 End_Label => Empty));
3303 end if;
3305 Hand_Stmt_Seq :=
3306 Make_Handled_Sequence_Of_Statements (Loc, Statements => Stmts);
3307 end Protected_Component_Ref;
3308 end if;
3310 -- Make an unprotected version of the subprogram for use within the same
3311 -- object, with new name and extra parameter representing the object.
3313 return
3314 Make_Subprogram_Body (Loc,
3315 Specification =>
3316 Build_Protected_Sub_Specification (N, Prot_Typ, Unprotected_Mode),
3317 Declarations => Decls,
3318 Handled_Statement_Sequence => Hand_Stmt_Seq);
3319 end Build_Lock_Free_Unprotected_Subprogram_Body;
3321 -------------------------
3322 -- Build_Master_Entity --
3323 -------------------------
3325 procedure Build_Master_Entity (Obj_Or_Typ : Entity_Id) is
3326 Loc : constant Source_Ptr := Sloc (Obj_Or_Typ);
3327 Context : Node_Id;
3328 Context_Id : Entity_Id;
3329 Decl : Node_Id;
3330 Decls : List_Id;
3331 Par : Node_Id;
3333 begin
3334 if Is_Itype (Obj_Or_Typ) then
3335 Par := Associated_Node_For_Itype (Obj_Or_Typ);
3336 else
3337 Par := Parent (Obj_Or_Typ);
3338 end if;
3340 -- When creating a master for a record component which is either a task
3341 -- or access-to-task, the enclosing record is the master scope and the
3342 -- proper insertion point is the component list.
3344 if Is_Record_Type (Current_Scope) then
3345 Context := Par;
3346 Context_Id := Current_Scope;
3347 Decls := List_Containing (Context);
3349 -- Default case for object declarations and access types. Note that the
3350 -- context is updated to the nearest enclosing body, block, package, or
3351 -- return statement.
3353 else
3354 Find_Enclosing_Context (Par, Context, Context_Id, Decls);
3355 end if;
3357 -- Nothing to do if the context already has a master
3359 if Has_Master_Entity (Context_Id) then
3360 return;
3362 -- Nothing to do if tasks or tasking hierarchies are prohibited
3364 elsif Restriction_Active (No_Tasking)
3365 or else Restriction_Active (No_Task_Hierarchy)
3366 then
3367 return;
3368 end if;
3370 -- Create a master, generate:
3371 -- _Master : constant Master_Id := Current_Master.all;
3373 Decl :=
3374 Make_Object_Declaration (Loc,
3375 Defining_Identifier =>
3376 Make_Defining_Identifier (Loc, Name_uMaster),
3377 Constant_Present => True,
3378 Object_Definition => New_Occurrence_Of (RTE (RE_Master_Id), Loc),
3379 Expression =>
3380 Make_Explicit_Dereference (Loc,
3381 New_Occurrence_Of (RTE (RE_Current_Master), Loc)));
3383 -- The master is inserted at the start of the declarative list of the
3384 -- context.
3386 Prepend_To (Decls, Decl);
3388 -- In certain cases where transient scopes are involved, the immediate
3389 -- scope is not always the proper master scope. Ensure that the master
3390 -- declaration and entity appear in the same context.
3392 if Context_Id /= Current_Scope then
3393 Push_Scope (Context_Id);
3394 Analyze (Decl);
3395 Pop_Scope;
3396 else
3397 Analyze (Decl);
3398 end if;
3400 -- Mark the enclosing scope and its associated construct as being task
3401 -- masters.
3403 Set_Has_Master_Entity (Context_Id);
3405 while Present (Context)
3406 and then Nkind (Context) /= N_Compilation_Unit
3407 loop
3408 if Nkind_In (Context, N_Block_Statement,
3409 N_Subprogram_Body,
3410 N_Task_Body)
3411 then
3412 Set_Is_Task_Master (Context);
3413 exit;
3415 elsif Nkind (Parent (Context)) = N_Subunit then
3416 Context := Corresponding_Stub (Parent (Context));
3417 end if;
3419 Context := Parent (Context);
3420 end loop;
3421 end Build_Master_Entity;
3423 ---------------------------
3424 -- Build_Master_Renaming --
3425 ---------------------------
3427 procedure Build_Master_Renaming
3428 (Ptr_Typ : Entity_Id;
3429 Ins_Nod : Node_Id := Empty)
3431 Loc : constant Source_Ptr := Sloc (Ptr_Typ);
3432 Context : Node_Id;
3433 Master_Decl : Node_Id;
3434 Master_Id : Entity_Id;
3436 begin
3437 -- Nothing to do if tasks or tasking hierarchies are prohibited
3439 if Restriction_Active (No_Tasking)
3440 or else Restriction_Active (No_Task_Hierarchy)
3441 then
3442 return;
3443 end if;
3445 -- Determine the proper context to insert the master renaming
3447 if Present (Ins_Nod) then
3448 Context := Ins_Nod;
3449 elsif Is_Itype (Ptr_Typ) then
3450 Context := Associated_Node_For_Itype (Ptr_Typ);
3451 else
3452 Context := Parent (Ptr_Typ);
3453 end if;
3455 -- Generate:
3456 -- <Ptr_Typ>M : Master_Id renames _Master;
3458 Master_Id :=
3459 Make_Defining_Identifier (Loc,
3460 New_External_Name (Chars (Ptr_Typ), 'M'));
3462 Master_Decl :=
3463 Make_Object_Renaming_Declaration (Loc,
3464 Defining_Identifier => Master_Id,
3465 Subtype_Mark => New_Occurrence_Of (RTE (RE_Master_Id), Loc),
3466 Name => Make_Identifier (Loc, Name_uMaster));
3468 Insert_Action (Context, Master_Decl);
3470 -- The renamed master now services the access type
3472 Set_Master_Id (Ptr_Typ, Master_Id);
3473 end Build_Master_Renaming;
3475 -----------------------------------------
3476 -- Build_Private_Protected_Declaration --
3477 -----------------------------------------
3479 function Build_Private_Protected_Declaration
3480 (N : Node_Id) return Entity_Id
3482 Loc : constant Source_Ptr := Sloc (N);
3483 Body_Id : constant Entity_Id := Defining_Entity (N);
3484 Decl : Node_Id;
3485 Plist : List_Id;
3486 Formal : Entity_Id;
3487 New_Spec : Node_Id;
3488 Spec_Id : Entity_Id;
3490 begin
3491 Formal := First_Formal (Body_Id);
3493 -- The protected operation always has at least one formal, namely the
3494 -- object itself, but it is only placed in the parameter list if
3495 -- expansion is enabled.
3497 if Present (Formal) or else Expander_Active then
3498 Plist := Copy_Parameter_List (Body_Id);
3499 else
3500 Plist := No_List;
3501 end if;
3503 if Nkind (Specification (N)) = N_Procedure_Specification then
3504 New_Spec :=
3505 Make_Procedure_Specification (Loc,
3506 Defining_Unit_Name =>
3507 Make_Defining_Identifier (Sloc (Body_Id),
3508 Chars => Chars (Body_Id)),
3509 Parameter_Specifications =>
3510 Plist);
3511 else
3512 New_Spec :=
3513 Make_Function_Specification (Loc,
3514 Defining_Unit_Name =>
3515 Make_Defining_Identifier (Sloc (Body_Id),
3516 Chars => Chars (Body_Id)),
3517 Parameter_Specifications => Plist,
3518 Result_Definition =>
3519 New_Occurrence_Of (Etype (Body_Id), Loc));
3520 end if;
3522 Decl := Make_Subprogram_Declaration (Loc, Specification => New_Spec);
3523 Insert_Before (N, Decl);
3524 Spec_Id := Defining_Unit_Name (New_Spec);
3526 -- Indicate that the entity comes from source, to ensure that cross-
3527 -- reference information is properly generated. The body itself is
3528 -- rewritten during expansion, and the body entity will not appear in
3529 -- calls to the operation.
3531 Set_Comes_From_Source (Spec_Id, True);
3532 Analyze (Decl);
3533 Set_Has_Completion (Spec_Id);
3534 Set_Convention (Spec_Id, Convention_Protected);
3535 return Spec_Id;
3536 end Build_Private_Protected_Declaration;
3538 ---------------------------
3539 -- Build_Protected_Entry --
3540 ---------------------------
3542 function Build_Protected_Entry
3543 (N : Node_Id;
3544 Ent : Entity_Id;
3545 Pid : Node_Id) return Node_Id
3547 Bod_Decls : constant List_Id := New_List;
3548 Decls : constant List_Id := Declarations (N);
3549 End_Lab : constant Node_Id :=
3550 End_Label (Handled_Statement_Sequence (N));
3551 End_Loc : constant Source_Ptr :=
3552 Sloc (Last (Statements (Handled_Statement_Sequence (N))));
3553 -- Used for the generated call to Complete_Entry_Body
3555 Loc : constant Source_Ptr := Sloc (N);
3557 Bod_Id : Entity_Id;
3558 Bod_Spec : Node_Id;
3559 Bod_Stmts : List_Id;
3560 Complete : Node_Id;
3561 Ohandle : Node_Id;
3563 EH_Loc : Source_Ptr;
3564 -- Used for the exception handler, inserted at end of the body
3566 begin
3567 -- Set the source location on the exception handler only when debugging
3568 -- the expanded code (see Make_Implicit_Exception_Handler).
3570 if Debug_Generated_Code then
3571 EH_Loc := End_Loc;
3573 -- Otherwise the inserted code should not be visible to the debugger
3575 else
3576 EH_Loc := No_Location;
3577 end if;
3579 Bod_Id :=
3580 Make_Defining_Identifier (Loc,
3581 Chars => Chars (Protected_Body_Subprogram (Ent)));
3582 Bod_Spec := Build_Protected_Entry_Specification (Loc, Bod_Id, Empty);
3584 -- Add the following declarations:
3586 -- type poVP is access poV;
3587 -- _object : poVP := poVP (_O);
3589 -- where _O is the formal parameter associated with the concurrent
3590 -- object. These declarations are needed for Complete_Entry_Body.
3592 Add_Object_Pointer (Loc, Pid, Bod_Decls);
3594 -- Add renamings for all formals, the Protection object, discriminals,
3595 -- privals and the entry index constant for use by debugger.
3597 Add_Formal_Renamings (Bod_Spec, Bod_Decls, Ent, Loc);
3598 Debug_Private_Data_Declarations (Decls);
3600 -- Put the declarations and the statements from the entry
3602 Bod_Stmts :=
3603 New_List (
3604 Make_Block_Statement (Loc,
3605 Declarations => Decls,
3606 Handled_Statement_Sequence => Handled_Statement_Sequence (N)));
3608 case Corresponding_Runtime_Package (Pid) is
3609 when System_Tasking_Protected_Objects_Entries =>
3610 Append_To (Bod_Stmts,
3611 Make_Procedure_Call_Statement (End_Loc,
3612 Name =>
3613 New_Occurrence_Of (RTE (RE_Complete_Entry_Body), Loc),
3614 Parameter_Associations => New_List (
3615 Make_Attribute_Reference (End_Loc,
3616 Prefix =>
3617 Make_Selected_Component (End_Loc,
3618 Prefix =>
3619 Make_Identifier (End_Loc, Name_uObject),
3620 Selector_Name =>
3621 Make_Identifier (End_Loc, Name_uObject)),
3622 Attribute_Name => Name_Unchecked_Access))));
3624 when System_Tasking_Protected_Objects_Single_Entry =>
3626 -- Historically, a call to Complete_Single_Entry_Body was
3627 -- inserted, but it was a null procedure.
3629 null;
3631 when others =>
3632 raise Program_Error;
3633 end case;
3635 -- When exceptions can not be propagated, we never need to call
3636 -- Exception_Complete_Entry_Body.
3638 if No_Exception_Handlers_Set then
3639 return
3640 Make_Subprogram_Body (Loc,
3641 Specification => Bod_Spec,
3642 Declarations => Bod_Decls,
3643 Handled_Statement_Sequence =>
3644 Make_Handled_Sequence_Of_Statements (Loc,
3645 Statements => Bod_Stmts,
3646 End_Label => End_Lab));
3648 else
3649 Ohandle := Make_Others_Choice (Loc);
3650 Set_All_Others (Ohandle);
3652 case Corresponding_Runtime_Package (Pid) is
3653 when System_Tasking_Protected_Objects_Entries =>
3654 Complete :=
3655 New_Occurrence_Of
3656 (RTE (RE_Exceptional_Complete_Entry_Body), Loc);
3658 when System_Tasking_Protected_Objects_Single_Entry =>
3659 Complete :=
3660 New_Occurrence_Of
3661 (RTE (RE_Exceptional_Complete_Single_Entry_Body), Loc);
3663 when others =>
3664 raise Program_Error;
3665 end case;
3667 -- Establish link between subprogram body entity and source entry
3669 Set_Corresponding_Protected_Entry (Bod_Id, Ent);
3671 -- Create body of entry procedure. The renaming declarations are
3672 -- placed ahead of the block that contains the actual entry body.
3674 return
3675 Make_Subprogram_Body (Loc,
3676 Specification => Bod_Spec,
3677 Declarations => Bod_Decls,
3678 Handled_Statement_Sequence =>
3679 Make_Handled_Sequence_Of_Statements (Loc,
3680 Statements => Bod_Stmts,
3681 End_Label => End_Lab,
3682 Exception_Handlers => New_List (
3683 Make_Implicit_Exception_Handler (EH_Loc,
3684 Exception_Choices => New_List (Ohandle),
3686 Statements => New_List (
3687 Make_Procedure_Call_Statement (EH_Loc,
3688 Name => Complete,
3689 Parameter_Associations => New_List (
3690 Make_Attribute_Reference (EH_Loc,
3691 Prefix =>
3692 Make_Selected_Component (EH_Loc,
3693 Prefix =>
3694 Make_Identifier (EH_Loc, Name_uObject),
3695 Selector_Name =>
3696 Make_Identifier (EH_Loc, Name_uObject)),
3697 Attribute_Name => Name_Unchecked_Access),
3699 Make_Function_Call (EH_Loc,
3700 Name =>
3701 New_Occurrence_Of
3702 (RTE (RE_Get_GNAT_Exception), Loc)))))))));
3703 end if;
3704 end Build_Protected_Entry;
3706 -----------------------------------------
3707 -- Build_Protected_Entry_Specification --
3708 -----------------------------------------
3710 function Build_Protected_Entry_Specification
3711 (Loc : Source_Ptr;
3712 Def_Id : Entity_Id;
3713 Ent_Id : Entity_Id) return Node_Id
3715 P : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uP);
3717 begin
3718 Set_Debug_Info_Needed (Def_Id);
3720 if Present (Ent_Id) then
3721 Append_Elmt (P, Accept_Address (Ent_Id));
3722 end if;
3724 return
3725 Make_Procedure_Specification (Loc,
3726 Defining_Unit_Name => Def_Id,
3727 Parameter_Specifications => New_List (
3728 Make_Parameter_Specification (Loc,
3729 Defining_Identifier =>
3730 Make_Defining_Identifier (Loc, Name_uO),
3731 Parameter_Type =>
3732 New_Occurrence_Of (RTE (RE_Address), Loc)),
3734 Make_Parameter_Specification (Loc,
3735 Defining_Identifier => P,
3736 Parameter_Type =>
3737 New_Occurrence_Of (RTE (RE_Address), Loc)),
3739 Make_Parameter_Specification (Loc,
3740 Defining_Identifier =>
3741 Make_Defining_Identifier (Loc, Name_uE),
3742 Parameter_Type =>
3743 New_Occurrence_Of (RTE (RE_Protected_Entry_Index), Loc))));
3744 end Build_Protected_Entry_Specification;
3746 --------------------------
3747 -- Build_Protected_Spec --
3748 --------------------------
3750 function Build_Protected_Spec
3751 (N : Node_Id;
3752 Obj_Type : Entity_Id;
3753 Ident : Entity_Id;
3754 Unprotected : Boolean := False) return List_Id
3756 Loc : constant Source_Ptr := Sloc (N);
3757 Decl : Node_Id;
3758 Formal : Entity_Id;
3759 New_Plist : List_Id;
3760 New_Param : Node_Id;
3762 begin
3763 New_Plist := New_List;
3765 Formal := First_Formal (Ident);
3766 while Present (Formal) loop
3767 New_Param :=
3768 Make_Parameter_Specification (Loc,
3769 Defining_Identifier =>
3770 Make_Defining_Identifier (Sloc (Formal), Chars (Formal)),
3771 Aliased_Present => Aliased_Present (Parent (Formal)),
3772 In_Present => In_Present (Parent (Formal)),
3773 Out_Present => Out_Present (Parent (Formal)),
3774 Parameter_Type => New_Occurrence_Of (Etype (Formal), Loc));
3776 if Unprotected then
3777 Set_Protected_Formal (Formal, Defining_Identifier (New_Param));
3778 end if;
3780 Append (New_Param, New_Plist);
3781 Next_Formal (Formal);
3782 end loop;
3784 -- If the subprogram is a procedure and the context is not an access
3785 -- to protected subprogram, the parameter is in-out. Otherwise it is
3786 -- an in parameter.
3788 Decl :=
3789 Make_Parameter_Specification (Loc,
3790 Defining_Identifier =>
3791 Make_Defining_Identifier (Loc, Name_uObject),
3792 In_Present => True,
3793 Out_Present =>
3794 (Etype (Ident) = Standard_Void_Type
3795 and then not Is_RTE (Obj_Type, RE_Address)),
3796 Parameter_Type =>
3797 New_Occurrence_Of (Obj_Type, Loc));
3798 Set_Debug_Info_Needed (Defining_Identifier (Decl));
3799 Prepend_To (New_Plist, Decl);
3801 return New_Plist;
3802 end Build_Protected_Spec;
3804 ---------------------------------------
3805 -- Build_Protected_Sub_Specification --
3806 ---------------------------------------
3808 function Build_Protected_Sub_Specification
3809 (N : Node_Id;
3810 Prot_Typ : Entity_Id;
3811 Mode : Subprogram_Protection_Mode) return Node_Id
3813 Loc : constant Source_Ptr := Sloc (N);
3814 Decl : Node_Id;
3815 Def_Id : Entity_Id;
3816 New_Id : Entity_Id;
3817 New_Plist : List_Id;
3818 New_Spec : Node_Id;
3820 Append_Chr : constant array (Subprogram_Protection_Mode) of Character :=
3821 (Dispatching_Mode => ' ',
3822 Protected_Mode => 'P',
3823 Unprotected_Mode => 'N');
3825 begin
3826 if Ekind (Defining_Unit_Name (Specification (N))) = E_Subprogram_Body
3827 then
3828 Decl := Unit_Declaration_Node (Corresponding_Spec (N));
3829 else
3830 Decl := N;
3831 end if;
3833 Def_Id := Defining_Unit_Name (Specification (Decl));
3835 New_Plist :=
3836 Build_Protected_Spec
3837 (Decl, Corresponding_Record_Type (Prot_Typ), Def_Id,
3838 Mode = Unprotected_Mode);
3839 New_Id :=
3840 Make_Defining_Identifier (Loc,
3841 Chars => Build_Selected_Name (Prot_Typ, Def_Id, Append_Chr (Mode)));
3843 -- Reference the original nondispatching subprogram since the analysis
3844 -- of the object.operation notation may need its original name (see
3845 -- Sem_Ch4.Names_Match).
3847 if Mode = Dispatching_Mode then
3848 Set_Ekind (New_Id, Ekind (Def_Id));
3849 Set_Original_Protected_Subprogram (New_Id, Def_Id);
3850 end if;
3852 -- Link the protected or unprotected version to the original subprogram
3853 -- it emulates.
3855 Set_Ekind (New_Id, Ekind (Def_Id));
3856 Set_Protected_Subprogram (New_Id, Def_Id);
3858 -- The unprotected operation carries the user code, and debugging
3859 -- information must be generated for it, even though this spec does
3860 -- not come from source. It is also convenient to allow gdb to step
3861 -- into the protected operation, even though it only contains lock/
3862 -- unlock calls.
3864 Set_Debug_Info_Needed (New_Id);
3866 -- If a pragma Eliminate applies to the source entity, the internal
3867 -- subprograms will be eliminated as well.
3869 Set_Is_Eliminated (New_Id, Is_Eliminated (Def_Id));
3871 if Nkind (Specification (Decl)) = N_Procedure_Specification then
3872 New_Spec :=
3873 Make_Procedure_Specification (Loc,
3874 Defining_Unit_Name => New_Id,
3875 Parameter_Specifications => New_Plist);
3877 -- Create a new specification for the anonymous subprogram type
3879 else
3880 New_Spec :=
3881 Make_Function_Specification (Loc,
3882 Defining_Unit_Name => New_Id,
3883 Parameter_Specifications => New_Plist,
3884 Result_Definition =>
3885 Copy_Result_Type (Result_Definition (Specification (Decl))));
3887 Set_Return_Present (Defining_Unit_Name (New_Spec));
3888 end if;
3890 return New_Spec;
3891 end Build_Protected_Sub_Specification;
3893 -------------------------------------
3894 -- Build_Protected_Subprogram_Body --
3895 -------------------------------------
3897 function Build_Protected_Subprogram_Body
3898 (N : Node_Id;
3899 Pid : Node_Id;
3900 N_Op_Spec : Node_Id) return Node_Id
3902 Exc_Safe : constant Boolean := not Might_Raise (N);
3903 -- True if N cannot raise an exception
3905 Loc : constant Source_Ptr := Sloc (N);
3906 Op_Spec : constant Node_Id := Specification (N);
3907 P_Op_Spec : constant Node_Id :=
3908 Build_Protected_Sub_Specification (N, Pid, Protected_Mode);
3910 Lock_Kind : RE_Id;
3911 Lock_Name : Node_Id;
3912 Lock_Stmt : Node_Id;
3913 Object_Parm : Node_Id;
3914 Pformal : Node_Id;
3915 R : Node_Id;
3916 Return_Stmt : Node_Id := Empty; -- init to avoid gcc 3 warning
3917 Pre_Stmts : List_Id := No_List; -- init to avoid gcc 3 warning
3918 Stmts : List_Id;
3919 Sub_Body : Node_Id;
3920 Uactuals : List_Id;
3921 Unprot_Call : Node_Id;
3923 begin
3924 -- Build a list of the formal parameters of the protected version of
3925 -- the subprogram to use as the actual parameters of the unprotected
3926 -- version.
3928 Uactuals := New_List;
3929 Pformal := First (Parameter_Specifications (P_Op_Spec));
3930 while Present (Pformal) loop
3931 Append_To (Uactuals,
3932 Make_Identifier (Loc, Chars (Defining_Identifier (Pformal))));
3933 Next (Pformal);
3934 end loop;
3936 -- Make a call to the unprotected version of the subprogram built above
3937 -- for use by the protected version built below.
3939 if Nkind (Op_Spec) = N_Function_Specification then
3940 if Exc_Safe then
3941 R := Make_Temporary (Loc, 'R');
3943 Unprot_Call :=
3944 Make_Object_Declaration (Loc,
3945 Defining_Identifier => R,
3946 Constant_Present => True,
3947 Object_Definition =>
3948 New_Copy (Result_Definition (N_Op_Spec)),
3949 Expression =>
3950 Make_Function_Call (Loc,
3951 Name =>
3952 Make_Identifier (Loc,
3953 Chars => Chars (Defining_Unit_Name (N_Op_Spec))),
3954 Parameter_Associations => Uactuals));
3956 Return_Stmt :=
3957 Make_Simple_Return_Statement (Loc,
3958 Expression => New_Occurrence_Of (R, Loc));
3960 else
3961 Unprot_Call :=
3962 Make_Simple_Return_Statement (Loc,
3963 Expression =>
3964 Make_Function_Call (Loc,
3965 Name =>
3966 Make_Identifier (Loc,
3967 Chars => Chars (Defining_Unit_Name (N_Op_Spec))),
3968 Parameter_Associations => Uactuals));
3969 end if;
3971 Lock_Kind := RE_Lock_Read_Only;
3973 else
3974 Unprot_Call :=
3975 Make_Procedure_Call_Statement (Loc,
3976 Name =>
3977 Make_Identifier (Loc, Chars (Defining_Unit_Name (N_Op_Spec))),
3978 Parameter_Associations => Uactuals);
3980 Lock_Kind := RE_Lock;
3981 end if;
3983 -- Wrap call in block that will be covered by an at_end handler
3985 if not Exc_Safe then
3986 Unprot_Call :=
3987 Make_Block_Statement (Loc,
3988 Handled_Statement_Sequence =>
3989 Make_Handled_Sequence_Of_Statements (Loc,
3990 Statements => New_List (Unprot_Call)));
3991 end if;
3993 -- Make the protected subprogram body. This locks the protected
3994 -- object and calls the unprotected version of the subprogram.
3996 case Corresponding_Runtime_Package (Pid) is
3997 when System_Tasking_Protected_Objects_Entries =>
3998 Lock_Name := New_Occurrence_Of (RTE (RE_Lock_Entries), Loc);
4000 when System_Tasking_Protected_Objects_Single_Entry =>
4001 Lock_Name := New_Occurrence_Of (RTE (RE_Lock_Entry), Loc);
4003 when System_Tasking_Protected_Objects =>
4004 Lock_Name := New_Occurrence_Of (RTE (Lock_Kind), Loc);
4006 when others =>
4007 raise Program_Error;
4008 end case;
4010 Object_Parm :=
4011 Make_Attribute_Reference (Loc,
4012 Prefix =>
4013 Make_Selected_Component (Loc,
4014 Prefix => Make_Identifier (Loc, Name_uObject),
4015 Selector_Name => Make_Identifier (Loc, Name_uObject)),
4016 Attribute_Name => Name_Unchecked_Access);
4018 Lock_Stmt :=
4019 Make_Procedure_Call_Statement (Loc,
4020 Name => Lock_Name,
4021 Parameter_Associations => New_List (Object_Parm));
4023 if Abort_Allowed then
4024 Stmts := New_List (
4025 Build_Runtime_Call (Loc, RE_Abort_Defer),
4026 Lock_Stmt);
4028 else
4029 Stmts := New_List (Lock_Stmt);
4030 end if;
4032 if not Exc_Safe then
4033 Append (Unprot_Call, Stmts);
4034 else
4035 if Nkind (Op_Spec) = N_Function_Specification then
4036 Pre_Stmts := Stmts;
4037 Stmts := Empty_List;
4038 else
4039 Append (Unprot_Call, Stmts);
4040 end if;
4042 -- Historical note: Previously, call to the cleanup was inserted
4043 -- here. This is now done by Build_Protected_Subprogram_Call_Cleanup,
4044 -- which is also shared by the 'not Exc_Safe' path.
4046 Build_Protected_Subprogram_Call_Cleanup (Op_Spec, Pid, Loc, Stmts);
4048 if Nkind (Op_Spec) = N_Function_Specification then
4049 Append_To (Stmts, Return_Stmt);
4050 Append_To (Pre_Stmts,
4051 Make_Block_Statement (Loc,
4052 Declarations => New_List (Unprot_Call),
4053 Handled_Statement_Sequence =>
4054 Make_Handled_Sequence_Of_Statements (Loc,
4055 Statements => Stmts)));
4056 Stmts := Pre_Stmts;
4057 end if;
4058 end if;
4060 Sub_Body :=
4061 Make_Subprogram_Body (Loc,
4062 Declarations => Empty_List,
4063 Specification => P_Op_Spec,
4064 Handled_Statement_Sequence =>
4065 Make_Handled_Sequence_Of_Statements (Loc, Statements => Stmts));
4067 -- Mark this subprogram as a protected subprogram body so that the
4068 -- cleanup will be inserted. This is done only in the 'not Exc_Safe'
4069 -- path as otherwise the cleanup has already been inserted.
4071 if not Exc_Safe then
4072 Set_Is_Protected_Subprogram_Body (Sub_Body);
4073 end if;
4075 return Sub_Body;
4076 end Build_Protected_Subprogram_Body;
4078 -------------------------------------
4079 -- Build_Protected_Subprogram_Call --
4080 -------------------------------------
4082 procedure Build_Protected_Subprogram_Call
4083 (N : Node_Id;
4084 Name : Node_Id;
4085 Rec : Node_Id;
4086 External : Boolean := True)
4088 Loc : constant Source_Ptr := Sloc (N);
4089 Sub : constant Entity_Id := Entity (Name);
4090 New_Sub : Node_Id;
4091 Params : List_Id;
4093 begin
4094 if External then
4095 New_Sub := New_Occurrence_Of (External_Subprogram (Sub), Loc);
4096 else
4097 New_Sub :=
4098 New_Occurrence_Of (Protected_Body_Subprogram (Sub), Loc);
4099 end if;
4101 if Present (Parameter_Associations (N)) then
4102 Params := New_Copy_List_Tree (Parameter_Associations (N));
4103 else
4104 Params := New_List;
4105 end if;
4107 -- If the type is an untagged derived type, convert to the root type,
4108 -- which is the one on which the operations are defined.
4110 if Nkind (Rec) = N_Unchecked_Type_Conversion
4111 and then not Is_Tagged_Type (Etype (Rec))
4112 and then Is_Derived_Type (Etype (Rec))
4113 then
4114 Set_Etype (Rec, Root_Type (Etype (Rec)));
4115 Set_Subtype_Mark (Rec,
4116 New_Occurrence_Of (Root_Type (Etype (Rec)), Sloc (N)));
4117 end if;
4119 Prepend (Rec, Params);
4121 if Ekind (Sub) = E_Procedure then
4122 Rewrite (N,
4123 Make_Procedure_Call_Statement (Loc,
4124 Name => New_Sub,
4125 Parameter_Associations => Params));
4127 else
4128 pragma Assert (Ekind (Sub) = E_Function);
4129 Rewrite (N,
4130 Make_Function_Call (Loc,
4131 Name => New_Sub,
4132 Parameter_Associations => Params));
4134 -- Preserve type of call for subsequent processing (required for
4135 -- call to Wrap_Transient_Expression in the case of a shared passive
4136 -- protected).
4138 Set_Etype (N, Etype (New_Sub));
4139 end if;
4141 if External
4142 and then Nkind (Rec) = N_Unchecked_Type_Conversion
4143 and then Is_Entity_Name (Expression (Rec))
4144 and then Is_Shared_Passive (Entity (Expression (Rec)))
4145 then
4146 Add_Shared_Var_Lock_Procs (N);
4147 end if;
4148 end Build_Protected_Subprogram_Call;
4150 ---------------------------------------------
4151 -- Build_Protected_Subprogram_Call_Cleanup --
4152 ---------------------------------------------
4154 procedure Build_Protected_Subprogram_Call_Cleanup
4155 (Op_Spec : Node_Id;
4156 Conc_Typ : Node_Id;
4157 Loc : Source_Ptr;
4158 Stmts : List_Id)
4160 Nam : Node_Id;
4162 begin
4163 -- If the associated protected object has entries, a protected
4164 -- procedure has to service entry queues. In this case generate:
4166 -- Service_Entries (_object._object'Access);
4168 if Nkind (Op_Spec) = N_Procedure_Specification
4169 and then Has_Entries (Conc_Typ)
4170 then
4171 case Corresponding_Runtime_Package (Conc_Typ) is
4172 when System_Tasking_Protected_Objects_Entries =>
4173 Nam := New_Occurrence_Of (RTE (RE_Service_Entries), Loc);
4175 when System_Tasking_Protected_Objects_Single_Entry =>
4176 Nam := New_Occurrence_Of (RTE (RE_Service_Entry), Loc);
4178 when others =>
4179 raise Program_Error;
4180 end case;
4182 Append_To (Stmts,
4183 Make_Procedure_Call_Statement (Loc,
4184 Name => Nam,
4185 Parameter_Associations => New_List (
4186 Make_Attribute_Reference (Loc,
4187 Prefix =>
4188 Make_Selected_Component (Loc,
4189 Prefix => Make_Identifier (Loc, Name_uObject),
4190 Selector_Name => Make_Identifier (Loc, Name_uObject)),
4191 Attribute_Name => Name_Unchecked_Access))));
4193 else
4194 -- Generate:
4195 -- Unlock (_object._object'Access);
4197 case Corresponding_Runtime_Package (Conc_Typ) is
4198 when System_Tasking_Protected_Objects_Entries =>
4199 Nam := New_Occurrence_Of (RTE (RE_Unlock_Entries), Loc);
4201 when System_Tasking_Protected_Objects_Single_Entry =>
4202 Nam := New_Occurrence_Of (RTE (RE_Unlock_Entry), Loc);
4204 when System_Tasking_Protected_Objects =>
4205 Nam := New_Occurrence_Of (RTE (RE_Unlock), Loc);
4207 when others =>
4208 raise Program_Error;
4209 end case;
4211 Append_To (Stmts,
4212 Make_Procedure_Call_Statement (Loc,
4213 Name => Nam,
4214 Parameter_Associations => New_List (
4215 Make_Attribute_Reference (Loc,
4216 Prefix =>
4217 Make_Selected_Component (Loc,
4218 Prefix => Make_Identifier (Loc, Name_uObject),
4219 Selector_Name => Make_Identifier (Loc, Name_uObject)),
4220 Attribute_Name => Name_Unchecked_Access))));
4221 end if;
4223 -- Generate:
4224 -- Abort_Undefer;
4226 if Abort_Allowed then
4227 Append_To (Stmts, Build_Runtime_Call (Loc, RE_Abort_Undefer));
4228 end if;
4229 end Build_Protected_Subprogram_Call_Cleanup;
4231 -------------------------
4232 -- Build_Selected_Name --
4233 -------------------------
4235 function Build_Selected_Name
4236 (Prefix : Entity_Id;
4237 Selector : Entity_Id;
4238 Append_Char : Character := ' ') return Name_Id
4240 Select_Buffer : String (1 .. Hostparm.Max_Name_Length);
4241 Select_Len : Natural;
4243 begin
4244 Get_Name_String (Chars (Selector));
4245 Select_Len := Name_Len;
4246 Select_Buffer (1 .. Select_Len) := Name_Buffer (1 .. Name_Len);
4247 Get_Name_String (Chars (Prefix));
4249 -- If scope is anonymous type, discard suffix to recover name of
4250 -- single protected object. Otherwise use protected type name.
4252 if Name_Buffer (Name_Len) = 'T' then
4253 Name_Len := Name_Len - 1;
4254 end if;
4256 Add_Str_To_Name_Buffer ("__");
4257 for J in 1 .. Select_Len loop
4258 Add_Char_To_Name_Buffer (Select_Buffer (J));
4259 end loop;
4261 -- Now add the Append_Char if specified. The encoding to follow
4262 -- depends on the type of entity. If Append_Char is either 'N' or 'P',
4263 -- then the entity is associated to a protected type subprogram.
4264 -- Otherwise, it is a protected type entry. For each case, the
4265 -- encoding to follow for the suffix is documented in exp_dbug.ads.
4267 -- It would be better to encapsulate this as a routine in Exp_Dbug ???
4269 if Append_Char /= ' ' then
4270 if Append_Char = 'P' or Append_Char = 'N' then
4271 Add_Char_To_Name_Buffer (Append_Char);
4272 return Name_Find;
4273 else
4274 Add_Str_To_Name_Buffer ((1 => '_', 2 => Append_Char));
4275 return New_External_Name (Name_Find, ' ', -1);
4276 end if;
4277 else
4278 return Name_Find;
4279 end if;
4280 end Build_Selected_Name;
4282 -----------------------------
4283 -- Build_Simple_Entry_Call --
4284 -----------------------------
4286 -- A task entry call is converted to a call to Call_Simple
4288 -- declare
4289 -- P : parms := (parm, parm, parm);
4290 -- begin
4291 -- Call_Simple (acceptor-task, entry-index, P'Address);
4292 -- parm := P.param;
4293 -- parm := P.param;
4294 -- ...
4295 -- end;
4297 -- Here Pnn is an aggregate of the type constructed for the entry to hold
4298 -- the parameters, and the constructed aggregate value contains either the
4299 -- parameters or, in the case of non-elementary types, references to these
4300 -- parameters. Then the address of this aggregate is passed to the runtime
4301 -- routine, along with the task id value and the task entry index value.
4302 -- Pnn is only required if parameters are present.
4304 -- The assignments after the call are present only in the case of in-out
4305 -- or out parameters for elementary types, and are used to assign back the
4306 -- resulting values of such parameters.
4308 -- Note: the reason that we insert a block here is that in the context
4309 -- of selects, conditional entry calls etc. the entry call statement
4310 -- appears on its own, not as an element of a list.
4312 -- A protected entry call is converted to a Protected_Entry_Call:
4314 -- declare
4315 -- P : E1_Params := (param, param, param);
4316 -- Pnn : Boolean;
4317 -- Bnn : Communications_Block;
4319 -- declare
4320 -- P : E1_Params := (param, param, param);
4321 -- Bnn : Communications_Block;
4323 -- begin
4324 -- Protected_Entry_Call (
4325 -- Object => po._object'Access,
4326 -- E => <entry index>;
4327 -- Uninterpreted_Data => P'Address;
4328 -- Mode => Simple_Call;
4329 -- Block => Bnn);
4330 -- parm := P.param;
4331 -- parm := P.param;
4332 -- ...
4333 -- end;
4335 procedure Build_Simple_Entry_Call
4336 (N : Node_Id;
4337 Concval : Node_Id;
4338 Ename : Node_Id;
4339 Index : Node_Id)
4341 begin
4342 Expand_Call (N);
4344 -- If call has been inlined, nothing left to do
4346 if Nkind (N) = N_Block_Statement then
4347 return;
4348 end if;
4350 -- Convert entry call to Call_Simple call
4352 declare
4353 Loc : constant Source_Ptr := Sloc (N);
4354 Parms : constant List_Id := Parameter_Associations (N);
4355 Stats : constant List_Id := New_List;
4356 Actual : Node_Id;
4357 Call : Node_Id;
4358 Comm_Name : Entity_Id;
4359 Conctyp : Node_Id;
4360 Decls : List_Id;
4361 Ent : Entity_Id;
4362 Ent_Acc : Entity_Id;
4363 Formal : Node_Id;
4364 Iface_Tag : Entity_Id;
4365 Iface_Typ : Entity_Id;
4366 N_Node : Node_Id;
4367 N_Var : Node_Id;
4368 P : Entity_Id;
4369 Parm1 : Node_Id;
4370 Parm2 : Node_Id;
4371 Parm3 : Node_Id;
4372 Pdecl : Node_Id;
4373 Plist : List_Id;
4374 X : Entity_Id;
4375 Xdecl : Node_Id;
4377 begin
4378 -- Simple entry and entry family cases merge here
4380 Ent := Entity (Ename);
4381 Ent_Acc := Entry_Parameters_Type (Ent);
4382 Conctyp := Etype (Concval);
4384 -- If prefix is an access type, dereference to obtain the task type
4386 if Is_Access_Type (Conctyp) then
4387 Conctyp := Designated_Type (Conctyp);
4388 end if;
4390 -- Special case for protected subprogram calls
4392 if Is_Protected_Type (Conctyp)
4393 and then Is_Subprogram (Entity (Ename))
4394 then
4395 if not Is_Eliminated (Entity (Ename)) then
4396 Build_Protected_Subprogram_Call
4397 (N, Ename, Convert_Concurrent (Concval, Conctyp));
4398 Analyze (N);
4399 end if;
4401 return;
4402 end if;
4404 -- First parameter is the Task_Id value from the task value or the
4405 -- Object from the protected object value, obtained by selecting
4406 -- the _Task_Id or _Object from the result of doing an unchecked
4407 -- conversion to convert the value to the corresponding record type.
4409 if Nkind (Concval) = N_Function_Call
4410 and then Is_Task_Type (Conctyp)
4411 and then Ada_Version >= Ada_2005
4412 then
4413 declare
4414 ExpR : constant Node_Id := Relocate_Node (Concval);
4415 Obj : constant Entity_Id := Make_Temporary (Loc, 'F', ExpR);
4416 Decl : Node_Id;
4418 begin
4419 Decl :=
4420 Make_Object_Declaration (Loc,
4421 Defining_Identifier => Obj,
4422 Object_Definition => New_Occurrence_Of (Conctyp, Loc),
4423 Expression => ExpR);
4424 Set_Etype (Obj, Conctyp);
4425 Decls := New_List (Decl);
4426 Rewrite (Concval, New_Occurrence_Of (Obj, Loc));
4427 end;
4429 else
4430 Decls := New_List;
4431 end if;
4433 Parm1 := Concurrent_Ref (Concval);
4435 -- Second parameter is the entry index, computed by the routine
4436 -- provided for this purpose. The value of this expression is
4437 -- assigned to an intermediate variable to assure that any entry
4438 -- family index expressions are evaluated before the entry
4439 -- parameters.
4441 if not Is_Protected_Type (Conctyp)
4442 or else
4443 Corresponding_Runtime_Package (Conctyp) =
4444 System_Tasking_Protected_Objects_Entries
4445 then
4446 X := Make_Defining_Identifier (Loc, Name_uX);
4448 Xdecl :=
4449 Make_Object_Declaration (Loc,
4450 Defining_Identifier => X,
4451 Object_Definition =>
4452 New_Occurrence_Of (RTE (RE_Task_Entry_Index), Loc),
4453 Expression => Actual_Index_Expression (
4454 Loc, Entity (Ename), Index, Concval));
4456 Append_To (Decls, Xdecl);
4457 Parm2 := New_Occurrence_Of (X, Loc);
4459 else
4460 Xdecl := Empty;
4461 Parm2 := Empty;
4462 end if;
4464 -- The third parameter is the packaged parameters. If there are
4465 -- none, then it is just the null address, since nothing is passed.
4467 if No (Parms) then
4468 Parm3 := New_Occurrence_Of (RTE (RE_Null_Address), Loc);
4469 P := Empty;
4471 -- Case of parameters present, where third argument is the address
4472 -- of a packaged record containing the required parameter values.
4474 else
4475 -- First build a list of parameter values, which are references to
4476 -- objects of the parameter types.
4478 Plist := New_List;
4480 Actual := First_Actual (N);
4481 Formal := First_Formal (Ent);
4482 while Present (Actual) loop
4484 -- If it is a by-copy type, copy it to a new variable. The
4485 -- packaged record has a field that points to this variable.
4487 if Is_By_Copy_Type (Etype (Actual)) then
4488 N_Node :=
4489 Make_Object_Declaration (Loc,
4490 Defining_Identifier => Make_Temporary (Loc, 'J'),
4491 Aliased_Present => True,
4492 Object_Definition =>
4493 New_Occurrence_Of (Etype (Formal), Loc));
4495 -- Mark the object as not needing initialization since the
4496 -- initialization is performed separately, avoiding errors
4497 -- on cases such as formals of null-excluding access types.
4499 Set_No_Initialization (N_Node);
4501 -- We must make a separate assignment statement for the
4502 -- case of limited types. We cannot assign it unless the
4503 -- Assignment_OK flag is set first. An out formal of an
4504 -- access type or whose type has a Default_Value must also
4505 -- be initialized from the actual (see RM 6.4.1 (13-13.1)),
4506 -- but no constraint, predicate, or null-exclusion check is
4507 -- applied before the call.
4509 if Ekind (Formal) /= E_Out_Parameter
4510 or else Is_Access_Type (Etype (Formal))
4511 or else
4512 (Is_Scalar_Type (Etype (Formal))
4513 and then
4514 Present (Default_Aspect_Value (Etype (Formal))))
4515 then
4516 N_Var :=
4517 New_Occurrence_Of (Defining_Identifier (N_Node), Loc);
4518 Set_Assignment_OK (N_Var);
4519 Append_To (Stats,
4520 Make_Assignment_Statement (Loc,
4521 Name => N_Var,
4522 Expression => Relocate_Node (Actual)));
4524 -- Mark the object as internal, so we don't later reset
4525 -- No_Initialization flag in Default_Initialize_Object,
4526 -- which would lead to needless default initialization.
4527 -- We don't set this outside the if statement, because
4528 -- out scalar parameters without Default_Value do require
4529 -- default initialization if Initialize_Scalars applies.
4531 Set_Is_Internal (Defining_Identifier (N_Node));
4533 -- If actual is an out parameter of a null-excluding
4534 -- access type, there is access check on entry, so set
4535 -- Suppress_Assignment_Checks on the generated statement
4536 -- that assigns the actual to the parameter block.
4538 Set_Suppress_Assignment_Checks (Last (Stats));
4539 end if;
4541 Append (N_Node, Decls);
4543 Append_To (Plist,
4544 Make_Attribute_Reference (Loc,
4545 Attribute_Name => Name_Unchecked_Access,
4546 Prefix =>
4547 New_Occurrence_Of
4548 (Defining_Identifier (N_Node), Loc)));
4550 else
4551 -- Interface class-wide formal
4553 if Ada_Version >= Ada_2005
4554 and then Ekind (Etype (Formal)) = E_Class_Wide_Type
4555 and then Is_Interface (Etype (Formal))
4556 then
4557 Iface_Typ := Etype (Etype (Formal));
4559 -- Generate:
4560 -- formal_iface_type! (actual.iface_tag)'reference
4562 Iface_Tag :=
4563 Find_Interface_Tag (Etype (Actual), Iface_Typ);
4564 pragma Assert (Present (Iface_Tag));
4566 Append_To (Plist,
4567 Make_Reference (Loc,
4568 Unchecked_Convert_To (Iface_Typ,
4569 Make_Selected_Component (Loc,
4570 Prefix =>
4571 Relocate_Node (Actual),
4572 Selector_Name =>
4573 New_Occurrence_Of (Iface_Tag, Loc)))));
4574 else
4575 -- Generate:
4576 -- actual'reference
4578 Append_To (Plist,
4579 Make_Reference (Loc, Relocate_Node (Actual)));
4580 end if;
4581 end if;
4583 Next_Actual (Actual);
4584 Next_Formal_With_Extras (Formal);
4585 end loop;
4587 -- Now build the declaration of parameters initialized with the
4588 -- aggregate containing this constructed parameter list.
4590 P := Make_Defining_Identifier (Loc, Name_uP);
4592 Pdecl :=
4593 Make_Object_Declaration (Loc,
4594 Defining_Identifier => P,
4595 Object_Definition =>
4596 New_Occurrence_Of (Designated_Type (Ent_Acc), Loc),
4597 Expression =>
4598 Make_Aggregate (Loc, Expressions => Plist));
4600 Parm3 :=
4601 Make_Attribute_Reference (Loc,
4602 Prefix => New_Occurrence_Of (P, Loc),
4603 Attribute_Name => Name_Address);
4605 Append (Pdecl, Decls);
4606 end if;
4608 -- Now we can create the call, case of protected type
4610 if Is_Protected_Type (Conctyp) then
4611 case Corresponding_Runtime_Package (Conctyp) is
4612 when System_Tasking_Protected_Objects_Entries =>
4614 -- Change the type of the index declaration
4616 Set_Object_Definition (Xdecl,
4617 New_Occurrence_Of (RTE (RE_Protected_Entry_Index), Loc));
4619 -- Some additional declarations for protected entry calls
4621 if No (Decls) then
4622 Decls := New_List;
4623 end if;
4625 -- Bnn : Communications_Block;
4627 Comm_Name := Make_Temporary (Loc, 'B');
4629 Append_To (Decls,
4630 Make_Object_Declaration (Loc,
4631 Defining_Identifier => Comm_Name,
4632 Object_Definition =>
4633 New_Occurrence_Of
4634 (RTE (RE_Communication_Block), Loc)));
4636 -- Some additional statements for protected entry calls
4638 -- Protected_Entry_Call
4639 -- (Object => po._object'Access,
4640 -- E => <entry index>;
4641 -- Uninterpreted_Data => P'Address;
4642 -- Mode => Simple_Call;
4643 -- Block => Bnn);
4645 Call :=
4646 Make_Procedure_Call_Statement (Loc,
4647 Name =>
4648 New_Occurrence_Of (RTE (RE_Protected_Entry_Call), Loc),
4650 Parameter_Associations => New_List (
4651 Make_Attribute_Reference (Loc,
4652 Attribute_Name => Name_Unchecked_Access,
4653 Prefix => Parm1),
4654 Parm2,
4655 Parm3,
4656 New_Occurrence_Of (RTE (RE_Simple_Call), Loc),
4657 New_Occurrence_Of (Comm_Name, Loc)));
4659 when System_Tasking_Protected_Objects_Single_Entry =>
4661 -- Protected_Single_Entry_Call
4662 -- (Object => po._object'Access,
4663 -- Uninterpreted_Data => P'Address);
4665 Call :=
4666 Make_Procedure_Call_Statement (Loc,
4667 Name =>
4668 New_Occurrence_Of
4669 (RTE (RE_Protected_Single_Entry_Call), Loc),
4671 Parameter_Associations => New_List (
4672 Make_Attribute_Reference (Loc,
4673 Attribute_Name => Name_Unchecked_Access,
4674 Prefix => Parm1),
4675 Parm3));
4677 when others =>
4678 raise Program_Error;
4679 end case;
4681 -- Case of task type
4683 else
4684 Call :=
4685 Make_Procedure_Call_Statement (Loc,
4686 Name =>
4687 New_Occurrence_Of (RTE (RE_Call_Simple), Loc),
4688 Parameter_Associations => New_List (Parm1, Parm2, Parm3));
4690 end if;
4692 Append_To (Stats, Call);
4694 -- If there are out or in/out parameters by copy add assignment
4695 -- statements for the result values.
4697 if Present (Parms) then
4698 Actual := First_Actual (N);
4699 Formal := First_Formal (Ent);
4701 Set_Assignment_OK (Actual);
4702 while Present (Actual) loop
4703 if Is_By_Copy_Type (Etype (Actual))
4704 and then Ekind (Formal) /= E_In_Parameter
4705 then
4706 N_Node :=
4707 Make_Assignment_Statement (Loc,
4708 Name => New_Copy (Actual),
4709 Expression =>
4710 Make_Explicit_Dereference (Loc,
4711 Make_Selected_Component (Loc,
4712 Prefix => New_Occurrence_Of (P, Loc),
4713 Selector_Name =>
4714 Make_Identifier (Loc, Chars (Formal)))));
4716 -- In all cases (including limited private types) we want
4717 -- the assignment to be valid.
4719 Set_Assignment_OK (Name (N_Node));
4721 -- If the call is the triggering alternative in an
4722 -- asynchronous select, or the entry_call alternative of a
4723 -- conditional entry call, the assignments for in-out
4724 -- parameters are incorporated into the statement list that
4725 -- follows, so that there are executed only if the entry
4726 -- call succeeds.
4728 if (Nkind (Parent (N)) = N_Triggering_Alternative
4729 and then N = Triggering_Statement (Parent (N)))
4730 or else
4731 (Nkind (Parent (N)) = N_Entry_Call_Alternative
4732 and then N = Entry_Call_Statement (Parent (N)))
4733 then
4734 if No (Statements (Parent (N))) then
4735 Set_Statements (Parent (N), New_List);
4736 end if;
4738 Prepend (N_Node, Statements (Parent (N)));
4740 else
4741 Insert_After (Call, N_Node);
4742 end if;
4743 end if;
4745 Next_Actual (Actual);
4746 Next_Formal_With_Extras (Formal);
4747 end loop;
4748 end if;
4750 -- Finally, create block and analyze it
4752 Rewrite (N,
4753 Make_Block_Statement (Loc,
4754 Declarations => Decls,
4755 Handled_Statement_Sequence =>
4756 Make_Handled_Sequence_Of_Statements (Loc,
4757 Statements => Stats)));
4759 Analyze (N);
4760 end;
4761 end Build_Simple_Entry_Call;
4763 --------------------------------
4764 -- Build_Task_Activation_Call --
4765 --------------------------------
4767 procedure Build_Task_Activation_Call (N : Node_Id) is
4768 function Activation_Call_Loc return Source_Ptr;
4769 -- Find a suitable source location for the activation call
4771 -------------------------
4772 -- Activation_Call_Loc --
4773 -------------------------
4775 function Activation_Call_Loc return Source_Ptr is
4776 begin
4777 -- The activation call must carry the location of the "end" keyword
4778 -- when the context is a package declaration.
4780 if Nkind (N) = N_Package_Declaration then
4781 return End_Keyword_Location (N);
4783 -- Otherwise the activation call must carry the location of the
4784 -- "begin" keyword.
4786 else
4787 return Begin_Keyword_Location (N);
4788 end if;
4789 end Activation_Call_Loc;
4791 -- Local variables
4793 Chain : Entity_Id;
4794 Call : Node_Id;
4795 Loc : Source_Ptr;
4796 Name : Node_Id;
4797 Owner : Node_Id;
4798 Stmt : Node_Id;
4800 -- Start of processing for Build_Task_Activation_Call
4802 begin
4803 -- For sequential elaboration policy, all the tasks will be activated at
4804 -- the end of the elaboration.
4806 if Partition_Elaboration_Policy = 'S' then
4807 return;
4809 -- Do not create an activation call for a package spec if the package
4810 -- has a completing body. The activation call will be inserted after
4811 -- the "begin" of the body.
4813 elsif Nkind (N) = N_Package_Declaration
4814 and then Present (Corresponding_Body (N))
4815 then
4816 return;
4817 end if;
4819 -- Obtain the activation chain entity. Block statements, entry bodies,
4820 -- subprogram bodies, and task bodies keep the entity in their nodes.
4821 -- Package bodies on the other hand store it in the declaration of the
4822 -- corresponding package spec.
4824 Owner := N;
4826 if Nkind (Owner) = N_Package_Body then
4827 Owner := Unit_Declaration_Node (Corresponding_Spec (Owner));
4828 end if;
4830 Chain := Activation_Chain_Entity (Owner);
4832 -- Nothing to do when there are no tasks to activate. This is indicated
4833 -- by a missing activation chain entity.
4835 if No (Chain) then
4836 return;
4837 end if;
4839 -- The location of the activation call must be as close as possible to
4840 -- the intended semantic location of the activation because the ABE
4841 -- mechanism relies heavily on accurate locations.
4843 Loc := Activation_Call_Loc;
4845 if Restricted_Profile then
4846 Name := New_Occurrence_Of (RTE (RE_Activate_Restricted_Tasks), Loc);
4847 else
4848 Name := New_Occurrence_Of (RTE (RE_Activate_Tasks), Loc);
4849 end if;
4851 Call :=
4852 Make_Procedure_Call_Statement (Loc,
4853 Name => Name,
4854 Parameter_Associations =>
4855 New_List (Make_Attribute_Reference (Loc,
4856 Prefix => New_Occurrence_Of (Chain, Loc),
4857 Attribute_Name => Name_Unchecked_Access)));
4859 if Nkind (N) = N_Package_Declaration then
4860 if Present (Private_Declarations (Specification (N))) then
4861 Append (Call, Private_Declarations (Specification (N)));
4862 else
4863 Append (Call, Visible_Declarations (Specification (N)));
4864 end if;
4866 else
4867 -- The call goes at the start of the statement sequence after the
4868 -- start of exception range label if one is present.
4870 if Present (Handled_Statement_Sequence (N)) then
4871 Stmt := First (Statements (Handled_Statement_Sequence (N)));
4873 -- A special case, skip exception range label if one is present
4874 -- (from front end zcx processing).
4876 if Nkind (Stmt) = N_Label and then Exception_Junk (Stmt) then
4877 Next (Stmt);
4878 end if;
4880 -- Another special case, if the first statement is a block from
4881 -- optimization of a local raise to a goto, then the call goes
4882 -- inside this block.
4884 if Nkind (Stmt) = N_Block_Statement
4885 and then Exception_Junk (Stmt)
4886 then
4887 Stmt := First (Statements (Handled_Statement_Sequence (Stmt)));
4888 end if;
4890 -- Insertion point is after any exception label pushes, since we
4891 -- want it covered by any local handlers.
4893 while Nkind (Stmt) in N_Push_xxx_Label loop
4894 Next (Stmt);
4895 end loop;
4897 -- Now we have the proper insertion point
4899 Insert_Before (Stmt, Call);
4901 else
4902 Set_Handled_Statement_Sequence (N,
4903 Make_Handled_Sequence_Of_Statements (Loc,
4904 Statements => New_List (Call)));
4905 end if;
4906 end if;
4908 Analyze (Call);
4910 if Legacy_Elaboration_Checks then
4911 Check_Task_Activation (N);
4912 end if;
4913 end Build_Task_Activation_Call;
4915 -------------------------------
4916 -- Build_Task_Allocate_Block --
4917 -------------------------------
4919 procedure Build_Task_Allocate_Block
4920 (Actions : List_Id;
4921 N : Node_Id;
4922 Args : List_Id)
4924 T : constant Entity_Id := Entity (Expression (N));
4925 Init : constant Entity_Id := Base_Init_Proc (T);
4926 Loc : constant Source_Ptr := Sloc (N);
4927 Chain : constant Entity_Id :=
4928 Make_Defining_Identifier (Loc, Name_uChain);
4929 Blkent : constant Entity_Id := Make_Temporary (Loc, 'A');
4930 Block : Node_Id;
4932 begin
4933 Block :=
4934 Make_Block_Statement (Loc,
4935 Identifier => New_Occurrence_Of (Blkent, Loc),
4936 Declarations => New_List (
4938 -- _Chain : Activation_Chain;
4940 Make_Object_Declaration (Loc,
4941 Defining_Identifier => Chain,
4942 Aliased_Present => True,
4943 Object_Definition =>
4944 New_Occurrence_Of (RTE (RE_Activation_Chain), Loc))),
4946 Handled_Statement_Sequence =>
4947 Make_Handled_Sequence_Of_Statements (Loc,
4949 Statements => New_List (
4951 -- Init (Args);
4953 Make_Procedure_Call_Statement (Loc,
4954 Name => New_Occurrence_Of (Init, Loc),
4955 Parameter_Associations => Args),
4957 -- Activate_Tasks (_Chain);
4959 Make_Procedure_Call_Statement (Loc,
4960 Name => New_Occurrence_Of (RTE (RE_Activate_Tasks), Loc),
4961 Parameter_Associations => New_List (
4962 Make_Attribute_Reference (Loc,
4963 Prefix => New_Occurrence_Of (Chain, Loc),
4964 Attribute_Name => Name_Unchecked_Access))))),
4966 Has_Created_Identifier => True,
4967 Is_Task_Allocation_Block => True);
4969 Append_To (Actions,
4970 Make_Implicit_Label_Declaration (Loc,
4971 Defining_Identifier => Blkent,
4972 Label_Construct => Block));
4974 Append_To (Actions, Block);
4976 Set_Activation_Chain_Entity (Block, Chain);
4977 end Build_Task_Allocate_Block;
4979 -----------------------------------------------
4980 -- Build_Task_Allocate_Block_With_Init_Stmts --
4981 -----------------------------------------------
4983 procedure Build_Task_Allocate_Block_With_Init_Stmts
4984 (Actions : List_Id;
4985 N : Node_Id;
4986 Init_Stmts : List_Id)
4988 Loc : constant Source_Ptr := Sloc (N);
4989 Chain : constant Entity_Id :=
4990 Make_Defining_Identifier (Loc, Name_uChain);
4991 Blkent : constant Entity_Id := Make_Temporary (Loc, 'A');
4992 Block : Node_Id;
4994 begin
4995 Append_To (Init_Stmts,
4996 Make_Procedure_Call_Statement (Loc,
4997 Name => New_Occurrence_Of (RTE (RE_Activate_Tasks), Loc),
4998 Parameter_Associations => New_List (
4999 Make_Attribute_Reference (Loc,
5000 Prefix => New_Occurrence_Of (Chain, Loc),
5001 Attribute_Name => Name_Unchecked_Access))));
5003 Block :=
5004 Make_Block_Statement (Loc,
5005 Identifier => New_Occurrence_Of (Blkent, Loc),
5006 Declarations => New_List (
5008 -- _Chain : Activation_Chain;
5010 Make_Object_Declaration (Loc,
5011 Defining_Identifier => Chain,
5012 Aliased_Present => True,
5013 Object_Definition =>
5014 New_Occurrence_Of (RTE (RE_Activation_Chain), Loc))),
5016 Handled_Statement_Sequence =>
5017 Make_Handled_Sequence_Of_Statements (Loc, Init_Stmts),
5019 Has_Created_Identifier => True,
5020 Is_Task_Allocation_Block => True);
5022 Append_To (Actions,
5023 Make_Implicit_Label_Declaration (Loc,
5024 Defining_Identifier => Blkent,
5025 Label_Construct => Block));
5027 Append_To (Actions, Block);
5029 Set_Activation_Chain_Entity (Block, Chain);
5030 end Build_Task_Allocate_Block_With_Init_Stmts;
5032 -----------------------------------
5033 -- Build_Task_Proc_Specification --
5034 -----------------------------------
5036 function Build_Task_Proc_Specification (T : Entity_Id) return Node_Id is
5037 Loc : constant Source_Ptr := Sloc (T);
5038 Spec_Id : Entity_Id;
5040 begin
5041 -- Case of explicit task type, suffix TB
5043 if Comes_From_Source (T) then
5044 Spec_Id :=
5045 Make_Defining_Identifier (Loc, New_External_Name (Chars (T), "TB"));
5047 -- Case of anonymous task type, suffix B
5049 else
5050 Spec_Id :=
5051 Make_Defining_Identifier (Loc, New_External_Name (Chars (T), 'B'));
5052 end if;
5054 Set_Is_Internal (Spec_Id);
5056 -- Associate the procedure with the task, if this is the declaration
5057 -- (and not the body) of the procedure.
5059 if No (Task_Body_Procedure (T)) then
5060 Set_Task_Body_Procedure (T, Spec_Id);
5061 end if;
5063 return
5064 Make_Procedure_Specification (Loc,
5065 Defining_Unit_Name => Spec_Id,
5066 Parameter_Specifications => New_List (
5067 Make_Parameter_Specification (Loc,
5068 Defining_Identifier =>
5069 Make_Defining_Identifier (Loc, Name_uTask),
5070 Parameter_Type =>
5071 Make_Access_Definition (Loc,
5072 Subtype_Mark =>
5073 New_Occurrence_Of (Corresponding_Record_Type (T), Loc)))));
5074 end Build_Task_Proc_Specification;
5076 ---------------------------------------
5077 -- Build_Unprotected_Subprogram_Body --
5078 ---------------------------------------
5080 function Build_Unprotected_Subprogram_Body
5081 (N : Node_Id;
5082 Pid : Node_Id) return Node_Id
5084 Decls : constant List_Id := Declarations (N);
5086 begin
5087 -- Add renamings for the Protection object, discriminals, privals, and
5088 -- the entry index constant for use by debugger.
5090 Debug_Private_Data_Declarations (Decls);
5092 -- Make an unprotected version of the subprogram for use within the same
5093 -- object, with a new name and an additional parameter representing the
5094 -- object.
5096 return
5097 Make_Subprogram_Body (Sloc (N),
5098 Specification =>
5099 Build_Protected_Sub_Specification (N, Pid, Unprotected_Mode),
5100 Declarations => Decls,
5101 Handled_Statement_Sequence => Handled_Statement_Sequence (N));
5102 end Build_Unprotected_Subprogram_Body;
5104 ----------------------------
5105 -- Collect_Entry_Families --
5106 ----------------------------
5108 procedure Collect_Entry_Families
5109 (Loc : Source_Ptr;
5110 Cdecls : List_Id;
5111 Current_Node : in out Node_Id;
5112 Conctyp : Entity_Id)
5114 Efam : Entity_Id;
5115 Efam_Decl : Node_Id;
5116 Efam_Type : Entity_Id;
5118 begin
5119 Efam := First_Entity (Conctyp);
5120 while Present (Efam) loop
5121 if Ekind (Efam) = E_Entry_Family then
5122 Efam_Type := Make_Temporary (Loc, 'F');
5124 declare
5125 Bas : Entity_Id :=
5126 Base_Type
5127 (Etype (Discrete_Subtype_Definition (Parent (Efam))));
5129 Bas_Decl : Node_Id := Empty;
5130 Lo, Hi : Node_Id;
5132 begin
5133 Get_Index_Bounds
5134 (Discrete_Subtype_Definition (Parent (Efam)), Lo, Hi);
5136 if Is_Potentially_Large_Family (Bas, Conctyp, Lo, Hi) then
5137 Bas := Make_Temporary (Loc, 'B');
5139 Bas_Decl :=
5140 Make_Subtype_Declaration (Loc,
5141 Defining_Identifier => Bas,
5142 Subtype_Indication =>
5143 Make_Subtype_Indication (Loc,
5144 Subtype_Mark =>
5145 New_Occurrence_Of (Standard_Integer, Loc),
5146 Constraint =>
5147 Make_Range_Constraint (Loc,
5148 Range_Expression => Make_Range (Loc,
5149 Make_Integer_Literal
5150 (Loc, -Entry_Family_Bound),
5151 Make_Integer_Literal
5152 (Loc, Entry_Family_Bound - 1)))));
5154 Insert_After (Current_Node, Bas_Decl);
5155 Current_Node := Bas_Decl;
5156 Analyze (Bas_Decl);
5157 end if;
5159 Efam_Decl :=
5160 Make_Full_Type_Declaration (Loc,
5161 Defining_Identifier => Efam_Type,
5162 Type_Definition =>
5163 Make_Unconstrained_Array_Definition (Loc,
5164 Subtype_Marks =>
5165 (New_List (New_Occurrence_Of (Bas, Loc))),
5167 Component_Definition =>
5168 Make_Component_Definition (Loc,
5169 Aliased_Present => False,
5170 Subtype_Indication =>
5171 New_Occurrence_Of (Standard_Character, Loc))));
5172 end;
5174 Insert_After (Current_Node, Efam_Decl);
5175 Current_Node := Efam_Decl;
5176 Analyze (Efam_Decl);
5178 Append_To (Cdecls,
5179 Make_Component_Declaration (Loc,
5180 Defining_Identifier =>
5181 Make_Defining_Identifier (Loc, Chars (Efam)),
5183 Component_Definition =>
5184 Make_Component_Definition (Loc,
5185 Aliased_Present => False,
5186 Subtype_Indication =>
5187 Make_Subtype_Indication (Loc,
5188 Subtype_Mark =>
5189 New_Occurrence_Of (Efam_Type, Loc),
5191 Constraint =>
5192 Make_Index_Or_Discriminant_Constraint (Loc,
5193 Constraints => New_List (
5194 New_Occurrence_Of
5195 (Etype (Discrete_Subtype_Definition
5196 (Parent (Efam))), Loc)))))));
5198 end if;
5200 Next_Entity (Efam);
5201 end loop;
5202 end Collect_Entry_Families;
5204 -----------------------
5205 -- Concurrent_Object --
5206 -----------------------
5208 function Concurrent_Object
5209 (Spec_Id : Entity_Id;
5210 Conc_Typ : Entity_Id) return Entity_Id
5212 begin
5213 -- Parameter _O or _object
5215 if Is_Protected_Type (Conc_Typ) then
5216 return First_Formal (Protected_Body_Subprogram (Spec_Id));
5218 -- Parameter _task
5220 else
5221 pragma Assert (Is_Task_Type (Conc_Typ));
5222 return First_Formal (Task_Body_Procedure (Conc_Typ));
5223 end if;
5224 end Concurrent_Object;
5226 ----------------------
5227 -- Copy_Result_Type --
5228 ----------------------
5230 function Copy_Result_Type (Res : Node_Id) return Node_Id is
5231 New_Res : constant Node_Id := New_Copy_Tree (Res);
5232 Par_Spec : Node_Id;
5233 Formal : Entity_Id;
5235 begin
5236 -- If the result type is an access_to_subprogram, we must create new
5237 -- entities for its spec.
5239 if Nkind (New_Res) = N_Access_Definition
5240 and then Present (Access_To_Subprogram_Definition (New_Res))
5241 then
5242 -- Provide new entities for the formals
5244 Par_Spec := First (Parameter_Specifications
5245 (Access_To_Subprogram_Definition (New_Res)));
5246 while Present (Par_Spec) loop
5247 Formal := Defining_Identifier (Par_Spec);
5248 Set_Defining_Identifier (Par_Spec,
5249 Make_Defining_Identifier (Sloc (Formal), Chars (Formal)));
5250 Next (Par_Spec);
5251 end loop;
5252 end if;
5254 return New_Res;
5255 end Copy_Result_Type;
5257 --------------------
5258 -- Concurrent_Ref --
5259 --------------------
5261 -- The expression returned for a reference to a concurrent object has the
5262 -- form:
5264 -- taskV!(name)._Task_Id
5266 -- for a task, and
5268 -- objectV!(name)._Object
5270 -- for a protected object. For the case of an access to a concurrent
5271 -- object, there is an extra explicit dereference:
5273 -- taskV!(name.all)._Task_Id
5274 -- objectV!(name.all)._Object
5276 -- here taskV and objectV are the types for the associated records, which
5277 -- contain the required _Task_Id and _Object fields for tasks and protected
5278 -- objects, respectively.
5280 -- For the case of a task type name, the expression is
5282 -- Self;
5284 -- i.e. a call to the Self function which returns precisely this Task_Id
5286 -- For the case of a protected type name, the expression is
5288 -- objectR
5290 -- which is a renaming of the _object field of the current object
5291 -- record, passed into protected operations as a parameter.
5293 function Concurrent_Ref (N : Node_Id) return Node_Id is
5294 Loc : constant Source_Ptr := Sloc (N);
5295 Ntyp : constant Entity_Id := Etype (N);
5296 Dtyp : Entity_Id;
5297 Sel : Name_Id;
5299 function Is_Current_Task (T : Entity_Id) return Boolean;
5300 -- Check whether the reference is to the immediately enclosing task
5301 -- type, or to an outer one (rare but legal).
5303 ---------------------
5304 -- Is_Current_Task --
5305 ---------------------
5307 function Is_Current_Task (T : Entity_Id) return Boolean is
5308 Scop : Entity_Id;
5310 begin
5311 Scop := Current_Scope;
5312 while Present (Scop) and then Scop /= Standard_Standard loop
5313 if Scop = T then
5314 return True;
5316 elsif Is_Task_Type (Scop) then
5317 return False;
5319 -- If this is a procedure nested within the task type, we must
5320 -- assume that it can be called from an inner task, and therefore
5321 -- cannot treat it as a local reference.
5323 elsif Is_Overloadable (Scop) and then In_Open_Scopes (T) then
5324 return False;
5326 else
5327 Scop := Scope (Scop);
5328 end if;
5329 end loop;
5331 -- We know that we are within the task body, so should have found it
5332 -- in scope.
5334 raise Program_Error;
5335 end Is_Current_Task;
5337 -- Start of processing for Concurrent_Ref
5339 begin
5340 if Is_Access_Type (Ntyp) then
5341 Dtyp := Designated_Type (Ntyp);
5343 if Is_Protected_Type (Dtyp) then
5344 Sel := Name_uObject;
5345 else
5346 Sel := Name_uTask_Id;
5347 end if;
5349 return
5350 Make_Selected_Component (Loc,
5351 Prefix =>
5352 Unchecked_Convert_To (Corresponding_Record_Type (Dtyp),
5353 Make_Explicit_Dereference (Loc, N)),
5354 Selector_Name => Make_Identifier (Loc, Sel));
5356 elsif Is_Entity_Name (N) and then Is_Concurrent_Type (Entity (N)) then
5357 if Is_Task_Type (Entity (N)) then
5359 if Is_Current_Task (Entity (N)) then
5360 return
5361 Make_Function_Call (Loc,
5362 Name => New_Occurrence_Of (RTE (RE_Self), Loc));
5364 else
5365 declare
5366 Decl : Node_Id;
5367 T_Self : constant Entity_Id := Make_Temporary (Loc, 'T');
5368 T_Body : constant Node_Id :=
5369 Parent (Corresponding_Body (Parent (Entity (N))));
5371 begin
5372 Decl :=
5373 Make_Object_Declaration (Loc,
5374 Defining_Identifier => T_Self,
5375 Object_Definition =>
5376 New_Occurrence_Of (RTE (RO_ST_Task_Id), Loc),
5377 Expression =>
5378 Make_Function_Call (Loc,
5379 Name => New_Occurrence_Of (RTE (RE_Self), Loc)));
5380 Prepend (Decl, Declarations (T_Body));
5381 Analyze (Decl);
5382 Set_Scope (T_Self, Entity (N));
5383 return New_Occurrence_Of (T_Self, Loc);
5384 end;
5385 end if;
5387 else
5388 pragma Assert (Is_Protected_Type (Entity (N)));
5390 return
5391 New_Occurrence_Of (Find_Protection_Object (Current_Scope), Loc);
5392 end if;
5394 else
5395 if Is_Protected_Type (Ntyp) then
5396 Sel := Name_uObject;
5397 elsif Is_Task_Type (Ntyp) then
5398 Sel := Name_uTask_Id;
5399 else
5400 raise Program_Error;
5401 end if;
5403 return
5404 Make_Selected_Component (Loc,
5405 Prefix =>
5406 Unchecked_Convert_To (Corresponding_Record_Type (Ntyp),
5407 New_Copy_Tree (N)),
5408 Selector_Name => Make_Identifier (Loc, Sel));
5409 end if;
5410 end Concurrent_Ref;
5412 ------------------------
5413 -- Convert_Concurrent --
5414 ------------------------
5416 function Convert_Concurrent
5417 (N : Node_Id;
5418 Typ : Entity_Id) return Node_Id
5420 begin
5421 if not Is_Concurrent_Type (Typ) then
5422 return N;
5423 else
5424 return
5425 Unchecked_Convert_To
5426 (Corresponding_Record_Type (Typ), New_Copy_Tree (N));
5427 end if;
5428 end Convert_Concurrent;
5430 -------------------------------------
5431 -- Create_Secondary_Stack_For_Task --
5432 -------------------------------------
5434 function Create_Secondary_Stack_For_Task (T : Node_Id) return Boolean is
5435 begin
5436 return
5437 (Restriction_Active (No_Implicit_Heap_Allocations)
5438 or else Restriction_Active (No_Implicit_Task_Allocations))
5439 and then not Restriction_Active (No_Secondary_Stack)
5440 and then Has_Rep_Pragma
5441 (T, Name_Secondary_Stack_Size, Check_Parents => False);
5442 end Create_Secondary_Stack_For_Task;
5444 -------------------------------------
5445 -- Debug_Private_Data_Declarations --
5446 -------------------------------------
5448 procedure Debug_Private_Data_Declarations (Decls : List_Id) is
5449 Debug_Nod : Node_Id;
5450 Decl : Node_Id;
5452 begin
5453 Decl := First (Decls);
5454 while Present (Decl) and then not Comes_From_Source (Decl) loop
5456 -- Declaration for concurrent entity _object and its access type,
5457 -- along with the entry index subtype:
5458 -- type prot_typVP is access prot_typV;
5459 -- _object : prot_typVP := prot_typV (_O);
5460 -- subtype Jnn is <Type of Index> range Low .. High;
5462 if Nkind_In (Decl, N_Full_Type_Declaration, N_Object_Declaration) then
5463 Set_Debug_Info_Needed (Defining_Identifier (Decl));
5465 -- Declaration for the Protection object, discriminals, privals, and
5466 -- entry index constant:
5467 -- conc_typR : protection_typ renames _object._object;
5468 -- discr_nameD : discr_typ renames _object.discr_name;
5469 -- discr_nameD : discr_typ renames _task.discr_name;
5470 -- prival_name : comp_typ renames _object.comp_name;
5471 -- J : constant Jnn :=
5472 -- Jnn'Val (_E - <Index expression> + Jnn'Pos (Jnn'First));
5474 elsif Nkind (Decl) = N_Object_Renaming_Declaration then
5475 Set_Debug_Info_Needed (Defining_Identifier (Decl));
5476 Debug_Nod := Debug_Renaming_Declaration (Decl);
5478 if Present (Debug_Nod) then
5479 Insert_After (Decl, Debug_Nod);
5480 end if;
5481 end if;
5483 Next (Decl);
5484 end loop;
5485 end Debug_Private_Data_Declarations;
5487 ------------------------------
5488 -- Ensure_Statement_Present --
5489 ------------------------------
5491 procedure Ensure_Statement_Present (Loc : Source_Ptr; Alt : Node_Id) is
5492 Stmt : Node_Id;
5494 begin
5495 if Opt.Suppress_Control_Flow_Optimizations
5496 and then Is_Empty_List (Statements (Alt))
5497 then
5498 Stmt := Make_Null_Statement (Loc);
5500 -- Mark NULL statement as coming from source so that it is not
5501 -- eliminated by GIGI.
5503 -- Another covert channel. If this is a requirement, it must be
5504 -- documented in sinfo/einfo ???
5506 Set_Comes_From_Source (Stmt, True);
5508 Set_Statements (Alt, New_List (Stmt));
5509 end if;
5510 end Ensure_Statement_Present;
5512 ----------------------------
5513 -- Entry_Index_Expression --
5514 ----------------------------
5516 function Entry_Index_Expression
5517 (Sloc : Source_Ptr;
5518 Ent : Entity_Id;
5519 Index : Node_Id;
5520 Ttyp : Entity_Id) return Node_Id
5522 Expr : Node_Id;
5523 Num : Node_Id;
5524 Lo : Node_Id;
5525 Hi : Node_Id;
5526 Prev : Entity_Id;
5527 S : Node_Id;
5529 begin
5530 -- The queues of entries and entry families appear in textual order in
5531 -- the associated record. The entry index is computed as the sum of the
5532 -- number of queues for all entries that precede the designated one, to
5533 -- which is added the index expression, if this expression denotes a
5534 -- member of a family.
5536 -- The following is a place holder for the count of simple entries
5538 Num := Make_Integer_Literal (Sloc, 1);
5540 -- We construct an expression which is a series of addition operations.
5541 -- The first operand is the number of single entries that precede this
5542 -- one, the second operand is the index value relative to the start of
5543 -- the referenced family, and the remaining operands are the lengths of
5544 -- the entry families that precede this entry, i.e. the constructed
5545 -- expression is:
5547 -- number_simple_entries +
5548 -- (s'pos (index-value) - s'pos (family'first)) + 1 +
5549 -- family'length + ...
5551 -- where index-value is the given index value, and s is the index
5552 -- subtype (we have to use pos because the subtype might be an
5553 -- enumeration type preventing direct subtraction). Note that the task
5554 -- entry array is one-indexed.
5556 -- The upper bound of the entry family may be a discriminant, so we
5557 -- retrieve the lower bound explicitly to compute offset, rather than
5558 -- using the index subtype which may mention a discriminant.
5560 if Present (Index) then
5561 S := Etype (Discrete_Subtype_Definition (Declaration_Node (Ent)));
5563 Expr :=
5564 Make_Op_Add (Sloc,
5565 Left_Opnd => Num,
5566 Right_Opnd =>
5567 Family_Offset
5568 (Sloc,
5569 Make_Attribute_Reference (Sloc,
5570 Attribute_Name => Name_Pos,
5571 Prefix => New_Occurrence_Of (Base_Type (S), Sloc),
5572 Expressions => New_List (Relocate_Node (Index))),
5573 Type_Low_Bound (S),
5574 Ttyp,
5575 False));
5576 else
5577 Expr := Num;
5578 end if;
5580 -- Now add lengths of preceding entries and entry families
5582 Prev := First_Entity (Ttyp);
5583 while Chars (Prev) /= Chars (Ent)
5584 or else (Ekind (Prev) /= Ekind (Ent))
5585 or else not Sem_Ch6.Type_Conformant (Ent, Prev)
5586 loop
5587 if Ekind (Prev) = E_Entry then
5588 Set_Intval (Num, Intval (Num) + 1);
5590 elsif Ekind (Prev) = E_Entry_Family then
5591 S := Etype (Discrete_Subtype_Definition (Declaration_Node (Prev)));
5592 Lo := Type_Low_Bound (S);
5593 Hi := Type_High_Bound (S);
5595 Expr :=
5596 Make_Op_Add (Sloc,
5597 Left_Opnd => Expr,
5598 Right_Opnd => Family_Size (Sloc, Hi, Lo, Ttyp, False));
5600 -- Other components are anonymous types to be ignored
5602 else
5603 null;
5604 end if;
5606 Next_Entity (Prev);
5607 end loop;
5609 return Expr;
5610 end Entry_Index_Expression;
5612 ---------------------------
5613 -- Establish_Task_Master --
5614 ---------------------------
5616 procedure Establish_Task_Master (N : Node_Id) is
5617 Call : Node_Id;
5619 begin
5620 if Restriction_Active (No_Task_Hierarchy) = False then
5621 Call := Build_Runtime_Call (Sloc (N), RE_Enter_Master);
5623 -- The block may have no declarations (and nevertheless be a task
5624 -- master) if it contains a call that may return an object that
5625 -- contains tasks.
5627 if No (Declarations (N)) then
5628 Set_Declarations (N, New_List (Call));
5629 else
5630 Prepend_To (Declarations (N), Call);
5631 end if;
5633 Analyze (Call);
5634 end if;
5635 end Establish_Task_Master;
5637 --------------------------------
5638 -- Expand_Accept_Declarations --
5639 --------------------------------
5641 -- Part of the expansion of an accept statement involves the creation of
5642 -- a declaration that can be referenced from the statement sequence of
5643 -- the accept:
5645 -- Ann : Address;
5647 -- This declaration is inserted immediately before the accept statement
5648 -- and it is important that it be inserted before the statements of the
5649 -- statement sequence are analyzed. Thus it would be too late to create
5650 -- this declaration in the Expand_N_Accept_Statement routine, which is
5651 -- why there is a separate procedure to be called directly from Sem_Ch9.
5653 -- Ann is used to hold the address of the record containing the parameters
5654 -- (see Expand_N_Entry_Call for more details on how this record is built).
5655 -- References to the parameters do an unchecked conversion of this address
5656 -- to a pointer to the required record type, and then access the field that
5657 -- holds the value of the required parameter. The entity for the address
5658 -- variable is held as the top stack element (i.e. the last element) of the
5659 -- Accept_Address stack in the corresponding entry entity, and this element
5660 -- must be set in place before the statements are processed.
5662 -- The above description applies to the case of a stand alone accept
5663 -- statement, i.e. one not appearing as part of a select alternative.
5665 -- For the case of an accept that appears as part of a select alternative
5666 -- of a selective accept, we must still create the declaration right away,
5667 -- since Ann is needed immediately, but there is an important difference:
5669 -- The declaration is inserted before the selective accept, not before
5670 -- the accept statement (which is not part of a list anyway, and so would
5671 -- not accommodate inserted declarations)
5673 -- We only need one address variable for the entire selective accept. So
5674 -- the Ann declaration is created only for the first accept alternative,
5675 -- and subsequent accept alternatives reference the same Ann variable.
5677 -- We can distinguish the two cases by seeing whether the accept statement
5678 -- is part of a list. If not, then it must be in an accept alternative.
5680 -- To expand the requeue statement, a label is provided at the end of the
5681 -- accept statement or alternative of which it is a part, so that the
5682 -- statement can be skipped after the requeue is complete. This label is
5683 -- created here rather than during the expansion of the accept statement,
5684 -- because it will be needed by any requeue statements within the accept,
5685 -- which are expanded before the accept.
5687 procedure Expand_Accept_Declarations (N : Node_Id; Ent : Entity_Id) is
5688 Loc : constant Source_Ptr := Sloc (N);
5689 Stats : constant Node_Id := Handled_Statement_Sequence (N);
5690 Ann : Entity_Id := Empty;
5691 Adecl : Node_Id;
5692 Lab : Node_Id;
5693 Ldecl : Node_Id;
5694 Ldecl2 : Node_Id;
5696 begin
5697 if Expander_Active then
5699 -- If we have no handled statement sequence, we may need to build
5700 -- a dummy sequence consisting of a null statement. This can be
5701 -- skipped if the trivial accept optimization is permitted.
5703 if not Trivial_Accept_OK
5704 and then (No (Stats) or else Null_Statements (Statements (Stats)))
5705 then
5706 Set_Handled_Statement_Sequence (N,
5707 Make_Handled_Sequence_Of_Statements (Loc,
5708 Statements => New_List (Make_Null_Statement (Loc))));
5709 end if;
5711 -- Create and declare two labels to be placed at the end of the
5712 -- accept statement. The first label is used to allow requeues to
5713 -- skip the remainder of entry processing. The second label is used
5714 -- to skip the remainder of entry processing if the rendezvous
5715 -- completes in the middle of the accept body.
5717 if Present (Handled_Statement_Sequence (N)) then
5718 declare
5719 Ent : Entity_Id;
5721 begin
5722 Ent := Make_Temporary (Loc, 'L');
5723 Lab := Make_Label (Loc, New_Occurrence_Of (Ent, Loc));
5724 Ldecl :=
5725 Make_Implicit_Label_Declaration (Loc,
5726 Defining_Identifier => Ent,
5727 Label_Construct => Lab);
5728 Append (Lab, Statements (Handled_Statement_Sequence (N)));
5730 Ent := Make_Temporary (Loc, 'L');
5731 Lab := Make_Label (Loc, New_Occurrence_Of (Ent, Loc));
5732 Ldecl2 :=
5733 Make_Implicit_Label_Declaration (Loc,
5734 Defining_Identifier => Ent,
5735 Label_Construct => Lab);
5736 Append (Lab, Statements (Handled_Statement_Sequence (N)));
5737 end;
5739 else
5740 Ldecl := Empty;
5741 Ldecl2 := Empty;
5742 end if;
5744 -- Case of stand alone accept statement
5746 if Is_List_Member (N) then
5748 if Present (Handled_Statement_Sequence (N)) then
5749 Ann := Make_Temporary (Loc, 'A');
5751 Adecl :=
5752 Make_Object_Declaration (Loc,
5753 Defining_Identifier => Ann,
5754 Object_Definition =>
5755 New_Occurrence_Of (RTE (RE_Address), Loc));
5757 Insert_Before_And_Analyze (N, Adecl);
5758 Insert_Before_And_Analyze (N, Ldecl);
5759 Insert_Before_And_Analyze (N, Ldecl2);
5760 end if;
5762 -- Case of accept statement which is in an accept alternative
5764 else
5765 declare
5766 Acc_Alt : constant Node_Id := Parent (N);
5767 Sel_Acc : constant Node_Id := Parent (Acc_Alt);
5768 Alt : Node_Id;
5770 begin
5771 pragma Assert (Nkind (Acc_Alt) = N_Accept_Alternative);
5772 pragma Assert (Nkind (Sel_Acc) = N_Selective_Accept);
5774 -- ??? Consider a single label for select statements
5776 if Present (Handled_Statement_Sequence (N)) then
5777 Prepend (Ldecl2,
5778 Statements (Handled_Statement_Sequence (N)));
5779 Analyze (Ldecl2);
5781 Prepend (Ldecl,
5782 Statements (Handled_Statement_Sequence (N)));
5783 Analyze (Ldecl);
5784 end if;
5786 -- Find first accept alternative of the selective accept. A
5787 -- valid selective accept must have at least one accept in it.
5789 Alt := First (Select_Alternatives (Sel_Acc));
5791 while Nkind (Alt) /= N_Accept_Alternative loop
5792 Next (Alt);
5793 end loop;
5795 -- If this is the first accept statement, then we have to
5796 -- create the Ann variable, as for the stand alone case, except
5797 -- that it is inserted before the selective accept. Similarly,
5798 -- a label for requeue expansion must be declared.
5800 if N = Accept_Statement (Alt) then
5801 Ann := Make_Temporary (Loc, 'A');
5802 Adecl :=
5803 Make_Object_Declaration (Loc,
5804 Defining_Identifier => Ann,
5805 Object_Definition =>
5806 New_Occurrence_Of (RTE (RE_Address), Loc));
5808 Insert_Before_And_Analyze (Sel_Acc, Adecl);
5810 -- If this is not the first accept statement, then find the Ann
5811 -- variable allocated by the first accept and use it.
5813 else
5814 Ann :=
5815 Node (Last_Elmt (Accept_Address
5816 (Entity (Entry_Direct_Name (Accept_Statement (Alt))))));
5817 end if;
5818 end;
5819 end if;
5821 -- Merge here with Ann either created or referenced, and Adecl
5822 -- pointing to the corresponding declaration. Remaining processing
5823 -- is the same for the two cases.
5825 if Present (Ann) then
5826 Append_Elmt (Ann, Accept_Address (Ent));
5827 Set_Debug_Info_Needed (Ann);
5828 end if;
5830 -- Create renaming declarations for the entry formals. Each reference
5831 -- to a formal becomes a dereference of a component of the parameter
5832 -- block, whose address is held in Ann. These declarations are
5833 -- eventually inserted into the accept block, and analyzed there so
5834 -- that they have the proper scope for gdb and do not conflict with
5835 -- other declarations.
5837 if Present (Parameter_Specifications (N))
5838 and then Present (Handled_Statement_Sequence (N))
5839 then
5840 declare
5841 Comp : Entity_Id;
5842 Decl : Node_Id;
5843 Formal : Entity_Id;
5844 New_F : Entity_Id;
5845 Renamed_Formal : Node_Id;
5847 begin
5848 Push_Scope (Ent);
5849 Formal := First_Formal (Ent);
5851 while Present (Formal) loop
5852 Comp := Entry_Component (Formal);
5853 New_F := Make_Defining_Identifier (Loc, Chars (Formal));
5855 Set_Etype (New_F, Etype (Formal));
5856 Set_Scope (New_F, Ent);
5858 -- Now we set debug info needed on New_F even though it does
5859 -- not come from source, so that the debugger will get the
5860 -- right information for these generated names.
5862 Set_Debug_Info_Needed (New_F);
5864 if Ekind (Formal) = E_In_Parameter then
5865 Set_Ekind (New_F, E_Constant);
5866 else
5867 Set_Ekind (New_F, E_Variable);
5868 Set_Extra_Constrained (New_F, Extra_Constrained (Formal));
5869 end if;
5871 Set_Actual_Subtype (New_F, Actual_Subtype (Formal));
5873 Renamed_Formal :=
5874 Make_Selected_Component (Loc,
5875 Prefix =>
5876 Unchecked_Convert_To (
5877 Entry_Parameters_Type (Ent),
5878 New_Occurrence_Of (Ann, Loc)),
5879 Selector_Name =>
5880 New_Occurrence_Of (Comp, Loc));
5882 Decl :=
5883 Build_Renamed_Formal_Declaration
5884 (New_F, Formal, Comp, Renamed_Formal);
5886 if No (Declarations (N)) then
5887 Set_Declarations (N, New_List);
5888 end if;
5890 Append (Decl, Declarations (N));
5891 Set_Renamed_Object (Formal, New_F);
5892 Next_Formal (Formal);
5893 end loop;
5895 End_Scope;
5896 end;
5897 end if;
5898 end if;
5899 end Expand_Accept_Declarations;
5901 ---------------------------------------------
5902 -- Expand_Access_Protected_Subprogram_Type --
5903 ---------------------------------------------
5905 procedure Expand_Access_Protected_Subprogram_Type (N : Node_Id) is
5906 Loc : constant Source_Ptr := Sloc (N);
5907 T : constant Entity_Id := Defining_Identifier (N);
5908 D_T : constant Entity_Id := Designated_Type (T);
5909 D_T2 : constant Entity_Id := Make_Temporary (Loc, 'D');
5910 E_T : constant Entity_Id := Make_Temporary (Loc, 'E');
5911 P_List : constant List_Id :=
5912 Build_Protected_Spec (N, RTE (RE_Address), D_T, False);
5914 Comps : List_Id;
5915 Decl1 : Node_Id;
5916 Decl2 : Node_Id;
5917 Def1 : Node_Id;
5919 begin
5920 -- Create access to subprogram with full signature
5922 if Etype (D_T) /= Standard_Void_Type then
5923 Def1 :=
5924 Make_Access_Function_Definition (Loc,
5925 Parameter_Specifications => P_List,
5926 Result_Definition =>
5927 Copy_Result_Type (Result_Definition (Type_Definition (N))));
5929 else
5930 Def1 :=
5931 Make_Access_Procedure_Definition (Loc,
5932 Parameter_Specifications => P_List);
5933 end if;
5935 Decl1 :=
5936 Make_Full_Type_Declaration (Loc,
5937 Defining_Identifier => D_T2,
5938 Type_Definition => Def1);
5940 -- Declare the new types before the original one since the latter will
5941 -- refer to them through the Equivalent_Type slot.
5943 Insert_Before_And_Analyze (N, Decl1);
5945 -- Associate the access to subprogram with its original access to
5946 -- protected subprogram type. Needed by the backend to know that this
5947 -- type corresponds with an access to protected subprogram type.
5949 Set_Original_Access_Type (D_T2, T);
5951 -- Create Equivalent_Type, a record with two components for an access to
5952 -- object and an access to subprogram.
5954 Comps := New_List (
5955 Make_Component_Declaration (Loc,
5956 Defining_Identifier => Make_Temporary (Loc, 'P'),
5957 Component_Definition =>
5958 Make_Component_Definition (Loc,
5959 Aliased_Present => False,
5960 Subtype_Indication =>
5961 New_Occurrence_Of (RTE (RE_Address), Loc))),
5963 Make_Component_Declaration (Loc,
5964 Defining_Identifier => Make_Temporary (Loc, 'S'),
5965 Component_Definition =>
5966 Make_Component_Definition (Loc,
5967 Aliased_Present => False,
5968 Subtype_Indication => New_Occurrence_Of (D_T2, Loc))));
5970 Decl2 :=
5971 Make_Full_Type_Declaration (Loc,
5972 Defining_Identifier => E_T,
5973 Type_Definition =>
5974 Make_Record_Definition (Loc,
5975 Component_List =>
5976 Make_Component_List (Loc, Component_Items => Comps)));
5978 Insert_Before_And_Analyze (N, Decl2);
5979 Set_Equivalent_Type (T, E_T);
5980 end Expand_Access_Protected_Subprogram_Type;
5982 --------------------------
5983 -- Expand_Entry_Barrier --
5984 --------------------------
5986 procedure Expand_Entry_Barrier (N : Node_Id; Ent : Entity_Id) is
5987 Cond : constant Node_Id := Condition (Entry_Body_Formal_Part (N));
5988 Prot : constant Entity_Id := Scope (Ent);
5989 Spec_Decl : constant Node_Id := Parent (Prot);
5991 Func_Id : Entity_Id := Empty;
5992 -- The entity of the barrier function
5994 function Is_Global_Entity (N : Node_Id) return Traverse_Result;
5995 -- Check whether entity in Barrier is external to protected type.
5996 -- If so, barrier may not be properly synchronized.
5998 function Is_Pure_Barrier (N : Node_Id) return Traverse_Result;
5999 -- Check whether N follows the Pure_Barriers restriction. Return OK if
6000 -- so.
6002 function Is_Simple_Barrier_Name (N : Node_Id) return Boolean;
6003 -- Check whether entity name N denotes a component of the protected
6004 -- object. This is used to check the Simple_Barrier restriction.
6006 ----------------------
6007 -- Is_Global_Entity --
6008 ----------------------
6010 function Is_Global_Entity (N : Node_Id) return Traverse_Result is
6011 E : Entity_Id;
6012 S : Entity_Id;
6014 begin
6015 if Is_Entity_Name (N) and then Present (Entity (N)) then
6016 E := Entity (N);
6017 S := Scope (E);
6019 if Ekind (E) = E_Variable then
6021 -- If the variable is local to the barrier function generated
6022 -- during expansion, it is ok. If expansion is not performed,
6023 -- then Func is Empty so this test cannot succeed.
6025 if Scope (E) = Func_Id then
6026 null;
6028 -- A protected call from a barrier to another object is ok
6030 elsif Ekind (Etype (E)) = E_Protected_Type then
6031 null;
6033 -- If the variable is within the package body we consider
6034 -- this safe. This is a common (if dubious) idiom.
6036 elsif S = Scope (Prot)
6037 and then Ekind_In (S, E_Package, E_Generic_Package)
6038 and then Nkind (Parent (E)) = N_Object_Declaration
6039 and then Nkind (Parent (Parent (E))) = N_Package_Body
6040 then
6041 null;
6043 else
6044 Error_Msg_N ("potentially unsynchronized barrier??", N);
6045 Error_Msg_N ("\& should be private component of type??", N);
6046 end if;
6047 end if;
6048 end if;
6050 return OK;
6051 end Is_Global_Entity;
6053 procedure Check_Unprotected_Barrier is
6054 new Traverse_Proc (Is_Global_Entity);
6056 ----------------------------
6057 -- Is_Simple_Barrier_Name --
6058 ----------------------------
6060 function Is_Simple_Barrier_Name (N : Node_Id) return Boolean is
6061 Renamed : Node_Id;
6063 begin
6064 -- Check if the name is a component of the protected object. If
6065 -- the expander is active, the component has been transformed into a
6066 -- renaming of _object.all.component. Original_Node is needed in case
6067 -- validity checking is enabled, in which case the simple object
6068 -- reference will have been rewritten.
6070 if Expander_Active then
6072 -- The expanded name may have been constant folded in which case
6073 -- the original node is not necessarily an entity name (e.g. an
6074 -- indexed component).
6076 if not Is_Entity_Name (Original_Node (N)) then
6077 return False;
6078 end if;
6080 Renamed := Renamed_Object (Entity (Original_Node (N)));
6082 return
6083 Present (Renamed)
6084 and then Nkind (Renamed) = N_Selected_Component
6085 and then Chars (Prefix (Prefix (Renamed))) = Name_uObject;
6086 else
6087 return Is_Protected_Component (Entity (N));
6088 end if;
6089 end Is_Simple_Barrier_Name;
6091 ---------------------
6092 -- Is_Pure_Barrier --
6093 ---------------------
6095 function Is_Pure_Barrier (N : Node_Id) return Traverse_Result is
6096 begin
6097 case Nkind (N) is
6098 when N_Expanded_Name
6099 | N_Identifier
6101 if No (Entity (N)) then
6102 return Abandon;
6104 elsif Is_Universal_Numeric_Type (Entity (N)) then
6105 return OK;
6106 end if;
6108 case Ekind (Entity (N)) is
6109 when E_Constant
6110 | E_Discriminant
6111 | E_Enumeration_Literal
6112 | E_Named_Integer
6113 | E_Named_Real
6115 return OK;
6117 when E_Component =>
6118 return OK;
6120 when E_Variable =>
6121 if Is_Simple_Barrier_Name (N) then
6122 return OK;
6123 end if;
6125 when E_Function =>
6127 -- The count attribute has been transformed into run-time
6128 -- calls.
6130 if Is_RTE (Entity (N), RE_Protected_Count)
6131 or else Is_RTE (Entity (N), RE_Protected_Count_Entry)
6132 then
6133 return OK;
6134 end if;
6136 when others =>
6137 null;
6138 end case;
6140 when N_Function_Call =>
6142 -- Function call checks are carried out as part of the analysis
6143 -- of the function call name.
6145 return OK;
6147 when N_Character_Literal
6148 | N_Integer_Literal
6149 | N_Real_Literal
6151 return OK;
6153 when N_Op_Boolean
6154 | N_Op_Not
6156 if Ekind (Entity (N)) = E_Operator then
6157 return OK;
6158 end if;
6160 when N_Short_Circuit =>
6161 return OK;
6163 when N_Indexed_Component
6164 | N_Selected_Component
6166 if not Is_Access_Type (Etype (Prefix (N))) then
6167 return OK;
6168 end if;
6170 when N_Type_Conversion =>
6172 -- Conversions to Universal_Integer will not raise constraint
6173 -- errors.
6175 if Cannot_Raise_Constraint_Error (N)
6176 or else Etype (N) = Universal_Integer
6177 then
6178 return OK;
6179 end if;
6181 when N_Unchecked_Type_Conversion =>
6182 return OK;
6184 when others =>
6185 null;
6186 end case;
6188 return Abandon;
6189 end Is_Pure_Barrier;
6191 function Check_Pure_Barriers is new Traverse_Func (Is_Pure_Barrier);
6193 -- Local variables
6195 Cond_Id : Entity_Id;
6196 Entry_Body : Node_Id;
6197 Func_Body : Node_Id := Empty;
6199 -- Start of processing for Expand_Entry_Barrier
6201 begin
6202 if No_Run_Time_Mode then
6203 Error_Msg_CRT ("entry barrier", N);
6204 return;
6205 end if;
6207 -- The body of the entry barrier must be analyzed in the context of the
6208 -- protected object, but its scope is external to it, just as any other
6209 -- unprotected version of a protected operation. The specification has
6210 -- been produced when the protected type declaration was elaborated. We
6211 -- build the body, insert it in the enclosing scope, but analyze it in
6212 -- the current context. A more uniform approach would be to treat the
6213 -- barrier just as a protected function, and discard the protected
6214 -- version of it because it is never called.
6216 if Expander_Active then
6217 Func_Body := Build_Barrier_Function (N, Ent, Prot);
6218 Func_Id := Barrier_Function (Ent);
6219 Set_Corresponding_Spec (Func_Body, Func_Id);
6221 Entry_Body := Parent (Corresponding_Body (Spec_Decl));
6223 if Nkind (Parent (Entry_Body)) = N_Subunit then
6224 Entry_Body := Corresponding_Stub (Parent (Entry_Body));
6225 end if;
6227 Insert_Before_And_Analyze (Entry_Body, Func_Body);
6229 Set_Discriminals (Spec_Decl);
6230 Set_Scope (Func_Id, Scope (Prot));
6232 else
6233 Analyze_And_Resolve (Cond, Any_Boolean);
6234 end if;
6236 -- Check Pure_Barriers restriction
6238 if Check_Pure_Barriers (Cond) = Abandon then
6239 Check_Restriction (Pure_Barriers, Cond);
6240 end if;
6242 -- The Ravenscar profile restricts barriers to simple variables declared
6243 -- within the protected object. We also allow Boolean constants, since
6244 -- these appear in several published examples and are also allowed by
6245 -- other compilers.
6247 -- Note that after analysis variables in this context will be replaced
6248 -- by the corresponding prival, that is to say a renaming of a selected
6249 -- component of the form _Object.Var. If expansion is disabled, as
6250 -- within a generic, we check that the entity appears in the current
6251 -- scope.
6253 if Is_Entity_Name (Cond) then
6254 Cond_Id := Entity (Cond);
6256 -- Perform a small optimization of simple barrier functions. If the
6257 -- scope of the condition's entity is not the barrier function, then
6258 -- the condition does not depend on any of the generated renamings.
6259 -- If this is the case, eliminate the renamings as they are useless.
6260 -- This optimization is not performed when the condition was folded
6261 -- and validity checks are in effect because the original condition
6262 -- may have produced at least one check that depends on the generated
6263 -- renamings.
6265 if Expander_Active
6266 and then Scope (Cond_Id) /= Func_Id
6267 and then not Validity_Check_Operands
6268 then
6269 Set_Declarations (Func_Body, Empty_List);
6270 end if;
6272 if Cond_Id = Standard_False or else Cond_Id = Standard_True then
6273 return;
6275 elsif Is_Simple_Barrier_Name (Cond) then
6276 return;
6277 end if;
6278 end if;
6280 -- It is not a boolean variable or literal, so check the restriction.
6281 -- Note that it is safe to be calling Check_Restriction from here, even
6282 -- though this is part of the expander, since Expand_Entry_Barrier is
6283 -- called from Sem_Ch9 even in -gnatc mode.
6285 Check_Restriction (Simple_Barriers, Cond);
6287 -- Emit warning if barrier contains global entities and is thus
6288 -- potentially unsynchronized.
6290 Check_Unprotected_Barrier (Cond);
6291 end Expand_Entry_Barrier;
6293 ------------------------------
6294 -- Expand_N_Abort_Statement --
6295 ------------------------------
6297 -- Expand abort T1, T2, .. Tn; into:
6298 -- Abort_Tasks (Task_List'(1 => T1.Task_Id, 2 => T2.Task_Id ...))
6300 procedure Expand_N_Abort_Statement (N : Node_Id) is
6301 Loc : constant Source_Ptr := Sloc (N);
6302 Tlist : constant List_Id := Names (N);
6303 Count : Nat;
6304 Aggr : Node_Id;
6305 Tasknm : Node_Id;
6307 begin
6308 Aggr := Make_Aggregate (Loc, Component_Associations => New_List);
6309 Count := 0;
6311 Tasknm := First (Tlist);
6313 while Present (Tasknm) loop
6314 Count := Count + 1;
6316 -- A task interface class-wide type object is being aborted. Retrieve
6317 -- its _task_id by calling a dispatching routine.
6319 if Ada_Version >= Ada_2005
6320 and then Ekind (Etype (Tasknm)) = E_Class_Wide_Type
6321 and then Is_Interface (Etype (Tasknm))
6322 and then Is_Task_Interface (Etype (Tasknm))
6323 then
6324 Append_To (Component_Associations (Aggr),
6325 Make_Component_Association (Loc,
6326 Choices => New_List (Make_Integer_Literal (Loc, Count)),
6327 Expression =>
6329 -- Task_Id (Tasknm._disp_get_task_id)
6331 Make_Unchecked_Type_Conversion (Loc,
6332 Subtype_Mark =>
6333 New_Occurrence_Of (RTE (RO_ST_Task_Id), Loc),
6334 Expression =>
6335 Make_Selected_Component (Loc,
6336 Prefix => New_Copy_Tree (Tasknm),
6337 Selector_Name =>
6338 Make_Identifier (Loc, Name_uDisp_Get_Task_Id)))));
6340 else
6341 Append_To (Component_Associations (Aggr),
6342 Make_Component_Association (Loc,
6343 Choices => New_List (Make_Integer_Literal (Loc, Count)),
6344 Expression => Concurrent_Ref (Tasknm)));
6345 end if;
6347 Next (Tasknm);
6348 end loop;
6350 Rewrite (N,
6351 Make_Procedure_Call_Statement (Loc,
6352 Name => New_Occurrence_Of (RTE (RE_Abort_Tasks), Loc),
6353 Parameter_Associations => New_List (
6354 Make_Qualified_Expression (Loc,
6355 Subtype_Mark => New_Occurrence_Of (RTE (RE_Task_List), Loc),
6356 Expression => Aggr))));
6358 Analyze (N);
6359 end Expand_N_Abort_Statement;
6361 -------------------------------
6362 -- Expand_N_Accept_Statement --
6363 -------------------------------
6365 -- This procedure handles expansion of accept statements that stand alone,
6366 -- i.e. they are not part of an accept alternative. The expansion of
6367 -- accept statement in accept alternatives is handled by the routines
6368 -- Expand_N_Accept_Alternative and Expand_N_Selective_Accept. The
6369 -- following description applies only to stand alone accept statements.
6371 -- If there is no handled statement sequence, or only null statements, then
6372 -- this is called a trivial accept, and the expansion is:
6374 -- Accept_Trivial (entry-index)
6376 -- If there is a handled statement sequence, then the expansion is:
6378 -- Ann : Address;
6379 -- {Lnn : Label}
6381 -- begin
6382 -- begin
6383 -- Accept_Call (entry-index, Ann);
6384 -- Renaming_Declarations for formals
6385 -- <statement sequence from N_Accept_Statement node>
6386 -- Complete_Rendezvous;
6387 -- <<Lnn>>
6389 -- exception
6390 -- when ... =>
6391 -- <exception handler from N_Accept_Statement node>
6392 -- Complete_Rendezvous;
6393 -- when ... =>
6394 -- <exception handler from N_Accept_Statement node>
6395 -- Complete_Rendezvous;
6396 -- ...
6397 -- end;
6399 -- exception
6400 -- when all others =>
6401 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
6402 -- end;
6404 -- The first three declarations were already inserted ahead of the accept
6405 -- statement by the Expand_Accept_Declarations procedure, which was called
6406 -- directly from the semantics during analysis of the accept statement,
6407 -- before analyzing its contained statements.
6409 -- The declarations from the N_Accept_Statement, as noted in Sinfo, come
6410 -- from possible expansion activity (the original source of course does
6411 -- not have any declarations associated with the accept statement, since
6412 -- an accept statement has no declarative part). In particular, if the
6413 -- expander is active, the first such declaration is the declaration of
6414 -- the Accept_Params_Ptr entity (see Sem_Ch9.Analyze_Accept_Statement).
6416 -- The two blocks are merged into a single block if the inner block has
6417 -- no exception handlers, but otherwise two blocks are required, since
6418 -- exceptions might be raised in the exception handlers of the inner
6419 -- block, and Exceptional_Complete_Rendezvous must be called.
6421 procedure Expand_N_Accept_Statement (N : Node_Id) is
6422 Loc : constant Source_Ptr := Sloc (N);
6423 Stats : constant Node_Id := Handled_Statement_Sequence (N);
6424 Ename : constant Node_Id := Entry_Direct_Name (N);
6425 Eindx : constant Node_Id := Entry_Index (N);
6426 Eent : constant Entity_Id := Entity (Ename);
6427 Acstack : constant Elist_Id := Accept_Address (Eent);
6428 Ann : constant Entity_Id := Node (Last_Elmt (Acstack));
6429 Ttyp : constant Entity_Id := Etype (Scope (Eent));
6430 Blkent : Entity_Id;
6431 Call : Node_Id;
6432 Block : Node_Id;
6434 begin
6435 -- If the accept statement is not part of a list, then its parent must
6436 -- be an accept alternative, and, as described above, we do not do any
6437 -- expansion for such accept statements at this level.
6439 if not Is_List_Member (N) then
6440 pragma Assert (Nkind (Parent (N)) = N_Accept_Alternative);
6441 return;
6443 -- Trivial accept case (no statement sequence, or null statements).
6444 -- If the accept statement has declarations, then just insert them
6445 -- before the procedure call.
6447 elsif Trivial_Accept_OK
6448 and then (No (Stats) or else Null_Statements (Statements (Stats)))
6449 then
6450 -- Remove declarations for renamings, because the parameter block
6451 -- will not be assigned.
6453 declare
6454 D : Node_Id;
6455 Next_D : Node_Id;
6457 begin
6458 D := First (Declarations (N));
6459 while Present (D) loop
6460 Next_D := Next (D);
6461 if Nkind (D) = N_Object_Renaming_Declaration then
6462 Remove (D);
6463 end if;
6465 D := Next_D;
6466 end loop;
6467 end;
6469 if Present (Declarations (N)) then
6470 Insert_Actions (N, Declarations (N));
6471 end if;
6473 Rewrite (N,
6474 Make_Procedure_Call_Statement (Loc,
6475 Name => New_Occurrence_Of (RTE (RE_Accept_Trivial), Loc),
6476 Parameter_Associations => New_List (
6477 Entry_Index_Expression (Loc, Entity (Ename), Eindx, Ttyp))));
6479 Analyze (N);
6481 -- Discard Entry_Address that was created for it, so it will not be
6482 -- emitted if this accept statement is in the statement part of a
6483 -- delay alternative.
6485 if Present (Stats) then
6486 Remove_Last_Elmt (Acstack);
6487 end if;
6489 -- Case of statement sequence present
6491 else
6492 -- Construct the block, using the declarations from the accept
6493 -- statement if any to initialize the declarations of the block.
6495 Blkent := Make_Temporary (Loc, 'A');
6496 Set_Ekind (Blkent, E_Block);
6497 Set_Etype (Blkent, Standard_Void_Type);
6498 Set_Scope (Blkent, Current_Scope);
6500 Block :=
6501 Make_Block_Statement (Loc,
6502 Identifier => New_Occurrence_Of (Blkent, Loc),
6503 Declarations => Declarations (N),
6504 Handled_Statement_Sequence => Build_Accept_Body (N));
6506 -- For the analysis of the generated declarations, the parent node
6507 -- must be properly set.
6509 Set_Parent (Block, Parent (N));
6511 -- Prepend call to Accept_Call to main statement sequence If the
6512 -- accept has exception handlers, the statement sequence is wrapped
6513 -- in a block. Insert call and renaming declarations in the
6514 -- declarations of the block, so they are elaborated before the
6515 -- handlers.
6517 Call :=
6518 Make_Procedure_Call_Statement (Loc,
6519 Name => New_Occurrence_Of (RTE (RE_Accept_Call), Loc),
6520 Parameter_Associations => New_List (
6521 Entry_Index_Expression (Loc, Entity (Ename), Eindx, Ttyp),
6522 New_Occurrence_Of (Ann, Loc)));
6524 if Parent (Stats) = N then
6525 Prepend (Call, Statements (Stats));
6526 else
6527 Set_Declarations (Parent (Stats), New_List (Call));
6528 end if;
6530 Analyze (Call);
6532 Push_Scope (Blkent);
6534 declare
6535 D : Node_Id;
6536 Next_D : Node_Id;
6537 Typ : Entity_Id;
6539 begin
6540 D := First (Declarations (N));
6541 while Present (D) loop
6542 Next_D := Next (D);
6544 if Nkind (D) = N_Object_Renaming_Declaration then
6546 -- The renaming declarations for the formals were created
6547 -- during analysis of the accept statement, and attached to
6548 -- the list of declarations. Place them now in the context
6549 -- of the accept block or subprogram.
6551 Remove (D);
6552 Typ := Entity (Subtype_Mark (D));
6553 Insert_After (Call, D);
6554 Analyze (D);
6556 -- If the formal is class_wide, it does not have an actual
6557 -- subtype. The analysis of the renaming declaration creates
6558 -- one, but we need to retain the class-wide nature of the
6559 -- entity.
6561 if Is_Class_Wide_Type (Typ) then
6562 Set_Etype (Defining_Identifier (D), Typ);
6563 end if;
6565 end if;
6567 D := Next_D;
6568 end loop;
6569 end;
6571 End_Scope;
6573 -- Replace the accept statement by the new block
6575 Rewrite (N, Block);
6576 Analyze (N);
6578 -- Last step is to unstack the Accept_Address value
6580 Remove_Last_Elmt (Acstack);
6581 end if;
6582 end Expand_N_Accept_Statement;
6584 ----------------------------------
6585 -- Expand_N_Asynchronous_Select --
6586 ----------------------------------
6588 -- This procedure assumes that the trigger statement is an entry call or
6589 -- a dispatching procedure call. A delay alternative should already have
6590 -- been expanded into an entry call to the appropriate delay object Wait
6591 -- entry.
6593 -- If the trigger is a task entry call, the select is implemented with
6594 -- a Task_Entry_Call:
6596 -- declare
6597 -- B : Boolean;
6598 -- C : Boolean;
6599 -- P : parms := (parm, parm, parm);
6601 -- -- Clean is added by Exp_Ch7.Expand_Cleanup_Actions
6603 -- procedure _clean is
6604 -- begin
6605 -- ...
6606 -- Cancel_Task_Entry_Call (C);
6607 -- ...
6608 -- end _clean;
6610 -- begin
6611 -- Abort_Defer;
6612 -- Task_Entry_Call
6613 -- (<acceptor-task>, -- Acceptor
6614 -- <entry-index>, -- E
6615 -- P'Address, -- Uninterpreted_Data
6616 -- Asynchronous_Call, -- Mode
6617 -- B); -- Rendezvous_Successful
6619 -- begin
6620 -- begin
6621 -- Abort_Undefer;
6622 -- <abortable-part>
6623 -- at end
6624 -- _clean; -- Added by Exp_Ch7.Expand_Cleanup_Actions
6625 -- end;
6626 -- exception
6627 -- when Abort_Signal => Abort_Undefer;
6628 -- end;
6630 -- parm := P.param;
6631 -- parm := P.param;
6632 -- ...
6633 -- if not C then
6634 -- <triggered-statements>
6635 -- end if;
6636 -- end;
6638 -- Note that Build_Simple_Entry_Call is used to expand the entry of the
6639 -- asynchronous entry call (by Expand_N_Entry_Call_Statement procedure)
6640 -- as follows:
6642 -- declare
6643 -- P : parms := (parm, parm, parm);
6644 -- begin
6645 -- Call_Simple (acceptor-task, entry-index, P'Address);
6646 -- parm := P.param;
6647 -- parm := P.param;
6648 -- ...
6649 -- end;
6651 -- so the task at hand is to convert the latter expansion into the former
6653 -- If the trigger is a protected entry call, the select is implemented
6654 -- with Protected_Entry_Call:
6656 -- declare
6657 -- P : E1_Params := (param, param, param);
6658 -- Bnn : Communications_Block;
6660 -- begin
6661 -- declare
6663 -- -- Clean is added by Exp_Ch7.Expand_Cleanup_Actions
6665 -- procedure _clean is
6666 -- begin
6667 -- ...
6668 -- if Enqueued (Bnn) then
6669 -- Cancel_Protected_Entry_Call (Bnn);
6670 -- end if;
6671 -- ...
6672 -- end _clean;
6674 -- begin
6675 -- begin
6676 -- Protected_Entry_Call
6677 -- (po._object'Access, -- Object
6678 -- <entry index>, -- E
6679 -- P'Address, -- Uninterpreted_Data
6680 -- Asynchronous_Call, -- Mode
6681 -- Bnn); -- Block
6683 -- if Enqueued (Bnn) then
6684 -- <abortable-part>
6685 -- end if;
6686 -- at end
6687 -- _clean; -- Added by Exp_Ch7.Expand_Cleanup_Actions
6688 -- end;
6689 -- exception
6690 -- when Abort_Signal => Abort_Undefer;
6691 -- end;
6693 -- if not Cancelled (Bnn) then
6694 -- <triggered-statements>
6695 -- end if;
6696 -- end;
6698 -- Build_Simple_Entry_Call is used to expand the all to a simple protected
6699 -- entry call:
6701 -- declare
6702 -- P : E1_Params := (param, param, param);
6703 -- Bnn : Communications_Block;
6705 -- begin
6706 -- Protected_Entry_Call
6707 -- (po._object'Access, -- Object
6708 -- <entry index>, -- E
6709 -- P'Address, -- Uninterpreted_Data
6710 -- Simple_Call, -- Mode
6711 -- Bnn); -- Block
6712 -- parm := P.param;
6713 -- parm := P.param;
6714 -- ...
6715 -- end;
6717 -- Ada 2005 (AI-345): If the trigger is a dispatching call, the select is
6718 -- expanded into:
6720 -- declare
6721 -- B : Boolean := False;
6722 -- Bnn : Communication_Block;
6723 -- C : Ada.Tags.Prim_Op_Kind;
6724 -- D : System.Storage_Elements.Dummy_Communication_Block;
6725 -- K : Ada.Tags.Tagged_Kind :=
6726 -- Ada.Tags.Get_Tagged_Kind (Ada.Tags.Tag (<object>));
6727 -- P : Parameters := (Param1 .. ParamN);
6728 -- S : Integer;
6729 -- U : Boolean;
6731 -- begin
6732 -- if K = Ada.Tags.TK_Limited_Tagged
6733 -- or else K = Ada.Tags.TK_Tagged
6734 -- then
6735 -- <dispatching-call>;
6736 -- <triggering-statements>;
6738 -- else
6739 -- S :=
6740 -- Ada.Tags.Get_Offset_Index
6741 -- (Ada.Tags.Tag (<object>), DT_Position (<dispatching-call>));
6743 -- _Disp_Get_Prim_Op_Kind (<object>, S, C);
6745 -- if C = POK_Protected_Entry then
6746 -- declare
6747 -- procedure _clean is
6748 -- begin
6749 -- if Enqueued (Bnn) then
6750 -- Cancel_Protected_Entry_Call (Bnn);
6751 -- end if;
6752 -- end _clean;
6754 -- begin
6755 -- begin
6756 -- _Disp_Asynchronous_Select
6757 -- (<object>, S, P'Address, D, B);
6758 -- Bnn := Communication_Block (D);
6760 -- Param1 := P.Param1;
6761 -- ...
6762 -- ParamN := P.ParamN;
6764 -- if Enqueued (Bnn) then
6765 -- <abortable-statements>
6766 -- end if;
6767 -- at end
6768 -- _clean; -- Added by Exp_Ch7.Expand_Cleanup_Actions
6769 -- end;
6770 -- exception
6771 -- when Abort_Signal => Abort_Undefer;
6772 -- end;
6774 -- if not Cancelled (Bnn) then
6775 -- <triggering-statements>
6776 -- end if;
6778 -- elsif C = POK_Task_Entry then
6779 -- declare
6780 -- procedure _clean is
6781 -- begin
6782 -- Cancel_Task_Entry_Call (U);
6783 -- end _clean;
6785 -- begin
6786 -- Abort_Defer;
6788 -- _Disp_Asynchronous_Select
6789 -- (<object>, S, P'Address, D, B);
6790 -- Bnn := Communication_Bloc (D);
6792 -- Param1 := P.Param1;
6793 -- ...
6794 -- ParamN := P.ParamN;
6796 -- begin
6797 -- begin
6798 -- Abort_Undefer;
6799 -- <abortable-statements>
6800 -- at end
6801 -- _clean; -- Added by Exp_Ch7.Expand_Cleanup_Actions
6802 -- end;
6803 -- exception
6804 -- when Abort_Signal => Abort_Undefer;
6805 -- end;
6807 -- if not U then
6808 -- <triggering-statements>
6809 -- end if;
6810 -- end;
6812 -- else
6813 -- <dispatching-call>;
6814 -- <triggering-statements>
6815 -- end if;
6816 -- end if;
6817 -- end;
6819 -- The job is to convert this to the asynchronous form
6821 -- If the trigger is a delay statement, it will have been expanded into
6822 -- a call to one of the GNARL delay procedures. This routine will convert
6823 -- this into a protected entry call on a delay object and then continue
6824 -- processing as for a protected entry call trigger. This requires
6825 -- declaring a Delay_Block object and adding a pointer to this object to
6826 -- the parameter list of the delay procedure to form the parameter list of
6827 -- the entry call. This object is used by the runtime to queue the delay
6828 -- request.
6830 -- For a description of the use of P and the assignments after the call,
6831 -- see Expand_N_Entry_Call_Statement.
6833 procedure Expand_N_Asynchronous_Select (N : Node_Id) is
6834 Loc : constant Source_Ptr := Sloc (N);
6835 Abrt : constant Node_Id := Abortable_Part (N);
6836 Trig : constant Node_Id := Triggering_Alternative (N);
6838 Abort_Block_Ent : Entity_Id;
6839 Abortable_Block : Node_Id;
6840 Actuals : List_Id;
6841 Astats : List_Id;
6842 Blk_Ent : constant Entity_Id := Make_Temporary (Loc, 'A');
6843 Blk_Typ : Entity_Id;
6844 Call : Node_Id;
6845 Call_Ent : Entity_Id;
6846 Cancel_Param : Entity_Id;
6847 Cleanup_Block : Node_Id;
6848 Cleanup_Block_Ent : Entity_Id;
6849 Cleanup_Stmts : List_Id;
6850 Conc_Typ_Stmts : List_Id;
6851 Concval : Node_Id;
6852 Dblock_Ent : Entity_Id;
6853 Decl : Node_Id;
6854 Decls : List_Id;
6855 Ecall : Node_Id;
6856 Ename : Node_Id;
6857 Enqueue_Call : Node_Id;
6858 Formals : List_Id;
6859 Hdle : List_Id;
6860 Handler_Stmt : Node_Id;
6861 Index : Node_Id;
6862 Lim_Typ_Stmts : List_Id;
6863 N_Orig : Node_Id;
6864 Obj : Entity_Id;
6865 Param : Node_Id;
6866 Params : List_Id;
6867 Pdef : Entity_Id;
6868 ProtE_Stmts : List_Id;
6869 ProtP_Stmts : List_Id;
6870 Stmt : Node_Id;
6871 Stmts : List_Id;
6872 TaskE_Stmts : List_Id;
6873 Tstats : List_Id;
6875 B : Entity_Id; -- Call status flag
6876 Bnn : Entity_Id; -- Communication block
6877 C : Entity_Id; -- Call kind
6878 K : Entity_Id; -- Tagged kind
6879 P : Entity_Id; -- Parameter block
6880 S : Entity_Id; -- Primitive operation slot
6881 T : Entity_Id; -- Additional status flag
6883 procedure Rewrite_Abortable_Part;
6884 -- If the trigger is a dispatching call, the expansion inserts multiple
6885 -- copies of the abortable part. This is both inefficient, and may lead
6886 -- to duplicate definitions that the back-end will reject, when the
6887 -- abortable part includes loops. This procedure rewrites the abortable
6888 -- part into a call to a generated procedure.
6890 ----------------------------
6891 -- Rewrite_Abortable_Part --
6892 ----------------------------
6894 procedure Rewrite_Abortable_Part is
6895 Proc : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uA);
6896 Decl : Node_Id;
6898 begin
6899 Decl :=
6900 Make_Subprogram_Body (Loc,
6901 Specification =>
6902 Make_Procedure_Specification (Loc, Defining_Unit_Name => Proc),
6903 Declarations => New_List,
6904 Handled_Statement_Sequence =>
6905 Make_Handled_Sequence_Of_Statements (Loc, Astats));
6906 Insert_Before (N, Decl);
6907 Analyze (Decl);
6909 -- Rewrite abortable part into a call to this procedure
6911 Astats :=
6912 New_List (
6913 Make_Procedure_Call_Statement (Loc,
6914 Name => New_Occurrence_Of (Proc, Loc)));
6915 end Rewrite_Abortable_Part;
6917 -- Start of processing for Expand_N_Asynchronous_Select
6919 begin
6920 -- Asynchronous select is not supported on restricted runtimes. Don't
6921 -- try to expand.
6923 if Restricted_Profile then
6924 return;
6925 end if;
6927 Process_Statements_For_Controlled_Objects (Trig);
6928 Process_Statements_For_Controlled_Objects (Abrt);
6930 Ecall := Triggering_Statement (Trig);
6932 Ensure_Statement_Present (Sloc (Ecall), Trig);
6934 -- Retrieve Astats and Tstats now because the finalization machinery may
6935 -- wrap them in blocks.
6937 Astats := Statements (Abrt);
6938 Tstats := Statements (Trig);
6940 -- The arguments in the call may require dynamic allocation, and the
6941 -- call statement may have been transformed into a block. The block
6942 -- may contain additional declarations for internal entities, and the
6943 -- original call is found by sequential search.
6945 if Nkind (Ecall) = N_Block_Statement then
6946 Ecall := First (Statements (Handled_Statement_Sequence (Ecall)));
6947 while not Nkind_In (Ecall, N_Procedure_Call_Statement,
6948 N_Entry_Call_Statement)
6949 loop
6950 Next (Ecall);
6951 end loop;
6952 end if;
6954 -- This is either a dispatching call or a delay statement used as a
6955 -- trigger which was expanded into a procedure call.
6957 if Nkind (Ecall) = N_Procedure_Call_Statement then
6958 if Ada_Version >= Ada_2005
6959 and then
6960 (No (Original_Node (Ecall))
6961 or else not Nkind_In (Original_Node (Ecall),
6962 N_Delay_Relative_Statement,
6963 N_Delay_Until_Statement))
6964 then
6965 Extract_Dispatching_Call (Ecall, Call_Ent, Obj, Actuals, Formals);
6967 Rewrite_Abortable_Part;
6968 Decls := New_List;
6969 Stmts := New_List;
6971 -- Call status flag processing, generate:
6972 -- B : Boolean := False;
6974 B := Build_B (Loc, Decls);
6976 -- Communication block processing, generate:
6977 -- Bnn : Communication_Block;
6979 Bnn := Make_Temporary (Loc, 'B');
6980 Append_To (Decls,
6981 Make_Object_Declaration (Loc,
6982 Defining_Identifier => Bnn,
6983 Object_Definition =>
6984 New_Occurrence_Of (RTE (RE_Communication_Block), Loc)));
6986 -- Call kind processing, generate:
6987 -- C : Ada.Tags.Prim_Op_Kind;
6989 C := Build_C (Loc, Decls);
6991 -- Tagged kind processing, generate:
6992 -- K : Ada.Tags.Tagged_Kind :=
6993 -- Ada.Tags.Get_Tagged_Kind (Ada.Tags.Tag (<object>));
6995 -- Dummy communication block, generate:
6996 -- D : Dummy_Communication_Block;
6998 Append_To (Decls,
6999 Make_Object_Declaration (Loc,
7000 Defining_Identifier =>
7001 Make_Defining_Identifier (Loc, Name_uD),
7002 Object_Definition =>
7003 New_Occurrence_Of
7004 (RTE (RE_Dummy_Communication_Block), Loc)));
7006 K := Build_K (Loc, Decls, Obj);
7008 -- Parameter block processing
7010 Blk_Typ := Build_Parameter_Block
7011 (Loc, Actuals, Formals, Decls);
7012 P := Parameter_Block_Pack
7013 (Loc, Blk_Typ, Actuals, Formals, Decls, Stmts);
7015 -- Dispatch table slot processing, generate:
7016 -- S : Integer;
7018 S := Build_S (Loc, Decls);
7020 -- Additional status flag processing, generate:
7021 -- Tnn : Boolean;
7023 T := Make_Temporary (Loc, 'T');
7024 Append_To (Decls,
7025 Make_Object_Declaration (Loc,
7026 Defining_Identifier => T,
7027 Object_Definition =>
7028 New_Occurrence_Of (Standard_Boolean, Loc)));
7030 ------------------------------
7031 -- Protected entry handling --
7032 ------------------------------
7034 -- Generate:
7035 -- Param1 := P.Param1;
7036 -- ...
7037 -- ParamN := P.ParamN;
7039 Cleanup_Stmts := Parameter_Block_Unpack (Loc, P, Actuals, Formals);
7041 -- Generate:
7042 -- Bnn := Communication_Block (D);
7044 Prepend_To (Cleanup_Stmts,
7045 Make_Assignment_Statement (Loc,
7046 Name => New_Occurrence_Of (Bnn, Loc),
7047 Expression =>
7048 Make_Unchecked_Type_Conversion (Loc,
7049 Subtype_Mark =>
7050 New_Occurrence_Of (RTE (RE_Communication_Block), Loc),
7051 Expression => Make_Identifier (Loc, Name_uD))));
7053 -- Generate:
7054 -- _Disp_Asynchronous_Select (<object>, S, P'Address, D, B);
7056 Prepend_To (Cleanup_Stmts,
7057 Make_Procedure_Call_Statement (Loc,
7058 Name =>
7059 New_Occurrence_Of
7060 (Find_Prim_Op
7061 (Etype (Etype (Obj)), Name_uDisp_Asynchronous_Select),
7062 Loc),
7063 Parameter_Associations =>
7064 New_List (
7065 New_Copy_Tree (Obj), -- <object>
7066 New_Occurrence_Of (S, Loc), -- S
7067 Make_Attribute_Reference (Loc, -- P'Address
7068 Prefix => New_Occurrence_Of (P, Loc),
7069 Attribute_Name => Name_Address),
7070 Make_Identifier (Loc, Name_uD), -- D
7071 New_Occurrence_Of (B, Loc)))); -- B
7073 -- Generate:
7074 -- if Enqueued (Bnn) then
7075 -- <abortable-statements>
7076 -- end if;
7078 Append_To (Cleanup_Stmts,
7079 Make_Implicit_If_Statement (N,
7080 Condition =>
7081 Make_Function_Call (Loc,
7082 Name =>
7083 New_Occurrence_Of (RTE (RE_Enqueued), Loc),
7084 Parameter_Associations =>
7085 New_List (New_Occurrence_Of (Bnn, Loc))),
7087 Then_Statements =>
7088 New_Copy_List_Tree (Astats)));
7090 -- Wrap the statements in a block. Exp_Ch7.Expand_Cleanup_Actions
7091 -- will then generate a _clean for the communication block Bnn.
7093 -- Generate:
7094 -- declare
7095 -- procedure _clean is
7096 -- begin
7097 -- if Enqueued (Bnn) then
7098 -- Cancel_Protected_Entry_Call (Bnn);
7099 -- end if;
7100 -- end _clean;
7101 -- begin
7102 -- Cleanup_Stmts
7103 -- at end
7104 -- _clean;
7105 -- end;
7107 Cleanup_Block_Ent := Make_Temporary (Loc, 'C');
7108 Cleanup_Block :=
7109 Build_Cleanup_Block (Loc, Cleanup_Block_Ent, Cleanup_Stmts, Bnn);
7111 -- Wrap the cleanup block in an exception handling block
7113 -- Generate:
7114 -- begin
7115 -- Cleanup_Block
7116 -- exception
7117 -- when Abort_Signal => Abort_Undefer;
7118 -- end;
7120 Abort_Block_Ent := Make_Temporary (Loc, 'A');
7121 ProtE_Stmts :=
7122 New_List (
7123 Make_Implicit_Label_Declaration (Loc,
7124 Defining_Identifier => Abort_Block_Ent),
7126 Build_Abort_Block
7127 (Loc, Abort_Block_Ent, Cleanup_Block_Ent, Cleanup_Block));
7129 -- Generate:
7130 -- if not Cancelled (Bnn) then
7131 -- <triggering-statements>
7132 -- end if;
7134 Append_To (ProtE_Stmts,
7135 Make_Implicit_If_Statement (N,
7136 Condition =>
7137 Make_Op_Not (Loc,
7138 Right_Opnd =>
7139 Make_Function_Call (Loc,
7140 Name =>
7141 New_Occurrence_Of (RTE (RE_Cancelled), Loc),
7142 Parameter_Associations =>
7143 New_List (New_Occurrence_Of (Bnn, Loc)))),
7145 Then_Statements =>
7146 New_Copy_List_Tree (Tstats)));
7148 -------------------------
7149 -- Task entry handling --
7150 -------------------------
7152 -- Generate:
7153 -- Param1 := P.Param1;
7154 -- ...
7155 -- ParamN := P.ParamN;
7157 TaskE_Stmts := Parameter_Block_Unpack (Loc, P, Actuals, Formals);
7159 -- Generate:
7160 -- Bnn := Communication_Block (D);
7162 Append_To (TaskE_Stmts,
7163 Make_Assignment_Statement (Loc,
7164 Name =>
7165 New_Occurrence_Of (Bnn, Loc),
7166 Expression =>
7167 Make_Unchecked_Type_Conversion (Loc,
7168 Subtype_Mark =>
7169 New_Occurrence_Of (RTE (RE_Communication_Block), Loc),
7170 Expression => Make_Identifier (Loc, Name_uD))));
7172 -- Generate:
7173 -- _Disp_Asynchronous_Select (<object>, S, P'Address, D, B);
7175 Prepend_To (TaskE_Stmts,
7176 Make_Procedure_Call_Statement (Loc,
7177 Name =>
7178 New_Occurrence_Of (
7179 Find_Prim_Op (Etype (Etype (Obj)),
7180 Name_uDisp_Asynchronous_Select),
7181 Loc),
7183 Parameter_Associations => New_List (
7184 New_Copy_Tree (Obj), -- <object>
7185 New_Occurrence_Of (S, Loc), -- S
7186 Make_Attribute_Reference (Loc, -- P'Address
7187 Prefix => New_Occurrence_Of (P, Loc),
7188 Attribute_Name => Name_Address),
7189 Make_Identifier (Loc, Name_uD), -- D
7190 New_Occurrence_Of (B, Loc)))); -- B
7192 -- Generate:
7193 -- Abort_Defer;
7195 Prepend_To (TaskE_Stmts, Build_Runtime_Call (Loc, RE_Abort_Defer));
7197 -- Generate:
7198 -- Abort_Undefer;
7199 -- <abortable-statements>
7201 Cleanup_Stmts := New_Copy_List_Tree (Astats);
7203 Prepend_To
7204 (Cleanup_Stmts, Build_Runtime_Call (Loc, RE_Abort_Undefer));
7206 -- Wrap the statements in a block. Exp_Ch7.Expand_Cleanup_Actions
7207 -- will generate a _clean for the additional status flag.
7209 -- Generate:
7210 -- declare
7211 -- procedure _clean is
7212 -- begin
7213 -- Cancel_Task_Entry_Call (U);
7214 -- end _clean;
7215 -- begin
7216 -- Cleanup_Stmts
7217 -- at end
7218 -- _clean;
7219 -- end;
7221 Cleanup_Block_Ent := Make_Temporary (Loc, 'C');
7222 Cleanup_Block :=
7223 Build_Cleanup_Block (Loc, Cleanup_Block_Ent, Cleanup_Stmts, T);
7225 -- Wrap the cleanup block in an exception handling block
7227 -- Generate:
7228 -- begin
7229 -- Cleanup_Block
7230 -- exception
7231 -- when Abort_Signal => Abort_Undefer;
7232 -- end;
7234 Abort_Block_Ent := Make_Temporary (Loc, 'A');
7236 Append_To (TaskE_Stmts,
7237 Make_Implicit_Label_Declaration (Loc,
7238 Defining_Identifier => Abort_Block_Ent));
7240 Append_To (TaskE_Stmts,
7241 Build_Abort_Block
7242 (Loc, Abort_Block_Ent, Cleanup_Block_Ent, Cleanup_Block));
7244 -- Generate:
7245 -- if not T then
7246 -- <triggering-statements>
7247 -- end if;
7249 Append_To (TaskE_Stmts,
7250 Make_Implicit_If_Statement (N,
7251 Condition =>
7252 Make_Op_Not (Loc, Right_Opnd => New_Occurrence_Of (T, Loc)),
7254 Then_Statements =>
7255 New_Copy_List_Tree (Tstats)));
7257 ----------------------------------
7258 -- Protected procedure handling --
7259 ----------------------------------
7261 -- Generate:
7262 -- <dispatching-call>;
7263 -- <triggering-statements>
7265 ProtP_Stmts := New_Copy_List_Tree (Tstats);
7266 Prepend_To (ProtP_Stmts, New_Copy_Tree (Ecall));
7268 -- Generate:
7269 -- S := Ada.Tags.Get_Offset_Index
7270 -- (Ada.Tags.Tag (<object>), DT_Position (Call_Ent));
7272 Conc_Typ_Stmts :=
7273 New_List (Build_S_Assignment (Loc, S, Obj, Call_Ent));
7275 -- Generate:
7276 -- _Disp_Get_Prim_Op_Kind (<object>, S, C);
7278 Append_To (Conc_Typ_Stmts,
7279 Make_Procedure_Call_Statement (Loc,
7280 Name =>
7281 New_Occurrence_Of
7282 (Find_Prim_Op (Etype (Etype (Obj)),
7283 Name_uDisp_Get_Prim_Op_Kind),
7284 Loc),
7285 Parameter_Associations =>
7286 New_List (
7287 New_Copy_Tree (Obj),
7288 New_Occurrence_Of (S, Loc),
7289 New_Occurrence_Of (C, Loc))));
7291 -- Generate:
7292 -- if C = POK_Procedure_Entry then
7293 -- ProtE_Stmts
7294 -- elsif C = POK_Task_Entry then
7295 -- TaskE_Stmts
7296 -- else
7297 -- ProtP_Stmts
7298 -- end if;
7300 Append_To (Conc_Typ_Stmts,
7301 Make_Implicit_If_Statement (N,
7302 Condition =>
7303 Make_Op_Eq (Loc,
7304 Left_Opnd =>
7305 New_Occurrence_Of (C, Loc),
7306 Right_Opnd =>
7307 New_Occurrence_Of (RTE (RE_POK_Protected_Entry), Loc)),
7309 Then_Statements =>
7310 ProtE_Stmts,
7312 Elsif_Parts =>
7313 New_List (
7314 Make_Elsif_Part (Loc,
7315 Condition =>
7316 Make_Op_Eq (Loc,
7317 Left_Opnd =>
7318 New_Occurrence_Of (C, Loc),
7319 Right_Opnd =>
7320 New_Occurrence_Of (RTE (RE_POK_Task_Entry), Loc)),
7322 Then_Statements =>
7323 TaskE_Stmts)),
7325 Else_Statements =>
7326 ProtP_Stmts));
7328 -- Generate:
7329 -- <dispatching-call>;
7330 -- <triggering-statements>
7332 Lim_Typ_Stmts := New_Copy_List_Tree (Tstats);
7333 Prepend_To (Lim_Typ_Stmts, New_Copy_Tree (Ecall));
7335 -- Generate:
7336 -- if K = Ada.Tags.TK_Limited_Tagged
7337 -- or else K = Ada.Tags.TK_Tagged
7338 -- then
7339 -- Lim_Typ_Stmts
7340 -- else
7341 -- Conc_Typ_Stmts
7342 -- end if;
7344 Append_To (Stmts,
7345 Make_Implicit_If_Statement (N,
7346 Condition => Build_Dispatching_Tag_Check (K, N),
7347 Then_Statements => Lim_Typ_Stmts,
7348 Else_Statements => Conc_Typ_Stmts));
7350 Rewrite (N,
7351 Make_Block_Statement (Loc,
7352 Declarations =>
7353 Decls,
7354 Handled_Statement_Sequence =>
7355 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
7357 Analyze (N);
7358 return;
7360 -- Delay triggering statement processing
7362 else
7363 -- Add a Delay_Block object to the parameter list of the delay
7364 -- procedure to form the parameter list of the Wait entry call.
7366 Dblock_Ent := Make_Temporary (Loc, 'D');
7368 Pdef := Entity (Name (Ecall));
7370 if Is_RTE (Pdef, RO_CA_Delay_For) then
7371 Enqueue_Call :=
7372 New_Occurrence_Of (RTE (RE_Enqueue_Duration), Loc);
7374 elsif Is_RTE (Pdef, RO_CA_Delay_Until) then
7375 Enqueue_Call :=
7376 New_Occurrence_Of (RTE (RE_Enqueue_Calendar), Loc);
7378 else pragma Assert (Is_RTE (Pdef, RO_RT_Delay_Until));
7379 Enqueue_Call := New_Occurrence_Of (RTE (RE_Enqueue_RT), Loc);
7380 end if;
7382 Append_To (Parameter_Associations (Ecall),
7383 Make_Attribute_Reference (Loc,
7384 Prefix => New_Occurrence_Of (Dblock_Ent, Loc),
7385 Attribute_Name => Name_Unchecked_Access));
7387 -- Create the inner block to protect the abortable part
7389 Hdle := New_List (Build_Abort_Block_Handler (Loc));
7391 Prepend_To (Astats, Build_Runtime_Call (Loc, RE_Abort_Undefer));
7393 Abortable_Block :=
7394 Make_Block_Statement (Loc,
7395 Identifier => New_Occurrence_Of (Blk_Ent, Loc),
7396 Handled_Statement_Sequence =>
7397 Make_Handled_Sequence_Of_Statements (Loc,
7398 Statements => Astats),
7399 Has_Created_Identifier => True,
7400 Is_Asynchronous_Call_Block => True);
7402 -- Append call to if Enqueue (When, DB'Unchecked_Access) then
7404 Rewrite (Ecall,
7405 Make_Implicit_If_Statement (N,
7406 Condition =>
7407 Make_Function_Call (Loc,
7408 Name => Enqueue_Call,
7409 Parameter_Associations => Parameter_Associations (Ecall)),
7410 Then_Statements =>
7411 New_List (Make_Block_Statement (Loc,
7412 Handled_Statement_Sequence =>
7413 Make_Handled_Sequence_Of_Statements (Loc,
7414 Statements => New_List (
7415 Make_Implicit_Label_Declaration (Loc,
7416 Defining_Identifier => Blk_Ent,
7417 Label_Construct => Abortable_Block),
7418 Abortable_Block),
7419 Exception_Handlers => Hdle)))));
7421 Stmts := New_List (Ecall);
7423 -- Construct statement sequence for new block
7425 Append_To (Stmts,
7426 Make_Implicit_If_Statement (N,
7427 Condition =>
7428 Make_Function_Call (Loc,
7429 Name => New_Occurrence_Of (
7430 RTE (RE_Timed_Out), Loc),
7431 Parameter_Associations => New_List (
7432 Make_Attribute_Reference (Loc,
7433 Prefix => New_Occurrence_Of (Dblock_Ent, Loc),
7434 Attribute_Name => Name_Unchecked_Access))),
7435 Then_Statements => Tstats));
7437 -- The result is the new block
7439 Set_Entry_Cancel_Parameter (Blk_Ent, Dblock_Ent);
7441 Rewrite (N,
7442 Make_Block_Statement (Loc,
7443 Declarations => New_List (
7444 Make_Object_Declaration (Loc,
7445 Defining_Identifier => Dblock_Ent,
7446 Aliased_Present => True,
7447 Object_Definition =>
7448 New_Occurrence_Of (RTE (RE_Delay_Block), Loc))),
7450 Handled_Statement_Sequence =>
7451 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
7453 Analyze (N);
7454 return;
7455 end if;
7457 else
7458 N_Orig := N;
7459 end if;
7461 Extract_Entry (Ecall, Concval, Ename, Index);
7462 Build_Simple_Entry_Call (Ecall, Concval, Ename, Index);
7464 Stmts := Statements (Handled_Statement_Sequence (Ecall));
7465 Decls := Declarations (Ecall);
7467 if Is_Protected_Type (Etype (Concval)) then
7469 -- Get the declarations of the block expanded from the entry call
7471 Decl := First (Decls);
7472 while Present (Decl)
7473 and then (Nkind (Decl) /= N_Object_Declaration
7474 or else not Is_RTE (Etype (Object_Definition (Decl)),
7475 RE_Communication_Block))
7476 loop
7477 Next (Decl);
7478 end loop;
7480 pragma Assert (Present (Decl));
7481 Cancel_Param := Defining_Identifier (Decl);
7483 -- Change the mode of the Protected_Entry_Call call
7485 -- Protected_Entry_Call (
7486 -- Object => po._object'Access,
7487 -- E => <entry index>;
7488 -- Uninterpreted_Data => P'Address;
7489 -- Mode => Asynchronous_Call;
7490 -- Block => Bnn);
7492 -- Skip assignments to temporaries created for in-out parameters
7494 -- This makes unwarranted assumptions about the shape of the expanded
7495 -- tree for the call, and should be cleaned up ???
7497 Stmt := First (Stmts);
7498 while Nkind (Stmt) /= N_Procedure_Call_Statement loop
7499 Next (Stmt);
7500 end loop;
7502 Call := Stmt;
7504 Param := First (Parameter_Associations (Call));
7505 while Present (Param)
7506 and then not Is_RTE (Etype (Param), RE_Call_Modes)
7507 loop
7508 Next (Param);
7509 end loop;
7511 pragma Assert (Present (Param));
7512 Rewrite (Param, New_Occurrence_Of (RTE (RE_Asynchronous_Call), Loc));
7513 Analyze (Param);
7515 -- Append an if statement to execute the abortable part
7517 -- Generate:
7518 -- if Enqueued (Bnn) then
7520 Append_To (Stmts,
7521 Make_Implicit_If_Statement (N,
7522 Condition =>
7523 Make_Function_Call (Loc,
7524 Name => New_Occurrence_Of (RTE (RE_Enqueued), Loc),
7525 Parameter_Associations => New_List (
7526 New_Occurrence_Of (Cancel_Param, Loc))),
7527 Then_Statements => Astats));
7529 Abortable_Block :=
7530 Make_Block_Statement (Loc,
7531 Identifier => New_Occurrence_Of (Blk_Ent, Loc),
7532 Handled_Statement_Sequence =>
7533 Make_Handled_Sequence_Of_Statements (Loc, Statements => Stmts),
7534 Has_Created_Identifier => True,
7535 Is_Asynchronous_Call_Block => True);
7537 -- Aborts are not deferred at beginning of exception handlers in
7538 -- ZCX mode.
7540 if ZCX_Exceptions then
7541 Handler_Stmt := Make_Null_Statement (Loc);
7543 else
7544 Handler_Stmt := Build_Runtime_Call (Loc, RE_Abort_Undefer);
7545 end if;
7547 Stmts := New_List (
7548 Make_Block_Statement (Loc,
7549 Handled_Statement_Sequence =>
7550 Make_Handled_Sequence_Of_Statements (Loc,
7551 Statements => New_List (
7552 Make_Implicit_Label_Declaration (Loc,
7553 Defining_Identifier => Blk_Ent,
7554 Label_Construct => Abortable_Block),
7555 Abortable_Block),
7557 -- exception
7559 Exception_Handlers => New_List (
7560 Make_Implicit_Exception_Handler (Loc,
7562 -- when Abort_Signal =>
7563 -- Abort_Undefer.all;
7565 Exception_Choices =>
7566 New_List (New_Occurrence_Of (Stand.Abort_Signal, Loc)),
7567 Statements => New_List (Handler_Stmt))))),
7569 -- if not Cancelled (Bnn) then
7570 -- triggered statements
7571 -- end if;
7573 Make_Implicit_If_Statement (N,
7574 Condition => Make_Op_Not (Loc,
7575 Right_Opnd =>
7576 Make_Function_Call (Loc,
7577 Name => New_Occurrence_Of (RTE (RE_Cancelled), Loc),
7578 Parameter_Associations => New_List (
7579 New_Occurrence_Of (Cancel_Param, Loc)))),
7580 Then_Statements => Tstats));
7582 -- Asynchronous task entry call
7584 else
7585 if No (Decls) then
7586 Decls := New_List;
7587 end if;
7589 B := Make_Defining_Identifier (Loc, Name_uB);
7591 -- Insert declaration of B in declarations of existing block
7593 Prepend_To (Decls,
7594 Make_Object_Declaration (Loc,
7595 Defining_Identifier => B,
7596 Object_Definition =>
7597 New_Occurrence_Of (Standard_Boolean, Loc)));
7599 Cancel_Param := Make_Defining_Identifier (Loc, Name_uC);
7601 -- Insert the declaration of C in the declarations of the existing
7602 -- block. The variable is initialized to something (True or False,
7603 -- does not matter) to prevent CodePeer from complaining about a
7604 -- possible read of an uninitialized variable.
7606 Prepend_To (Decls,
7607 Make_Object_Declaration (Loc,
7608 Defining_Identifier => Cancel_Param,
7609 Object_Definition => New_Occurrence_Of (Standard_Boolean, Loc),
7610 Expression => New_Occurrence_Of (Standard_False, Loc),
7611 Has_Init_Expression => True));
7613 -- Remove and save the call to Call_Simple
7615 Stmt := First (Stmts);
7617 -- Skip assignments to temporaries created for in-out parameters.
7618 -- This makes unwarranted assumptions about the shape of the expanded
7619 -- tree for the call, and should be cleaned up ???
7621 while Nkind (Stmt) /= N_Procedure_Call_Statement loop
7622 Next (Stmt);
7623 end loop;
7625 Call := Stmt;
7627 -- Create the inner block to protect the abortable part
7629 Hdle := New_List (Build_Abort_Block_Handler (Loc));
7631 Prepend_To (Astats, Build_Runtime_Call (Loc, RE_Abort_Undefer));
7633 Abortable_Block :=
7634 Make_Block_Statement (Loc,
7635 Identifier => New_Occurrence_Of (Blk_Ent, Loc),
7636 Handled_Statement_Sequence =>
7637 Make_Handled_Sequence_Of_Statements (Loc, Statements => Astats),
7638 Has_Created_Identifier => True,
7639 Is_Asynchronous_Call_Block => True);
7641 Insert_After (Call,
7642 Make_Block_Statement (Loc,
7643 Handled_Statement_Sequence =>
7644 Make_Handled_Sequence_Of_Statements (Loc,
7645 Statements => New_List (
7646 Make_Implicit_Label_Declaration (Loc,
7647 Defining_Identifier => Blk_Ent,
7648 Label_Construct => Abortable_Block),
7649 Abortable_Block),
7650 Exception_Handlers => Hdle)));
7652 -- Create new call statement
7654 Params := Parameter_Associations (Call);
7656 Append_To (Params,
7657 New_Occurrence_Of (RTE (RE_Asynchronous_Call), Loc));
7658 Append_To (Params, New_Occurrence_Of (B, Loc));
7660 Rewrite (Call,
7661 Make_Procedure_Call_Statement (Loc,
7662 Name => New_Occurrence_Of (RTE (RE_Task_Entry_Call), Loc),
7663 Parameter_Associations => Params));
7665 -- Construct statement sequence for new block
7667 Append_To (Stmts,
7668 Make_Implicit_If_Statement (N,
7669 Condition =>
7670 Make_Op_Not (Loc, New_Occurrence_Of (Cancel_Param, Loc)),
7671 Then_Statements => Tstats));
7673 -- Protected the call against abort
7675 Prepend_To (Stmts, Build_Runtime_Call (Loc, RE_Abort_Defer));
7676 end if;
7678 Set_Entry_Cancel_Parameter (Blk_Ent, Cancel_Param);
7680 -- The result is the new block
7682 Rewrite (N_Orig,
7683 Make_Block_Statement (Loc,
7684 Declarations => Decls,
7685 Handled_Statement_Sequence =>
7686 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
7688 Analyze (N_Orig);
7689 end Expand_N_Asynchronous_Select;
7691 -------------------------------------
7692 -- Expand_N_Conditional_Entry_Call --
7693 -------------------------------------
7695 -- The conditional task entry call is converted to a call to
7696 -- Task_Entry_Call:
7698 -- declare
7699 -- B : Boolean;
7700 -- P : parms := (parm, parm, parm);
7702 -- begin
7703 -- Task_Entry_Call
7704 -- (<acceptor-task>, -- Acceptor
7705 -- <entry-index>, -- E
7706 -- P'Address, -- Uninterpreted_Data
7707 -- Conditional_Call, -- Mode
7708 -- B); -- Rendezvous_Successful
7709 -- parm := P.param;
7710 -- parm := P.param;
7711 -- ...
7712 -- if B then
7713 -- normal-statements
7714 -- else
7715 -- else-statements
7716 -- end if;
7717 -- end;
7719 -- For a description of the use of P and the assignments after the call,
7720 -- see Expand_N_Entry_Call_Statement. Note that the entry call of the
7721 -- conditional entry call has already been expanded (by the Expand_N_Entry
7722 -- _Call_Statement procedure) as follows:
7724 -- declare
7725 -- P : parms := (parm, parm, parm);
7726 -- begin
7727 -- ... info for in-out parameters
7728 -- Call_Simple (acceptor-task, entry-index, P'Address);
7729 -- parm := P.param;
7730 -- parm := P.param;
7731 -- ...
7732 -- end;
7734 -- so the task at hand is to convert the latter expansion into the former
7736 -- The conditional protected entry call is converted to a call to
7737 -- Protected_Entry_Call:
7739 -- declare
7740 -- P : parms := (parm, parm, parm);
7741 -- Bnn : Communications_Block;
7743 -- begin
7744 -- Protected_Entry_Call
7745 -- (po._object'Access, -- Object
7746 -- <entry index>, -- E
7747 -- P'Address, -- Uninterpreted_Data
7748 -- Conditional_Call, -- Mode
7749 -- Bnn); -- Block
7750 -- parm := P.param;
7751 -- parm := P.param;
7752 -- ...
7753 -- if Cancelled (Bnn) then
7754 -- else-statements
7755 -- else
7756 -- normal-statements
7757 -- end if;
7758 -- end;
7760 -- Ada 2005 (AI-345): A dispatching conditional entry call is converted
7761 -- into:
7763 -- declare
7764 -- B : Boolean := False;
7765 -- C : Ada.Tags.Prim_Op_Kind;
7766 -- K : Ada.Tags.Tagged_Kind :=
7767 -- Ada.Tags.Get_Tagged_Kind (Ada.Tags.Tag (<object>));
7768 -- P : Parameters := (Param1 .. ParamN);
7769 -- S : Integer;
7771 -- begin
7772 -- if K = Ada.Tags.TK_Limited_Tagged
7773 -- or else K = Ada.Tags.TK_Tagged
7774 -- then
7775 -- <dispatching-call>;
7776 -- <triggering-statements>
7778 -- else
7779 -- S :=
7780 -- Ada.Tags.Get_Offset_Index
7781 -- (Ada.Tags.Tag (<object>), DT_Position (<dispatching-call>));
7783 -- _Disp_Conditional_Select (<object>, S, P'Address, C, B);
7785 -- if C = POK_Protected_Entry
7786 -- or else C = POK_Task_Entry
7787 -- then
7788 -- Param1 := P.Param1;
7789 -- ...
7790 -- ParamN := P.ParamN;
7791 -- end if;
7793 -- if B then
7794 -- if C = POK_Procedure
7795 -- or else C = POK_Protected_Procedure
7796 -- or else C = POK_Task_Procedure
7797 -- then
7798 -- <dispatching-call>;
7799 -- end if;
7801 -- <triggering-statements>
7802 -- else
7803 -- <else-statements>
7804 -- end if;
7805 -- end if;
7806 -- end;
7808 procedure Expand_N_Conditional_Entry_Call (N : Node_Id) is
7809 Loc : constant Source_Ptr := Sloc (N);
7810 Alt : constant Node_Id := Entry_Call_Alternative (N);
7811 Blk : Node_Id := Entry_Call_Statement (Alt);
7813 Actuals : List_Id;
7814 Blk_Typ : Entity_Id;
7815 Call : Node_Id;
7816 Call_Ent : Entity_Id;
7817 Conc_Typ_Stmts : List_Id;
7818 Decl : Node_Id;
7819 Decls : List_Id;
7820 Formals : List_Id;
7821 Lim_Typ_Stmts : List_Id;
7822 N_Stats : List_Id;
7823 Obj : Entity_Id;
7824 Param : Node_Id;
7825 Params : List_Id;
7826 Stmt : Node_Id;
7827 Stmts : List_Id;
7828 Transient_Blk : Node_Id;
7829 Unpack : List_Id;
7831 B : Entity_Id; -- Call status flag
7832 C : Entity_Id; -- Call kind
7833 K : Entity_Id; -- Tagged kind
7834 P : Entity_Id; -- Parameter block
7835 S : Entity_Id; -- Primitive operation slot
7837 begin
7838 Process_Statements_For_Controlled_Objects (N);
7840 if Ada_Version >= Ada_2005
7841 and then Nkind (Blk) = N_Procedure_Call_Statement
7842 then
7843 Extract_Dispatching_Call (Blk, Call_Ent, Obj, Actuals, Formals);
7845 Decls := New_List;
7846 Stmts := New_List;
7848 -- Call status flag processing, generate:
7849 -- B : Boolean := False;
7851 B := Build_B (Loc, Decls);
7853 -- Call kind processing, generate:
7854 -- C : Ada.Tags.Prim_Op_Kind;
7856 C := Build_C (Loc, Decls);
7858 -- Tagged kind processing, generate:
7859 -- K : Ada.Tags.Tagged_Kind :=
7860 -- Ada.Tags.Get_Tagged_Kind (Ada.Tags.Tag (<object>));
7862 K := Build_K (Loc, Decls, Obj);
7864 -- Parameter block processing
7866 Blk_Typ := Build_Parameter_Block (Loc, Actuals, Formals, Decls);
7867 P := Parameter_Block_Pack
7868 (Loc, Blk_Typ, Actuals, Formals, Decls, Stmts);
7870 -- Dispatch table slot processing, generate:
7871 -- S : Integer;
7873 S := Build_S (Loc, Decls);
7875 -- Generate:
7876 -- S := Ada.Tags.Get_Offset_Index
7877 -- (Ada.Tags.Tag (<object>), DT_Position (Call_Ent));
7879 Conc_Typ_Stmts :=
7880 New_List (Build_S_Assignment (Loc, S, Obj, Call_Ent));
7882 -- Generate:
7883 -- _Disp_Conditional_Select (<object>, S, P'Address, C, B);
7885 Append_To (Conc_Typ_Stmts,
7886 Make_Procedure_Call_Statement (Loc,
7887 Name =>
7888 New_Occurrence_Of (
7889 Find_Prim_Op (Etype (Etype (Obj)),
7890 Name_uDisp_Conditional_Select),
7891 Loc),
7892 Parameter_Associations =>
7893 New_List (
7894 New_Copy_Tree (Obj), -- <object>
7895 New_Occurrence_Of (S, Loc), -- S
7896 Make_Attribute_Reference (Loc, -- P'Address
7897 Prefix => New_Occurrence_Of (P, Loc),
7898 Attribute_Name => Name_Address),
7899 New_Occurrence_Of (C, Loc), -- C
7900 New_Occurrence_Of (B, Loc)))); -- B
7902 -- Generate:
7903 -- if C = POK_Protected_Entry
7904 -- or else C = POK_Task_Entry
7905 -- then
7906 -- Param1 := P.Param1;
7907 -- ...
7908 -- ParamN := P.ParamN;
7909 -- end if;
7911 Unpack := Parameter_Block_Unpack (Loc, P, Actuals, Formals);
7913 -- Generate the if statement only when the packed parameters need
7914 -- explicit assignments to their corresponding actuals.
7916 if Present (Unpack) then
7917 Append_To (Conc_Typ_Stmts,
7918 Make_Implicit_If_Statement (N,
7919 Condition =>
7920 Make_Or_Else (Loc,
7921 Left_Opnd =>
7922 Make_Op_Eq (Loc,
7923 Left_Opnd =>
7924 New_Occurrence_Of (C, Loc),
7925 Right_Opnd =>
7926 New_Occurrence_Of (RTE (
7927 RE_POK_Protected_Entry), Loc)),
7929 Right_Opnd =>
7930 Make_Op_Eq (Loc,
7931 Left_Opnd =>
7932 New_Occurrence_Of (C, Loc),
7933 Right_Opnd =>
7934 New_Occurrence_Of (RTE (RE_POK_Task_Entry), Loc))),
7936 Then_Statements => Unpack));
7937 end if;
7939 -- Generate:
7940 -- if B then
7941 -- if C = POK_Procedure
7942 -- or else C = POK_Protected_Procedure
7943 -- or else C = POK_Task_Procedure
7944 -- then
7945 -- <dispatching-call>
7946 -- end if;
7947 -- <normal-statements>
7948 -- else
7949 -- <else-statements>
7950 -- end if;
7952 N_Stats := New_Copy_List_Tree (Statements (Alt));
7954 Prepend_To (N_Stats,
7955 Make_Implicit_If_Statement (N,
7956 Condition =>
7957 Make_Or_Else (Loc,
7958 Left_Opnd =>
7959 Make_Op_Eq (Loc,
7960 Left_Opnd =>
7961 New_Occurrence_Of (C, Loc),
7962 Right_Opnd =>
7963 New_Occurrence_Of (RTE (RE_POK_Procedure), Loc)),
7965 Right_Opnd =>
7966 Make_Or_Else (Loc,
7967 Left_Opnd =>
7968 Make_Op_Eq (Loc,
7969 Left_Opnd =>
7970 New_Occurrence_Of (C, Loc),
7971 Right_Opnd =>
7972 New_Occurrence_Of (RTE (
7973 RE_POK_Protected_Procedure), Loc)),
7975 Right_Opnd =>
7976 Make_Op_Eq (Loc,
7977 Left_Opnd =>
7978 New_Occurrence_Of (C, Loc),
7979 Right_Opnd =>
7980 New_Occurrence_Of (RTE (
7981 RE_POK_Task_Procedure), Loc)))),
7983 Then_Statements =>
7984 New_List (Blk)));
7986 Append_To (Conc_Typ_Stmts,
7987 Make_Implicit_If_Statement (N,
7988 Condition => New_Occurrence_Of (B, Loc),
7989 Then_Statements => N_Stats,
7990 Else_Statements => Else_Statements (N)));
7992 -- Generate:
7993 -- <dispatching-call>;
7994 -- <triggering-statements>
7996 Lim_Typ_Stmts := New_Copy_List_Tree (Statements (Alt));
7997 Prepend_To (Lim_Typ_Stmts, New_Copy_Tree (Blk));
7999 -- Generate:
8000 -- if K = Ada.Tags.TK_Limited_Tagged
8001 -- or else K = Ada.Tags.TK_Tagged
8002 -- then
8003 -- Lim_Typ_Stmts
8004 -- else
8005 -- Conc_Typ_Stmts
8006 -- end if;
8008 Append_To (Stmts,
8009 Make_Implicit_If_Statement (N,
8010 Condition => Build_Dispatching_Tag_Check (K, N),
8011 Then_Statements => Lim_Typ_Stmts,
8012 Else_Statements => Conc_Typ_Stmts));
8014 Rewrite (N,
8015 Make_Block_Statement (Loc,
8016 Declarations =>
8017 Decls,
8018 Handled_Statement_Sequence =>
8019 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
8021 -- As described above, the entry alternative is transformed into a
8022 -- block that contains the gnulli call, and possibly assignment
8023 -- statements for in-out parameters. The gnulli call may itself be
8024 -- rewritten into a transient block if some unconstrained parameters
8025 -- require it. We need to retrieve the call to complete its parameter
8026 -- list.
8028 else
8029 Transient_Blk :=
8030 First_Real_Statement (Handled_Statement_Sequence (Blk));
8032 if Present (Transient_Blk)
8033 and then Nkind (Transient_Blk) = N_Block_Statement
8034 then
8035 Blk := Transient_Blk;
8036 end if;
8038 Stmts := Statements (Handled_Statement_Sequence (Blk));
8039 Stmt := First (Stmts);
8040 while Nkind (Stmt) /= N_Procedure_Call_Statement loop
8041 Next (Stmt);
8042 end loop;
8044 Call := Stmt;
8045 Params := Parameter_Associations (Call);
8047 if Is_RTE (Entity (Name (Call)), RE_Protected_Entry_Call) then
8049 -- Substitute Conditional_Entry_Call for Simple_Call parameter
8051 Param := First (Params);
8052 while Present (Param)
8053 and then not Is_RTE (Etype (Param), RE_Call_Modes)
8054 loop
8055 Next (Param);
8056 end loop;
8058 pragma Assert (Present (Param));
8059 Rewrite (Param,
8060 New_Occurrence_Of (RTE (RE_Conditional_Call), Loc));
8062 Analyze (Param);
8064 -- Find the Communication_Block parameter for the call to the
8065 -- Cancelled function.
8067 Decl := First (Declarations (Blk));
8068 while Present (Decl)
8069 and then not Is_RTE (Etype (Object_Definition (Decl)),
8070 RE_Communication_Block)
8071 loop
8072 Next (Decl);
8073 end loop;
8075 -- Add an if statement to execute the else part if the call
8076 -- does not succeed (as indicated by the Cancelled predicate).
8078 Append_To (Stmts,
8079 Make_Implicit_If_Statement (N,
8080 Condition => Make_Function_Call (Loc,
8081 Name => New_Occurrence_Of (RTE (RE_Cancelled), Loc),
8082 Parameter_Associations => New_List (
8083 New_Occurrence_Of (Defining_Identifier (Decl), Loc))),
8084 Then_Statements => Else_Statements (N),
8085 Else_Statements => Statements (Alt)));
8087 else
8088 B := Make_Defining_Identifier (Loc, Name_uB);
8090 -- Insert declaration of B in declarations of existing block
8092 if No (Declarations (Blk)) then
8093 Set_Declarations (Blk, New_List);
8094 end if;
8096 Prepend_To (Declarations (Blk),
8097 Make_Object_Declaration (Loc,
8098 Defining_Identifier => B,
8099 Object_Definition =>
8100 New_Occurrence_Of (Standard_Boolean, Loc)));
8102 -- Create new call statement
8104 Append_To (Params,
8105 New_Occurrence_Of (RTE (RE_Conditional_Call), Loc));
8106 Append_To (Params, New_Occurrence_Of (B, Loc));
8108 Rewrite (Call,
8109 Make_Procedure_Call_Statement (Loc,
8110 Name => New_Occurrence_Of (RTE (RE_Task_Entry_Call), Loc),
8111 Parameter_Associations => Params));
8113 -- Construct statement sequence for new block
8115 Append_To (Stmts,
8116 Make_Implicit_If_Statement (N,
8117 Condition => New_Occurrence_Of (B, Loc),
8118 Then_Statements => Statements (Alt),
8119 Else_Statements => Else_Statements (N)));
8120 end if;
8122 -- The result is the new block
8124 Rewrite (N,
8125 Make_Block_Statement (Loc,
8126 Declarations => Declarations (Blk),
8127 Handled_Statement_Sequence =>
8128 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
8129 end if;
8131 Analyze (N);
8132 end Expand_N_Conditional_Entry_Call;
8134 ---------------------------------------
8135 -- Expand_N_Delay_Relative_Statement --
8136 ---------------------------------------
8138 -- Delay statement is implemented as a procedure call to Delay_For
8139 -- defined in Ada.Calendar.Delays in order to reduce the overhead of
8140 -- simple delays imposed by the use of Protected Objects.
8142 procedure Expand_N_Delay_Relative_Statement (N : Node_Id) is
8143 Loc : constant Source_Ptr := Sloc (N);
8144 Proc : Entity_Id;
8146 begin
8147 -- Try to use System.Relative_Delays.Delay_For only if available. This
8148 -- is the implementation used on restricted platforms when Ada.Calendar
8149 -- is not available.
8151 if RTE_Available (RO_RD_Delay_For) then
8152 Proc := RTE (RO_RD_Delay_For);
8154 -- Otherwise, use Ada.Calendar.Delays.Delay_For and emit an error
8155 -- message if not available.
8157 else
8158 Proc := RTE (RO_CA_Delay_For);
8159 end if;
8161 Rewrite (N,
8162 Make_Procedure_Call_Statement (Loc,
8163 Name => New_Occurrence_Of (Proc, Loc),
8164 Parameter_Associations => New_List (Expression (N))));
8165 Analyze (N);
8166 end Expand_N_Delay_Relative_Statement;
8168 ------------------------------------
8169 -- Expand_N_Delay_Until_Statement --
8170 ------------------------------------
8172 -- Delay Until statement is implemented as a procedure call to
8173 -- Delay_Until defined in Ada.Calendar.Delays and Ada.Real_Time.Delays.
8175 procedure Expand_N_Delay_Until_Statement (N : Node_Id) is
8176 Loc : constant Source_Ptr := Sloc (N);
8177 Typ : Entity_Id;
8179 begin
8180 if Is_RTE (Base_Type (Etype (Expression (N))), RO_CA_Time) then
8181 Typ := RTE (RO_CA_Delay_Until);
8182 else
8183 Typ := RTE (RO_RT_Delay_Until);
8184 end if;
8186 Rewrite (N,
8187 Make_Procedure_Call_Statement (Loc,
8188 Name => New_Occurrence_Of (Typ, Loc),
8189 Parameter_Associations => New_List (Expression (N))));
8191 Analyze (N);
8192 end Expand_N_Delay_Until_Statement;
8194 -------------------------
8195 -- Expand_N_Entry_Body --
8196 -------------------------
8198 procedure Expand_N_Entry_Body (N : Node_Id) is
8199 begin
8200 -- Associate discriminals with the next protected operation body to be
8201 -- expanded.
8203 if Present (Next_Protected_Operation (N)) then
8204 Set_Discriminals (Parent (Current_Scope));
8205 end if;
8206 end Expand_N_Entry_Body;
8208 -----------------------------------
8209 -- Expand_N_Entry_Call_Statement --
8210 -----------------------------------
8212 -- An entry call is expanded into GNARLI calls to implement a simple entry
8213 -- call (see Build_Simple_Entry_Call).
8215 procedure Expand_N_Entry_Call_Statement (N : Node_Id) is
8216 Concval : Node_Id;
8217 Ename : Node_Id;
8218 Index : Node_Id;
8220 begin
8221 if No_Run_Time_Mode then
8222 Error_Msg_CRT ("entry call", N);
8223 return;
8224 end if;
8226 -- If this entry call is part of an asynchronous select, don't expand it
8227 -- here; it will be expanded with the select statement. Don't expand
8228 -- timed entry calls either, as they are translated into asynchronous
8229 -- entry calls.
8231 -- ??? This whole approach is questionable; it may be better to go back
8232 -- to allowing the expansion to take place and then attempting to fix it
8233 -- up in Expand_N_Asynchronous_Select. The tricky part is figuring out
8234 -- whether the expanded call is on a task or protected entry.
8236 if (Nkind (Parent (N)) /= N_Triggering_Alternative
8237 or else N /= Triggering_Statement (Parent (N)))
8238 and then (Nkind (Parent (N)) /= N_Entry_Call_Alternative
8239 or else N /= Entry_Call_Statement (Parent (N))
8240 or else Nkind (Parent (Parent (N))) /= N_Timed_Entry_Call)
8241 then
8242 Extract_Entry (N, Concval, Ename, Index);
8243 Build_Simple_Entry_Call (N, Concval, Ename, Index);
8244 end if;
8245 end Expand_N_Entry_Call_Statement;
8247 --------------------------------
8248 -- Expand_N_Entry_Declaration --
8249 --------------------------------
8251 -- If there are parameters, then first, each of the formals is marked by
8252 -- setting Is_Entry_Formal. Next a record type is built which is used to
8253 -- hold the parameter values. The name of this record type is entryP where
8254 -- entry is the name of the entry, with an additional corresponding access
8255 -- type called entryPA. The record type has matching components for each
8256 -- formal (the component names are the same as the formal names). For
8257 -- elementary types, the component type matches the formal type. For
8258 -- composite types, an access type is declared (with the name formalA)
8259 -- which designates the formal type, and the type of the component is this
8260 -- access type. Finally the Entry_Component of each formal is set to
8261 -- reference the corresponding record component.
8263 procedure Expand_N_Entry_Declaration (N : Node_Id) is
8264 Loc : constant Source_Ptr := Sloc (N);
8265 Entry_Ent : constant Entity_Id := Defining_Identifier (N);
8266 Components : List_Id;
8267 Formal : Node_Id;
8268 Ftype : Entity_Id;
8269 Last_Decl : Node_Id;
8270 Component : Entity_Id;
8271 Ctype : Entity_Id;
8272 Decl : Node_Id;
8273 Rec_Ent : Entity_Id;
8274 Acc_Ent : Entity_Id;
8276 begin
8277 Formal := First_Formal (Entry_Ent);
8278 Last_Decl := N;
8280 -- Most processing is done only if parameters are present
8282 if Present (Formal) then
8283 Components := New_List;
8285 -- Loop through formals
8287 while Present (Formal) loop
8288 Set_Is_Entry_Formal (Formal);
8289 Component :=
8290 Make_Defining_Identifier (Sloc (Formal), Chars (Formal));
8291 Set_Entry_Component (Formal, Component);
8292 Set_Entry_Formal (Component, Formal);
8293 Ftype := Etype (Formal);
8295 -- Declare new access type and then append
8297 Ctype := Make_Temporary (Loc, 'A');
8298 Set_Is_Param_Block_Component_Type (Ctype);
8300 Decl :=
8301 Make_Full_Type_Declaration (Loc,
8302 Defining_Identifier => Ctype,
8303 Type_Definition =>
8304 Make_Access_To_Object_Definition (Loc,
8305 All_Present => True,
8306 Constant_Present => Ekind (Formal) = E_In_Parameter,
8307 Subtype_Indication => New_Occurrence_Of (Ftype, Loc)));
8309 Insert_After (Last_Decl, Decl);
8310 Last_Decl := Decl;
8312 Append_To (Components,
8313 Make_Component_Declaration (Loc,
8314 Defining_Identifier => Component,
8315 Component_Definition =>
8316 Make_Component_Definition (Loc,
8317 Aliased_Present => False,
8318 Subtype_Indication => New_Occurrence_Of (Ctype, Loc))));
8320 Next_Formal_With_Extras (Formal);
8321 end loop;
8323 -- Create the Entry_Parameter_Record declaration
8325 Rec_Ent := Make_Temporary (Loc, 'P');
8327 Decl :=
8328 Make_Full_Type_Declaration (Loc,
8329 Defining_Identifier => Rec_Ent,
8330 Type_Definition =>
8331 Make_Record_Definition (Loc,
8332 Component_List =>
8333 Make_Component_List (Loc,
8334 Component_Items => Components)));
8336 Insert_After (Last_Decl, Decl);
8337 Last_Decl := Decl;
8339 -- Construct and link in the corresponding access type
8341 Acc_Ent := Make_Temporary (Loc, 'A');
8343 Set_Entry_Parameters_Type (Entry_Ent, Acc_Ent);
8345 Decl :=
8346 Make_Full_Type_Declaration (Loc,
8347 Defining_Identifier => Acc_Ent,
8348 Type_Definition =>
8349 Make_Access_To_Object_Definition (Loc,
8350 All_Present => True,
8351 Subtype_Indication => New_Occurrence_Of (Rec_Ent, Loc)));
8353 Insert_After (Last_Decl, Decl);
8354 end if;
8355 end Expand_N_Entry_Declaration;
8357 -----------------------------
8358 -- Expand_N_Protected_Body --
8359 -----------------------------
8361 -- Protected bodies are expanded to the completion of the subprograms
8362 -- created for the corresponding protected type. These are a protected and
8363 -- unprotected version of each protected subprogram in the object, a
8364 -- function to calculate each entry barrier, and a procedure to execute the
8365 -- sequence of statements of each protected entry body. For example, for
8366 -- protected type ptype:
8368 -- function entB
8369 -- (O : System.Address;
8370 -- E : Protected_Entry_Index)
8371 -- return Boolean
8372 -- is
8373 -- <discriminant renamings>
8374 -- <private object renamings>
8375 -- begin
8376 -- return <barrier expression>;
8377 -- end entB;
8379 -- procedure pprocN (_object : in out poV;...) is
8380 -- <discriminant renamings>
8381 -- <private object renamings>
8382 -- begin
8383 -- <sequence of statements>
8384 -- end pprocN;
8386 -- procedure pprocP (_object : in out poV;...) is
8387 -- procedure _clean is
8388 -- Pn : Boolean;
8389 -- begin
8390 -- ptypeS (_object, Pn);
8391 -- Unlock (_object._object'Access);
8392 -- Abort_Undefer.all;
8393 -- end _clean;
8395 -- begin
8396 -- Abort_Defer.all;
8397 -- Lock (_object._object'Access);
8398 -- pprocN (_object;...);
8399 -- at end
8400 -- _clean;
8401 -- end pproc;
8403 -- function pfuncN (_object : poV;...) return Return_Type is
8404 -- <discriminant renamings>
8405 -- <private object renamings>
8406 -- begin
8407 -- <sequence of statements>
8408 -- end pfuncN;
8410 -- function pfuncP (_object : poV) return Return_Type is
8411 -- procedure _clean is
8412 -- begin
8413 -- Unlock (_object._object'Access);
8414 -- Abort_Undefer.all;
8415 -- end _clean;
8417 -- begin
8418 -- Abort_Defer.all;
8419 -- Lock (_object._object'Access);
8420 -- return pfuncN (_object);
8422 -- at end
8423 -- _clean;
8424 -- end pfunc;
8426 -- procedure entE
8427 -- (O : System.Address;
8428 -- P : System.Address;
8429 -- E : Protected_Entry_Index)
8430 -- is
8431 -- <discriminant renamings>
8432 -- <private object renamings>
8433 -- type poVP is access poV;
8434 -- _Object : ptVP := ptVP!(O);
8436 -- begin
8437 -- begin
8438 -- <statement sequence>
8439 -- Complete_Entry_Body (_Object._Object);
8440 -- exception
8441 -- when all others =>
8442 -- Exceptional_Complete_Entry_Body (
8443 -- _Object._Object, Get_GNAT_Exception);
8444 -- end;
8445 -- end entE;
8447 -- The type poV is the record created for the protected type to hold
8448 -- the state of the protected object.
8450 procedure Expand_N_Protected_Body (N : Node_Id) is
8451 Loc : constant Source_Ptr := Sloc (N);
8452 Pid : constant Entity_Id := Corresponding_Spec (N);
8454 Lock_Free_Active : constant Boolean := Uses_Lock_Free (Pid);
8455 -- This flag indicates whether the lock free implementation is active
8457 Current_Node : Node_Id;
8458 Disp_Op_Body : Node_Id;
8459 New_Op_Body : Node_Id;
8460 Op_Body : Node_Id;
8461 Op_Id : Entity_Id;
8463 function Build_Dispatching_Subprogram_Body
8464 (N : Node_Id;
8465 Pid : Node_Id;
8466 Prot_Bod : Node_Id) return Node_Id;
8467 -- Build a dispatching version of the protected subprogram body. The
8468 -- newly generated subprogram contains a call to the original protected
8469 -- body. The following code is generated:
8471 -- function <protected-function-name> (Param1 .. ParamN) return
8472 -- <return-type> is
8473 -- begin
8474 -- return <protected-function-name>P (Param1 .. ParamN);
8475 -- end <protected-function-name>;
8477 -- or
8479 -- procedure <protected-procedure-name> (Param1 .. ParamN) is
8480 -- begin
8481 -- <protected-procedure-name>P (Param1 .. ParamN);
8482 -- end <protected-procedure-name>
8484 ---------------------------------------
8485 -- Build_Dispatching_Subprogram_Body --
8486 ---------------------------------------
8488 function Build_Dispatching_Subprogram_Body
8489 (N : Node_Id;
8490 Pid : Node_Id;
8491 Prot_Bod : Node_Id) return Node_Id
8493 Loc : constant Source_Ptr := Sloc (N);
8494 Actuals : List_Id;
8495 Formal : Node_Id;
8496 Spec : Node_Id;
8497 Stmts : List_Id;
8499 begin
8500 -- Generate a specification without a letter suffix in order to
8501 -- override an interface function or procedure.
8503 Spec := Build_Protected_Sub_Specification (N, Pid, Dispatching_Mode);
8505 -- The formal parameters become the actuals of the protected function
8506 -- or procedure call.
8508 Actuals := New_List;
8509 Formal := First (Parameter_Specifications (Spec));
8510 while Present (Formal) loop
8511 Append_To (Actuals,
8512 Make_Identifier (Loc, Chars (Defining_Identifier (Formal))));
8513 Next (Formal);
8514 end loop;
8516 if Nkind (Spec) = N_Procedure_Specification then
8517 Stmts :=
8518 New_List (
8519 Make_Procedure_Call_Statement (Loc,
8520 Name =>
8521 New_Occurrence_Of (Corresponding_Spec (Prot_Bod), Loc),
8522 Parameter_Associations => Actuals));
8524 else
8525 pragma Assert (Nkind (Spec) = N_Function_Specification);
8527 Stmts :=
8528 New_List (
8529 Make_Simple_Return_Statement (Loc,
8530 Expression =>
8531 Make_Function_Call (Loc,
8532 Name =>
8533 New_Occurrence_Of (Corresponding_Spec (Prot_Bod), Loc),
8534 Parameter_Associations => Actuals)));
8535 end if;
8537 return
8538 Make_Subprogram_Body (Loc,
8539 Declarations => Empty_List,
8540 Specification => Spec,
8541 Handled_Statement_Sequence =>
8542 Make_Handled_Sequence_Of_Statements (Loc, Stmts));
8543 end Build_Dispatching_Subprogram_Body;
8545 -- Start of processing for Expand_N_Protected_Body
8547 begin
8548 if No_Run_Time_Mode then
8549 Error_Msg_CRT ("protected body", N);
8550 return;
8551 end if;
8553 -- This is the proper body corresponding to a stub. The declarations
8554 -- must be inserted at the point of the stub, which in turn is in the
8555 -- declarative part of the parent unit.
8557 if Nkind (Parent (N)) = N_Subunit then
8558 Current_Node := Corresponding_Stub (Parent (N));
8559 else
8560 Current_Node := N;
8561 end if;
8563 Op_Body := First (Declarations (N));
8565 -- The protected body is replaced with the bodies of its protected
8566 -- operations, and the declarations for internal objects that may
8567 -- have been created for entry family bounds.
8569 Rewrite (N, Make_Null_Statement (Sloc (N)));
8570 Analyze (N);
8572 while Present (Op_Body) loop
8573 case Nkind (Op_Body) is
8574 when N_Subprogram_Declaration =>
8575 null;
8577 when N_Subprogram_Body =>
8579 -- Do not create bodies for eliminated operations
8581 if not Is_Eliminated (Defining_Entity (Op_Body))
8582 and then not Is_Eliminated (Corresponding_Spec (Op_Body))
8583 then
8584 if Lock_Free_Active then
8585 New_Op_Body :=
8586 Build_Lock_Free_Unprotected_Subprogram_Body
8587 (Op_Body, Pid);
8588 else
8589 New_Op_Body :=
8590 Build_Unprotected_Subprogram_Body (Op_Body, Pid);
8591 end if;
8593 Insert_After (Current_Node, New_Op_Body);
8594 Current_Node := New_Op_Body;
8595 Analyze (New_Op_Body);
8597 -- Build the corresponding protected operation. It may
8598 -- appear that this is needed only if this is a visible
8599 -- operation of the type, or if it is an interrupt handler,
8600 -- and this was the strategy used previously in GNAT.
8602 -- However, the operation may be exported through a 'Access
8603 -- to an external caller. This is the common idiom in code
8604 -- that uses the Ada 2005 Timing_Events package. As a result
8605 -- we need to produce the protected body for both visible
8606 -- and private operations, as well as operations that only
8607 -- have a body in the source, and for which we create a
8608 -- declaration in the protected body itself.
8610 if Present (Corresponding_Spec (Op_Body)) then
8611 if Lock_Free_Active then
8612 New_Op_Body :=
8613 Build_Lock_Free_Protected_Subprogram_Body
8614 (Op_Body, Pid, Specification (New_Op_Body));
8615 else
8616 New_Op_Body :=
8617 Build_Protected_Subprogram_Body
8618 (Op_Body, Pid, Specification (New_Op_Body));
8619 end if;
8621 Insert_After (Current_Node, New_Op_Body);
8622 Analyze (New_Op_Body);
8624 Current_Node := New_Op_Body;
8626 -- Generate an overriding primitive operation body for
8627 -- this subprogram if the protected type implements an
8628 -- interface.
8630 if Ada_Version >= Ada_2005
8631 and then
8632 Present (Interfaces (Corresponding_Record_Type (Pid)))
8633 then
8634 Disp_Op_Body :=
8635 Build_Dispatching_Subprogram_Body
8636 (Op_Body, Pid, New_Op_Body);
8638 Insert_After (Current_Node, Disp_Op_Body);
8639 Analyze (Disp_Op_Body);
8641 Current_Node := Disp_Op_Body;
8642 end if;
8643 end if;
8644 end if;
8646 when N_Entry_Body =>
8647 Op_Id := Defining_Identifier (Op_Body);
8648 New_Op_Body := Build_Protected_Entry (Op_Body, Op_Id, Pid);
8650 Insert_After (Current_Node, New_Op_Body);
8651 Current_Node := New_Op_Body;
8652 Analyze (New_Op_Body);
8654 when N_Implicit_Label_Declaration =>
8655 null;
8657 when N_Itype_Reference =>
8658 Insert_After (Current_Node, New_Copy (Op_Body));
8660 when N_Freeze_Entity =>
8661 New_Op_Body := New_Copy (Op_Body);
8663 if Present (Entity (Op_Body))
8664 and then Freeze_Node (Entity (Op_Body)) = Op_Body
8665 then
8666 Set_Freeze_Node (Entity (Op_Body), New_Op_Body);
8667 end if;
8669 Insert_After (Current_Node, New_Op_Body);
8670 Current_Node := New_Op_Body;
8671 Analyze (New_Op_Body);
8673 when N_Pragma =>
8674 New_Op_Body := New_Copy (Op_Body);
8675 Insert_After (Current_Node, New_Op_Body);
8676 Current_Node := New_Op_Body;
8677 Analyze (New_Op_Body);
8679 when N_Object_Declaration =>
8680 pragma Assert (not Comes_From_Source (Op_Body));
8681 New_Op_Body := New_Copy (Op_Body);
8682 Insert_After (Current_Node, New_Op_Body);
8683 Current_Node := New_Op_Body;
8684 Analyze (New_Op_Body);
8686 when others =>
8687 raise Program_Error;
8688 end case;
8690 Next (Op_Body);
8691 end loop;
8693 -- Finally, create the body of the function that maps an entry index
8694 -- into the corresponding body index, except when there is no entry, or
8695 -- in a Ravenscar-like profile.
8697 if Corresponding_Runtime_Package (Pid) =
8698 System_Tasking_Protected_Objects_Entries
8699 then
8700 New_Op_Body := Build_Find_Body_Index (Pid);
8701 Insert_After (Current_Node, New_Op_Body);
8702 Current_Node := New_Op_Body;
8703 Analyze (New_Op_Body);
8704 end if;
8706 -- Ada 2005 (AI-345): Construct the primitive wrapper bodies after the
8707 -- protected body. At this point all wrapper specs have been created,
8708 -- frozen and included in the dispatch table for the protected type.
8710 if Ada_Version >= Ada_2005 then
8711 Build_Wrapper_Bodies (Loc, Pid, Current_Node);
8712 end if;
8713 end Expand_N_Protected_Body;
8715 -----------------------------------------
8716 -- Expand_N_Protected_Type_Declaration --
8717 -----------------------------------------
8719 -- First we create a corresponding record type declaration used to
8720 -- represent values of this protected type.
8721 -- The general form of this type declaration is
8723 -- type poV (discriminants) is record
8724 -- _Object : aliased <kind>Protection
8725 -- [(<entry count> [, <handler count>])];
8726 -- [entry_family : array (bounds) of Void;]
8727 -- <private data fields>
8728 -- end record;
8730 -- The discriminants are present only if the corresponding protected type
8731 -- has discriminants, and they exactly mirror the protected type
8732 -- discriminants. The private data fields similarly mirror the private
8733 -- declarations of the protected type.
8735 -- The Object field is always present. It contains RTS specific data used
8736 -- to control the protected object. It is declared as Aliased so that it
8737 -- can be passed as a pointer to the RTS. This allows the protected record
8738 -- to be referenced within RTS data structures. An appropriate Protection
8739 -- type and discriminant are generated.
8741 -- The Service field is present for protected objects with entries. It
8742 -- contains sufficient information to allow the entry service procedure for
8743 -- this object to be called when the object is not known till runtime.
8745 -- One entry_family component is present for each entry family in the
8746 -- task definition (see Expand_N_Task_Type_Declaration).
8748 -- When a protected object is declared, an instance of the protected type
8749 -- value record is created. The elaboration of this declaration creates the
8750 -- correct bounds for the entry families, and also evaluates the priority
8751 -- expression if needed. The initialization routine for the protected type
8752 -- itself then calls Initialize_Protection with appropriate parameters to
8753 -- initialize the value of the Task_Id field. Install_Handlers may be also
8754 -- called if a pragma Attach_Handler applies.
8756 -- Note: this record is passed to the subprograms created by the expansion
8757 -- of protected subprograms and entries. It is an in parameter to protected
8758 -- functions and an in out parameter to procedures and entry bodies. The
8759 -- Entity_Id for this created record type is placed in the
8760 -- Corresponding_Record_Type field of the associated protected type entity.
8762 -- Next we create a procedure specifications for protected subprograms and
8763 -- entry bodies. For each protected subprograms two subprograms are
8764 -- created, an unprotected and a protected version. The unprotected version
8765 -- is called from within other operations of the same protected object.
8767 -- We also build the call to register the procedure if a pragma
8768 -- Interrupt_Handler applies.
8770 -- A single subprogram is created to service all entry bodies; it has an
8771 -- additional boolean out parameter indicating that the previous entry call
8772 -- made by the current task was serviced immediately, i.e. not by proxy.
8773 -- The O parameter contains a pointer to a record object of the type
8774 -- described above. An untyped interface is used here to allow this
8775 -- procedure to be called in places where the type of the object to be
8776 -- serviced is not known. This must be done, for example, when a call that
8777 -- may have been requeued is cancelled; the corresponding object must be
8778 -- serviced, but which object that is not known till runtime.
8780 -- procedure ptypeS
8781 -- (O : System.Address; P : out Boolean);
8782 -- procedure pprocN (_object : in out poV);
8783 -- procedure pproc (_object : in out poV);
8784 -- function pfuncN (_object : poV);
8785 -- function pfunc (_object : poV);
8786 -- ...
8788 -- Note that this must come after the record type declaration, since
8789 -- the specs refer to this type.
8791 procedure Expand_N_Protected_Type_Declaration (N : Node_Id) is
8792 Discr_Map : constant Elist_Id := New_Elmt_List;
8793 Loc : constant Source_Ptr := Sloc (N);
8794 Prot_Typ : constant Entity_Id := Defining_Identifier (N);
8796 Lock_Free_Active : constant Boolean := Uses_Lock_Free (Prot_Typ);
8797 -- This flag indicates whether the lock free implementation is active
8799 Pdef : constant Node_Id := Protected_Definition (N);
8800 -- This contains two lists; one for visible and one for private decls
8802 Current_Node : Node_Id := N;
8803 E_Count : Int;
8804 Entries_Aggr : Node_Id;
8806 procedure Check_Inlining (Subp : Entity_Id);
8807 -- If the original operation has a pragma Inline, propagate the flag
8808 -- to the internal body, for possible inlining later on. The source
8809 -- operation is invisible to the back-end and is never actually called.
8811 procedure Expand_Entry_Declaration (Decl : Node_Id);
8812 -- Create the entry barrier and the procedure body for entry declaration
8813 -- Decl. All generated subprograms are added to Entry_Bodies_Array.
8815 function Static_Component_Size (Comp : Entity_Id) return Boolean;
8816 -- When compiling under the Ravenscar profile, private components must
8817 -- have a static size, or else a protected object will require heap
8818 -- allocation, violating the corresponding restriction. It is preferable
8819 -- to make this check here, because it provides a better error message
8820 -- than the back-end, which refers to the object as a whole.
8822 procedure Register_Handler;
8823 -- For a protected operation that is an interrupt handler, add the
8824 -- freeze action that will register it as such.
8826 --------------------
8827 -- Check_Inlining --
8828 --------------------
8830 procedure Check_Inlining (Subp : Entity_Id) is
8831 begin
8832 if Is_Inlined (Subp) then
8833 Set_Is_Inlined (Protected_Body_Subprogram (Subp));
8834 Set_Is_Inlined (Subp, False);
8835 end if;
8836 end Check_Inlining;
8838 ---------------------------
8839 -- Static_Component_Size --
8840 ---------------------------
8842 function Static_Component_Size (Comp : Entity_Id) return Boolean is
8843 Typ : constant Entity_Id := Etype (Comp);
8844 C : Entity_Id;
8846 begin
8847 if Is_Scalar_Type (Typ) then
8848 return True;
8850 elsif Is_Array_Type (Typ) then
8851 return Compile_Time_Known_Bounds (Typ);
8853 elsif Is_Record_Type (Typ) then
8854 C := First_Component (Typ);
8855 while Present (C) loop
8856 if not Static_Component_Size (C) then
8857 return False;
8858 end if;
8860 Next_Component (C);
8861 end loop;
8863 return True;
8865 -- Any other type will be checked by the back-end
8867 else
8868 return True;
8869 end if;
8870 end Static_Component_Size;
8872 ------------------------------
8873 -- Expand_Entry_Declaration --
8874 ------------------------------
8876 procedure Expand_Entry_Declaration (Decl : Node_Id) is
8877 Ent_Id : constant Entity_Id := Defining_Entity (Decl);
8878 Bar_Id : Entity_Id;
8879 Bod_Id : Entity_Id;
8880 Subp : Node_Id;
8882 begin
8883 E_Count := E_Count + 1;
8885 -- Create the protected body subprogram
8887 Bod_Id :=
8888 Make_Defining_Identifier (Loc,
8889 Chars => Build_Selected_Name (Prot_Typ, Ent_Id, 'E'));
8890 Set_Protected_Body_Subprogram (Ent_Id, Bod_Id);
8892 Subp :=
8893 Make_Subprogram_Declaration (Loc,
8894 Specification =>
8895 Build_Protected_Entry_Specification (Loc, Bod_Id, Ent_Id));
8897 Insert_After (Current_Node, Subp);
8898 Current_Node := Subp;
8900 Analyze (Subp);
8902 -- Build a wrapper procedure to handle contract cases, preconditions,
8903 -- and postconditions.
8905 Build_Contract_Wrapper (Ent_Id, N);
8907 -- Create the barrier function
8909 Bar_Id :=
8910 Make_Defining_Identifier (Loc,
8911 Chars => Build_Selected_Name (Prot_Typ, Ent_Id, 'B'));
8912 Set_Barrier_Function (Ent_Id, Bar_Id);
8914 Subp :=
8915 Make_Subprogram_Declaration (Loc,
8916 Specification =>
8917 Build_Barrier_Function_Specification (Loc, Bar_Id));
8918 Set_Is_Entry_Barrier_Function (Subp);
8920 Insert_After (Current_Node, Subp);
8921 Current_Node := Subp;
8923 Analyze (Subp);
8925 Set_Protected_Body_Subprogram (Bar_Id, Bar_Id);
8926 Set_Scope (Bar_Id, Scope (Ent_Id));
8928 -- Collect pointers to the protected subprogram and the barrier
8929 -- of the current entry, for insertion into Entry_Bodies_Array.
8931 Append_To (Expressions (Entries_Aggr),
8932 Make_Aggregate (Loc,
8933 Expressions => New_List (
8934 Make_Attribute_Reference (Loc,
8935 Prefix => New_Occurrence_Of (Bar_Id, Loc),
8936 Attribute_Name => Name_Unrestricted_Access),
8937 Make_Attribute_Reference (Loc,
8938 Prefix => New_Occurrence_Of (Bod_Id, Loc),
8939 Attribute_Name => Name_Unrestricted_Access))));
8940 end Expand_Entry_Declaration;
8942 ----------------------
8943 -- Register_Handler --
8944 ----------------------
8946 procedure Register_Handler is
8948 -- All semantic checks already done in Sem_Prag
8950 Prot_Proc : constant Entity_Id :=
8951 Defining_Unit_Name (Specification (Current_Node));
8953 Proc_Address : constant Node_Id :=
8954 Make_Attribute_Reference (Loc,
8955 Prefix =>
8956 New_Occurrence_Of (Prot_Proc, Loc),
8957 Attribute_Name => Name_Address);
8959 RTS_Call : constant Entity_Id :=
8960 Make_Procedure_Call_Statement (Loc,
8961 Name =>
8962 New_Occurrence_Of
8963 (RTE (RE_Register_Interrupt_Handler), Loc),
8964 Parameter_Associations => New_List (Proc_Address));
8965 begin
8966 Append_Freeze_Action (Prot_Proc, RTS_Call);
8967 end Register_Handler;
8969 -- Local variables
8971 Body_Arr : Node_Id;
8972 Body_Id : Entity_Id;
8973 Cdecls : List_Id;
8974 Comp : Node_Id;
8975 Expr : Node_Id;
8976 New_Priv : Node_Id;
8977 Obj_Def : Node_Id;
8978 Object_Comp : Node_Id;
8979 Priv : Node_Id;
8980 Rec_Decl : Node_Id;
8981 Sub : Node_Id;
8983 -- Start of processing for Expand_N_Protected_Type_Declaration
8985 begin
8986 if Present (Corresponding_Record_Type (Prot_Typ)) then
8987 return;
8988 else
8989 Rec_Decl := Build_Corresponding_Record (N, Prot_Typ, Loc);
8990 end if;
8992 Cdecls := Component_Items (Component_List (Type_Definition (Rec_Decl)));
8994 Qualify_Entity_Names (N);
8996 -- If the type has discriminants, their occurrences in the declaration
8997 -- have been replaced by the corresponding discriminals. For components
8998 -- that are constrained by discriminants, their homologues in the
8999 -- corresponding record type must refer to the discriminants of that
9000 -- record, so we must apply a new renaming to subtypes_indications:
9002 -- protected discriminant => discriminal => record discriminant
9004 -- This replacement is not applied to default expressions, for which
9005 -- the discriminal is correct.
9007 if Has_Discriminants (Prot_Typ) then
9008 declare
9009 Disc : Entity_Id;
9010 Decl : Node_Id;
9012 begin
9013 Disc := First_Discriminant (Prot_Typ);
9014 Decl := First (Discriminant_Specifications (Rec_Decl));
9015 while Present (Disc) loop
9016 Append_Elmt (Discriminal (Disc), Discr_Map);
9017 Append_Elmt (Defining_Identifier (Decl), Discr_Map);
9018 Next_Discriminant (Disc);
9019 Next (Decl);
9020 end loop;
9021 end;
9022 end if;
9024 -- Fill in the component declarations
9026 -- Add components for entry families. For each entry family, create an
9027 -- anonymous type declaration with the same size, and analyze the type.
9029 Collect_Entry_Families (Loc, Cdecls, Current_Node, Prot_Typ);
9031 pragma Assert (Present (Pdef));
9033 Insert_After (Current_Node, Rec_Decl);
9034 Current_Node := Rec_Decl;
9036 -- Add private field components
9038 if Present (Private_Declarations (Pdef)) then
9039 Priv := First (Private_Declarations (Pdef));
9040 while Present (Priv) loop
9041 if Nkind (Priv) = N_Component_Declaration then
9042 if not Static_Component_Size (Defining_Identifier (Priv)) then
9044 -- When compiling for a restricted profile, the private
9045 -- components must have a static size. If not, this is an
9046 -- error for a single protected declaration, and rates a
9047 -- warning on a protected type declaration.
9049 if not Comes_From_Source (Prot_Typ) then
9051 -- It's ok to be checking this restriction at expansion
9052 -- time, because this is only for the restricted profile,
9053 -- which is not subject to strict RM conformance, so it
9054 -- is OK to miss this check in -gnatc mode.
9056 Check_Restriction (No_Implicit_Heap_Allocations, Priv);
9057 Check_Restriction
9058 (No_Implicit_Protected_Object_Allocations, Priv);
9060 elsif Restriction_Active (No_Implicit_Heap_Allocations) then
9061 if not Discriminated_Size (Defining_Identifier (Priv))
9062 then
9063 -- Any object of the type will be non-static
9065 Error_Msg_N ("component has non-static size??", Priv);
9066 Error_Msg_NE
9067 ("\creation of protected object of type& will "
9068 & "violate restriction "
9069 & "No_Implicit_Heap_Allocations??", Priv, Prot_Typ);
9070 else
9071 -- Object will be non-static if discriminants are
9073 Error_Msg_NE
9074 ("creation of protected object of type& with "
9075 & "non-static discriminants will violate "
9076 & "restriction No_Implicit_Heap_Allocations??",
9077 Priv, Prot_Typ);
9078 end if;
9080 -- Likewise for No_Implicit_Protected_Object_Allocations
9082 elsif Restriction_Active
9083 (No_Implicit_Protected_Object_Allocations)
9084 then
9085 if not Discriminated_Size (Defining_Identifier (Priv))
9086 then
9087 -- Any object of the type will be non-static
9089 Error_Msg_N ("component has non-static size??", Priv);
9090 Error_Msg_NE
9091 ("\creation of protected object of type& will "
9092 & "violate restriction "
9093 & "No_Implicit_Protected_Object_Allocations??",
9094 Priv, Prot_Typ);
9095 else
9096 -- Object will be non-static if discriminants are
9098 Error_Msg_NE
9099 ("creation of protected object of type& with "
9100 & "non-static discriminants will violate "
9101 & "restriction "
9102 & "No_Implicit_Protected_Object_Allocations??",
9103 Priv, Prot_Typ);
9104 end if;
9105 end if;
9106 end if;
9108 -- The component definition consists of a subtype indication,
9109 -- or (in Ada 2005) an access definition. Make a copy of the
9110 -- proper definition.
9112 declare
9113 Old_Comp : constant Node_Id := Component_Definition (Priv);
9114 Oent : constant Entity_Id := Defining_Identifier (Priv);
9115 Nent : constant Entity_Id :=
9116 Make_Defining_Identifier (Sloc (Oent),
9117 Chars => Chars (Oent));
9118 New_Comp : Node_Id;
9120 begin
9121 if Present (Subtype_Indication (Old_Comp)) then
9122 New_Comp :=
9123 Make_Component_Definition (Sloc (Oent),
9124 Aliased_Present => False,
9125 Subtype_Indication =>
9126 New_Copy_Tree
9127 (Subtype_Indication (Old_Comp), Discr_Map));
9128 else
9129 New_Comp :=
9130 Make_Component_Definition (Sloc (Oent),
9131 Aliased_Present => False,
9132 Access_Definition =>
9133 New_Copy_Tree
9134 (Access_Definition (Old_Comp), Discr_Map));
9135 end if;
9137 New_Priv :=
9138 Make_Component_Declaration (Loc,
9139 Defining_Identifier => Nent,
9140 Component_Definition => New_Comp,
9141 Expression => Expression (Priv));
9143 Set_Has_Per_Object_Constraint (Nent,
9144 Has_Per_Object_Constraint (Oent));
9146 Append_To (Cdecls, New_Priv);
9147 end;
9149 elsif Nkind (Priv) = N_Subprogram_Declaration then
9151 -- Make the unprotected version of the subprogram available
9152 -- for expansion of intra object calls. There is need for
9153 -- a protected version only if the subprogram is an interrupt
9154 -- handler, otherwise this operation can only be called from
9155 -- within the body.
9157 Sub :=
9158 Make_Subprogram_Declaration (Loc,
9159 Specification =>
9160 Build_Protected_Sub_Specification
9161 (Priv, Prot_Typ, Unprotected_Mode));
9163 Insert_After (Current_Node, Sub);
9164 Analyze (Sub);
9166 Set_Protected_Body_Subprogram
9167 (Defining_Unit_Name (Specification (Priv)),
9168 Defining_Unit_Name (Specification (Sub)));
9169 Check_Inlining (Defining_Unit_Name (Specification (Priv)));
9170 Current_Node := Sub;
9172 Sub :=
9173 Make_Subprogram_Declaration (Loc,
9174 Specification =>
9175 Build_Protected_Sub_Specification
9176 (Priv, Prot_Typ, Protected_Mode));
9178 Insert_After (Current_Node, Sub);
9179 Analyze (Sub);
9180 Current_Node := Sub;
9182 if Is_Interrupt_Handler
9183 (Defining_Unit_Name (Specification (Priv)))
9184 then
9185 if not Restricted_Profile then
9186 Register_Handler;
9187 end if;
9188 end if;
9189 end if;
9191 Next (Priv);
9192 end loop;
9193 end if;
9195 -- Except for the lock-free implementation, append the _Object field
9196 -- with the right type to the component list. We need to compute the
9197 -- number of entries, and in some cases the number of Attach_Handler
9198 -- pragmas.
9200 if not Lock_Free_Active then
9201 declare
9202 Entry_Count_Expr : constant Node_Id :=
9203 Build_Entry_Count_Expression
9204 (Prot_Typ, Cdecls, Loc);
9205 Num_Attach_Handler : Nat := 0;
9206 Protection_Subtype : Node_Id;
9207 Ritem : Node_Id;
9209 begin
9210 if Has_Attach_Handler (Prot_Typ) then
9211 Ritem := First_Rep_Item (Prot_Typ);
9212 while Present (Ritem) loop
9213 if Nkind (Ritem) = N_Pragma
9214 and then Pragma_Name (Ritem) = Name_Attach_Handler
9215 then
9216 Num_Attach_Handler := Num_Attach_Handler + 1;
9217 end if;
9219 Next_Rep_Item (Ritem);
9220 end loop;
9221 end if;
9223 -- Determine the proper protection type. There are two special
9224 -- cases: 1) when the protected type has dynamic interrupt
9225 -- handlers, and 2) when it has static handlers and we use a
9226 -- restricted profile.
9228 if Has_Attach_Handler (Prot_Typ)
9229 and then not Restricted_Profile
9230 then
9231 Protection_Subtype :=
9232 Make_Subtype_Indication (Loc,
9233 Subtype_Mark =>
9234 New_Occurrence_Of
9235 (RTE (RE_Static_Interrupt_Protection), Loc),
9236 Constraint =>
9237 Make_Index_Or_Discriminant_Constraint (Loc,
9238 Constraints => New_List (
9239 Entry_Count_Expr,
9240 Make_Integer_Literal (Loc, Num_Attach_Handler))));
9242 elsif Has_Interrupt_Handler (Prot_Typ)
9243 and then not Restriction_Active (No_Dynamic_Attachment)
9244 then
9245 Protection_Subtype :=
9246 Make_Subtype_Indication (Loc,
9247 Subtype_Mark =>
9248 New_Occurrence_Of
9249 (RTE (RE_Dynamic_Interrupt_Protection), Loc),
9250 Constraint =>
9251 Make_Index_Or_Discriminant_Constraint (Loc,
9252 Constraints => New_List (Entry_Count_Expr)));
9254 else
9255 case Corresponding_Runtime_Package (Prot_Typ) is
9256 when System_Tasking_Protected_Objects_Entries =>
9257 Protection_Subtype :=
9258 Make_Subtype_Indication (Loc,
9259 Subtype_Mark =>
9260 New_Occurrence_Of
9261 (RTE (RE_Protection_Entries), Loc),
9262 Constraint =>
9263 Make_Index_Or_Discriminant_Constraint (Loc,
9264 Constraints => New_List (Entry_Count_Expr)));
9266 when System_Tasking_Protected_Objects_Single_Entry =>
9267 Protection_Subtype :=
9268 New_Occurrence_Of (RTE (RE_Protection_Entry), Loc);
9270 when System_Tasking_Protected_Objects =>
9271 Protection_Subtype :=
9272 New_Occurrence_Of (RTE (RE_Protection), Loc);
9274 when others =>
9275 raise Program_Error;
9276 end case;
9277 end if;
9279 Object_Comp :=
9280 Make_Component_Declaration (Loc,
9281 Defining_Identifier =>
9282 Make_Defining_Identifier (Loc, Name_uObject),
9283 Component_Definition =>
9284 Make_Component_Definition (Loc,
9285 Aliased_Present => True,
9286 Subtype_Indication => Protection_Subtype));
9287 end;
9289 -- Put the _Object component after the private component so that it
9290 -- be finalized early as required by 9.4 (20)
9292 Append_To (Cdecls, Object_Comp);
9293 end if;
9295 -- Analyze the record declaration immediately after construction,
9296 -- because the initialization procedure is needed for single object
9297 -- declarations before the next entity is analyzed (the freeze call
9298 -- that generates this initialization procedure is found below).
9300 Analyze (Rec_Decl, Suppress => All_Checks);
9302 -- Ada 2005 (AI-345): Construct the primitive entry wrappers before
9303 -- the corresponding record is frozen. If any wrappers are generated,
9304 -- Current_Node is updated accordingly.
9306 if Ada_Version >= Ada_2005 then
9307 Build_Wrapper_Specs (Loc, Prot_Typ, Current_Node);
9308 end if;
9310 -- Collect pointers to entry bodies and their barriers, to be placed
9311 -- in the Entry_Bodies_Array for the type. For each entry/family we
9312 -- add an expression to the aggregate which is the initial value of
9313 -- this array. The array is declared after all protected subprograms.
9315 if Has_Entries (Prot_Typ) then
9316 Entries_Aggr := Make_Aggregate (Loc, Expressions => New_List);
9317 else
9318 Entries_Aggr := Empty;
9319 end if;
9321 -- Build two new procedure specifications for each protected subprogram;
9322 -- one to call from outside the object and one to call from inside.
9323 -- Build a barrier function and an entry body action procedure
9324 -- specification for each protected entry. Initialize the entry body
9325 -- array. If subprogram is flagged as eliminated, do not generate any
9326 -- internal operations.
9328 E_Count := 0;
9329 Comp := First (Visible_Declarations (Pdef));
9330 while Present (Comp) loop
9331 if Nkind (Comp) = N_Subprogram_Declaration then
9332 Sub :=
9333 Make_Subprogram_Declaration (Loc,
9334 Specification =>
9335 Build_Protected_Sub_Specification
9336 (Comp, Prot_Typ, Unprotected_Mode));
9338 Insert_After (Current_Node, Sub);
9339 Analyze (Sub);
9341 Set_Protected_Body_Subprogram
9342 (Defining_Unit_Name (Specification (Comp)),
9343 Defining_Unit_Name (Specification (Sub)));
9344 Check_Inlining (Defining_Unit_Name (Specification (Comp)));
9346 -- Make the protected version of the subprogram available for
9347 -- expansion of external calls.
9349 Current_Node := Sub;
9351 Sub :=
9352 Make_Subprogram_Declaration (Loc,
9353 Specification =>
9354 Build_Protected_Sub_Specification
9355 (Comp, Prot_Typ, Protected_Mode));
9357 Insert_After (Current_Node, Sub);
9358 Analyze (Sub);
9360 Current_Node := Sub;
9362 -- Generate an overriding primitive operation specification for
9363 -- this subprogram if the protected type implements an interface
9364 -- and Build_Wrapper_Spec did not generate its wrapper.
9366 if Ada_Version >= Ada_2005
9367 and then
9368 Present (Interfaces (Corresponding_Record_Type (Prot_Typ)))
9369 then
9370 declare
9371 Found : Boolean := False;
9372 Prim_Elmt : Elmt_Id;
9373 Prim_Op : Node_Id;
9375 begin
9376 Prim_Elmt :=
9377 First_Elmt
9378 (Primitive_Operations
9379 (Corresponding_Record_Type (Prot_Typ)));
9381 while Present (Prim_Elmt) loop
9382 Prim_Op := Node (Prim_Elmt);
9384 if Is_Primitive_Wrapper (Prim_Op)
9385 and then Wrapped_Entity (Prim_Op) =
9386 Defining_Entity (Specification (Comp))
9387 then
9388 Found := True;
9389 exit;
9390 end if;
9392 Next_Elmt (Prim_Elmt);
9393 end loop;
9395 if not Found then
9396 Sub :=
9397 Make_Subprogram_Declaration (Loc,
9398 Specification =>
9399 Build_Protected_Sub_Specification
9400 (Comp, Prot_Typ, Dispatching_Mode));
9402 Insert_After (Current_Node, Sub);
9403 Analyze (Sub);
9405 Current_Node := Sub;
9406 end if;
9407 end;
9408 end if;
9410 -- If a pragma Interrupt_Handler applies, build and add a call to
9411 -- Register_Interrupt_Handler to the freezing actions of the
9412 -- protected version (Current_Node) of the subprogram:
9414 -- system.interrupts.register_interrupt_handler
9415 -- (prot_procP'address);
9417 if not Restricted_Profile
9418 and then Is_Interrupt_Handler
9419 (Defining_Unit_Name (Specification (Comp)))
9420 then
9421 Register_Handler;
9422 end if;
9424 elsif Nkind (Comp) = N_Entry_Declaration then
9425 Expand_Entry_Declaration (Comp);
9426 end if;
9428 Next (Comp);
9429 end loop;
9431 -- If there are some private entry declarations, expand it as if they
9432 -- were visible entries.
9434 if Present (Private_Declarations (Pdef)) then
9435 Comp := First (Private_Declarations (Pdef));
9436 while Present (Comp) loop
9437 if Nkind (Comp) = N_Entry_Declaration then
9438 Expand_Entry_Declaration (Comp);
9439 end if;
9441 Next (Comp);
9442 end loop;
9443 end if;
9445 -- Create the declaration of an array object which contains the values
9446 -- of aspect/pragma Max_Queue_Length for all entries of the protected
9447 -- type. This object is later passed to the appropriate protected object
9448 -- initialization routine.
9450 if Has_Entries (Prot_Typ)
9451 and then Corresponding_Runtime_Package (Prot_Typ) =
9452 System_Tasking_Protected_Objects_Entries
9453 then
9454 declare
9455 Count : Int;
9456 Item : Entity_Id;
9457 Max_Vals : Node_Id;
9458 Maxes : List_Id;
9459 Maxes_Id : Entity_Id;
9460 Need_Array : Boolean := False;
9462 begin
9463 -- First check if there is any Max_Queue_Length pragma
9465 Item := First_Entity (Prot_Typ);
9466 while Present (Item) loop
9467 if Is_Entry (Item) and then Has_Max_Queue_Length (Item) then
9468 Need_Array := True;
9469 exit;
9470 end if;
9472 Next_Entity (Item);
9473 end loop;
9475 -- Gather the Max_Queue_Length values of all entries in a list. A
9476 -- value of zero indicates that the entry has no limitation on its
9477 -- queue length.
9479 if Need_Array then
9480 Count := 0;
9481 Item := First_Entity (Prot_Typ);
9482 Maxes := New_List;
9483 while Present (Item) loop
9484 if Is_Entry (Item) then
9485 Count := Count + 1;
9486 Append_To (Maxes,
9487 Make_Integer_Literal
9488 (Loc, Get_Max_Queue_Length (Item)));
9489 end if;
9491 Next_Entity (Item);
9492 end loop;
9494 -- Create the declaration of the array object. Generate:
9496 -- Maxes_Id : aliased constant
9497 -- Protected_Entry_Queue_Max_Array
9498 -- (1 .. Count) := (..., ...);
9500 Maxes_Id :=
9501 Make_Defining_Identifier (Loc,
9502 Chars => New_External_Name (Chars (Prot_Typ), 'B'));
9504 Max_Vals :=
9505 Make_Object_Declaration (Loc,
9506 Defining_Identifier => Maxes_Id,
9507 Aliased_Present => True,
9508 Constant_Present => True,
9509 Object_Definition =>
9510 Make_Subtype_Indication (Loc,
9511 Subtype_Mark =>
9512 New_Occurrence_Of
9513 (RTE (RE_Protected_Entry_Queue_Max_Array), Loc),
9514 Constraint =>
9515 Make_Index_Or_Discriminant_Constraint (Loc,
9516 Constraints => New_List (
9517 Make_Range (Loc,
9518 Make_Integer_Literal (Loc, 1),
9519 Make_Integer_Literal (Loc, Count))))),
9520 Expression => Make_Aggregate (Loc, Maxes));
9522 -- A pointer to this array will be placed in the corresponding
9523 -- record by its initialization procedure so this needs to be
9524 -- analyzed here.
9526 Insert_After (Current_Node, Max_Vals);
9527 Current_Node := Max_Vals;
9528 Analyze (Max_Vals);
9530 Set_Entry_Max_Queue_Lengths_Array (Prot_Typ, Maxes_Id);
9531 end if;
9532 end;
9533 end if;
9535 -- Emit declaration for Entry_Bodies_Array, now that the addresses of
9536 -- all protected subprograms have been collected.
9538 if Has_Entries (Prot_Typ) then
9539 Body_Id :=
9540 Make_Defining_Identifier (Sloc (Prot_Typ),
9541 Chars => New_External_Name (Chars (Prot_Typ), 'A'));
9543 case Corresponding_Runtime_Package (Prot_Typ) is
9544 when System_Tasking_Protected_Objects_Entries =>
9545 Expr := Entries_Aggr;
9546 Obj_Def :=
9547 Make_Subtype_Indication (Loc,
9548 Subtype_Mark =>
9549 New_Occurrence_Of
9550 (RTE (RE_Protected_Entry_Body_Array), Loc),
9551 Constraint =>
9552 Make_Index_Or_Discriminant_Constraint (Loc,
9553 Constraints => New_List (
9554 Make_Range (Loc,
9555 Make_Integer_Literal (Loc, 1),
9556 Make_Integer_Literal (Loc, E_Count)))));
9558 when System_Tasking_Protected_Objects_Single_Entry =>
9559 Expr := Remove_Head (Expressions (Entries_Aggr));
9560 Obj_Def := New_Occurrence_Of (RTE (RE_Entry_Body), Loc);
9562 when others =>
9563 raise Program_Error;
9564 end case;
9566 Body_Arr :=
9567 Make_Object_Declaration (Loc,
9568 Defining_Identifier => Body_Id,
9569 Aliased_Present => True,
9570 Constant_Present => True,
9571 Object_Definition => Obj_Def,
9572 Expression => Expr);
9574 -- A pointer to this array will be placed in the corresponding record
9575 -- by its initialization procedure so this needs to be analyzed here.
9577 Insert_After (Current_Node, Body_Arr);
9578 Current_Node := Body_Arr;
9579 Analyze (Body_Arr);
9581 Set_Entry_Bodies_Array (Prot_Typ, Body_Id);
9583 -- Finally, build the function that maps an entry index into the
9584 -- corresponding body. A pointer to this function is placed in each
9585 -- object of the type. Except for a ravenscar-like profile (no abort,
9586 -- no entry queue, 1 entry)
9588 if Corresponding_Runtime_Package (Prot_Typ) =
9589 System_Tasking_Protected_Objects_Entries
9590 then
9591 Sub :=
9592 Make_Subprogram_Declaration (Loc,
9593 Specification => Build_Find_Body_Index_Spec (Prot_Typ));
9595 Insert_After (Current_Node, Sub);
9596 Analyze (Sub);
9597 end if;
9598 end if;
9599 end Expand_N_Protected_Type_Declaration;
9601 --------------------------------
9602 -- Expand_N_Requeue_Statement --
9603 --------------------------------
9605 -- A nondispatching requeue statement is expanded into one of four GNARLI
9606 -- operations, depending on the source and destination (task or protected
9607 -- object). A dispatching requeue statement is expanded into a call to the
9608 -- predefined primitive _Disp_Requeue. In addition, code is generated to
9609 -- jump around the remainder of processing for the original entry and, if
9610 -- the destination is (different) protected object, to attempt to service
9611 -- it. The following illustrates the various cases:
9613 -- procedure entE
9614 -- (O : System.Address;
9615 -- P : System.Address;
9616 -- E : Protected_Entry_Index)
9617 -- is
9618 -- <discriminant renamings>
9619 -- <private object renamings>
9620 -- type poVP is access poV;
9621 -- _object : ptVP := ptVP!(O);
9623 -- begin
9624 -- begin
9625 -- <start of statement sequence for entry>
9627 -- -- Requeue from one protected entry body to another protected
9628 -- -- entry.
9630 -- Requeue_Protected_Entry (
9631 -- _object._object'Access,
9632 -- new._object'Access,
9633 -- E,
9634 -- Abort_Present);
9635 -- return;
9637 -- <some more of the statement sequence for entry>
9639 -- -- Requeue from an entry body to a task entry
9641 -- Requeue_Protected_To_Task_Entry (
9642 -- New._task_id,
9643 -- E,
9644 -- Abort_Present);
9645 -- return;
9647 -- <rest of statement sequence for entry>
9648 -- Complete_Entry_Body (_object._object);
9650 -- exception
9651 -- when all others =>
9652 -- Exceptional_Complete_Entry_Body (
9653 -- _object._object, Get_GNAT_Exception);
9654 -- end;
9655 -- end entE;
9657 -- Requeue of a task entry call to a task entry
9659 -- Accept_Call (E, Ann);
9660 -- <start of statement sequence for accept statement>
9661 -- Requeue_Task_Entry (New._task_id, E, Abort_Present);
9662 -- goto Lnn;
9663 -- <rest of statement sequence for accept statement>
9664 -- <<Lnn>>
9665 -- Complete_Rendezvous;
9667 -- exception
9668 -- when all others =>
9669 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
9671 -- Requeue of a task entry call to a protected entry
9673 -- Accept_Call (E, Ann);
9674 -- <start of statement sequence for accept statement>
9675 -- Requeue_Task_To_Protected_Entry (
9676 -- new._object'Access,
9677 -- E,
9678 -- Abort_Present);
9679 -- newS (new, Pnn);
9680 -- goto Lnn;
9681 -- <rest of statement sequence for accept statement>
9682 -- <<Lnn>>
9683 -- Complete_Rendezvous;
9685 -- exception
9686 -- when all others =>
9687 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
9689 -- Ada 2012 (AI05-0030): Dispatching requeue to an interface primitive
9690 -- marked by pragma Implemented (XXX, By_Entry).
9692 -- The requeue is inside a protected entry:
9694 -- procedure entE
9695 -- (O : System.Address;
9696 -- P : System.Address;
9697 -- E : Protected_Entry_Index)
9698 -- is
9699 -- <discriminant renamings>
9700 -- <private object renamings>
9701 -- type poVP is access poV;
9702 -- _object : ptVP := ptVP!(O);
9704 -- begin
9705 -- begin
9706 -- <start of statement sequence for entry>
9708 -- _Disp_Requeue
9709 -- (<interface class-wide object>,
9710 -- True,
9711 -- _object'Address,
9712 -- Ada.Tags.Get_Offset_Index
9713 -- (Tag (_object),
9714 -- <interface dispatch table index of target entry>),
9715 -- Abort_Present);
9716 -- return;
9718 -- <rest of statement sequence for entry>
9719 -- Complete_Entry_Body (_object._object);
9721 -- exception
9722 -- when all others =>
9723 -- Exceptional_Complete_Entry_Body (
9724 -- _object._object, Get_GNAT_Exception);
9725 -- end;
9726 -- end entE;
9728 -- The requeue is inside a task entry:
9730 -- Accept_Call (E, Ann);
9731 -- <start of statement sequence for accept statement>
9732 -- _Disp_Requeue
9733 -- (<interface class-wide object>,
9734 -- False,
9735 -- null,
9736 -- Ada.Tags.Get_Offset_Index
9737 -- (Tag (_object),
9738 -- <interface dispatch table index of target entrt>),
9739 -- Abort_Present);
9740 -- newS (new, Pnn);
9741 -- goto Lnn;
9742 -- <rest of statement sequence for accept statement>
9743 -- <<Lnn>>
9744 -- Complete_Rendezvous;
9746 -- exception
9747 -- when all others =>
9748 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
9750 -- Ada 2012 (AI05-0030): Dispatching requeue to an interface primitive
9751 -- marked by pragma Implemented (XXX, By_Protected_Procedure). The requeue
9752 -- statement is replaced by a dispatching call with actual parameters taken
9753 -- from the inner-most accept statement or entry body.
9755 -- Target.Primitive (Param1, ..., ParamN);
9757 -- Ada 2012 (AI05-0030): Dispatching requeue to an interface primitive
9758 -- marked by pragma Implemented (XXX, By_Any | Optional) or not marked
9759 -- at all.
9761 -- declare
9762 -- S : constant Offset_Index :=
9763 -- Get_Offset_Index (Tag (Concval), DT_Position (Ename));
9764 -- C : constant Prim_Op_Kind := Get_Prim_Op_Kind (Tag (Concval), S);
9766 -- begin
9767 -- if C = POK_Protected_Entry
9768 -- or else C = POK_Task_Entry
9769 -- then
9770 -- <statements for dispatching requeue>
9772 -- elsif C = POK_Protected_Procedure then
9773 -- <dispatching call equivalent>
9775 -- else
9776 -- raise Program_Error;
9777 -- end if;
9778 -- end;
9780 procedure Expand_N_Requeue_Statement (N : Node_Id) is
9781 Loc : constant Source_Ptr := Sloc (N);
9782 Conc_Typ : Entity_Id;
9783 Concval : Node_Id;
9784 Ename : Node_Id;
9785 Index : Node_Id;
9786 Old_Typ : Entity_Id;
9788 function Build_Dispatching_Call_Equivalent return Node_Id;
9789 -- Ada 2012 (AI05-0030): N denotes a dispatching requeue statement of
9790 -- the form Concval.Ename. It is statically known that Ename is allowed
9791 -- to be implemented by a protected procedure. Create a dispatching call
9792 -- equivalent of Concval.Ename taking the actual parameters from the
9793 -- inner-most accept statement or entry body.
9795 function Build_Dispatching_Requeue return Node_Id;
9796 -- Ada 2012 (AI05-0030): N denotes a dispatching requeue statement of
9797 -- the form Concval.Ename. It is statically known that Ename is allowed
9798 -- to be implemented by a protected or a task entry. Create a call to
9799 -- primitive _Disp_Requeue which handles the low-level actions.
9801 function Build_Dispatching_Requeue_To_Any return Node_Id;
9802 -- Ada 2012 (AI05-0030): N denotes a dispatching requeue statement of
9803 -- the form Concval.Ename. Ename is either marked by pragma Implemented
9804 -- (XXX, By_Any | Optional) or not marked at all. Create a block which
9805 -- determines at runtime whether Ename denotes an entry or a procedure
9806 -- and perform the appropriate kind of dispatching select.
9808 function Build_Normal_Requeue return Node_Id;
9809 -- N denotes a nondispatching requeue statement to either a task or a
9810 -- protected entry. Build the appropriate runtime call to perform the
9811 -- action.
9813 function Build_Skip_Statement (Search : Node_Id) return Node_Id;
9814 -- For a protected entry, create a return statement to skip the rest of
9815 -- the entry body. Otherwise, create a goto statement to skip the rest
9816 -- of a task accept statement. The lookup for the enclosing entry body
9817 -- or accept statement starts from Search.
9819 ---------------------------------------
9820 -- Build_Dispatching_Call_Equivalent --
9821 ---------------------------------------
9823 function Build_Dispatching_Call_Equivalent return Node_Id is
9824 Call_Ent : constant Entity_Id := Entity (Ename);
9825 Obj : constant Node_Id := Original_Node (Concval);
9826 Acc_Ent : Node_Id;
9827 Actuals : List_Id;
9828 Formal : Node_Id;
9829 Formals : List_Id;
9831 begin
9832 -- Climb the parent chain looking for the inner-most entry body or
9833 -- accept statement.
9835 Acc_Ent := N;
9836 while Present (Acc_Ent)
9837 and then not Nkind_In (Acc_Ent, N_Accept_Statement,
9838 N_Entry_Body)
9839 loop
9840 Acc_Ent := Parent (Acc_Ent);
9841 end loop;
9843 -- A requeue statement should be housed inside an entry body or an
9844 -- accept statement at some level. If this is not the case, then the
9845 -- tree is malformed.
9847 pragma Assert (Present (Acc_Ent));
9849 -- Recover the list of formal parameters
9851 if Nkind (Acc_Ent) = N_Entry_Body then
9852 Acc_Ent := Entry_Body_Formal_Part (Acc_Ent);
9853 end if;
9855 Formals := Parameter_Specifications (Acc_Ent);
9857 -- Create the actual parameters for the dispatching call. These are
9858 -- simply copies of the entry body or accept statement formals in the
9859 -- same order as they appear.
9861 Actuals := No_List;
9863 if Present (Formals) then
9864 Actuals := New_List;
9865 Formal := First (Formals);
9866 while Present (Formal) loop
9867 Append_To (Actuals,
9868 Make_Identifier (Loc, Chars (Defining_Identifier (Formal))));
9869 Next (Formal);
9870 end loop;
9871 end if;
9873 -- Generate:
9874 -- Obj.Call_Ent (Actuals);
9876 return
9877 Make_Procedure_Call_Statement (Loc,
9878 Name =>
9879 Make_Selected_Component (Loc,
9880 Prefix => Make_Identifier (Loc, Chars (Obj)),
9881 Selector_Name => Make_Identifier (Loc, Chars (Call_Ent))),
9883 Parameter_Associations => Actuals);
9884 end Build_Dispatching_Call_Equivalent;
9886 -------------------------------
9887 -- Build_Dispatching_Requeue --
9888 -------------------------------
9890 function Build_Dispatching_Requeue return Node_Id is
9891 Params : constant List_Id := New_List;
9893 begin
9894 -- Process the "with abort" parameter
9896 Prepend_To (Params,
9897 New_Occurrence_Of (Boolean_Literals (Abort_Present (N)), Loc));
9899 -- Process the entry wrapper's position in the primary dispatch
9900 -- table parameter. Generate:
9902 -- Ada.Tags.Get_Entry_Index
9903 -- (T => To_Tag_Ptr (Obj'Address).all,
9904 -- Position =>
9905 -- Ada.Tags.Get_Offset_Index
9906 -- (Ada.Tags.Tag (Concval),
9907 -- <interface dispatch table position of Ename>));
9909 -- Note that Obj'Address is recursively expanded into a call to
9910 -- Base_Address (Obj).
9912 if Tagged_Type_Expansion then
9913 Prepend_To (Params,
9914 Make_Function_Call (Loc,
9915 Name => New_Occurrence_Of (RTE (RE_Get_Entry_Index), Loc),
9916 Parameter_Associations => New_List (
9918 Make_Explicit_Dereference (Loc,
9919 Unchecked_Convert_To (RTE (RE_Tag_Ptr),
9920 Make_Attribute_Reference (Loc,
9921 Prefix => New_Copy_Tree (Concval),
9922 Attribute_Name => Name_Address))),
9924 Make_Function_Call (Loc,
9925 Name => New_Occurrence_Of (RTE (RE_Get_Offset_Index), Loc),
9926 Parameter_Associations => New_List (
9927 Unchecked_Convert_To (RTE (RE_Tag), Concval),
9928 Make_Integer_Literal (Loc,
9929 DT_Position (Entity (Ename))))))));
9931 -- VM targets
9933 else
9934 Prepend_To (Params,
9935 Make_Function_Call (Loc,
9936 Name => New_Occurrence_Of (RTE (RE_Get_Entry_Index), Loc),
9937 Parameter_Associations => New_List (
9939 Make_Attribute_Reference (Loc,
9940 Prefix => Concval,
9941 Attribute_Name => Name_Tag),
9943 Make_Function_Call (Loc,
9944 Name => New_Occurrence_Of (RTE (RE_Get_Offset_Index), Loc),
9946 Parameter_Associations => New_List (
9948 -- Obj_Tag
9950 Make_Attribute_Reference (Loc,
9951 Prefix => Concval,
9952 Attribute_Name => Name_Tag),
9954 -- Tag_Typ
9956 Make_Attribute_Reference (Loc,
9957 Prefix => New_Occurrence_Of (Etype (Concval), Loc),
9958 Attribute_Name => Name_Tag),
9960 -- Position
9962 Make_Integer_Literal (Loc,
9963 DT_Position (Entity (Ename))))))));
9964 end if;
9966 -- Specific actuals for protected to XXX requeue
9968 if Is_Protected_Type (Old_Typ) then
9969 Prepend_To (Params,
9970 Make_Attribute_Reference (Loc, -- _object'Address
9971 Prefix =>
9972 Concurrent_Ref (New_Occurrence_Of (Old_Typ, Loc)),
9973 Attribute_Name => Name_Address));
9975 Prepend_To (Params, -- True
9976 New_Occurrence_Of (Standard_True, Loc));
9978 -- Specific actuals for task to XXX requeue
9980 else
9981 pragma Assert (Is_Task_Type (Old_Typ));
9983 Prepend_To (Params, -- null
9984 New_Occurrence_Of (RTE (RE_Null_Address), Loc));
9986 Prepend_To (Params, -- False
9987 New_Occurrence_Of (Standard_False, Loc));
9988 end if;
9990 -- Add the object parameter
9992 Prepend_To (Params, New_Copy_Tree (Concval));
9994 -- Generate:
9995 -- _Disp_Requeue (<Params>);
9997 -- Find entity for Disp_Requeue operation, which belongs to
9998 -- the type and may not be directly visible.
10000 declare
10001 Elmt : Elmt_Id;
10002 Op : Entity_Id;
10003 pragma Warnings (Off, Op);
10005 begin
10006 Elmt := First_Elmt (Primitive_Operations (Etype (Conc_Typ)));
10007 while Present (Elmt) loop
10008 Op := Node (Elmt);
10009 exit when Chars (Op) = Name_uDisp_Requeue;
10010 Next_Elmt (Elmt);
10011 end loop;
10013 return
10014 Make_Procedure_Call_Statement (Loc,
10015 Name => New_Occurrence_Of (Op, Loc),
10016 Parameter_Associations => Params);
10017 end;
10018 end Build_Dispatching_Requeue;
10020 --------------------------------------
10021 -- Build_Dispatching_Requeue_To_Any --
10022 --------------------------------------
10024 function Build_Dispatching_Requeue_To_Any return Node_Id is
10025 Call_Ent : constant Entity_Id := Entity (Ename);
10026 Obj : constant Node_Id := Original_Node (Concval);
10027 Skip : constant Node_Id := Build_Skip_Statement (N);
10028 C : Entity_Id;
10029 Decls : List_Id;
10030 S : Entity_Id;
10031 Stmts : List_Id;
10033 begin
10034 Decls := New_List;
10035 Stmts := New_List;
10037 -- Dispatch table slot processing, generate:
10038 -- S : Integer;
10040 S := Build_S (Loc, Decls);
10042 -- Call kind processing, generate:
10043 -- C : Ada.Tags.Prim_Op_Kind;
10045 C := Build_C (Loc, Decls);
10047 -- Generate:
10048 -- S := Ada.Tags.Get_Offset_Index
10049 -- (Ada.Tags.Tag (Obj), DT_Position (Call_Ent));
10051 Append_To (Stmts, Build_S_Assignment (Loc, S, Obj, Call_Ent));
10053 -- Generate:
10054 -- _Disp_Get_Prim_Op_Kind (Obj, S, C);
10056 Append_To (Stmts,
10057 Make_Procedure_Call_Statement (Loc,
10058 Name =>
10059 New_Occurrence_Of (
10060 Find_Prim_Op (Etype (Etype (Obj)),
10061 Name_uDisp_Get_Prim_Op_Kind),
10062 Loc),
10063 Parameter_Associations => New_List (
10064 New_Copy_Tree (Obj),
10065 New_Occurrence_Of (S, Loc),
10066 New_Occurrence_Of (C, Loc))));
10068 Append_To (Stmts,
10070 -- if C = POK_Protected_Entry
10071 -- or else C = POK_Task_Entry
10072 -- then
10074 Make_Implicit_If_Statement (N,
10075 Condition =>
10076 Make_Op_Or (Loc,
10077 Left_Opnd =>
10078 Make_Op_Eq (Loc,
10079 Left_Opnd =>
10080 New_Occurrence_Of (C, Loc),
10081 Right_Opnd =>
10082 New_Occurrence_Of (RTE (RE_POK_Protected_Entry), Loc)),
10084 Right_Opnd =>
10085 Make_Op_Eq (Loc,
10086 Left_Opnd =>
10087 New_Occurrence_Of (C, Loc),
10088 Right_Opnd =>
10089 New_Occurrence_Of (RTE (RE_POK_Task_Entry), Loc))),
10091 -- Dispatching requeue equivalent
10093 Then_Statements => New_List (
10094 Build_Dispatching_Requeue,
10095 Skip),
10097 -- elsif C = POK_Protected_Procedure then
10099 Elsif_Parts => New_List (
10100 Make_Elsif_Part (Loc,
10101 Condition =>
10102 Make_Op_Eq (Loc,
10103 Left_Opnd =>
10104 New_Occurrence_Of (C, Loc),
10105 Right_Opnd =>
10106 New_Occurrence_Of (
10107 RTE (RE_POK_Protected_Procedure), Loc)),
10109 -- Dispatching call equivalent
10111 Then_Statements => New_List (
10112 Build_Dispatching_Call_Equivalent))),
10114 -- else
10115 -- raise Program_Error;
10116 -- end if;
10118 Else_Statements => New_List (
10119 Make_Raise_Program_Error (Loc,
10120 Reason => PE_Explicit_Raise))));
10122 -- Wrap everything into a block
10124 return
10125 Make_Block_Statement (Loc,
10126 Declarations => Decls,
10127 Handled_Statement_Sequence =>
10128 Make_Handled_Sequence_Of_Statements (Loc,
10129 Statements => Stmts));
10130 end Build_Dispatching_Requeue_To_Any;
10132 --------------------------
10133 -- Build_Normal_Requeue --
10134 --------------------------
10136 function Build_Normal_Requeue return Node_Id is
10137 Params : constant List_Id := New_List;
10138 Param : Node_Id;
10139 RT_Call : Node_Id;
10141 begin
10142 -- Process the "with abort" parameter
10144 Prepend_To (Params,
10145 New_Occurrence_Of (Boolean_Literals (Abort_Present (N)), Loc));
10147 -- Add the index expression to the parameters. It is common among all
10148 -- four cases.
10150 Prepend_To (Params,
10151 Entry_Index_Expression (Loc, Entity (Ename), Index, Conc_Typ));
10153 if Is_Protected_Type (Old_Typ) then
10154 declare
10155 Self_Param : Node_Id;
10157 begin
10158 Self_Param :=
10159 Make_Attribute_Reference (Loc,
10160 Prefix =>
10161 Concurrent_Ref (New_Occurrence_Of (Old_Typ, Loc)),
10162 Attribute_Name =>
10163 Name_Unchecked_Access);
10165 -- Protected to protected requeue
10167 if Is_Protected_Type (Conc_Typ) then
10168 RT_Call :=
10169 New_Occurrence_Of (
10170 RTE (RE_Requeue_Protected_Entry), Loc);
10172 Param :=
10173 Make_Attribute_Reference (Loc,
10174 Prefix =>
10175 Concurrent_Ref (Concval),
10176 Attribute_Name =>
10177 Name_Unchecked_Access);
10179 -- Protected to task requeue
10181 else pragma Assert (Is_Task_Type (Conc_Typ));
10182 RT_Call :=
10183 New_Occurrence_Of (
10184 RTE (RE_Requeue_Protected_To_Task_Entry), Loc);
10186 Param := Concurrent_Ref (Concval);
10187 end if;
10189 Prepend_To (Params, Param);
10190 Prepend_To (Params, Self_Param);
10191 end;
10193 else pragma Assert (Is_Task_Type (Old_Typ));
10195 -- Task to protected requeue
10197 if Is_Protected_Type (Conc_Typ) then
10198 RT_Call :=
10199 New_Occurrence_Of (
10200 RTE (RE_Requeue_Task_To_Protected_Entry), Loc);
10202 Param :=
10203 Make_Attribute_Reference (Loc,
10204 Prefix =>
10205 Concurrent_Ref (Concval),
10206 Attribute_Name =>
10207 Name_Unchecked_Access);
10209 -- Task to task requeue
10211 else pragma Assert (Is_Task_Type (Conc_Typ));
10212 RT_Call :=
10213 New_Occurrence_Of (RTE (RE_Requeue_Task_Entry), Loc);
10215 Param := Concurrent_Ref (Concval);
10216 end if;
10218 Prepend_To (Params, Param);
10219 end if;
10221 return
10222 Make_Procedure_Call_Statement (Loc,
10223 Name => RT_Call,
10224 Parameter_Associations => Params);
10225 end Build_Normal_Requeue;
10227 --------------------------
10228 -- Build_Skip_Statement --
10229 --------------------------
10231 function Build_Skip_Statement (Search : Node_Id) return Node_Id is
10232 Skip_Stmt : Node_Id;
10234 begin
10235 -- Build a return statement to skip the rest of the entire body
10237 if Is_Protected_Type (Old_Typ) then
10238 Skip_Stmt := Make_Simple_Return_Statement (Loc);
10240 -- If the requeue is within a task, find the end label of the
10241 -- enclosing accept statement and create a goto statement to it.
10243 else
10244 declare
10245 Acc : Node_Id;
10246 Label : Node_Id;
10248 begin
10249 -- Climb the parent chain looking for the enclosing accept
10250 -- statement.
10252 Acc := Parent (Search);
10253 while Present (Acc)
10254 and then Nkind (Acc) /= N_Accept_Statement
10255 loop
10256 Acc := Parent (Acc);
10257 end loop;
10259 -- The last statement is the second label used for completing
10260 -- the rendezvous the usual way. The label we are looking for
10261 -- is right before it.
10263 Label :=
10264 Prev (Last (Statements (Handled_Statement_Sequence (Acc))));
10266 pragma Assert (Nkind (Label) = N_Label);
10268 -- Generate a goto statement to skip the rest of the accept
10270 Skip_Stmt :=
10271 Make_Goto_Statement (Loc,
10272 Name =>
10273 New_Occurrence_Of (Entity (Identifier (Label)), Loc));
10274 end;
10275 end if;
10277 Set_Analyzed (Skip_Stmt);
10279 return Skip_Stmt;
10280 end Build_Skip_Statement;
10282 -- Start of processing for Expand_N_Requeue_Statement
10284 begin
10285 -- Extract the components of the entry call
10287 Extract_Entry (N, Concval, Ename, Index);
10288 Conc_Typ := Etype (Concval);
10290 -- If the prefix is an access to class-wide type, dereference to get
10291 -- object and entry type.
10293 if Is_Access_Type (Conc_Typ) then
10294 Conc_Typ := Designated_Type (Conc_Typ);
10295 Rewrite (Concval,
10296 Make_Explicit_Dereference (Loc, Relocate_Node (Concval)));
10297 Analyze_And_Resolve (Concval, Conc_Typ);
10298 end if;
10300 -- Examine the scope stack in order to find nearest enclosing protected
10301 -- or task type. This will constitute our invocation source.
10303 Old_Typ := Current_Scope;
10304 while Present (Old_Typ)
10305 and then not Is_Protected_Type (Old_Typ)
10306 and then not Is_Task_Type (Old_Typ)
10307 loop
10308 Old_Typ := Scope (Old_Typ);
10309 end loop;
10311 -- Ada 2012 (AI05-0030): We have a dispatching requeue of the form
10312 -- Concval.Ename where the type of Concval is class-wide concurrent
10313 -- interface.
10315 if Ada_Version >= Ada_2012
10316 and then Present (Concval)
10317 and then Is_Class_Wide_Type (Conc_Typ)
10318 and then Is_Concurrent_Interface (Conc_Typ)
10319 then
10320 declare
10321 Has_Impl : Boolean := False;
10322 Impl_Kind : Name_Id := No_Name;
10324 begin
10325 -- Check whether the Ename is flagged by pragma Implemented
10327 if Has_Rep_Pragma (Entity (Ename), Name_Implemented) then
10328 Has_Impl := True;
10329 Impl_Kind := Implementation_Kind (Entity (Ename));
10330 end if;
10332 -- The procedure_or_entry_NAME is guaranteed to be overridden by
10333 -- an entry. Create a call to predefined primitive _Disp_Requeue.
10335 if Has_Impl and then Impl_Kind = Name_By_Entry then
10336 Rewrite (N, Build_Dispatching_Requeue);
10337 Analyze (N);
10338 Insert_After (N, Build_Skip_Statement (N));
10340 -- The procedure_or_entry_NAME is guaranteed to be overridden by
10341 -- a protected procedure. In this case the requeue is transformed
10342 -- into a dispatching call.
10344 elsif Has_Impl
10345 and then Impl_Kind = Name_By_Protected_Procedure
10346 then
10347 Rewrite (N, Build_Dispatching_Call_Equivalent);
10348 Analyze (N);
10350 -- The procedure_or_entry_NAME's implementation kind is either
10351 -- By_Any, Optional, or pragma Implemented was not applied at all.
10352 -- In this case a runtime test determines whether Ename denotes an
10353 -- entry or a protected procedure and performs the appropriate
10354 -- call.
10356 else
10357 Rewrite (N, Build_Dispatching_Requeue_To_Any);
10358 Analyze (N);
10359 end if;
10360 end;
10362 -- Processing for regular (nondispatching) requeues
10364 else
10365 Rewrite (N, Build_Normal_Requeue);
10366 Analyze (N);
10367 Insert_After (N, Build_Skip_Statement (N));
10368 end if;
10369 end Expand_N_Requeue_Statement;
10371 -------------------------------
10372 -- Expand_N_Selective_Accept --
10373 -------------------------------
10375 procedure Expand_N_Selective_Accept (N : Node_Id) is
10376 Loc : constant Source_Ptr := Sloc (N);
10377 Alts : constant List_Id := Select_Alternatives (N);
10379 -- Note: in the below declarations a lot of new lists are allocated
10380 -- unconditionally which may well not end up being used. That's not
10381 -- a good idea since it wastes space gratuitously ???
10383 Accept_Case : List_Id;
10384 Accept_List : constant List_Id := New_List;
10386 Alt : Node_Id;
10387 Alt_List : constant List_Id := New_List;
10388 Alt_Stats : List_Id;
10389 Ann : Entity_Id := Empty;
10391 Check_Guard : Boolean := True;
10393 Decls : constant List_Id := New_List;
10394 Stats : constant List_Id := New_List;
10395 Body_List : constant List_Id := New_List;
10396 Trailing_List : constant List_Id := New_List;
10398 Choices : List_Id;
10399 Else_Present : Boolean := False;
10400 Terminate_Alt : Node_Id := Empty;
10401 Select_Mode : Node_Id;
10403 Delay_Case : List_Id;
10404 Delay_Count : Integer := 0;
10405 Delay_Val : Entity_Id;
10406 Delay_Index : Entity_Id;
10407 Delay_Min : Entity_Id;
10408 Delay_Num : Pos := 1;
10409 Delay_Alt_List : List_Id := New_List;
10410 Delay_List : constant List_Id := New_List;
10411 D : Entity_Id;
10412 M : Entity_Id;
10414 First_Delay : Boolean := True;
10415 Guard_Open : Entity_Id;
10417 End_Lab : Node_Id;
10418 Index : Pos := 1;
10419 Lab : Node_Id;
10420 Num_Alts : Nat;
10421 Num_Accept : Nat := 0;
10422 Proc : Node_Id;
10423 Time_Type : Entity_Id;
10424 Select_Call : Node_Id;
10426 Qnam : constant Entity_Id :=
10427 Make_Defining_Identifier (Loc, New_External_Name ('S', 0));
10429 Xnam : constant Entity_Id :=
10430 Make_Defining_Identifier (Loc, New_External_Name ('J', 1));
10432 -----------------------
10433 -- Local subprograms --
10434 -----------------------
10436 function Accept_Or_Raise return List_Id;
10437 -- For the rare case where delay alternatives all have guards, and
10438 -- all of them are closed, it is still possible that there were open
10439 -- accept alternatives with no callers. We must reexamine the
10440 -- Accept_List, and execute a selective wait with no else if some
10441 -- accept is open. If none, we raise program_error.
10443 procedure Add_Accept (Alt : Node_Id);
10444 -- Process a single accept statement in a select alternative. Build
10445 -- procedure for body of accept, and add entry to dispatch table with
10446 -- expression for guard, in preparation for call to run time select.
10448 function Make_And_Declare_Label (Num : Int) return Node_Id;
10449 -- Manufacture a label using Num as a serial number and declare it.
10450 -- The declaration is appended to Decls. The label marks the trailing
10451 -- statements of an accept or delay alternative.
10453 function Make_Select_Call (Select_Mode : Entity_Id) return Node_Id;
10454 -- Build call to Selective_Wait runtime routine
10456 procedure Process_Delay_Alternative (Alt : Node_Id; Index : Int);
10457 -- Add code to compare value of delay with previous values, and
10458 -- generate case entry for trailing statements.
10460 procedure Process_Accept_Alternative
10461 (Alt : Node_Id;
10462 Index : Int;
10463 Proc : Node_Id);
10464 -- Add code to call corresponding procedure, and branch to
10465 -- trailing statements, if any.
10467 ---------------------
10468 -- Accept_Or_Raise --
10469 ---------------------
10471 function Accept_Or_Raise return List_Id is
10472 Cond : Node_Id;
10473 Stats : List_Id;
10474 J : constant Entity_Id := Make_Temporary (Loc, 'J');
10476 begin
10477 -- We generate the following:
10479 -- for J in q'range loop
10480 -- if q(J).S /=null_task_entry then
10481 -- selective_wait (simple_mode,...);
10482 -- done := True;
10483 -- exit;
10484 -- end if;
10485 -- end loop;
10487 -- if no rendez_vous then
10488 -- raise program_error;
10489 -- end if;
10491 -- Note that the code needs to know that the selector name
10492 -- in an Accept_Alternative is named S.
10494 Cond := Make_Op_Ne (Loc,
10495 Left_Opnd =>
10496 Make_Selected_Component (Loc,
10497 Prefix =>
10498 Make_Indexed_Component (Loc,
10499 Prefix => New_Occurrence_Of (Qnam, Loc),
10500 Expressions => New_List (New_Occurrence_Of (J, Loc))),
10501 Selector_Name => Make_Identifier (Loc, Name_S)),
10502 Right_Opnd =>
10503 New_Occurrence_Of (RTE (RE_Null_Task_Entry), Loc));
10505 Stats := New_List (
10506 Make_Implicit_Loop_Statement (N,
10507 Iteration_Scheme =>
10508 Make_Iteration_Scheme (Loc,
10509 Loop_Parameter_Specification =>
10510 Make_Loop_Parameter_Specification (Loc,
10511 Defining_Identifier => J,
10512 Discrete_Subtype_Definition =>
10513 Make_Attribute_Reference (Loc,
10514 Prefix => New_Occurrence_Of (Qnam, Loc),
10515 Attribute_Name => Name_Range,
10516 Expressions => New_List (
10517 Make_Integer_Literal (Loc, 1))))),
10519 Statements => New_List (
10520 Make_Implicit_If_Statement (N,
10521 Condition => Cond,
10522 Then_Statements => New_List (
10523 Make_Select_Call (
10524 New_Occurrence_Of (RTE (RE_Simple_Mode), Loc)),
10525 Make_Exit_Statement (Loc))))));
10527 Append_To (Stats,
10528 Make_Raise_Program_Error (Loc,
10529 Condition => Make_Op_Eq (Loc,
10530 Left_Opnd => New_Occurrence_Of (Xnam, Loc),
10531 Right_Opnd =>
10532 New_Occurrence_Of (RTE (RE_No_Rendezvous), Loc)),
10533 Reason => PE_All_Guards_Closed));
10535 return Stats;
10536 end Accept_Or_Raise;
10538 ----------------
10539 -- Add_Accept --
10540 ----------------
10542 procedure Add_Accept (Alt : Node_Id) is
10543 Acc_Stm : constant Node_Id := Accept_Statement (Alt);
10544 Ename : constant Node_Id := Entry_Direct_Name (Acc_Stm);
10545 Eloc : constant Source_Ptr := Sloc (Ename);
10546 Eent : constant Entity_Id := Entity (Ename);
10547 Index : constant Node_Id := Entry_Index (Acc_Stm);
10548 Null_Body : Node_Id;
10549 Proc_Body : Node_Id;
10550 PB_Ent : Entity_Id;
10551 Expr : Node_Id;
10552 Call : Node_Id;
10554 begin
10555 if No (Ann) then
10556 Ann := Node (Last_Elmt (Accept_Address (Eent)));
10557 end if;
10559 if Present (Condition (Alt)) then
10560 Expr :=
10561 Make_If_Expression (Eloc, New_List (
10562 Condition (Alt),
10563 Entry_Index_Expression (Eloc, Eent, Index, Scope (Eent)),
10564 New_Occurrence_Of (RTE (RE_Null_Task_Entry), Eloc)));
10565 else
10566 Expr :=
10567 Entry_Index_Expression
10568 (Eloc, Eent, Index, Scope (Eent));
10569 end if;
10571 if Present (Handled_Statement_Sequence (Accept_Statement (Alt))) then
10572 Null_Body := New_Occurrence_Of (Standard_False, Eloc);
10574 -- Always add call to Abort_Undefer when generating code, since
10575 -- this is what the runtime expects (abort deferred in
10576 -- Selective_Wait). In CodePeer mode this only confuses the
10577 -- analysis with unknown calls, so don't do it.
10579 if not CodePeer_Mode then
10580 Call := Build_Runtime_Call (Loc, RE_Abort_Undefer);
10581 Insert_Before
10582 (First (Statements (Handled_Statement_Sequence
10583 (Accept_Statement (Alt)))),
10584 Call);
10585 Analyze (Call);
10586 end if;
10588 PB_Ent :=
10589 Make_Defining_Identifier (Eloc,
10590 New_External_Name (Chars (Ename), 'A', Num_Accept));
10592 -- Link the acceptor to the original receiving entry
10594 Set_Ekind (PB_Ent, E_Procedure);
10595 Set_Receiving_Entry (PB_Ent, Eent);
10597 if Comes_From_Source (Alt) then
10598 Set_Debug_Info_Needed (PB_Ent);
10599 end if;
10601 Proc_Body :=
10602 Make_Subprogram_Body (Eloc,
10603 Specification =>
10604 Make_Procedure_Specification (Eloc,
10605 Defining_Unit_Name => PB_Ent),
10606 Declarations => Declarations (Acc_Stm),
10607 Handled_Statement_Sequence =>
10608 Build_Accept_Body (Accept_Statement (Alt)));
10610 -- During the analysis of the body of the accept statement, any
10611 -- zero cost exception handler records were collected in the
10612 -- Accept_Handler_Records field of the N_Accept_Alternative node.
10613 -- This is where we move them to where they belong, namely the
10614 -- newly created procedure.
10616 Set_Handler_Records (PB_Ent, Accept_Handler_Records (Alt));
10617 Append (Proc_Body, Body_List);
10619 else
10620 Null_Body := New_Occurrence_Of (Standard_True, Eloc);
10622 -- if accept statement has declarations, insert above, given that
10623 -- we are not creating a body for the accept.
10625 if Present (Declarations (Acc_Stm)) then
10626 Insert_Actions (N, Declarations (Acc_Stm));
10627 end if;
10628 end if;
10630 Append_To (Accept_List,
10631 Make_Aggregate (Eloc, Expressions => New_List (Null_Body, Expr)));
10633 Num_Accept := Num_Accept + 1;
10634 end Add_Accept;
10636 ----------------------------
10637 -- Make_And_Declare_Label --
10638 ----------------------------
10640 function Make_And_Declare_Label (Num : Int) return Node_Id is
10641 Lab_Id : Node_Id;
10643 begin
10644 Lab_Id := Make_Identifier (Loc, New_External_Name ('L', Num));
10645 Lab :=
10646 Make_Label (Loc, Lab_Id);
10648 Append_To (Decls,
10649 Make_Implicit_Label_Declaration (Loc,
10650 Defining_Identifier =>
10651 Make_Defining_Identifier (Loc, Chars (Lab_Id)),
10652 Label_Construct => Lab));
10654 return Lab;
10655 end Make_And_Declare_Label;
10657 ----------------------
10658 -- Make_Select_Call --
10659 ----------------------
10661 function Make_Select_Call (Select_Mode : Entity_Id) return Node_Id is
10662 Params : constant List_Id := New_List;
10664 begin
10665 Append_To (Params,
10666 Make_Attribute_Reference (Loc,
10667 Prefix => New_Occurrence_Of (Qnam, Loc),
10668 Attribute_Name => Name_Unchecked_Access));
10669 Append_To (Params, Select_Mode);
10670 Append_To (Params, New_Occurrence_Of (Ann, Loc));
10671 Append_To (Params, New_Occurrence_Of (Xnam, Loc));
10673 return
10674 Make_Procedure_Call_Statement (Loc,
10675 Name => New_Occurrence_Of (RTE (RE_Selective_Wait), Loc),
10676 Parameter_Associations => Params);
10677 end Make_Select_Call;
10679 --------------------------------
10680 -- Process_Accept_Alternative --
10681 --------------------------------
10683 procedure Process_Accept_Alternative
10684 (Alt : Node_Id;
10685 Index : Int;
10686 Proc : Node_Id)
10688 Astmt : constant Node_Id := Accept_Statement (Alt);
10689 Alt_Stats : List_Id;
10691 begin
10692 Adjust_Condition (Condition (Alt));
10694 -- Accept with body
10696 if Present (Handled_Statement_Sequence (Astmt)) then
10697 Alt_Stats :=
10698 New_List (
10699 Make_Procedure_Call_Statement (Sloc (Proc),
10700 Name =>
10701 New_Occurrence_Of
10702 (Defining_Unit_Name (Specification (Proc)),
10703 Sloc (Proc))));
10705 -- Accept with no body (followed by trailing statements)
10707 else
10708 Alt_Stats := Empty_List;
10709 end if;
10711 Ensure_Statement_Present (Sloc (Astmt), Alt);
10713 -- After the call, if any, branch to trailing statements, if any.
10714 -- We create a label for each, as well as the corresponding label
10715 -- declaration.
10717 if not Is_Empty_List (Statements (Alt)) then
10718 Lab := Make_And_Declare_Label (Index);
10719 Append (Lab, Trailing_List);
10720 Append_List (Statements (Alt), Trailing_List);
10721 Append_To (Trailing_List,
10722 Make_Goto_Statement (Loc,
10723 Name => New_Copy (Identifier (End_Lab))));
10725 else
10726 Lab := End_Lab;
10727 end if;
10729 Append_To (Alt_Stats,
10730 Make_Goto_Statement (Loc, Name => New_Copy (Identifier (Lab))));
10732 Append_To (Alt_List,
10733 Make_Case_Statement_Alternative (Loc,
10734 Discrete_Choices => New_List (Make_Integer_Literal (Loc, Index)),
10735 Statements => Alt_Stats));
10736 end Process_Accept_Alternative;
10738 -------------------------------
10739 -- Process_Delay_Alternative --
10740 -------------------------------
10742 procedure Process_Delay_Alternative (Alt : Node_Id; Index : Int) is
10743 Dloc : constant Source_Ptr := Sloc (Delay_Statement (Alt));
10744 Cond : Node_Id;
10745 Delay_Alt : List_Id;
10747 begin
10748 -- Deal with C/Fortran boolean as delay condition
10750 Adjust_Condition (Condition (Alt));
10752 -- Determine the smallest specified delay
10754 -- for each delay alternative generate:
10756 -- if guard-expression then
10757 -- Delay_Val := delay-expression;
10758 -- Guard_Open := True;
10759 -- if Delay_Val < Delay_Min then
10760 -- Delay_Min := Delay_Val;
10761 -- Delay_Index := Index;
10762 -- end if;
10763 -- end if;
10765 -- The enclosing if-statement is omitted if there is no guard
10767 if Delay_Count = 1 or else First_Delay then
10768 First_Delay := False;
10770 Delay_Alt := New_List (
10771 Make_Assignment_Statement (Loc,
10772 Name => New_Occurrence_Of (Delay_Min, Loc),
10773 Expression => Expression (Delay_Statement (Alt))));
10775 if Delay_Count > 1 then
10776 Append_To (Delay_Alt,
10777 Make_Assignment_Statement (Loc,
10778 Name => New_Occurrence_Of (Delay_Index, Loc),
10779 Expression => Make_Integer_Literal (Loc, Index)));
10780 end if;
10782 else
10783 Delay_Alt := New_List (
10784 Make_Assignment_Statement (Loc,
10785 Name => New_Occurrence_Of (Delay_Val, Loc),
10786 Expression => Expression (Delay_Statement (Alt))));
10788 if Time_Type = Standard_Duration then
10789 Cond :=
10790 Make_Op_Lt (Loc,
10791 Left_Opnd => New_Occurrence_Of (Delay_Val, Loc),
10792 Right_Opnd => New_Occurrence_Of (Delay_Min, Loc));
10794 else
10795 -- The scope of the time type must define a comparison
10796 -- operator. The scope itself may not be visible, so we
10797 -- construct a node with entity information to insure that
10798 -- semantic analysis can find the proper operator.
10800 Cond :=
10801 Make_Function_Call (Loc,
10802 Name => Make_Selected_Component (Loc,
10803 Prefix =>
10804 New_Occurrence_Of (Scope (Time_Type), Loc),
10805 Selector_Name =>
10806 Make_Operator_Symbol (Loc,
10807 Chars => Name_Op_Lt,
10808 Strval => No_String)),
10809 Parameter_Associations =>
10810 New_List (
10811 New_Occurrence_Of (Delay_Val, Loc),
10812 New_Occurrence_Of (Delay_Min, Loc)));
10814 Set_Entity (Prefix (Name (Cond)), Scope (Time_Type));
10815 end if;
10817 Append_To (Delay_Alt,
10818 Make_Implicit_If_Statement (N,
10819 Condition => Cond,
10820 Then_Statements => New_List (
10821 Make_Assignment_Statement (Loc,
10822 Name => New_Occurrence_Of (Delay_Min, Loc),
10823 Expression => New_Occurrence_Of (Delay_Val, Loc)),
10825 Make_Assignment_Statement (Loc,
10826 Name => New_Occurrence_Of (Delay_Index, Loc),
10827 Expression => Make_Integer_Literal (Loc, Index)))));
10828 end if;
10830 if Check_Guard then
10831 Append_To (Delay_Alt,
10832 Make_Assignment_Statement (Loc,
10833 Name => New_Occurrence_Of (Guard_Open, Loc),
10834 Expression => New_Occurrence_Of (Standard_True, Loc)));
10835 end if;
10837 if Present (Condition (Alt)) then
10838 Delay_Alt := New_List (
10839 Make_Implicit_If_Statement (N,
10840 Condition => Condition (Alt),
10841 Then_Statements => Delay_Alt));
10842 end if;
10844 Append_List (Delay_Alt, Delay_List);
10846 Ensure_Statement_Present (Dloc, Alt);
10848 -- If the delay alternative has a statement part, add choice to the
10849 -- case statements for delays.
10851 if not Is_Empty_List (Statements (Alt)) then
10853 if Delay_Count = 1 then
10854 Append_List (Statements (Alt), Delay_Alt_List);
10856 else
10857 Append_To (Delay_Alt_List,
10858 Make_Case_Statement_Alternative (Loc,
10859 Discrete_Choices => New_List (
10860 Make_Integer_Literal (Loc, Index)),
10861 Statements => Statements (Alt)));
10862 end if;
10864 elsif Delay_Count = 1 then
10866 -- If the single delay has no trailing statements, add a branch
10867 -- to the exit label to the selective wait.
10869 Delay_Alt_List := New_List (
10870 Make_Goto_Statement (Loc,
10871 Name => New_Copy (Identifier (End_Lab))));
10873 end if;
10874 end Process_Delay_Alternative;
10876 -- Start of processing for Expand_N_Selective_Accept
10878 begin
10879 Process_Statements_For_Controlled_Objects (N);
10881 -- First insert some declarations before the select. The first is:
10883 -- Ann : Address
10885 -- This variable holds the parameters passed to the accept body. This
10886 -- declaration has already been inserted by the time we get here by
10887 -- a call to Expand_Accept_Declarations made from the semantics when
10888 -- processing the first accept statement contained in the select. We
10889 -- can find this entity as Accept_Address (E), where E is any of the
10890 -- entries references by contained accept statements.
10892 -- The first step is to scan the list of Selective_Accept_Statements
10893 -- to find this entity, and also count the number of accepts, and
10894 -- determine if terminated, delay or else is present:
10896 Num_Alts := 0;
10898 Alt := First (Alts);
10899 while Present (Alt) loop
10900 Process_Statements_For_Controlled_Objects (Alt);
10902 if Nkind (Alt) = N_Accept_Alternative then
10903 Add_Accept (Alt);
10905 elsif Nkind (Alt) = N_Delay_Alternative then
10906 Delay_Count := Delay_Count + 1;
10908 -- If the delays are relative delays, the delay expressions have
10909 -- type Standard_Duration. Otherwise they must have some time type
10910 -- recognized by GNAT.
10912 if Nkind (Delay_Statement (Alt)) = N_Delay_Relative_Statement then
10913 Time_Type := Standard_Duration;
10914 else
10915 Time_Type := Etype (Expression (Delay_Statement (Alt)));
10917 if Is_RTE (Base_Type (Etype (Time_Type)), RO_CA_Time)
10918 or else Is_RTE (Base_Type (Etype (Time_Type)), RO_RT_Time)
10919 then
10920 null;
10921 else
10922 Error_Msg_NE (
10923 "& is not a time type (RM 9.6(6))",
10924 Expression (Delay_Statement (Alt)), Time_Type);
10925 Time_Type := Standard_Duration;
10926 Set_Etype (Expression (Delay_Statement (Alt)), Any_Type);
10927 end if;
10928 end if;
10930 if No (Condition (Alt)) then
10932 -- This guard will always be open
10934 Check_Guard := False;
10935 end if;
10937 elsif Nkind (Alt) = N_Terminate_Alternative then
10938 Adjust_Condition (Condition (Alt));
10939 Terminate_Alt := Alt;
10940 end if;
10942 Num_Alts := Num_Alts + 1;
10943 Next (Alt);
10944 end loop;
10946 Else_Present := Present (Else_Statements (N));
10948 -- At the same time (see procedure Add_Accept) we build the accept list:
10950 -- Qnn : Accept_List (1 .. num-select) := (
10951 -- (null-body, entry-index),
10952 -- (null-body, entry-index),
10953 -- ..
10954 -- (null_body, entry-index));
10956 -- In the above declaration, null-body is True if the corresponding
10957 -- accept has no body, and false otherwise. The entry is either the
10958 -- entry index expression if there is no guard, or if a guard is
10959 -- present, then an if expression of the form:
10961 -- (if guard then entry-index else Null_Task_Entry)
10963 -- If a guard is statically known to be false, the entry can simply
10964 -- be omitted from the accept list.
10966 Append_To (Decls,
10967 Make_Object_Declaration (Loc,
10968 Defining_Identifier => Qnam,
10969 Object_Definition => New_Occurrence_Of (RTE (RE_Accept_List), Loc),
10970 Aliased_Present => True,
10971 Expression =>
10972 Make_Qualified_Expression (Loc,
10973 Subtype_Mark =>
10974 New_Occurrence_Of (RTE (RE_Accept_List), Loc),
10975 Expression =>
10976 Make_Aggregate (Loc, Expressions => Accept_List))));
10978 -- Then we declare the variable that holds the index for the accept
10979 -- that will be selected for service:
10981 -- Xnn : Select_Index;
10983 Append_To (Decls,
10984 Make_Object_Declaration (Loc,
10985 Defining_Identifier => Xnam,
10986 Object_Definition =>
10987 New_Occurrence_Of (RTE (RE_Select_Index), Loc),
10988 Expression =>
10989 New_Occurrence_Of (RTE (RE_No_Rendezvous), Loc)));
10991 -- After this follow procedure declarations for each accept body
10993 -- procedure Pnn is
10994 -- begin
10995 -- ...
10996 -- end;
10998 -- where the ... are statements from the corresponding procedure body.
10999 -- No parameters are involved, since the parameters are passed via Ann
11000 -- and the parameter references have already been expanded to be direct
11001 -- references to Ann (see Exp_Ch2.Expand_Entry_Parameter). Furthermore,
11002 -- any embedded tasking statements (which would normally be illegal in
11003 -- procedures), have been converted to calls to the tasking runtime so
11004 -- there is no problem in putting them into procedures.
11006 -- The original accept statement has been expanded into a block in
11007 -- the same fashion as for simple accepts (see Build_Accept_Body).
11009 -- Note: we don't really need to build these procedures for the case
11010 -- where no delay statement is present, but it is just as easy to
11011 -- build them unconditionally, and not significantly inefficient,
11012 -- since if they are short they will be inlined anyway.
11014 -- The procedure declarations have been assembled in Body_List
11016 -- If delays are present, we must compute the required delay.
11017 -- We first generate the declarations:
11019 -- Delay_Index : Boolean := 0;
11020 -- Delay_Min : Some_Time_Type.Time;
11021 -- Delay_Val : Some_Time_Type.Time;
11023 -- Delay_Index will be set to the index of the minimum delay, i.e. the
11024 -- active delay that is actually chosen as the basis for the possible
11025 -- delay if an immediate rendez-vous is not possible.
11027 -- In the most common case there is a single delay statement, and this
11028 -- is handled specially.
11030 if Delay_Count > 0 then
11032 -- Generate the required declarations
11034 Delay_Val :=
11035 Make_Defining_Identifier (Loc, New_External_Name ('D', 1));
11036 Delay_Index :=
11037 Make_Defining_Identifier (Loc, New_External_Name ('D', 2));
11038 Delay_Min :=
11039 Make_Defining_Identifier (Loc, New_External_Name ('D', 3));
11041 Append_To (Decls,
11042 Make_Object_Declaration (Loc,
11043 Defining_Identifier => Delay_Val,
11044 Object_Definition => New_Occurrence_Of (Time_Type, Loc)));
11046 Append_To (Decls,
11047 Make_Object_Declaration (Loc,
11048 Defining_Identifier => Delay_Index,
11049 Object_Definition => New_Occurrence_Of (Standard_Integer, Loc),
11050 Expression => Make_Integer_Literal (Loc, 0)));
11052 Append_To (Decls,
11053 Make_Object_Declaration (Loc,
11054 Defining_Identifier => Delay_Min,
11055 Object_Definition => New_Occurrence_Of (Time_Type, Loc),
11056 Expression =>
11057 Unchecked_Convert_To (Time_Type,
11058 Make_Attribute_Reference (Loc,
11059 Prefix =>
11060 New_Occurrence_Of (Underlying_Type (Time_Type), Loc),
11061 Attribute_Name => Name_Last))));
11063 -- Create Duration and Delay_Mode objects used for passing a delay
11064 -- value to RTS
11066 D := Make_Temporary (Loc, 'D');
11067 M := Make_Temporary (Loc, 'M');
11069 declare
11070 Discr : Entity_Id;
11072 begin
11073 -- Note that these values are defined in s-osprim.ads and must
11074 -- be kept in sync:
11076 -- Relative : constant := 0;
11077 -- Absolute_Calendar : constant := 1;
11078 -- Absolute_RT : constant := 2;
11080 if Time_Type = Standard_Duration then
11081 Discr := Make_Integer_Literal (Loc, 0);
11083 elsif Is_RTE (Base_Type (Etype (Time_Type)), RO_CA_Time) then
11084 Discr := Make_Integer_Literal (Loc, 1);
11086 else
11087 pragma Assert
11088 (Is_RTE (Base_Type (Etype (Time_Type)), RO_RT_Time));
11089 Discr := Make_Integer_Literal (Loc, 2);
11090 end if;
11092 Append_To (Decls,
11093 Make_Object_Declaration (Loc,
11094 Defining_Identifier => D,
11095 Object_Definition =>
11096 New_Occurrence_Of (Standard_Duration, Loc)));
11098 Append_To (Decls,
11099 Make_Object_Declaration (Loc,
11100 Defining_Identifier => M,
11101 Object_Definition =>
11102 New_Occurrence_Of (Standard_Integer, Loc),
11103 Expression => Discr));
11104 end;
11106 if Check_Guard then
11107 Guard_Open :=
11108 Make_Defining_Identifier (Loc, New_External_Name ('G', 1));
11110 Append_To (Decls,
11111 Make_Object_Declaration (Loc,
11112 Defining_Identifier => Guard_Open,
11113 Object_Definition =>
11114 New_Occurrence_Of (Standard_Boolean, Loc),
11115 Expression =>
11116 New_Occurrence_Of (Standard_False, Loc)));
11117 end if;
11119 -- Delay_Count is zero, don't need M and D set (suppress warning)
11121 else
11122 M := Empty;
11123 D := Empty;
11124 end if;
11126 if Present (Terminate_Alt) then
11128 -- If the terminate alternative guard is False, use
11129 -- Simple_Mode; otherwise use Terminate_Mode.
11131 if Present (Condition (Terminate_Alt)) then
11132 Select_Mode := Make_If_Expression (Loc,
11133 New_List (Condition (Terminate_Alt),
11134 New_Occurrence_Of (RTE (RE_Terminate_Mode), Loc),
11135 New_Occurrence_Of (RTE (RE_Simple_Mode), Loc)));
11136 else
11137 Select_Mode := New_Occurrence_Of (RTE (RE_Terminate_Mode), Loc);
11138 end if;
11140 elsif Else_Present or Delay_Count > 0 then
11141 Select_Mode := New_Occurrence_Of (RTE (RE_Else_Mode), Loc);
11143 else
11144 Select_Mode := New_Occurrence_Of (RTE (RE_Simple_Mode), Loc);
11145 end if;
11147 Select_Call := Make_Select_Call (Select_Mode);
11148 Append (Select_Call, Stats);
11150 -- Now generate code to act on the result. There is an entry
11151 -- in this case for each accept statement with a non-null body,
11152 -- followed by a branch to the statements that follow the Accept.
11153 -- In the absence of delay alternatives, we generate:
11155 -- case X is
11156 -- when No_Rendezvous => -- omitted if simple mode
11157 -- goto Lab0;
11159 -- when 1 =>
11160 -- P1n;
11161 -- goto Lab1;
11163 -- when 2 =>
11164 -- P2n;
11165 -- goto Lab2;
11167 -- when others =>
11168 -- goto Exit;
11169 -- end case;
11171 -- Lab0: Else_Statements;
11172 -- goto exit;
11174 -- Lab1: Trailing_Statements1;
11175 -- goto Exit;
11177 -- Lab2: Trailing_Statements2;
11178 -- goto Exit;
11179 -- ...
11180 -- Exit:
11182 -- Generate label for common exit
11184 End_Lab := Make_And_Declare_Label (Num_Alts + 1);
11186 -- First entry is the default case, when no rendezvous is possible
11188 Choices := New_List (New_Occurrence_Of (RTE (RE_No_Rendezvous), Loc));
11190 if Else_Present then
11192 -- If no rendezvous is possible, the else part is executed
11194 Lab := Make_And_Declare_Label (0);
11195 Alt_Stats := New_List (
11196 Make_Goto_Statement (Loc,
11197 Name => New_Copy (Identifier (Lab))));
11199 Append (Lab, Trailing_List);
11200 Append_List (Else_Statements (N), Trailing_List);
11201 Append_To (Trailing_List,
11202 Make_Goto_Statement (Loc,
11203 Name => New_Copy (Identifier (End_Lab))));
11204 else
11205 Alt_Stats := New_List (
11206 Make_Goto_Statement (Loc,
11207 Name => New_Copy (Identifier (End_Lab))));
11208 end if;
11210 Append_To (Alt_List,
11211 Make_Case_Statement_Alternative (Loc,
11212 Discrete_Choices => Choices,
11213 Statements => Alt_Stats));
11215 -- We make use of the fact that Accept_Index is an integer type, and
11216 -- generate successive literals for entries for each accept. Only those
11217 -- for which there is a body or trailing statements get a case entry.
11219 Alt := First (Select_Alternatives (N));
11220 Proc := First (Body_List);
11221 while Present (Alt) loop
11223 if Nkind (Alt) = N_Accept_Alternative then
11224 Process_Accept_Alternative (Alt, Index, Proc);
11225 Index := Index + 1;
11227 if Present
11228 (Handled_Statement_Sequence (Accept_Statement (Alt)))
11229 then
11230 Next (Proc);
11231 end if;
11233 elsif Nkind (Alt) = N_Delay_Alternative then
11234 Process_Delay_Alternative (Alt, Delay_Num);
11235 Delay_Num := Delay_Num + 1;
11236 end if;
11238 Next (Alt);
11239 end loop;
11241 -- An others choice is always added to the main case, as well
11242 -- as the delay case (to satisfy the compiler).
11244 Append_To (Alt_List,
11245 Make_Case_Statement_Alternative (Loc,
11246 Discrete_Choices =>
11247 New_List (Make_Others_Choice (Loc)),
11248 Statements =>
11249 New_List (Make_Goto_Statement (Loc,
11250 Name => New_Copy (Identifier (End_Lab))))));
11252 Accept_Case := New_List (
11253 Make_Case_Statement (Loc,
11254 Expression => New_Occurrence_Of (Xnam, Loc),
11255 Alternatives => Alt_List));
11257 Append_List (Trailing_List, Accept_Case);
11258 Append_List (Body_List, Decls);
11260 -- Construct case statement for trailing statements of delay
11261 -- alternatives, if there are several of them.
11263 if Delay_Count > 1 then
11264 Append_To (Delay_Alt_List,
11265 Make_Case_Statement_Alternative (Loc,
11266 Discrete_Choices =>
11267 New_List (Make_Others_Choice (Loc)),
11268 Statements =>
11269 New_List (Make_Null_Statement (Loc))));
11271 Delay_Case := New_List (
11272 Make_Case_Statement (Loc,
11273 Expression => New_Occurrence_Of (Delay_Index, Loc),
11274 Alternatives => Delay_Alt_List));
11275 else
11276 Delay_Case := Delay_Alt_List;
11277 end if;
11279 -- If there are no delay alternatives, we append the case statement
11280 -- to the statement list.
11282 if Delay_Count = 0 then
11283 Append_List (Accept_Case, Stats);
11285 -- Delay alternatives present
11287 else
11288 -- If delay alternatives are present we generate:
11290 -- find minimum delay.
11291 -- DX := minimum delay;
11292 -- M := <delay mode>;
11293 -- Timed_Selective_Wait (Q'Unchecked_Access, Delay_Mode, P,
11294 -- DX, MX, X);
11296 -- if X = No_Rendezvous then
11297 -- case statement for delay statements.
11298 -- else
11299 -- case statement for accept alternatives.
11300 -- end if;
11302 declare
11303 Cases : Node_Id;
11304 Stmt : Node_Id;
11305 Parms : List_Id;
11306 Parm : Node_Id;
11307 Conv : Node_Id;
11309 begin
11310 -- The type of the delay expression is known to be legal
11312 if Time_Type = Standard_Duration then
11313 Conv := New_Occurrence_Of (Delay_Min, Loc);
11315 elsif Is_RTE (Base_Type (Etype (Time_Type)), RO_CA_Time) then
11316 Conv := Make_Function_Call (Loc,
11317 New_Occurrence_Of (RTE (RO_CA_To_Duration), Loc),
11318 New_List (New_Occurrence_Of (Delay_Min, Loc)));
11320 else
11321 pragma Assert
11322 (Is_RTE (Base_Type (Etype (Time_Type)), RO_RT_Time));
11324 Conv := Make_Function_Call (Loc,
11325 New_Occurrence_Of (RTE (RO_RT_To_Duration), Loc),
11326 New_List (New_Occurrence_Of (Delay_Min, Loc)));
11327 end if;
11329 Stmt := Make_Assignment_Statement (Loc,
11330 Name => New_Occurrence_Of (D, Loc),
11331 Expression => Conv);
11333 -- Change the value for Accept_Modes. (Else_Mode -> Delay_Mode)
11335 Parms := Parameter_Associations (Select_Call);
11337 Parm := First (Parms);
11338 while Present (Parm) and then Parm /= Select_Mode loop
11339 Next (Parm);
11340 end loop;
11342 pragma Assert (Present (Parm));
11343 Rewrite (Parm, New_Occurrence_Of (RTE (RE_Delay_Mode), Loc));
11344 Analyze (Parm);
11346 -- Prepare two new parameters of Duration and Delay_Mode type
11347 -- which represent the value and the mode of the minimum delay.
11349 Next (Parm);
11350 Insert_After (Parm, New_Occurrence_Of (M, Loc));
11351 Insert_After (Parm, New_Occurrence_Of (D, Loc));
11353 -- Create a call to RTS
11355 Rewrite (Select_Call,
11356 Make_Procedure_Call_Statement (Loc,
11357 Name => New_Occurrence_Of (RTE (RE_Timed_Selective_Wait), Loc),
11358 Parameter_Associations => Parms));
11360 -- This new call should follow the calculation of the minimum
11361 -- delay.
11363 Insert_List_Before (Select_Call, Delay_List);
11365 if Check_Guard then
11366 Stmt :=
11367 Make_Implicit_If_Statement (N,
11368 Condition => New_Occurrence_Of (Guard_Open, Loc),
11369 Then_Statements => New_List (
11370 New_Copy_Tree (Stmt),
11371 New_Copy_Tree (Select_Call)),
11372 Else_Statements => Accept_Or_Raise);
11373 Rewrite (Select_Call, Stmt);
11374 else
11375 Insert_Before (Select_Call, Stmt);
11376 end if;
11378 Cases :=
11379 Make_Implicit_If_Statement (N,
11380 Condition => Make_Op_Eq (Loc,
11381 Left_Opnd => New_Occurrence_Of (Xnam, Loc),
11382 Right_Opnd =>
11383 New_Occurrence_Of (RTE (RE_No_Rendezvous), Loc)),
11385 Then_Statements => Delay_Case,
11386 Else_Statements => Accept_Case);
11388 Append (Cases, Stats);
11389 end;
11390 end if;
11392 Append (End_Lab, Stats);
11394 -- Replace accept statement with appropriate block
11396 Rewrite (N,
11397 Make_Block_Statement (Loc,
11398 Declarations => Decls,
11399 Handled_Statement_Sequence =>
11400 Make_Handled_Sequence_Of_Statements (Loc, Statements => Stats)));
11401 Analyze (N);
11403 -- Note: have to worry more about abort deferral in above code ???
11405 -- Final step is to unstack the Accept_Address entries for all accept
11406 -- statements appearing in accept alternatives in the select statement
11408 Alt := First (Alts);
11409 while Present (Alt) loop
11410 if Nkind (Alt) = N_Accept_Alternative then
11411 Remove_Last_Elmt (Accept_Address
11412 (Entity (Entry_Direct_Name (Accept_Statement (Alt)))));
11413 end if;
11415 Next (Alt);
11416 end loop;
11417 end Expand_N_Selective_Accept;
11419 -------------------------------------------
11420 -- Expand_N_Single_Protected_Declaration --
11421 -------------------------------------------
11423 -- A single protected declaration should never be present after semantic
11424 -- analysis because it is transformed into a protected type declaration
11425 -- and an accompanying anonymous object. This routine ensures that the
11426 -- transformation takes place.
11428 procedure Expand_N_Single_Protected_Declaration (N : Node_Id) is
11429 begin
11430 raise Program_Error;
11431 end Expand_N_Single_Protected_Declaration;
11433 --------------------------------------
11434 -- Expand_N_Single_Task_Declaration --
11435 --------------------------------------
11437 -- A single task declaration should never be present after semantic
11438 -- analysis because it is transformed into a task type declaration and
11439 -- an accompanying anonymous object. This routine ensures that the
11440 -- transformation takes place.
11442 procedure Expand_N_Single_Task_Declaration (N : Node_Id) is
11443 begin
11444 raise Program_Error;
11445 end Expand_N_Single_Task_Declaration;
11447 ------------------------
11448 -- Expand_N_Task_Body --
11449 ------------------------
11451 -- Given a task body
11453 -- task body tname is
11454 -- <declarations>
11455 -- begin
11456 -- <statements>
11457 -- end x;
11459 -- This expansion routine converts it into a procedure and sets the
11460 -- elaboration flag for the procedure to true, to represent the fact
11461 -- that the task body is now elaborated:
11463 -- procedure tnameB (_Task : access tnameV) is
11464 -- discriminal : dtype renames _Task.discriminant;
11466 -- procedure _clean is
11467 -- begin
11468 -- Abort_Defer.all;
11469 -- Complete_Task;
11470 -- Abort_Undefer.all;
11471 -- return;
11472 -- end _clean;
11474 -- begin
11475 -- Abort_Undefer.all;
11476 -- <declarations>
11477 -- System.Task_Stages.Complete_Activation;
11478 -- <statements>
11479 -- at end
11480 -- _clean;
11481 -- end tnameB;
11483 -- tnameE := True;
11485 -- In addition, if the task body is an activator, then a call to activate
11486 -- tasks is added at the start of the statements, before the call to
11487 -- Complete_Activation, and if in addition the task is a master then it
11488 -- must be established as a master. These calls are inserted and analyzed
11489 -- in Expand_Cleanup_Actions, when the Handled_Sequence_Of_Statements is
11490 -- expanded.
11492 -- There is one discriminal declaration line generated for each
11493 -- discriminant that is present to provide an easy reference point for
11494 -- discriminant references inside the body (see Exp_Ch2.Expand_Name).
11496 -- Note on relationship to GNARLI definition. In the GNARLI definition,
11497 -- task body procedures have a profile (Arg : System.Address). That is
11498 -- needed because GNARLI has to use the same access-to-subprogram type
11499 -- for all task types. We depend here on knowing that in GNAT, passing
11500 -- an address argument by value is identical to passing a record value
11501 -- by access (in either case a single pointer is passed), so even though
11502 -- this procedure has the wrong profile. In fact it's all OK, since the
11503 -- callings sequence is identical.
11505 procedure Expand_N_Task_Body (N : Node_Id) is
11506 Loc : constant Source_Ptr := Sloc (N);
11507 Ttyp : constant Entity_Id := Corresponding_Spec (N);
11508 Call : Node_Id;
11509 New_N : Node_Id;
11511 Insert_Nod : Node_Id;
11512 -- Used to determine the proper location of wrapper body insertions
11514 begin
11515 -- if no task body procedure, means we had an error in configurable
11516 -- run-time mode, and there is no point in proceeding further.
11518 if No (Task_Body_Procedure (Ttyp)) then
11519 return;
11520 end if;
11522 -- Add renaming declarations for discriminals and a declaration for the
11523 -- entry family index (if applicable).
11525 Install_Private_Data_Declarations
11526 (Loc, Task_Body_Procedure (Ttyp), Ttyp, N, Declarations (N));
11528 -- Add a call to Abort_Undefer at the very beginning of the task
11529 -- body since this body is called with abort still deferred.
11531 if Abort_Allowed then
11532 Call := Build_Runtime_Call (Loc, RE_Abort_Undefer);
11533 Insert_Before
11534 (First (Statements (Handled_Statement_Sequence (N))), Call);
11535 Analyze (Call);
11536 end if;
11538 -- The statement part has already been protected with an at_end and
11539 -- cleanup actions. The call to Complete_Activation must be placed
11540 -- at the head of the sequence of statements of that block. The
11541 -- declarations have been merged in this sequence of statements but
11542 -- the first real statement is accessible from the First_Real_Statement
11543 -- field (which was set for exactly this purpose).
11545 if Restricted_Profile then
11546 Call := Build_Runtime_Call (Loc, RE_Complete_Restricted_Activation);
11547 else
11548 Call := Build_Runtime_Call (Loc, RE_Complete_Activation);
11549 end if;
11551 Insert_Before
11552 (First_Real_Statement (Handled_Statement_Sequence (N)), Call);
11553 Analyze (Call);
11555 New_N :=
11556 Make_Subprogram_Body (Loc,
11557 Specification => Build_Task_Proc_Specification (Ttyp),
11558 Declarations => Declarations (N),
11559 Handled_Statement_Sequence => Handled_Statement_Sequence (N));
11560 Set_Is_Task_Body_Procedure (New_N);
11562 -- If the task contains generic instantiations, cleanup actions are
11563 -- delayed until after instantiation. Transfer the activation chain to
11564 -- the subprogram, to insure that the activation call is properly
11565 -- generated. It the task body contains inner tasks, indicate that the
11566 -- subprogram is a task master.
11568 if Delay_Cleanups (Ttyp) then
11569 Set_Activation_Chain_Entity (New_N, Activation_Chain_Entity (N));
11570 Set_Is_Task_Master (New_N, Is_Task_Master (N));
11571 end if;
11573 Rewrite (N, New_N);
11574 Analyze (N);
11576 -- Set elaboration flag immediately after task body. If the body is a
11577 -- subunit, the flag is set in the declarative part containing the stub.
11579 if Nkind (Parent (N)) /= N_Subunit then
11580 Insert_After (N,
11581 Make_Assignment_Statement (Loc,
11582 Name =>
11583 Make_Identifier (Loc, New_External_Name (Chars (Ttyp), 'E')),
11584 Expression => New_Occurrence_Of (Standard_True, Loc)));
11585 end if;
11587 -- Ada 2005 (AI-345): Construct the primitive entry wrapper bodies after
11588 -- the task body. At this point all wrapper specs have been created,
11589 -- frozen and included in the dispatch table for the task type.
11591 if Ada_Version >= Ada_2005 then
11592 if Nkind (Parent (N)) = N_Subunit then
11593 Insert_Nod := Corresponding_Stub (Parent (N));
11594 else
11595 Insert_Nod := N;
11596 end if;
11598 Build_Wrapper_Bodies (Loc, Ttyp, Insert_Nod);
11599 end if;
11600 end Expand_N_Task_Body;
11602 ------------------------------------
11603 -- Expand_N_Task_Type_Declaration --
11604 ------------------------------------
11606 -- We have several things to do. First we must create a Boolean flag used
11607 -- to mark if the body is elaborated yet. This variable gets set to True
11608 -- when the body of the task is elaborated (we can't rely on the normal
11609 -- ABE mechanism for the task body, since we need to pass an access to
11610 -- this elaboration boolean to the runtime routines).
11612 -- taskE : aliased Boolean := False;
11614 -- Next a variable is declared to hold the task stack size (either the
11615 -- default : Unspecified_Size, or a value that is set by a pragma
11616 -- Storage_Size). If the value of the pragma Storage_Size is static, then
11617 -- the variable is initialized with this value:
11619 -- taskZ : Size_Type := Unspecified_Size;
11620 -- or
11621 -- taskZ : Size_Type := Size_Type (size_expression);
11623 -- Note: No variable is needed to hold the task relative deadline since
11624 -- its value would never be static because the parameter is of a private
11625 -- type (Ada.Real_Time.Time_Span).
11627 -- Next we create a corresponding record type declaration used to represent
11628 -- values of this task. The general form of this type declaration is
11630 -- type taskV (discriminants) is record
11631 -- _Task_Id : Task_Id;
11632 -- entry_family : array (bounds) of Void;
11633 -- _Priority : Integer := priority_expression;
11634 -- _Size : Size_Type := size_expression;
11635 -- _Secondary_Stack_Size : Size_Type := size_expression;
11636 -- _Task_Info : Task_Info_Type := task_info_expression;
11637 -- _CPU : Integer := cpu_range_expression;
11638 -- _Relative_Deadline : Time_Span := time_span_expression;
11639 -- _Domain : Dispatching_Domain := dd_expression;
11640 -- end record;
11642 -- The discriminants are present only if the corresponding task type has
11643 -- discriminants, and they exactly mirror the task type discriminants.
11645 -- The Id field is always present. It contains the Task_Id value, as set by
11646 -- the call to Create_Task. Note that although the task is limited, the
11647 -- task value record type is not limited, so there is no problem in passing
11648 -- this field as an out parameter to Create_Task.
11650 -- One entry_family component is present for each entry family in the task
11651 -- definition. The bounds correspond to the bounds of the entry family
11652 -- (which may depend on discriminants). The element type is void, since we
11653 -- only need the bounds information for determining the entry index. Note
11654 -- that the use of an anonymous array would normally be illegal in this
11655 -- context, but this is a parser check, and the semantics is quite prepared
11656 -- to handle such a case.
11658 -- The _Size field is present only if a Storage_Size pragma appears in the
11659 -- task definition. The expression captures the argument that was present
11660 -- in the pragma, and is used to override the task stack size otherwise
11661 -- associated with the task type.
11663 -- The _Secondary_Stack_Size field is present only the task entity has a
11664 -- Secondary_Stack_Size rep item. It will be filled at the freeze point,
11665 -- when the record init proc is built, to capture the expression of the
11666 -- rep item (see Build_Record_Init_Proc in Exp_Ch3). Note that it cannot
11667 -- be filled here since aspect evaluations are delayed till the freeze
11668 -- point.
11670 -- The _Priority field is present only if the task entity has a Priority or
11671 -- Interrupt_Priority rep item (pragma, aspect specification or attribute
11672 -- definition clause). It will be filled at the freeze point, when the
11673 -- record init proc is built, to capture the expression of the rep item
11674 -- (see Build_Record_Init_Proc in Exp_Ch3). Note that it cannot be filled
11675 -- here since aspect evaluations are delayed till the freeze point.
11677 -- The _Task_Info field is present only if a Task_Info pragma appears in
11678 -- the task definition. The expression captures the argument that was
11679 -- present in the pragma, and is used to provide the Task_Image parameter
11680 -- to the call to Create_Task.
11682 -- The _CPU field is present only if the task entity has a CPU rep item
11683 -- (pragma, aspect specification or attribute definition clause). It will
11684 -- be filled at the freeze point, when the record init proc is built, to
11685 -- capture the expression of the rep item (see Build_Record_Init_Proc in
11686 -- Exp_Ch3). Note that it cannot be filled here since aspect evaluations
11687 -- are delayed till the freeze point.
11689 -- The _Relative_Deadline field is present only if a Relative_Deadline
11690 -- pragma appears in the task definition. The expression captures the
11691 -- argument that was present in the pragma, and is used to provide the
11692 -- Relative_Deadline parameter to the call to Create_Task.
11694 -- The _Domain field is present only if the task entity has a
11695 -- Dispatching_Domain rep item (pragma, aspect specification or attribute
11696 -- definition clause). It will be filled at the freeze point, when the
11697 -- record init proc is built, to capture the expression of the rep item
11698 -- (see Build_Record_Init_Proc in Exp_Ch3). Note that it cannot be filled
11699 -- here since aspect evaluations are delayed till the freeze point.
11701 -- When a task is declared, an instance of the task value record is
11702 -- created. The elaboration of this declaration creates the correct bounds
11703 -- for the entry families, and also evaluates the size, priority, and
11704 -- task_Info expressions if needed. The initialization routine for the task
11705 -- type itself then calls Create_Task with appropriate parameters to
11706 -- initialize the value of the Task_Id field.
11708 -- Note: the address of this record is passed as the "Discriminants"
11709 -- parameter for Create_Task. Since Create_Task merely passes this onto the
11710 -- body procedure, it does not matter that it does not quite match the
11711 -- GNARLI model of what is being passed (the record contains more than just
11712 -- the discriminants, but the discriminants can be found from the record
11713 -- value).
11715 -- The Entity_Id for this created record type is placed in the
11716 -- Corresponding_Record_Type field of the associated task type entity.
11718 -- Next we create a procedure specification for the task body procedure:
11720 -- procedure taskB (_Task : access taskV);
11722 -- Note that this must come after the record type declaration, since
11723 -- the spec refers to this type. It turns out that the initialization
11724 -- procedure for the value type references the task body spec, but that's
11725 -- fine, since it won't be generated till the freeze point for the type,
11726 -- which is certainly after the task body spec declaration.
11728 -- Finally, we set the task index value field of the entry attribute in
11729 -- the case of a simple entry.
11731 procedure Expand_N_Task_Type_Declaration (N : Node_Id) is
11732 Loc : constant Source_Ptr := Sloc (N);
11733 TaskId : constant Entity_Id := Defining_Identifier (N);
11734 Tasktyp : constant Entity_Id := Etype (Defining_Identifier (N));
11735 Tasknm : constant Name_Id := Chars (Tasktyp);
11736 Taskdef : constant Node_Id := Task_Definition (N);
11738 Body_Decl : Node_Id;
11739 Cdecls : List_Id;
11740 Decl_Stack : Node_Id;
11741 Decl_SS : Node_Id;
11742 Elab_Decl : Node_Id;
11743 Ent_Stack : Entity_Id;
11744 Proc_Spec : Node_Id;
11745 Rec_Decl : Node_Id;
11746 Rec_Ent : Entity_Id;
11747 Size_Decl : Entity_Id;
11748 Task_Size : Node_Id;
11750 function Get_Relative_Deadline_Pragma (T : Node_Id) return Node_Id;
11751 -- Searches the task definition T for the first occurrence of the pragma
11752 -- Relative Deadline. The caller has ensured that the pragma is present
11753 -- in the task definition. Note that this routine cannot be implemented
11754 -- with the Rep Item chain mechanism since Relative_Deadline pragmas are
11755 -- not chained because their expansion into a procedure call statement
11756 -- would cause a break in the chain.
11758 ----------------------------------
11759 -- Get_Relative_Deadline_Pragma --
11760 ----------------------------------
11762 function Get_Relative_Deadline_Pragma (T : Node_Id) return Node_Id is
11763 N : Node_Id;
11765 begin
11766 N := First (Visible_Declarations (T));
11767 while Present (N) loop
11768 if Nkind (N) = N_Pragma
11769 and then Pragma_Name (N) = Name_Relative_Deadline
11770 then
11771 return N;
11772 end if;
11774 Next (N);
11775 end loop;
11777 N := First (Private_Declarations (T));
11778 while Present (N) loop
11779 if Nkind (N) = N_Pragma
11780 and then Pragma_Name (N) = Name_Relative_Deadline
11781 then
11782 return N;
11783 end if;
11785 Next (N);
11786 end loop;
11788 raise Program_Error;
11789 end Get_Relative_Deadline_Pragma;
11791 -- Start of processing for Expand_N_Task_Type_Declaration
11793 begin
11794 -- If already expanded, nothing to do
11796 if Present (Corresponding_Record_Type (Tasktyp)) then
11797 return;
11798 end if;
11800 -- Here we will do the expansion
11802 Rec_Decl := Build_Corresponding_Record (N, Tasktyp, Loc);
11804 Rec_Ent := Defining_Identifier (Rec_Decl);
11805 Cdecls := Component_Items (Component_List
11806 (Type_Definition (Rec_Decl)));
11808 Qualify_Entity_Names (N);
11810 -- First create the elaboration variable
11812 Elab_Decl :=
11813 Make_Object_Declaration (Loc,
11814 Defining_Identifier =>
11815 Make_Defining_Identifier (Sloc (Tasktyp),
11816 Chars => New_External_Name (Tasknm, 'E')),
11817 Aliased_Present => True,
11818 Object_Definition => New_Occurrence_Of (Standard_Boolean, Loc),
11819 Expression => New_Occurrence_Of (Standard_False, Loc));
11821 Insert_After (N, Elab_Decl);
11823 -- Next create the declaration of the size variable (tasknmZ)
11825 Set_Storage_Size_Variable (Tasktyp,
11826 Make_Defining_Identifier (Sloc (Tasktyp),
11827 Chars => New_External_Name (Tasknm, 'Z')));
11829 if Present (Taskdef)
11830 and then Has_Storage_Size_Pragma (Taskdef)
11831 and then
11832 Is_OK_Static_Expression
11833 (Expression
11834 (First (Pragma_Argument_Associations
11835 (Get_Rep_Pragma (TaskId, Name_Storage_Size)))))
11836 then
11837 Size_Decl :=
11838 Make_Object_Declaration (Loc,
11839 Defining_Identifier => Storage_Size_Variable (Tasktyp),
11840 Object_Definition =>
11841 New_Occurrence_Of (RTE (RE_Size_Type), Loc),
11842 Expression =>
11843 Convert_To (RTE (RE_Size_Type),
11844 Relocate_Node
11845 (Expression (First (Pragma_Argument_Associations
11846 (Get_Rep_Pragma
11847 (TaskId, Name_Storage_Size)))))));
11849 else
11850 Size_Decl :=
11851 Make_Object_Declaration (Loc,
11852 Defining_Identifier => Storage_Size_Variable (Tasktyp),
11853 Object_Definition =>
11854 New_Occurrence_Of (RTE (RE_Size_Type), Loc),
11855 Expression =>
11856 New_Occurrence_Of (RTE (RE_Unspecified_Size), Loc));
11857 end if;
11859 Insert_After (Elab_Decl, Size_Decl);
11861 -- Next build the rest of the corresponding record declaration. This is
11862 -- done last, since the corresponding record initialization procedure
11863 -- will reference the previously created entities.
11865 -- Fill in the component declarations -- first the _Task_Id field
11867 Append_To (Cdecls,
11868 Make_Component_Declaration (Loc,
11869 Defining_Identifier =>
11870 Make_Defining_Identifier (Loc, Name_uTask_Id),
11871 Component_Definition =>
11872 Make_Component_Definition (Loc,
11873 Aliased_Present => False,
11874 Subtype_Indication => New_Occurrence_Of (RTE (RO_ST_Task_Id),
11875 Loc))));
11877 -- Declare static ATCB (that is, created by the expander) if we are
11878 -- using the Restricted run time.
11880 if Restricted_Profile then
11881 Append_To (Cdecls,
11882 Make_Component_Declaration (Loc,
11883 Defining_Identifier =>
11884 Make_Defining_Identifier (Loc, Name_uATCB),
11886 Component_Definition =>
11887 Make_Component_Definition (Loc,
11888 Aliased_Present => True,
11889 Subtype_Indication => Make_Subtype_Indication (Loc,
11890 Subtype_Mark =>
11891 New_Occurrence_Of (RTE (RE_Ada_Task_Control_Block), Loc),
11893 Constraint =>
11894 Make_Index_Or_Discriminant_Constraint (Loc,
11895 Constraints =>
11896 New_List (Make_Integer_Literal (Loc, 0)))))));
11898 end if;
11900 -- Declare static stack (that is, created by the expander) if we are
11901 -- using the Restricted run time on a bare board configuration.
11903 if Restricted_Profile and then Preallocated_Stacks_On_Target then
11905 -- First we need to extract the appropriate stack size
11907 Ent_Stack := Make_Defining_Identifier (Loc, Name_uStack);
11909 if Present (Taskdef) and then Has_Storage_Size_Pragma (Taskdef) then
11910 declare
11911 Expr_N : constant Node_Id :=
11912 Expression (First (
11913 Pragma_Argument_Associations (
11914 Get_Rep_Pragma (TaskId, Name_Storage_Size))));
11915 Etyp : constant Entity_Id := Etype (Expr_N);
11916 P : constant Node_Id := Parent (Expr_N);
11918 begin
11919 -- The stack is defined inside the corresponding record.
11920 -- Therefore if the size of the stack is set by means of
11921 -- a discriminant, we must reference the discriminant of the
11922 -- corresponding record type.
11924 if Nkind (Expr_N) in N_Has_Entity
11925 and then Present (Discriminal_Link (Entity (Expr_N)))
11926 then
11927 Task_Size :=
11928 New_Occurrence_Of
11929 (CR_Discriminant (Discriminal_Link (Entity (Expr_N))),
11930 Loc);
11931 Set_Parent (Task_Size, P);
11932 Set_Etype (Task_Size, Etyp);
11933 Set_Analyzed (Task_Size);
11935 else
11936 Task_Size := New_Copy_Tree (Expr_N);
11937 end if;
11938 end;
11940 else
11941 Task_Size :=
11942 New_Occurrence_Of (RTE (RE_Default_Stack_Size), Loc);
11943 end if;
11945 Decl_Stack := Make_Component_Declaration (Loc,
11946 Defining_Identifier => Ent_Stack,
11948 Component_Definition =>
11949 Make_Component_Definition (Loc,
11950 Aliased_Present => True,
11951 Subtype_Indication => Make_Subtype_Indication (Loc,
11952 Subtype_Mark =>
11953 New_Occurrence_Of (RTE (RE_Storage_Array), Loc),
11955 Constraint =>
11956 Make_Index_Or_Discriminant_Constraint (Loc,
11957 Constraints => New_List (Make_Range (Loc,
11958 Low_Bound => Make_Integer_Literal (Loc, 1),
11959 High_Bound => Convert_To (RTE (RE_Storage_Offset),
11960 Task_Size)))))));
11962 Append_To (Cdecls, Decl_Stack);
11964 -- The appropriate alignment for the stack is ensured by the run-time
11965 -- code in charge of task creation.
11967 end if;
11969 -- Declare a static secondary stack if the conditions for a statically
11970 -- generated stack are met.
11972 if Create_Secondary_Stack_For_Task (TaskId) then
11973 declare
11974 Size_Expr : constant Node_Id :=
11975 Expression (First (
11976 Pragma_Argument_Associations (
11977 Get_Rep_Pragma (TaskId,
11978 Name_Secondary_Stack_Size))));
11980 Stack_Size : Node_Id;
11982 begin
11983 -- The secondary stack is defined inside the corresponding
11984 -- record. Therefore if the size of the stack is set by means
11985 -- of a discriminant, we must reference the discriminant of the
11986 -- corresponding record type.
11988 if Nkind (Size_Expr) in N_Has_Entity
11989 and then Present (Discriminal_Link (Entity (Size_Expr)))
11990 then
11991 Stack_Size :=
11992 New_Occurrence_Of
11993 (CR_Discriminant (Discriminal_Link (Entity (Size_Expr))),
11994 Loc);
11995 Set_Parent (Stack_Size, Parent (Size_Expr));
11996 Set_Etype (Stack_Size, Etype (Size_Expr));
11997 Set_Analyzed (Stack_Size);
11999 else
12000 Stack_Size := New_Copy_Tree (Size_Expr);
12001 end if;
12003 -- Create the secondary stack for the task
12005 Decl_SS :=
12006 Make_Component_Declaration (Loc,
12007 Defining_Identifier =>
12008 Make_Defining_Identifier (Loc, Name_uSecondary_Stack),
12009 Component_Definition =>
12010 Make_Component_Definition (Loc,
12011 Aliased_Present => True,
12012 Subtype_Indication =>
12013 Make_Subtype_Indication (Loc,
12014 Subtype_Mark =>
12015 New_Occurrence_Of (RTE (RE_SS_Stack), Loc),
12016 Constraint =>
12017 Make_Index_Or_Discriminant_Constraint (Loc,
12018 Constraints => New_List (
12019 Convert_To (RTE (RE_Size_Type),
12020 Stack_Size))))));
12022 Append_To (Cdecls, Decl_SS);
12023 end;
12024 end if;
12026 -- Add components for entry families
12028 Collect_Entry_Families (Loc, Cdecls, Size_Decl, Tasktyp);
12030 -- Add the _Priority component if a Interrupt_Priority or Priority rep
12031 -- item is present.
12033 if Has_Rep_Item (TaskId, Name_Priority, Check_Parents => False) then
12034 Append_To (Cdecls,
12035 Make_Component_Declaration (Loc,
12036 Defining_Identifier =>
12037 Make_Defining_Identifier (Loc, Name_uPriority),
12038 Component_Definition =>
12039 Make_Component_Definition (Loc,
12040 Aliased_Present => False,
12041 Subtype_Indication =>
12042 New_Occurrence_Of (Standard_Integer, Loc))));
12043 end if;
12045 -- Add the _Size component if a Storage_Size pragma is present
12047 if Present (Taskdef) and then Has_Storage_Size_Pragma (Taskdef) then
12048 Append_To (Cdecls,
12049 Make_Component_Declaration (Loc,
12050 Defining_Identifier =>
12051 Make_Defining_Identifier (Loc, Name_uSize),
12053 Component_Definition =>
12054 Make_Component_Definition (Loc,
12055 Aliased_Present => False,
12056 Subtype_Indication =>
12057 New_Occurrence_Of (RTE (RE_Size_Type), Loc)),
12059 Expression =>
12060 Convert_To (RTE (RE_Size_Type),
12061 New_Copy_Tree (
12062 Expression (First (
12063 Pragma_Argument_Associations (
12064 Get_Rep_Pragma (TaskId, Name_Storage_Size))))))));
12065 end if;
12067 -- Add the _Secondary_Stack_Size component if a Secondary_Stack_Size
12068 -- pragma is present.
12070 if Has_Rep_Pragma
12071 (TaskId, Name_Secondary_Stack_Size, Check_Parents => False)
12072 then
12073 Append_To (Cdecls,
12074 Make_Component_Declaration (Loc,
12075 Defining_Identifier =>
12076 Make_Defining_Identifier (Loc, Name_uSecondary_Stack_Size),
12078 Component_Definition =>
12079 Make_Component_Definition (Loc,
12080 Aliased_Present => False,
12081 Subtype_Indication =>
12082 New_Occurrence_Of (RTE (RE_Size_Type), Loc))));
12083 end if;
12085 -- Add the _Task_Info component if a Task_Info pragma is present
12087 if Has_Rep_Pragma (TaskId, Name_Task_Info, Check_Parents => False) then
12088 Append_To (Cdecls,
12089 Make_Component_Declaration (Loc,
12090 Defining_Identifier =>
12091 Make_Defining_Identifier (Loc, Name_uTask_Info),
12093 Component_Definition =>
12094 Make_Component_Definition (Loc,
12095 Aliased_Present => False,
12096 Subtype_Indication =>
12097 New_Occurrence_Of (RTE (RE_Task_Info_Type), Loc)),
12099 Expression => New_Copy (
12100 Expression (First (
12101 Pragma_Argument_Associations (
12102 Get_Rep_Pragma
12103 (TaskId, Name_Task_Info, Check_Parents => False)))))));
12104 end if;
12106 -- Add the _CPU component if a CPU rep item is present
12108 if Has_Rep_Item (TaskId, Name_CPU, Check_Parents => False) then
12109 Append_To (Cdecls,
12110 Make_Component_Declaration (Loc,
12111 Defining_Identifier =>
12112 Make_Defining_Identifier (Loc, Name_uCPU),
12114 Component_Definition =>
12115 Make_Component_Definition (Loc,
12116 Aliased_Present => False,
12117 Subtype_Indication =>
12118 New_Occurrence_Of (RTE (RE_CPU_Range), Loc))));
12119 end if;
12121 -- Add the _Relative_Deadline component if a Relative_Deadline pragma is
12122 -- present. If we are using a restricted run time this component will
12123 -- not be added (deadlines are not allowed by the Ravenscar profile),
12124 -- unless the task dispatching policy is EDF (for GNAT_Ravenscar_EDF
12125 -- profile).
12127 if (not Restricted_Profile or else Task_Dispatching_Policy = 'E')
12128 and then Present (Taskdef)
12129 and then Has_Relative_Deadline_Pragma (Taskdef)
12130 then
12131 Append_To (Cdecls,
12132 Make_Component_Declaration (Loc,
12133 Defining_Identifier =>
12134 Make_Defining_Identifier (Loc, Name_uRelative_Deadline),
12136 Component_Definition =>
12137 Make_Component_Definition (Loc,
12138 Aliased_Present => False,
12139 Subtype_Indication =>
12140 New_Occurrence_Of (RTE (RE_Time_Span), Loc)),
12142 Expression =>
12143 Convert_To (RTE (RE_Time_Span),
12144 New_Copy_Tree (
12145 Expression (First (
12146 Pragma_Argument_Associations (
12147 Get_Relative_Deadline_Pragma (Taskdef))))))));
12148 end if;
12150 -- Add the _Dispatching_Domain component if a Dispatching_Domain rep
12151 -- item is present. If we are using a restricted run time this component
12152 -- will not be added (dispatching domains are not allowed by the
12153 -- Ravenscar profile).
12155 if not Restricted_Profile
12156 and then
12157 Has_Rep_Item
12158 (TaskId, Name_Dispatching_Domain, Check_Parents => False)
12159 then
12160 Append_To (Cdecls,
12161 Make_Component_Declaration (Loc,
12162 Defining_Identifier =>
12163 Make_Defining_Identifier (Loc, Name_uDispatching_Domain),
12165 Component_Definition =>
12166 Make_Component_Definition (Loc,
12167 Aliased_Present => False,
12168 Subtype_Indication =>
12169 New_Occurrence_Of
12170 (RTE (RE_Dispatching_Domain_Access), Loc))));
12171 end if;
12173 Insert_After (Size_Decl, Rec_Decl);
12175 -- Analyze the record declaration immediately after construction,
12176 -- because the initialization procedure is needed for single task
12177 -- declarations before the next entity is analyzed.
12179 Analyze (Rec_Decl);
12181 -- Create the declaration of the task body procedure
12183 Proc_Spec := Build_Task_Proc_Specification (Tasktyp);
12184 Body_Decl :=
12185 Make_Subprogram_Declaration (Loc,
12186 Specification => Proc_Spec);
12187 Set_Is_Task_Body_Procedure (Body_Decl);
12189 Insert_After (Rec_Decl, Body_Decl);
12191 -- The subprogram does not comes from source, so we have to indicate the
12192 -- need for debugging information explicitly.
12194 if Comes_From_Source (Original_Node (N)) then
12195 Set_Debug_Info_Needed (Defining_Entity (Proc_Spec));
12196 end if;
12198 -- Ada 2005 (AI-345): Construct the primitive entry wrapper specs before
12199 -- the corresponding record has been frozen.
12201 if Ada_Version >= Ada_2005 then
12202 Build_Wrapper_Specs (Loc, Tasktyp, Rec_Decl);
12203 end if;
12205 -- Ada 2005 (AI-345): We must defer freezing to allow further
12206 -- declaration of primitive subprograms covering task interfaces
12208 if Ada_Version <= Ada_95 then
12210 -- Now we can freeze the corresponding record. This needs manually
12211 -- freezing, since it is really part of the task type, and the task
12212 -- type is frozen at this stage. We of course need the initialization
12213 -- procedure for this corresponding record type and we won't get it
12214 -- in time if we don't freeze now.
12216 declare
12217 L : constant List_Id := Freeze_Entity (Rec_Ent, N);
12218 begin
12219 if Is_Non_Empty_List (L) then
12220 Insert_List_After (Body_Decl, L);
12221 end if;
12222 end;
12223 end if;
12225 -- Complete the expansion of access types to the current task type, if
12226 -- any were declared.
12228 Expand_Previous_Access_Type (Tasktyp);
12230 -- Create wrappers for entries that have contract cases, preconditions
12231 -- and postconditions.
12233 declare
12234 Ent : Entity_Id;
12236 begin
12237 Ent := First_Entity (Tasktyp);
12238 while Present (Ent) loop
12239 if Ekind_In (Ent, E_Entry, E_Entry_Family) then
12240 Build_Contract_Wrapper (Ent, N);
12241 end if;
12243 Next_Entity (Ent);
12244 end loop;
12245 end;
12246 end Expand_N_Task_Type_Declaration;
12248 -------------------------------
12249 -- Expand_N_Timed_Entry_Call --
12250 -------------------------------
12252 -- A timed entry call in normal case is not implemented using ATC mechanism
12253 -- anymore for efficiency reason.
12255 -- select
12256 -- T.E;
12257 -- S1;
12258 -- or
12259 -- delay D;
12260 -- S2;
12261 -- end select;
12263 -- is expanded as follows:
12265 -- 1) When T.E is a task entry_call;
12267 -- declare
12268 -- B : Boolean;
12269 -- X : Task_Entry_Index := <entry index>;
12270 -- DX : Duration := To_Duration (D);
12271 -- M : Delay_Mode := <discriminant>;
12272 -- P : parms := (parm, parm, parm);
12274 -- begin
12275 -- Timed_Protected_Entry_Call
12276 -- (<acceptor-task>, X, P'Address, DX, M, B);
12277 -- if B then
12278 -- S1;
12279 -- else
12280 -- S2;
12281 -- end if;
12282 -- end;
12284 -- 2) When T.E is a protected entry_call;
12286 -- declare
12287 -- B : Boolean;
12288 -- X : Protected_Entry_Index := <entry index>;
12289 -- DX : Duration := To_Duration (D);
12290 -- M : Delay_Mode := <discriminant>;
12291 -- P : parms := (parm, parm, parm);
12293 -- begin
12294 -- Timed_Protected_Entry_Call
12295 -- (<object>'unchecked_access, X, P'Address, DX, M, B);
12296 -- if B then
12297 -- S1;
12298 -- else
12299 -- S2;
12300 -- end if;
12301 -- end;
12303 -- 3) Ada 2005 (AI-345): When T.E is a dispatching procedure call, there
12304 -- is no delay and the triggering statements are executed. We first
12305 -- determine the kind of the triggering call and then execute a
12306 -- synchronized operation or a direct call.
12308 -- declare
12309 -- B : Boolean := False;
12310 -- C : Ada.Tags.Prim_Op_Kind;
12311 -- DX : Duration := To_Duration (D)
12312 -- K : Ada.Tags.Tagged_Kind :=
12313 -- Ada.Tags.Get_Tagged_Kind (Ada.Tags.Tag (<object>));
12314 -- M : Integer :=...;
12315 -- P : Parameters := (Param1 .. ParamN);
12316 -- S : Integer;
12318 -- begin
12319 -- if K = Ada.Tags.TK_Limited_Tagged
12320 -- or else K = Ada.Tags.TK_Tagged
12321 -- then
12322 -- <dispatching-call>;
12323 -- B := True;
12325 -- else
12326 -- S :=
12327 -- Ada.Tags.Get_Offset_Index
12328 -- (Ada.Tags.Tag (<object>), DT_Position (<dispatching-call>));
12330 -- _Disp_Timed_Select (<object>, S, P'Address, DX, M, C, B);
12332 -- if C = POK_Protected_Entry
12333 -- or else C = POK_Task_Entry
12334 -- then
12335 -- Param1 := P.Param1;
12336 -- ...
12337 -- ParamN := P.ParamN;
12338 -- end if;
12340 -- if B then
12341 -- if C = POK_Procedure
12342 -- or else C = POK_Protected_Procedure
12343 -- or else C = POK_Task_Procedure
12344 -- then
12345 -- <dispatching-call>;
12346 -- end if;
12347 -- end if;
12348 -- end if;
12350 -- if B then
12351 -- <triggering-statements>
12352 -- else
12353 -- <timed-statements>
12354 -- end if;
12355 -- end;
12357 -- The triggering statement and the sequence of timed statements have not
12358 -- been analyzed yet (see Analyzed_Timed_Entry_Call), but they may contain
12359 -- global references if within an instantiation.
12361 procedure Expand_N_Timed_Entry_Call (N : Node_Id) is
12362 Loc : constant Source_Ptr := Sloc (N);
12364 Actuals : List_Id;
12365 Blk_Typ : Entity_Id;
12366 Call : Node_Id;
12367 Call_Ent : Entity_Id;
12368 Conc_Typ_Stmts : List_Id;
12369 Concval : Node_Id := Empty; -- init to avoid warning
12370 D_Alt : constant Node_Id := Delay_Alternative (N);
12371 D_Conv : Node_Id;
12372 D_Disc : Node_Id;
12373 D_Stat : Node_Id := Delay_Statement (D_Alt);
12374 D_Stats : List_Id;
12375 D_Type : Entity_Id;
12376 Decls : List_Id;
12377 Dummy : Node_Id;
12378 E_Alt : constant Node_Id := Entry_Call_Alternative (N);
12379 E_Call : Node_Id := Entry_Call_Statement (E_Alt);
12380 E_Stats : List_Id;
12381 Ename : Node_Id;
12382 Formals : List_Id;
12383 Index : Node_Id;
12384 Is_Disp_Select : Boolean;
12385 Lim_Typ_Stmts : List_Id;
12386 N_Stats : List_Id;
12387 Obj : Entity_Id;
12388 Param : Node_Id;
12389 Params : List_Id;
12390 Stmt : Node_Id;
12391 Stmts : List_Id;
12392 Unpack : List_Id;
12394 B : Entity_Id; -- Call status flag
12395 C : Entity_Id; -- Call kind
12396 D : Entity_Id; -- Delay
12397 K : Entity_Id; -- Tagged kind
12398 M : Entity_Id; -- Delay mode
12399 P : Entity_Id; -- Parameter block
12400 S : Entity_Id; -- Primitive operation slot
12402 -- Start of processing for Expand_N_Timed_Entry_Call
12404 begin
12405 -- Under the Ravenscar profile, timed entry calls are excluded. An error
12406 -- was already reported on spec, so do not attempt to expand the call.
12408 if Restriction_Active (No_Select_Statements) then
12409 return;
12410 end if;
12412 Process_Statements_For_Controlled_Objects (E_Alt);
12413 Process_Statements_For_Controlled_Objects (D_Alt);
12415 Ensure_Statement_Present (Sloc (D_Stat), D_Alt);
12417 -- Retrieve E_Stats and D_Stats now because the finalization machinery
12418 -- may wrap them in blocks.
12420 E_Stats := Statements (E_Alt);
12421 D_Stats := Statements (D_Alt);
12423 -- The arguments in the call may require dynamic allocation, and the
12424 -- call statement may have been transformed into a block. The block
12425 -- may contain additional declarations for internal entities, and the
12426 -- original call is found by sequential search.
12428 if Nkind (E_Call) = N_Block_Statement then
12429 E_Call := First (Statements (Handled_Statement_Sequence (E_Call)));
12430 while not Nkind_In (E_Call, N_Procedure_Call_Statement,
12431 N_Entry_Call_Statement)
12432 loop
12433 Next (E_Call);
12434 end loop;
12435 end if;
12437 Is_Disp_Select :=
12438 Ada_Version >= Ada_2005
12439 and then Nkind (E_Call) = N_Procedure_Call_Statement;
12441 if Is_Disp_Select then
12442 Extract_Dispatching_Call (E_Call, Call_Ent, Obj, Actuals, Formals);
12443 Decls := New_List;
12445 Stmts := New_List;
12447 -- Generate:
12448 -- B : Boolean := False;
12450 B := Build_B (Loc, Decls);
12452 -- Generate:
12453 -- C : Ada.Tags.Prim_Op_Kind;
12455 C := Build_C (Loc, Decls);
12457 -- Because the analysis of all statements was disabled, manually
12458 -- analyze the delay statement.
12460 Analyze (D_Stat);
12461 D_Stat := Original_Node (D_Stat);
12463 else
12464 -- Build an entry call using Simple_Entry_Call
12466 Extract_Entry (E_Call, Concval, Ename, Index);
12467 Build_Simple_Entry_Call (E_Call, Concval, Ename, Index);
12469 Decls := Declarations (E_Call);
12470 Stmts := Statements (Handled_Statement_Sequence (E_Call));
12472 if No (Decls) then
12473 Decls := New_List;
12474 end if;
12476 -- Generate:
12477 -- B : Boolean;
12479 B := Make_Defining_Identifier (Loc, Name_uB);
12481 Prepend_To (Decls,
12482 Make_Object_Declaration (Loc,
12483 Defining_Identifier => B,
12484 Object_Definition =>
12485 New_Occurrence_Of (Standard_Boolean, Loc)));
12486 end if;
12488 -- Duration and mode processing
12490 D_Type := Base_Type (Etype (Expression (D_Stat)));
12492 -- Use the type of the delay expression (Calendar or Real_Time) to
12493 -- generate the appropriate conversion.
12495 if Nkind (D_Stat) = N_Delay_Relative_Statement then
12496 D_Disc := Make_Integer_Literal (Loc, 0);
12497 D_Conv := Relocate_Node (Expression (D_Stat));
12499 elsif Is_RTE (D_Type, RO_CA_Time) then
12500 D_Disc := Make_Integer_Literal (Loc, 1);
12501 D_Conv :=
12502 Make_Function_Call (Loc,
12503 Name => New_Occurrence_Of (RTE (RO_CA_To_Duration), Loc),
12504 Parameter_Associations =>
12505 New_List (New_Copy (Expression (D_Stat))));
12507 else pragma Assert (Is_RTE (D_Type, RO_RT_Time));
12508 D_Disc := Make_Integer_Literal (Loc, 2);
12509 D_Conv :=
12510 Make_Function_Call (Loc,
12511 Name => New_Occurrence_Of (RTE (RO_RT_To_Duration), Loc),
12512 Parameter_Associations =>
12513 New_List (New_Copy (Expression (D_Stat))));
12514 end if;
12516 D := Make_Temporary (Loc, 'D');
12518 -- Generate:
12519 -- D : Duration;
12521 Append_To (Decls,
12522 Make_Object_Declaration (Loc,
12523 Defining_Identifier => D,
12524 Object_Definition => New_Occurrence_Of (Standard_Duration, Loc)));
12526 M := Make_Temporary (Loc, 'M');
12528 -- Generate:
12529 -- M : Integer := (0 | 1 | 2);
12531 Append_To (Decls,
12532 Make_Object_Declaration (Loc,
12533 Defining_Identifier => M,
12534 Object_Definition => New_Occurrence_Of (Standard_Integer, Loc),
12535 Expression => D_Disc));
12537 -- Do the assignment at this stage only because the evaluation of the
12538 -- expression must not occur before (see ACVC C97302A).
12540 Append_To (Stmts,
12541 Make_Assignment_Statement (Loc,
12542 Name => New_Occurrence_Of (D, Loc),
12543 Expression => D_Conv));
12545 -- Parameter block processing
12547 -- Manually create the parameter block for dispatching calls. In the
12548 -- case of entries, the block has already been created during the call
12549 -- to Build_Simple_Entry_Call.
12551 if Is_Disp_Select then
12553 -- Tagged kind processing, generate:
12554 -- K : Ada.Tags.Tagged_Kind :=
12555 -- Ada.Tags.Get_Tagged_Kind (Ada.Tags.Tag <object>));
12557 K := Build_K (Loc, Decls, Obj);
12559 Blk_Typ := Build_Parameter_Block (Loc, Actuals, Formals, Decls);
12560 P :=
12561 Parameter_Block_Pack (Loc, Blk_Typ, Actuals, Formals, Decls, Stmts);
12563 -- Dispatch table slot processing, generate:
12564 -- S : Integer;
12566 S := Build_S (Loc, Decls);
12568 -- Generate:
12569 -- S := Ada.Tags.Get_Offset_Index
12570 -- (Ada.Tags.Tag (<object>), DT_Position (Call_Ent));
12572 Conc_Typ_Stmts :=
12573 New_List (Build_S_Assignment (Loc, S, Obj, Call_Ent));
12575 -- Generate:
12576 -- _Disp_Timed_Select (<object>, S, P'Address, D, M, C, B);
12578 -- where Obj is the controlling formal parameter, S is the dispatch
12579 -- table slot number of the dispatching operation, P is the wrapped
12580 -- parameter block, D is the duration, M is the duration mode, C is
12581 -- the call kind and B is the call status.
12583 Params := New_List;
12585 Append_To (Params, New_Copy_Tree (Obj));
12586 Append_To (Params, New_Occurrence_Of (S, Loc));
12587 Append_To (Params,
12588 Make_Attribute_Reference (Loc,
12589 Prefix => New_Occurrence_Of (P, Loc),
12590 Attribute_Name => Name_Address));
12591 Append_To (Params, New_Occurrence_Of (D, Loc));
12592 Append_To (Params, New_Occurrence_Of (M, Loc));
12593 Append_To (Params, New_Occurrence_Of (C, Loc));
12594 Append_To (Params, New_Occurrence_Of (B, Loc));
12596 Append_To (Conc_Typ_Stmts,
12597 Make_Procedure_Call_Statement (Loc,
12598 Name =>
12599 New_Occurrence_Of
12600 (Find_Prim_Op
12601 (Etype (Etype (Obj)), Name_uDisp_Timed_Select), Loc),
12602 Parameter_Associations => Params));
12604 -- Generate:
12605 -- if C = POK_Protected_Entry
12606 -- or else C = POK_Task_Entry
12607 -- then
12608 -- Param1 := P.Param1;
12609 -- ...
12610 -- ParamN := P.ParamN;
12611 -- end if;
12613 Unpack := Parameter_Block_Unpack (Loc, P, Actuals, Formals);
12615 -- Generate the if statement only when the packed parameters need
12616 -- explicit assignments to their corresponding actuals.
12618 if Present (Unpack) then
12619 Append_To (Conc_Typ_Stmts,
12620 Make_Implicit_If_Statement (N,
12622 Condition =>
12623 Make_Or_Else (Loc,
12624 Left_Opnd =>
12625 Make_Op_Eq (Loc,
12626 Left_Opnd => New_Occurrence_Of (C, Loc),
12627 Right_Opnd =>
12628 New_Occurrence_Of
12629 (RTE (RE_POK_Protected_Entry), Loc)),
12631 Right_Opnd =>
12632 Make_Op_Eq (Loc,
12633 Left_Opnd => New_Occurrence_Of (C, Loc),
12634 Right_Opnd =>
12635 New_Occurrence_Of (RTE (RE_POK_Task_Entry), Loc))),
12637 Then_Statements => Unpack));
12638 end if;
12640 -- Generate:
12642 -- if B then
12643 -- if C = POK_Procedure
12644 -- or else C = POK_Protected_Procedure
12645 -- or else C = POK_Task_Procedure
12646 -- then
12647 -- <dispatching-call>
12648 -- end if;
12649 -- end if;
12651 N_Stats := New_List (
12652 Make_Implicit_If_Statement (N,
12653 Condition =>
12654 Make_Or_Else (Loc,
12655 Left_Opnd =>
12656 Make_Op_Eq (Loc,
12657 Left_Opnd => New_Occurrence_Of (C, Loc),
12658 Right_Opnd =>
12659 New_Occurrence_Of (RTE (RE_POK_Procedure), Loc)),
12661 Right_Opnd =>
12662 Make_Or_Else (Loc,
12663 Left_Opnd =>
12664 Make_Op_Eq (Loc,
12665 Left_Opnd => New_Occurrence_Of (C, Loc),
12666 Right_Opnd =>
12667 New_Occurrence_Of (RTE (
12668 RE_POK_Protected_Procedure), Loc)),
12669 Right_Opnd =>
12670 Make_Op_Eq (Loc,
12671 Left_Opnd => New_Occurrence_Of (C, Loc),
12672 Right_Opnd =>
12673 New_Occurrence_Of
12674 (RTE (RE_POK_Task_Procedure), Loc)))),
12676 Then_Statements => New_List (E_Call)));
12678 Append_To (Conc_Typ_Stmts,
12679 Make_Implicit_If_Statement (N,
12680 Condition => New_Occurrence_Of (B, Loc),
12681 Then_Statements => N_Stats));
12683 -- Generate:
12684 -- <dispatching-call>;
12685 -- B := True;
12687 Lim_Typ_Stmts :=
12688 New_List (New_Copy_Tree (E_Call),
12689 Make_Assignment_Statement (Loc,
12690 Name => New_Occurrence_Of (B, Loc),
12691 Expression => New_Occurrence_Of (Standard_True, Loc)));
12693 -- Generate:
12694 -- if K = Ada.Tags.TK_Limited_Tagged
12695 -- or else K = Ada.Tags.TK_Tagged
12696 -- then
12697 -- Lim_Typ_Stmts
12698 -- else
12699 -- Conc_Typ_Stmts
12700 -- end if;
12702 Append_To (Stmts,
12703 Make_Implicit_If_Statement (N,
12704 Condition => Build_Dispatching_Tag_Check (K, N),
12705 Then_Statements => Lim_Typ_Stmts,
12706 Else_Statements => Conc_Typ_Stmts));
12708 -- Generate:
12710 -- if B then
12711 -- <triggering-statements>
12712 -- else
12713 -- <timed-statements>
12714 -- end if;
12716 Append_To (Stmts,
12717 Make_Implicit_If_Statement (N,
12718 Condition => New_Occurrence_Of (B, Loc),
12719 Then_Statements => E_Stats,
12720 Else_Statements => D_Stats));
12722 else
12723 -- Simple case of a nondispatching trigger. Skip assignments to
12724 -- temporaries created for in-out parameters.
12726 -- This makes unwarranted assumptions about the shape of the expanded
12727 -- tree for the call, and should be cleaned up ???
12729 Stmt := First (Stmts);
12730 while Nkind (Stmt) /= N_Procedure_Call_Statement loop
12731 Next (Stmt);
12732 end loop;
12734 -- Do the assignment at this stage only because the evaluation
12735 -- of the expression must not occur before (see ACVC C97302A).
12737 Insert_Before (Stmt,
12738 Make_Assignment_Statement (Loc,
12739 Name => New_Occurrence_Of (D, Loc),
12740 Expression => D_Conv));
12742 Call := Stmt;
12743 Params := Parameter_Associations (Call);
12745 -- For a protected type, we build a Timed_Protected_Entry_Call
12747 if Is_Protected_Type (Etype (Concval)) then
12749 -- Create a new call statement
12751 Param := First (Params);
12752 while Present (Param)
12753 and then not Is_RTE (Etype (Param), RE_Call_Modes)
12754 loop
12755 Next (Param);
12756 end loop;
12758 Dummy := Remove_Next (Next (Param));
12760 -- Remove garbage is following the Cancel_Param if present
12762 Dummy := Next (Param);
12764 -- Remove the mode of the Protected_Entry_Call call, then remove
12765 -- the Communication_Block of the Protected_Entry_Call call, and
12766 -- finally add Duration and a Delay_Mode parameter
12768 pragma Assert (Present (Param));
12769 Rewrite (Param, New_Occurrence_Of (D, Loc));
12771 Rewrite (Dummy, New_Occurrence_Of (M, Loc));
12773 -- Add a Boolean flag for successful entry call
12775 Append_To (Params, New_Occurrence_Of (B, Loc));
12777 case Corresponding_Runtime_Package (Etype (Concval)) is
12778 when System_Tasking_Protected_Objects_Entries =>
12779 Rewrite (Call,
12780 Make_Procedure_Call_Statement (Loc,
12781 Name =>
12782 New_Occurrence_Of
12783 (RTE (RE_Timed_Protected_Entry_Call), Loc),
12784 Parameter_Associations => Params));
12786 when others =>
12787 raise Program_Error;
12788 end case;
12790 -- For the task case, build a Timed_Task_Entry_Call
12792 else
12793 -- Create a new call statement
12795 Append_To (Params, New_Occurrence_Of (D, Loc));
12796 Append_To (Params, New_Occurrence_Of (M, Loc));
12797 Append_To (Params, New_Occurrence_Of (B, Loc));
12799 Rewrite (Call,
12800 Make_Procedure_Call_Statement (Loc,
12801 Name =>
12802 New_Occurrence_Of (RTE (RE_Timed_Task_Entry_Call), Loc),
12803 Parameter_Associations => Params));
12804 end if;
12806 Append_To (Stmts,
12807 Make_Implicit_If_Statement (N,
12808 Condition => New_Occurrence_Of (B, Loc),
12809 Then_Statements => E_Stats,
12810 Else_Statements => D_Stats));
12811 end if;
12813 Rewrite (N,
12814 Make_Block_Statement (Loc,
12815 Declarations => Decls,
12816 Handled_Statement_Sequence =>
12817 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
12819 Analyze (N);
12820 end Expand_N_Timed_Entry_Call;
12822 ----------------------------------------
12823 -- Expand_Protected_Body_Declarations --
12824 ----------------------------------------
12826 procedure Expand_Protected_Body_Declarations
12827 (N : Node_Id;
12828 Spec_Id : Entity_Id)
12830 begin
12831 if No_Run_Time_Mode then
12832 Error_Msg_CRT ("protected body", N);
12833 return;
12835 elsif Expander_Active then
12837 -- Associate discriminals with the first subprogram or entry body to
12838 -- be expanded.
12840 if Present (First_Protected_Operation (Declarations (N))) then
12841 Set_Discriminals (Parent (Spec_Id));
12842 end if;
12843 end if;
12844 end Expand_Protected_Body_Declarations;
12846 -------------------------
12847 -- External_Subprogram --
12848 -------------------------
12850 function External_Subprogram (E : Entity_Id) return Entity_Id is
12851 Subp : constant Entity_Id := Protected_Body_Subprogram (E);
12853 begin
12854 -- The internal and external subprograms follow each other on the entity
12855 -- chain. Note that previously private operations had no separate
12856 -- external subprogram. We now create one in all cases, because a
12857 -- private operation may actually appear in an external call, through
12858 -- a 'Access reference used for a callback.
12860 -- If the operation is a function that returns an anonymous access type,
12861 -- the corresponding itype appears before the operation, and must be
12862 -- skipped.
12864 -- This mechanism is fragile, there should be a real link between the
12865 -- two versions of the operation, but there is no place to put it ???
12867 if Is_Access_Type (Next_Entity (Subp)) then
12868 return Next_Entity (Next_Entity (Subp));
12869 else
12870 return Next_Entity (Subp);
12871 end if;
12872 end External_Subprogram;
12874 ------------------------------
12875 -- Extract_Dispatching_Call --
12876 ------------------------------
12878 procedure Extract_Dispatching_Call
12879 (N : Node_Id;
12880 Call_Ent : out Entity_Id;
12881 Object : out Entity_Id;
12882 Actuals : out List_Id;
12883 Formals : out List_Id)
12885 Call_Nam : Node_Id;
12887 begin
12888 pragma Assert (Nkind (N) = N_Procedure_Call_Statement);
12890 if Present (Original_Node (N)) then
12891 Call_Nam := Name (Original_Node (N));
12892 else
12893 Call_Nam := Name (N);
12894 end if;
12896 -- Retrieve the name of the dispatching procedure. It contains the
12897 -- dispatch table slot number.
12899 loop
12900 case Nkind (Call_Nam) is
12901 when N_Identifier =>
12902 exit;
12904 when N_Selected_Component =>
12905 Call_Nam := Selector_Name (Call_Nam);
12907 when others =>
12908 raise Program_Error;
12909 end case;
12910 end loop;
12912 Actuals := Parameter_Associations (N);
12913 Call_Ent := Entity (Call_Nam);
12914 Formals := Parameter_Specifications (Parent (Call_Ent));
12915 Object := First (Actuals);
12917 if Present (Original_Node (Object)) then
12918 Object := Original_Node (Object);
12919 end if;
12921 -- If the type of the dispatching object is an access type then return
12922 -- an explicit dereference of a copy of the object, and note that this
12923 -- is the controlling actual of the call.
12925 if Is_Access_Type (Etype (Object)) then
12926 Object :=
12927 Make_Explicit_Dereference (Sloc (N), New_Copy_Tree (Object));
12928 Analyze (Object);
12929 Set_Is_Controlling_Actual (Object);
12930 end if;
12931 end Extract_Dispatching_Call;
12933 -------------------
12934 -- Extract_Entry --
12935 -------------------
12937 procedure Extract_Entry
12938 (N : Node_Id;
12939 Concval : out Node_Id;
12940 Ename : out Node_Id;
12941 Index : out Node_Id)
12943 Nam : constant Node_Id := Name (N);
12945 begin
12946 -- For a simple entry, the name is a selected component, with the
12947 -- prefix being the task value, and the selector being the entry.
12949 if Nkind (Nam) = N_Selected_Component then
12950 Concval := Prefix (Nam);
12951 Ename := Selector_Name (Nam);
12952 Index := Empty;
12954 -- For a member of an entry family, the name is an indexed component
12955 -- where the prefix is a selected component, whose prefix in turn is
12956 -- the task value, and whose selector is the entry family. The single
12957 -- expression in the expressions list of the indexed component is the
12958 -- subscript for the family.
12960 else pragma Assert (Nkind (Nam) = N_Indexed_Component);
12961 Concval := Prefix (Prefix (Nam));
12962 Ename := Selector_Name (Prefix (Nam));
12963 Index := First (Expressions (Nam));
12964 end if;
12966 -- Through indirection, the type may actually be a limited view of a
12967 -- concurrent type. When compiling a call, the non-limited view of the
12968 -- type is visible.
12970 if From_Limited_With (Etype (Concval)) then
12971 Set_Etype (Concval, Non_Limited_View (Etype (Concval)));
12972 end if;
12973 end Extract_Entry;
12975 -------------------
12976 -- Family_Offset --
12977 -------------------
12979 function Family_Offset
12980 (Loc : Source_Ptr;
12981 Hi : Node_Id;
12982 Lo : Node_Id;
12983 Ttyp : Entity_Id;
12984 Cap : Boolean) return Node_Id
12986 Ityp : Entity_Id;
12987 Real_Hi : Node_Id;
12988 Real_Lo : Node_Id;
12990 function Convert_Discriminant_Ref (Bound : Node_Id) return Node_Id;
12991 -- If one of the bounds is a reference to a discriminant, replace with
12992 -- corresponding discriminal of type. Within the body of a task retrieve
12993 -- the renamed discriminant by simple visibility, using its generated
12994 -- name. Within a protected object, find the original discriminant and
12995 -- replace it with the discriminal of the current protected operation.
12997 ------------------------------
12998 -- Convert_Discriminant_Ref --
12999 ------------------------------
13001 function Convert_Discriminant_Ref (Bound : Node_Id) return Node_Id is
13002 Loc : constant Source_Ptr := Sloc (Bound);
13003 B : Node_Id;
13004 D : Entity_Id;
13006 begin
13007 if Is_Entity_Name (Bound)
13008 and then Ekind (Entity (Bound)) = E_Discriminant
13009 then
13010 if Is_Task_Type (Ttyp) and then Has_Completion (Ttyp) then
13011 B := Make_Identifier (Loc, Chars (Entity (Bound)));
13012 Find_Direct_Name (B);
13014 elsif Is_Protected_Type (Ttyp) then
13015 D := First_Discriminant (Ttyp);
13016 while Chars (D) /= Chars (Entity (Bound)) loop
13017 Next_Discriminant (D);
13018 end loop;
13020 B := New_Occurrence_Of (Discriminal (D), Loc);
13022 else
13023 B := New_Occurrence_Of (Discriminal (Entity (Bound)), Loc);
13024 end if;
13026 elsif Nkind (Bound) = N_Attribute_Reference then
13027 return Bound;
13029 else
13030 B := New_Copy_Tree (Bound);
13031 end if;
13033 return
13034 Make_Attribute_Reference (Loc,
13035 Attribute_Name => Name_Pos,
13036 Prefix => New_Occurrence_Of (Etype (Bound), Loc),
13037 Expressions => New_List (B));
13038 end Convert_Discriminant_Ref;
13040 -- Start of processing for Family_Offset
13042 begin
13043 Real_Hi := Convert_Discriminant_Ref (Hi);
13044 Real_Lo := Convert_Discriminant_Ref (Lo);
13046 if Cap then
13047 if Is_Task_Type (Ttyp) then
13048 Ityp := RTE (RE_Task_Entry_Index);
13049 else
13050 Ityp := RTE (RE_Protected_Entry_Index);
13051 end if;
13053 Real_Hi :=
13054 Make_Attribute_Reference (Loc,
13055 Prefix => New_Occurrence_Of (Ityp, Loc),
13056 Attribute_Name => Name_Min,
13057 Expressions => New_List (
13058 Real_Hi,
13059 Make_Integer_Literal (Loc, Entry_Family_Bound - 1)));
13061 Real_Lo :=
13062 Make_Attribute_Reference (Loc,
13063 Prefix => New_Occurrence_Of (Ityp, Loc),
13064 Attribute_Name => Name_Max,
13065 Expressions => New_List (
13066 Real_Lo,
13067 Make_Integer_Literal (Loc, -Entry_Family_Bound)));
13068 end if;
13070 return Make_Op_Subtract (Loc, Real_Hi, Real_Lo);
13071 end Family_Offset;
13073 -----------------
13074 -- Family_Size --
13075 -----------------
13077 function Family_Size
13078 (Loc : Source_Ptr;
13079 Hi : Node_Id;
13080 Lo : Node_Id;
13081 Ttyp : Entity_Id;
13082 Cap : Boolean) return Node_Id
13084 Ityp : Entity_Id;
13086 begin
13087 if Is_Task_Type (Ttyp) then
13088 Ityp := RTE (RE_Task_Entry_Index);
13089 else
13090 Ityp := RTE (RE_Protected_Entry_Index);
13091 end if;
13093 return
13094 Make_Attribute_Reference (Loc,
13095 Prefix => New_Occurrence_Of (Ityp, Loc),
13096 Attribute_Name => Name_Max,
13097 Expressions => New_List (
13098 Make_Op_Add (Loc,
13099 Left_Opnd => Family_Offset (Loc, Hi, Lo, Ttyp, Cap),
13100 Right_Opnd => Make_Integer_Literal (Loc, 1)),
13101 Make_Integer_Literal (Loc, 0)));
13102 end Family_Size;
13104 ----------------------------
13105 -- Find_Enclosing_Context --
13106 ----------------------------
13108 procedure Find_Enclosing_Context
13109 (N : Node_Id;
13110 Context : out Node_Id;
13111 Context_Id : out Entity_Id;
13112 Context_Decls : out List_Id)
13114 begin
13115 -- Traverse the parent chain looking for an enclosing body, block,
13116 -- package or return statement.
13118 Context := Parent (N);
13119 while Present (Context) loop
13120 if Nkind_In (Context, N_Entry_Body,
13121 N_Extended_Return_Statement,
13122 N_Package_Body,
13123 N_Package_Declaration,
13124 N_Subprogram_Body,
13125 N_Task_Body)
13126 then
13127 exit;
13129 -- Do not consider block created to protect a list of statements with
13130 -- an Abort_Defer / Abort_Undefer_Direct pair.
13132 elsif Nkind (Context) = N_Block_Statement
13133 and then not Is_Abort_Block (Context)
13134 then
13135 exit;
13136 end if;
13138 Context := Parent (Context);
13139 end loop;
13141 pragma Assert (Present (Context));
13143 -- Extract the constituents of the context
13145 if Nkind (Context) = N_Extended_Return_Statement then
13146 Context_Decls := Return_Object_Declarations (Context);
13147 Context_Id := Return_Statement_Entity (Context);
13149 -- Package declarations and bodies use a common library-level activation
13150 -- chain or task master, therefore return the package declaration as the
13151 -- proper carrier for the appropriate flag.
13153 elsif Nkind (Context) = N_Package_Body then
13154 Context_Decls := Declarations (Context);
13155 Context_Id := Corresponding_Spec (Context);
13156 Context := Parent (Context_Id);
13158 if Nkind (Context) = N_Defining_Program_Unit_Name then
13159 Context := Parent (Parent (Context));
13160 else
13161 Context := Parent (Context);
13162 end if;
13164 elsif Nkind (Context) = N_Package_Declaration then
13165 Context_Decls := Visible_Declarations (Specification (Context));
13166 Context_Id := Defining_Unit_Name (Specification (Context));
13168 if Nkind (Context_Id) = N_Defining_Program_Unit_Name then
13169 Context_Id := Defining_Identifier (Context_Id);
13170 end if;
13172 else
13173 if Nkind (Context) = N_Block_Statement then
13174 Context_Id := Entity (Identifier (Context));
13176 elsif Nkind (Context) = N_Entry_Body then
13177 Context_Id := Defining_Identifier (Context);
13179 elsif Nkind (Context) = N_Subprogram_Body then
13180 if Present (Corresponding_Spec (Context)) then
13181 Context_Id := Corresponding_Spec (Context);
13182 else
13183 Context_Id := Defining_Unit_Name (Specification (Context));
13185 if Nkind (Context_Id) = N_Defining_Program_Unit_Name then
13186 Context_Id := Defining_Identifier (Context_Id);
13187 end if;
13188 end if;
13190 elsif Nkind (Context) = N_Task_Body then
13191 Context_Id := Corresponding_Spec (Context);
13193 else
13194 raise Program_Error;
13195 end if;
13197 Context_Decls := Declarations (Context);
13198 end if;
13200 pragma Assert (Present (Context_Id));
13201 pragma Assert (Present (Context_Decls));
13202 end Find_Enclosing_Context;
13204 -----------------------
13205 -- Find_Master_Scope --
13206 -----------------------
13208 function Find_Master_Scope (E : Entity_Id) return Entity_Id is
13209 S : Entity_Id;
13211 begin
13212 -- In Ada 2005, the master is the innermost enclosing scope that is not
13213 -- transient. If the enclosing block is the rewriting of a call or the
13214 -- scope is an extended return statement this is valid master. The
13215 -- master in an extended return is only used within the return, and is
13216 -- subsequently overwritten in Move_Activation_Chain, but it must exist
13217 -- now before that overwriting occurs.
13219 S := Scope (E);
13221 if Ada_Version >= Ada_2005 then
13222 while Is_Internal (S) loop
13223 if Nkind (Parent (S)) = N_Block_Statement
13224 and then
13225 Nkind (Original_Node (Parent (S))) = N_Procedure_Call_Statement
13226 then
13227 exit;
13229 elsif Ekind (S) = E_Return_Statement then
13230 exit;
13232 else
13233 S := Scope (S);
13234 end if;
13235 end loop;
13236 end if;
13238 return S;
13239 end Find_Master_Scope;
13241 -------------------------------
13242 -- First_Protected_Operation --
13243 -------------------------------
13245 function First_Protected_Operation (D : List_Id) return Node_Id is
13246 First_Op : Node_Id;
13248 begin
13249 First_Op := First (D);
13250 while Present (First_Op)
13251 and then not Nkind_In (First_Op, N_Subprogram_Body, N_Entry_Body)
13252 loop
13253 Next (First_Op);
13254 end loop;
13256 return First_Op;
13257 end First_Protected_Operation;
13259 ---------------------------------------
13260 -- Install_Private_Data_Declarations --
13261 ---------------------------------------
13263 procedure Install_Private_Data_Declarations
13264 (Loc : Source_Ptr;
13265 Spec_Id : Entity_Id;
13266 Conc_Typ : Entity_Id;
13267 Body_Nod : Node_Id;
13268 Decls : List_Id;
13269 Barrier : Boolean := False;
13270 Family : Boolean := False)
13272 Is_Protected : constant Boolean := Is_Protected_Type (Conc_Typ);
13273 Decl : Node_Id;
13274 Def : Node_Id;
13275 Insert_Node : Node_Id := Empty;
13276 Obj_Ent : Entity_Id;
13278 procedure Add (Decl : Node_Id);
13279 -- Add a single declaration after Insert_Node. If this is the first
13280 -- addition, Decl is added to the front of Decls and it becomes the
13281 -- insertion node.
13283 function Replace_Bound (Bound : Node_Id) return Node_Id;
13284 -- The bounds of an entry index may depend on discriminants, create a
13285 -- reference to the corresponding prival. Otherwise return a duplicate
13286 -- of the original bound.
13288 ---------
13289 -- Add --
13290 ---------
13292 procedure Add (Decl : Node_Id) is
13293 begin
13294 if No (Insert_Node) then
13295 Prepend_To (Decls, Decl);
13296 else
13297 Insert_After (Insert_Node, Decl);
13298 end if;
13300 Insert_Node := Decl;
13301 end Add;
13303 --------------------------
13304 -- Replace_Discriminant --
13305 --------------------------
13307 function Replace_Bound (Bound : Node_Id) return Node_Id is
13308 begin
13309 if Nkind (Bound) = N_Identifier
13310 and then Is_Discriminal (Entity (Bound))
13311 then
13312 return Make_Identifier (Loc, Chars (Entity (Bound)));
13313 else
13314 return Duplicate_Subexpr (Bound);
13315 end if;
13316 end Replace_Bound;
13318 -- Start of processing for Install_Private_Data_Declarations
13320 begin
13321 -- Step 1: Retrieve the concurrent object entity. Obj_Ent can denote
13322 -- formal parameter _O, _object or _task depending on the context.
13324 Obj_Ent := Concurrent_Object (Spec_Id, Conc_Typ);
13326 -- Special processing of _O for barrier functions, protected entries
13327 -- and families.
13329 if Barrier
13330 or else
13331 (Is_Protected
13332 and then
13333 (Ekind (Spec_Id) = E_Entry
13334 or else Ekind (Spec_Id) = E_Entry_Family))
13335 then
13336 declare
13337 Conc_Rec : constant Entity_Id :=
13338 Corresponding_Record_Type (Conc_Typ);
13339 Typ_Id : constant Entity_Id :=
13340 Make_Defining_Identifier (Loc,
13341 New_External_Name (Chars (Conc_Rec), 'P'));
13342 begin
13343 -- Generate:
13344 -- type prot_typVP is access prot_typV;
13346 Decl :=
13347 Make_Full_Type_Declaration (Loc,
13348 Defining_Identifier => Typ_Id,
13349 Type_Definition =>
13350 Make_Access_To_Object_Definition (Loc,
13351 Subtype_Indication =>
13352 New_Occurrence_Of (Conc_Rec, Loc)));
13353 Add (Decl);
13355 -- Generate:
13356 -- _object : prot_typVP := prot_typV (_O);
13358 Decl :=
13359 Make_Object_Declaration (Loc,
13360 Defining_Identifier =>
13361 Make_Defining_Identifier (Loc, Name_uObject),
13362 Object_Definition => New_Occurrence_Of (Typ_Id, Loc),
13363 Expression =>
13364 Unchecked_Convert_To (Typ_Id,
13365 New_Occurrence_Of (Obj_Ent, Loc)));
13366 Add (Decl);
13368 -- Set the reference to the concurrent object
13370 Obj_Ent := Defining_Identifier (Decl);
13371 end;
13372 end if;
13374 -- Step 2: Create the Protection object and build its declaration for
13375 -- any protected entry (family) of subprogram. Note for the lock-free
13376 -- implementation, the Protection object is not needed anymore.
13378 if Is_Protected and then not Uses_Lock_Free (Conc_Typ) then
13379 declare
13380 Prot_Ent : constant Entity_Id := Make_Temporary (Loc, 'R');
13381 Prot_Typ : RE_Id;
13383 begin
13384 Set_Protection_Object (Spec_Id, Prot_Ent);
13386 -- Determine the proper protection type
13388 if Has_Attach_Handler (Conc_Typ)
13389 and then not Restricted_Profile
13390 then
13391 Prot_Typ := RE_Static_Interrupt_Protection;
13393 elsif Has_Interrupt_Handler (Conc_Typ)
13394 and then not Restriction_Active (No_Dynamic_Attachment)
13395 then
13396 Prot_Typ := RE_Dynamic_Interrupt_Protection;
13398 else
13399 case Corresponding_Runtime_Package (Conc_Typ) is
13400 when System_Tasking_Protected_Objects_Entries =>
13401 Prot_Typ := RE_Protection_Entries;
13403 when System_Tasking_Protected_Objects_Single_Entry =>
13404 Prot_Typ := RE_Protection_Entry;
13406 when System_Tasking_Protected_Objects =>
13407 Prot_Typ := RE_Protection;
13409 when others =>
13410 raise Program_Error;
13411 end case;
13412 end if;
13414 -- Generate:
13415 -- conc_typR : protection_typ renames _object._object;
13417 Decl :=
13418 Make_Object_Renaming_Declaration (Loc,
13419 Defining_Identifier => Prot_Ent,
13420 Subtype_Mark =>
13421 New_Occurrence_Of (RTE (Prot_Typ), Loc),
13422 Name =>
13423 Make_Selected_Component (Loc,
13424 Prefix => New_Occurrence_Of (Obj_Ent, Loc),
13425 Selector_Name => Make_Identifier (Loc, Name_uObject)));
13426 Add (Decl);
13427 end;
13428 end if;
13430 -- Step 3: Add discriminant renamings (if any)
13432 if Has_Discriminants (Conc_Typ) then
13433 declare
13434 D : Entity_Id;
13436 begin
13437 D := First_Discriminant (Conc_Typ);
13438 while Present (D) loop
13440 -- Adjust the source location
13442 Set_Sloc (Discriminal (D), Loc);
13444 -- Generate:
13445 -- discr_name : discr_typ renames _object.discr_name;
13446 -- or
13447 -- discr_name : discr_typ renames _task.discr_name;
13449 Decl :=
13450 Make_Object_Renaming_Declaration (Loc,
13451 Defining_Identifier => Discriminal (D),
13452 Subtype_Mark => New_Occurrence_Of (Etype (D), Loc),
13453 Name =>
13454 Make_Selected_Component (Loc,
13455 Prefix => New_Occurrence_Of (Obj_Ent, Loc),
13456 Selector_Name => Make_Identifier (Loc, Chars (D))));
13457 Add (Decl);
13459 -- Set debug info needed on this renaming declaration even
13460 -- though it does not come from source, so that the debugger
13461 -- will get the right information for these generated names.
13463 Set_Debug_Info_Needed (Discriminal (D));
13465 Next_Discriminant (D);
13466 end loop;
13467 end;
13468 end if;
13470 -- Step 4: Add private component renamings (if any)
13472 if Is_Protected then
13473 Def := Protected_Definition (Parent (Conc_Typ));
13475 if Present (Private_Declarations (Def)) then
13476 declare
13477 Comp : Node_Id;
13478 Comp_Id : Entity_Id;
13479 Decl_Id : Entity_Id;
13481 begin
13482 Comp := First (Private_Declarations (Def));
13483 while Present (Comp) loop
13484 if Nkind (Comp) = N_Component_Declaration then
13485 Comp_Id := Defining_Identifier (Comp);
13486 Decl_Id :=
13487 Make_Defining_Identifier (Loc, Chars (Comp_Id));
13489 -- Minimal decoration
13491 if Ekind (Spec_Id) = E_Function then
13492 Set_Ekind (Decl_Id, E_Constant);
13493 else
13494 Set_Ekind (Decl_Id, E_Variable);
13495 end if;
13497 Set_Prival (Comp_Id, Decl_Id);
13498 Set_Prival_Link (Decl_Id, Comp_Id);
13499 Set_Is_Aliased (Decl_Id, Is_Aliased (Comp_Id));
13501 -- Generate:
13502 -- comp_name : comp_typ renames _object.comp_name;
13504 Decl :=
13505 Make_Object_Renaming_Declaration (Loc,
13506 Defining_Identifier => Decl_Id,
13507 Subtype_Mark =>
13508 New_Occurrence_Of (Etype (Comp_Id), Loc),
13509 Name =>
13510 Make_Selected_Component (Loc,
13511 Prefix =>
13512 New_Occurrence_Of (Obj_Ent, Loc),
13513 Selector_Name =>
13514 Make_Identifier (Loc, Chars (Comp_Id))));
13515 Add (Decl);
13516 end if;
13518 Next (Comp);
13519 end loop;
13520 end;
13521 end if;
13522 end if;
13524 -- Step 5: Add the declaration of the entry index and the associated
13525 -- type for barrier functions and entry families.
13527 if (Barrier and Family) or else Ekind (Spec_Id) = E_Entry_Family then
13528 declare
13529 E : constant Entity_Id := Index_Object (Spec_Id);
13530 Index : constant Entity_Id :=
13531 Defining_Identifier
13532 (Entry_Index_Specification
13533 (Entry_Body_Formal_Part (Body_Nod)));
13534 Index_Con : constant Entity_Id :=
13535 Make_Defining_Identifier (Loc, Chars (Index));
13536 High : Node_Id;
13537 Index_Typ : Entity_Id;
13538 Low : Node_Id;
13540 begin
13541 -- Minimal decoration
13543 Set_Ekind (Index_Con, E_Constant);
13544 Set_Entry_Index_Constant (Index, Index_Con);
13545 Set_Discriminal_Link (Index_Con, Index);
13547 -- Retrieve the bounds of the entry family
13549 High := Type_High_Bound (Etype (Index));
13550 Low := Type_Low_Bound (Etype (Index));
13552 -- In the simple case the entry family is given by a subtype mark
13553 -- and the index constant has the same type.
13555 if Is_Entity_Name (Original_Node (
13556 Discrete_Subtype_Definition (Parent (Index))))
13557 then
13558 Index_Typ := Etype (Index);
13560 -- Otherwise a new subtype declaration is required
13562 else
13563 High := Replace_Bound (High);
13564 Low := Replace_Bound (Low);
13566 Index_Typ := Make_Temporary (Loc, 'J');
13568 -- Generate:
13569 -- subtype Jnn is <Etype of Index> range Low .. High;
13571 Decl :=
13572 Make_Subtype_Declaration (Loc,
13573 Defining_Identifier => Index_Typ,
13574 Subtype_Indication =>
13575 Make_Subtype_Indication (Loc,
13576 Subtype_Mark =>
13577 New_Occurrence_Of (Base_Type (Etype (Index)), Loc),
13578 Constraint =>
13579 Make_Range_Constraint (Loc,
13580 Range_Expression =>
13581 Make_Range (Loc, Low, High))));
13582 Add (Decl);
13583 end if;
13585 Set_Etype (Index_Con, Index_Typ);
13587 -- Create the object which designates the index:
13588 -- J : constant Jnn :=
13589 -- Jnn'Val (_E - <index expr> + Jnn'Pos (Jnn'First));
13591 -- where Jnn is the subtype created above or the original type of
13592 -- the index, _E is a formal of the protected body subprogram and
13593 -- <index expr> is the index of the first family member.
13595 Decl :=
13596 Make_Object_Declaration (Loc,
13597 Defining_Identifier => Index_Con,
13598 Constant_Present => True,
13599 Object_Definition =>
13600 New_Occurrence_Of (Index_Typ, Loc),
13602 Expression =>
13603 Make_Attribute_Reference (Loc,
13604 Prefix =>
13605 New_Occurrence_Of (Index_Typ, Loc),
13606 Attribute_Name => Name_Val,
13608 Expressions => New_List (
13610 Make_Op_Add (Loc,
13611 Left_Opnd =>
13612 Make_Op_Subtract (Loc,
13613 Left_Opnd => New_Occurrence_Of (E, Loc),
13614 Right_Opnd =>
13615 Entry_Index_Expression (Loc,
13616 Defining_Identifier (Body_Nod),
13617 Empty, Conc_Typ)),
13619 Right_Opnd =>
13620 Make_Attribute_Reference (Loc,
13621 Prefix =>
13622 New_Occurrence_Of (Index_Typ, Loc),
13623 Attribute_Name => Name_Pos,
13624 Expressions => New_List (
13625 Make_Attribute_Reference (Loc,
13626 Prefix =>
13627 New_Occurrence_Of (Index_Typ, Loc),
13628 Attribute_Name => Name_First)))))));
13629 Add (Decl);
13630 end;
13631 end if;
13632 end Install_Private_Data_Declarations;
13634 ---------------------------------
13635 -- Is_Potentially_Large_Family --
13636 ---------------------------------
13638 function Is_Potentially_Large_Family
13639 (Base_Index : Entity_Id;
13640 Conctyp : Entity_Id;
13641 Lo : Node_Id;
13642 Hi : Node_Id) return Boolean
13644 begin
13645 return Scope (Base_Index) = Standard_Standard
13646 and then Base_Index = Base_Type (Standard_Integer)
13647 and then Has_Discriminants (Conctyp)
13648 and then
13649 Present (Discriminant_Default_Value (First_Discriminant (Conctyp)))
13650 and then
13651 (Denotes_Discriminant (Lo, True)
13652 or else
13653 Denotes_Discriminant (Hi, True));
13654 end Is_Potentially_Large_Family;
13656 -------------------------------------
13657 -- Is_Private_Primitive_Subprogram --
13658 -------------------------------------
13660 function Is_Private_Primitive_Subprogram (Id : Entity_Id) return Boolean is
13661 begin
13662 return
13663 (Ekind (Id) = E_Function or else Ekind (Id) = E_Procedure)
13664 and then Is_Private_Primitive (Id);
13665 end Is_Private_Primitive_Subprogram;
13667 ------------------
13668 -- Index_Object --
13669 ------------------
13671 function Index_Object (Spec_Id : Entity_Id) return Entity_Id is
13672 Bod_Subp : constant Entity_Id := Protected_Body_Subprogram (Spec_Id);
13673 Formal : Entity_Id;
13675 begin
13676 Formal := First_Formal (Bod_Subp);
13677 while Present (Formal) loop
13679 -- Look for formal parameter _E
13681 if Chars (Formal) = Name_uE then
13682 return Formal;
13683 end if;
13685 Next_Formal (Formal);
13686 end loop;
13688 -- A protected body subprogram should always have the parameter in
13689 -- question.
13691 raise Program_Error;
13692 end Index_Object;
13694 --------------------------------
13695 -- Make_Initialize_Protection --
13696 --------------------------------
13698 function Make_Initialize_Protection
13699 (Protect_Rec : Entity_Id) return List_Id
13701 Loc : constant Source_Ptr := Sloc (Protect_Rec);
13702 P_Arr : Entity_Id;
13703 Pdec : Node_Id;
13704 Ptyp : constant Node_Id :=
13705 Corresponding_Concurrent_Type (Protect_Rec);
13706 Args : List_Id;
13707 L : constant List_Id := New_List;
13708 Has_Entry : constant Boolean := Has_Entries (Ptyp);
13709 Prio_Type : Entity_Id;
13710 Prio_Var : Entity_Id := Empty;
13711 Restricted : constant Boolean := Restricted_Profile;
13713 begin
13714 -- We may need two calls to properly initialize the object, one to
13715 -- Initialize_Protection, and possibly one to Install_Handlers if we
13716 -- have a pragma Attach_Handler.
13718 -- Get protected declaration. In the case of a task type declaration,
13719 -- this is simply the parent of the protected type entity. In the single
13720 -- protected object declaration, this parent will be the implicit type,
13721 -- and we can find the corresponding single protected object declaration
13722 -- by searching forward in the declaration list in the tree.
13724 -- Is the test for N_Single_Protected_Declaration needed here??? Nodes
13725 -- of this type should have been removed during semantic analysis.
13727 Pdec := Parent (Ptyp);
13728 while not Nkind_In (Pdec, N_Protected_Type_Declaration,
13729 N_Single_Protected_Declaration)
13730 loop
13731 Next (Pdec);
13732 end loop;
13734 -- Build the parameter list for the call. Note that _Init is the name
13735 -- of the formal for the object to be initialized, which is the task
13736 -- value record itself.
13738 Args := New_List;
13740 -- For lock-free implementation, skip initializations of the Protection
13741 -- object.
13743 if not Uses_Lock_Free (Defining_Identifier (Pdec)) then
13745 -- Object parameter. This is a pointer to the object of type
13746 -- Protection used by the GNARL to control the protected object.
13748 Append_To (Args,
13749 Make_Attribute_Reference (Loc,
13750 Prefix =>
13751 Make_Selected_Component (Loc,
13752 Prefix => Make_Identifier (Loc, Name_uInit),
13753 Selector_Name => Make_Identifier (Loc, Name_uObject)),
13754 Attribute_Name => Name_Unchecked_Access));
13756 -- Priority parameter. Set to Unspecified_Priority unless there is a
13757 -- Priority rep item, in which case we take the value from the pragma
13758 -- or attribute definition clause, or there is an Interrupt_Priority
13759 -- rep item and no Priority rep item, and we set the ceiling to
13760 -- Interrupt_Priority'Last, an implementation-defined value, see
13761 -- (RM D.3(10)).
13763 if Has_Rep_Item (Ptyp, Name_Priority, Check_Parents => False) then
13764 declare
13765 Prio_Clause : constant Node_Id :=
13766 Get_Rep_Item
13767 (Ptyp, Name_Priority, Check_Parents => False);
13769 Prio : Node_Id;
13771 begin
13772 -- Pragma Priority
13774 if Nkind (Prio_Clause) = N_Pragma then
13775 Prio :=
13776 Expression
13777 (First (Pragma_Argument_Associations (Prio_Clause)));
13779 -- Get_Rep_Item returns either priority pragma
13781 if Pragma_Name (Prio_Clause) = Name_Priority then
13782 Prio_Type := RTE (RE_Any_Priority);
13783 else
13784 Prio_Type := RTE (RE_Interrupt_Priority);
13785 end if;
13787 -- Attribute definition clause Priority
13789 else
13790 if Chars (Prio_Clause) = Name_Priority then
13791 Prio_Type := RTE (RE_Any_Priority);
13792 else
13793 Prio_Type := RTE (RE_Interrupt_Priority);
13794 end if;
13796 Prio := Expression (Prio_Clause);
13797 end if;
13799 -- Always create a locale variable to capture the priority.
13800 -- The priority is also passed to Install_Restriced_Handlers.
13801 -- Note that it is really necessary to create this variable
13802 -- explicitly. It might be thought that removing side effects
13803 -- would the appropriate approach, but that could generate
13804 -- declarations improperly placed in the enclosing scope.
13806 Prio_Var := Make_Temporary (Loc, 'R', Prio);
13807 Append_To (L,
13808 Make_Object_Declaration (Loc,
13809 Defining_Identifier => Prio_Var,
13810 Object_Definition => New_Occurrence_Of (Prio_Type, Loc),
13811 Expression => Relocate_Node (Prio)));
13813 Append_To (Args, New_Occurrence_Of (Prio_Var, Loc));
13814 end;
13816 -- When no priority is specified but an xx_Handler pragma is, we
13817 -- default to System.Interrupts.Default_Interrupt_Priority, see
13818 -- D.3(10).
13820 elsif Has_Attach_Handler (Ptyp)
13821 or else Has_Interrupt_Handler (Ptyp)
13822 then
13823 Append_To (Args,
13824 New_Occurrence_Of (RTE (RE_Default_Interrupt_Priority), Loc));
13826 -- Normal case, no priority or xx_Handler specified, default priority
13828 else
13829 Append_To (Args,
13830 New_Occurrence_Of (RTE (RE_Unspecified_Priority), Loc));
13831 end if;
13833 -- Deadline_Floor parameter for GNAT_Ravenscar_EDF runtimes
13835 if Restricted_Profile and Task_Dispatching_Policy = 'E' then
13836 Deadline_Floor : declare
13837 Item : constant Node_Id :=
13838 Get_Rep_Item
13839 (Ptyp, Name_Deadline_Floor, Check_Parents => False);
13841 Deadline : Node_Id;
13843 begin
13844 if Present (Item) then
13846 -- Pragma Deadline_Floor
13848 if Nkind (Item) = N_Pragma then
13849 Deadline :=
13850 Expression
13851 (First (Pragma_Argument_Associations (Item)));
13853 -- Attribute definition clause Deadline_Floor
13855 else
13856 pragma Assert
13857 (Nkind (Item) = N_Attribute_Definition_Clause);
13859 Deadline := Expression (Item);
13860 end if;
13862 Append_To (Args, Deadline);
13864 -- Unusual case: default deadline
13866 else
13867 Append_To (Args,
13868 New_Occurrence_Of (RTE (RE_Time_Span_Zero), Loc));
13869 end if;
13870 end Deadline_Floor;
13871 end if;
13873 -- Test for Compiler_Info parameter. This parameter allows entry body
13874 -- procedures and barrier functions to be called from the runtime. It
13875 -- is a pointer to the record generated by the compiler to represent
13876 -- the protected object.
13878 -- A protected type without entries that covers an interface and
13879 -- overrides the abstract routines with protected procedures is
13880 -- considered equivalent to a protected type with entries in the
13881 -- context of dispatching select statements.
13883 -- Protected types with interrupt handlers (when not using a
13884 -- restricted profile) are also considered equivalent to protected
13885 -- types with entries.
13887 -- The types which are used (Static_Interrupt_Protection and
13888 -- Dynamic_Interrupt_Protection) are derived from Protection_Entries.
13890 declare
13891 Pkg_Id : constant RTU_Id := Corresponding_Runtime_Package (Ptyp);
13893 Called_Subp : RE_Id;
13895 begin
13896 case Pkg_Id is
13897 when System_Tasking_Protected_Objects_Entries =>
13898 Called_Subp := RE_Initialize_Protection_Entries;
13900 -- Argument Compiler_Info
13902 Append_To (Args,
13903 Make_Attribute_Reference (Loc,
13904 Prefix => Make_Identifier (Loc, Name_uInit),
13905 Attribute_Name => Name_Address));
13907 when System_Tasking_Protected_Objects_Single_Entry =>
13908 Called_Subp := RE_Initialize_Protection_Entry;
13910 -- Argument Compiler_Info
13912 Append_To (Args,
13913 Make_Attribute_Reference (Loc,
13914 Prefix => Make_Identifier (Loc, Name_uInit),
13915 Attribute_Name => Name_Address));
13917 when System_Tasking_Protected_Objects =>
13918 Called_Subp := RE_Initialize_Protection;
13920 when others =>
13921 raise Program_Error;
13922 end case;
13924 -- Entry_Queue_Maxes parameter. This is an access to an array of
13925 -- naturals representing the entry queue maximums for each entry
13926 -- in the protected type. Zero represents no max. The access is
13927 -- null if there is no limit for all entries (usual case).
13929 if Has_Entry
13930 and then Pkg_Id = System_Tasking_Protected_Objects_Entries
13931 then
13932 if Present (Entry_Max_Queue_Lengths_Array (Ptyp)) then
13933 Append_To (Args,
13934 Make_Attribute_Reference (Loc,
13935 Prefix =>
13936 New_Occurrence_Of
13937 (Entry_Max_Queue_Lengths_Array (Ptyp), Loc),
13938 Attribute_Name => Name_Unrestricted_Access));
13939 else
13940 Append_To (Args, Make_Null (Loc));
13941 end if;
13943 -- Edge cases exist where entry initialization functions are
13944 -- called, but no entries exist, so null is appended.
13946 elsif Pkg_Id = System_Tasking_Protected_Objects_Entries then
13947 Append_To (Args, Make_Null (Loc));
13948 end if;
13950 -- Entry_Bodies parameter. This is a pointer to an array of
13951 -- pointers to the entry body procedures and barrier functions of
13952 -- the object. If the protected type has no entries this object
13953 -- will not exist, in this case, pass a null (it can happen when
13954 -- there are protected interrupt handlers or interfaces).
13956 if Has_Entry then
13957 P_Arr := Entry_Bodies_Array (Ptyp);
13959 -- Argument Entry_Body (for single entry) or Entry_Bodies (for
13960 -- multiple entries).
13962 Append_To (Args,
13963 Make_Attribute_Reference (Loc,
13964 Prefix => New_Occurrence_Of (P_Arr, Loc),
13965 Attribute_Name => Name_Unrestricted_Access));
13967 if Pkg_Id = System_Tasking_Protected_Objects_Entries then
13969 -- Find index mapping function (clumsy but ok for now)
13971 while Ekind (P_Arr) /= E_Function loop
13972 Next_Entity (P_Arr);
13973 end loop;
13975 Append_To (Args,
13976 Make_Attribute_Reference (Loc,
13977 Prefix => New_Occurrence_Of (P_Arr, Loc),
13978 Attribute_Name => Name_Unrestricted_Access));
13979 end if;
13981 elsif Pkg_Id = System_Tasking_Protected_Objects_Single_Entry then
13983 -- This is the case where we have a protected object with
13984 -- interfaces and no entries, and the single entry restriction
13985 -- is in effect. We pass a null pointer for the entry
13986 -- parameter because there is no actual entry.
13988 Append_To (Args, Make_Null (Loc));
13990 elsif Pkg_Id = System_Tasking_Protected_Objects_Entries then
13992 -- This is the case where we have a protected object with no
13993 -- entries and:
13994 -- - either interrupt handlers with non restricted profile,
13995 -- - or interfaces
13996 -- Note that the types which are used for interrupt handlers
13997 -- (Static/Dynamic_Interrupt_Protection) are derived from
13998 -- Protection_Entries. We pass two null pointers because there
13999 -- is no actual entry, and the initialization procedure needs
14000 -- both Entry_Bodies and Find_Body_Index.
14002 Append_To (Args, Make_Null (Loc));
14003 Append_To (Args, Make_Null (Loc));
14004 end if;
14006 Append_To (L,
14007 Make_Procedure_Call_Statement (Loc,
14008 Name =>
14009 New_Occurrence_Of (RTE (Called_Subp), Loc),
14010 Parameter_Associations => Args));
14011 end;
14012 end if;
14014 if Has_Attach_Handler (Ptyp) then
14016 -- We have a list of N Attach_Handler (ProcI, ExprI), and we have to
14017 -- make the following call:
14019 -- Install_Handlers (_object,
14020 -- ((Expr1, Proc1'access), ...., (ExprN, ProcN'access));
14022 -- or, in the case of Ravenscar:
14024 -- Install_Restricted_Handlers
14025 -- (Prio, ((Expr1, Proc1'access), ...., (ExprN, ProcN'access)));
14027 declare
14028 Args : constant List_Id := New_List;
14029 Table : constant List_Id := New_List;
14030 Ritem : Node_Id := First_Rep_Item (Ptyp);
14032 begin
14033 -- Build the Priority parameter (only for ravenscar)
14035 if Restricted then
14037 -- Priority comes from a pragma
14039 if Present (Prio_Var) then
14040 Append_To (Args, New_Occurrence_Of (Prio_Var, Loc));
14042 -- Priority is the default one
14044 else
14045 Append_To (Args,
14046 New_Occurrence_Of
14047 (RTE (RE_Default_Interrupt_Priority), Loc));
14048 end if;
14049 end if;
14051 -- Build the Attach_Handler table argument
14053 while Present (Ritem) loop
14054 if Nkind (Ritem) = N_Pragma
14055 and then Pragma_Name (Ritem) = Name_Attach_Handler
14056 then
14057 declare
14058 Handler : constant Node_Id :=
14059 First (Pragma_Argument_Associations (Ritem));
14061 Interrupt : constant Node_Id := Next (Handler);
14062 Expr : constant Node_Id := Expression (Interrupt);
14064 begin
14065 Append_To (Table,
14066 Make_Aggregate (Loc, Expressions => New_List (
14067 Unchecked_Convert_To
14068 (RTE (RE_System_Interrupt_Id), Expr),
14069 Make_Attribute_Reference (Loc,
14070 Prefix =>
14071 Make_Selected_Component (Loc,
14072 Prefix =>
14073 Make_Identifier (Loc, Name_uInit),
14074 Selector_Name =>
14075 Duplicate_Subexpr_No_Checks
14076 (Expression (Handler))),
14077 Attribute_Name => Name_Access))));
14078 end;
14079 end if;
14081 Next_Rep_Item (Ritem);
14082 end loop;
14084 -- Append the table argument we just built
14086 Append_To (Args, Make_Aggregate (Loc, Table));
14088 -- Append the Install_Handlers (or Install_Restricted_Handlers)
14089 -- call to the statements.
14091 if Restricted then
14092 -- Call a simplified version of Install_Handlers to be used
14093 -- when the Ravenscar restrictions are in effect
14094 -- (Install_Restricted_Handlers).
14096 Append_To (L,
14097 Make_Procedure_Call_Statement (Loc,
14098 Name =>
14099 New_Occurrence_Of
14100 (RTE (RE_Install_Restricted_Handlers), Loc),
14101 Parameter_Associations => Args));
14103 else
14104 if not Uses_Lock_Free (Defining_Identifier (Pdec)) then
14106 -- First, prepends the _object argument
14108 Prepend_To (Args,
14109 Make_Attribute_Reference (Loc,
14110 Prefix =>
14111 Make_Selected_Component (Loc,
14112 Prefix => Make_Identifier (Loc, Name_uInit),
14113 Selector_Name =>
14114 Make_Identifier (Loc, Name_uObject)),
14115 Attribute_Name => Name_Unchecked_Access));
14116 end if;
14118 -- Then, insert call to Install_Handlers
14120 Append_To (L,
14121 Make_Procedure_Call_Statement (Loc,
14122 Name =>
14123 New_Occurrence_Of (RTE (RE_Install_Handlers), Loc),
14124 Parameter_Associations => Args));
14125 end if;
14126 end;
14127 end if;
14129 return L;
14130 end Make_Initialize_Protection;
14132 ---------------------------
14133 -- Make_Task_Create_Call --
14134 ---------------------------
14136 function Make_Task_Create_Call (Task_Rec : Entity_Id) return Node_Id is
14137 Loc : constant Source_Ptr := Sloc (Task_Rec);
14138 Args : List_Id;
14139 Ecount : Node_Id;
14140 Name : Node_Id;
14141 Tdec : Node_Id;
14142 Tdef : Node_Id;
14143 Tnam : Name_Id;
14144 Ttyp : Node_Id;
14146 begin
14147 Ttyp := Corresponding_Concurrent_Type (Task_Rec);
14148 Tnam := Chars (Ttyp);
14150 -- Get task declaration. In the case of a task type declaration, this is
14151 -- simply the parent of the task type entity. In the single task
14152 -- declaration, this parent will be the implicit type, and we can find
14153 -- the corresponding single task declaration by searching forward in the
14154 -- declaration list in the tree.
14156 -- Is the test for N_Single_Task_Declaration needed here??? Nodes of
14157 -- this type should have been removed during semantic analysis.
14159 Tdec := Parent (Ttyp);
14160 while not Nkind_In (Tdec, N_Task_Type_Declaration,
14161 N_Single_Task_Declaration)
14162 loop
14163 Next (Tdec);
14164 end loop;
14166 -- Now we can find the task definition from this declaration
14168 Tdef := Task_Definition (Tdec);
14170 -- Build the parameter list for the call. Note that _Init is the name
14171 -- of the formal for the object to be initialized, which is the task
14172 -- value record itself.
14174 Args := New_List;
14176 -- Priority parameter. Set to Unspecified_Priority unless there is a
14177 -- Priority rep item, in which case we take the value from the rep item.
14178 -- Not used on Ravenscar_EDF profile.
14180 if not (Restricted_Profile and then Task_Dispatching_Policy = 'E') then
14181 if Has_Rep_Item (Ttyp, Name_Priority, Check_Parents => False) then
14182 Append_To (Args,
14183 Make_Selected_Component (Loc,
14184 Prefix => Make_Identifier (Loc, Name_uInit),
14185 Selector_Name => Make_Identifier (Loc, Name_uPriority)));
14186 else
14187 Append_To (Args,
14188 New_Occurrence_Of (RTE (RE_Unspecified_Priority), Loc));
14189 end if;
14190 end if;
14192 -- Optional Stack parameter
14194 if Restricted_Profile then
14196 -- If the stack has been preallocated by the expander then
14197 -- pass its address. Otherwise, pass a null address.
14199 if Preallocated_Stacks_On_Target then
14200 Append_To (Args,
14201 Make_Attribute_Reference (Loc,
14202 Prefix =>
14203 Make_Selected_Component (Loc,
14204 Prefix => Make_Identifier (Loc, Name_uInit),
14205 Selector_Name => Make_Identifier (Loc, Name_uStack)),
14206 Attribute_Name => Name_Address));
14208 else
14209 Append_To (Args,
14210 New_Occurrence_Of (RTE (RE_Null_Address), Loc));
14211 end if;
14212 end if;
14214 -- Size parameter. If no Storage_Size pragma is present, then
14215 -- the size is taken from the taskZ variable for the type, which
14216 -- is either Unspecified_Size, or has been reset by the use of
14217 -- a Storage_Size attribute definition clause. If a pragma is
14218 -- present, then the size is taken from the _Size field of the
14219 -- task value record, which was set from the pragma value.
14221 if Present (Tdef) and then Has_Storage_Size_Pragma (Tdef) then
14222 Append_To (Args,
14223 Make_Selected_Component (Loc,
14224 Prefix => Make_Identifier (Loc, Name_uInit),
14225 Selector_Name => Make_Identifier (Loc, Name_uSize)));
14227 else
14228 Append_To (Args,
14229 New_Occurrence_Of (Storage_Size_Variable (Ttyp), Loc));
14230 end if;
14232 -- Secondary_Stack parameter used for restricted profiles
14234 if Restricted_Profile then
14236 -- If the secondary stack has been allocated by the expander then
14237 -- pass its access pointer. Otherwise, pass null.
14239 if Create_Secondary_Stack_For_Task (Ttyp) then
14240 Append_To (Args,
14241 Make_Attribute_Reference (Loc,
14242 Prefix =>
14243 Make_Selected_Component (Loc,
14244 Prefix => Make_Identifier (Loc, Name_uInit),
14245 Selector_Name =>
14246 Make_Identifier (Loc, Name_uSecondary_Stack)),
14247 Attribute_Name => Name_Unrestricted_Access));
14249 else
14250 Append_To (Args, Make_Null (Loc));
14251 end if;
14252 end if;
14254 -- Secondary_Stack_Size parameter. Set RE_Unspecified_Size unless there
14255 -- is a Secondary_Stack_Size pragma, in which case take the value from
14256 -- the pragma. If the restriction No_Secondary_Stack is active then a
14257 -- size of 0 is passed regardless to prevent the allocation of the
14258 -- unused stack.
14260 if Restriction_Active (No_Secondary_Stack) then
14261 Append_To (Args, Make_Integer_Literal (Loc, 0));
14263 elsif Has_Rep_Pragma
14264 (Ttyp, Name_Secondary_Stack_Size, Check_Parents => False)
14265 then
14266 Append_To (Args,
14267 Make_Selected_Component (Loc,
14268 Prefix => Make_Identifier (Loc, Name_uInit),
14269 Selector_Name =>
14270 Make_Identifier (Loc, Name_uSecondary_Stack_Size)));
14272 else
14273 Append_To (Args,
14274 New_Occurrence_Of (RTE (RE_Unspecified_Size), Loc));
14275 end if;
14277 -- Task_Info parameter. Set to Unspecified_Task_Info unless there is a
14278 -- Task_Info pragma, in which case we take the value from the pragma.
14280 if Has_Rep_Pragma (Ttyp, Name_Task_Info, Check_Parents => False) then
14281 Append_To (Args,
14282 Make_Selected_Component (Loc,
14283 Prefix => Make_Identifier (Loc, Name_uInit),
14284 Selector_Name => Make_Identifier (Loc, Name_uTask_Info)));
14286 else
14287 Append_To (Args,
14288 New_Occurrence_Of (RTE (RE_Unspecified_Task_Info), Loc));
14289 end if;
14291 -- CPU parameter. Set to Unspecified_CPU unless there is a CPU rep item,
14292 -- in which case we take the value from the rep item. The parameter is
14293 -- passed as an Integer because in the case of unspecified CPU the
14294 -- value is not in the range of CPU_Range.
14296 if Has_Rep_Item (Ttyp, Name_CPU, Check_Parents => False) then
14297 Append_To (Args,
14298 Convert_To (Standard_Integer,
14299 Make_Selected_Component (Loc,
14300 Prefix => Make_Identifier (Loc, Name_uInit),
14301 Selector_Name => Make_Identifier (Loc, Name_uCPU))));
14302 else
14303 Append_To (Args,
14304 New_Occurrence_Of (RTE (RE_Unspecified_CPU), Loc));
14305 end if;
14307 if not Restricted_Profile or else Task_Dispatching_Policy = 'E' then
14309 -- Deadline parameter. If no Relative_Deadline pragma is present,
14310 -- then the deadline is Time_Span_Zero. If a pragma is present, then
14311 -- the deadline is taken from the _Relative_Deadline field of the
14312 -- task value record, which was set from the pragma value. Note that
14313 -- this parameter must not be generated for the restricted profiles
14314 -- since Ravenscar does not allow deadlines.
14316 -- Case where pragma Relative_Deadline applies: use given value
14318 if Present (Tdef) and then Has_Relative_Deadline_Pragma (Tdef) then
14319 Append_To (Args,
14320 Make_Selected_Component (Loc,
14321 Prefix => Make_Identifier (Loc, Name_uInit),
14322 Selector_Name =>
14323 Make_Identifier (Loc, Name_uRelative_Deadline)));
14325 -- No pragma Relative_Deadline apply to the task
14327 else
14328 Append_To (Args,
14329 New_Occurrence_Of (RTE (RE_Time_Span_Zero), Loc));
14330 end if;
14331 end if;
14333 if not Restricted_Profile then
14335 -- Dispatching_Domain parameter. If no Dispatching_Domain rep item is
14336 -- present, then the dispatching domain is null. If a rep item is
14337 -- present, then the dispatching domain is taken from the
14338 -- _Dispatching_Domain field of the task value record, which was set
14339 -- from the rep item value.
14341 -- Case where Dispatching_Domain rep item applies: use given value
14343 if Has_Rep_Item
14344 (Ttyp, Name_Dispatching_Domain, Check_Parents => False)
14345 then
14346 Append_To (Args,
14347 Make_Selected_Component (Loc,
14348 Prefix =>
14349 Make_Identifier (Loc, Name_uInit),
14350 Selector_Name =>
14351 Make_Identifier (Loc, Name_uDispatching_Domain)));
14353 -- No pragma or aspect Dispatching_Domain applies to the task
14355 else
14356 Append_To (Args, Make_Null (Loc));
14357 end if;
14359 -- Number of entries. This is an expression of the form:
14361 -- n + _Init.a'Length + _Init.a'B'Length + ...
14363 -- where a,b... are the entry family names for the task definition
14365 Ecount :=
14366 Build_Entry_Count_Expression
14367 (Ttyp,
14368 Component_Items
14369 (Component_List
14370 (Type_Definition
14371 (Parent (Corresponding_Record_Type (Ttyp))))),
14372 Loc);
14373 Append_To (Args, Ecount);
14375 -- Master parameter. This is a reference to the _Master parameter of
14376 -- the initialization procedure, except in the case of the pragma
14377 -- Restrictions (No_Task_Hierarchy) where the value is fixed to
14378 -- System.Tasking.Library_Task_Level.
14380 if Restriction_Active (No_Task_Hierarchy) = False then
14381 Append_To (Args, Make_Identifier (Loc, Name_uMaster));
14382 else
14383 Append_To (Args,
14384 New_Occurrence_Of (RTE (RE_Library_Task_Level), Loc));
14385 end if;
14386 end if;
14388 -- State parameter. This is a pointer to the task body procedure. The
14389 -- required value is obtained by taking 'Unrestricted_Access of the task
14390 -- body procedure and converting it (with an unchecked conversion) to
14391 -- the type required by the task kernel. For further details, see the
14392 -- description of Expand_N_Task_Body. We use 'Unrestricted_Access rather
14393 -- than 'Address in order to avoid creating trampolines.
14395 declare
14396 Body_Proc : constant Node_Id := Get_Task_Body_Procedure (Ttyp);
14397 Subp_Ptr_Typ : constant Node_Id :=
14398 Create_Itype (E_Access_Subprogram_Type, Tdec);
14399 Ref : constant Node_Id := Make_Itype_Reference (Loc);
14401 begin
14402 Set_Directly_Designated_Type (Subp_Ptr_Typ, Body_Proc);
14403 Set_Etype (Subp_Ptr_Typ, Subp_Ptr_Typ);
14405 -- Be sure to freeze a reference to the access-to-subprogram type,
14406 -- otherwise gigi will complain that it's in the wrong scope, because
14407 -- it's actually inside the init procedure for the record type that
14408 -- corresponds to the task type.
14410 Set_Itype (Ref, Subp_Ptr_Typ);
14411 Append_Freeze_Action (Task_Rec, Ref);
14413 Append_To (Args,
14414 Unchecked_Convert_To (RTE (RE_Task_Procedure_Access),
14415 Make_Qualified_Expression (Loc,
14416 Subtype_Mark => New_Occurrence_Of (Subp_Ptr_Typ, Loc),
14417 Expression =>
14418 Make_Attribute_Reference (Loc,
14419 Prefix => New_Occurrence_Of (Body_Proc, Loc),
14420 Attribute_Name => Name_Unrestricted_Access))));
14421 end;
14423 -- Discriminants parameter. This is just the address of the task
14424 -- value record itself (which contains the discriminant values
14426 Append_To (Args,
14427 Make_Attribute_Reference (Loc,
14428 Prefix => Make_Identifier (Loc, Name_uInit),
14429 Attribute_Name => Name_Address));
14431 -- Elaborated parameter. This is an access to the elaboration Boolean
14433 Append_To (Args,
14434 Make_Attribute_Reference (Loc,
14435 Prefix => Make_Identifier (Loc, New_External_Name (Tnam, 'E')),
14436 Attribute_Name => Name_Unchecked_Access));
14438 -- Add Chain parameter (not done for sequential elaboration policy, see
14439 -- comment for Create_Restricted_Task_Sequential in s-tarest.ads).
14441 if Partition_Elaboration_Policy /= 'S' then
14442 Append_To (Args, Make_Identifier (Loc, Name_uChain));
14443 end if;
14445 -- Task name parameter. Take this from the _Task_Id parameter to the
14446 -- init call unless there is a Task_Name pragma, in which case we take
14447 -- the value from the pragma.
14449 if Has_Rep_Pragma (Ttyp, Name_Task_Name, Check_Parents => False) then
14450 -- Copy expression in full, because it may be dynamic and have
14451 -- side effects.
14453 Append_To (Args,
14454 New_Copy_Tree
14455 (Expression
14456 (First
14457 (Pragma_Argument_Associations
14458 (Get_Rep_Pragma
14459 (Ttyp, Name_Task_Name, Check_Parents => False))))));
14461 else
14462 Append_To (Args, Make_Identifier (Loc, Name_uTask_Name));
14463 end if;
14465 -- Created_Task parameter. This is the _Task_Id field of the task
14466 -- record value
14468 Append_To (Args,
14469 Make_Selected_Component (Loc,
14470 Prefix => Make_Identifier (Loc, Name_uInit),
14471 Selector_Name => Make_Identifier (Loc, Name_uTask_Id)));
14473 declare
14474 Create_RE : RE_Id;
14476 begin
14477 if Restricted_Profile then
14478 if Partition_Elaboration_Policy = 'S' then
14479 Create_RE := RE_Create_Restricted_Task_Sequential;
14480 else
14481 Create_RE := RE_Create_Restricted_Task;
14482 end if;
14483 else
14484 Create_RE := RE_Create_Task;
14485 end if;
14487 Name := New_Occurrence_Of (RTE (Create_RE), Loc);
14488 end;
14490 return
14491 Make_Procedure_Call_Statement (Loc,
14492 Name => Name,
14493 Parameter_Associations => Args);
14494 end Make_Task_Create_Call;
14496 ------------------------------
14497 -- Next_Protected_Operation --
14498 ------------------------------
14500 function Next_Protected_Operation (N : Node_Id) return Node_Id is
14501 Next_Op : Node_Id;
14503 begin
14504 -- Check whether there is a subsequent body for a protected operation
14505 -- in the current protected body. In Ada2012 that includes expression
14506 -- functions that are completions.
14508 Next_Op := Next (N);
14509 while Present (Next_Op)
14510 and then not Nkind_In (Next_Op,
14511 N_Subprogram_Body, N_Entry_Body, N_Expression_Function)
14512 loop
14513 Next (Next_Op);
14514 end loop;
14516 return Next_Op;
14517 end Next_Protected_Operation;
14519 ---------------------
14520 -- Null_Statements --
14521 ---------------------
14523 function Null_Statements (Stats : List_Id) return Boolean is
14524 Stmt : Node_Id;
14526 begin
14527 Stmt := First (Stats);
14528 while Nkind (Stmt) /= N_Empty
14529 and then (Nkind_In (Stmt, N_Null_Statement, N_Label)
14530 or else
14531 (Nkind (Stmt) = N_Pragma
14532 and then
14533 Nam_In (Pragma_Name_Unmapped (Stmt),
14534 Name_Unreferenced,
14535 Name_Unmodified,
14536 Name_Warnings)))
14537 loop
14538 Next (Stmt);
14539 end loop;
14541 return Nkind (Stmt) = N_Empty;
14542 end Null_Statements;
14544 --------------------------
14545 -- Parameter_Block_Pack --
14546 --------------------------
14548 function Parameter_Block_Pack
14549 (Loc : Source_Ptr;
14550 Blk_Typ : Entity_Id;
14551 Actuals : List_Id;
14552 Formals : List_Id;
14553 Decls : List_Id;
14554 Stmts : List_Id) return Node_Id
14556 Actual : Entity_Id;
14557 Expr : Node_Id := Empty;
14558 Formal : Entity_Id;
14559 Has_Param : Boolean := False;
14560 P : Entity_Id;
14561 Params : List_Id;
14562 Temp_Asn : Node_Id;
14563 Temp_Nam : Node_Id;
14565 begin
14566 Actual := First (Actuals);
14567 Formal := Defining_Identifier (First (Formals));
14568 Params := New_List;
14569 while Present (Actual) loop
14570 if Is_By_Copy_Type (Etype (Actual)) then
14571 -- Generate:
14572 -- Jnn : aliased <formal-type>
14574 Temp_Nam := Make_Temporary (Loc, 'J');
14576 Append_To (Decls,
14577 Make_Object_Declaration (Loc,
14578 Aliased_Present => True,
14579 Defining_Identifier => Temp_Nam,
14580 Object_Definition =>
14581 New_Occurrence_Of (Etype (Formal), Loc)));
14583 -- The object is initialized with an explicit assignment
14584 -- later. Indicate that it does not need an initialization
14585 -- to prevent spurious warnings if the type excludes null.
14587 Set_No_Initialization (Last (Decls));
14589 if Ekind (Formal) /= E_Out_Parameter then
14591 -- Generate:
14592 -- Jnn := <actual>
14594 Temp_Asn :=
14595 New_Occurrence_Of (Temp_Nam, Loc);
14597 Set_Assignment_OK (Temp_Asn);
14599 Append_To (Stmts,
14600 Make_Assignment_Statement (Loc,
14601 Name => Temp_Asn,
14602 Expression => New_Copy_Tree (Actual)));
14603 end if;
14605 -- If the actual is not controlling, generate:
14607 -- Jnn'unchecked_access
14609 -- and add it to aggegate for access to formals. Note that the
14610 -- actual may be by-copy but still be a controlling actual if it
14611 -- is an access to class-wide interface.
14613 if not Is_Controlling_Actual (Actual) then
14614 Append_To (Params,
14615 Make_Attribute_Reference (Loc,
14616 Attribute_Name => Name_Unchecked_Access,
14617 Prefix => New_Occurrence_Of (Temp_Nam, Loc)));
14619 Has_Param := True;
14620 end if;
14622 -- The controlling parameter is omitted
14624 else
14625 if not Is_Controlling_Actual (Actual) then
14626 Append_To (Params,
14627 Make_Reference (Loc, New_Copy_Tree (Actual)));
14629 Has_Param := True;
14630 end if;
14631 end if;
14633 Next_Actual (Actual);
14634 Next_Formal_With_Extras (Formal);
14635 end loop;
14637 if Has_Param then
14638 Expr := Make_Aggregate (Loc, Params);
14639 end if;
14641 -- Generate:
14642 -- P : Ann := (
14643 -- J1'unchecked_access;
14644 -- <actual2>'reference;
14645 -- ...);
14647 P := Make_Temporary (Loc, 'P');
14649 Append_To (Decls,
14650 Make_Object_Declaration (Loc,
14651 Defining_Identifier => P,
14652 Object_Definition => New_Occurrence_Of (Blk_Typ, Loc),
14653 Expression => Expr));
14655 return P;
14656 end Parameter_Block_Pack;
14658 ----------------------------
14659 -- Parameter_Block_Unpack --
14660 ----------------------------
14662 function Parameter_Block_Unpack
14663 (Loc : Source_Ptr;
14664 P : Entity_Id;
14665 Actuals : List_Id;
14666 Formals : List_Id) return List_Id
14668 Actual : Entity_Id;
14669 Asnmt : Node_Id;
14670 Formal : Entity_Id;
14671 Has_Asnmt : Boolean := False;
14672 Result : constant List_Id := New_List;
14674 begin
14675 Actual := First (Actuals);
14676 Formal := Defining_Identifier (First (Formals));
14677 while Present (Actual) loop
14678 if Is_By_Copy_Type (Etype (Actual))
14679 and then Ekind (Formal) /= E_In_Parameter
14680 then
14681 -- Generate:
14682 -- <actual> := P.<formal>;
14684 Asnmt :=
14685 Make_Assignment_Statement (Loc,
14686 Name =>
14687 New_Copy (Actual),
14688 Expression =>
14689 Make_Explicit_Dereference (Loc,
14690 Make_Selected_Component (Loc,
14691 Prefix =>
14692 New_Occurrence_Of (P, Loc),
14693 Selector_Name =>
14694 Make_Identifier (Loc, Chars (Formal)))));
14696 Set_Assignment_OK (Name (Asnmt));
14697 Append_To (Result, Asnmt);
14699 Has_Asnmt := True;
14700 end if;
14702 Next_Actual (Actual);
14703 Next_Formal_With_Extras (Formal);
14704 end loop;
14706 if Has_Asnmt then
14707 return Result;
14708 else
14709 return New_List (Make_Null_Statement (Loc));
14710 end if;
14711 end Parameter_Block_Unpack;
14713 ----------------------
14714 -- Set_Discriminals --
14715 ----------------------
14717 procedure Set_Discriminals (Dec : Node_Id) is
14718 D : Entity_Id;
14719 Pdef : Entity_Id;
14720 D_Minal : Entity_Id;
14722 begin
14723 pragma Assert (Nkind (Dec) = N_Protected_Type_Declaration);
14724 Pdef := Defining_Identifier (Dec);
14726 if Has_Discriminants (Pdef) then
14727 D := First_Discriminant (Pdef);
14728 while Present (D) loop
14729 D_Minal :=
14730 Make_Defining_Identifier (Sloc (D),
14731 Chars => New_External_Name (Chars (D), 'D'));
14733 Set_Ekind (D_Minal, E_Constant);
14734 Set_Etype (D_Minal, Etype (D));
14735 Set_Scope (D_Minal, Pdef);
14736 Set_Discriminal (D, D_Minal);
14737 Set_Discriminal_Link (D_Minal, D);
14739 Next_Discriminant (D);
14740 end loop;
14741 end if;
14742 end Set_Discriminals;
14744 -----------------------
14745 -- Trivial_Accept_OK --
14746 -----------------------
14748 function Trivial_Accept_OK return Boolean is
14749 begin
14750 case Opt.Task_Dispatching_Policy is
14752 -- If we have the default task dispatching policy in effect, we can
14753 -- definitely do the optimization (one way of looking at this is to
14754 -- think of the formal definition of the default policy being allowed
14755 -- to run any task it likes after a rendezvous, so even if notionally
14756 -- a full rescheduling occurs, we can say that our dispatching policy
14757 -- (i.e. the default dispatching policy) reorders the queue to be the
14758 -- same as just before the call.
14760 when ' ' =>
14761 return True;
14763 -- FIFO_Within_Priorities certainly does not permit this
14764 -- optimization since the Rendezvous is a scheduling action that may
14765 -- require some other task to be run.
14767 when 'F' =>
14768 return False;
14770 -- For now, disallow the optimization for all other policies. This
14771 -- may be over-conservative, but it is certainly not incorrect.
14773 when others =>
14774 return False;
14775 end case;
14776 end Trivial_Accept_OK;
14778 end Exp_Ch9;