Disable tests for strdup/strndup on __hpux__
[official-gcc.git] / gcc / ada / exp_ch9.adb
blobf83c233a516b20dbc4f9010d67626266f97aabdd
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-2023, 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 Accessibility; use Accessibility;
27 with Atree; use Atree;
28 with Aspects; use Aspects;
29 with Checks; use Checks;
30 with Contracts; use Contracts;
31 with Einfo; use Einfo;
32 with Einfo.Entities; use Einfo.Entities;
33 with Einfo.Utils; use Einfo.Utils;
34 with Elists; use Elists;
35 with Errout; use Errout;
36 with Exp_Ch3; use Exp_Ch3;
37 with Exp_Ch6; use Exp_Ch6;
38 with Exp_Ch11; use Exp_Ch11;
39 with Exp_Dbug; use Exp_Dbug;
40 with Exp_Sel; use Exp_Sel;
41 with Exp_Smem; use Exp_Smem;
42 with Exp_Tss; use Exp_Tss;
43 with Exp_Util; use Exp_Util;
44 with Freeze; use Freeze;
45 with Hostparm;
46 with Itypes; use Itypes;
47 with Namet; use Namet;
48 with Nlists; use Nlists;
49 with Nmake; use Nmake;
50 with Opt; use Opt;
51 with Restrict; use Restrict;
52 with Rident; use Rident;
53 with Rtsfind; use Rtsfind;
54 with Sem; use Sem;
55 with Sem_Aux; use Sem_Aux;
56 with Sem_Ch5; use Sem_Ch5;
57 with Sem_Ch6; use Sem_Ch6;
58 with Sem_Ch8; use Sem_Ch8;
59 with Sem_Ch9; use Sem_Ch9;
60 with Sem_Ch11; use Sem_Ch11;
61 with Sem_Ch13; use Sem_Ch13;
62 with Sem_Elab; use Sem_Elab;
63 with Sem_Eval; use Sem_Eval;
64 with Sem_Res; use Sem_Res;
65 with Sem_Util; use Sem_Util;
66 with Sinfo; use Sinfo;
67 with Sinfo.Nodes; use Sinfo.Nodes;
68 with Sinfo.Utils; use Sinfo.Utils;
69 with Snames; use Snames;
70 with Stand; use Stand;
71 with Targparm; use Targparm;
72 with Tbuild; use Tbuild;
73 with Uintp; use Uintp;
74 with Validsw; use Validsw;
76 package body Exp_Ch9 is
78 -- The following constant establishes the upper bound for the index of
79 -- an entry family. It is used to limit the allocated size of protected
80 -- types with defaulted discriminant of an integer type, when the bound
81 -- of some entry family depends on a discriminant. The limitation to entry
82 -- families of 128K should be reasonable in all cases, and is a documented
83 -- implementation restriction.
85 Entry_Family_Bound : constant Pos := 2**16;
87 -----------------------
88 -- Local Subprograms --
89 -----------------------
91 function Actual_Index_Expression
92 (Sloc : Source_Ptr;
93 Ent : Entity_Id;
94 Index : Node_Id;
95 Tsk : Entity_Id) return Node_Id;
96 -- Compute the index position for an entry call. Tsk is the target task. If
97 -- the bounds of some entry family depend on discriminants, the expression
98 -- computed by this function uses the discriminants of the target task.
100 procedure Add_Object_Pointer
101 (Loc : Source_Ptr;
102 Conc_Typ : Entity_Id;
103 Decls : List_Id);
104 -- Prepend an object pointer declaration to the declaration list Decls.
105 -- This object pointer is initialized to a type conversion of the System.
106 -- Address pointer passed to entry barrier functions and entry body
107 -- procedures.
109 procedure Add_Formal_Renamings
110 (Spec : Node_Id;
111 Decls : List_Id;
112 Ent : Entity_Id;
113 Loc : Source_Ptr);
114 -- Create renaming declarations for the formals, inside the procedure that
115 -- implements an entry body. The renamings make the original names of the
116 -- formals accessible to gdb, and serve no other purpose.
117 -- Spec is the specification of the procedure being built.
118 -- Decls is the list of declarations to be enhanced.
119 -- Ent is the entity for the original entry body.
121 function Build_Accept_Body (Astat : Node_Id) return Node_Id;
122 -- Transform accept statement into a block with added exception handler.
123 -- Used both for simple accept statements and for accept alternatives in
124 -- select statements. Astat is the accept statement.
126 function Build_Barrier_Function
127 (N : Node_Id;
128 Ent : Entity_Id;
129 Pid : Entity_Id) return Node_Id;
130 -- Build the function body returning the value of the barrier expression
131 -- for the specified entry body.
133 function Build_Barrier_Function_Specification
134 (Loc : Source_Ptr;
135 Def_Id : Entity_Id) return Node_Id;
136 -- Build a specification for a function implementing the protected entry
137 -- barrier of the specified entry body.
139 function Build_Corresponding_Record
140 (N : Node_Id;
141 Ctyp : Entity_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 : Entity_Id;
158 Loc : Source_Ptr) return Node_Id;
159 -- Compute number of entries for concurrent object. This is a count of
160 -- simple entries, followed by an expression that computes the length
161 -- of the range of each entry family. A single array with that size is
162 -- allocated for each concurrent object of the type.
164 function Build_Find_Body_Index (Typ : Entity_Id) return Node_Id;
165 -- Build the function that translates the entry index in the call
166 -- (which depends on the size of entry families) into an index into the
167 -- Entry_Bodies_Array, to determine the body and barrier function used
168 -- in a protected entry call. A pointer to this function appears in every
169 -- protected object.
171 function Build_Find_Body_Index_Spec (Typ : Entity_Id) return Node_Id;
172 -- Build subprogram declaration for previous one
174 function Build_Lock_Free_Protected_Subprogram_Body
175 (N : Node_Id;
176 Prot_Typ : Node_Id;
177 Unprot_Spec : Node_Id) return Node_Id;
178 -- N denotes a subprogram body of protected type Prot_Typ. Unprot_Spec is
179 -- the subprogram specification of the unprotected version of N. Transform
180 -- N such that it invokes the unprotected version of the body.
182 function Build_Lock_Free_Unprotected_Subprogram_Body
183 (N : Node_Id;
184 Prot_Typ : Node_Id) return Node_Id;
185 -- N denotes a subprogram body of protected type Prot_Typ. Build a version
186 -- of N where the original statements of N are synchronized through atomic
187 -- actions such as compare and exchange. Prior to invoking this routine, it
188 -- has been established that N can be implemented in a lock-free fashion.
190 function Build_Parameter_Block
191 (Loc : Source_Ptr;
192 Actuals : List_Id;
193 Formals : List_Id;
194 Decls : List_Id) return Entity_Id;
195 -- Generate an access type for each actual parameter in the list Actuals.
196 -- Create an encapsulating record that contains all the actuals and return
197 -- its type. Generate:
198 -- type Ann1 is access all <actual1-type>
199 -- ...
200 -- type AnnN is access all <actualN-type>
201 -- type Pnn is record
202 -- <formal1> : Ann1;
203 -- ...
204 -- <formalN> : AnnN;
205 -- end record;
207 function Build_Protected_Entry
208 (N : Node_Id;
209 Ent : Entity_Id;
210 Pid : Node_Id) return Node_Id;
211 -- Build the procedure implementing the statement sequence of the specified
212 -- entry body.
214 function Build_Protected_Entry_Specification
215 (Loc : Source_Ptr;
216 Def_Id : Entity_Id;
217 Ent_Id : Entity_Id) return Node_Id;
218 -- Build a specification for the procedure implementing the statements of
219 -- the specified entry body. Add attributes associating it with the entry
220 -- defining identifier Ent_Id.
222 function Build_Protected_Spec
223 (N : Node_Id;
224 Obj_Type : Entity_Id;
225 Ident : Entity_Id;
226 Unprotected : Boolean := False) return List_Id;
227 -- Utility shared by Build_Protected_Sub_Spec and Expand_Access_Protected_
228 -- Subprogram_Type. Builds signature of protected subprogram, adding the
229 -- formal that corresponds to the object itself. For an access to protected
230 -- subprogram, there is no object type to specify, so the parameter has
231 -- type Address and mode In. An indirect call through such a pointer will
232 -- convert the address to a reference to the actual object. The object is
233 -- a limited record and therefore a by_reference type.
235 function Build_Protected_Subprogram_Body
236 (N : Node_Id;
237 Pid : Node_Id;
238 N_Op_Spec : Node_Id) return Node_Id;
239 -- This function is used to construct the protected version of a protected
240 -- subprogram. Its statement sequence first defers abort, then locks the
241 -- associated protected object, and then enters a block that contains a
242 -- call to the unprotected version of the subprogram (for details, see
243 -- Build_Unprotected_Subprogram_Body). This block statement requires a
244 -- cleanup handler that unlocks the object in all cases. For details,
245 -- see Exp_Ch7.Expand_Cleanup_Actions.
247 function Build_Renamed_Formal_Declaration
248 (New_F : Entity_Id;
249 Formal : Entity_Id;
250 Comp : Entity_Id;
251 Renamed_Formal : Node_Id) return Node_Id;
252 -- Create a renaming declaration for a formal, within a protected entry
253 -- body or an accept body. The renamed object is a component of the
254 -- parameter block that is a parameter in the entry call.
256 -- In Ada 2012, if the formal is an incomplete tagged type, the renaming
257 -- does not dereference the corresponding component to prevent an illegal
258 -- use of the incomplete type (AI05-0151).
260 function Build_Selected_Name
261 (Prefix : Entity_Id;
262 Selector : Entity_Id;
263 Append_Char : Character := ' ') return Name_Id;
264 -- Build a name in the form of Prefix__Selector, with an optional character
265 -- appended. This is used for internal subprograms generated for operations
266 -- of protected types, including barrier functions. For the subprograms
267 -- generated for entry bodies and entry barriers, the generated name
268 -- includes a sequence number that makes names unique in the presence of
269 -- entry overloading. This is necessary because entry body procedures and
270 -- barrier functions all have the same signature.
272 procedure Build_Simple_Entry_Call
273 (N : Node_Id;
274 Concval : Node_Id;
275 Ename : Node_Id;
276 Index : Node_Id);
277 -- Build the call corresponding to the task entry call. N is the task entry
278 -- call, Concval is the concurrent object, Ename is the entry name and
279 -- Index is the entry family index.
280 -- Note that N might be expanded into an N_Block_Statement if it gets
281 -- inlined.
283 function Build_Task_Proc_Specification (T : Entity_Id) return Node_Id;
284 -- This routine constructs a specification for the procedure that we will
285 -- build for the task body for task type T. The spec has the form:
287 -- procedure tnameB (_Task : access tnameV);
289 -- where name is the character name taken from the task type entity that
290 -- is passed as the argument to the procedure, and tnameV is the task
291 -- value type that is associated with the task type.
293 function Build_Unprotected_Subprogram_Body
294 (N : Node_Id;
295 Pid : Node_Id) return Node_Id;
296 -- This routine constructs the unprotected version of a protected
297 -- subprogram body, which contains all of the code in the original,
298 -- unexpanded body. This is the version of the protected subprogram that is
299 -- called from all protected operations on the same object, including the
300 -- protected version of the same subprogram.
302 procedure Build_Wrapper_Bodies
303 (Loc : Source_Ptr;
304 Typ : Entity_Id;
305 N : Node_Id);
306 -- Ada 2005 (AI-345): Typ is either a concurrent type or the corresponding
307 -- record of a concurrent type. N is the insertion node where all bodies
308 -- will be placed. This routine builds the bodies of the subprograms which
309 -- serve as an indirection mechanism to overriding primitives of concurrent
310 -- types, entries and protected procedures. Any new body is analyzed.
312 procedure Build_Wrapper_Specs
313 (Loc : Source_Ptr;
314 Typ : Entity_Id;
315 N : in out Node_Id);
316 -- Ada 2005 (AI-345): Typ is either a concurrent type or the corresponding
317 -- record of a concurrent type. N is the insertion node where all specs
318 -- will be placed. This routine builds the specs of the subprograms which
319 -- serve as an indirection mechanism to overriding primitives of concurrent
320 -- types, entries and protected procedures. Any new spec is analyzed.
322 procedure Collect_Entry_Families
323 (Loc : Source_Ptr;
324 Cdecls : List_Id;
325 Current_Node : in out Node_Id;
326 Conctyp : Entity_Id);
327 -- For each entry family in a concurrent type, create an anonymous array
328 -- type of the right size, and add a component to the corresponding_record.
330 function Concurrent_Object
331 (Spec_Id : Entity_Id;
332 Conc_Typ : Entity_Id) return Entity_Id;
333 -- Given a subprogram entity Spec_Id and concurrent type Conc_Typ, return
334 -- the entity associated with the concurrent object in the Protected_Body_
335 -- Subprogram or the Task_Body_Procedure of Spec_Id. The returned entity
336 -- denotes formal parameter _O, _object or _task.
338 function Copy_Result_Type (Res : Node_Id) return Node_Id;
339 -- Copy the result type of a function specification, when building the
340 -- internal operation corresponding to a protected function, or when
341 -- expanding an access to protected function. If the result is an anonymous
342 -- access to subprogram itself, we need to create a new signature with the
343 -- same parameter names and the same resolved types, but with new entities
344 -- for the formals.
346 function Create_Secondary_Stack_For_Task (T : Node_Id) return Boolean;
347 -- Return whether a secondary stack for the task T should be created by the
348 -- expander. The secondary stack for a task will be created by the expander
349 -- if the size of the stack has been specified by the Secondary_Stack_Size
350 -- representation aspect and either the No_Implicit_Heap_Allocations or
351 -- No_Implicit_Task_Allocations restrictions are in effect and the
352 -- No_Secondary_Stack restriction is not.
354 procedure Debug_Private_Data_Declarations (Decls : List_Id);
355 -- Decls is a list which may contain the declarations created by Install_
356 -- Private_Data_Declarations. All generated entities are marked as needing
357 -- debug info and debug nodes are manually generation where necessary. This
358 -- step of the expansion must to be done after private data has been moved
359 -- to its final resting scope to ensure proper visibility of debug objects.
361 procedure Ensure_Statement_Present (Loc : Source_Ptr; Alt : Node_Id);
362 -- If control flow optimizations are suppressed, and Alt is an accept,
363 -- delay, or entry call alternative with no trailing statements, insert
364 -- a null trailing statement with the given Loc (which is the sloc of
365 -- the accept, delay, or entry call statement). There might not be any
366 -- generated code for the accept, delay, or entry call itself (the effect
367 -- of these statements is part of the general processing done for the
368 -- enclosing selective accept, timed entry call, or asynchronous select),
369 -- and the null statement is there to carry the sloc of that statement to
370 -- the back-end for trace-based coverage analysis purposes.
372 procedure Extract_Dispatching_Call
373 (N : Node_Id;
374 Call_Ent : out Entity_Id;
375 Object : out Entity_Id;
376 Actuals : out List_Id;
377 Formals : out List_Id);
378 -- Given a dispatching call, extract the entity of the name of the call,
379 -- its actual dispatching object, its actual parameters and the formal
380 -- parameters of the overridden interface-level version. If the type of
381 -- the dispatching object is an access type then an explicit dereference
382 -- is returned in Object.
384 procedure Extract_Entry
385 (N : Node_Id;
386 Concval : out Node_Id;
387 Ename : out Node_Id;
388 Index : out Node_Id);
389 -- Given an entry call, returns the associated concurrent object, the entry
390 -- name, and the entry family index.
392 function Family_Offset
393 (Loc : Source_Ptr;
394 Hi : Node_Id;
395 Lo : Node_Id;
396 Ttyp : Entity_Id;
397 Cap : Boolean) return Node_Id;
398 -- Compute (Hi - Lo) for two entry family indexes. Hi is the index in an
399 -- accept statement, or the upper bound in the discrete subtype of an entry
400 -- declaration. Lo is the corresponding lower bound. Ttyp is the concurrent
401 -- type of the entry. If Cap is true, the result is capped according to
402 -- Entry_Family_Bound.
404 function Family_Size
405 (Loc : Source_Ptr;
406 Hi : Node_Id;
407 Lo : Node_Id;
408 Ttyp : Entity_Id;
409 Cap : Boolean) return Node_Id;
410 -- Compute (Hi - Lo) + 1 Max 0, to determine the number of entries in a
411 -- family, and handle properly the superflat case. This is equivalent to
412 -- the use of 'Length on the index type, but must use Family_Offset to
413 -- handle properly the case of bounds that depend on discriminants. If
414 -- Cap is true, the result is capped according to Entry_Family_Bound.
416 procedure Find_Enclosing_Context
417 (N : Node_Id;
418 Context : out Node_Id;
419 Context_Id : out Entity_Id;
420 Context_Decls : out List_Id);
421 -- Subsidiary routine to procedures Build_Activation_Chain_Entity and
422 -- Build_Master_Entity. Given an arbitrary node in the tree, find the
423 -- nearest enclosing body, block, package, or return statement and return
424 -- its constituents. Context is the enclosing construct, Context_Id is
425 -- the scope of Context_Id and Context_Decls is the declarative list of
426 -- Context.
428 function Index_Object (Spec_Id : Entity_Id) return Entity_Id;
429 -- Given a subprogram identifier, return the entity which is associated
430 -- with the protection entry index in the Protected_Body_Subprogram or
431 -- the Task_Body_Procedure of Spec_Id. The returned entity denotes formal
432 -- parameter _E.
434 function Is_Potentially_Large_Family
435 (Base_Index : Entity_Id;
436 Conctyp : Entity_Id;
437 Lo : Node_Id;
438 Hi : Node_Id) return Boolean;
439 -- Determine whether an entry family is potentially large because one of
440 -- its bounds denotes a discrminant.
442 function Is_Private_Primitive_Subprogram (Id : Entity_Id) return Boolean;
443 -- Determine whether Id is a function or a procedure and is marked as a
444 -- private primitive.
446 function Null_Statements (Stats : List_Id) return Boolean;
447 -- Used to check DO-END sequence. Checks for equivalent of DO NULL; END.
448 -- Allows labels, and pragma Warnings/Unreferenced in the sequence as well
449 -- to still count as null. Returns True for a null sequence. The argument
450 -- is the list of statements from the DO-END sequence.
452 function Parameter_Block_Pack
453 (Loc : Source_Ptr;
454 Blk_Typ : Entity_Id;
455 Actuals : List_Id;
456 Formals : List_Id;
457 Decls : List_Id;
458 Stmts : List_Id) return Entity_Id;
459 -- Set the components of the generated parameter block with the values
460 -- of the actual parameters. Generate aliased temporaries to capture the
461 -- values for types that are passed by copy. Otherwise generate a reference
462 -- to the actual's value. Return the address of the aggregate block.
463 -- Generate:
464 -- Jnn1 : alias <formal-type1>;
465 -- Jnn1 := <actual1>;
466 -- ...
467 -- P : Blk_Typ := (
468 -- Jnn1'unchecked_access;
469 -- <actual2>'reference;
470 -- ...);
472 function Parameter_Block_Unpack
473 (Loc : Source_Ptr;
474 P : Entity_Id;
475 Actuals : List_Id;
476 Formals : List_Id) return List_Id;
477 -- Retrieve the values of the components from the parameter block and
478 -- assign then to the original actual parameters. Generate:
479 -- <actual1> := P.<formal1>;
480 -- ...
481 -- <actualN> := P.<formalN>;
483 procedure Reset_Scopes_To (Bod : Node_Id; E : Entity_Id);
484 -- Reset the scope of declarations and blocks at the top level of Bod to
485 -- be E. Bod is either a block or a subprogram body. Used after expanding
486 -- various kinds of entry bodies into their corresponding constructs. This
487 -- is needed during unnesting to determine whether a body generated for an
488 -- entry or an accept alternative includes uplevel references.
490 function Trivial_Accept_OK return Boolean;
491 -- If there is no DO-END block for an accept, or if the DO-END block has
492 -- only null statements, then it is possible to do the Rendezvous with much
493 -- less overhead using the Accept_Trivial routine in the run-time library.
494 -- However, this is not always a valid optimization. Whether it is valid or
495 -- not depends on the Task_Dispatching_Policy. The issue is whether a full
496 -- rescheduling action is required or not. In FIFO_Within_Priorities, such
497 -- a rescheduling is required, so this optimization is not allowed. This
498 -- function returns True if the optimization is permitted.
500 -----------------------------
501 -- Actual_Index_Expression --
502 -----------------------------
504 function Actual_Index_Expression
505 (Sloc : Source_Ptr;
506 Ent : Entity_Id;
507 Index : Node_Id;
508 Tsk : Entity_Id) return Node_Id
510 Ttyp : constant Entity_Id := Etype (Tsk);
511 Expr : Node_Id;
512 Num : Node_Id;
513 Lo : Node_Id;
514 Hi : Node_Id;
515 Prev : Entity_Id;
516 S : Node_Id;
518 function Actual_Family_Offset (Hi, Lo : Node_Id) return Node_Id;
519 -- Compute difference between bounds of entry family
521 --------------------------
522 -- Actual_Family_Offset --
523 --------------------------
525 function Actual_Family_Offset (Hi, Lo : Node_Id) return Node_Id is
527 function Actual_Discriminant_Ref (Bound : Node_Id) return Node_Id;
528 -- Replace a reference to a discriminant with a selected component
529 -- denoting the discriminant of the target task.
531 -----------------------------
532 -- Actual_Discriminant_Ref --
533 -----------------------------
535 function Actual_Discriminant_Ref (Bound : Node_Id) return Node_Id is
536 Typ : constant Entity_Id := Etype (Bound);
537 B : Node_Id;
539 begin
540 if not Is_Entity_Name (Bound)
541 or else Ekind (Entity (Bound)) /= E_Discriminant
542 then
543 if Nkind (Bound) = N_Attribute_Reference then
544 return Bound;
545 else
546 B := New_Copy_Tree (Bound);
547 end if;
549 else
550 B :=
551 Make_Selected_Component (Sloc,
552 Prefix => New_Copy_Tree (Tsk),
553 Selector_Name => New_Occurrence_Of (Entity (Bound), Sloc));
555 Analyze_And_Resolve (B, Typ);
556 end if;
558 return
559 Make_Attribute_Reference (Sloc,
560 Attribute_Name => Name_Pos,
561 Prefix => New_Occurrence_Of (Etype (Bound), Sloc),
562 Expressions => New_List (B));
563 end Actual_Discriminant_Ref;
565 -- Start of processing for Actual_Family_Offset
567 begin
568 return
569 Make_Op_Subtract (Sloc,
570 Left_Opnd => Actual_Discriminant_Ref (Hi),
571 Right_Opnd => Actual_Discriminant_Ref (Lo));
572 end Actual_Family_Offset;
574 -- Start of processing for Actual_Index_Expression
576 begin
577 -- The queues of entries and entry families appear in textual order in
578 -- the associated record. The entry index is computed as the sum of the
579 -- number of queues for all entries that precede the designated one, to
580 -- which is added the index expression, if this expression denotes a
581 -- member of a family.
583 -- The following is a place holder for the count of simple entries
585 Num := Make_Integer_Literal (Sloc, 1);
587 -- We construct an expression which is a series of addition operations.
588 -- See comments in Entry_Index_Expression, which is identical in
589 -- structure.
591 if Present (Index) then
592 S := Entry_Index_Type (Ent);
594 -- First make sure the index is in range if requested. The index type
595 -- has been directly set on the prefix, see Resolve_Entry.
597 if Do_Range_Check (Index) then
598 Generate_Range_Check
599 (Index, Etype (Prefix (Parent (Index))), CE_Range_Check_Failed);
600 end if;
602 Expr :=
603 Make_Op_Add (Sloc,
604 Left_Opnd => Num,
605 Right_Opnd =>
606 Actual_Family_Offset (
607 Make_Attribute_Reference (Sloc,
608 Attribute_Name => Name_Pos,
609 Prefix => New_Occurrence_Of (Base_Type (S), Sloc),
610 Expressions => New_List (Relocate_Node (Index))),
611 Type_Low_Bound (S)));
612 else
613 Expr := Num;
614 end if;
616 -- Now add lengths of preceding entries and entry families
618 Prev := First_Entity (Ttyp);
619 while Chars (Prev) /= Chars (Ent)
620 or else Ekind (Prev) /= Ekind (Ent)
621 or else not Sem_Ch6.Type_Conformant (Ent, Prev)
622 loop
623 if Ekind (Prev) = E_Entry then
624 Set_Intval (Num, Intval (Num) + 1);
626 elsif Ekind (Prev) = E_Entry_Family then
627 S := Entry_Index_Type (Prev);
629 -- The need for the following full view retrieval stems from this
630 -- complex case of nested generics and tasking:
632 -- generic
633 -- type Formal_Index is range <>;
634 -- ...
635 -- package Outer is
636 -- type Index is private;
637 -- generic
638 -- ...
639 -- package Inner is
640 -- procedure P;
641 -- end Inner;
642 -- private
643 -- type Index is new Formal_Index range 1 .. 10;
644 -- end Outer;
646 -- package body Outer is
647 -- task type T is
648 -- entry Fam (Index); -- (2)
649 -- entry E;
650 -- end T;
651 -- package body Inner is -- (3)
652 -- procedure P is
653 -- begin
654 -- T.E; -- (1)
655 -- end P;
656 -- end Inner;
657 -- ...
659 -- We are currently building the index expression for the entry
660 -- call "T.E" (1). Part of the expansion must mention the range
661 -- of the discrete type "Index" (2) of entry family "Fam".
663 -- However only the private view of type "Index" is available to
664 -- the inner generic (3) because there was no prior mention of
665 -- the type inside "Inner". This visibility requirement is
666 -- implicit and cannot be detected during the construction of
667 -- the generic trees and needs special handling.
669 if In_Instance_Body
670 and then Is_Private_Type (S)
671 and then Present (Full_View (S))
672 then
673 S := Full_View (S);
674 end if;
676 Lo := Type_Low_Bound (S);
677 Hi := Type_High_Bound (S);
679 Expr :=
680 Make_Op_Add (Sloc,
681 Left_Opnd => Expr,
682 Right_Opnd =>
683 Make_Op_Add (Sloc,
684 Left_Opnd => Actual_Family_Offset (Hi, Lo),
685 Right_Opnd => Make_Integer_Literal (Sloc, 1)));
687 -- Other components are anonymous types to be ignored
689 else
690 null;
691 end if;
693 Next_Entity (Prev);
694 end loop;
696 return Expr;
697 end Actual_Index_Expression;
699 --------------------------
700 -- Add_Formal_Renamings --
701 --------------------------
703 procedure Add_Formal_Renamings
704 (Spec : Node_Id;
705 Decls : List_Id;
706 Ent : Entity_Id;
707 Loc : Source_Ptr)
709 Ptr : constant Entity_Id :=
710 Defining_Identifier
711 (Next (First (Parameter_Specifications (Spec))));
712 -- The name of the formal that holds the address of the parameter block
713 -- for the call.
715 Comp : Entity_Id;
716 Decl : Node_Id;
717 Formal : Entity_Id;
718 New_F : Entity_Id;
719 Renamed_Formal : Node_Id;
721 begin
722 Formal := First_Formal (Ent);
723 while Present (Formal) loop
724 Comp := Entry_Component (Formal);
725 New_F :=
726 Make_Defining_Identifier (Sloc (Formal),
727 Chars => Chars (Formal));
728 Set_Etype (New_F, Etype (Formal));
729 Set_Scope (New_F, Ent);
731 -- Now we set debug info needed on New_F even though it does not come
732 -- from source, so that the debugger will get the right information
733 -- for these generated names.
735 Set_Debug_Info_Needed (New_F);
737 if Ekind (Formal) = E_In_Parameter then
738 Mutate_Ekind (New_F, E_Constant);
739 else
740 Mutate_Ekind (New_F, E_Variable);
741 Set_Extra_Constrained (New_F, Extra_Constrained (Formal));
742 end if;
744 Set_Actual_Subtype (New_F, Actual_Subtype (Formal));
746 Renamed_Formal :=
747 Make_Selected_Component (Loc,
748 Prefix =>
749 Make_Explicit_Dereference (Loc,
750 Unchecked_Convert_To (Entry_Parameters_Type (Ent),
751 Make_Identifier (Loc, Chars (Ptr)))),
752 Selector_Name => New_Occurrence_Of (Comp, Loc));
754 Decl :=
755 Build_Renamed_Formal_Declaration
756 (New_F, Formal, Comp, Renamed_Formal);
758 Append (Decl, Decls);
759 Set_Renamed_Object (Formal, New_F);
760 Next_Formal (Formal);
761 end loop;
762 end Add_Formal_Renamings;
764 ------------------------
765 -- Add_Object_Pointer --
766 ------------------------
768 procedure Add_Object_Pointer
769 (Loc : Source_Ptr;
770 Conc_Typ : Entity_Id;
771 Decls : List_Id)
773 Rec_Typ : constant Entity_Id := Corresponding_Record_Type (Conc_Typ);
774 Decl : Node_Id;
775 Obj_Ptr : Node_Id;
777 begin
778 -- Create the renaming declaration for the Protection object of a
779 -- protected type. _Object is used by Complete_Entry_Body.
780 -- ??? An attempt to make this a renaming was unsuccessful.
782 -- Build the entity for the access type
784 Obj_Ptr :=
785 Make_Defining_Identifier (Loc,
786 New_External_Name (Chars (Rec_Typ), 'P'));
788 -- Generate:
789 -- _object : poVP := poVP!O;
791 Decl :=
792 Make_Object_Declaration (Loc,
793 Defining_Identifier => Make_Defining_Identifier (Loc, Name_uObject),
794 Object_Definition => New_Occurrence_Of (Obj_Ptr, Loc),
795 Expression =>
796 Unchecked_Convert_To (Obj_Ptr, Make_Identifier (Loc, Name_uO)));
797 Set_Debug_Info_Needed (Defining_Identifier (Decl));
798 Prepend_To (Decls, Decl);
800 -- Generate:
801 -- type poVP is access poV;
803 Decl :=
804 Make_Full_Type_Declaration (Loc,
805 Defining_Identifier =>
806 Obj_Ptr,
807 Type_Definition =>
808 Make_Access_To_Object_Definition (Loc,
809 Subtype_Indication =>
810 New_Occurrence_Of (Rec_Typ, Loc)));
811 Set_Debug_Info_Needed (Defining_Identifier (Decl));
812 Prepend_To (Decls, Decl);
813 end Add_Object_Pointer;
815 -----------------------
816 -- Build_Accept_Body --
817 -----------------------
819 function Build_Accept_Body (Astat : Node_Id) return Node_Id is
820 Loc : constant Source_Ptr := Sloc (Astat);
821 Stats : constant Node_Id := Handled_Statement_Sequence (Astat);
822 New_S : Node_Id;
823 Hand : Node_Id;
824 Call : Node_Id;
825 Ohandle : Node_Id;
827 begin
828 -- At the end of the statement sequence, Complete_Rendezvous is called.
829 -- A label skipping the Complete_Rendezvous, and all other accept
830 -- processing, has already been added for the expansion of requeue
831 -- statements. The Sloc is copied from the last statement since it
832 -- is really part of this last statement.
834 Call :=
835 Build_Runtime_Call
836 (Sloc (Last (Statements (Stats))), RE_Complete_Rendezvous);
837 Insert_Before (Last (Statements (Stats)), Call);
838 Analyze (Call);
840 -- Ada 2022 (AI12-0279)
842 if Has_Yield_Aspect (Entity (Entry_Direct_Name (Astat)))
843 and then RTE_Available (RE_Yield)
844 then
845 Insert_Action_After (Call,
846 Make_Procedure_Call_Statement (Loc,
847 New_Occurrence_Of (RTE (RE_Yield), Loc)));
848 end if;
850 -- If exception handlers are present, then append Complete_Rendezvous
851 -- calls to the handlers, and construct the required outer block. As
852 -- above, the Sloc is copied from the last statement in the sequence.
854 if Present (Exception_Handlers (Stats)) then
855 Hand := First (Exception_Handlers (Stats));
856 while Present (Hand) loop
857 Call :=
858 Build_Runtime_Call
859 (Sloc (Last (Statements (Hand))), RE_Complete_Rendezvous);
860 Append (Call, Statements (Hand));
861 Analyze (Call);
863 -- Ada 2022 (AI12-0279)
865 if Has_Yield_Aspect (Entity (Entry_Direct_Name (Astat)))
866 and then RTE_Available (RE_Yield)
867 then
868 Insert_Action_After (Call,
869 Make_Procedure_Call_Statement (Loc,
870 New_Occurrence_Of (RTE (RE_Yield), Loc)));
871 end if;
873 Next (Hand);
874 end loop;
876 New_S :=
877 Make_Handled_Sequence_Of_Statements (Loc,
878 Statements => New_List (
879 Make_Block_Statement (Loc,
880 Handled_Statement_Sequence => Stats)));
882 else
883 New_S := Stats;
884 end if;
886 -- At this stage we know that the new statement sequence does
887 -- not have an exception handler part, so we supply one to call
888 -- Exceptional_Complete_Rendezvous. This handler is
890 -- when all others =>
891 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
893 -- We handle Abort_Signal to make sure that we properly catch the abort
894 -- case and wake up the caller.
896 Call :=
897 Make_Procedure_Call_Statement (Sloc (Stats),
898 Name => New_Occurrence_Of (
899 RTE (RE_Exceptional_Complete_Rendezvous), Sloc (Stats)),
900 Parameter_Associations => New_List (
901 Make_Function_Call (Sloc (Stats),
902 Name =>
903 New_Occurrence_Of
904 (RTE (RE_Get_GNAT_Exception), Sloc (Stats)))));
906 Ohandle := Make_Others_Choice (Loc);
907 Set_All_Others (Ohandle);
909 Set_Exception_Handlers (New_S,
910 New_List (
911 Make_Implicit_Exception_Handler (Loc,
912 Exception_Choices => New_List (Ohandle),
914 Statements => New_List (Call))));
916 -- Ada 2022 (AI12-0279)
918 if Has_Yield_Aspect (Entity (Entry_Direct_Name (Astat)))
919 and then RTE_Available (RE_Yield)
920 then
921 Insert_Action_After (Call,
922 Make_Procedure_Call_Statement (Loc,
923 New_Occurrence_Of (RTE (RE_Yield), Loc)));
924 end if;
926 Set_Parent (New_S, Astat); -- temp parent for Analyze call
927 Analyze_Exception_Handlers (Exception_Handlers (New_S));
928 Expand_Exception_Handlers (New_S);
930 -- Exceptional_Complete_Rendezvous must be called with abort still
931 -- deferred, which is the case for a "when all others" handler.
933 return New_S;
934 end Build_Accept_Body;
936 -----------------------------------
937 -- Build_Activation_Chain_Entity --
938 -----------------------------------
940 procedure Build_Activation_Chain_Entity (N : Node_Id) is
941 function Has_Activation_Chain (Stmt : Node_Id) return Boolean;
942 -- Determine whether an extended return statement has activation chain
944 --------------------------
945 -- Has_Activation_Chain --
946 --------------------------
948 function Has_Activation_Chain (Stmt : Node_Id) return Boolean is
949 Decl : Node_Id;
951 begin
952 Decl := First (Return_Object_Declarations (Stmt));
953 while Present (Decl) loop
954 if Nkind (Decl) = N_Object_Declaration
955 and then Chars (Defining_Identifier (Decl)) = Name_uChain
956 then
957 return True;
958 end if;
960 Next (Decl);
961 end loop;
963 return False;
964 end Has_Activation_Chain;
966 -- Local variables
968 Context : Node_Id;
969 Context_Id : Entity_Id;
970 Decls : List_Id;
972 -- Start of processing for Build_Activation_Chain_Entity
974 begin
975 -- No action needed if the run-time has no tasking support
977 if Global_No_Tasking then
978 return;
979 end if;
981 -- Activation chain is never used for sequential elaboration policy, see
982 -- comment for Create_Restricted_Task_Sequential in s-tarest.ads).
984 if Partition_Elaboration_Policy = 'S' then
985 return;
986 end if;
988 Find_Enclosing_Context (N, Context, Context_Id, Decls);
990 -- If activation chain entity has not been declared already, create one
992 if Nkind (Context) = N_Extended_Return_Statement
993 or else No (Activation_Chain_Entity (Context))
994 then
995 -- Since extended return statements do not store the entity of the
996 -- chain, examine the return object declarations to avoid creating
997 -- a duplicate.
999 if Nkind (Context) = N_Extended_Return_Statement
1000 and then Has_Activation_Chain (Context)
1001 then
1002 return;
1003 end if;
1005 declare
1006 Loc : constant Source_Ptr := Sloc (Context);
1007 Chain : Entity_Id;
1008 Decl : Node_Id;
1010 begin
1011 Chain := Make_Defining_Identifier (Sloc (N), Name_uChain);
1013 -- Note: An extended return statement is not really a task
1014 -- activator, but it does have an activation chain on which to
1015 -- store the tasks temporarily. On successful return, the tasks
1016 -- on this chain are moved to the chain passed in by the caller.
1017 -- We do not build an Activation_Chain_Entity for an extended
1018 -- return statement, because we do not want to build a call to
1019 -- Activate_Tasks. Task activation is the responsibility of the
1020 -- caller.
1022 if Nkind (Context) /= N_Extended_Return_Statement then
1023 Set_Activation_Chain_Entity (Context, Chain);
1024 end if;
1026 Decl :=
1027 Make_Object_Declaration (Loc,
1028 Defining_Identifier => Chain,
1029 Aliased_Present => True,
1030 Object_Definition =>
1031 New_Occurrence_Of (RTE (RE_Activation_Chain), Loc));
1033 Prepend_To (Decls, Decl);
1035 -- Ensure that _chain appears in the proper scope of the context
1037 if Context_Id /= Current_Scope then
1038 Push_Scope (Context_Id);
1039 Analyze (Decl);
1040 Pop_Scope;
1041 else
1042 Analyze (Decl);
1043 end if;
1044 end;
1045 end if;
1046 end Build_Activation_Chain_Entity;
1048 ----------------------------
1049 -- Build_Barrier_Function --
1050 ----------------------------
1052 function Build_Barrier_Function
1053 (N : Node_Id;
1054 Ent : Entity_Id;
1055 Pid : Entity_Id) return Node_Id
1057 Ent_Formals : constant Node_Id := Entry_Body_Formal_Part (N);
1058 Cond : constant Node_Id := Condition (Ent_Formals);
1059 Loc : constant Source_Ptr := Sloc (Cond);
1060 Func_Id : constant Entity_Id := Barrier_Function (Ent);
1061 Op_Decls : constant List_Id := New_List;
1062 Stmt : Node_Id;
1063 Func_Body : Node_Id;
1065 begin
1066 -- Add a declaration for the Protection object, renaming declarations
1067 -- for the discriminals and privals and finally a declaration for the
1068 -- entry family index (if applicable).
1070 Install_Private_Data_Declarations (Sloc (N),
1071 Spec_Id => Func_Id,
1072 Conc_Typ => Pid,
1073 Body_Nod => N,
1074 Decls => Op_Decls,
1075 Barrier => True,
1076 Family => Ekind (Ent) = E_Entry_Family);
1078 -- If compiling with -fpreserve-control-flow, make sure we insert an
1079 -- IF statement so that the back-end knows to generate a conditional
1080 -- branch instruction, even if the condition is just the name of a
1081 -- boolean object. Note that Expand_N_If_Statement knows to preserve
1082 -- such redundant IF statements under -fpreserve-control-flow
1083 -- (whether coming from this routine, or directly from source).
1085 if Opt.Suppress_Control_Flow_Optimizations then
1086 Stmt :=
1087 Make_Implicit_If_Statement (Cond,
1088 Condition => Cond,
1089 Then_Statements => New_List (
1090 Make_Simple_Return_Statement (Loc,
1091 New_Occurrence_Of (Standard_True, Loc))),
1093 Else_Statements => New_List (
1094 Make_Simple_Return_Statement (Loc,
1095 New_Occurrence_Of (Standard_False, Loc))));
1097 else
1098 Stmt := Make_Simple_Return_Statement (Loc, Cond);
1099 end if;
1101 -- Note: the condition in the barrier function needs to be properly
1102 -- processed for the C/Fortran boolean possibility, but this happens
1103 -- automatically since the return statement does this normalization.
1105 Func_Body :=
1106 Make_Subprogram_Body (Loc,
1107 Specification =>
1108 Build_Barrier_Function_Specification (Loc,
1109 Make_Defining_Identifier (Loc, Chars (Func_Id))),
1110 Declarations => Op_Decls,
1111 Handled_Statement_Sequence =>
1112 Make_Handled_Sequence_Of_Statements (Loc,
1113 Statements => New_List (Stmt)));
1114 Set_Is_Entry_Barrier_Function (Func_Body);
1116 return Func_Body;
1117 end Build_Barrier_Function;
1119 ------------------------------------------
1120 -- Build_Barrier_Function_Specification --
1121 ------------------------------------------
1123 function Build_Barrier_Function_Specification
1124 (Loc : Source_Ptr;
1125 Def_Id : Entity_Id) return Node_Id
1127 begin
1128 Set_Debug_Info_Needed (Def_Id);
1130 return
1131 Make_Function_Specification (Loc,
1132 Defining_Unit_Name => Def_Id,
1133 Parameter_Specifications => New_List (
1134 Make_Parameter_Specification (Loc,
1135 Defining_Identifier =>
1136 Make_Defining_Identifier (Loc, Name_uO),
1137 Parameter_Type =>
1138 New_Occurrence_Of (RTE (RE_Address), Loc)),
1140 Make_Parameter_Specification (Loc,
1141 Defining_Identifier =>
1142 Make_Defining_Identifier (Loc, Name_uE),
1143 Parameter_Type =>
1144 New_Occurrence_Of (RTE (RE_Protected_Entry_Index), Loc))),
1146 Result_Definition =>
1147 New_Occurrence_Of (Standard_Boolean, Loc));
1148 end Build_Barrier_Function_Specification;
1150 --------------------------
1151 -- Build_Call_With_Task --
1152 --------------------------
1154 function Build_Call_With_Task
1155 (N : Node_Id;
1156 E : Entity_Id) return Node_Id
1158 Loc : constant Source_Ptr := Sloc (N);
1159 begin
1160 return
1161 Make_Function_Call (Loc,
1162 Name => New_Occurrence_Of (E, Loc),
1163 Parameter_Associations => New_List (Concurrent_Ref (N)));
1164 end Build_Call_With_Task;
1166 -----------------------------
1167 -- Build_Class_Wide_Master --
1168 -----------------------------
1170 procedure Build_Class_Wide_Master (Typ : Entity_Id) is
1171 Loc : constant Source_Ptr := Sloc (Typ);
1172 Master_Decl : Node_Id;
1173 Master_Id : Entity_Id;
1174 Master_Scope : Entity_Id;
1175 Name_Id : Node_Id;
1176 Related_Node : Node_Id;
1177 Ren_Decl : Node_Id;
1179 begin
1180 -- No action needed if the run-time has no tasking support
1182 if Global_No_Tasking then
1183 return;
1184 end if;
1186 -- Find the declaration that created the access type, which is either a
1187 -- type declaration, or an object declaration with an access definition,
1188 -- in which case the type is anonymous.
1190 if Is_Itype (Typ) then
1191 Related_Node := Associated_Node_For_Itype (Typ);
1192 else
1193 Related_Node := Parent (Typ);
1194 end if;
1196 Master_Scope := Find_Master_Scope (Typ);
1198 -- Nothing to do if the master scope already contains a _master entity.
1199 -- The only exception to this is the following scenario:
1201 -- Source_Scope
1202 -- Transient_Scope_1
1203 -- _master
1205 -- Transient_Scope_2
1206 -- use of master
1208 -- In this case the source scope is marked as having the master entity
1209 -- even though the actual declaration appears inside an inner scope. If
1210 -- the second transient scope requires a _master, it cannot use the one
1211 -- already declared because the entity is not visible.
1213 Name_Id := Make_Identifier (Loc, Name_uMaster);
1214 Master_Decl := Empty;
1216 if not Has_Master_Entity (Master_Scope)
1217 or else No (Current_Entity_In_Scope (Name_Id))
1218 then
1219 declare
1220 Ins_Nod : Node_Id;
1221 Par_Nod : Node_Id;
1223 begin
1224 Master_Decl := Build_Master_Declaration (Loc);
1226 -- Ensure that the master declaration is placed before its use
1228 Ins_Nod := Find_Hook_Context (Related_Node);
1229 while not Is_List_Member (Ins_Nod) loop
1230 Ins_Nod := Parent (Ins_Nod);
1231 end loop;
1233 Par_Nod := Parent (List_Containing (Ins_Nod));
1235 -- For internal blocks created by Wrap_Loop_Statement, Wrap_
1236 -- Statements_In_Block, and Build_Abort_Undefer_Block, remember
1237 -- that they have a task master entity declaration; required by
1238 -- Build_Master_Entity to avoid creating another master entity,
1239 -- and also ensures that subsequent calls to Find_Master_Scope
1240 -- return this scope as the master scope of Typ.
1242 if Is_Internal_Block (Par_Nod) then
1243 Set_Has_Master_Entity (Entity (Identifier (Par_Nod)));
1245 elsif Nkind (Par_Nod) = N_Handled_Sequence_Of_Statements
1246 and then Is_Internal_Block (Parent (Par_Nod))
1247 then
1248 Set_Has_Master_Entity (Entity (Identifier (Parent (Par_Nod))));
1250 -- Otherwise remember that this scope has an associated task
1251 -- master entity declaration.
1253 else
1254 Set_Has_Master_Entity (Master_Scope);
1255 end if;
1257 Insert_Before (First (List_Containing (Ins_Nod)), Master_Decl);
1258 Analyze (Master_Decl);
1260 -- Mark the containing scope as a task master. Masters associated
1261 -- with return statements are already marked at this stage (see
1262 -- Analyze_Subprogram_Body).
1264 if Ekind (Current_Scope) /= E_Return_Statement then
1265 declare
1266 Par : Node_Id := Related_Node;
1268 begin
1269 while Nkind (Par) /= N_Compilation_Unit loop
1270 Par := Parent (Par);
1272 -- If we fall off the top, we are at the outer level,
1273 -- and the environment task is our effective master,
1274 -- so nothing to mark.
1276 if Nkind (Par) in
1277 N_Block_Statement | N_Subprogram_Body | N_Task_Body
1278 then
1279 Set_Is_Task_Master (Par);
1280 exit;
1281 end if;
1282 end loop;
1283 end;
1284 end if;
1285 end;
1286 end if;
1288 Master_Id :=
1289 Make_Defining_Identifier (Loc, New_External_Name (Chars (Typ), 'M'));
1291 -- Generate:
1292 -- typeMnn renames _master;
1294 Ren_Decl :=
1295 Make_Object_Renaming_Declaration (Loc,
1296 Defining_Identifier => Master_Id,
1297 Subtype_Mark => New_Occurrence_Of (Standard_Integer, Loc),
1298 Name => Name_Id);
1300 -- If the master is declared locally, add the renaming declaration
1301 -- immediately after it, to prevent access-before-elaboration in the
1302 -- back-end.
1304 if Present (Master_Decl) then
1305 Insert_After (Master_Decl, Ren_Decl);
1306 Analyze (Ren_Decl);
1308 else
1309 Insert_Action (Related_Node, Ren_Decl);
1310 end if;
1312 Set_Master_Id (Typ, Master_Id);
1313 end Build_Class_Wide_Master;
1315 --------------------------------
1316 -- Build_Corresponding_Record --
1317 --------------------------------
1319 function Build_Corresponding_Record
1320 (N : Node_Id;
1321 Ctyp : Entity_Id;
1322 Loc : Source_Ptr) return Node_Id
1324 Rec_Ent : constant Entity_Id :=
1325 Make_Defining_Identifier
1326 (Loc, New_External_Name (Chars (Ctyp), 'V'));
1327 Disc : Entity_Id;
1328 Dlist : List_Id;
1329 New_Disc : Entity_Id;
1330 Cdecls : List_Id;
1332 begin
1333 Set_Corresponding_Record_Type (Ctyp, Rec_Ent);
1334 Mutate_Ekind (Rec_Ent, E_Record_Type);
1335 Set_Has_Delayed_Freeze (Rec_Ent, Has_Delayed_Freeze (Ctyp));
1336 Set_Is_Concurrent_Record_Type (Rec_Ent, True);
1337 Set_Corresponding_Concurrent_Type (Rec_Ent, Ctyp);
1338 Set_Stored_Constraint (Rec_Ent, No_Elist);
1339 Cdecls := New_List;
1341 -- Use discriminals to create list of discriminants for record, and
1342 -- create new discriminals for use in default expressions, etc. It is
1343 -- worth noting that a task discriminant gives rise to 5 entities;
1345 -- a) The original discriminant.
1346 -- b) The discriminal for use in the task.
1347 -- c) The discriminant of the corresponding record.
1348 -- d) The discriminal for the init proc of the corresponding record.
1349 -- e) The local variable that renames the discriminant in the procedure
1350 -- for the task body.
1352 -- In fact the discriminals b) are used in the renaming declarations
1353 -- for e). See details in einfo (Handling of Discriminants).
1355 if Present (Discriminant_Specifications (N)) then
1356 Dlist := New_List;
1357 Disc := First_Discriminant (Ctyp);
1359 while Present (Disc) loop
1360 New_Disc := CR_Discriminant (Disc);
1362 Append_To (Dlist,
1363 Make_Discriminant_Specification (Loc,
1364 Defining_Identifier => New_Disc,
1365 Discriminant_Type =>
1366 New_Occurrence_Of (Etype (Disc), Loc),
1367 Expression =>
1368 New_Copy (Discriminant_Default_Value (Disc))));
1370 Next_Discriminant (Disc);
1371 end loop;
1373 else
1374 Dlist := No_List;
1375 end if;
1377 -- Now we can construct the record type declaration. Note that this
1378 -- record is "limited tagged". It is "limited" to reflect the underlying
1379 -- limitedness of the task or protected object that it represents, and
1380 -- ensuring for example that it is properly passed by reference. It is
1381 -- "tagged" to give support to dispatching calls through interfaces. We
1382 -- propagate here the list of interfaces covered by the concurrent type
1383 -- (Ada 2005: AI-345).
1385 return
1386 Make_Full_Type_Declaration (Loc,
1387 Defining_Identifier => Rec_Ent,
1388 Discriminant_Specifications => Dlist,
1389 Type_Definition =>
1390 Make_Record_Definition (Loc,
1391 Component_List =>
1392 Make_Component_List (Loc, Component_Items => Cdecls),
1393 Tagged_Present =>
1394 Ada_Version >= Ada_2005 and then Is_Tagged_Type (Ctyp),
1395 Interface_List => Interface_List (N),
1396 Limited_Present => True));
1397 end Build_Corresponding_Record;
1399 ---------------------------------
1400 -- Build_Dispatching_Tag_Check --
1401 ---------------------------------
1403 function Build_Dispatching_Tag_Check
1404 (K : Entity_Id;
1405 N : Node_Id) return Node_Id
1407 Loc : constant Source_Ptr := Sloc (N);
1409 begin
1410 return
1411 Make_Op_Or (Loc,
1412 Make_Op_Eq (Loc,
1413 Left_Opnd =>
1414 New_Occurrence_Of (K, Loc),
1415 Right_Opnd =>
1416 New_Occurrence_Of (RTE (RE_TK_Limited_Tagged), Loc)),
1418 Make_Op_Eq (Loc,
1419 Left_Opnd =>
1420 New_Occurrence_Of (K, Loc),
1421 Right_Opnd =>
1422 New_Occurrence_Of (RTE (RE_TK_Tagged), Loc)));
1423 end Build_Dispatching_Tag_Check;
1425 ----------------------------------
1426 -- Build_Entry_Count_Expression --
1427 ----------------------------------
1429 function Build_Entry_Count_Expression
1430 (Concurrent_Type : Entity_Id;
1431 Loc : Source_Ptr) return Node_Id
1433 Eindx : Nat;
1434 Ent : Entity_Id;
1435 Ecount : Node_Id;
1436 Lo : Node_Id;
1437 Hi : Node_Id;
1438 Typ : Entity_Id;
1439 Large : Boolean;
1441 begin
1442 -- Count number of non-family entries
1444 Eindx := 0;
1445 Ent := First_Entity (Concurrent_Type);
1446 while Present (Ent) loop
1447 if Ekind (Ent) = E_Entry then
1448 Eindx := Eindx + 1;
1449 end if;
1451 Next_Entity (Ent);
1452 end loop;
1454 Ecount := Make_Integer_Literal (Loc, Eindx);
1456 -- Loop through entry families building the addition nodes
1458 Ent := First_Entity (Concurrent_Type);
1459 while Present (Ent) loop
1460 if Ekind (Ent) = E_Entry_Family then
1461 Typ := Entry_Index_Type (Ent);
1462 Hi := Type_High_Bound (Typ);
1463 Lo := Type_Low_Bound (Typ);
1464 Large := Is_Potentially_Large_Family
1465 (Base_Type (Typ), Concurrent_Type, Lo, Hi);
1466 Ecount :=
1467 Make_Op_Add (Loc,
1468 Left_Opnd => Ecount,
1469 Right_Opnd =>
1470 Family_Size (Loc, Hi, Lo, Concurrent_Type, Large));
1471 end if;
1473 Next_Entity (Ent);
1474 end loop;
1476 return Ecount;
1477 end Build_Entry_Count_Expression;
1479 ------------------------------
1480 -- Build_Master_Declaration --
1481 ------------------------------
1483 function Build_Master_Declaration (Loc : Source_Ptr) return Node_Id is
1484 Master_Decl : Node_Id;
1486 begin
1487 -- Generate a dummy master if tasks or tasking hierarchies are
1488 -- prohibited.
1490 -- _Master : constant Integer := Library_Task_Level;
1492 if not Tasking_Allowed
1493 or else Restrictions.Set (No_Task_Hierarchy)
1494 or else not RTE_Available (RE_Current_Master)
1495 then
1496 Master_Decl :=
1497 Make_Object_Declaration (Loc,
1498 Defining_Identifier =>
1499 Make_Defining_Identifier (Loc, Name_uMaster),
1500 Constant_Present => True,
1501 Object_Definition =>
1502 New_Occurrence_Of (Standard_Integer, Loc),
1503 Expression =>
1504 Make_Integer_Literal (Loc, Library_Task_Level));
1506 -- Generate:
1507 -- _master : constant Integer := Current_Master.all;
1509 else
1510 Master_Decl :=
1511 Make_Object_Declaration (Loc,
1512 Defining_Identifier =>
1513 Make_Defining_Identifier (Loc, Name_uMaster),
1514 Constant_Present => True,
1515 Object_Definition =>
1516 New_Occurrence_Of (Standard_Integer, Loc),
1517 Expression =>
1518 Make_Explicit_Dereference (Loc,
1519 New_Occurrence_Of (RTE (RE_Current_Master), Loc)));
1520 end if;
1522 return Master_Decl;
1523 end Build_Master_Declaration;
1525 ---------------------------
1526 -- Build_Parameter_Block --
1527 ---------------------------
1529 function Build_Parameter_Block
1530 (Loc : Source_Ptr;
1531 Actuals : List_Id;
1532 Formals : List_Id;
1533 Decls : List_Id) return Entity_Id
1535 Actual : Entity_Id;
1536 Comp_Nam : Node_Id;
1537 Comps : List_Id;
1538 Formal : Entity_Id;
1539 Has_Comp : Boolean := False;
1540 Rec_Nam : Node_Id;
1542 begin
1543 Actual := First (Actuals);
1544 Comps := New_List;
1545 Formal := Defining_Identifier (First (Formals));
1547 while Present (Actual) loop
1548 if not Is_Controlling_Actual (Actual) then
1550 -- Generate:
1551 -- type Ann is access all <actual-type>
1553 Comp_Nam := Make_Temporary (Loc, 'A');
1554 Set_Is_Param_Block_Component_Type (Comp_Nam);
1556 Append_To (Decls,
1557 Make_Full_Type_Declaration (Loc,
1558 Defining_Identifier => Comp_Nam,
1559 Type_Definition =>
1560 Make_Access_To_Object_Definition (Loc,
1561 All_Present => True,
1562 Constant_Present => Ekind (Formal) = E_In_Parameter,
1563 Subtype_Indication =>
1564 New_Occurrence_Of (Etype (Actual), Loc))));
1566 -- Generate:
1567 -- Param : Ann;
1569 Append_To (Comps,
1570 Make_Component_Declaration (Loc,
1571 Defining_Identifier =>
1572 Make_Defining_Identifier (Loc, Chars (Formal)),
1573 Component_Definition =>
1574 Make_Component_Definition (Loc,
1575 Aliased_Present =>
1576 False,
1577 Subtype_Indication =>
1578 New_Occurrence_Of (Comp_Nam, Loc))));
1580 Has_Comp := True;
1581 end if;
1583 Next_Actual (Actual);
1584 Next_Formal_With_Extras (Formal);
1585 end loop;
1587 Rec_Nam := Make_Temporary (Loc, 'P');
1589 if Has_Comp then
1591 -- Generate:
1592 -- type Pnn is record
1593 -- Param1 : Ann1;
1594 -- ...
1595 -- ParamN : AnnN;
1597 -- where Pnn is a parameter wrapping record, Param1 .. ParamN are
1598 -- the original parameter names and Ann1 .. AnnN are the access to
1599 -- actual types.
1601 Append_To (Decls,
1602 Make_Full_Type_Declaration (Loc,
1603 Defining_Identifier =>
1604 Rec_Nam,
1605 Type_Definition =>
1606 Make_Record_Definition (Loc,
1607 Component_List =>
1608 Make_Component_List (Loc, Comps))));
1609 else
1610 -- Generate:
1611 -- type Pnn is null record;
1613 Append_To (Decls,
1614 Make_Full_Type_Declaration (Loc,
1615 Defining_Identifier =>
1616 Rec_Nam,
1617 Type_Definition =>
1618 Make_Record_Definition (Loc,
1619 Null_Present => True,
1620 Component_List => Empty)));
1621 end if;
1623 return Rec_Nam;
1624 end Build_Parameter_Block;
1626 --------------------------------------
1627 -- Build_Renamed_Formal_Declaration --
1628 --------------------------------------
1630 function Build_Renamed_Formal_Declaration
1631 (New_F : Entity_Id;
1632 Formal : Entity_Id;
1633 Comp : Entity_Id;
1634 Renamed_Formal : Node_Id) return Node_Id
1636 Loc : constant Source_Ptr := Sloc (New_F);
1637 Decl : Node_Id;
1639 begin
1640 -- If the formal is a tagged incomplete type, it is already passed
1641 -- by reference, so it is sufficient to rename the pointer component
1642 -- that corresponds to the actual. Otherwise we need to dereference
1643 -- the pointer component to obtain the actual.
1645 if Is_Incomplete_Type (Etype (Formal))
1646 and then Is_Tagged_Type (Etype (Formal))
1647 then
1648 Decl :=
1649 Make_Object_Renaming_Declaration (Loc,
1650 Defining_Identifier => New_F,
1651 Subtype_Mark => New_Occurrence_Of (Etype (Comp), Loc),
1652 Name => Renamed_Formal);
1654 else
1655 Decl :=
1656 Make_Object_Renaming_Declaration (Loc,
1657 Defining_Identifier => New_F,
1658 Subtype_Mark => New_Occurrence_Of (Etype (Formal), Loc),
1659 Name =>
1660 Make_Explicit_Dereference (Loc, Renamed_Formal));
1661 end if;
1663 return Decl;
1664 end Build_Renamed_Formal_Declaration;
1666 --------------------------
1667 -- Build_Wrapper_Bodies --
1668 --------------------------
1670 procedure Build_Wrapper_Bodies
1671 (Loc : Source_Ptr;
1672 Typ : Entity_Id;
1673 N : Node_Id)
1675 Rec_Typ : Entity_Id;
1677 function Build_Wrapper_Body
1678 (Loc : Source_Ptr;
1679 Subp_Id : Entity_Id;
1680 Obj_Typ : Entity_Id;
1681 Formals : List_Id) return Node_Id;
1682 -- Ada 2005 (AI-345): Build the body that wraps a primitive operation
1683 -- associated with a protected or task type. Subp_Id is the subprogram
1684 -- name which will be wrapped. Obj_Typ is the type of the new formal
1685 -- parameter which handles dispatching and object notation. Formals are
1686 -- the original formals of Subp_Id which will be explicitly replicated.
1688 ------------------------
1689 -- Build_Wrapper_Body --
1690 ------------------------
1692 function Build_Wrapper_Body
1693 (Loc : Source_Ptr;
1694 Subp_Id : Entity_Id;
1695 Obj_Typ : Entity_Id;
1696 Formals : List_Id) return Node_Id
1698 Body_Spec : Node_Id;
1700 begin
1701 Body_Spec := Build_Wrapper_Spec (Subp_Id, Obj_Typ, Formals);
1703 -- The subprogram is not overriding or is not a primitive declared
1704 -- between two views.
1706 if No (Body_Spec) then
1707 return Empty;
1708 end if;
1710 declare
1711 Actuals : List_Id := No_List;
1712 Conv_Id : Node_Id;
1713 First_Form : Node_Id;
1714 Formal : Node_Id;
1715 Nam : Node_Id;
1717 begin
1718 -- Map formals to actuals. Use the list built for the wrapper
1719 -- spec, skipping the object notation parameter.
1721 First_Form := First (Parameter_Specifications (Body_Spec));
1723 Formal := First_Form;
1724 Next (Formal);
1726 if Present (Formal) then
1727 Actuals := New_List;
1728 while Present (Formal) loop
1729 Append_To (Actuals,
1730 Make_Identifier (Loc,
1731 Chars => Chars (Defining_Identifier (Formal))));
1732 Next (Formal);
1733 end loop;
1734 end if;
1736 -- Special processing for primitives declared between a private
1737 -- type and its completion: the wrapper needs a properly typed
1738 -- parameter if the wrapped operation has a controlling first
1739 -- parameter. Note that this might not be the case for a function
1740 -- with a controlling result.
1742 if Is_Private_Primitive_Subprogram (Subp_Id) then
1743 if No (Actuals) then
1744 Actuals := New_List;
1745 end if;
1747 if Is_Controlling_Formal (First_Formal (Subp_Id)) then
1748 Prepend_To (Actuals,
1749 Unchecked_Convert_To
1750 (Corresponding_Concurrent_Type (Obj_Typ),
1751 Make_Identifier (Loc, Name_uO)));
1753 else
1754 Prepend_To (Actuals,
1755 Make_Identifier (Loc,
1756 Chars => Chars (Defining_Identifier (First_Form))));
1757 end if;
1759 Nam := New_Occurrence_Of (Subp_Id, Loc);
1760 else
1761 -- An access-to-variable object parameter requires an explicit
1762 -- dereference in the unchecked conversion. This case occurs
1763 -- when a protected entry wrapper must override an interface
1764 -- level procedure with interface access as first parameter.
1766 -- O.all.Subp_Id (Formal_1, ..., Formal_N)
1768 if Nkind (Parameter_Type (First_Form)) =
1769 N_Access_Definition
1770 then
1771 Conv_Id :=
1772 Make_Explicit_Dereference (Loc,
1773 Prefix => Make_Identifier (Loc, Name_uO));
1774 else
1775 Conv_Id := Make_Identifier (Loc, Name_uO);
1776 end if;
1778 Nam :=
1779 Make_Selected_Component (Loc,
1780 Prefix =>
1781 Unchecked_Convert_To
1782 (Corresponding_Concurrent_Type (Obj_Typ), Conv_Id),
1783 Selector_Name => New_Occurrence_Of (Subp_Id, Loc));
1784 end if;
1786 -- Create the subprogram body. For a function, the call to the
1787 -- actual subprogram has to be converted to the corresponding
1788 -- record if it is a controlling result.
1790 if Ekind (Subp_Id) = E_Function then
1791 declare
1792 Res : Node_Id;
1794 begin
1795 Res :=
1796 Make_Function_Call (Loc,
1797 Name => Nam,
1798 Parameter_Associations => Actuals);
1800 if Has_Controlling_Result (Subp_Id) then
1801 Res :=
1802 Unchecked_Convert_To
1803 (Corresponding_Record_Type (Etype (Subp_Id)), Res);
1804 end if;
1806 return
1807 Make_Subprogram_Body (Loc,
1808 Specification => Body_Spec,
1809 Declarations => Empty_List,
1810 Handled_Statement_Sequence =>
1811 Make_Handled_Sequence_Of_Statements (Loc,
1812 Statements => New_List (
1813 Make_Simple_Return_Statement (Loc, Res))));
1814 end;
1816 else
1817 return
1818 Make_Subprogram_Body (Loc,
1819 Specification => Body_Spec,
1820 Declarations => Empty_List,
1821 Handled_Statement_Sequence =>
1822 Make_Handled_Sequence_Of_Statements (Loc,
1823 Statements => New_List (
1824 Make_Procedure_Call_Statement (Loc,
1825 Name => Nam,
1826 Parameter_Associations => Actuals))));
1827 end if;
1828 end;
1829 end Build_Wrapper_Body;
1831 -- Start of processing for Build_Wrapper_Bodies
1833 begin
1834 if Is_Concurrent_Type (Typ) then
1835 Rec_Typ := Corresponding_Record_Type (Typ);
1836 else
1837 Rec_Typ := Typ;
1838 end if;
1840 -- Generate wrapper bodies for a concurrent type which implements an
1841 -- interface.
1843 if Present (Interfaces (Rec_Typ)) then
1844 declare
1845 Insert_Nod : Node_Id;
1846 Prim : Entity_Id;
1847 Prim_Elmt : Elmt_Id;
1848 Prim_Decl : Node_Id;
1849 Subp : Entity_Id;
1850 Wrap_Body : Node_Id;
1851 Wrap_Id : Entity_Id;
1853 begin
1854 Insert_Nod := N;
1856 -- Examine all primitive operations of the corresponding record
1857 -- type, looking for wrapper specs. Generate bodies in order to
1858 -- complete them.
1860 Prim_Elmt := First_Elmt (Primitive_Operations (Rec_Typ));
1861 while Present (Prim_Elmt) loop
1862 Prim := Node (Prim_Elmt);
1864 if (Ekind (Prim) = E_Function
1865 or else Ekind (Prim) = E_Procedure)
1866 and then Is_Primitive_Wrapper (Prim)
1867 then
1868 Subp := Wrapped_Entity (Prim);
1869 Prim_Decl := Parent (Parent (Prim));
1871 Wrap_Body :=
1872 Build_Wrapper_Body (Loc,
1873 Subp_Id => Subp,
1874 Obj_Typ => Rec_Typ,
1875 Formals => Parameter_Specifications (Parent (Subp)));
1876 Wrap_Id := Defining_Unit_Name (Specification (Wrap_Body));
1878 Set_Corresponding_Spec (Wrap_Body, Prim);
1879 Set_Corresponding_Body (Prim_Decl, Wrap_Id);
1881 Insert_After (Insert_Nod, Wrap_Body);
1882 Insert_Nod := Wrap_Body;
1884 Analyze (Wrap_Body);
1885 end if;
1887 Next_Elmt (Prim_Elmt);
1888 end loop;
1889 end;
1890 end if;
1891 end Build_Wrapper_Bodies;
1893 ------------------------
1894 -- Build_Wrapper_Spec --
1895 ------------------------
1897 function Build_Wrapper_Spec
1898 (Subp_Id : Entity_Id;
1899 Obj_Typ : Entity_Id;
1900 Formals : List_Id) return Node_Id
1902 function Overriding_Possible
1903 (Iface_Op : Entity_Id;
1904 Wrapper : Entity_Id) return Boolean;
1905 -- Determine whether a primitive operation can be overridden by Wrapper.
1906 -- Iface_Op is the candidate primitive operation of an interface type,
1907 -- Wrapper is the generated entry wrapper.
1909 function Replicate_Formals
1910 (Loc : Source_Ptr;
1911 Formals : List_Id) return List_Id;
1912 -- An explicit parameter replication is required due to the Is_Entry_
1913 -- Formal flag being set for all the formals of an entry. The explicit
1914 -- replication removes the flag that would otherwise cause a different
1915 -- path of analysis.
1917 -------------------------
1918 -- Overriding_Possible --
1919 -------------------------
1921 function Overriding_Possible
1922 (Iface_Op : Entity_Id;
1923 Wrapper : Entity_Id) return Boolean
1925 Iface_Op_Spec : constant Node_Id := Parent (Iface_Op);
1926 Wrapper_Spec : constant Node_Id := Parent (Wrapper);
1928 function Type_Conformant_Parameters
1929 (Iface_Op_Params : List_Id;
1930 Wrapper_Params : List_Id) return Boolean;
1931 -- Determine whether the parameters of the generated entry wrapper
1932 -- and those of a primitive operation are type conformant. During
1933 -- this check, the first parameter of the primitive operation is
1934 -- skipped if it is a controlling argument: protected functions
1935 -- may have a controlling result.
1937 --------------------------------
1938 -- Type_Conformant_Parameters --
1939 --------------------------------
1941 function Type_Conformant_Parameters
1942 (Iface_Op_Params : List_Id;
1943 Wrapper_Params : List_Id) return Boolean
1945 Iface_Op_Param : Node_Id;
1946 Iface_Op_Typ : Entity_Id;
1947 Wrapper_Param : Node_Id;
1948 Wrapper_Typ : Entity_Id;
1950 begin
1951 -- Skip the first (controlling) parameter of primitive operation
1953 Iface_Op_Param := First (Iface_Op_Params);
1955 if Present (First_Formal (Iface_Op))
1956 and then Is_Controlling_Formal (First_Formal (Iface_Op))
1957 then
1958 Next (Iface_Op_Param);
1959 end if;
1961 Wrapper_Param := First (Wrapper_Params);
1962 while Present (Iface_Op_Param)
1963 and then Present (Wrapper_Param)
1964 loop
1965 Iface_Op_Typ := Find_Parameter_Type (Iface_Op_Param);
1966 Wrapper_Typ := Find_Parameter_Type (Wrapper_Param);
1968 -- The two parameters must be mode conformant
1970 if not Conforming_Types
1971 (Iface_Op_Typ, Wrapper_Typ, Mode_Conformant)
1972 then
1973 return False;
1974 end if;
1976 Next (Iface_Op_Param);
1977 Next (Wrapper_Param);
1978 end loop;
1980 -- One of the lists is longer than the other
1982 if Present (Iface_Op_Param) or else Present (Wrapper_Param) then
1983 return False;
1984 end if;
1986 return True;
1987 end Type_Conformant_Parameters;
1989 -- Start of processing for Overriding_Possible
1991 begin
1992 if Chars (Iface_Op) /= Chars (Wrapper) then
1993 return False;
1994 end if;
1996 -- If an inherited subprogram is implemented by a protected procedure
1997 -- or an entry, then the first parameter of the inherited subprogram
1998 -- must be of mode OUT or IN OUT, or access-to-variable parameter.
2000 if Ekind (Iface_Op) = E_Procedure
2001 and then Present (Parameter_Specifications (Iface_Op_Spec))
2002 then
2003 declare
2004 Obj_Param : constant Node_Id :=
2005 First (Parameter_Specifications (Iface_Op_Spec));
2006 begin
2007 if not Out_Present (Obj_Param)
2008 and then Nkind (Parameter_Type (Obj_Param)) /=
2009 N_Access_Definition
2010 then
2011 return False;
2012 end if;
2013 end;
2014 end if;
2016 return
2017 Type_Conformant_Parameters
2018 (Parameter_Specifications (Iface_Op_Spec),
2019 Parameter_Specifications (Wrapper_Spec));
2020 end Overriding_Possible;
2022 -----------------------
2023 -- Replicate_Formals --
2024 -----------------------
2026 function Replicate_Formals
2027 (Loc : Source_Ptr;
2028 Formals : List_Id) return List_Id
2030 New_Formals : constant List_Id := New_List;
2031 Formal : Node_Id;
2032 Param_Type : Node_Id;
2034 begin
2035 Formal := First (Formals);
2037 -- Skip the object parameter when dealing with primitives declared
2038 -- between two views.
2040 if Is_Private_Primitive_Subprogram (Subp_Id)
2041 and then not Has_Controlling_Result (Subp_Id)
2042 then
2043 Next (Formal);
2044 end if;
2046 while Present (Formal) loop
2048 -- Create an explicit copy of the entry parameter
2050 -- When creating the wrapper subprogram for a primitive operation
2051 -- of a protected interface we must construct an equivalent
2052 -- signature to that of the overriding operation. For regular
2053 -- parameters we can just use the type of the formal, but for
2054 -- access to subprogram parameters we need to reanalyze the
2055 -- parameter type to create local entities for the signature of
2056 -- the subprogram type. Using the entities of the overriding
2057 -- subprogram will result in out-of-scope errors in the back-end.
2059 if Nkind (Parameter_Type (Formal)) = N_Access_Definition then
2060 Param_Type := Copy_Separate_Tree (Parameter_Type (Formal));
2061 else
2062 Param_Type :=
2063 New_Occurrence_Of (Etype (Parameter_Type (Formal)), Loc);
2064 end if;
2066 Append_To (New_Formals,
2067 Make_Parameter_Specification (Loc,
2068 Defining_Identifier =>
2069 Make_Defining_Identifier (Loc,
2070 Chars => Chars (Defining_Identifier (Formal))),
2071 In_Present => In_Present (Formal),
2072 Out_Present => Out_Present (Formal),
2073 Null_Exclusion_Present => Null_Exclusion_Present (Formal),
2074 Parameter_Type => Param_Type));
2076 Next (Formal);
2077 end loop;
2079 return New_Formals;
2080 end Replicate_Formals;
2082 -- Local variables
2084 Loc : constant Source_Ptr := Sloc (Subp_Id);
2085 First_Param : Node_Id := Empty;
2086 Iface : Entity_Id;
2087 Iface_Elmt : Elmt_Id;
2088 Iface_Op : Entity_Id;
2089 Iface_Op_Elmt : Elmt_Id;
2090 Overridden_Subp : Entity_Id;
2092 -- Start of processing for Build_Wrapper_Spec
2094 begin
2095 -- No point in building wrappers for untagged concurrent types
2097 pragma Assert (Is_Tagged_Type (Obj_Typ));
2099 -- Check if this subprogram has a profile that matches some interface
2100 -- primitive.
2102 Check_Synchronized_Overriding (Subp_Id, Overridden_Subp);
2104 if Present (Overridden_Subp) then
2105 First_Param :=
2106 First (Parameter_Specifications (Parent (Overridden_Subp)));
2108 -- An entry or a protected procedure can override a routine where the
2109 -- controlling formal is either IN OUT, OUT or is of access-to-variable
2110 -- type. Since the wrapper must have the exact same signature as that of
2111 -- the overridden subprogram, we try to find the overriding candidate
2112 -- and use its controlling formal.
2114 -- Check every implemented interface
2116 elsif Present (Interfaces (Obj_Typ)) then
2117 Iface_Elmt := First_Elmt (Interfaces (Obj_Typ));
2118 Search : while Present (Iface_Elmt) loop
2119 Iface := Node (Iface_Elmt);
2121 -- Check every interface primitive
2123 if Present (Primitive_Operations (Iface)) then
2124 Iface_Op_Elmt := First_Elmt (Primitive_Operations (Iface));
2125 while Present (Iface_Op_Elmt) loop
2126 Iface_Op := Node (Iface_Op_Elmt);
2128 -- Ignore predefined primitives
2130 if not Is_Predefined_Dispatching_Operation (Iface_Op) then
2131 Iface_Op := Ultimate_Alias (Iface_Op);
2133 -- The current primitive operation can be overridden by
2134 -- the generated entry wrapper.
2136 if Overriding_Possible (Iface_Op, Subp_Id) then
2137 First_Param :=
2138 First (Parameter_Specifications (Parent (Iface_Op)));
2140 exit Search;
2141 end if;
2142 end if;
2144 Next_Elmt (Iface_Op_Elmt);
2145 end loop;
2146 end if;
2148 Next_Elmt (Iface_Elmt);
2149 end loop Search;
2150 end if;
2152 -- Do not generate the wrapper if no interface primitive is covered by
2153 -- the subprogram and it is not a primitive declared between two views
2154 -- (see Process_Full_View).
2156 if No (First_Param)
2157 and then not Is_Private_Primitive_Subprogram (Subp_Id)
2158 then
2159 return Empty;
2160 end if;
2162 declare
2163 Wrapper_Id : constant Entity_Id :=
2164 Make_Defining_Identifier (Loc, Chars (Subp_Id));
2165 New_Formals : List_Id;
2166 Obj_Param : Node_Id;
2167 Obj_Param_Typ : Entity_Id;
2169 begin
2170 -- Minimum decoration is needed to catch the entity in
2171 -- Sem_Ch6.Override_Dispatching_Operation.
2173 if Ekind (Subp_Id) = E_Function then
2174 Mutate_Ekind (Wrapper_Id, E_Function);
2175 else
2176 Mutate_Ekind (Wrapper_Id, E_Procedure);
2177 end if;
2179 Set_Is_Primitive_Wrapper (Wrapper_Id);
2180 Set_Wrapped_Entity (Wrapper_Id, Subp_Id);
2181 Set_Is_Private_Primitive (Wrapper_Id,
2182 Is_Private_Primitive_Subprogram (Subp_Id));
2184 -- Process the formals
2186 New_Formals := Replicate_Formals (Loc, Formals);
2188 -- A function with a controlling result and no first controlling
2189 -- formal needs no additional parameter.
2191 if Has_Controlling_Result (Subp_Id)
2192 and then
2193 (No (First_Formal (Subp_Id))
2194 or else not Is_Controlling_Formal (First_Formal (Subp_Id)))
2195 then
2196 null;
2198 -- Routine Subp_Id has been found to override an interface primitive.
2199 -- If the interface operation has an access parameter, create a copy
2200 -- of it, with the same null exclusion indicator if present.
2202 elsif Present (First_Param) then
2203 if Nkind (Parameter_Type (First_Param)) = N_Access_Definition then
2204 Obj_Param_Typ :=
2205 Make_Access_Definition (Loc,
2206 Subtype_Mark =>
2207 New_Occurrence_Of (Obj_Typ, Loc),
2208 Null_Exclusion_Present =>
2209 Null_Exclusion_Present (Parameter_Type (First_Param)),
2210 Constant_Present =>
2211 Constant_Present (Parameter_Type (First_Param)));
2212 else
2213 Obj_Param_Typ := New_Occurrence_Of (Obj_Typ, Loc);
2214 end if;
2216 Obj_Param :=
2217 Make_Parameter_Specification (Loc,
2218 Defining_Identifier =>
2219 Make_Defining_Identifier (Loc,
2220 Chars => Name_uO),
2221 In_Present => In_Present (First_Param),
2222 Out_Present => Out_Present (First_Param),
2223 Parameter_Type => Obj_Param_Typ);
2225 Prepend_To (New_Formals, Obj_Param);
2227 -- If we are dealing with a primitive declared between two views,
2228 -- implemented by a synchronized operation, we need to create
2229 -- a default parameter. The mode of the parameter must match that
2230 -- of the primitive operation.
2232 else
2233 pragma Assert (Is_Private_Primitive_Subprogram (Subp_Id));
2235 Obj_Param :=
2236 Make_Parameter_Specification (Loc,
2237 Defining_Identifier =>
2238 Make_Defining_Identifier (Loc, Name_uO),
2239 In_Present =>
2240 In_Present (Parent (First_Entity (Subp_Id))),
2241 Out_Present => Ekind (Subp_Id) /= E_Function,
2242 Parameter_Type => New_Occurrence_Of (Obj_Typ, Loc));
2244 Prepend_To (New_Formals, Obj_Param);
2245 end if;
2247 -- Build the final spec. If it is a function with a controlling
2248 -- result, it is a primitive operation of the corresponding
2249 -- record type, so mark the spec accordingly.
2251 if Ekind (Subp_Id) = E_Function then
2252 declare
2253 Res_Def : Node_Id;
2255 begin
2256 if Has_Controlling_Result (Subp_Id) then
2257 Res_Def :=
2258 New_Occurrence_Of
2259 (Corresponding_Record_Type (Etype (Subp_Id)), Loc);
2260 else
2261 Res_Def := New_Copy (Result_Definition (Parent (Subp_Id)));
2262 end if;
2264 return
2265 Make_Function_Specification (Loc,
2266 Defining_Unit_Name => Wrapper_Id,
2267 Parameter_Specifications => New_Formals,
2268 Result_Definition => Res_Def);
2269 end;
2270 else
2271 return
2272 Make_Procedure_Specification (Loc,
2273 Defining_Unit_Name => Wrapper_Id,
2274 Parameter_Specifications => New_Formals);
2275 end if;
2276 end;
2277 end Build_Wrapper_Spec;
2279 -------------------------
2280 -- Build_Wrapper_Specs --
2281 -------------------------
2283 procedure Build_Wrapper_Specs
2284 (Loc : Source_Ptr;
2285 Typ : Entity_Id;
2286 N : in out Node_Id)
2288 Def : Node_Id;
2289 Rec_Typ : Entity_Id;
2290 procedure Scan_Declarations (L : List_Id);
2291 -- Common processing for visible and private declarations
2292 -- of a protected type.
2294 procedure Scan_Declarations (L : List_Id) is
2295 Decl : Node_Id;
2296 Wrap_Decl : Node_Id;
2297 Wrap_Spec : Node_Id;
2299 begin
2300 if No (L) then
2301 return;
2302 end if;
2304 Decl := First (L);
2305 while Present (Decl) loop
2306 Wrap_Spec := Empty;
2308 if Nkind (Decl) = N_Entry_Declaration
2309 and then Ekind (Defining_Identifier (Decl)) = E_Entry
2310 then
2311 Wrap_Spec :=
2312 Build_Wrapper_Spec
2313 (Subp_Id => Defining_Identifier (Decl),
2314 Obj_Typ => Rec_Typ,
2315 Formals => Parameter_Specifications (Decl));
2317 elsif Nkind (Decl) = N_Subprogram_Declaration then
2318 Wrap_Spec :=
2319 Build_Wrapper_Spec
2320 (Subp_Id => Defining_Unit_Name (Specification (Decl)),
2321 Obj_Typ => Rec_Typ,
2322 Formals =>
2323 Parameter_Specifications (Specification (Decl)));
2324 end if;
2326 if Present (Wrap_Spec) then
2327 Wrap_Decl :=
2328 Make_Subprogram_Declaration (Loc,
2329 Specification => Wrap_Spec);
2331 Insert_After (N, Wrap_Decl);
2332 N := Wrap_Decl;
2334 Analyze (Wrap_Decl);
2335 end if;
2337 Next (Decl);
2338 end loop;
2339 end Scan_Declarations;
2341 -- start of processing for Build_Wrapper_Specs
2343 begin
2344 if Is_Protected_Type (Typ) then
2345 Def := Protected_Definition (Parent (Typ));
2346 else pragma Assert (Is_Task_Type (Typ));
2347 Def := Task_Definition (Parent (Typ));
2348 end if;
2350 Rec_Typ := Corresponding_Record_Type (Typ);
2352 -- Generate wrapper specs for a concurrent type which implements an
2353 -- interface. Operations in both the visible and private parts may
2354 -- implement progenitor operations.
2356 if Present (Interfaces (Rec_Typ)) and then Present (Def) then
2357 Scan_Declarations (Visible_Declarations (Def));
2358 Scan_Declarations (Private_Declarations (Def));
2359 end if;
2360 end Build_Wrapper_Specs;
2362 ---------------------------
2363 -- Build_Find_Body_Index --
2364 ---------------------------
2366 function Build_Find_Body_Index (Typ : Entity_Id) return Node_Id is
2367 Loc : constant Source_Ptr := Sloc (Typ);
2368 Ent : Entity_Id;
2369 E_Typ : Entity_Id;
2370 Has_F : Boolean := False;
2371 Index : Nat;
2372 If_St : Node_Id := Empty;
2373 Lo : Node_Id;
2374 Hi : Node_Id;
2375 Decls : List_Id := New_List;
2376 Ret : Node_Id := Empty;
2377 Spec : Node_Id;
2378 Siz : Node_Id := Empty;
2380 procedure Add_If_Clause (Expr : Node_Id);
2381 -- Add test for range of current entry
2383 function Convert_Discriminant_Ref (Bound : Node_Id) return Node_Id;
2384 -- If a bound of an entry is given by a discriminant, retrieve the
2385 -- actual value of the discriminant from the enclosing object.
2387 -------------------
2388 -- Add_If_Clause --
2389 -------------------
2391 procedure Add_If_Clause (Expr : Node_Id) is
2392 Cond : Node_Id;
2393 Stats : constant List_Id :=
2394 New_List (
2395 Make_Simple_Return_Statement (Loc,
2396 Expression => Make_Integer_Literal (Loc, Index + 1)));
2398 begin
2399 -- Index for current entry body
2401 Index := Index + 1;
2403 -- Compute total length of entry queues so far
2405 if No (Siz) then
2406 Siz := Expr;
2407 else
2408 Siz :=
2409 Make_Op_Add (Loc,
2410 Left_Opnd => Siz,
2411 Right_Opnd => Expr);
2412 end if;
2414 Cond :=
2415 Make_Op_Le (Loc,
2416 Left_Opnd => Make_Identifier (Loc, Name_uE),
2417 Right_Opnd => Siz);
2419 -- Map entry queue indexes in the range of the current family
2420 -- into the current index, that designates the entry body.
2422 if No (If_St) then
2423 If_St :=
2424 Make_Implicit_If_Statement (Typ,
2425 Condition => Cond,
2426 Then_Statements => Stats,
2427 Elsif_Parts => New_List);
2428 Ret := If_St;
2430 else
2431 Append_To (Elsif_Parts (If_St),
2432 Make_Elsif_Part (Loc,
2433 Condition => Cond,
2434 Then_Statements => Stats));
2435 end if;
2436 end Add_If_Clause;
2438 ------------------------------
2439 -- Convert_Discriminant_Ref --
2440 ------------------------------
2442 function Convert_Discriminant_Ref (Bound : Node_Id) return Node_Id is
2443 B : Node_Id;
2445 begin
2446 if Is_Entity_Name (Bound)
2447 and then Ekind (Entity (Bound)) = E_Discriminant
2448 then
2449 B :=
2450 Make_Selected_Component (Loc,
2451 Prefix =>
2452 Unchecked_Convert_To (Corresponding_Record_Type (Typ),
2453 Make_Explicit_Dereference (Loc,
2454 Make_Identifier (Loc, Name_uObject))),
2455 Selector_Name => Make_Identifier (Loc, Chars (Bound)));
2456 Set_Etype (B, Etype (Entity (Bound)));
2457 else
2458 B := New_Copy_Tree (Bound);
2459 end if;
2461 return B;
2462 end Convert_Discriminant_Ref;
2464 -- Start of processing for Build_Find_Body_Index
2466 begin
2467 Spec := Build_Find_Body_Index_Spec (Typ);
2469 Ent := First_Entity (Typ);
2470 while Present (Ent) loop
2471 if Ekind (Ent) = E_Entry_Family then
2472 Has_F := True;
2473 exit;
2474 end if;
2476 Next_Entity (Ent);
2477 end loop;
2479 if not Has_F then
2481 -- If the protected type has no entry families, there is a one-one
2482 -- correspondence between entry queue and entry body.
2484 Ret :=
2485 Make_Simple_Return_Statement (Loc,
2486 Expression => Make_Identifier (Loc, Name_uE));
2488 else
2489 -- Suppose entries e1, e2, ... have size l1, l2, ... we generate
2490 -- the following:
2492 -- if E <= l1 then return 1;
2493 -- elsif E <= l1 + l2 then return 2;
2494 -- ...
2496 Index := 0;
2497 Siz := Empty;
2498 Ent := First_Entity (Typ);
2500 Add_Object_Pointer (Loc, Typ, Decls);
2502 while Present (Ent) loop
2503 if Ekind (Ent) = E_Entry then
2504 Add_If_Clause (Make_Integer_Literal (Loc, 1));
2506 elsif Ekind (Ent) = E_Entry_Family then
2507 E_Typ := Entry_Index_Type (Ent);
2508 Hi := Convert_Discriminant_Ref (Type_High_Bound (E_Typ));
2509 Lo := Convert_Discriminant_Ref (Type_Low_Bound (E_Typ));
2510 Add_If_Clause (Family_Size (Loc, Hi, Lo, Typ, False));
2511 end if;
2513 Next_Entity (Ent);
2514 end loop;
2516 if Index = 1 then
2517 Decls := New_List;
2518 Ret :=
2519 Make_Simple_Return_Statement (Loc,
2520 Expression => Make_Integer_Literal (Loc, 1));
2522 else
2523 -- Ranges are in increasing order, so last one doesn't need guard
2525 declare
2526 Nod : constant Node_Id := Last (Elsif_Parts (Ret));
2527 begin
2528 Remove (Nod);
2529 Set_Else_Statements (Ret, Then_Statements (Nod));
2531 -- If Elsif_Parts becomes empty then remove it entirely, as
2532 -- otherwise we would violate the invariant of If_Statement
2533 -- node described in Sinfo.
2535 if Is_Empty_List (Elsif_Parts (Ret)) then
2536 pragma Assert (Elsif_Parts (Ret) /= No_List);
2537 Set_Elsif_Parts (Ret, No_List);
2538 end if;
2539 end;
2540 end if;
2541 end if;
2543 return
2544 Make_Subprogram_Body (Loc,
2545 Specification => Spec,
2546 Declarations => Decls,
2547 Handled_Statement_Sequence =>
2548 Make_Handled_Sequence_Of_Statements (Loc,
2549 Statements => New_List (Ret)));
2550 end Build_Find_Body_Index;
2552 --------------------------------
2553 -- Build_Find_Body_Index_Spec --
2554 --------------------------------
2556 function Build_Find_Body_Index_Spec (Typ : Entity_Id) return Node_Id is
2557 Loc : constant Source_Ptr := Sloc (Typ);
2558 Id : constant Entity_Id :=
2559 Make_Defining_Identifier (Loc,
2560 Chars => New_External_Name (Chars (Typ), 'F'));
2561 Parm1 : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uO);
2562 Parm2 : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uE);
2564 begin
2565 return
2566 Make_Function_Specification (Loc,
2567 Defining_Unit_Name => Id,
2568 Parameter_Specifications => New_List (
2569 Make_Parameter_Specification (Loc,
2570 Defining_Identifier => Parm1,
2571 Parameter_Type =>
2572 New_Occurrence_Of (RTE (RE_Address), Loc)),
2574 Make_Parameter_Specification (Loc,
2575 Defining_Identifier => Parm2,
2576 Parameter_Type =>
2577 New_Occurrence_Of (RTE (RE_Protected_Entry_Index), Loc))),
2579 Result_Definition => New_Occurrence_Of (
2580 RTE (RE_Protected_Entry_Index), Loc));
2581 end Build_Find_Body_Index_Spec;
2583 -----------------------------------------------
2584 -- Build_Lock_Free_Protected_Subprogram_Body --
2585 -----------------------------------------------
2587 function Build_Lock_Free_Protected_Subprogram_Body
2588 (N : Node_Id;
2589 Prot_Typ : Node_Id;
2590 Unprot_Spec : Node_Id) return Node_Id
2592 Actuals : constant List_Id := New_List;
2593 Loc : constant Source_Ptr := Sloc (N);
2594 Spec : constant Node_Id := Specification (N);
2595 Unprot_Id : constant Entity_Id := Defining_Unit_Name (Unprot_Spec);
2596 Formal : Node_Id;
2597 Prot_Spec : Node_Id;
2598 Stmt : Node_Id;
2600 begin
2601 -- Create the protected version of the body
2603 Prot_Spec :=
2604 Build_Protected_Sub_Specification (N, Prot_Typ, Protected_Mode);
2606 -- Build the actual parameters which appear in the call to the
2607 -- unprotected version of the body.
2609 Formal := First (Parameter_Specifications (Prot_Spec));
2610 while Present (Formal) loop
2611 Append_To (Actuals,
2612 Make_Identifier (Loc, Chars (Defining_Identifier (Formal))));
2614 Next (Formal);
2615 end loop;
2617 -- Function case, generate:
2618 -- return <Unprot_Func_Call>;
2620 if Nkind (Spec) = N_Function_Specification then
2621 Stmt :=
2622 Make_Simple_Return_Statement (Loc,
2623 Expression =>
2624 Make_Function_Call (Loc,
2625 Name =>
2626 Make_Identifier (Loc, Chars (Unprot_Id)),
2627 Parameter_Associations => Actuals));
2629 -- Procedure case, call the unprotected version
2631 else
2632 Stmt :=
2633 Make_Procedure_Call_Statement (Loc,
2634 Name =>
2635 Make_Identifier (Loc, Chars (Unprot_Id)),
2636 Parameter_Associations => Actuals);
2637 end if;
2639 return
2640 Make_Subprogram_Body (Loc,
2641 Declarations => Empty_List,
2642 Specification => Prot_Spec,
2643 Handled_Statement_Sequence =>
2644 Make_Handled_Sequence_Of_Statements (Loc,
2645 Statements => New_List (Stmt)));
2646 end Build_Lock_Free_Protected_Subprogram_Body;
2648 -------------------------------------------------
2649 -- Build_Lock_Free_Unprotected_Subprogram_Body --
2650 -------------------------------------------------
2652 -- Procedures which meet the lock-free implementation requirements and
2653 -- reference a unique scalar component Comp are expanded in the following
2654 -- manner:
2656 -- procedure P (...) is
2657 -- Expected_Comp : constant Comp_Type :=
2658 -- Comp_Type
2659 -- (System.Atomic_Primitives.Lock_Free_Read_N
2660 -- (_Object.Comp'Address));
2661 -- begin
2662 -- loop
2663 -- declare
2664 -- <original declarations before the object renaming declaration
2665 -- of Comp>
2667 -- Desired_Comp : Comp_Type := Expected_Comp;
2668 -- Comp : Comp_Type renames Desired_Comp;
2670 -- <original declarations after the object renaming declaration
2671 -- of Comp>
2673 -- begin
2674 -- <original statements>
2675 -- exit when System.Atomic_Primitives.Lock_Free_Try_Write_N
2676 -- (_Object.Comp'Address,
2677 -- Interfaces.Unsigned_N (Expected_Comp),
2678 -- Interfaces.Unsigned_N (Desired_Comp));
2679 -- end;
2680 -- end loop;
2681 -- end P;
2683 -- Each return and raise statement of P is transformed into an atomic
2684 -- status check:
2686 -- if System.Atomic_Primitives.Lock_Free_Try_Write_N
2687 -- (_Object.Comp'Address,
2688 -- Interfaces.Unsigned_N (Expected_Comp),
2689 -- Interfaces.Unsigned_N (Desired_Comp));
2690 -- then
2691 -- <original statement>
2692 -- else
2693 -- goto L0;
2694 -- end if;
2696 -- Functions which meet the lock-free implementation requirements and
2697 -- reference a unique scalar component Comp are expanded in the following
2698 -- manner:
2700 -- function F (...) return ... is
2701 -- <original declarations before the object renaming declaration
2702 -- of Comp>
2704 -- Expected_Comp : constant Comp_Type :=
2705 -- Comp_Type
2706 -- (System.Atomic_Primitives.Lock_Free_Read_N
2707 -- (_Object.Comp'Address));
2708 -- Comp : Comp_Type renames Expected_Comp;
2710 -- <original declarations after the object renaming declaration of
2711 -- Comp>
2713 -- begin
2714 -- <original statements>
2715 -- end F;
2717 function Build_Lock_Free_Unprotected_Subprogram_Body
2718 (N : Node_Id;
2719 Prot_Typ : Node_Id) return Node_Id
2721 function Referenced_Component (N : Node_Id) return Entity_Id;
2722 -- Subprograms which meet the lock-free implementation criteria are
2723 -- allowed to reference only one unique component. Return the prival
2724 -- of the said component.
2726 --------------------------
2727 -- Referenced_Component --
2728 --------------------------
2730 function Referenced_Component (N : Node_Id) return Entity_Id is
2731 Comp : Entity_Id;
2732 Decl : Node_Id;
2733 Source_Comp : Entity_Id := Empty;
2735 begin
2736 -- Find the unique source component which N references in its
2737 -- statements.
2739 for Index in 1 .. Lock_Free_Subprogram_Table.Last loop
2740 declare
2741 Element : Lock_Free_Subprogram renames
2742 Lock_Free_Subprogram_Table.Table (Index);
2743 begin
2744 if Element.Sub_Body = N then
2745 Source_Comp := Element.Comp_Id;
2746 exit;
2747 end if;
2748 end;
2749 end loop;
2751 if No (Source_Comp) then
2752 return Empty;
2753 end if;
2755 -- Find the prival which corresponds to the source component within
2756 -- the declarations of N.
2758 Decl := First (Declarations (N));
2759 while Present (Decl) loop
2761 -- Privals appear as object renamings
2763 if Nkind (Decl) = N_Object_Renaming_Declaration then
2764 Comp := Defining_Identifier (Decl);
2766 if Present (Prival_Link (Comp))
2767 and then Prival_Link (Comp) = Source_Comp
2768 then
2769 return Comp;
2770 end if;
2771 end if;
2773 Next (Decl);
2774 end loop;
2776 return Empty;
2777 end Referenced_Component;
2779 -- Local variables
2781 Comp : constant Entity_Id := Referenced_Component (N);
2782 Loc : constant Source_Ptr := Sloc (N);
2783 Hand_Stmt_Seq : Node_Id := Handled_Statement_Sequence (N);
2784 Decls : List_Id := Declarations (N);
2786 -- Start of processing for Build_Lock_Free_Unprotected_Subprogram_Body
2788 begin
2789 -- Add renamings for the protection object, discriminals, privals, and
2790 -- the entry index constant for use by debugger.
2792 Debug_Private_Data_Declarations (Decls);
2794 -- Perform the lock-free expansion when the subprogram references a
2795 -- protected component.
2797 if Present (Comp) then
2798 Protected_Component_Ref : declare
2799 Comp_Decl : constant Node_Id := Parent (Comp);
2800 Comp_Sel_Nam : constant Node_Id := Name (Comp_Decl);
2801 Comp_Type : constant Entity_Id := Etype (Comp);
2803 Is_Procedure : constant Boolean :=
2804 Ekind (Corresponding_Spec (N)) = E_Procedure;
2805 -- Indicates if N is a protected procedure body
2807 Block_Decls : List_Id := No_List;
2808 Try_Write : Entity_Id;
2809 Desired_Comp : Entity_Id;
2810 Decl : Node_Id;
2811 Label : Node_Id;
2812 Label_Id : Entity_Id := Empty;
2813 Read : Entity_Id;
2814 Expected_Comp : Entity_Id;
2815 Stmt : Node_Id;
2816 Stmts : List_Id :=
2817 New_Copy_List_Tree (Statements (Hand_Stmt_Seq));
2818 Typ_Size : Int;
2819 Unsigned : Entity_Id;
2821 function Process_Node (N : Node_Id) return Traverse_Result;
2822 -- Transform a single node if it is a return statement, a raise
2823 -- statement or a reference to Comp.
2825 procedure Process_Stmts (Stmts : List_Id);
2826 -- Given a statement sequence Stmts, wrap any return or raise
2827 -- statements in the following manner:
2829 -- if System.Atomic_Primitives.Lock_Free_Try_Write_N
2830 -- (_Object.Comp'Address,
2831 -- Interfaces.Unsigned_N (Expected_Comp),
2832 -- Interfaces.Unsigned_N (Desired_Comp))
2833 -- then
2834 -- <Stmt>;
2835 -- else
2836 -- goto L0;
2837 -- end if;
2839 ------------------
2840 -- Process_Node --
2841 ------------------
2843 function Process_Node (N : Node_Id) return Traverse_Result is
2845 procedure Wrap_Statement (Stmt : Node_Id);
2846 -- Wrap an arbitrary statement inside an if statement where the
2847 -- condition does an atomic check on the state of the object.
2849 --------------------
2850 -- Wrap_Statement --
2851 --------------------
2853 procedure Wrap_Statement (Stmt : Node_Id) is
2854 begin
2855 -- The first time through, create the declaration of a label
2856 -- which is used to skip the remainder of source statements
2857 -- if the state of the object has changed.
2859 if No (Label_Id) then
2860 Label_Id :=
2861 Make_Identifier (Loc, New_External_Name ('L', 0));
2862 Set_Entity (Label_Id,
2863 Make_Defining_Identifier (Loc, Chars (Label_Id)));
2864 end if;
2866 -- Generate:
2867 -- if System.Atomic_Primitives.Lock_Free_Try_Write_N
2868 -- (_Object.Comp'Address,
2869 -- Interfaces.Unsigned_N (Expected_Comp),
2870 -- Interfaces.Unsigned_N (Desired_Comp))
2871 -- then
2872 -- <Stmt>;
2873 -- else
2874 -- goto L0;
2875 -- end if;
2877 Rewrite (Stmt,
2878 Make_Implicit_If_Statement (N,
2879 Condition =>
2880 Make_Function_Call (Loc,
2881 Name =>
2882 New_Occurrence_Of (Try_Write, Loc),
2883 Parameter_Associations => New_List (
2884 Make_Attribute_Reference (Loc,
2885 Prefix => Relocate_Node (Comp_Sel_Nam),
2886 Attribute_Name => Name_Address),
2888 Unchecked_Convert_To (Unsigned,
2889 New_Occurrence_Of (Expected_Comp, Loc)),
2891 Unchecked_Convert_To (Unsigned,
2892 New_Occurrence_Of (Desired_Comp, Loc)))),
2894 Then_Statements => New_List (Relocate_Node (Stmt)),
2896 Else_Statements => New_List (
2897 Make_Goto_Statement (Loc,
2898 Name =>
2899 New_Occurrence_Of (Entity (Label_Id), Loc)))));
2900 end Wrap_Statement;
2902 -- Start of processing for Process_Node
2904 begin
2905 -- Wrap each return and raise statement that appear inside a
2906 -- procedure. Skip the last return statement which is added by
2907 -- default since it is transformed into an exit statement.
2909 if Is_Procedure
2910 and then ((Nkind (N) = N_Simple_Return_Statement
2911 and then N /= Last (Stmts))
2912 or else Nkind (N) = N_Extended_Return_Statement
2913 or else (Nkind (N) in
2914 N_Raise_xxx_Error | N_Raise_Statement
2915 and then Comes_From_Source (N)))
2916 then
2917 Wrap_Statement (N);
2918 return Skip;
2919 end if;
2921 -- Force reanalysis
2923 Set_Analyzed (N, False);
2925 return OK;
2926 end Process_Node;
2928 procedure Process_Nodes is new Traverse_Proc (Process_Node);
2930 -------------------
2931 -- Process_Stmts --
2932 -------------------
2934 procedure Process_Stmts (Stmts : List_Id) is
2935 Stmt : Node_Id;
2936 begin
2937 Stmt := First (Stmts);
2938 while Present (Stmt) loop
2939 Process_Nodes (Stmt);
2940 Next (Stmt);
2941 end loop;
2942 end Process_Stmts;
2944 -- Start of processing for Protected_Component_Ref
2946 begin
2947 -- Get the type size
2949 if Known_Static_Esize (Comp_Type) then
2950 Typ_Size := UI_To_Int (Esize (Comp_Type));
2952 -- If the Esize (Object_Size) is unknown at compile time, look at
2953 -- the RM_Size (Value_Size) since it may have been set by an
2954 -- explicit representation clause.
2956 elsif Known_Static_RM_Size (Comp_Type) then
2957 Typ_Size := UI_To_Int (RM_Size (Comp_Type));
2959 -- Should not happen since this has already been checked in
2960 -- Allows_Lock_Free_Implementation (see Sem_Ch9).
2962 else
2963 raise Program_Error;
2964 end if;
2966 -- Retrieve all relevant atomic routines and types
2968 case Typ_Size is
2969 when 8 =>
2970 Try_Write := RTE (RE_Lock_Free_Try_Write_8);
2971 Read := RTE (RE_Lock_Free_Read_8);
2972 Unsigned := RTE (RE_Uint8);
2974 when 16 =>
2975 Try_Write := RTE (RE_Lock_Free_Try_Write_16);
2976 Read := RTE (RE_Lock_Free_Read_16);
2977 Unsigned := RTE (RE_Uint16);
2979 when 32 =>
2980 Try_Write := RTE (RE_Lock_Free_Try_Write_32);
2981 Read := RTE (RE_Lock_Free_Read_32);
2982 Unsigned := RTE (RE_Uint32);
2984 when 64 =>
2985 Try_Write := RTE (RE_Lock_Free_Try_Write_64);
2986 Read := RTE (RE_Lock_Free_Read_64);
2987 Unsigned := RTE (RE_Uint64);
2989 when others =>
2990 raise Program_Error;
2991 end case;
2993 -- Generate:
2994 -- Expected_Comp : constant Comp_Type :=
2995 -- Comp_Type
2996 -- (System.Atomic_Primitives.Lock_Free_Read_N
2997 -- (_Object.Comp'Address));
2999 Expected_Comp :=
3000 Make_Defining_Identifier (Loc,
3001 New_External_Name (Chars (Comp), Suffix => "_saved"));
3003 Decl :=
3004 Make_Object_Declaration (Loc,
3005 Defining_Identifier => Expected_Comp,
3006 Object_Definition => New_Occurrence_Of (Comp_Type, Loc),
3007 Constant_Present => True,
3008 Expression =>
3009 Unchecked_Convert_To (Comp_Type,
3010 Make_Function_Call (Loc,
3011 Name => New_Occurrence_Of (Read, Loc),
3012 Parameter_Associations => New_List (
3013 Make_Attribute_Reference (Loc,
3014 Prefix => Relocate_Node (Comp_Sel_Nam),
3015 Attribute_Name => Name_Address)))));
3017 -- Protected procedures
3019 if Is_Procedure then
3020 -- Move the original declarations inside the generated block
3022 Block_Decls := Decls;
3024 -- Reset the declarations list of the protected procedure to
3025 -- contain only Decl.
3027 Decls := New_List (Decl);
3029 -- Generate:
3030 -- Desired_Comp : Comp_Type := Expected_Comp;
3032 Desired_Comp :=
3033 Make_Defining_Identifier (Loc,
3034 New_External_Name (Chars (Comp), Suffix => "_current"));
3036 -- Insert the declarations of Expected_Comp and Desired_Comp in
3037 -- the block declarations right before the renaming of the
3038 -- protected component.
3040 Insert_Before (Comp_Decl,
3041 Make_Object_Declaration (Loc,
3042 Defining_Identifier => Desired_Comp,
3043 Object_Definition => New_Occurrence_Of (Comp_Type, Loc),
3044 Expression =>
3045 New_Occurrence_Of (Expected_Comp, Loc)));
3047 -- Protected function
3049 else
3050 Desired_Comp := Expected_Comp;
3052 -- Insert the declaration of Expected_Comp in the function
3053 -- declarations right before the renaming of the protected
3054 -- component.
3056 Insert_Before (Comp_Decl, Decl);
3057 end if;
3059 -- Rewrite the protected component renaming declaration to be a
3060 -- renaming of Desired_Comp.
3062 -- Generate:
3063 -- Comp : Comp_Type renames Desired_Comp;
3065 Rewrite (Comp_Decl,
3066 Make_Object_Renaming_Declaration (Loc,
3067 Defining_Identifier =>
3068 Defining_Identifier (Comp_Decl),
3069 Subtype_Mark =>
3070 New_Occurrence_Of (Comp_Type, Loc),
3071 Name =>
3072 New_Occurrence_Of (Desired_Comp, Loc)));
3074 -- Wrap any return or raise statements in Stmts in same the manner
3075 -- described in Process_Stmts.
3077 Process_Stmts (Stmts);
3079 -- Generate:
3080 -- exit when System.Atomic_Primitives.Lock_Free_Try_Write_N
3081 -- (_Object.Comp'Address,
3082 -- Interfaces.Unsigned_N (Expected_Comp),
3083 -- Interfaces.Unsigned_N (Desired_Comp))
3085 if Is_Procedure then
3086 Stmt :=
3087 Make_Exit_Statement (Loc,
3088 Condition =>
3089 Make_Function_Call (Loc,
3090 Name =>
3091 New_Occurrence_Of (Try_Write, Loc),
3092 Parameter_Associations => New_List (
3093 Make_Attribute_Reference (Loc,
3094 Prefix => Relocate_Node (Comp_Sel_Nam),
3095 Attribute_Name => Name_Address),
3097 Unchecked_Convert_To (Unsigned,
3098 New_Occurrence_Of (Expected_Comp, Loc)),
3100 Unchecked_Convert_To (Unsigned,
3101 New_Occurrence_Of (Desired_Comp, Loc)))));
3103 -- Small optimization: transform the default return statement
3104 -- of a procedure into the atomic exit statement.
3106 if Nkind (Last (Stmts)) = N_Simple_Return_Statement then
3107 Rewrite (Last (Stmts), Stmt);
3108 else
3109 Append_To (Stmts, Stmt);
3110 end if;
3111 end if;
3113 -- Create the declaration of the label used to skip the rest of
3114 -- the source statements when the object state changes.
3116 if Present (Label_Id) then
3117 Label := Make_Label (Loc, Label_Id);
3118 Append_To (Decls,
3119 Make_Implicit_Label_Declaration (Loc,
3120 Defining_Identifier => Entity (Label_Id),
3121 Label_Construct => Label));
3122 Append_To (Stmts, Label);
3123 end if;
3125 -- Generate:
3126 -- loop
3127 -- declare
3128 -- <Decls>
3129 -- begin
3130 -- <Stmts>
3131 -- end;
3132 -- end loop;
3134 if Is_Procedure then
3135 Stmts :=
3136 New_List (
3137 Make_Loop_Statement (Loc,
3138 Statements => New_List (
3139 Make_Block_Statement (Loc,
3140 Declarations => Block_Decls,
3141 Handled_Statement_Sequence =>
3142 Make_Handled_Sequence_Of_Statements (Loc,
3143 Statements => Stmts))),
3144 End_Label => Empty));
3145 end if;
3147 Hand_Stmt_Seq :=
3148 Make_Handled_Sequence_Of_Statements (Loc, Statements => Stmts);
3149 end Protected_Component_Ref;
3150 end if;
3152 -- Make an unprotected version of the subprogram for use within the same
3153 -- object, with new name and extra parameter representing the object.
3155 return
3156 Make_Subprogram_Body (Loc,
3157 Specification =>
3158 Build_Protected_Sub_Specification (N, Prot_Typ, Unprotected_Mode),
3159 Declarations => Decls,
3160 Handled_Statement_Sequence => Hand_Stmt_Seq);
3161 end Build_Lock_Free_Unprotected_Subprogram_Body;
3163 -------------------------
3164 -- Build_Master_Entity --
3165 -------------------------
3167 procedure Build_Master_Entity (Obj_Or_Typ : Entity_Id) is
3168 Loc : constant Source_Ptr := Sloc (Obj_Or_Typ);
3169 Context : Node_Id;
3170 Context_Id : Entity_Id;
3171 Decl : Node_Id;
3172 Decls : List_Id;
3173 Par : Node_Id;
3175 begin
3176 -- No action needed if the run-time has no tasking support
3178 if Global_No_Tasking then
3179 return;
3180 end if;
3182 if Is_Itype (Obj_Or_Typ) then
3183 Par := Associated_Node_For_Itype (Obj_Or_Typ);
3184 else
3185 Par := Parent (Obj_Or_Typ);
3186 end if;
3188 -- When creating a master for a record component which is either a task
3189 -- or access-to-task, the enclosing record is the master scope and the
3190 -- proper insertion point is the component list.
3192 if Is_Record_Type (Current_Scope) then
3193 Context := Par;
3194 Context_Id := Current_Scope;
3195 Decls := List_Containing (Context);
3197 -- Default case for object declarations and access types. Note that the
3198 -- context is updated to the nearest enclosing body, block, package, or
3199 -- return statement.
3201 else
3202 Find_Enclosing_Context (Par, Context, Context_Id, Decls);
3203 end if;
3205 -- When the enclosing context is a BIP function whose result type has
3206 -- tasks, the function has an extra formal that is the master of the
3207 -- tasks to be created by its returned object (that is, when its
3208 -- enclosing context is a return statement). However, if the body of
3209 -- the function creates tasks before its return statements, such tasks
3210 -- need their own master.
3212 if Has_Master_Entity (Context_Id)
3213 and then Ekind (Context_Id) = E_Function
3214 and then Is_Build_In_Place_Function (Context_Id)
3215 and then Needs_BIP_Task_Actuals (Context_Id)
3216 then
3217 -- No need to add it again if previously added
3219 declare
3220 Master_Present : Boolean;
3222 begin
3223 -- Handle transient scopes
3225 if Context_Id /= Current_Scope then
3226 Push_Scope (Context_Id);
3227 Master_Present :=
3228 Present (Current_Entity_In_Scope (Name_uMaster));
3229 Pop_Scope;
3230 else
3231 Master_Present :=
3232 Present (Current_Entity_In_Scope (Name_uMaster));
3233 end if;
3235 if Master_Present then
3236 return;
3237 end if;
3238 end;
3240 -- Nothing to do if the context already has a master; internally built
3241 -- finalizers don't need a master.
3243 elsif Has_Master_Entity (Context_Id)
3244 or else Is_Finalizer (Context_Id)
3245 then
3246 return;
3247 end if;
3249 Decl := Build_Master_Declaration (Loc);
3251 -- The master is inserted at the start of the declarative list of the
3252 -- context.
3254 Prepend_To (Decls, Decl);
3256 -- In certain cases where transient scopes are involved, the immediate
3257 -- scope is not always the proper master scope. Ensure that the master
3258 -- declaration and entity appear in the same context.
3260 if Context_Id /= Current_Scope then
3261 Push_Scope (Context_Id);
3262 Analyze (Decl);
3263 Pop_Scope;
3264 else
3265 Analyze (Decl);
3266 end if;
3268 -- Mark the enclosing scope and its associated construct as being task
3269 -- masters.
3271 Set_Has_Master_Entity (Context_Id);
3273 while Present (Context)
3274 and then Nkind (Context) /= N_Compilation_Unit
3275 loop
3276 if Nkind (Context) in
3277 N_Block_Statement | N_Subprogram_Body | N_Task_Body
3278 then
3279 Set_Is_Task_Master (Context);
3280 exit;
3282 elsif Nkind (Parent (Context)) = N_Subunit then
3283 Context := Corresponding_Stub (Parent (Context));
3284 end if;
3286 Context := Parent (Context);
3287 end loop;
3288 end Build_Master_Entity;
3290 ---------------------------
3291 -- Build_Master_Renaming --
3292 ---------------------------
3294 procedure Build_Master_Renaming
3295 (Ptr_Typ : Entity_Id;
3296 Ins_Nod : Node_Id := Empty)
3298 Loc : constant Source_Ptr := Sloc (Ptr_Typ);
3299 Context : Node_Id;
3300 Master_Decl : Node_Id;
3301 Master_Id : Entity_Id;
3303 begin
3304 -- No action needed if the run-time has no tasking support
3306 if Global_No_Tasking then
3307 return;
3308 end if;
3310 -- Determine the proper context to insert the master renaming
3312 if Present (Ins_Nod) then
3313 Context := Ins_Nod;
3315 elsif Is_Itype (Ptr_Typ) then
3316 Context := Associated_Node_For_Itype (Ptr_Typ);
3318 -- When the context references a discriminant or a component of a
3319 -- private type and we are processing declarations in the private
3320 -- part of the enclosing package, we must insert the master renaming
3321 -- before the full declaration of the private type; otherwise the
3322 -- master renaming would be inserted in the public part of the
3323 -- package (and hence before the declaration of _master).
3325 if In_Private_Part (Current_Scope) then
3326 declare
3327 Ctx : Node_Id := Context;
3329 begin
3330 if Nkind (Context) = N_Discriminant_Specification then
3331 Ctx := Parent (Ctx);
3332 else
3333 while Nkind (Ctx) in
3334 N_Component_Declaration | N_Component_List
3335 loop
3336 Ctx := Parent (Ctx);
3337 end loop;
3338 end if;
3340 if Nkind (Ctx) in N_Private_Type_Declaration
3341 | N_Private_Extension_Declaration
3342 then
3343 Context := Parent (Full_View (Defining_Identifier (Ctx)));
3344 end if;
3345 end;
3346 end if;
3348 else
3349 Context := Parent (Ptr_Typ);
3350 end if;
3352 -- Generate:
3353 -- <Ptr_Typ>M : Master_Id renames _Master;
3354 -- and add a numeric suffix to the name to ensure that it is
3355 -- unique in case other access types in nested constructs
3356 -- are homonyms of this one.
3358 Master_Id :=
3359 Make_Defining_Identifier (Loc,
3360 New_External_Name (Chars (Ptr_Typ), 'M', -1));
3362 Master_Decl :=
3363 Make_Object_Renaming_Declaration (Loc,
3364 Defining_Identifier => Master_Id,
3365 Subtype_Mark =>
3366 New_Occurrence_Of (Standard_Integer, Loc),
3367 Name => Make_Identifier (Loc, Name_uMaster));
3369 Insert_Action (Context, Master_Decl);
3371 -- The renamed master now services the access type
3373 Set_Master_Id (Ptr_Typ, Master_Id);
3374 end Build_Master_Renaming;
3376 ---------------------------
3377 -- Build_Protected_Entry --
3378 ---------------------------
3380 function Build_Protected_Entry
3381 (N : Node_Id;
3382 Ent : Entity_Id;
3383 Pid : Node_Id) return Node_Id
3385 Bod_Decls : constant List_Id := New_List;
3386 Decls : constant List_Id := Declarations (N);
3387 End_Lab : constant Node_Id :=
3388 End_Label (Handled_Statement_Sequence (N));
3389 End_Loc : constant Source_Ptr :=
3390 Sloc (Last (Statements (Handled_Statement_Sequence (N))));
3391 -- Used for the generated call to Complete_Entry_Body
3393 Loc : constant Source_Ptr := Sloc (N);
3395 Block_Id : Entity_Id;
3396 Bod_Id : Entity_Id;
3397 Bod_Spec : Node_Id;
3398 Bod_Stmts : List_Id;
3399 Complete : Node_Id;
3400 Ohandle : Node_Id;
3401 Proc_Body : Node_Id;
3403 EH_Loc : Source_Ptr;
3404 -- Used for the exception handler, inserted at end of the body
3406 begin
3407 -- Set the source location on the exception handler only when debugging
3408 -- the expanded code (see Make_Implicit_Exception_Handler).
3410 if Debug_Generated_Code then
3411 EH_Loc := End_Loc;
3413 -- Otherwise the inserted code should not be visible to the debugger
3415 else
3416 EH_Loc := No_Location;
3417 end if;
3419 Bod_Id :=
3420 Make_Defining_Identifier (Loc,
3421 Chars => Chars (Protected_Body_Subprogram (Ent)));
3422 Bod_Spec := Build_Protected_Entry_Specification (Loc, Bod_Id, Empty);
3424 -- Add the following declarations:
3426 -- type poVP is access poV;
3427 -- _object : poVP := poVP (_O);
3429 -- where _O is the formal parameter associated with the concurrent
3430 -- object. These declarations are needed for Complete_Entry_Body.
3432 Add_Object_Pointer (Loc, Pid, Bod_Decls);
3434 -- Add renamings for all formals, the Protection object, discriminals,
3435 -- privals and the entry index constant for use by debugger.
3437 Add_Formal_Renamings (Bod_Spec, Bod_Decls, Ent, Loc);
3438 Debug_Private_Data_Declarations (Decls);
3440 -- Put the declarations and the statements from the entry
3442 Bod_Stmts :=
3443 New_List (
3444 Make_Block_Statement (Loc,
3445 Declarations => Decls,
3446 Handled_Statement_Sequence => Handled_Statement_Sequence (N)));
3448 -- Analyze now and reset scopes for declarations so that Scope fields
3449 -- currently denoting the entry will now denote the block scope, and
3450 -- the block's scope will be set to the new procedure entity.
3452 Analyze_Statements (Bod_Stmts);
3454 Block_Id := Entity (Identifier (First (Bod_Stmts)));
3456 Set_Scope (Block_Id, Protected_Body_Subprogram (Ent));
3457 Set_Uses_Sec_Stack (Block_Id, Uses_Sec_Stack (Corresponding_Spec (N)));
3459 Reset_Scopes_To (First (Bod_Stmts), Block_Id);
3460 Set_At_End_Proc (First (Bod_Stmts), At_End_Proc (N));
3462 case Corresponding_Runtime_Package (Pid) is
3463 when System_Tasking_Protected_Objects_Entries =>
3464 Append_To (Bod_Stmts,
3465 Make_Procedure_Call_Statement (End_Loc,
3466 Name =>
3467 New_Occurrence_Of (RTE (RE_Complete_Entry_Body), Loc),
3468 Parameter_Associations => New_List (
3469 Make_Attribute_Reference (End_Loc,
3470 Prefix =>
3471 Make_Selected_Component (End_Loc,
3472 Prefix =>
3473 Make_Identifier (End_Loc, Name_uObject),
3474 Selector_Name =>
3475 Make_Identifier (End_Loc, Name_uObject)),
3476 Attribute_Name => Name_Unchecked_Access))));
3478 when System_Tasking_Protected_Objects_Single_Entry =>
3480 -- Historically, a call to Complete_Single_Entry_Body was
3481 -- inserted, but it was a null procedure.
3483 null;
3485 when others =>
3486 raise Program_Error;
3487 end case;
3489 -- When exceptions cannot be propagated, we never need to call
3490 -- Exception_Complete_Entry_Body.
3492 if No_Exception_Handlers_Set then
3493 return
3494 Make_Subprogram_Body (Loc,
3495 Specification => Bod_Spec,
3496 Declarations => Bod_Decls,
3497 Handled_Statement_Sequence =>
3498 Make_Handled_Sequence_Of_Statements (Loc,
3499 Statements => Bod_Stmts,
3500 End_Label => End_Lab));
3502 else
3503 Ohandle := Make_Others_Choice (Loc);
3504 Set_All_Others (Ohandle);
3506 case Corresponding_Runtime_Package (Pid) is
3507 when System_Tasking_Protected_Objects_Entries =>
3508 Complete :=
3509 New_Occurrence_Of
3510 (RTE (RE_Exceptional_Complete_Entry_Body), Loc);
3512 when System_Tasking_Protected_Objects_Single_Entry =>
3513 Complete :=
3514 New_Occurrence_Of
3515 (RTE (RE_Exceptional_Complete_Single_Entry_Body), Loc);
3517 when others =>
3518 raise Program_Error;
3519 end case;
3521 -- Create body of entry procedure. The renaming declarations are
3522 -- placed ahead of the block that contains the actual entry body.
3524 Proc_Body :=
3525 Make_Subprogram_Body (Loc,
3526 Specification => Bod_Spec,
3527 Declarations => Bod_Decls,
3528 Handled_Statement_Sequence =>
3529 Make_Handled_Sequence_Of_Statements (Loc,
3530 Statements => Bod_Stmts,
3531 End_Label => End_Lab,
3532 Exception_Handlers => New_List (
3533 Make_Implicit_Exception_Handler (EH_Loc,
3534 Exception_Choices => New_List (Ohandle),
3536 Statements => New_List (
3537 Make_Procedure_Call_Statement (EH_Loc,
3538 Name => Complete,
3539 Parameter_Associations => New_List (
3540 Make_Attribute_Reference (EH_Loc,
3541 Prefix =>
3542 Make_Selected_Component (EH_Loc,
3543 Prefix =>
3544 Make_Identifier (EH_Loc, Name_uObject),
3545 Selector_Name =>
3546 Make_Identifier (EH_Loc, Name_uObject)),
3547 Attribute_Name => Name_Unchecked_Access),
3549 Make_Function_Call (EH_Loc,
3550 Name =>
3551 New_Occurrence_Of
3552 (RTE (RE_Get_GNAT_Exception), Loc)))))))));
3554 -- Establish link between subprogram body and source entry body
3556 Set_Corresponding_Entry_Body (Proc_Body, N);
3558 Reset_Scopes_To (Proc_Body, Protected_Body_Subprogram (Ent));
3559 return Proc_Body;
3560 end if;
3561 end Build_Protected_Entry;
3563 -----------------------------------------
3564 -- Build_Protected_Entry_Specification --
3565 -----------------------------------------
3567 function Build_Protected_Entry_Specification
3568 (Loc : Source_Ptr;
3569 Def_Id : Entity_Id;
3570 Ent_Id : Entity_Id) return Node_Id
3572 P : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uP);
3574 begin
3575 Set_Debug_Info_Needed (Def_Id);
3577 if Present (Ent_Id) then
3578 Append_Elmt (P, Accept_Address (Ent_Id));
3579 end if;
3581 return
3582 Make_Procedure_Specification (Loc,
3583 Defining_Unit_Name => Def_Id,
3584 Parameter_Specifications => New_List (
3585 Make_Parameter_Specification (Loc,
3586 Defining_Identifier =>
3587 Make_Defining_Identifier (Loc, Name_uO),
3588 Parameter_Type =>
3589 New_Occurrence_Of (RTE (RE_Address), Loc)),
3591 Make_Parameter_Specification (Loc,
3592 Defining_Identifier => P,
3593 Parameter_Type =>
3594 New_Occurrence_Of (RTE (RE_Address), Loc)),
3596 Make_Parameter_Specification (Loc,
3597 Defining_Identifier =>
3598 Make_Defining_Identifier (Loc, Name_uE),
3599 Parameter_Type =>
3600 New_Occurrence_Of (RTE (RE_Protected_Entry_Index), Loc))));
3601 end Build_Protected_Entry_Specification;
3603 --------------------------
3604 -- Build_Protected_Spec --
3605 --------------------------
3607 function Build_Protected_Spec
3608 (N : Node_Id;
3609 Obj_Type : Entity_Id;
3610 Ident : Entity_Id;
3611 Unprotected : Boolean := False) return List_Id
3613 Loc : constant Source_Ptr := Sloc (N);
3615 Decl : Node_Id;
3616 Formal : Entity_Id;
3617 New_Formal : Entity_Id;
3618 New_Plist : List_Id;
3620 begin
3621 New_Plist := New_List;
3623 Formal := First_Formal (Ident);
3624 while Present (Formal) loop
3625 New_Formal :=
3626 Make_Defining_Identifier (Sloc (Formal), Chars (Formal));
3627 Set_Comes_From_Source (New_Formal, Comes_From_Source (Formal));
3629 if Unprotected then
3630 Mutate_Ekind (New_Formal, Ekind (Formal));
3631 Set_Protected_Formal (Formal, New_Formal);
3632 end if;
3634 Append_To (New_Plist,
3635 Make_Parameter_Specification (Loc,
3636 Defining_Identifier => New_Formal,
3637 Aliased_Present => Aliased_Present (Parent (Formal)),
3638 In_Present => In_Present (Parent (Formal)),
3639 Out_Present => Out_Present (Parent (Formal)),
3640 Parameter_Type => New_Occurrence_Of (Etype (Formal), Loc)));
3642 Next_Formal (Formal);
3643 end loop;
3645 -- If the subprogram is a procedure and the context is not an access
3646 -- to protected subprogram, the parameter is in-out. Otherwise it is
3647 -- an in parameter.
3649 Decl :=
3650 Make_Parameter_Specification (Loc,
3651 Defining_Identifier =>
3652 Make_Defining_Identifier (Loc, Name_uObject),
3653 In_Present => True,
3654 Out_Present =>
3655 (Etype (Ident) = Standard_Void_Type
3656 and then not Is_RTE (Obj_Type, RE_Address)),
3657 Parameter_Type =>
3658 New_Occurrence_Of (Obj_Type, Loc));
3659 Set_Debug_Info_Needed (Defining_Identifier (Decl));
3660 Prepend_To (New_Plist, Decl);
3662 return New_Plist;
3663 end Build_Protected_Spec;
3665 ---------------------------------------
3666 -- Build_Protected_Sub_Specification --
3667 ---------------------------------------
3669 function Build_Protected_Sub_Specification
3670 (N : Node_Id;
3671 Prot_Typ : Entity_Id;
3672 Mode : Subprogram_Protection_Mode) return Node_Id
3674 Loc : constant Source_Ptr := Sloc (N);
3675 Decl : Node_Id;
3676 Def_Id : Entity_Id;
3677 New_Id : Entity_Id;
3678 New_Plist : List_Id;
3679 New_Spec : Node_Id;
3681 Append_Chr : constant array (Subprogram_Protection_Mode) of Character :=
3682 (Dispatching_Mode => ' ',
3683 Protected_Mode => 'P',
3684 Unprotected_Mode => 'N');
3686 begin
3687 if Ekind (Defining_Unit_Name (Specification (N))) = E_Subprogram_Body
3688 then
3689 Decl := Unit_Declaration_Node (Corresponding_Spec (N));
3690 else
3691 Decl := N;
3692 end if;
3694 Def_Id := Defining_Unit_Name (Specification (Decl));
3696 New_Plist :=
3697 Build_Protected_Spec
3698 (Decl, Corresponding_Record_Type (Prot_Typ), Def_Id,
3699 Mode = Unprotected_Mode);
3700 New_Id :=
3701 Make_Defining_Identifier (Loc,
3702 Chars => Build_Selected_Name (Prot_Typ, Def_Id, Append_Chr (Mode)));
3704 -- Reference the original nondispatching subprogram since the analysis
3705 -- of the object.operation notation may need its original name (see
3706 -- Sem_Ch4.Names_Match).
3708 if Mode = Dispatching_Mode then
3709 Mutate_Ekind (New_Id, Ekind (Def_Id));
3710 Set_Original_Protected_Subprogram (New_Id, Def_Id);
3711 end if;
3713 -- Link the protected or unprotected version to the original subprogram
3714 -- it emulates.
3716 Mutate_Ekind (New_Id, Ekind (Def_Id));
3717 Set_Protected_Subprogram (New_Id, Def_Id);
3719 -- The unprotected operation carries the user code, and debugging
3720 -- information must be generated for it, even though this spec does
3721 -- not come from source. It is also convenient to allow gdb to step
3722 -- into the protected operation, even though it only contains lock/
3723 -- unlock calls.
3725 Set_Debug_Info_Needed (New_Id);
3727 -- If a pragma Eliminate applies to the source entity, the internal
3728 -- subprograms will be eliminated as well.
3730 Set_Is_Eliminated (New_Id, Is_Eliminated (Def_Id));
3732 -- It seems we should set Has_Nested_Subprogram here, but instead we
3733 -- currently set it in Expand_N_Protected_Body, because the entity
3734 -- created here isn't the one that Corresponding_Spec of the body
3735 -- will later be set to, and that's the entity where it's needed. ???
3737 Set_Has_Nested_Subprogram (New_Id, Has_Nested_Subprogram (Def_Id));
3739 if Nkind (Specification (Decl)) = N_Procedure_Specification then
3740 New_Spec :=
3741 Make_Procedure_Specification (Loc,
3742 Defining_Unit_Name => New_Id,
3743 Parameter_Specifications => New_Plist);
3745 -- Create a new specification for the anonymous subprogram type
3747 else
3748 New_Spec :=
3749 Make_Function_Specification (Loc,
3750 Defining_Unit_Name => New_Id,
3751 Parameter_Specifications => New_Plist,
3752 Result_Definition =>
3753 Copy_Result_Type (Result_Definition (Specification (Decl))));
3755 Set_Return_Present (Defining_Unit_Name (New_Spec));
3756 end if;
3758 return New_Spec;
3759 end Build_Protected_Sub_Specification;
3761 -------------------------------------
3762 -- Build_Protected_Subprogram_Body --
3763 -------------------------------------
3765 function Build_Protected_Subprogram_Body
3766 (N : Node_Id;
3767 Pid : Node_Id;
3768 N_Op_Spec : Node_Id) return Node_Id
3770 Might_Raise : constant Boolean := Sem_Util.Might_Raise (N);
3772 Loc : constant Source_Ptr := Sloc (N);
3773 Op_Spec : constant Node_Id := Specification (N);
3774 P_Op_Spec : constant Node_Id :=
3775 Build_Protected_Sub_Specification (N, Pid, Protected_Mode);
3777 Lock_Kind : RE_Id;
3778 Lock_Name : Node_Id;
3779 Lock_Stmt : Node_Id;
3780 Object_Parm : Node_Id;
3781 Pformal : Node_Id;
3782 R : Node_Id;
3783 Return_Stmt : Node_Id := Empty; -- init to avoid gcc 3 warning
3784 Pre_Stmts : List_Id := No_List; -- init to avoid gcc 3 warning
3785 Stmts : List_Id;
3786 Sub_Body : Node_Id;
3787 Uactuals : List_Id;
3788 Unprot_Call : Node_Id;
3790 begin
3791 -- Build a list of the formal parameters of the protected version of
3792 -- the subprogram to use as the actual parameters of the unprotected
3793 -- version.
3795 Uactuals := New_List;
3796 Pformal := First (Parameter_Specifications (P_Op_Spec));
3797 while Present (Pformal) loop
3798 Append_To (Uactuals,
3799 Make_Identifier (Loc, Chars (Defining_Identifier (Pformal))));
3800 Next (Pformal);
3801 end loop;
3803 -- Make a call to the unprotected version of the subprogram built above
3804 -- for use by the protected version built below.
3806 if Nkind (Op_Spec) = N_Function_Specification then
3807 if Might_Raise then
3808 Unprot_Call :=
3809 Make_Simple_Return_Statement (Loc,
3810 Expression =>
3811 Make_Function_Call (Loc,
3812 Name =>
3813 Make_Identifier (Loc,
3814 Chars => Chars (Defining_Unit_Name (N_Op_Spec))),
3815 Parameter_Associations => Uactuals));
3817 else
3818 R := Make_Temporary (Loc, 'R');
3820 Unprot_Call :=
3821 Make_Object_Declaration (Loc,
3822 Defining_Identifier => R,
3823 Constant_Present => True,
3824 Object_Definition =>
3825 New_Copy (Result_Definition (N_Op_Spec)),
3826 Expression =>
3827 Make_Function_Call (Loc,
3828 Name =>
3829 Make_Identifier (Loc,
3830 Chars => Chars (Defining_Unit_Name (N_Op_Spec))),
3831 Parameter_Associations => Uactuals));
3833 Return_Stmt :=
3834 Make_Simple_Return_Statement (Loc,
3835 Expression => New_Occurrence_Of (R, Loc));
3836 end if;
3838 if Has_Aspect (Pid, Aspect_Exclusive_Functions)
3839 and then
3840 (No (Find_Value_Of_Aspect (Pid, Aspect_Exclusive_Functions))
3841 or else
3842 Is_True (Static_Boolean (Find_Value_Of_Aspect
3843 (Pid, Aspect_Exclusive_Functions))))
3844 then
3845 Lock_Kind := RE_Lock;
3846 else
3847 Lock_Kind := RE_Lock_Read_Only;
3848 end if;
3849 else
3850 Unprot_Call :=
3851 Make_Procedure_Call_Statement (Loc,
3852 Name =>
3853 Make_Identifier (Loc, Chars (Defining_Unit_Name (N_Op_Spec))),
3854 Parameter_Associations => Uactuals);
3856 Lock_Kind := RE_Lock;
3857 end if;
3859 -- Wrap call in block that will be covered by an at_end handler
3861 if Might_Raise then
3862 Unprot_Call :=
3863 Make_Block_Statement (Loc,
3864 Handled_Statement_Sequence =>
3865 Make_Handled_Sequence_Of_Statements (Loc,
3866 Statements => New_List (Unprot_Call)));
3867 end if;
3869 -- Make the protected subprogram body. This locks the protected
3870 -- object and calls the unprotected version of the subprogram.
3872 case Corresponding_Runtime_Package (Pid) is
3873 when System_Tasking_Protected_Objects_Entries =>
3874 Lock_Name := New_Occurrence_Of (RTE (RE_Lock_Entries), Loc);
3876 when System_Tasking_Protected_Objects_Single_Entry =>
3877 Lock_Name := New_Occurrence_Of (RTE (RE_Lock_Entry), Loc);
3879 when System_Tasking_Protected_Objects =>
3880 Lock_Name := New_Occurrence_Of (RTE (Lock_Kind), Loc);
3882 when others =>
3883 raise Program_Error;
3884 end case;
3886 Object_Parm :=
3887 Make_Attribute_Reference (Loc,
3888 Prefix =>
3889 Make_Selected_Component (Loc,
3890 Prefix => Make_Identifier (Loc, Name_uObject),
3891 Selector_Name => Make_Identifier (Loc, Name_uObject)),
3892 Attribute_Name => Name_Unchecked_Access);
3894 Lock_Stmt :=
3895 Make_Procedure_Call_Statement (Loc,
3896 Name => Lock_Name,
3897 Parameter_Associations => New_List (Object_Parm));
3899 if Abort_Allowed then
3900 Stmts := New_List (
3901 Build_Runtime_Call (Loc, RE_Abort_Defer),
3902 Lock_Stmt);
3904 else
3905 Stmts := New_List (Lock_Stmt);
3906 end if;
3908 if Might_Raise then
3909 Append (Unprot_Call, Stmts);
3910 else
3911 if Nkind (Op_Spec) = N_Function_Specification then
3912 Pre_Stmts := Stmts;
3913 Stmts := Empty_List;
3914 else
3915 Append (Unprot_Call, Stmts);
3916 end if;
3918 Build_Protected_Subprogram_Call_Cleanup (Op_Spec, Pid, Loc, Stmts);
3920 if Nkind (Op_Spec) = N_Function_Specification then
3921 Append_To (Stmts, Return_Stmt);
3922 Append_To (Pre_Stmts,
3923 Make_Block_Statement (Loc,
3924 Declarations => New_List (Unprot_Call),
3925 Handled_Statement_Sequence =>
3926 Make_Handled_Sequence_Of_Statements (Loc,
3927 Statements => Stmts)));
3928 Stmts := Pre_Stmts;
3929 end if;
3930 end if;
3932 Sub_Body :=
3933 Make_Subprogram_Body (Loc,
3934 Declarations => Empty_List,
3935 Specification => P_Op_Spec,
3936 Handled_Statement_Sequence =>
3937 Make_Handled_Sequence_Of_Statements (Loc, Statements => Stmts));
3939 -- Mark this subprogram as a protected subprogram body so that the
3940 -- cleanup will be inserted. This is done only in the Might_Raise
3941 -- case because otherwise the cleanup has already been inserted.
3943 if Might_Raise then
3944 Set_Is_Protected_Subprogram_Body (Sub_Body);
3945 end if;
3947 return Sub_Body;
3948 end Build_Protected_Subprogram_Body;
3950 -------------------------------------
3951 -- Build_Protected_Subprogram_Call --
3952 -------------------------------------
3954 procedure Build_Protected_Subprogram_Call
3955 (N : Node_Id;
3956 Name : Node_Id;
3957 Rec : Node_Id;
3958 External : Boolean := True)
3960 Loc : constant Source_Ptr := Sloc (N);
3961 Sub : constant Entity_Id := Entity (Name);
3962 New_Sub : Node_Id;
3963 Params : List_Id;
3965 begin
3966 if External then
3967 New_Sub := New_Occurrence_Of (External_Subprogram (Sub), Loc);
3968 else
3969 New_Sub :=
3970 New_Occurrence_Of (Protected_Body_Subprogram (Sub), Loc);
3971 end if;
3973 if Present (Parameter_Associations (N)) then
3974 Params := New_Copy_List_Tree (Parameter_Associations (N));
3975 else
3976 Params := New_List;
3977 end if;
3979 -- If the type is an untagged derived type, convert to the root type,
3980 -- which is the one on which the operations are defined.
3982 if Nkind (Rec) = N_Unchecked_Type_Conversion
3983 and then not Is_Tagged_Type (Etype (Rec))
3984 and then Is_Derived_Type (Etype (Rec))
3985 then
3986 Set_Etype (Rec, Root_Type (Etype (Rec)));
3987 Set_Subtype_Mark (Rec,
3988 New_Occurrence_Of (Root_Type (Etype (Rec)), Sloc (N)));
3989 end if;
3991 Prepend (Rec, Params);
3993 if Ekind (Sub) = E_Procedure then
3994 Rewrite (N,
3995 Make_Procedure_Call_Statement (Loc,
3996 Name => New_Sub,
3997 Parameter_Associations => Params));
3999 else
4000 pragma Assert (Ekind (Sub) = E_Function);
4001 Rewrite (N,
4002 Make_Function_Call (Loc,
4003 Name => New_Sub,
4004 Parameter_Associations => Params));
4006 -- Preserve type of call for subsequent processing (required for
4007 -- call to Wrap_Transient_Expression in the case of a shared passive
4008 -- protected).
4010 Set_Etype (N, Etype (New_Sub));
4011 end if;
4013 if External
4014 and then Nkind (Rec) = N_Unchecked_Type_Conversion
4015 and then Is_Entity_Name (Expression (Rec))
4016 and then Is_Shared_Passive (Entity (Expression (Rec)))
4017 then
4018 Add_Shared_Var_Lock_Procs (N);
4019 end if;
4020 end Build_Protected_Subprogram_Call;
4022 ---------------------------------------------
4023 -- Build_Protected_Subprogram_Call_Cleanup --
4024 ---------------------------------------------
4026 procedure Build_Protected_Subprogram_Call_Cleanup
4027 (Op_Spec : Node_Id;
4028 Conc_Typ : Node_Id;
4029 Loc : Source_Ptr;
4030 Stmts : List_Id)
4032 Nam : Node_Id;
4034 begin
4035 -- If the associated protected object has entries, a protected
4036 -- procedure has to service entry queues. In this case generate:
4038 -- Service_Entries (_object._object'Access);
4040 if Nkind (Op_Spec) = N_Procedure_Specification
4041 and then Has_Entries (Conc_Typ)
4042 then
4043 case Corresponding_Runtime_Package (Conc_Typ) is
4044 when System_Tasking_Protected_Objects_Entries =>
4045 Nam := New_Occurrence_Of (RTE (RE_Service_Entries), Loc);
4047 when System_Tasking_Protected_Objects_Single_Entry =>
4048 Nam := New_Occurrence_Of (RTE (RE_Service_Entry), Loc);
4050 when others =>
4051 raise Program_Error;
4052 end case;
4054 Append_To (Stmts,
4055 Make_Procedure_Call_Statement (Loc,
4056 Name => Nam,
4057 Parameter_Associations => New_List (
4058 Make_Attribute_Reference (Loc,
4059 Prefix =>
4060 Make_Selected_Component (Loc,
4061 Prefix => Make_Identifier (Loc, Name_uObject),
4062 Selector_Name => Make_Identifier (Loc, Name_uObject)),
4063 Attribute_Name => Name_Unchecked_Access))));
4065 else
4066 -- Generate:
4067 -- Unlock (_object._object'Access);
4069 case Corresponding_Runtime_Package (Conc_Typ) is
4070 when System_Tasking_Protected_Objects_Entries =>
4071 Nam := New_Occurrence_Of (RTE (RE_Unlock_Entries), Loc);
4073 when System_Tasking_Protected_Objects_Single_Entry =>
4074 Nam := New_Occurrence_Of (RTE (RE_Unlock_Entry), Loc);
4076 when System_Tasking_Protected_Objects =>
4077 Nam := New_Occurrence_Of (RTE (RE_Unlock), Loc);
4079 when others =>
4080 raise Program_Error;
4081 end case;
4083 Append_To (Stmts,
4084 Make_Procedure_Call_Statement (Loc,
4085 Name => Nam,
4086 Parameter_Associations => New_List (
4087 Make_Attribute_Reference (Loc,
4088 Prefix =>
4089 Make_Selected_Component (Loc,
4090 Prefix => Make_Identifier (Loc, Name_uObject),
4091 Selector_Name => Make_Identifier (Loc, Name_uObject)),
4092 Attribute_Name => Name_Unchecked_Access))));
4093 end if;
4095 -- Generate:
4096 -- Abort_Undefer;
4098 if Abort_Allowed then
4099 Append_To (Stmts, Build_Runtime_Call (Loc, RE_Abort_Undefer));
4100 end if;
4101 end Build_Protected_Subprogram_Call_Cleanup;
4103 -------------------------
4104 -- Build_Selected_Name --
4105 -------------------------
4107 function Build_Selected_Name
4108 (Prefix : Entity_Id;
4109 Selector : Entity_Id;
4110 Append_Char : Character := ' ') return Name_Id
4112 Select_Buffer : String (1 .. Hostparm.Max_Name_Length);
4113 Select_Len : Natural;
4115 begin
4116 Get_Name_String (Chars (Selector));
4117 Select_Len := Name_Len;
4118 Select_Buffer (1 .. Select_Len) := Name_Buffer (1 .. Name_Len);
4119 Get_Name_String (Chars (Prefix));
4121 -- If scope is anonymous type, discard suffix to recover name of
4122 -- single protected object. Otherwise use protected type name.
4124 if Name_Buffer (Name_Len) = 'T' then
4125 Name_Len := Name_Len - 1;
4126 end if;
4128 Add_Str_To_Name_Buffer ("__");
4129 for J in 1 .. Select_Len loop
4130 Add_Char_To_Name_Buffer (Select_Buffer (J));
4131 end loop;
4133 -- Now add the Append_Char if specified. The encoding to follow
4134 -- depends on the type of entity. If Append_Char is either 'N' or 'P',
4135 -- then the entity is associated to a protected type subprogram.
4136 -- Otherwise, it is a protected type entry. For each case, the
4137 -- encoding to follow for the suffix is documented in exp_dbug.ads.
4139 -- It would be better to encapsulate this as a routine in Exp_Dbug ???
4141 if Append_Char /= ' ' then
4142 if Append_Char in 'P' | 'N' then
4143 Add_Char_To_Name_Buffer (Append_Char);
4144 return Name_Find;
4145 else
4146 Add_Str_To_Name_Buffer ((1 => '_', 2 => Append_Char));
4147 return New_External_Name (Name_Find, ' ', -1);
4148 end if;
4149 else
4150 return Name_Find;
4151 end if;
4152 end Build_Selected_Name;
4154 -----------------------------
4155 -- Build_Simple_Entry_Call --
4156 -----------------------------
4158 -- A task entry call is converted to a call to Call_Simple
4160 -- declare
4161 -- P : parms := (parm, parm, parm);
4162 -- begin
4163 -- Call_Simple (acceptor-task, entry-index, P'Address);
4164 -- parm := P.param;
4165 -- parm := P.param;
4166 -- ...
4167 -- end;
4169 -- Here Pnn is an aggregate of the type constructed for the entry to hold
4170 -- the parameters, and the constructed aggregate value contains either the
4171 -- parameters or, in the case of non-elementary types, references to these
4172 -- parameters. Then the address of this aggregate is passed to the runtime
4173 -- routine, along with the task id value and the task entry index value.
4174 -- Pnn is only required if parameters are present.
4176 -- The assignments after the call are present only in the case of in-out
4177 -- or out parameters for elementary types, and are used to assign back the
4178 -- resulting values of such parameters.
4180 -- Note: the reason that we insert a block here is that in the context
4181 -- of selects, conditional entry calls etc. the entry call statement
4182 -- appears on its own, not as an element of a list.
4184 -- A protected entry call is converted to a Protected_Entry_Call:
4186 -- declare
4187 -- P : E1_Params := (param, param, param);
4188 -- Pnn : Boolean;
4189 -- Bnn : Communications_Block;
4191 -- declare
4192 -- P : E1_Params := (param, param, param);
4193 -- Bnn : Communications_Block;
4195 -- begin
4196 -- Protected_Entry_Call (
4197 -- Object => po._object'Access,
4198 -- E => <entry index>;
4199 -- Uninterpreted_Data => P'Address;
4200 -- Mode => Simple_Call;
4201 -- Block => Bnn);
4202 -- parm := P.param;
4203 -- parm := P.param;
4204 -- ...
4205 -- end;
4207 procedure Build_Simple_Entry_Call
4208 (N : Node_Id;
4209 Concval : Node_Id;
4210 Ename : Node_Id;
4211 Index : Node_Id)
4213 begin
4214 Expand_Call (N);
4216 -- If call has been inlined, nothing left to do
4218 if Nkind (N) = N_Block_Statement then
4219 return;
4220 end if;
4222 -- Convert entry call to Call_Simple call
4224 declare
4225 Loc : constant Source_Ptr := Sloc (N);
4226 Parms : constant List_Id := Parameter_Associations (N);
4227 Stats : constant List_Id := New_List;
4228 Actual : Node_Id;
4229 Call : Node_Id;
4230 Comm_Name : Entity_Id;
4231 Conctyp : Node_Id;
4232 Decls : List_Id;
4233 Ent : Entity_Id;
4234 Ent_Acc : Entity_Id;
4235 Formal : Node_Id;
4236 Iface_Tag : Entity_Id;
4237 Iface_Typ : Entity_Id;
4238 N_Node : Node_Id;
4239 N_Var : Node_Id;
4240 P : Entity_Id;
4241 Parm1 : Node_Id;
4242 Parm2 : Node_Id;
4243 Parm3 : Node_Id;
4244 Pdecl : Node_Id;
4245 Plist : List_Id;
4246 X : Entity_Id;
4247 Xdecl : Node_Id;
4249 begin
4250 -- Simple entry and entry family cases merge here
4252 Ent := Entity (Ename);
4253 Ent_Acc := Entry_Parameters_Type (Ent);
4254 Conctyp := Etype (Concval);
4256 -- Special case for protected subprogram calls
4258 if Is_Protected_Type (Conctyp)
4259 and then Is_Subprogram (Entity (Ename))
4260 then
4261 if not Is_Eliminated (Entity (Ename)) then
4262 Build_Protected_Subprogram_Call
4263 (N, Ename, Convert_Concurrent (Concval, Conctyp));
4264 Analyze (N);
4265 end if;
4267 return;
4268 end if;
4270 -- First parameter is the Task_Id value from the task value or the
4271 -- Object from the protected object value, obtained by selecting
4272 -- the _Task_Id or _Object from the result of doing an unchecked
4273 -- conversion to convert the value to the corresponding record type.
4275 if Nkind (Concval) = N_Function_Call
4276 and then Is_Task_Type (Conctyp)
4277 and then Ada_Version >= Ada_2005
4278 then
4279 declare
4280 ExpR : constant Node_Id := Relocate_Node (Concval);
4281 Obj : constant Entity_Id := Make_Temporary (Loc, 'F', ExpR);
4282 Decl : Node_Id;
4284 begin
4285 Decl :=
4286 Make_Object_Declaration (Loc,
4287 Defining_Identifier => Obj,
4288 Object_Definition => New_Occurrence_Of (Conctyp, Loc),
4289 Expression => ExpR);
4290 Set_Etype (Obj, Conctyp);
4291 Decls := New_List (Decl);
4292 Rewrite (Concval, New_Occurrence_Of (Obj, Loc));
4293 end;
4295 else
4296 Decls := New_List;
4297 end if;
4299 Parm1 := Concurrent_Ref (Concval);
4301 -- Second parameter is the entry index, computed by the routine
4302 -- provided for this purpose. The value of this expression is
4303 -- assigned to an intermediate variable to assure that any entry
4304 -- family index expressions are evaluated before the entry
4305 -- parameters.
4307 if not Is_Protected_Type (Conctyp)
4308 or else
4309 Corresponding_Runtime_Package (Conctyp) =
4310 System_Tasking_Protected_Objects_Entries
4311 then
4312 X := Make_Defining_Identifier (Loc, Name_uX);
4314 Xdecl :=
4315 Make_Object_Declaration (Loc,
4316 Defining_Identifier => X,
4317 Object_Definition =>
4318 New_Occurrence_Of (RTE (RE_Task_Entry_Index), Loc),
4319 Expression => Actual_Index_Expression (
4320 Loc, Entity (Ename), Index, Concval));
4322 Append_To (Decls, Xdecl);
4323 Parm2 := New_Occurrence_Of (X, Loc);
4325 else
4326 Xdecl := Empty;
4327 Parm2 := Empty;
4328 end if;
4330 -- The third parameter is the packaged parameters. If there are
4331 -- none, then it is just the null address, since nothing is passed.
4333 if No (Parms) then
4334 Parm3 := New_Occurrence_Of (RTE (RE_Null_Address), Loc);
4335 P := Empty;
4337 -- Case of parameters present, where third argument is the address
4338 -- of a packaged record containing the required parameter values.
4340 else
4341 -- First build a list of parameter values, which are references to
4342 -- objects of the parameter types.
4344 Plist := New_List;
4346 Actual := First_Actual (N);
4347 Formal := First_Formal (Ent);
4348 while Present (Actual) loop
4350 -- If it is a by-copy type, copy it to a new variable. The
4351 -- packaged record has a field that points to this variable.
4353 if Is_By_Copy_Type (Etype (Actual)) then
4354 N_Node :=
4355 Make_Object_Declaration (Loc,
4356 Defining_Identifier => Make_Temporary (Loc, 'J'),
4357 Aliased_Present => True,
4358 Object_Definition =>
4359 New_Occurrence_Of (Etype (Formal), Loc));
4361 -- Mark the object as not needing initialization since the
4362 -- initialization is performed separately, avoiding errors
4363 -- on cases such as formals of null-excluding access types.
4365 Set_No_Initialization (N_Node);
4367 -- We must make a separate assignment statement for the
4368 -- case of limited types. We cannot assign it unless the
4369 -- Assignment_OK flag is set first. An out formal of an
4370 -- access type or whose type has a Default_Value must also
4371 -- be initialized from the actual (see RM 6.4.1 (13-13.1)),
4372 -- but no constraint, predicate, or null-exclusion check is
4373 -- applied before the call.
4375 if Ekind (Formal) /= E_Out_Parameter
4376 or else Is_Access_Type (Etype (Formal))
4377 or else
4378 (Is_Scalar_Type (Etype (Formal))
4379 and then
4380 Present (Default_Aspect_Value (Etype (Formal))))
4381 then
4382 N_Var :=
4383 New_Occurrence_Of (Defining_Identifier (N_Node), Loc);
4384 Set_Assignment_OK (N_Var);
4385 Append_To (Stats,
4386 Make_Assignment_Statement (Loc,
4387 Name => N_Var,
4388 Expression => Relocate_Node (Actual)));
4390 -- Mark the object as internal, so we don't later reset
4391 -- No_Initialization flag in Default_Initialize_Object,
4392 -- which would lead to needless default initialization.
4393 -- We don't set this outside the if statement, because
4394 -- out scalar parameters without Default_Value do require
4395 -- default initialization if Initialize_Scalars applies.
4397 Set_Is_Internal (Defining_Identifier (N_Node));
4399 -- If actual is an out parameter of a null-excluding
4400 -- access type, there is access check on entry, so set
4401 -- Suppress_Assignment_Checks on the generated statement
4402 -- that assigns the actual to the parameter block.
4404 Set_Suppress_Assignment_Checks (Last (Stats));
4405 end if;
4407 Append (N_Node, Decls);
4409 Append_To (Plist,
4410 Make_Attribute_Reference (Loc,
4411 Attribute_Name => Name_Unchecked_Access,
4412 Prefix =>
4413 New_Occurrence_Of
4414 (Defining_Identifier (N_Node), Loc)));
4416 else
4417 -- Interface class-wide formal
4419 if Ada_Version >= Ada_2005
4420 and then Ekind (Etype (Formal)) = E_Class_Wide_Type
4421 and then Is_Interface (Etype (Formal))
4422 then
4423 Iface_Typ := Etype (Etype (Formal));
4425 -- Generate:
4426 -- formal_iface_type! (actual.iface_tag)'reference
4428 Iface_Tag :=
4429 Find_Interface_Tag (Etype (Actual), Iface_Typ);
4430 pragma Assert (Present (Iface_Tag));
4432 Append_To (Plist,
4433 Make_Reference (Loc,
4434 Unchecked_Convert_To (Iface_Typ,
4435 Make_Selected_Component (Loc,
4436 Prefix =>
4437 Relocate_Node (Actual),
4438 Selector_Name =>
4439 New_Occurrence_Of (Iface_Tag, Loc)))));
4440 else
4441 -- Generate:
4442 -- actual'reference
4444 Append_To (Plist,
4445 Make_Reference (Loc, Relocate_Node (Actual)));
4446 end if;
4447 end if;
4449 Next_Actual (Actual);
4450 Next_Formal_With_Extras (Formal);
4451 end loop;
4453 -- Now build the declaration of parameters initialized with the
4454 -- aggregate containing this constructed parameter list.
4456 P := Make_Defining_Identifier (Loc, Name_uP);
4458 Pdecl :=
4459 Make_Object_Declaration (Loc,
4460 Defining_Identifier => P,
4461 Object_Definition =>
4462 New_Occurrence_Of (Designated_Type (Ent_Acc), Loc),
4463 Expression =>
4464 Make_Aggregate (Loc, Expressions => Plist));
4466 Parm3 :=
4467 Make_Attribute_Reference (Loc,
4468 Prefix => New_Occurrence_Of (P, Loc),
4469 Attribute_Name => Name_Address);
4471 Append (Pdecl, Decls);
4472 end if;
4474 -- Now we can create the call, case of protected type
4476 if Is_Protected_Type (Conctyp) then
4477 case Corresponding_Runtime_Package (Conctyp) is
4478 when System_Tasking_Protected_Objects_Entries =>
4480 -- Change the type of the index declaration
4482 Set_Object_Definition (Xdecl,
4483 New_Occurrence_Of (RTE (RE_Protected_Entry_Index), Loc));
4485 -- Some additional declarations for protected entry calls
4487 if No (Decls) then
4488 Decls := New_List;
4489 end if;
4491 -- Bnn : Communications_Block;
4493 Comm_Name := Make_Temporary (Loc, 'B');
4495 Append_To (Decls,
4496 Make_Object_Declaration (Loc,
4497 Defining_Identifier => Comm_Name,
4498 Object_Definition =>
4499 New_Occurrence_Of
4500 (RTE (RE_Communication_Block), Loc)));
4502 -- Some additional statements for protected entry calls
4504 -- Protected_Entry_Call
4505 -- (Object => po._object'Access,
4506 -- E => <entry index>;
4507 -- Uninterpreted_Data => P'Address;
4508 -- Mode => Simple_Call;
4509 -- Block => Bnn);
4511 Call :=
4512 Make_Procedure_Call_Statement (Loc,
4513 Name =>
4514 New_Occurrence_Of (RTE (RE_Protected_Entry_Call), Loc),
4516 Parameter_Associations => New_List (
4517 Make_Attribute_Reference (Loc,
4518 Attribute_Name => Name_Unchecked_Access,
4519 Prefix => Parm1),
4520 Parm2,
4521 Parm3,
4522 New_Occurrence_Of (RTE (RE_Simple_Call), Loc),
4523 New_Occurrence_Of (Comm_Name, Loc)));
4525 when System_Tasking_Protected_Objects_Single_Entry =>
4527 -- Protected_Single_Entry_Call
4528 -- (Object => po._object'Access,
4529 -- Uninterpreted_Data => P'Address);
4531 Call :=
4532 Make_Procedure_Call_Statement (Loc,
4533 Name =>
4534 New_Occurrence_Of
4535 (RTE (RE_Protected_Single_Entry_Call), Loc),
4537 Parameter_Associations => New_List (
4538 Make_Attribute_Reference (Loc,
4539 Attribute_Name => Name_Unchecked_Access,
4540 Prefix => Parm1),
4541 Parm3));
4543 when others =>
4544 raise Program_Error;
4545 end case;
4547 -- Case of task type
4549 else
4550 Call :=
4551 Make_Procedure_Call_Statement (Loc,
4552 Name =>
4553 New_Occurrence_Of (RTE (RE_Call_Simple), Loc),
4554 Parameter_Associations => New_List (Parm1, Parm2, Parm3));
4556 end if;
4558 Append_To (Stats, Call);
4560 -- If there are out or in/out parameters by copy add assignment
4561 -- statements for the result values.
4563 if Present (Parms) then
4564 Actual := First_Actual (N);
4565 Formal := First_Formal (Ent);
4567 Set_Assignment_OK (Actual);
4568 while Present (Actual) loop
4569 if Is_By_Copy_Type (Etype (Actual))
4570 and then Ekind (Formal) /= E_In_Parameter
4571 then
4572 N_Node :=
4573 Make_Assignment_Statement (Loc,
4574 Name => New_Copy (Actual),
4575 Expression =>
4576 Make_Explicit_Dereference (Loc,
4577 Make_Selected_Component (Loc,
4578 Prefix => New_Occurrence_Of (P, Loc),
4579 Selector_Name =>
4580 Make_Identifier (Loc, Chars (Formal)))));
4582 -- In all cases (including limited private types) we want
4583 -- the assignment to be valid.
4585 Set_Assignment_OK (Name (N_Node));
4587 -- If the call is the triggering alternative in an
4588 -- asynchronous select, or the entry_call alternative of a
4589 -- conditional entry call, the assignments for in-out
4590 -- parameters are incorporated into the statement list that
4591 -- follows, so that there are executed only if the entry
4592 -- call succeeds.
4594 if (Nkind (Parent (N)) = N_Triggering_Alternative
4595 and then N = Triggering_Statement (Parent (N)))
4596 or else
4597 (Nkind (Parent (N)) = N_Entry_Call_Alternative
4598 and then N = Entry_Call_Statement (Parent (N)))
4599 then
4600 if No (Statements (Parent (N))) then
4601 Set_Statements (Parent (N), New_List);
4602 end if;
4604 Prepend (N_Node, Statements (Parent (N)));
4606 else
4607 Insert_After (Call, N_Node);
4608 end if;
4609 end if;
4611 Next_Actual (Actual);
4612 Next_Formal_With_Extras (Formal);
4613 end loop;
4614 end if;
4616 -- Finally, create block and analyze it
4618 Rewrite (N,
4619 Make_Block_Statement (Loc,
4620 Declarations => Decls,
4621 Handled_Statement_Sequence =>
4622 Make_Handled_Sequence_Of_Statements (Loc,
4623 Statements => Stats)));
4625 Analyze (N);
4626 end;
4627 end Build_Simple_Entry_Call;
4629 --------------------------------
4630 -- Build_Task_Activation_Call --
4631 --------------------------------
4633 procedure Build_Task_Activation_Call (N : Node_Id) is
4634 function Activation_Call_Loc return Source_Ptr;
4635 -- Find a suitable source location for the activation call
4637 -------------------------
4638 -- Activation_Call_Loc --
4639 -------------------------
4641 function Activation_Call_Loc return Source_Ptr is
4642 begin
4643 -- The activation call must carry the location of the "end" keyword
4644 -- when the context is a package declaration.
4646 if Nkind (N) = N_Package_Declaration then
4647 return End_Keyword_Location (N);
4649 -- Otherwise the activation call must carry the location of the
4650 -- "begin" keyword.
4652 else
4653 return Begin_Keyword_Location (N);
4654 end if;
4655 end Activation_Call_Loc;
4657 -- Local variables
4659 Chain : Entity_Id;
4660 Call : Node_Id;
4661 Loc : Source_Ptr;
4662 Name : Node_Id;
4663 Owner : Node_Id;
4664 Stmt : Node_Id;
4666 -- Start of processing for Build_Task_Activation_Call
4668 begin
4669 -- For sequential elaboration policy, all the tasks will be activated at
4670 -- the end of the elaboration.
4672 if Partition_Elaboration_Policy = 'S' then
4673 return;
4675 -- Do not create an activation call for a package spec if the package
4676 -- has a completing body. The activation call will be inserted after
4677 -- the "begin" of the body.
4679 elsif Nkind (N) = N_Package_Declaration
4680 and then Present (Corresponding_Body (N))
4681 then
4682 return;
4683 end if;
4685 -- Obtain the activation chain entity. Block statements, entry bodies,
4686 -- subprogram bodies, and task bodies keep the entity in their nodes.
4687 -- Package bodies on the other hand store it in the declaration of the
4688 -- corresponding package spec.
4690 Owner := N;
4692 if Nkind (Owner) = N_Package_Body then
4693 Owner := Unit_Declaration_Node (Corresponding_Spec (Owner));
4694 end if;
4696 Chain := Activation_Chain_Entity (Owner);
4698 -- Nothing to do when there are no tasks to activate. This is indicated
4699 -- by a missing activation chain entity; also skip generating it when
4700 -- it is a ghost entity.
4702 if No (Chain) or else Is_Ignored_Ghost_Entity (Chain) then
4703 return;
4705 -- The availability of the activation chain entity does not ensure
4706 -- that we have tasks to activate because it may have been declared
4707 -- by the frontend to pass a required extra formal to a build-in-place
4708 -- subprogram call. If we are within the scope of a protected type and
4709 -- pragma Detect_Blocking is active we can assume that no tasks will be
4710 -- activated; if tasks are created in a protected object and this pragma
4711 -- is active then the frontend emits a warning and Program_Error is
4712 -- raised at runtime.
4714 elsif Detect_Blocking and then Within_Protected_Type (Current_Scope) then
4715 return;
4716 end if;
4718 -- The location of the activation call must be as close as possible to
4719 -- the intended semantic location of the activation because the ABE
4720 -- mechanism relies heavily on accurate locations.
4722 Loc := Activation_Call_Loc;
4724 if Restricted_Profile then
4725 Name := New_Occurrence_Of (RTE (RE_Activate_Restricted_Tasks), Loc);
4726 else
4727 Name := New_Occurrence_Of (RTE (RE_Activate_Tasks), Loc);
4728 end if;
4730 Call :=
4731 Make_Procedure_Call_Statement (Loc,
4732 Name => Name,
4733 Parameter_Associations =>
4734 New_List (Make_Attribute_Reference (Loc,
4735 Prefix => New_Occurrence_Of (Chain, Loc),
4736 Attribute_Name => Name_Unchecked_Access)));
4738 if Nkind (N) = N_Package_Declaration then
4739 if Present (Private_Declarations (Specification (N))) then
4740 Append (Call, Private_Declarations (Specification (N)));
4741 else
4742 Append (Call, Visible_Declarations (Specification (N)));
4743 end if;
4745 else
4746 -- The call goes at the start of the statement sequence after the
4747 -- start of exception range label if one is present.
4749 if Present (Handled_Statement_Sequence (N)) then
4750 Stmt := First (Statements (Handled_Statement_Sequence (N)));
4752 -- A special case, skip exception range label if one is present
4753 -- (from front end zcx processing).
4755 if Nkind (Stmt) = N_Label and then Exception_Junk (Stmt) then
4756 Next (Stmt);
4757 end if;
4759 -- Another special case, if the first statement is a block from
4760 -- optimization of a local raise to a goto, then the call goes
4761 -- inside this block.
4763 if Nkind (Stmt) = N_Block_Statement
4764 and then Exception_Junk (Stmt)
4765 then
4766 Stmt := First (Statements (Handled_Statement_Sequence (Stmt)));
4767 end if;
4769 -- Insertion point is after any exception label pushes, since we
4770 -- want it covered by any local handlers.
4772 while Nkind (Stmt) in N_Push_xxx_Label loop
4773 Next (Stmt);
4774 end loop;
4776 -- Now we have the proper insertion point
4778 Insert_Before (Stmt, Call);
4780 else
4781 Set_Handled_Statement_Sequence (N,
4782 Make_Handled_Sequence_Of_Statements (Loc,
4783 Statements => New_List (Call)));
4784 end if;
4785 end if;
4787 Analyze (Call);
4789 if Legacy_Elaboration_Checks then
4790 Check_Task_Activation (N);
4791 end if;
4792 end Build_Task_Activation_Call;
4794 -------------------------------
4795 -- Build_Task_Allocate_Block --
4796 -------------------------------
4798 procedure Build_Task_Allocate_Block
4799 (Actions : List_Id;
4800 N : Node_Id;
4801 Args : List_Id)
4803 T : constant Entity_Id := Entity (Expression (N));
4804 Init : constant Entity_Id := Base_Init_Proc (T);
4805 Loc : constant Source_Ptr := Sloc (N);
4806 Chain : constant Entity_Id :=
4807 Make_Defining_Identifier (Loc, Name_uChain);
4808 Blkent : constant Entity_Id := Make_Temporary (Loc, 'A');
4809 Block : Node_Id;
4811 begin
4812 Block :=
4813 Make_Block_Statement (Loc,
4814 Identifier => New_Occurrence_Of (Blkent, Loc),
4815 Declarations => New_List (
4817 -- _Chain : Activation_Chain;
4819 Make_Object_Declaration (Loc,
4820 Defining_Identifier => Chain,
4821 Aliased_Present => True,
4822 Object_Definition =>
4823 New_Occurrence_Of (RTE (RE_Activation_Chain), Loc))),
4825 Handled_Statement_Sequence =>
4826 Make_Handled_Sequence_Of_Statements (Loc,
4828 Statements => New_List (
4830 -- Init (Args);
4832 Make_Procedure_Call_Statement (Loc,
4833 Name => New_Occurrence_Of (Init, Loc),
4834 Parameter_Associations => Args),
4836 -- Activate_Tasks (_Chain);
4838 Make_Procedure_Call_Statement (Loc,
4839 Name => New_Occurrence_Of (RTE (RE_Activate_Tasks), Loc),
4840 Parameter_Associations => New_List (
4841 Make_Attribute_Reference (Loc,
4842 Prefix => New_Occurrence_Of (Chain, Loc),
4843 Attribute_Name => Name_Unchecked_Access))))),
4845 Has_Created_Identifier => True,
4846 Is_Task_Allocation_Block => True);
4848 Append_To (Actions,
4849 Make_Implicit_Label_Declaration (Loc,
4850 Defining_Identifier => Blkent,
4851 Label_Construct => Block));
4853 Append_To (Actions, Block);
4855 Set_Activation_Chain_Entity (Block, Chain);
4856 end Build_Task_Allocate_Block;
4858 -----------------------------------------------
4859 -- Build_Task_Allocate_Block_With_Init_Stmts --
4860 -----------------------------------------------
4862 procedure Build_Task_Allocate_Block_With_Init_Stmts
4863 (Actions : List_Id;
4864 N : Node_Id;
4865 Init_Stmts : List_Id)
4867 Loc : constant Source_Ptr := Sloc (N);
4868 Chain : constant Entity_Id :=
4869 Make_Defining_Identifier (Loc, Name_uChain);
4870 Blkent : constant Entity_Id := Make_Temporary (Loc, 'A');
4871 Block : Node_Id;
4873 begin
4874 Append_To (Init_Stmts,
4875 Make_Procedure_Call_Statement (Loc,
4876 Name => New_Occurrence_Of (RTE (RE_Activate_Tasks), Loc),
4877 Parameter_Associations => New_List (
4878 Make_Attribute_Reference (Loc,
4879 Prefix => New_Occurrence_Of (Chain, Loc),
4880 Attribute_Name => Name_Unchecked_Access))));
4882 Block :=
4883 Make_Block_Statement (Loc,
4884 Identifier => New_Occurrence_Of (Blkent, Loc),
4885 Declarations => New_List (
4887 -- _Chain : Activation_Chain;
4889 Make_Object_Declaration (Loc,
4890 Defining_Identifier => Chain,
4891 Aliased_Present => True,
4892 Object_Definition =>
4893 New_Occurrence_Of (RTE (RE_Activation_Chain), Loc))),
4895 Handled_Statement_Sequence =>
4896 Make_Handled_Sequence_Of_Statements (Loc, Init_Stmts),
4898 Has_Created_Identifier => True,
4899 Is_Task_Allocation_Block => True);
4901 Append_To (Actions,
4902 Make_Implicit_Label_Declaration (Loc,
4903 Defining_Identifier => Blkent,
4904 Label_Construct => Block));
4906 Append_To (Actions, Block);
4908 Set_Activation_Chain_Entity (Block, Chain);
4909 end Build_Task_Allocate_Block_With_Init_Stmts;
4911 -----------------------------------
4912 -- Build_Task_Proc_Specification --
4913 -----------------------------------
4915 function Build_Task_Proc_Specification (T : Entity_Id) return Node_Id is
4916 Loc : constant Source_Ptr := Sloc (T);
4917 Spec_Id : Entity_Id;
4919 begin
4920 -- Case of explicit task type, suffix TB
4922 if Comes_From_Source (T) then
4923 Spec_Id :=
4924 Make_Defining_Identifier (Loc, New_External_Name (Chars (T), "TB"));
4926 -- Case of anonymous task type, suffix B
4928 else
4929 Spec_Id :=
4930 Make_Defining_Identifier (Loc, New_External_Name (Chars (T), 'B'));
4931 end if;
4933 Set_Is_Internal (Spec_Id);
4935 -- Associate the procedure with the task, if this is the declaration
4936 -- (and not the body) of the procedure.
4938 if No (Task_Body_Procedure (T)) then
4939 Set_Task_Body_Procedure (T, Spec_Id);
4940 end if;
4942 return
4943 Make_Procedure_Specification (Loc,
4944 Defining_Unit_Name => Spec_Id,
4945 Parameter_Specifications => New_List (
4946 Make_Parameter_Specification (Loc,
4947 Defining_Identifier =>
4948 Make_Defining_Identifier (Loc, Name_uTask),
4949 Parameter_Type =>
4950 Make_Access_Definition (Loc,
4951 Subtype_Mark =>
4952 New_Occurrence_Of (Corresponding_Record_Type (T), Loc)))));
4953 end Build_Task_Proc_Specification;
4955 ---------------------------------------
4956 -- Build_Unprotected_Subprogram_Body --
4957 ---------------------------------------
4959 function Build_Unprotected_Subprogram_Body
4960 (N : Node_Id;
4961 Pid : Node_Id) return Node_Id
4963 Decls : constant List_Id := Declarations (N);
4965 begin
4966 -- Add renamings for the Protection object, discriminals, privals, and
4967 -- the entry index constant for use by debugger.
4969 Debug_Private_Data_Declarations (Decls);
4971 -- Make an unprotected version of the subprogram for use within the same
4972 -- object, with a new name and an additional parameter representing the
4973 -- object.
4975 return
4976 Make_Subprogram_Body (Sloc (N),
4977 Specification =>
4978 Build_Protected_Sub_Specification (N, Pid, Unprotected_Mode),
4979 Declarations => Decls,
4980 Handled_Statement_Sequence => Handled_Statement_Sequence (N),
4981 At_End_Proc => At_End_Proc (N));
4982 end Build_Unprotected_Subprogram_Body;
4984 ----------------------------
4985 -- Collect_Entry_Families --
4986 ----------------------------
4988 procedure Collect_Entry_Families
4989 (Loc : Source_Ptr;
4990 Cdecls : List_Id;
4991 Current_Node : in out Node_Id;
4992 Conctyp : Entity_Id)
4994 Efam : Entity_Id;
4995 Efam_Decl : Node_Id;
4996 Efam_Type : Entity_Id;
4998 begin
4999 Efam := First_Entity (Conctyp);
5000 while Present (Efam) loop
5001 if Ekind (Efam) = E_Entry_Family then
5002 Efam_Type := Make_Temporary (Loc, 'F');
5004 declare
5005 Eityp : constant Entity_Id := Entry_Index_Type (Efam);
5006 Lo : constant Node_Id := Type_Low_Bound (Eityp);
5007 Hi : constant Node_Id := Type_High_Bound (Eityp);
5008 Bdecl : Node_Id;
5009 Bityp : Entity_Id;
5011 begin
5012 Bityp := Base_Type (Eityp);
5014 if Is_Potentially_Large_Family (Bityp, Conctyp, Lo, Hi) then
5015 Bityp := Make_Temporary (Loc, 'B');
5017 Bdecl :=
5018 Make_Subtype_Declaration (Loc,
5019 Defining_Identifier => Bityp,
5020 Subtype_Indication =>
5021 Make_Subtype_Indication (Loc,
5022 Subtype_Mark =>
5023 New_Occurrence_Of (Standard_Integer, Loc),
5024 Constraint =>
5025 Make_Range_Constraint (Loc,
5026 Range_Expression => Make_Range (Loc,
5027 Make_Integer_Literal
5028 (Loc, -Entry_Family_Bound),
5029 Make_Integer_Literal
5030 (Loc, Entry_Family_Bound - 1)))));
5032 Insert_After (Current_Node, Bdecl);
5033 Current_Node := Bdecl;
5034 Analyze (Bdecl);
5035 end if;
5037 Efam_Decl :=
5038 Make_Full_Type_Declaration (Loc,
5039 Defining_Identifier => Efam_Type,
5040 Type_Definition =>
5041 Make_Unconstrained_Array_Definition (Loc,
5042 Subtype_Marks =>
5043 (New_List (New_Occurrence_Of (Bityp, Loc))),
5045 Component_Definition =>
5046 Make_Component_Definition (Loc,
5047 Aliased_Present => False,
5048 Subtype_Indication =>
5049 New_Occurrence_Of (Standard_Character, Loc))));
5050 end;
5052 Insert_After (Current_Node, Efam_Decl);
5053 Current_Node := Efam_Decl;
5054 Analyze (Efam_Decl);
5056 Append_To (Cdecls,
5057 Make_Component_Declaration (Loc,
5058 Defining_Identifier =>
5059 Make_Defining_Identifier (Loc, Chars (Efam)),
5061 Component_Definition =>
5062 Make_Component_Definition (Loc,
5063 Aliased_Present => False,
5064 Subtype_Indication =>
5065 Make_Subtype_Indication (Loc,
5066 Subtype_Mark =>
5067 New_Occurrence_Of (Efam_Type, Loc),
5069 Constraint =>
5070 Make_Index_Or_Discriminant_Constraint (Loc,
5071 Constraints => New_List (
5072 New_Occurrence_Of (Entry_Index_Type (Efam),
5073 Loc)))))));
5074 end if;
5076 Next_Entity (Efam);
5077 end loop;
5078 end Collect_Entry_Families;
5080 -----------------------
5081 -- Concurrent_Object --
5082 -----------------------
5084 function Concurrent_Object
5085 (Spec_Id : Entity_Id;
5086 Conc_Typ : Entity_Id) return Entity_Id
5088 begin
5089 -- Parameter _O or _object
5091 if Is_Protected_Type (Conc_Typ) then
5092 return First_Formal (Protected_Body_Subprogram (Spec_Id));
5094 -- Parameter _task
5096 else
5097 pragma Assert (Is_Task_Type (Conc_Typ));
5098 return First_Formal (Task_Body_Procedure (Conc_Typ));
5099 end if;
5100 end Concurrent_Object;
5102 ----------------------
5103 -- Copy_Result_Type --
5104 ----------------------
5106 function Copy_Result_Type (Res : Node_Id) return Node_Id is
5107 New_Res : constant Node_Id := New_Copy_Tree (Res);
5108 Par_Spec : Node_Id;
5109 Formal : Entity_Id;
5111 begin
5112 -- If the result type is an access_to_subprogram, we must create new
5113 -- entities for its spec.
5115 if Nkind (New_Res) = N_Access_Definition
5116 and then Present (Access_To_Subprogram_Definition (New_Res))
5117 then
5118 -- Provide new entities for the formals
5120 Par_Spec := First (Parameter_Specifications
5121 (Access_To_Subprogram_Definition (New_Res)));
5122 while Present (Par_Spec) loop
5123 Formal := Defining_Identifier (Par_Spec);
5124 Set_Defining_Identifier (Par_Spec,
5125 Make_Defining_Identifier (Sloc (Formal), Chars (Formal)));
5126 Next (Par_Spec);
5127 end loop;
5128 end if;
5130 return New_Res;
5131 end Copy_Result_Type;
5133 --------------------
5134 -- Concurrent_Ref --
5135 --------------------
5137 -- The expression returned for a reference to a concurrent object has the
5138 -- form:
5140 -- taskV!(name)._Task_Id
5142 -- for a task, and
5144 -- objectV!(name)._Object
5146 -- for a protected object. For the case of an access to a concurrent
5147 -- object, there is an extra explicit dereference:
5149 -- taskV!(name.all)._Task_Id
5150 -- objectV!(name.all)._Object
5152 -- here taskV and objectV are the types for the associated records, which
5153 -- contain the required _Task_Id and _Object fields for tasks and protected
5154 -- objects, respectively.
5156 -- For the case of a task type name, the expression is
5158 -- Self;
5160 -- i.e. a call to the Self function which returns precisely this Task_Id
5162 -- For the case of a protected type name, the expression is
5164 -- objectR
5166 -- which is a renaming of the _object field of the current object
5167 -- record, passed into protected operations as a parameter.
5169 function Concurrent_Ref (N : Node_Id) return Node_Id is
5170 Loc : constant Source_Ptr := Sloc (N);
5171 Ntyp : constant Entity_Id := Etype (N);
5172 Dtyp : Entity_Id;
5173 Sel : Name_Id;
5175 function Is_Current_Task (T : Entity_Id) return Boolean;
5176 -- Check whether the reference is to the immediately enclosing task
5177 -- type, or to an outer one (rare but legal).
5179 ---------------------
5180 -- Is_Current_Task --
5181 ---------------------
5183 function Is_Current_Task (T : Entity_Id) return Boolean is
5184 Scop : Entity_Id;
5186 begin
5187 Scop := Current_Scope;
5188 while Present (Scop) and then Scop /= Standard_Standard loop
5189 if Scop = T then
5190 return True;
5192 elsif Is_Task_Type (Scop) then
5193 return False;
5195 -- If this is a procedure nested within the task type, we must
5196 -- assume that it can be called from an inner task, and therefore
5197 -- cannot treat it as a local reference.
5199 elsif Is_Overloadable (Scop) and then In_Open_Scopes (T) then
5200 return False;
5202 else
5203 Scop := Scope (Scop);
5204 end if;
5205 end loop;
5207 -- We know that we are within the task body, so should have found it
5208 -- in scope.
5210 raise Program_Error;
5211 end Is_Current_Task;
5213 -- Start of processing for Concurrent_Ref
5215 begin
5216 if Is_Access_Type (Ntyp) then
5217 Dtyp := Designated_Type (Ntyp);
5219 if Is_Protected_Type (Dtyp) then
5220 Sel := Name_uObject;
5221 else
5222 Sel := Name_uTask_Id;
5223 end if;
5225 return
5226 Make_Selected_Component (Loc,
5227 Prefix =>
5228 Unchecked_Convert_To (Corresponding_Record_Type (Dtyp),
5229 Make_Explicit_Dereference (Loc, N)),
5230 Selector_Name => Make_Identifier (Loc, Sel));
5232 elsif Is_Entity_Name (N) and then Is_Concurrent_Type (Entity (N)) then
5233 if Is_Task_Type (Entity (N)) then
5235 if Is_Current_Task (Entity (N)) then
5236 return
5237 Make_Function_Call (Loc,
5238 Name => New_Occurrence_Of (RTE (RE_Self), Loc));
5240 else
5241 declare
5242 Decl : Node_Id;
5243 T_Self : constant Entity_Id := Make_Temporary (Loc, 'T');
5244 T_Body : constant Node_Id :=
5245 Parent (Corresponding_Body (Parent (Entity (N))));
5247 begin
5248 Decl :=
5249 Make_Object_Declaration (Loc,
5250 Defining_Identifier => T_Self,
5251 Object_Definition =>
5252 New_Occurrence_Of (RTE (RO_ST_Task_Id), Loc),
5253 Expression =>
5254 Make_Function_Call (Loc,
5255 Name => New_Occurrence_Of (RTE (RE_Self), Loc)));
5256 Prepend (Decl, Declarations (T_Body));
5257 Analyze (Decl);
5258 Set_Scope (T_Self, Entity (N));
5259 return New_Occurrence_Of (T_Self, Loc);
5260 end;
5261 end if;
5263 else
5264 pragma Assert (Is_Protected_Type (Entity (N)));
5266 return
5267 New_Occurrence_Of (Find_Protection_Object (Current_Scope), Loc);
5268 end if;
5270 else
5271 if Is_Protected_Type (Ntyp) then
5272 Sel := Name_uObject;
5273 elsif Is_Task_Type (Ntyp) then
5274 Sel := Name_uTask_Id;
5275 else
5276 raise Program_Error;
5277 end if;
5279 return
5280 Make_Selected_Component (Loc,
5281 Prefix =>
5282 Unchecked_Convert_To (Corresponding_Record_Type (Ntyp),
5283 New_Copy_Tree (N)),
5284 Selector_Name => Make_Identifier (Loc, Sel));
5285 end if;
5286 end Concurrent_Ref;
5288 ------------------------
5289 -- Convert_Concurrent --
5290 ------------------------
5292 function Convert_Concurrent
5293 (N : Node_Id;
5294 Typ : Entity_Id) return Node_Id
5296 begin
5297 if not Is_Concurrent_Type (Typ) then
5298 return N;
5299 else
5300 return
5301 Unchecked_Convert_To
5302 (Corresponding_Record_Type (Typ), New_Copy_Tree (N));
5303 end if;
5304 end Convert_Concurrent;
5306 -------------------------------------
5307 -- Create_Secondary_Stack_For_Task --
5308 -------------------------------------
5310 function Create_Secondary_Stack_For_Task (T : Node_Id) return Boolean is
5311 begin
5312 return
5313 (Restriction_Active (No_Implicit_Heap_Allocations)
5314 or else Restriction_Active (No_Implicit_Task_Allocations))
5315 and then not Restriction_Active (No_Secondary_Stack)
5316 and then Has_Rep_Pragma
5317 (T, Name_Secondary_Stack_Size, Check_Parents => False);
5318 end Create_Secondary_Stack_For_Task;
5320 -------------------------------------
5321 -- Debug_Private_Data_Declarations --
5322 -------------------------------------
5324 procedure Debug_Private_Data_Declarations (Decls : List_Id) is
5325 Debug_Nod : Node_Id;
5326 Decl : Node_Id;
5328 begin
5329 Decl := First (Decls);
5330 while Present (Decl) and then not Comes_From_Source (Decl) loop
5332 -- Declaration for concurrent entity _object and its access type,
5333 -- along with the entry index subtype:
5334 -- type prot_typVP is access prot_typV;
5335 -- _object : prot_typVP := prot_typV (_O);
5336 -- subtype Jnn is <Type of Index> range Low .. High;
5338 if Nkind (Decl) in N_Full_Type_Declaration | N_Object_Declaration then
5339 Set_Debug_Info_Needed (Defining_Identifier (Decl));
5341 -- Declaration for the Protection object, discriminals, privals, and
5342 -- entry index constant:
5343 -- conc_typR : protection_typ renames _object._object;
5344 -- discr_nameD : discr_typ renames _object.discr_name;
5345 -- discr_nameD : discr_typ renames _task.discr_name;
5346 -- prival_name : comp_typ renames _object.comp_name;
5347 -- J : constant Jnn :=
5348 -- Jnn'Val (_E - <Index expression> + Jnn'Pos (Jnn'First));
5350 elsif Nkind (Decl) = N_Object_Renaming_Declaration then
5351 Set_Debug_Info_Needed (Defining_Identifier (Decl));
5352 Debug_Nod := Debug_Renaming_Declaration (Decl);
5354 if Present (Debug_Nod) then
5355 Insert_After (Decl, Debug_Nod);
5356 end if;
5357 end if;
5359 Next (Decl);
5360 end loop;
5361 end Debug_Private_Data_Declarations;
5363 ------------------------------
5364 -- Ensure_Statement_Present --
5365 ------------------------------
5367 procedure Ensure_Statement_Present (Loc : Source_Ptr; Alt : Node_Id) is
5368 Stmt : Node_Id;
5370 begin
5371 if Opt.Suppress_Control_Flow_Optimizations
5372 and then Is_Empty_List (Statements (Alt))
5373 then
5374 Stmt := Make_Null_Statement (Loc);
5376 -- Mark NULL statement as coming from source so that it is not
5377 -- eliminated by GIGI.
5379 -- Another covert channel. If this is a requirement, it must be
5380 -- documented in sinfo/einfo ???
5382 Set_Comes_From_Source (Stmt, True);
5384 Set_Statements (Alt, New_List (Stmt));
5385 end if;
5386 end Ensure_Statement_Present;
5388 ----------------------------
5389 -- Entry_Index_Expression --
5390 ----------------------------
5392 function Entry_Index_Expression
5393 (Sloc : Source_Ptr;
5394 Ent : Entity_Id;
5395 Index : Node_Id;
5396 Ttyp : Entity_Id) return Node_Id
5398 Expr : Node_Id;
5399 Num : Node_Id;
5400 Lo : Node_Id;
5401 Hi : Node_Id;
5402 Prev : Entity_Id;
5403 S : Node_Id;
5405 begin
5406 -- The queues of entries and entry families appear in textual order in
5407 -- the associated record. The entry index is computed as the sum of the
5408 -- number of queues for all entries that precede the designated one, to
5409 -- which is added the index expression, if this expression denotes a
5410 -- member of a family.
5412 -- The following is a place holder for the count of simple entries
5414 Num := Make_Integer_Literal (Sloc, 1);
5416 -- We construct an expression which is a series of addition operations.
5417 -- The first operand is the number of single entries that precede this
5418 -- one, the second operand is the index value relative to the start of
5419 -- the referenced family, and the remaining operands are the lengths of
5420 -- the entry families that precede this entry, i.e. the constructed
5421 -- expression is:
5423 -- number_simple_entries +
5424 -- (s'pos (index-value) - s'pos (family'first)) + 1 +
5425 -- family'length + ...
5427 -- where index-value is the given index value, and s is the index
5428 -- subtype (we have to use pos because the subtype might be an
5429 -- enumeration type preventing direct subtraction). Note that the task
5430 -- entry array is one-indexed.
5432 -- The upper bound of the entry family may be a discriminant, so we
5433 -- retrieve the lower bound explicitly to compute offset, rather than
5434 -- using the index subtype which may mention a discriminant.
5436 if Present (Index) then
5437 S := Entry_Index_Type (Ent);
5439 -- First make sure the index is in range if requested. The index type
5440 -- is the pristine Entry_Index_Type of the entry.
5442 if Do_Range_Check (Index) then
5443 Generate_Range_Check (Index, S, CE_Range_Check_Failed);
5444 end if;
5446 Expr :=
5447 Make_Op_Add (Sloc,
5448 Left_Opnd => Num,
5449 Right_Opnd =>
5450 Family_Offset
5451 (Sloc,
5452 Make_Attribute_Reference (Sloc,
5453 Attribute_Name => Name_Pos,
5454 Prefix => New_Occurrence_Of (Base_Type (S), Sloc),
5455 Expressions => New_List (Relocate_Node (Index))),
5456 Type_Low_Bound (S),
5457 Ttyp,
5458 False));
5459 else
5460 Expr := Num;
5461 end if;
5463 -- Now add lengths of preceding entries and entry families
5465 Prev := First_Entity (Ttyp);
5466 while Chars (Prev) /= Chars (Ent)
5467 or else Ekind (Prev) /= Ekind (Ent)
5468 or else not Sem_Ch6.Type_Conformant (Ent, Prev)
5469 loop
5470 if Ekind (Prev) = E_Entry then
5471 Set_Intval (Num, Intval (Num) + 1);
5473 elsif Ekind (Prev) = E_Entry_Family then
5474 S := Entry_Index_Type (Prev);
5475 Lo := Type_Low_Bound (S);
5476 Hi := Type_High_Bound (S);
5478 Expr :=
5479 Make_Op_Add (Sloc,
5480 Left_Opnd => Expr,
5481 Right_Opnd => Family_Size (Sloc, Hi, Lo, Ttyp, False));
5483 -- Other components are anonymous types to be ignored
5485 else
5486 null;
5487 end if;
5489 Next_Entity (Prev);
5490 end loop;
5492 return Expr;
5493 end Entry_Index_Expression;
5495 ---------------------------
5496 -- Establish_Task_Master --
5497 ---------------------------
5499 procedure Establish_Task_Master (N : Node_Id) is
5500 Call : Node_Id;
5502 begin
5503 if Restriction_Active (No_Task_Hierarchy) = False then
5504 Call := Build_Runtime_Call (Sloc (N), RE_Enter_Master);
5506 -- The block may have no declarations (and nevertheless be a task
5507 -- master) if it contains a call that may return an object that
5508 -- contains tasks.
5510 if No (Declarations (N)) then
5511 Set_Declarations (N, New_List (Call));
5512 else
5513 Prepend_To (Declarations (N), Call);
5514 end if;
5516 Analyze (Call);
5517 end if;
5518 end Establish_Task_Master;
5520 --------------------------------
5521 -- Expand_Accept_Declarations --
5522 --------------------------------
5524 -- Part of the expansion of an accept statement involves the creation of
5525 -- a declaration that can be referenced from the statement sequence of
5526 -- the accept:
5528 -- Ann : Address;
5530 -- This declaration is inserted immediately before the accept statement
5531 -- and it is important that it be inserted before the statements of the
5532 -- statement sequence are analyzed. Thus it would be too late to create
5533 -- this declaration in the Expand_N_Accept_Statement routine, which is
5534 -- why there is a separate procedure to be called directly from Sem_Ch9.
5536 -- Ann is used to hold the address of the record containing the parameters
5537 -- (see Expand_N_Entry_Call for more details on how this record is built).
5538 -- References to the parameters do an unchecked conversion of this address
5539 -- to a pointer to the required record type, and then access the field that
5540 -- holds the value of the required parameter. The entity for the address
5541 -- variable is held as the top stack element (i.e. the last element) of the
5542 -- Accept_Address stack in the corresponding entry entity, and this element
5543 -- must be set in place before the statements are processed.
5545 -- The above description applies to the case of a stand alone accept
5546 -- statement, i.e. one not appearing as part of a select alternative.
5548 -- For the case of an accept that appears as part of a select alternative
5549 -- of a selective accept, we must still create the declaration right away,
5550 -- since Ann is needed immediately, but there is an important difference:
5552 -- The declaration is inserted before the selective accept, not before
5553 -- the accept statement (which is not part of a list anyway, and so would
5554 -- not accommodate inserted declarations)
5556 -- We only need one address variable for the entire selective accept. So
5557 -- the Ann declaration is created only for the first accept alternative,
5558 -- and subsequent accept alternatives reference the same Ann variable.
5560 -- We can distinguish the two cases by seeing whether the accept statement
5561 -- is part of a list. If not, then it must be in an accept alternative.
5563 -- To expand the requeue statement, a label is provided at the end of the
5564 -- accept statement or alternative of which it is a part, so that the
5565 -- statement can be skipped after the requeue is complete. This label is
5566 -- created here rather than during the expansion of the accept statement,
5567 -- because it will be needed by any requeue statements within the accept,
5568 -- which are expanded before the accept.
5570 procedure Expand_Accept_Declarations (N : Node_Id; Ent : Entity_Id) is
5571 Loc : constant Source_Ptr := Sloc (N);
5572 Stats : constant Node_Id := Handled_Statement_Sequence (N);
5573 Ann : Entity_Id := Empty;
5574 Adecl : Node_Id;
5575 Lab : Node_Id;
5576 Ldecl : Node_Id;
5577 Ldecl2 : Node_Id;
5579 begin
5580 if Expander_Active then
5582 -- If we have no handled statement sequence, we may need to build
5583 -- a dummy sequence consisting of a null statement. This can be
5584 -- skipped if the trivial accept optimization is permitted.
5586 if not Trivial_Accept_OK
5587 and then (No (Stats) or else Null_Statements (Statements (Stats)))
5588 then
5589 Set_Handled_Statement_Sequence (N,
5590 Make_Handled_Sequence_Of_Statements (Loc,
5591 Statements => New_List (Make_Null_Statement (Loc))));
5592 end if;
5594 -- Create and declare two labels to be placed at the end of the
5595 -- accept statement. The first label is used to allow requeues to
5596 -- skip the remainder of entry processing. The second label is used
5597 -- to skip the remainder of entry processing if the rendezvous
5598 -- completes in the middle of the accept body.
5600 if Present (Handled_Statement_Sequence (N)) then
5601 declare
5602 Ent : Entity_Id;
5604 begin
5605 Ent := Make_Temporary (Loc, 'L');
5606 Lab := Make_Label (Loc, New_Occurrence_Of (Ent, Loc));
5607 Ldecl :=
5608 Make_Implicit_Label_Declaration (Loc,
5609 Defining_Identifier => Ent,
5610 Label_Construct => Lab);
5611 Append (Lab, Statements (Handled_Statement_Sequence (N)));
5613 Ent := Make_Temporary (Loc, 'L');
5614 Lab := Make_Label (Loc, New_Occurrence_Of (Ent, Loc));
5615 Ldecl2 :=
5616 Make_Implicit_Label_Declaration (Loc,
5617 Defining_Identifier => Ent,
5618 Label_Construct => Lab);
5619 Append (Lab, Statements (Handled_Statement_Sequence (N)));
5620 end;
5622 else
5623 Ldecl := Empty;
5624 Ldecl2 := Empty;
5625 end if;
5627 -- Case of stand alone accept statement
5629 if Is_List_Member (N) then
5631 if Present (Handled_Statement_Sequence (N)) then
5632 Ann := Make_Temporary (Loc, 'A');
5634 Adecl :=
5635 Make_Object_Declaration (Loc,
5636 Defining_Identifier => Ann,
5637 Object_Definition =>
5638 New_Occurrence_Of (RTE (RE_Address), Loc));
5640 Insert_Before_And_Analyze (N, Adecl);
5641 Insert_Before_And_Analyze (N, Ldecl);
5642 Insert_Before_And_Analyze (N, Ldecl2);
5643 end if;
5645 -- Case of accept statement which is in an accept alternative
5647 else
5648 declare
5649 Acc_Alt : constant Node_Id := Parent (N);
5650 Sel_Acc : constant Node_Id := Parent (Acc_Alt);
5651 Alt : Node_Id;
5653 begin
5654 pragma Assert (Nkind (Acc_Alt) = N_Accept_Alternative);
5655 pragma Assert (Nkind (Sel_Acc) = N_Selective_Accept);
5657 -- ??? Consider a single label for select statements
5659 if Present (Handled_Statement_Sequence (N)) then
5660 Prepend (Ldecl2,
5661 Statements (Handled_Statement_Sequence (N)));
5662 Analyze (Ldecl2);
5664 Prepend (Ldecl,
5665 Statements (Handled_Statement_Sequence (N)));
5666 Analyze (Ldecl);
5667 end if;
5669 -- Find first accept alternative of the selective accept. A
5670 -- valid selective accept must have at least one accept in it.
5672 Alt := First (Select_Alternatives (Sel_Acc));
5674 while Nkind (Alt) /= N_Accept_Alternative loop
5675 Next (Alt);
5676 end loop;
5678 -- If this is the first accept statement, then we have to
5679 -- create the Ann variable, as for the stand alone case, except
5680 -- that it is inserted before the selective accept. Similarly,
5681 -- a label for requeue expansion must be declared.
5683 if N = Accept_Statement (Alt) then
5684 Ann := Make_Temporary (Loc, 'A');
5685 Adecl :=
5686 Make_Object_Declaration (Loc,
5687 Defining_Identifier => Ann,
5688 Object_Definition =>
5689 New_Occurrence_Of (RTE (RE_Address), Loc));
5691 Insert_Before_And_Analyze (Sel_Acc, Adecl);
5693 -- If this is not the first accept statement, then find the Ann
5694 -- variable allocated by the first accept and use it.
5696 else
5697 Ann :=
5698 Node (Last_Elmt (Accept_Address
5699 (Entity (Entry_Direct_Name (Accept_Statement (Alt))))));
5700 end if;
5701 end;
5702 end if;
5704 -- Merge here with Ann either created or referenced, and Adecl
5705 -- pointing to the corresponding declaration. Remaining processing
5706 -- is the same for the two cases.
5708 if Present (Ann) then
5709 Append_Elmt (Ann, Accept_Address (Ent));
5710 Set_Debug_Info_Needed (Ann);
5711 end if;
5713 -- Create renaming declarations for the entry formals. Each reference
5714 -- to a formal becomes a dereference of a component of the parameter
5715 -- block, whose address is held in Ann. These declarations are
5716 -- eventually inserted into the accept block, and analyzed there so
5717 -- that they have the proper scope for gdb and do not conflict with
5718 -- other declarations.
5720 if Present (Parameter_Specifications (N))
5721 and then Present (Handled_Statement_Sequence (N))
5722 then
5723 declare
5724 Comp : Entity_Id;
5725 Decl : Node_Id;
5726 Formal : Entity_Id;
5727 New_F : Entity_Id;
5728 Renamed_Formal : Node_Id;
5730 begin
5731 Push_Scope (Ent);
5732 Formal := First_Formal (Ent);
5734 while Present (Formal) loop
5735 Comp := Entry_Component (Formal);
5736 New_F := Make_Defining_Identifier (Loc, Chars (Formal));
5738 Set_Etype (New_F, Etype (Formal));
5739 Set_Scope (New_F, Ent);
5741 -- Now we set debug info needed on New_F even though it does
5742 -- not come from source, so that the debugger will get the
5743 -- right information for these generated names.
5745 Set_Debug_Info_Needed (New_F);
5747 if Ekind (Formal) = E_In_Parameter then
5748 Mutate_Ekind (New_F, E_Constant);
5749 else
5750 Mutate_Ekind (New_F, E_Variable);
5751 Set_Extra_Constrained (New_F, Extra_Constrained (Formal));
5752 end if;
5754 Set_Actual_Subtype (New_F, Actual_Subtype (Formal));
5756 Renamed_Formal :=
5757 Make_Selected_Component (Loc,
5758 Prefix =>
5759 Make_Explicit_Dereference (Loc,
5760 Unchecked_Convert_To (
5761 Entry_Parameters_Type (Ent),
5762 New_Occurrence_Of (Ann, Loc))),
5763 Selector_Name =>
5764 New_Occurrence_Of (Comp, Loc));
5766 Decl :=
5767 Build_Renamed_Formal_Declaration
5768 (New_F, Formal, Comp, Renamed_Formal);
5770 if No (Declarations (N)) then
5771 Set_Declarations (N, New_List);
5772 end if;
5774 Append (Decl, Declarations (N));
5775 Set_Renamed_Object (Formal, New_F);
5776 Next_Formal (Formal);
5777 end loop;
5779 End_Scope;
5780 end;
5781 end if;
5782 end if;
5783 end Expand_Accept_Declarations;
5785 ---------------------------------------------
5786 -- Expand_Access_Protected_Subprogram_Type --
5787 ---------------------------------------------
5789 procedure Expand_Access_Protected_Subprogram_Type (N : Node_Id) is
5790 Loc : constant Source_Ptr := Sloc (N);
5791 T : constant Entity_Id := Defining_Identifier (N);
5792 D_T : constant Entity_Id := Designated_Type (T);
5793 D_T2 : constant Entity_Id := Make_Temporary (Loc, 'D');
5794 E_T : constant Entity_Id := Make_Temporary (Loc, 'E');
5795 P_List : constant List_Id :=
5796 Build_Protected_Spec (N, RTE (RE_Address), D_T, False);
5798 Comps : List_Id;
5799 Decl1 : Node_Id;
5800 Decl2 : Node_Id;
5801 Def1 : Node_Id;
5803 begin
5804 -- Create access to subprogram with full signature
5806 if Etype (D_T) /= Standard_Void_Type then
5807 Def1 :=
5808 Make_Access_Function_Definition (Loc,
5809 Parameter_Specifications => P_List,
5810 Result_Definition =>
5811 Copy_Result_Type (Result_Definition (Type_Definition (N))));
5813 else
5814 Def1 :=
5815 Make_Access_Procedure_Definition (Loc,
5816 Parameter_Specifications => P_List);
5817 end if;
5819 Decl1 :=
5820 Make_Full_Type_Declaration (Loc,
5821 Defining_Identifier => D_T2,
5822 Type_Definition => Def1);
5824 -- Declare the new types before the original one since the latter will
5825 -- refer to them through the Equivalent_Type slot.
5827 Insert_Before_And_Analyze (N, Decl1);
5829 -- Associate the access to subprogram with its original access to
5830 -- protected subprogram type. Needed by the backend to know that this
5831 -- type corresponds with an access to protected subprogram type.
5833 Set_Original_Access_Type (D_T2, T);
5835 -- Create Equivalent_Type, a record with two components for an access to
5836 -- object and an access to subprogram.
5838 Comps := New_List (
5839 Make_Component_Declaration (Loc,
5840 Defining_Identifier => Make_Temporary (Loc, 'P'),
5841 Component_Definition =>
5842 Make_Component_Definition (Loc,
5843 Aliased_Present => False,
5844 Subtype_Indication =>
5845 New_Occurrence_Of (RTE (RE_Address), Loc))),
5847 Make_Component_Declaration (Loc,
5848 Defining_Identifier => Make_Temporary (Loc, 'S'),
5849 Component_Definition =>
5850 Make_Component_Definition (Loc,
5851 Aliased_Present => False,
5852 Subtype_Indication => New_Occurrence_Of (D_T2, Loc))));
5854 Decl2 :=
5855 Make_Full_Type_Declaration (Loc,
5856 Defining_Identifier => E_T,
5857 Type_Definition =>
5858 Make_Record_Definition (Loc,
5859 Component_List =>
5860 Make_Component_List (Loc, Component_Items => Comps)));
5862 Insert_Before_And_Analyze (N, Decl2);
5863 Set_Equivalent_Type (T, E_T);
5864 end Expand_Access_Protected_Subprogram_Type;
5866 --------------------------
5867 -- Expand_Entry_Barrier --
5868 --------------------------
5870 procedure Expand_Entry_Barrier (N : Node_Id; Ent : Entity_Id) is
5871 Cond : constant Node_Id := Condition (Entry_Body_Formal_Part (N));
5872 Prot : constant Entity_Id := Scope (Ent);
5873 Spec_Decl : constant Node_Id := Parent (Prot);
5875 Func_Id : Entity_Id := Empty;
5876 -- The entity of the barrier function
5878 function Is_Global_Entity (N : Node_Id) return Traverse_Result;
5879 -- Check whether entity in Barrier is external to protected type.
5880 -- If so, barrier may not be properly synchronized.
5882 function Is_Pure_Barrier (N : Node_Id) return Traverse_Result;
5883 -- Check whether N meets the Pure_Barriers restriction. Return OK if
5884 -- so.
5886 function Is_Simple_Barrier (N : Node_Id) return Boolean;
5887 -- Check whether N meets the Simple_Barriers restriction. Return OK if
5888 -- so.
5890 ----------------------
5891 -- Is_Global_Entity --
5892 ----------------------
5894 function Is_Global_Entity (N : Node_Id) return Traverse_Result is
5895 E : Entity_Id;
5896 S : Entity_Id;
5898 begin
5899 if Is_Entity_Name (N) and then Present (Entity (N)) then
5900 E := Entity (N);
5901 S := Scope (E);
5903 if Ekind (E) = E_Variable then
5905 -- If the variable is local to the barrier function generated
5906 -- during expansion, it is ok. If expansion is not performed,
5907 -- then Func is Empty so this test cannot succeed.
5909 if Scope (E) = Func_Id then
5910 null;
5912 -- A protected call from a barrier to another object is ok
5914 elsif Ekind (Etype (E)) = E_Protected_Type then
5915 null;
5917 -- If the variable is within the package body we consider
5918 -- this safe. This is a common (if dubious) idiom.
5920 elsif S = Scope (Prot)
5921 and then Is_Package_Or_Generic_Package (S)
5922 and then Nkind (Parent (E)) = N_Object_Declaration
5923 and then Nkind (Parent (Parent (E))) = N_Package_Body
5924 then
5925 null;
5927 else
5928 Error_Msg_N ("potentially unsynchronized barrier??", N);
5929 Error_Msg_N ("\& should be private component of type??", N);
5930 end if;
5931 end if;
5932 end if;
5934 return OK;
5935 end Is_Global_Entity;
5937 procedure Check_Unprotected_Barrier is
5938 new Traverse_Proc (Is_Global_Entity);
5940 -----------------------
5941 -- Is_Simple_Barrier --
5942 -----------------------
5944 function Is_Simple_Barrier (N : Node_Id) return Boolean is
5945 Renamed : Node_Id;
5947 begin
5948 if Is_Static_Expression (N) then
5949 return True;
5950 elsif Ada_Version >= Ada_2022
5951 and then Nkind (N) in N_Selected_Component | N_Indexed_Component
5952 and then Statically_Names_Object (N)
5953 then
5954 -- Restriction relaxed in Ada 2022 to allow statically named
5955 -- subcomponents.
5956 return Is_Simple_Barrier (Prefix (N));
5957 end if;
5959 -- Check if the name is a component of the protected object. If
5960 -- the expander is active, the component has been transformed into a
5961 -- renaming of _object.all.component. Original_Node is needed in case
5962 -- validity checking is enabled, in which case the simple object
5963 -- reference will have been rewritten.
5965 if Expander_Active then
5967 -- The expanded name may have been constant folded in which case
5968 -- the original node is not necessarily an entity name (e.g. an
5969 -- indexed component).
5971 if not Is_Entity_Name (Original_Node (N)) then
5972 return False;
5973 end if;
5975 Renamed := Renamed_Object (Entity (Original_Node (N)));
5977 return
5978 Present (Renamed)
5979 and then Nkind (Renamed) = N_Selected_Component
5980 and then Chars (Prefix (Prefix (Renamed))) = Name_uObject;
5981 elsif not Is_Entity_Name (N) then
5982 return False;
5983 else
5984 return Is_Protected_Component (Entity (N));
5985 end if;
5986 end Is_Simple_Barrier;
5988 ---------------------
5989 -- Is_Pure_Barrier --
5990 ---------------------
5992 function Is_Pure_Barrier (N : Node_Id) return Traverse_Result is
5993 begin
5994 case Nkind (N) is
5995 when N_Expanded_Name
5996 | N_Identifier
5999 -- Because of N_Expanded_Name case, return Skip instead of OK.
6001 if No (Entity (N)) then
6002 return Abandon;
6004 elsif Is_Numeric_Type (Entity (N)) then
6005 return Skip;
6006 end if;
6008 case Ekind (Entity (N)) is
6009 when E_Constant
6010 | E_Discriminant
6012 return Skip;
6014 when E_Enumeration_Literal
6015 | E_Named_Integer
6016 | E_Named_Real
6018 if not Is_OK_Static_Expression (N) then
6019 return Abandon;
6020 end if;
6021 return Skip;
6023 when E_Component =>
6024 return Skip;
6026 when E_Variable =>
6027 if Is_Simple_Barrier (N) then
6028 return Skip;
6029 end if;
6031 when E_Function =>
6033 -- The count attribute has been transformed into run-time
6034 -- calls.
6036 if Is_RTE (Entity (N), RE_Protected_Count)
6037 or else Is_RTE (Entity (N), RE_Protected_Count_Entry)
6038 then
6039 return Skip;
6040 end if;
6042 when others =>
6043 null;
6044 end case;
6046 when N_Function_Call =>
6048 -- Function call checks are carried out as part of the analysis
6049 -- of the function call name.
6051 return OK;
6053 when N_Character_Literal
6054 | N_Integer_Literal
6055 | N_Real_Literal
6057 return OK;
6059 when N_Op_Boolean
6060 | N_Op_Not
6062 if Ekind (Entity (N)) = E_Operator then
6063 return OK;
6064 end if;
6066 when N_Short_Circuit
6067 | N_If_Expression
6068 | N_Case_Expression
6070 return OK;
6072 when N_Indexed_Component | N_Selected_Component =>
6073 if Statically_Names_Object (N) then
6074 return Is_Pure_Barrier (Prefix (N));
6075 else
6076 return Abandon;
6077 end if;
6079 when N_Case_Expression_Alternative =>
6080 -- do not traverse Discrete_Choices subtree
6081 if Is_Pure_Barrier (Expression (N)) /= Abandon then
6082 return Skip;
6083 end if;
6085 when N_Expression_With_Actions =>
6086 -- this may occur in the case of a Count attribute reference
6087 if Is_Rewrite_Substitution (N)
6088 and then Is_Pure_Barrier (Original_Node (N)) /= Abandon
6089 then
6090 return Skip;
6091 end if;
6093 when N_Membership_Test =>
6094 if Is_Pure_Barrier (Left_Opnd (N)) /= Abandon
6095 and then All_Membership_Choices_Static (N)
6096 then
6097 return Skip;
6098 end if;
6100 when N_Type_Conversion =>
6102 -- Conversions to Universal_Integer do not raise constraint
6103 -- errors. Likewise if the expression's type is statically
6104 -- compatible with the target's type.
6106 if Etype (N) = Universal_Integer
6107 or else Subtypes_Statically_Compatible
6108 (Etype (Expression (N)), Etype (N))
6109 then
6110 return OK;
6111 end if;
6113 when N_Unchecked_Type_Conversion =>
6114 return OK;
6116 when others =>
6117 null;
6118 end case;
6120 return Abandon;
6121 end Is_Pure_Barrier;
6123 function Check_Pure_Barriers is new Traverse_Func (Is_Pure_Barrier);
6125 -- Local variables
6127 Entry_Body : Node_Id;
6128 Func_Body : Node_Id := Empty;
6130 -- Start of processing for Expand_Entry_Barrier
6132 begin
6133 if No_Run_Time_Mode then
6134 Error_Msg_CRT ("entry barrier", N);
6135 return;
6136 end if;
6138 -- Prevent cascaded errors
6140 if Nkind (Cond) = N_Error then
6141 return;
6142 end if;
6144 -- The body of the entry barrier must be analyzed in the context of the
6145 -- protected object, but its scope is external to it, just as any other
6146 -- unprotected version of a protected operation. The specification has
6147 -- been produced when the protected type declaration was elaborated. We
6148 -- build the body, insert it in the enclosing scope, but analyze it in
6149 -- the current context. A more uniform approach would be to treat the
6150 -- barrier just as a protected function, and discard the protected
6151 -- version of it because it is never called.
6153 if Expander_Active then
6154 Func_Body := Build_Barrier_Function (N, Ent, Prot);
6155 Func_Id := Barrier_Function (Ent);
6156 Set_Corresponding_Spec (Func_Body, Func_Id);
6158 Entry_Body := Parent (Corresponding_Body (Spec_Decl));
6160 if Nkind (Parent (Entry_Body)) = N_Subunit then
6161 Entry_Body := Corresponding_Stub (Parent (Entry_Body));
6162 end if;
6164 Insert_Before_And_Analyze (Entry_Body, Func_Body);
6166 Set_Discriminals (Spec_Decl);
6167 Set_Scope (Func_Id, Scope (Prot));
6169 else
6170 Analyze_And_Resolve (Cond, Any_Boolean);
6171 end if;
6173 -- Check Simple_Barriers and Pure_Barriers restrictions.
6174 -- Note that it is safe to be calling Check_Restriction from here, even
6175 -- though this is part of the expander, since Expand_Entry_Barrier is
6176 -- called from Sem_Ch9 even in -gnatc mode.
6178 if not Is_Simple_Barrier (Cond) then
6179 -- flag restriction violation
6180 Check_Restriction (Simple_Barriers, Cond);
6181 end if;
6183 if Check_Pure_Barriers (Cond) = Abandon then
6184 -- flag restriction violation
6185 Check_Restriction (Pure_Barriers, Cond);
6187 -- Emit warning if barrier contains global entities and is thus
6188 -- potentially unsynchronized (if Pure_Barriers restrictions
6189 -- are met then no need to check for this).
6190 Check_Unprotected_Barrier (Cond);
6191 end if;
6193 -- Perform a small optimization of simple barrier functions. If the
6194 -- scope of the condition's entity is not the barrier function, then
6195 -- the condition does not depend on any of the generated renamings.
6196 -- If this is the case, eliminate the renamings as they are useless.
6197 -- This optimization is not performed when the condition was folded
6198 -- and validity checks are in effect because the original condition
6199 -- may have produced at least one check that depends on the generated
6200 -- renamings.
6202 if Expander_Active
6203 and then Is_Entity_Name (Cond)
6204 and then Scope (Entity (Cond)) /= Func_Id
6205 and then not Validity_Check_Operands
6206 then
6207 Set_Declarations (Func_Body, Empty_List);
6208 end if;
6209 end Expand_Entry_Barrier;
6211 ------------------------------
6212 -- Expand_N_Abort_Statement --
6213 ------------------------------
6215 -- Expand abort T1, T2, .. Tn; into:
6216 -- Abort_Tasks (Task_List'(1 => T1.Task_Id, 2 => T2.Task_Id ...))
6218 procedure Expand_N_Abort_Statement (N : Node_Id) is
6219 Loc : constant Source_Ptr := Sloc (N);
6220 Tlist : constant List_Id := Names (N);
6221 Count : Nat;
6222 Aggr : Node_Id;
6223 Tasknm : Node_Id;
6225 begin
6226 Aggr := Make_Aggregate (Loc, Component_Associations => New_List);
6227 Count := 0;
6229 Tasknm := First (Tlist);
6231 while Present (Tasknm) loop
6232 Count := Count + 1;
6234 -- A task interface class-wide type object is being aborted. Retrieve
6235 -- its _task_id by calling a dispatching routine.
6237 if Ada_Version >= Ada_2005
6238 and then Ekind (Etype (Tasknm)) = E_Class_Wide_Type
6239 and then Is_Interface (Etype (Tasknm))
6240 and then Is_Task_Interface (Etype (Tasknm))
6241 then
6242 Append_To (Component_Associations (Aggr),
6243 Make_Component_Association (Loc,
6244 Choices => New_List (Make_Integer_Literal (Loc, Count)),
6245 Expression =>
6247 -- Task_Id (Tasknm._disp_get_task_id)
6249 Unchecked_Convert_To
6250 (RTE (RO_ST_Task_Id),
6251 Make_Selected_Component (Loc,
6252 Prefix => New_Copy_Tree (Tasknm),
6253 Selector_Name =>
6254 Make_Identifier (Loc, Name_uDisp_Get_Task_Id)))));
6256 else
6257 Append_To (Component_Associations (Aggr),
6258 Make_Component_Association (Loc,
6259 Choices => New_List (Make_Integer_Literal (Loc, Count)),
6260 Expression => Concurrent_Ref (Tasknm)));
6261 end if;
6263 Next (Tasknm);
6264 end loop;
6266 Rewrite (N,
6267 Make_Procedure_Call_Statement (Loc,
6268 Name => New_Occurrence_Of (RTE (RE_Abort_Tasks), Loc),
6269 Parameter_Associations => New_List (
6270 Make_Qualified_Expression (Loc,
6271 Subtype_Mark => New_Occurrence_Of (RTE (RE_Task_List), Loc),
6272 Expression => Aggr))));
6274 Analyze (N);
6275 end Expand_N_Abort_Statement;
6277 -------------------------------
6278 -- Expand_N_Accept_Statement --
6279 -------------------------------
6281 -- This procedure handles expansion of accept statements that stand alone,
6282 -- i.e. they are not part of an accept alternative. The expansion of
6283 -- accept statement in accept alternatives is handled by the routines
6284 -- Expand_N_Accept_Alternative and Expand_N_Selective_Accept. The
6285 -- following description applies only to stand alone accept statements.
6287 -- If there is no handled statement sequence, or only null statements, then
6288 -- this is called a trivial accept, and the expansion is:
6290 -- Accept_Trivial (entry-index)
6292 -- If there is a handled statement sequence, then the expansion is:
6294 -- Ann : Address;
6295 -- {Lnn : Label}
6297 -- begin
6298 -- begin
6299 -- Accept_Call (entry-index, Ann);
6300 -- Renaming_Declarations for formals
6301 -- <statement sequence from N_Accept_Statement node>
6302 -- Complete_Rendezvous;
6303 -- <<Lnn>>
6305 -- exception
6306 -- when ... =>
6307 -- <exception handler from N_Accept_Statement node>
6308 -- Complete_Rendezvous;
6309 -- when ... =>
6310 -- <exception handler from N_Accept_Statement node>
6311 -- Complete_Rendezvous;
6312 -- ...
6313 -- end;
6315 -- exception
6316 -- when all others =>
6317 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
6318 -- end;
6320 -- The first three declarations were already inserted ahead of the accept
6321 -- statement by the Expand_Accept_Declarations procedure, which was called
6322 -- directly from the semantics during analysis of the accept statement,
6323 -- before analyzing its contained statements.
6325 -- The declarations from the N_Accept_Statement, as noted in Sinfo, come
6326 -- from possible expansion activity (the original source of course does
6327 -- not have any declarations associated with the accept statement, since
6328 -- an accept statement has no declarative part). In particular, if the
6329 -- expander is active, the first such declaration is the declaration of
6330 -- the Accept_Params_Ptr entity (see Sem_Ch9.Analyze_Accept_Statement).
6332 -- The two blocks are merged into a single block if the inner block has
6333 -- no exception handlers, but otherwise two blocks are required, since
6334 -- exceptions might be raised in the exception handlers of the inner
6335 -- block, and Exceptional_Complete_Rendezvous must be called.
6337 procedure Expand_N_Accept_Statement (N : Node_Id) is
6338 Loc : constant Source_Ptr := Sloc (N);
6339 Stats : constant Node_Id := Handled_Statement_Sequence (N);
6340 Ename : constant Node_Id := Entry_Direct_Name (N);
6341 Eindx : constant Node_Id := Entry_Index (N);
6342 Eent : constant Entity_Id := Entity (Ename);
6343 Acstack : constant Elist_Id := Accept_Address (Eent);
6344 Ann : constant Entity_Id := Node (Last_Elmt (Acstack));
6345 Ttyp : constant Entity_Id := Etype (Scope (Eent));
6346 Blkent : Entity_Id;
6347 Call : Node_Id;
6348 Block : Node_Id;
6350 begin
6351 -- If the accept statement is not part of a list, then its parent must
6352 -- be an accept alternative, and, as described above, we do not do any
6353 -- expansion for such accept statements at this level.
6355 if not Is_List_Member (N) then
6356 pragma Assert (Nkind (Parent (N)) = N_Accept_Alternative);
6357 return;
6359 -- Trivial accept case (no statement sequence, or null statements).
6360 -- If the accept statement has declarations, then just insert them
6361 -- before the procedure call.
6363 elsif Trivial_Accept_OK
6364 and then (No (Stats) or else Null_Statements (Statements (Stats)))
6365 then
6366 -- Remove declarations for renamings, because the parameter block
6367 -- will not be assigned.
6369 declare
6370 D : Node_Id;
6371 Next_D : Node_Id;
6373 begin
6374 D := First (Declarations (N));
6375 while Present (D) loop
6376 Next_D := Next (D);
6377 if Nkind (D) = N_Object_Renaming_Declaration then
6378 Remove (D);
6379 end if;
6381 D := Next_D;
6382 end loop;
6383 end;
6385 if Present (Declarations (N)) then
6386 Insert_Actions (N, Declarations (N));
6387 end if;
6389 Rewrite (N,
6390 Make_Procedure_Call_Statement (Loc,
6391 Name => New_Occurrence_Of (RTE (RE_Accept_Trivial), Loc),
6392 Parameter_Associations => New_List (
6393 Entry_Index_Expression (Loc, Entity (Ename), Eindx, Ttyp))));
6395 Analyze (N);
6397 -- Ada 2022 (AI12-0279)
6399 if Has_Yield_Aspect (Eent)
6400 and then RTE_Available (RE_Yield)
6401 then
6402 Insert_Action_After (N,
6403 Make_Procedure_Call_Statement (Loc,
6404 New_Occurrence_Of (RTE (RE_Yield), Loc)));
6405 end if;
6407 -- Discard Entry_Address that was created for it, so it will not be
6408 -- emitted if this accept statement is in the statement part of a
6409 -- delay alternative.
6411 if Present (Stats) then
6412 Remove_Last_Elmt (Acstack);
6413 end if;
6415 -- Case of statement sequence present
6417 else
6418 -- Construct the block, using the declarations from the accept
6419 -- statement if any to initialize the declarations of the block.
6421 Blkent := Make_Temporary (Loc, 'A');
6422 Mutate_Ekind (Blkent, E_Block);
6423 Set_Etype (Blkent, Standard_Void_Type);
6424 Set_Scope (Blkent, Current_Scope);
6426 Block :=
6427 Make_Block_Statement (Loc,
6428 Identifier => New_Occurrence_Of (Blkent, Loc),
6429 Declarations => Declarations (N),
6430 Handled_Statement_Sequence => Build_Accept_Body (N));
6432 -- Reset the Scope of local entities associated with the accept
6433 -- statement (that currently reference the entry scope) to the
6434 -- block scope, to avoid having references to the locals treated
6435 -- as up-level references.
6437 Reset_Scopes_To (Block, Blkent);
6439 -- For the analysis of the generated declarations, the parent node
6440 -- must be properly set.
6442 Set_Parent (Block, Parent (N));
6443 Set_Parent (Blkent, Block);
6445 -- Prepend call to Accept_Call to main statement sequence If the
6446 -- accept has exception handlers, the statement sequence is wrapped
6447 -- in a block. Insert call and renaming declarations in the
6448 -- declarations of the block, so they are elaborated before the
6449 -- handlers.
6451 Call :=
6452 Make_Procedure_Call_Statement (Loc,
6453 Name => New_Occurrence_Of (RTE (RE_Accept_Call), Loc),
6454 Parameter_Associations => New_List (
6455 Entry_Index_Expression (Loc, Entity (Ename), Eindx, Ttyp),
6456 New_Occurrence_Of (Ann, Loc)));
6458 if Parent (Stats) = N then
6459 Prepend (Call, Statements (Stats));
6460 else
6461 Set_Declarations (Parent (Stats), New_List (Call));
6462 end if;
6464 Analyze (Call);
6466 Push_Scope (Blkent);
6468 declare
6469 D : Node_Id;
6470 Next_D : Node_Id;
6471 Typ : Entity_Id;
6473 begin
6474 D := First (Declarations (N));
6475 while Present (D) loop
6476 Next_D := Next (D);
6478 if Nkind (D) = N_Object_Renaming_Declaration then
6480 -- The renaming declarations for the formals were created
6481 -- during analysis of the accept statement, and attached to
6482 -- the list of declarations. Place them now in the context
6483 -- of the accept block or subprogram.
6485 Remove (D);
6486 Typ := Entity (Subtype_Mark (D));
6487 Insert_After (Call, D);
6488 Analyze (D);
6490 -- If the formal is class_wide, it does not have an actual
6491 -- subtype. The analysis of the renaming declaration creates
6492 -- one, but we need to retain the class-wide nature of the
6493 -- entity.
6495 if Is_Class_Wide_Type (Typ) then
6496 Set_Etype (Defining_Identifier (D), Typ);
6497 end if;
6499 end if;
6501 D := Next_D;
6502 end loop;
6503 end;
6505 End_Scope;
6507 -- Replace the accept statement by the new block
6509 Rewrite (N, Block);
6510 Analyze (N);
6512 -- Last step is to unstack the Accept_Address value
6514 Remove_Last_Elmt (Acstack);
6515 end if;
6516 end Expand_N_Accept_Statement;
6518 ----------------------------------
6519 -- Expand_N_Asynchronous_Select --
6520 ----------------------------------
6522 -- This procedure assumes that the trigger statement is an entry call or
6523 -- a dispatching procedure call. A delay alternative should already have
6524 -- been expanded into an entry call to the appropriate delay object Wait
6525 -- entry.
6527 -- If the trigger is a task entry call, the select is implemented with
6528 -- a Task_Entry_Call:
6530 -- declare
6531 -- B : Boolean;
6532 -- C : Boolean;
6533 -- P : parms := (parm, parm, parm);
6535 -- -- Clean is added by Exp_Ch7.Expand_Cleanup_Actions
6537 -- procedure _clean is
6538 -- begin
6539 -- ...
6540 -- Cancel_Task_Entry_Call (C);
6541 -- ...
6542 -- end _clean;
6544 -- begin
6545 -- Abort_Defer;
6546 -- Task_Entry_Call
6547 -- (<acceptor-task>, -- Acceptor
6548 -- <entry-index>, -- E
6549 -- P'Address, -- Uninterpreted_Data
6550 -- Asynchronous_Call, -- Mode
6551 -- B); -- Rendezvous_Successful
6553 -- begin
6554 -- begin
6555 -- Abort_Undefer;
6556 -- <abortable-part>
6557 -- at end
6558 -- _clean; -- Added by Exp_Ch7.Expand_Cleanup_Actions
6559 -- end;
6560 -- exception
6561 -- when Abort_Signal => Abort_Undefer;
6562 -- end;
6564 -- parm := P.param;
6565 -- parm := P.param;
6566 -- ...
6567 -- if not C then
6568 -- <triggered-statements>
6569 -- end if;
6570 -- end;
6572 -- Note that Build_Simple_Entry_Call is used to expand the entry of the
6573 -- asynchronous entry call (by Expand_N_Entry_Call_Statement procedure)
6574 -- as follows:
6576 -- declare
6577 -- P : parms := (parm, parm, parm);
6578 -- begin
6579 -- Call_Simple (acceptor-task, entry-index, P'Address);
6580 -- parm := P.param;
6581 -- parm := P.param;
6582 -- ...
6583 -- end;
6585 -- so the task at hand is to convert the latter expansion into the former
6587 -- If the trigger is a protected entry call, the select is implemented
6588 -- with Protected_Entry_Call:
6590 -- declare
6591 -- P : E1_Params := (param, param, param);
6592 -- Bnn : Communications_Block;
6594 -- begin
6595 -- declare
6597 -- -- Clean is added by Exp_Ch7.Expand_Cleanup_Actions
6599 -- procedure _clean is
6600 -- begin
6601 -- ...
6602 -- if Enqueued (Bnn) then
6603 -- Cancel_Protected_Entry_Call (Bnn);
6604 -- end if;
6605 -- ...
6606 -- end _clean;
6608 -- begin
6609 -- begin
6610 -- Protected_Entry_Call
6611 -- (po._object'Access, -- Object
6612 -- <entry index>, -- E
6613 -- P'Address, -- Uninterpreted_Data
6614 -- Asynchronous_Call, -- Mode
6615 -- Bnn); -- Block
6617 -- if Enqueued (Bnn) then
6618 -- <abortable-part>
6619 -- end if;
6620 -- at end
6621 -- _clean; -- Added by Exp_Ch7.Expand_Cleanup_Actions
6622 -- end;
6623 -- exception
6624 -- when Abort_Signal => Abort_Undefer;
6625 -- end;
6627 -- if not Cancelled (Bnn) then
6628 -- <triggered-statements>
6629 -- end if;
6630 -- end;
6632 -- Build_Simple_Entry_Call is used to expand the all to a simple protected
6633 -- entry call:
6635 -- declare
6636 -- P : E1_Params := (param, param, param);
6637 -- Bnn : Communications_Block;
6639 -- begin
6640 -- Protected_Entry_Call
6641 -- (po._object'Access, -- Object
6642 -- <entry index>, -- E
6643 -- P'Address, -- Uninterpreted_Data
6644 -- Simple_Call, -- Mode
6645 -- Bnn); -- Block
6646 -- parm := P.param;
6647 -- parm := P.param;
6648 -- ...
6649 -- end;
6651 -- Ada 2005 (AI-345): If the trigger is a dispatching call, the select is
6652 -- expanded into:
6654 -- declare
6655 -- B : Boolean := False;
6656 -- Bnn : Communication_Block;
6657 -- C : Ada.Tags.Prim_Op_Kind;
6658 -- D : System.Storage_Elements.Dummy_Communication_Block;
6659 -- K : Ada.Tags.Tagged_Kind :=
6660 -- Ada.Tags.Get_Tagged_Kind (Ada.Tags.Tag (<object>));
6661 -- P : Parameters := (Param1 .. ParamN);
6662 -- S : Integer;
6663 -- U : Boolean;
6665 -- begin
6666 -- if K = Ada.Tags.TK_Limited_Tagged
6667 -- or else K = Ada.Tags.TK_Tagged
6668 -- then
6669 -- <dispatching-call>;
6670 -- <triggering-statements>;
6672 -- else
6673 -- S :=
6674 -- Ada.Tags.Get_Offset_Index
6675 -- (Ada.Tags.Tag (<object>), DT_Position (<dispatching-call>));
6677 -- _Disp_Get_Prim_Op_Kind (<object>, S, C);
6679 -- if C = POK_Protected_Entry then
6680 -- declare
6681 -- procedure _clean is
6682 -- begin
6683 -- if Enqueued (Bnn) then
6684 -- Cancel_Protected_Entry_Call (Bnn);
6685 -- end if;
6686 -- end _clean;
6688 -- begin
6689 -- begin
6690 -- _Disp_Asynchronous_Select
6691 -- (<object>, S, P'Address, D, B);
6692 -- Bnn := Communication_Block (D);
6694 -- Param1 := P.Param1;
6695 -- ...
6696 -- ParamN := P.ParamN;
6698 -- if Enqueued (Bnn) then
6699 -- <abortable-statements>
6700 -- end if;
6701 -- at end
6702 -- _clean; -- Added by Exp_Ch7.Expand_Cleanup_Actions
6703 -- end;
6704 -- exception
6705 -- when Abort_Signal => Abort_Undefer;
6706 -- end;
6708 -- if not Cancelled (Bnn) then
6709 -- <triggering-statements>
6710 -- end if;
6712 -- elsif C = POK_Task_Entry then
6713 -- declare
6714 -- procedure _clean is
6715 -- begin
6716 -- Cancel_Task_Entry_Call (U);
6717 -- end _clean;
6719 -- begin
6720 -- Abort_Defer;
6722 -- _Disp_Asynchronous_Select
6723 -- (<object>, S, P'Address, D, B);
6724 -- Bnn := Communication_Bloc (D);
6726 -- Param1 := P.Param1;
6727 -- ...
6728 -- ParamN := P.ParamN;
6730 -- begin
6731 -- begin
6732 -- Abort_Undefer;
6733 -- <abortable-statements>
6734 -- at end
6735 -- _clean; -- Added by Exp_Ch7.Expand_Cleanup_Actions
6736 -- end;
6737 -- exception
6738 -- when Abort_Signal => Abort_Undefer;
6739 -- end;
6741 -- if not U then
6742 -- <triggering-statements>
6743 -- end if;
6744 -- end;
6746 -- else
6747 -- <dispatching-call>;
6748 -- <triggering-statements>
6749 -- end if;
6750 -- end if;
6751 -- end;
6753 -- The job is to convert this to the asynchronous form
6755 -- If the trigger is a delay statement, it will have been expanded into
6756 -- a call to one of the GNARL delay procedures. This routine will convert
6757 -- this into a protected entry call on a delay object and then continue
6758 -- processing as for a protected entry call trigger. This requires
6759 -- declaring a Delay_Block object and adding a pointer to this object to
6760 -- the parameter list of the delay procedure to form the parameter list of
6761 -- the entry call. This object is used by the runtime to queue the delay
6762 -- request.
6764 -- For a description of the use of P and the assignments after the call,
6765 -- see Expand_N_Entry_Call_Statement.
6767 procedure Expand_N_Asynchronous_Select (N : Node_Id) is
6768 Loc : constant Source_Ptr := Sloc (N);
6769 Abrt : constant Node_Id := Abortable_Part (N);
6770 Trig : constant Node_Id := Triggering_Alternative (N);
6772 Abort_Block_Ent : Entity_Id;
6773 Abortable_Block : Node_Id;
6774 Actuals : List_Id;
6775 Astats : List_Id;
6776 Blk_Ent : constant Entity_Id := Make_Temporary (Loc, 'A');
6777 Blk_Typ : Entity_Id;
6778 Call : Node_Id;
6779 Call_Ent : Entity_Id;
6780 Cancel_Param : Entity_Id;
6781 Cleanup_Block : Node_Id;
6782 Cleanup_Block_Ent : Entity_Id;
6783 Cleanup_Stmts : List_Id;
6784 Conc_Typ_Stmts : List_Id;
6785 Concval : Node_Id;
6786 Dblock_Ent : Entity_Id;
6787 Decl : Node_Id;
6788 Decls : List_Id;
6789 Ecall : Node_Id;
6790 Ename : Node_Id;
6791 Enqueue_Call : Node_Id;
6792 Formals : List_Id;
6793 Hdle : List_Id;
6794 Index : Node_Id;
6795 Lim_Typ_Stmts : List_Id;
6796 N_Orig : Node_Id;
6797 Obj : Entity_Id;
6798 Param : Node_Id;
6799 Params : List_Id;
6800 Pdef : Entity_Id;
6801 ProtE_Stmts : List_Id;
6802 ProtP_Stmts : List_Id;
6803 Stmt : Node_Id;
6804 Stmts : List_Id;
6805 TaskE_Stmts : List_Id;
6806 Tstats : List_Id;
6808 B : Entity_Id; -- Call status flag
6809 Bnn : Entity_Id; -- Communication block
6810 C : Entity_Id; -- Call kind
6811 K : Entity_Id; -- Tagged kind
6812 P : Entity_Id; -- Parameter block
6813 S : Entity_Id; -- Primitive operation slot
6814 T : Entity_Id; -- Additional status flag
6816 procedure Rewrite_Abortable_Part;
6817 -- If the trigger is a dispatching call, the expansion inserts multiple
6818 -- copies of the abortable part. This is both inefficient, and may lead
6819 -- to duplicate definitions that the back-end will reject, when the
6820 -- abortable part includes loops. This procedure rewrites the abortable
6821 -- part into a call to a generated procedure.
6823 ----------------------------
6824 -- Rewrite_Abortable_Part --
6825 ----------------------------
6827 procedure Rewrite_Abortable_Part is
6828 Proc : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uA);
6829 Decl : Node_Id;
6831 begin
6832 Decl :=
6833 Make_Subprogram_Body (Loc,
6834 Specification =>
6835 Make_Procedure_Specification (Loc, Defining_Unit_Name => Proc),
6836 Declarations => New_List,
6837 Handled_Statement_Sequence =>
6838 Make_Handled_Sequence_Of_Statements (Loc, Astats));
6839 Insert_Before (N, Decl);
6840 Analyze (Decl);
6842 -- Rewrite abortable part into a call to this procedure
6844 Astats :=
6845 New_List (
6846 Make_Procedure_Call_Statement (Loc,
6847 Name => New_Occurrence_Of (Proc, Loc)));
6848 end Rewrite_Abortable_Part;
6850 -- Start of processing for Expand_N_Asynchronous_Select
6852 begin
6853 -- Asynchronous select is not supported on restricted runtimes. Don't
6854 -- try to expand.
6856 if Restricted_Profile then
6857 return;
6858 end if;
6860 Process_Statements_For_Controlled_Objects (Trig);
6861 Process_Statements_For_Controlled_Objects (Abrt);
6863 Ecall := Triggering_Statement (Trig);
6865 Ensure_Statement_Present (Sloc (Ecall), Trig);
6867 -- Retrieve Astats and Tstats now because the finalization machinery may
6868 -- wrap them in blocks.
6870 Astats := Statements (Abrt);
6871 Tstats := Statements (Trig);
6873 -- The arguments in the call may require dynamic allocation, and the
6874 -- call statement may have been transformed into a block. The block
6875 -- may contain additional declarations for internal entities, and the
6876 -- original call is found by sequential search.
6878 if Nkind (Ecall) = N_Block_Statement then
6879 Ecall := First (Statements (Handled_Statement_Sequence (Ecall)));
6880 while Nkind (Ecall) not in
6881 N_Procedure_Call_Statement | N_Entry_Call_Statement
6882 loop
6883 Next (Ecall);
6884 end loop;
6885 end if;
6887 -- This is either a dispatching call or a delay statement used as a
6888 -- trigger which was expanded into a procedure call.
6890 if Nkind (Ecall) = N_Procedure_Call_Statement then
6891 if Ada_Version >= Ada_2005
6892 and then
6893 (No (Original_Node (Ecall))
6894 or else Nkind (Original_Node (Ecall)) not in N_Delay_Statement)
6895 then
6896 Extract_Dispatching_Call (Ecall, Call_Ent, Obj, Actuals, Formals);
6898 Rewrite_Abortable_Part;
6899 Decls := New_List;
6900 Stmts := New_List;
6902 -- Call status flag processing, generate:
6903 -- B : Boolean := False;
6905 B := Build_B (Loc, Decls);
6907 -- Communication block processing, generate:
6908 -- Bnn : Communication_Block;
6910 Bnn := Make_Temporary (Loc, 'B');
6911 Append_To (Decls,
6912 Make_Object_Declaration (Loc,
6913 Defining_Identifier => Bnn,
6914 Object_Definition =>
6915 New_Occurrence_Of (RTE (RE_Communication_Block), Loc)));
6917 -- Call kind processing, generate:
6918 -- C : Ada.Tags.Prim_Op_Kind;
6920 C := Build_C (Loc, Decls);
6922 -- Tagged kind processing, generate:
6923 -- K : Ada.Tags.Tagged_Kind :=
6924 -- Ada.Tags.Get_Tagged_Kind (Ada.Tags.Tag (<object>));
6926 -- Dummy communication block, generate:
6927 -- D : Dummy_Communication_Block;
6929 Append_To (Decls,
6930 Make_Object_Declaration (Loc,
6931 Defining_Identifier =>
6932 Make_Defining_Identifier (Loc, Name_uD),
6933 Object_Definition =>
6934 New_Occurrence_Of
6935 (RTE (RE_Dummy_Communication_Block), Loc)));
6937 K := Build_K (Loc, Decls, Obj);
6939 -- Parameter block processing
6941 Blk_Typ := Build_Parameter_Block
6942 (Loc, Actuals, Formals, Decls);
6943 P := Parameter_Block_Pack
6944 (Loc, Blk_Typ, Actuals, Formals, Decls, Stmts);
6946 -- Dispatch table slot processing, generate:
6947 -- S : Integer;
6949 S := Build_S (Loc, Decls);
6951 -- Additional status flag processing, generate:
6952 -- Tnn : Boolean;
6954 T := Make_Temporary (Loc, 'T');
6955 Append_To (Decls,
6956 Make_Object_Declaration (Loc,
6957 Defining_Identifier => T,
6958 Object_Definition =>
6959 New_Occurrence_Of (Standard_Boolean, Loc)));
6961 ------------------------------
6962 -- Protected entry handling --
6963 ------------------------------
6965 -- Generate:
6966 -- Param1 := P.Param1;
6967 -- ...
6968 -- ParamN := P.ParamN;
6970 Cleanup_Stmts := Parameter_Block_Unpack (Loc, P, Actuals, Formals);
6972 -- Generate:
6973 -- Bnn := Communication_Block (D);
6975 Prepend_To (Cleanup_Stmts,
6976 Make_Assignment_Statement (Loc,
6977 Name => New_Occurrence_Of (Bnn, Loc),
6978 Expression =>
6979 Unchecked_Convert_To
6980 (RTE (RE_Communication_Block),
6981 Make_Identifier (Loc, Name_uD))));
6983 -- Generate:
6984 -- _Disp_Asynchronous_Select (<object>, S, P'Address, D, B);
6986 Prepend_To (Cleanup_Stmts,
6987 Make_Procedure_Call_Statement (Loc,
6988 Name =>
6989 New_Occurrence_Of
6990 (Find_Prim_Op
6991 (Etype (Etype (Obj)), Name_uDisp_Asynchronous_Select),
6992 Loc),
6993 Parameter_Associations =>
6994 New_List (
6995 New_Copy_Tree (Obj), -- <object>
6996 New_Occurrence_Of (S, Loc), -- S
6997 Make_Attribute_Reference (Loc, -- P'Address
6998 Prefix => New_Occurrence_Of (P, Loc),
6999 Attribute_Name => Name_Address),
7000 Make_Identifier (Loc, Name_uD), -- D
7001 New_Occurrence_Of (B, Loc)))); -- B
7003 -- Generate:
7004 -- if Enqueued (Bnn) then
7005 -- <abortable-statements>
7006 -- end if;
7008 Append_To (Cleanup_Stmts,
7009 Make_Implicit_If_Statement (N,
7010 Condition =>
7011 Make_Function_Call (Loc,
7012 Name =>
7013 New_Occurrence_Of (RTE (RE_Enqueued), Loc),
7014 Parameter_Associations =>
7015 New_List (New_Occurrence_Of (Bnn, Loc))),
7017 Then_Statements =>
7018 New_Copy_List_Tree (Astats)));
7020 -- Wrap the statements in a block. Exp_Ch7.Expand_Cleanup_Actions
7021 -- will then generate a _clean for the communication block Bnn.
7023 -- Generate:
7024 -- declare
7025 -- procedure _clean is
7026 -- begin
7027 -- if Enqueued (Bnn) then
7028 -- Cancel_Protected_Entry_Call (Bnn);
7029 -- end if;
7030 -- end _clean;
7031 -- begin
7032 -- Cleanup_Stmts
7033 -- at end
7034 -- _clean;
7035 -- end;
7037 Cleanup_Block_Ent := Make_Temporary (Loc, 'C');
7038 Cleanup_Block :=
7039 Build_Cleanup_Block (Loc, Cleanup_Block_Ent, Cleanup_Stmts, Bnn);
7041 -- Wrap the cleanup block in an exception handling block
7043 -- Generate:
7044 -- begin
7045 -- Cleanup_Block
7046 -- exception
7047 -- when Abort_Signal => Abort_Undefer;
7048 -- end;
7050 Abort_Block_Ent := Make_Temporary (Loc, 'A');
7051 ProtE_Stmts :=
7052 New_List (
7053 Make_Implicit_Label_Declaration (Loc,
7054 Defining_Identifier => Abort_Block_Ent),
7056 Build_Abort_Block
7057 (Loc, Abort_Block_Ent, Cleanup_Block_Ent, Cleanup_Block));
7059 -- Generate:
7060 -- if not Cancelled (Bnn) then
7061 -- <triggering-statements>
7062 -- end if;
7064 Append_To (ProtE_Stmts,
7065 Make_Implicit_If_Statement (N,
7066 Condition =>
7067 Make_Op_Not (Loc,
7068 Right_Opnd =>
7069 Make_Function_Call (Loc,
7070 Name =>
7071 New_Occurrence_Of (RTE (RE_Cancelled), Loc),
7072 Parameter_Associations =>
7073 New_List (New_Occurrence_Of (Bnn, Loc)))),
7075 Then_Statements =>
7076 New_Copy_List_Tree (Tstats)));
7078 -------------------------
7079 -- Task entry handling --
7080 -------------------------
7082 -- Generate:
7083 -- Param1 := P.Param1;
7084 -- ...
7085 -- ParamN := P.ParamN;
7087 TaskE_Stmts := Parameter_Block_Unpack (Loc, P, Actuals, Formals);
7089 -- Generate:
7090 -- Bnn := Communication_Block (D);
7092 Append_To (TaskE_Stmts,
7093 Make_Assignment_Statement (Loc,
7094 Name =>
7095 New_Occurrence_Of (Bnn, Loc),
7096 Expression =>
7097 Unchecked_Convert_To
7098 (RTE (RE_Communication_Block),
7099 Make_Identifier (Loc, Name_uD))));
7101 -- Generate:
7102 -- _Disp_Asynchronous_Select (<object>, S, P'Address, D, B);
7104 Prepend_To (TaskE_Stmts,
7105 Make_Procedure_Call_Statement (Loc,
7106 Name =>
7107 New_Occurrence_Of (
7108 Find_Prim_Op (Etype (Etype (Obj)),
7109 Name_uDisp_Asynchronous_Select),
7110 Loc),
7112 Parameter_Associations => New_List (
7113 New_Copy_Tree (Obj), -- <object>
7114 New_Occurrence_Of (S, Loc), -- S
7115 Make_Attribute_Reference (Loc, -- P'Address
7116 Prefix => New_Occurrence_Of (P, Loc),
7117 Attribute_Name => Name_Address),
7118 Make_Identifier (Loc, Name_uD), -- D
7119 New_Occurrence_Of (B, Loc)))); -- B
7121 -- Generate:
7122 -- Abort_Defer;
7124 Prepend_To (TaskE_Stmts, Build_Runtime_Call (Loc, RE_Abort_Defer));
7126 -- Generate:
7127 -- Abort_Undefer;
7128 -- <abortable-statements>
7130 Cleanup_Stmts := New_Copy_List_Tree (Astats);
7132 Prepend_To
7133 (Cleanup_Stmts, Build_Runtime_Call (Loc, RE_Abort_Undefer));
7135 -- Wrap the statements in a block. Exp_Ch7.Expand_Cleanup_Actions
7136 -- will generate a _clean for the additional status flag.
7138 -- Generate:
7139 -- declare
7140 -- procedure _clean is
7141 -- begin
7142 -- Cancel_Task_Entry_Call (U);
7143 -- end _clean;
7144 -- begin
7145 -- Cleanup_Stmts
7146 -- at end
7147 -- _clean;
7148 -- end;
7150 Cleanup_Block_Ent := Make_Temporary (Loc, 'C');
7151 Cleanup_Block :=
7152 Build_Cleanup_Block (Loc, Cleanup_Block_Ent, Cleanup_Stmts, T);
7154 -- Wrap the cleanup block in an exception handling block
7156 -- Generate:
7157 -- begin
7158 -- Cleanup_Block
7159 -- exception
7160 -- when Abort_Signal => Abort_Undefer;
7161 -- end;
7163 Abort_Block_Ent := Make_Temporary (Loc, 'A');
7165 Append_To (TaskE_Stmts,
7166 Make_Implicit_Label_Declaration (Loc,
7167 Defining_Identifier => Abort_Block_Ent));
7169 Append_To (TaskE_Stmts,
7170 Build_Abort_Block
7171 (Loc, Abort_Block_Ent, Cleanup_Block_Ent, Cleanup_Block));
7173 -- Generate:
7174 -- if not T then
7175 -- <triggering-statements>
7176 -- end if;
7178 Append_To (TaskE_Stmts,
7179 Make_Implicit_If_Statement (N,
7180 Condition =>
7181 Make_Op_Not (Loc, Right_Opnd => New_Occurrence_Of (T, Loc)),
7183 Then_Statements =>
7184 New_Copy_List_Tree (Tstats)));
7186 ----------------------------------
7187 -- Protected procedure handling --
7188 ----------------------------------
7190 -- Generate:
7191 -- <dispatching-call>;
7192 -- <triggering-statements>
7194 ProtP_Stmts := New_Copy_List_Tree (Tstats);
7195 Prepend_To (ProtP_Stmts, New_Copy_Tree (Ecall));
7197 -- Generate:
7198 -- S := Ada.Tags.Get_Offset_Index
7199 -- (Ada.Tags.Tag (<object>), DT_Position (Call_Ent));
7201 Conc_Typ_Stmts :=
7202 New_List (Build_S_Assignment (Loc, S, Obj, Call_Ent));
7204 -- Generate:
7205 -- _Disp_Get_Prim_Op_Kind (<object>, S, C);
7207 Append_To (Conc_Typ_Stmts,
7208 Make_Procedure_Call_Statement (Loc,
7209 Name =>
7210 New_Occurrence_Of
7211 (Find_Prim_Op (Etype (Etype (Obj)),
7212 Name_uDisp_Get_Prim_Op_Kind),
7213 Loc),
7214 Parameter_Associations =>
7215 New_List (
7216 New_Copy_Tree (Obj),
7217 New_Occurrence_Of (S, Loc),
7218 New_Occurrence_Of (C, Loc))));
7220 -- Generate:
7221 -- if C = POK_Procedure_Entry then
7222 -- ProtE_Stmts
7223 -- elsif C = POK_Task_Entry then
7224 -- TaskE_Stmts
7225 -- else
7226 -- ProtP_Stmts
7227 -- end if;
7229 Append_To (Conc_Typ_Stmts,
7230 Make_Implicit_If_Statement (N,
7231 Condition =>
7232 Make_Op_Eq (Loc,
7233 Left_Opnd =>
7234 New_Occurrence_Of (C, Loc),
7235 Right_Opnd =>
7236 New_Occurrence_Of (RTE (RE_POK_Protected_Entry), Loc)),
7238 Then_Statements =>
7239 ProtE_Stmts,
7241 Elsif_Parts =>
7242 New_List (
7243 Make_Elsif_Part (Loc,
7244 Condition =>
7245 Make_Op_Eq (Loc,
7246 Left_Opnd =>
7247 New_Occurrence_Of (C, Loc),
7248 Right_Opnd =>
7249 New_Occurrence_Of (RTE (RE_POK_Task_Entry), Loc)),
7251 Then_Statements =>
7252 TaskE_Stmts)),
7254 Else_Statements =>
7255 ProtP_Stmts));
7257 -- Generate:
7258 -- <dispatching-call>;
7259 -- <triggering-statements>
7261 Lim_Typ_Stmts := New_Copy_List_Tree (Tstats);
7262 Prepend_To (Lim_Typ_Stmts, New_Copy_Tree (Ecall));
7264 -- Generate:
7265 -- if K = Ada.Tags.TK_Limited_Tagged
7266 -- or else K = Ada.Tags.TK_Tagged
7267 -- then
7268 -- Lim_Typ_Stmts
7269 -- else
7270 -- Conc_Typ_Stmts
7271 -- end if;
7273 Append_To (Stmts,
7274 Make_Implicit_If_Statement (N,
7275 Condition => Build_Dispatching_Tag_Check (K, N),
7276 Then_Statements => Lim_Typ_Stmts,
7277 Else_Statements => Conc_Typ_Stmts));
7279 Rewrite (N,
7280 Make_Block_Statement (Loc,
7281 Declarations =>
7282 Decls,
7283 Handled_Statement_Sequence =>
7284 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
7286 Analyze (N);
7287 return;
7289 -- Delay triggering statement processing
7291 else
7292 -- Add a Delay_Block object to the parameter list of the delay
7293 -- procedure to form the parameter list of the Wait entry call.
7295 Dblock_Ent := Make_Temporary (Loc, 'D');
7297 Pdef := Entity (Name (Ecall));
7299 if Is_RTE (Pdef, RO_CA_Delay_For) then
7300 Enqueue_Call :=
7301 New_Occurrence_Of (RTE (RE_Enqueue_Duration), Loc);
7303 elsif Is_RTE (Pdef, RO_CA_Delay_Until) then
7304 Enqueue_Call :=
7305 New_Occurrence_Of (RTE (RE_Enqueue_Calendar), Loc);
7307 else pragma Assert (Is_RTE (Pdef, RO_RT_Delay_Until));
7308 Enqueue_Call := New_Occurrence_Of (RTE (RE_Enqueue_RT), Loc);
7309 end if;
7311 Append_To (Parameter_Associations (Ecall),
7312 Make_Attribute_Reference (Loc,
7313 Prefix => New_Occurrence_Of (Dblock_Ent, Loc),
7314 Attribute_Name => Name_Unchecked_Access));
7316 -- Create the inner block to protect the abortable part
7318 Hdle := New_List (Build_Abort_Block_Handler (Loc));
7320 Prepend_To (Astats, Build_Runtime_Call (Loc, RE_Abort_Undefer));
7322 Abortable_Block :=
7323 Make_Block_Statement (Loc,
7324 Identifier => New_Occurrence_Of (Blk_Ent, Loc),
7325 Handled_Statement_Sequence =>
7326 Make_Handled_Sequence_Of_Statements (Loc,
7327 Statements => Astats),
7328 Has_Created_Identifier => True,
7329 Is_Asynchronous_Call_Block => True);
7331 -- Append call to if Enqueue (When, DB'Unchecked_Access) then
7333 Rewrite (Ecall,
7334 Make_Implicit_If_Statement (N,
7335 Condition =>
7336 Make_Function_Call (Loc,
7337 Name => Enqueue_Call,
7338 Parameter_Associations => Parameter_Associations (Ecall)),
7339 Then_Statements =>
7340 New_List (Make_Block_Statement (Loc,
7341 Handled_Statement_Sequence =>
7342 Make_Handled_Sequence_Of_Statements (Loc,
7343 Statements => New_List (
7344 Make_Implicit_Label_Declaration (Loc,
7345 Defining_Identifier => Blk_Ent,
7346 Label_Construct => Abortable_Block),
7347 Abortable_Block),
7348 Exception_Handlers => Hdle)))));
7350 Stmts := New_List (Ecall);
7352 -- Construct statement sequence for new block
7354 Append_To (Stmts,
7355 Make_Implicit_If_Statement (N,
7356 Condition =>
7357 Make_Function_Call (Loc,
7358 Name => New_Occurrence_Of (
7359 RTE (RE_Timed_Out), Loc),
7360 Parameter_Associations => New_List (
7361 Make_Attribute_Reference (Loc,
7362 Prefix => New_Occurrence_Of (Dblock_Ent, Loc),
7363 Attribute_Name => Name_Unchecked_Access))),
7364 Then_Statements => Tstats));
7366 -- The result is the new block
7368 Set_Entry_Cancel_Parameter (Blk_Ent, Dblock_Ent);
7370 Rewrite (N,
7371 Make_Block_Statement (Loc,
7372 Declarations => New_List (
7373 Make_Object_Declaration (Loc,
7374 Defining_Identifier => Dblock_Ent,
7375 Aliased_Present => True,
7376 Object_Definition =>
7377 New_Occurrence_Of (RTE (RE_Delay_Block), Loc))),
7379 Handled_Statement_Sequence =>
7380 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
7382 Analyze (N);
7383 return;
7384 end if;
7386 else
7387 N_Orig := N;
7388 end if;
7390 Extract_Entry (Ecall, Concval, Ename, Index);
7391 Build_Simple_Entry_Call (Ecall, Concval, Ename, Index);
7393 Stmts := Statements (Handled_Statement_Sequence (Ecall));
7394 Decls := Declarations (Ecall);
7396 if Is_Protected_Type (Etype (Concval)) then
7398 -- Get the declarations of the block expanded from the entry call
7400 Decl := First (Decls);
7401 while Present (Decl)
7402 and then (Nkind (Decl) /= N_Object_Declaration
7403 or else not Is_RTE (Etype (Object_Definition (Decl)),
7404 RE_Communication_Block))
7405 loop
7406 Next (Decl);
7407 end loop;
7409 pragma Assert (Present (Decl));
7410 Cancel_Param := Defining_Identifier (Decl);
7412 -- Change the mode of the Protected_Entry_Call call
7414 -- Protected_Entry_Call (
7415 -- Object => po._object'Access,
7416 -- E => <entry index>;
7417 -- Uninterpreted_Data => P'Address;
7418 -- Mode => Asynchronous_Call;
7419 -- Block => Bnn);
7421 -- Skip assignments to temporaries created for in-out parameters
7423 -- This makes unwarranted assumptions about the shape of the expanded
7424 -- tree for the call, and should be cleaned up ???
7426 Stmt := First (Stmts);
7427 while Nkind (Stmt) /= N_Procedure_Call_Statement loop
7428 Next (Stmt);
7429 end loop;
7431 Call := Stmt;
7433 Param := First (Parameter_Associations (Call));
7434 while Present (Param)
7435 and then not Is_RTE (Etype (Param), RE_Call_Modes)
7436 loop
7437 Next (Param);
7438 end loop;
7440 pragma Assert (Present (Param));
7441 Rewrite (Param, New_Occurrence_Of (RTE (RE_Asynchronous_Call), Loc));
7442 Analyze (Param);
7444 -- Append an if statement to execute the abortable part
7446 -- Generate:
7447 -- if Enqueued (Bnn) then
7449 Append_To (Stmts,
7450 Make_Implicit_If_Statement (N,
7451 Condition =>
7452 Make_Function_Call (Loc,
7453 Name => New_Occurrence_Of (RTE (RE_Enqueued), Loc),
7454 Parameter_Associations => New_List (
7455 New_Occurrence_Of (Cancel_Param, Loc))),
7456 Then_Statements => Astats));
7458 Abortable_Block :=
7459 Make_Block_Statement (Loc,
7460 Identifier => New_Occurrence_Of (Blk_Ent, Loc),
7461 Handled_Statement_Sequence =>
7462 Make_Handled_Sequence_Of_Statements (Loc, Statements => Stmts),
7463 Has_Created_Identifier => True,
7464 Is_Asynchronous_Call_Block => True);
7466 Stmts := New_List (
7467 Make_Block_Statement (Loc,
7468 Handled_Statement_Sequence =>
7469 Make_Handled_Sequence_Of_Statements (Loc,
7470 Statements => New_List (
7471 Make_Implicit_Label_Declaration (Loc,
7472 Defining_Identifier => Blk_Ent,
7473 Label_Construct => Abortable_Block),
7474 Abortable_Block),
7476 -- exception
7478 Exception_Handlers => New_List (
7479 Make_Implicit_Exception_Handler (Loc,
7481 -- when Abort_Signal =>
7482 -- null;
7484 Exception_Choices =>
7485 New_List (New_Occurrence_Of (Stand.Abort_Signal, Loc)),
7486 Statements => New_List (Make_Null_Statement (Loc)))))),
7488 -- if not Cancelled (Bnn) then
7489 -- triggered statements
7490 -- end if;
7492 Make_Implicit_If_Statement (N,
7493 Condition => Make_Op_Not (Loc,
7494 Right_Opnd =>
7495 Make_Function_Call (Loc,
7496 Name => New_Occurrence_Of (RTE (RE_Cancelled), Loc),
7497 Parameter_Associations => New_List (
7498 New_Occurrence_Of (Cancel_Param, Loc)))),
7499 Then_Statements => Tstats));
7501 -- Asynchronous task entry call
7503 else
7504 if No (Decls) then
7505 Decls := New_List;
7506 end if;
7508 B := Make_Defining_Identifier (Loc, Name_uB);
7510 -- Insert declaration of B in declarations of existing block
7512 Prepend_To (Decls,
7513 Make_Object_Declaration (Loc,
7514 Defining_Identifier => B,
7515 Object_Definition =>
7516 New_Occurrence_Of (Standard_Boolean, Loc)));
7518 Cancel_Param := Make_Defining_Identifier (Loc, Name_uC);
7520 -- Insert the declaration of C in the declarations of the existing
7521 -- block. The variable is initialized to something (True or False,
7522 -- does not matter) to prevent CodePeer from complaining about a
7523 -- possible read of an uninitialized variable.
7525 Prepend_To (Decls,
7526 Make_Object_Declaration (Loc,
7527 Defining_Identifier => Cancel_Param,
7528 Object_Definition => New_Occurrence_Of (Standard_Boolean, Loc),
7529 Expression => New_Occurrence_Of (Standard_False, Loc),
7530 Has_Init_Expression => True));
7532 -- Remove and save the call to Call_Simple
7534 Stmt := First (Stmts);
7536 -- Skip assignments to temporaries created for in-out parameters.
7537 -- This makes unwarranted assumptions about the shape of the expanded
7538 -- tree for the call, and should be cleaned up ???
7540 while Nkind (Stmt) /= N_Procedure_Call_Statement loop
7541 Next (Stmt);
7542 end loop;
7544 Call := Stmt;
7546 -- Create the inner block to protect the abortable part
7548 Hdle := New_List (Build_Abort_Block_Handler (Loc));
7550 if Abort_Allowed then
7551 Prepend_To (Astats, Build_Runtime_Call (Loc, RE_Abort_Undefer));
7552 end if;
7554 Abortable_Block :=
7555 Make_Block_Statement (Loc,
7556 Identifier => New_Occurrence_Of (Blk_Ent, Loc),
7557 Handled_Statement_Sequence =>
7558 Make_Handled_Sequence_Of_Statements (Loc, Statements => Astats),
7559 Has_Created_Identifier => True,
7560 Is_Asynchronous_Call_Block => True);
7562 Insert_After (Call,
7563 Make_Block_Statement (Loc,
7564 Handled_Statement_Sequence =>
7565 Make_Handled_Sequence_Of_Statements (Loc,
7566 Statements => New_List (
7567 Make_Implicit_Label_Declaration (Loc,
7568 Defining_Identifier => Blk_Ent,
7569 Label_Construct => Abortable_Block),
7570 Abortable_Block),
7571 Exception_Handlers => Hdle)));
7573 -- Create new call statement
7575 Params := Parameter_Associations (Call);
7577 Append_To (Params,
7578 New_Occurrence_Of (RTE (RE_Asynchronous_Call), Loc));
7579 Append_To (Params, New_Occurrence_Of (B, Loc));
7581 Rewrite (Call,
7582 Make_Procedure_Call_Statement (Loc,
7583 Name => New_Occurrence_Of (RTE (RE_Task_Entry_Call), Loc),
7584 Parameter_Associations => Params));
7586 -- Construct statement sequence for new block
7588 Append_To (Stmts,
7589 Make_Implicit_If_Statement (N,
7590 Condition =>
7591 Make_Op_Not (Loc, New_Occurrence_Of (Cancel_Param, Loc)),
7592 Then_Statements => Tstats));
7594 -- Protected the call against abort
7596 Prepend_To (Stmts, Build_Runtime_Call (Loc, RE_Abort_Defer));
7597 end if;
7599 Set_Entry_Cancel_Parameter (Blk_Ent, Cancel_Param);
7601 -- The result is the new block
7603 Rewrite (N_Orig,
7604 Make_Block_Statement (Loc,
7605 Declarations => Decls,
7606 Handled_Statement_Sequence =>
7607 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
7609 Analyze (N_Orig);
7610 end Expand_N_Asynchronous_Select;
7612 -------------------------------------
7613 -- Expand_N_Conditional_Entry_Call --
7614 -------------------------------------
7616 -- The conditional task entry call is converted to a call to
7617 -- Task_Entry_Call:
7619 -- declare
7620 -- B : Boolean;
7621 -- P : parms := (parm, parm, parm);
7623 -- begin
7624 -- Task_Entry_Call
7625 -- (<acceptor-task>, -- Acceptor
7626 -- <entry-index>, -- E
7627 -- P'Address, -- Uninterpreted_Data
7628 -- Conditional_Call, -- Mode
7629 -- B); -- Rendezvous_Successful
7630 -- parm := P.param;
7631 -- parm := P.param;
7632 -- ...
7633 -- if B then
7634 -- normal-statements
7635 -- else
7636 -- else-statements
7637 -- end if;
7638 -- end;
7640 -- For a description of the use of P and the assignments after the call,
7641 -- see Expand_N_Entry_Call_Statement. Note that the entry call of the
7642 -- conditional entry call has already been expanded (by the Expand_N_Entry
7643 -- _Call_Statement procedure) as follows:
7645 -- declare
7646 -- P : parms := (parm, parm, parm);
7647 -- begin
7648 -- ... info for in-out parameters
7649 -- Call_Simple (acceptor-task, entry-index, P'Address);
7650 -- parm := P.param;
7651 -- parm := P.param;
7652 -- ...
7653 -- end;
7655 -- so the task at hand is to convert the latter expansion into the former
7657 -- The conditional protected entry call is converted to a call to
7658 -- Protected_Entry_Call:
7660 -- declare
7661 -- P : parms := (parm, parm, parm);
7662 -- Bnn : Communications_Block;
7664 -- begin
7665 -- Protected_Entry_Call
7666 -- (po._object'Access, -- Object
7667 -- <entry index>, -- E
7668 -- P'Address, -- Uninterpreted_Data
7669 -- Conditional_Call, -- Mode
7670 -- Bnn); -- Block
7671 -- parm := P.param;
7672 -- parm := P.param;
7673 -- ...
7674 -- if Cancelled (Bnn) then
7675 -- else-statements
7676 -- else
7677 -- normal-statements
7678 -- end if;
7679 -- end;
7681 -- Ada 2005 (AI-345): A dispatching conditional entry call is converted
7682 -- into:
7684 -- declare
7685 -- B : Boolean := False;
7686 -- C : Ada.Tags.Prim_Op_Kind;
7687 -- K : Ada.Tags.Tagged_Kind :=
7688 -- Ada.Tags.Get_Tagged_Kind (Ada.Tags.Tag (<object>));
7689 -- P : Parameters := (Param1 .. ParamN);
7690 -- S : Integer;
7692 -- begin
7693 -- if K = Ada.Tags.TK_Limited_Tagged
7694 -- or else K = Ada.Tags.TK_Tagged
7695 -- then
7696 -- <dispatching-call>;
7697 -- -- <triggering-statements> (code factorized after if-stmt)
7699 -- else
7700 -- S :=
7701 -- Ada.Tags.Get_Offset_Index
7702 -- (Ada.Tags.Tag (<object>), DT_Position (<dispatching-call>));
7704 -- _Disp_Conditional_Select (<object>, S, P'Address, C, B);
7706 -- if C = POK_Protected_Entry
7707 -- or else C = POK_Task_Entry
7708 -- then
7709 -- Param1 := P.Param1;
7710 -- ...
7711 -- ParamN := P.ParamN;
7712 -- end if;
7714 -- if B then
7715 -- if C = POK_Procedure
7716 -- or else C = POK_Protected_Procedure
7717 -- or else C = POK_Task_Procedure
7718 -- then
7719 -- <dispatching-call>;
7720 -- end if;
7722 -- -- <triggering-statements> (code factorized after if-stmt)
7723 -- else
7724 -- <else-statements>
7725 -- goto L0; -- skip triggering statements
7726 -- end if;
7727 -- end if;
7728 -- <triggering-statements>
7729 -- L0:
7730 -- end;
7732 procedure Expand_N_Conditional_Entry_Call (N : Node_Id) is
7733 Loc : constant Source_Ptr := Sloc (N);
7734 Alt : constant Node_Id := Entry_Call_Alternative (N);
7735 Blk : Node_Id := Entry_Call_Statement (Alt);
7737 Actuals : List_Id;
7738 Blk_Typ : Entity_Id;
7739 Call : Node_Id;
7740 Call_Ent : Entity_Id;
7741 Conc_Typ_Stmts : List_Id;
7742 Decl : Node_Id;
7743 Decls : List_Id;
7744 Formals : List_Id;
7745 Label : Node_Id;
7746 Label_Id : Entity_Id := Empty;
7747 Lim_Typ_Stmts : List_Id;
7748 N_Stats : List_Id;
7749 Obj : Entity_Id;
7750 Param : Node_Id;
7751 Params : List_Id;
7752 Stmt : Node_Id;
7753 Stmts : List_Id;
7754 Transient_Blk : Node_Id;
7755 Unpack : List_Id;
7757 B : Entity_Id; -- Call status flag
7758 C : Entity_Id; -- Call kind
7759 K : Entity_Id; -- Tagged kind
7760 P : Entity_Id; -- Parameter block
7761 S : Entity_Id; -- Primitive operation slot
7763 begin
7764 Process_Statements_For_Controlled_Objects (N);
7766 if Ada_Version >= Ada_2005
7767 and then Nkind (Blk) = N_Procedure_Call_Statement
7768 then
7769 Extract_Dispatching_Call (Blk, Call_Ent, Obj, Actuals, Formals);
7771 Decls := New_List;
7772 Stmts := New_List;
7774 -- Call status flag processing, generate:
7775 -- B : Boolean := False;
7777 B := Build_B (Loc, Decls);
7779 -- Call kind processing, generate:
7780 -- C : Ada.Tags.Prim_Op_Kind;
7782 C := Build_C (Loc, Decls);
7784 -- Tagged kind processing, generate:
7785 -- K : Ada.Tags.Tagged_Kind :=
7786 -- Ada.Tags.Get_Tagged_Kind (Ada.Tags.Tag (<object>));
7788 K := Build_K (Loc, Decls, Obj);
7790 -- Parameter block processing
7792 Blk_Typ := Build_Parameter_Block (Loc, Actuals, Formals, Decls);
7793 P := Parameter_Block_Pack
7794 (Loc, Blk_Typ, Actuals, Formals, Decls, Stmts);
7796 -- Dispatch table slot processing, generate:
7797 -- S : Integer;
7799 S := Build_S (Loc, Decls);
7801 -- Generate:
7802 -- S := Ada.Tags.Get_Offset_Index
7803 -- (Ada.Tags.Tag (<object>), DT_Position (Call_Ent));
7805 Conc_Typ_Stmts :=
7806 New_List (Build_S_Assignment (Loc, S, Obj, Call_Ent));
7808 -- Generate:
7809 -- _Disp_Conditional_Select (<object>, S, P'Address, C, B);
7811 Append_To (Conc_Typ_Stmts,
7812 Make_Procedure_Call_Statement (Loc,
7813 Name =>
7814 New_Occurrence_Of (
7815 Find_Prim_Op (Etype (Etype (Obj)),
7816 Name_uDisp_Conditional_Select),
7817 Loc),
7818 Parameter_Associations =>
7819 New_List (
7820 New_Copy_Tree (Obj), -- <object>
7821 New_Occurrence_Of (S, Loc), -- S
7822 Make_Attribute_Reference (Loc, -- P'Address
7823 Prefix => New_Occurrence_Of (P, Loc),
7824 Attribute_Name => Name_Address),
7825 New_Occurrence_Of (C, Loc), -- C
7826 New_Occurrence_Of (B, Loc)))); -- B
7828 -- Generate:
7829 -- if C = POK_Protected_Entry
7830 -- or else C = POK_Task_Entry
7831 -- then
7832 -- Param1 := P.Param1;
7833 -- ...
7834 -- ParamN := P.ParamN;
7835 -- end if;
7837 Unpack := Parameter_Block_Unpack (Loc, P, Actuals, Formals);
7839 -- Generate the if statement only when the packed parameters need
7840 -- explicit assignments to their corresponding actuals.
7842 if Present (Unpack) then
7843 Append_To (Conc_Typ_Stmts,
7844 Make_Implicit_If_Statement (N,
7845 Condition =>
7846 Make_Or_Else (Loc,
7847 Left_Opnd =>
7848 Make_Op_Eq (Loc,
7849 Left_Opnd =>
7850 New_Occurrence_Of (C, Loc),
7851 Right_Opnd =>
7852 New_Occurrence_Of (RTE (
7853 RE_POK_Protected_Entry), Loc)),
7855 Right_Opnd =>
7856 Make_Op_Eq (Loc,
7857 Left_Opnd =>
7858 New_Occurrence_Of (C, Loc),
7859 Right_Opnd =>
7860 New_Occurrence_Of (RTE (RE_POK_Task_Entry), Loc))),
7862 Then_Statements => Unpack));
7863 end if;
7865 -- Generate:
7866 -- if B then
7867 -- if C = POK_Procedure
7868 -- or else C = POK_Protected_Procedure
7869 -- or else C = POK_Task_Procedure
7870 -- then
7871 -- <dispatching-call>
7872 -- end if;
7873 -- -- <triggering-stataments> (code factorized after if-stmt)
7874 -- else
7875 -- <else-statements>
7876 -- goto L0; -- skip triggering statements
7877 -- end if;
7879 N_Stats := New_List;
7881 Prepend_To (N_Stats,
7882 Make_Implicit_If_Statement (N,
7883 Condition =>
7884 Make_Or_Else (Loc,
7885 Left_Opnd =>
7886 Make_Op_Eq (Loc,
7887 Left_Opnd =>
7888 New_Occurrence_Of (C, Loc),
7889 Right_Opnd =>
7890 New_Occurrence_Of (RTE (RE_POK_Procedure), Loc)),
7892 Right_Opnd =>
7893 Make_Or_Else (Loc,
7894 Left_Opnd =>
7895 Make_Op_Eq (Loc,
7896 Left_Opnd =>
7897 New_Occurrence_Of (C, Loc),
7898 Right_Opnd =>
7899 New_Occurrence_Of (RTE (
7900 RE_POK_Protected_Procedure), Loc)),
7902 Right_Opnd =>
7903 Make_Op_Eq (Loc,
7904 Left_Opnd =>
7905 New_Occurrence_Of (C, Loc),
7906 Right_Opnd =>
7907 New_Occurrence_Of (RTE (
7908 RE_POK_Task_Procedure), Loc)))),
7910 Then_Statements =>
7911 New_List (Blk)));
7913 Label_Id := Make_Identifier (Loc, New_External_Name ('L', 0));
7914 Set_Entity (Label_Id,
7915 Make_Defining_Identifier (Loc, Chars (Label_Id)));
7917 Append_To (Else_Statements (N),
7918 Make_Goto_Statement (Loc,
7919 Name => New_Occurrence_Of (Entity (Label_Id), Loc)));
7921 Append_To (Conc_Typ_Stmts,
7922 Make_Implicit_If_Statement (N,
7923 Condition => New_Occurrence_Of (B, Loc),
7924 Then_Statements => N_Stats,
7925 Else_Statements => Else_Statements (N)));
7927 -- Generate:
7928 -- <dispatching-call>;
7929 -- -- <triggering-statements> (code factorized after if-stmt)
7931 Lim_Typ_Stmts := New_List (New_Copy_Tree (Blk));
7933 -- Generate:
7934 -- if K = Ada.Tags.TK_Limited_Tagged
7935 -- or else K = Ada.Tags.TK_Tagged
7936 -- then
7937 -- Lim_Typ_Stmts
7938 -- else
7939 -- Conc_Typ_Stmts
7940 -- end if;
7942 Append_To (Stmts,
7943 Make_Implicit_If_Statement (N,
7944 Condition => Build_Dispatching_Tag_Check (K, N),
7945 Then_Statements => Lim_Typ_Stmts,
7946 Else_Statements => Conc_Typ_Stmts));
7948 Label := Make_Label (Loc, Label_Id);
7949 Append_To (Decls,
7950 Make_Implicit_Label_Declaration (Loc,
7951 Defining_Identifier => Entity (Label_Id),
7952 Label_Construct => Label));
7954 Append_List_To (Stmts, Statements (Alt)); -- triggering-statements
7955 Append_To (Stmts, Label);
7957 Rewrite (N,
7958 Make_Block_Statement (Loc,
7959 Declarations =>
7960 Decls,
7961 Handled_Statement_Sequence =>
7962 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
7964 -- As described above, the entry alternative is transformed into a
7965 -- block that contains the gnulli call, and possibly assignment
7966 -- statements for in-out parameters. The gnulli call may itself be
7967 -- rewritten into a transient block if some unconstrained parameters
7968 -- require it. We need to retrieve the call to complete its parameter
7969 -- list.
7971 else
7972 Transient_Blk :=
7973 First (Statements (Handled_Statement_Sequence (Blk)));
7975 if Present (Transient_Blk)
7976 and then Nkind (Transient_Blk) = N_Block_Statement
7977 then
7978 Blk := Transient_Blk;
7979 end if;
7981 Stmts := Statements (Handled_Statement_Sequence (Blk));
7982 Stmt := First (Stmts);
7983 while Nkind (Stmt) /= N_Procedure_Call_Statement loop
7984 Next (Stmt);
7985 end loop;
7987 Call := Stmt;
7988 Params := Parameter_Associations (Call);
7990 if Is_RTE (Entity (Name (Call)), RE_Protected_Entry_Call) then
7992 -- Substitute Conditional_Entry_Call for Simple_Call parameter
7994 Param := First (Params);
7995 while Present (Param)
7996 and then not Is_RTE (Etype (Param), RE_Call_Modes)
7997 loop
7998 Next (Param);
7999 end loop;
8001 pragma Assert (Present (Param));
8002 Rewrite (Param,
8003 New_Occurrence_Of (RTE (RE_Conditional_Call), Loc));
8005 Analyze (Param);
8007 -- Find the Communication_Block parameter for the call to the
8008 -- Cancelled function.
8010 Decl := First (Declarations (Blk));
8011 while Present (Decl)
8012 and then not Is_RTE (Etype (Object_Definition (Decl)),
8013 RE_Communication_Block)
8014 loop
8015 Next (Decl);
8016 end loop;
8018 -- Add an if statement to execute the else part if the call
8019 -- does not succeed (as indicated by the Cancelled predicate).
8021 Append_To (Stmts,
8022 Make_Implicit_If_Statement (N,
8023 Condition => Make_Function_Call (Loc,
8024 Name => New_Occurrence_Of (RTE (RE_Cancelled), Loc),
8025 Parameter_Associations => New_List (
8026 New_Occurrence_Of (Defining_Identifier (Decl), Loc))),
8027 Then_Statements => Else_Statements (N),
8028 Else_Statements => Statements (Alt)));
8030 else
8031 B := Make_Defining_Identifier (Loc, Name_uB);
8033 -- Insert declaration of B in declarations of existing block
8035 if No (Declarations (Blk)) then
8036 Set_Declarations (Blk, New_List);
8037 end if;
8039 Prepend_To (Declarations (Blk),
8040 Make_Object_Declaration (Loc,
8041 Defining_Identifier => B,
8042 Object_Definition =>
8043 New_Occurrence_Of (Standard_Boolean, Loc)));
8045 -- Create new call statement
8047 Append_To (Params,
8048 New_Occurrence_Of (RTE (RE_Conditional_Call), Loc));
8049 Append_To (Params, New_Occurrence_Of (B, Loc));
8051 Rewrite (Call,
8052 Make_Procedure_Call_Statement (Loc,
8053 Name => New_Occurrence_Of (RTE (RE_Task_Entry_Call), Loc),
8054 Parameter_Associations => Params));
8056 -- Construct statement sequence for new block
8058 Append_To (Stmts,
8059 Make_Implicit_If_Statement (N,
8060 Condition => New_Occurrence_Of (B, Loc),
8061 Then_Statements => Statements (Alt),
8062 Else_Statements => Else_Statements (N)));
8063 end if;
8065 -- The result is the new block
8067 Rewrite (N,
8068 Make_Block_Statement (Loc,
8069 Declarations => Declarations (Blk),
8070 Handled_Statement_Sequence =>
8071 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
8072 end if;
8074 Analyze (N);
8076 Reset_Scopes_To (N, Entity (Identifier (N)));
8077 end Expand_N_Conditional_Entry_Call;
8079 ---------------------------------------
8080 -- Expand_N_Delay_Relative_Statement --
8081 ---------------------------------------
8083 -- Delay statement is implemented as a procedure call to Delay_For
8084 -- defined in Ada.Calendar.Delays in order to reduce the overhead of
8085 -- simple delays imposed by the use of Protected Objects.
8087 procedure Expand_N_Delay_Relative_Statement (N : Node_Id) is
8088 Loc : constant Source_Ptr := Sloc (N);
8089 Proc : Entity_Id;
8091 begin
8092 -- Try to use Ada.Calendar.Delays.Delay_For if available.
8094 if RTE_Available (RO_CA_Delay_For) then
8095 Proc := RTE (RO_CA_Delay_For);
8097 -- Otherwise, use System.Relative_Delays.Delay_For and emit an error
8098 -- message if not available. This is the implementation used on
8099 -- restricted platforms when Ada.Calendar is not available.
8101 else
8102 Proc := RTE (RO_RD_Delay_For);
8103 end if;
8105 Rewrite (N,
8106 Make_Procedure_Call_Statement (Loc,
8107 Name => New_Occurrence_Of (Proc, Loc),
8108 Parameter_Associations => New_List (Expression (N))));
8109 Analyze (N);
8110 end Expand_N_Delay_Relative_Statement;
8112 ------------------------------------
8113 -- Expand_N_Delay_Until_Statement --
8114 ------------------------------------
8116 -- Delay Until statement is implemented as a procedure call to
8117 -- Delay_Until defined in Ada.Calendar.Delays and Ada.Real_Time.Delays.
8119 procedure Expand_N_Delay_Until_Statement (N : Node_Id) is
8120 Loc : constant Source_Ptr := Sloc (N);
8121 Typ : Entity_Id;
8123 begin
8124 if Is_RTE (Base_Type (Etype (Expression (N))), RO_CA_Time) then
8125 Typ := RTE (RO_CA_Delay_Until);
8126 else
8127 Typ := RTE (RO_RT_Delay_Until);
8128 end if;
8130 Rewrite (N,
8131 Make_Procedure_Call_Statement (Loc,
8132 Name => New_Occurrence_Of (Typ, Loc),
8133 Parameter_Associations => New_List (Expression (N))));
8135 Analyze (N);
8136 end Expand_N_Delay_Until_Statement;
8138 -------------------------
8139 -- Expand_N_Entry_Body --
8140 -------------------------
8142 procedure Expand_N_Entry_Body (N : Node_Id) is
8143 begin
8144 -- Associate discriminals with the next protected operation body to be
8145 -- expanded.
8147 if Present (Next_Protected_Operation (N)) then
8148 Set_Discriminals (Parent (Current_Scope));
8149 end if;
8150 end Expand_N_Entry_Body;
8152 -----------------------------------
8153 -- Expand_N_Entry_Call_Statement --
8154 -----------------------------------
8156 -- An entry call is expanded into GNARLI calls to implement a simple entry
8157 -- call (see Build_Simple_Entry_Call).
8159 procedure Expand_N_Entry_Call_Statement (N : Node_Id) is
8160 Concval : Node_Id;
8161 Ename : Node_Id;
8162 Index : Node_Id;
8164 begin
8165 if No_Run_Time_Mode then
8166 Error_Msg_CRT ("entry call", N);
8167 return;
8168 end if;
8170 -- If this entry call is part of an asynchronous select, don't expand it
8171 -- here; it will be expanded with the select statement. Don't expand
8172 -- timed entry calls either, as they are translated into asynchronous
8173 -- entry calls.
8175 -- ??? This whole approach is questionable; it may be better to go back
8176 -- to allowing the expansion to take place and then attempting to fix it
8177 -- up in Expand_N_Asynchronous_Select. The tricky part is figuring out
8178 -- whether the expanded call is on a task or protected entry.
8180 if (Nkind (Parent (N)) /= N_Triggering_Alternative
8181 or else N /= Triggering_Statement (Parent (N)))
8182 and then (Nkind (Parent (N)) /= N_Entry_Call_Alternative
8183 or else N /= Entry_Call_Statement (Parent (N))
8184 or else Nkind (Parent (Parent (N))) /= N_Timed_Entry_Call)
8185 then
8186 Extract_Entry (N, Concval, Ename, Index);
8187 Build_Simple_Entry_Call (N, Concval, Ename, Index);
8188 end if;
8189 end Expand_N_Entry_Call_Statement;
8191 --------------------------------
8192 -- Expand_N_Entry_Declaration --
8193 --------------------------------
8195 -- If there are parameters, then first, each of the formals is marked by
8196 -- setting Is_Entry_Formal. Next a record type is built which is used to
8197 -- hold the parameter values. The name of this record type is entryP where
8198 -- entry is the name of the entry, with an additional corresponding access
8199 -- type called entryPA. The record type has matching components for each
8200 -- formal (the component names are the same as the formal names). For
8201 -- elementary types, the component type matches the formal type. For
8202 -- composite types, an access type is declared (with the name formalA)
8203 -- which designates the formal type, and the type of the component is this
8204 -- access type. Finally the Entry_Component of each formal is set to
8205 -- reference the corresponding record component.
8207 procedure Expand_N_Entry_Declaration (N : Node_Id) is
8208 Loc : constant Source_Ptr := Sloc (N);
8209 Entry_Ent : constant Entity_Id := Defining_Identifier (N);
8210 Components : List_Id;
8211 Formal : Node_Id;
8212 Ftype : Entity_Id;
8213 Last_Decl : Node_Id;
8214 Component : Entity_Id;
8215 Ctype : Entity_Id;
8216 Decl : Node_Id;
8217 Rec_Ent : Entity_Id;
8218 Acc_Ent : Entity_Id;
8220 begin
8221 Formal := First_Formal (Entry_Ent);
8222 Last_Decl := N;
8224 -- Most processing is done only if parameters are present
8226 if Present (Formal) then
8227 Components := New_List;
8229 -- Loop through formals
8231 while Present (Formal) loop
8232 Set_Is_Entry_Formal (Formal);
8233 Component :=
8234 Make_Defining_Identifier (Sloc (Formal), Chars (Formal));
8235 Set_Entry_Component (Formal, Component);
8236 Set_Entry_Formal (Component, Formal);
8237 Ftype := Etype (Formal);
8239 -- Declare new access type and then append
8241 Ctype := Make_Temporary (Loc, 'A');
8242 Set_Is_Param_Block_Component_Type (Ctype);
8244 Decl :=
8245 Make_Full_Type_Declaration (Loc,
8246 Defining_Identifier => Ctype,
8247 Type_Definition =>
8248 Make_Access_To_Object_Definition (Loc,
8249 All_Present => True,
8250 Constant_Present => Ekind (Formal) = E_In_Parameter,
8251 Subtype_Indication => New_Occurrence_Of (Ftype, Loc)));
8253 Insert_After (Last_Decl, Decl);
8254 Last_Decl := Decl;
8256 Append_To (Components,
8257 Make_Component_Declaration (Loc,
8258 Defining_Identifier => Component,
8259 Component_Definition =>
8260 Make_Component_Definition (Loc,
8261 Aliased_Present => False,
8262 Subtype_Indication => New_Occurrence_Of (Ctype, Loc))));
8264 Next_Formal_With_Extras (Formal);
8265 end loop;
8267 -- Create the Entry_Parameter_Record declaration
8269 Rec_Ent := Make_Temporary (Loc, 'P');
8271 Decl :=
8272 Make_Full_Type_Declaration (Loc,
8273 Defining_Identifier => Rec_Ent,
8274 Type_Definition =>
8275 Make_Record_Definition (Loc,
8276 Component_List =>
8277 Make_Component_List (Loc,
8278 Component_Items => Components)));
8280 Insert_After (Last_Decl, Decl);
8281 Last_Decl := Decl;
8283 -- Construct and link in the corresponding access type
8285 Acc_Ent := Make_Temporary (Loc, 'A');
8287 Set_Entry_Parameters_Type (Entry_Ent, Acc_Ent);
8289 Decl :=
8290 Make_Full_Type_Declaration (Loc,
8291 Defining_Identifier => Acc_Ent,
8292 Type_Definition =>
8293 Make_Access_To_Object_Definition (Loc,
8294 All_Present => True,
8295 Subtype_Indication => New_Occurrence_Of (Rec_Ent, Loc)));
8297 Insert_After (Last_Decl, Decl);
8298 end if;
8299 end Expand_N_Entry_Declaration;
8301 -----------------------------
8302 -- Expand_N_Protected_Body --
8303 -----------------------------
8305 -- Protected bodies are expanded to the completion of the subprograms
8306 -- created for the corresponding protected type. These are a protected and
8307 -- unprotected version of each protected subprogram in the object, a
8308 -- function to calculate each entry barrier, and a procedure to execute the
8309 -- sequence of statements of each protected entry body. For example, for
8310 -- protected type ptype:
8312 -- function entB
8313 -- (O : System.Address;
8314 -- E : Protected_Entry_Index)
8315 -- return Boolean
8316 -- is
8317 -- <discriminant renamings>
8318 -- <private object renamings>
8319 -- begin
8320 -- return <barrier expression>;
8321 -- end entB;
8323 -- procedure pprocN (_object : in out poV;...) is
8324 -- <discriminant renamings>
8325 -- <private object renamings>
8326 -- begin
8327 -- <sequence of statements>
8328 -- end pprocN;
8330 -- procedure pprocP (_object : in out poV;...) is
8331 -- procedure _clean is
8332 -- Pn : Boolean;
8333 -- begin
8334 -- ptypeS (_object, Pn);
8335 -- Unlock (_object._object'Access);
8336 -- Abort_Undefer.all;
8337 -- end _clean;
8339 -- begin
8340 -- Abort_Defer.all;
8341 -- Lock (_object._object'Access);
8342 -- pprocN (_object;...);
8343 -- at end
8344 -- _clean;
8345 -- end pproc;
8347 -- function pfuncN (_object : poV;...) return Return_Type is
8348 -- <discriminant renamings>
8349 -- <private object renamings>
8350 -- begin
8351 -- <sequence of statements>
8352 -- end pfuncN;
8354 -- function pfuncP (_object : poV) return Return_Type is
8355 -- procedure _clean is
8356 -- begin
8357 -- Unlock (_object._object'Access);
8358 -- Abort_Undefer.all;
8359 -- end _clean;
8361 -- begin
8362 -- Abort_Defer.all;
8363 -- Lock (_object._object'Access);
8364 -- return pfuncN (_object);
8366 -- at end
8367 -- _clean;
8368 -- end pfunc;
8370 -- procedure entE
8371 -- (O : System.Address;
8372 -- P : System.Address;
8373 -- E : Protected_Entry_Index)
8374 -- is
8375 -- <discriminant renamings>
8376 -- <private object renamings>
8377 -- type poVP is access poV;
8378 -- _Object : ptVP := ptVP!(O);
8380 -- begin
8381 -- begin
8382 -- <statement sequence>
8383 -- Complete_Entry_Body (_Object._Object);
8384 -- exception
8385 -- when all others =>
8386 -- Exceptional_Complete_Entry_Body (
8387 -- _Object._Object, Get_GNAT_Exception);
8388 -- end;
8389 -- end entE;
8391 -- The type poV is the record created for the protected type to hold
8392 -- the state of the protected object.
8394 procedure Expand_N_Protected_Body (N : Node_Id) is
8395 Loc : constant Source_Ptr := Sloc (N);
8396 Pid : constant Entity_Id := Corresponding_Spec (N);
8398 Lock_Free_Active : constant Boolean := Uses_Lock_Free (Pid);
8399 -- This flag indicates whether the lock free implementation is active
8401 Current_Node : Node_Id;
8402 Disp_Op_Body : Node_Id;
8403 New_Op_Body : Node_Id;
8404 New_Op_Spec : Node_Id;
8405 Op_Body : Node_Id;
8406 Op_Decl : Node_Id;
8407 Op_Id : Entity_Id;
8408 Op_Spec : Entity_Id;
8410 function Build_Dispatching_Subprogram_Body
8411 (N : Node_Id;
8412 Pid : Node_Id;
8413 Prot_Bod : Node_Id) return Node_Id;
8414 -- Build a dispatching version of the protected subprogram body. The
8415 -- newly generated subprogram contains a call to the original protected
8416 -- body. The following code is generated:
8418 -- function <protected-function-name> (Param1 .. ParamN) return
8419 -- <return-type> is
8420 -- begin
8421 -- return <protected-function-name>P (Param1 .. ParamN);
8422 -- end <protected-function-name>;
8424 -- or
8426 -- procedure <protected-procedure-name> (Param1 .. ParamN) is
8427 -- begin
8428 -- <protected-procedure-name>P (Param1 .. ParamN);
8429 -- end <protected-procedure-name>
8431 ---------------------------------------
8432 -- Build_Dispatching_Subprogram_Body --
8433 ---------------------------------------
8435 function Build_Dispatching_Subprogram_Body
8436 (N : Node_Id;
8437 Pid : Node_Id;
8438 Prot_Bod : Node_Id) return Node_Id
8440 Loc : constant Source_Ptr := Sloc (N);
8441 Actuals : List_Id;
8442 Formal : Node_Id;
8443 Spec : Node_Id;
8444 Stmts : List_Id;
8446 begin
8447 -- Generate a specification without a letter suffix in order to
8448 -- override an interface function or procedure.
8450 Spec := Build_Protected_Sub_Specification (N, Pid, Dispatching_Mode);
8452 -- The formal parameters become the actuals of the protected function
8453 -- or procedure call.
8455 Actuals := New_List;
8456 Formal := First (Parameter_Specifications (Spec));
8457 while Present (Formal) loop
8458 Append_To (Actuals,
8459 Make_Identifier (Loc, Chars (Defining_Identifier (Formal))));
8460 Next (Formal);
8461 end loop;
8463 if Nkind (Spec) = N_Procedure_Specification then
8464 Stmts :=
8465 New_List (
8466 Make_Procedure_Call_Statement (Loc,
8467 Name =>
8468 New_Occurrence_Of (Corresponding_Spec (Prot_Bod), Loc),
8469 Parameter_Associations => Actuals));
8471 else
8472 pragma Assert (Nkind (Spec) = N_Function_Specification);
8474 Stmts :=
8475 New_List (
8476 Make_Simple_Return_Statement (Loc,
8477 Expression =>
8478 Make_Function_Call (Loc,
8479 Name =>
8480 New_Occurrence_Of (Corresponding_Spec (Prot_Bod), Loc),
8481 Parameter_Associations => Actuals)));
8482 end if;
8484 return
8485 Make_Subprogram_Body (Loc,
8486 Declarations => Empty_List,
8487 Specification => Spec,
8488 Handled_Statement_Sequence =>
8489 Make_Handled_Sequence_Of_Statements (Loc, Stmts));
8490 end Build_Dispatching_Subprogram_Body;
8492 -- Start of processing for Expand_N_Protected_Body
8494 begin
8495 if No_Run_Time_Mode then
8496 Error_Msg_CRT ("protected body", N);
8497 return;
8498 end if;
8500 -- This is the proper body corresponding to a stub. The declarations
8501 -- must be inserted at the point of the stub, which in turn is in the
8502 -- declarative part of the parent unit.
8504 if Nkind (Parent (N)) = N_Subunit then
8505 Current_Node := Corresponding_Stub (Parent (N));
8506 else
8507 Current_Node := N;
8508 end if;
8510 Op_Body := First (Declarations (N));
8512 -- The protected body is replaced with the bodies of its protected
8513 -- operations, and the declarations for internal objects that may
8514 -- have been created for entry family bounds.
8516 Rewrite (N, Make_Null_Statement (Sloc (N)));
8517 Analyze (N);
8519 while Present (Op_Body) loop
8520 case Nkind (Op_Body) is
8521 when N_Subprogram_Declaration =>
8522 null;
8524 when N_Subprogram_Body =>
8525 Op_Spec := Corresponding_Spec (Op_Body);
8527 -- Do not create bodies for eliminated operations
8529 if not Is_Eliminated (Defining_Entity (Op_Body))
8530 and then not Is_Eliminated (Op_Spec)
8531 then
8532 if Lock_Free_Active then
8533 New_Op_Body :=
8534 Build_Lock_Free_Unprotected_Subprogram_Body
8535 (Op_Body, Pid);
8536 else
8537 New_Op_Body :=
8538 Build_Unprotected_Subprogram_Body (Op_Body, Pid);
8539 end if;
8541 Insert_After (Current_Node, New_Op_Body);
8542 Current_Node := New_Op_Body;
8543 Analyze (New_Op_Body);
8545 New_Op_Spec := Corresponding_Spec (New_Op_Body);
8547 -- When the original subprogram body has nested subprograms,
8548 -- the new body also has them, so set the flag accordingly.
8550 Set_Has_Nested_Subprogram
8551 (New_Op_Spec, Has_Nested_Subprogram (New_Op_Spec));
8553 -- Similarly, when the original subprogram body uses the
8554 -- secondary stack, the new body also does. This is needed
8555 -- when the cleanup actions of the subprogram are delayed
8556 -- because it contains a package instance with a body.
8558 Set_Uses_Sec_Stack (New_Op_Spec, Uses_Sec_Stack (Op_Spec));
8560 -- Now reset the scopes of the top-level nested subprograms
8561 -- and other declaration entities so that they now refer to
8562 -- the new body's entity (it would preferable to do this
8563 -- within Build_Protected_Sub_Specification, which is called
8564 -- from Build_Unprotected_Subprogram_Body, but the needed
8565 -- subprogram entity isn't available via Corresponding_Spec
8566 -- until after the above Analyze call).
8568 Reset_Scopes_To (New_Op_Body, New_Op_Spec);
8570 -- Build the corresponding protected operation. This is
8571 -- needed only if this is a public or private operation of
8572 -- the type.
8574 Op_Decl := Unit_Declaration_Node (Op_Spec);
8576 if Nkind (Parent (Op_Decl)) = N_Protected_Definition then
8577 if Lock_Free_Active then
8578 New_Op_Body :=
8579 Build_Lock_Free_Protected_Subprogram_Body
8580 (Op_Body, Pid, Specification (New_Op_Body));
8581 else
8582 New_Op_Body :=
8583 Build_Protected_Subprogram_Body
8584 (Op_Body, Pid, Specification (New_Op_Body));
8585 end if;
8587 Insert_After (Current_Node, New_Op_Body);
8588 Current_Node := New_Op_Body;
8589 Analyze (New_Op_Body);
8591 -- Generate an overriding primitive operation body for
8592 -- this subprogram if the protected type implements
8593 -- an interface.
8595 if Ada_Version >= Ada_2005
8596 and then
8597 Present (Interfaces (Corresponding_Record_Type (Pid)))
8598 then
8599 Disp_Op_Body :=
8600 Build_Dispatching_Subprogram_Body (
8601 Op_Body, Pid, New_Op_Body);
8603 Insert_After (Current_Node, Disp_Op_Body);
8604 Current_Node := Disp_Op_Body;
8605 Analyze (Disp_Op_Body);
8606 end if;
8607 end if;
8608 end if;
8610 when N_Entry_Body =>
8611 Op_Id := Defining_Identifier (Op_Body);
8612 New_Op_Body := Build_Protected_Entry (Op_Body, Op_Id, Pid);
8614 Insert_After (Current_Node, New_Op_Body);
8615 Current_Node := New_Op_Body;
8616 Analyze (New_Op_Body);
8618 when N_Implicit_Label_Declaration =>
8619 null;
8621 when N_Call_Marker
8622 | N_Itype_Reference
8624 New_Op_Body := New_Copy (Op_Body);
8625 Insert_After (Current_Node, New_Op_Body);
8626 Current_Node := New_Op_Body;
8628 when N_Freeze_Entity =>
8629 New_Op_Body := New_Copy (Op_Body);
8631 if Present (Entity (Op_Body))
8632 and then Freeze_Node (Entity (Op_Body)) = Op_Body
8633 then
8634 Set_Freeze_Node (Entity (Op_Body), New_Op_Body);
8635 end if;
8637 Insert_After (Current_Node, New_Op_Body);
8638 Current_Node := New_Op_Body;
8639 Analyze (New_Op_Body);
8641 when N_Pragma =>
8642 New_Op_Body := New_Copy (Op_Body);
8643 Insert_After (Current_Node, New_Op_Body);
8644 Current_Node := New_Op_Body;
8645 Analyze (New_Op_Body);
8647 when N_Object_Declaration =>
8648 pragma Assert (not Comes_From_Source (Op_Body));
8649 New_Op_Body := New_Copy (Op_Body);
8650 Insert_After (Current_Node, New_Op_Body);
8651 Current_Node := New_Op_Body;
8652 Analyze (New_Op_Body);
8654 when others =>
8655 raise Program_Error;
8656 end case;
8658 Next (Op_Body);
8659 end loop;
8661 -- Finally, create the body of the function that maps an entry index
8662 -- into the corresponding body index, except when there is no entry, or
8663 -- in a Ravenscar-like profile.
8665 if Corresponding_Runtime_Package (Pid) =
8666 System_Tasking_Protected_Objects_Entries
8667 then
8668 New_Op_Body := Build_Find_Body_Index (Pid);
8669 Insert_After (Current_Node, New_Op_Body);
8670 Current_Node := New_Op_Body;
8671 Analyze (New_Op_Body);
8672 end if;
8674 -- Ada 2005 (AI-345): Construct the primitive wrapper bodies after the
8675 -- protected body. At this point all wrapper specs have been created,
8676 -- frozen and included in the dispatch table for the protected type.
8678 if Ada_Version >= Ada_2005 then
8679 Build_Wrapper_Bodies (Loc, Pid, Current_Node);
8680 end if;
8681 end Expand_N_Protected_Body;
8683 -----------------------------------------
8684 -- Expand_N_Protected_Type_Declaration --
8685 -----------------------------------------
8687 -- First we create a corresponding record type declaration used to
8688 -- represent values of this protected type.
8689 -- The general form of this type declaration is
8691 -- type poV (discriminants) is record
8692 -- _Object : aliased <kind>Protection
8693 -- [(<entry count> [, <handler count>])];
8694 -- [entry_family : array (bounds) of Void;]
8695 -- <private data fields>
8696 -- end record;
8698 -- The discriminants are present only if the corresponding protected type
8699 -- has discriminants, and they exactly mirror the protected type
8700 -- discriminants. The private data fields similarly mirror the private
8701 -- declarations of the protected type.
8703 -- The Object field is always present. It contains RTS specific data used
8704 -- to control the protected object. It is declared as Aliased so that it
8705 -- can be passed as a pointer to the RTS. This allows the protected record
8706 -- to be referenced within RTS data structures. An appropriate Protection
8707 -- type and discriminant are generated.
8709 -- The Service field is present for protected objects with entries. It
8710 -- contains sufficient information to allow the entry service procedure for
8711 -- this object to be called when the object is not known till runtime.
8713 -- One entry_family component is present for each entry family in the
8714 -- task definition (see Expand_N_Task_Type_Declaration).
8716 -- When a protected object is declared, an instance of the protected type
8717 -- value record is created. The elaboration of this declaration creates the
8718 -- correct bounds for the entry families, and also evaluates the priority
8719 -- expression if needed. The initialization routine for the protected type
8720 -- itself then calls Initialize_Protection with appropriate parameters to
8721 -- initialize the value of the Task_Id field. Install_Handlers may be also
8722 -- called if a pragma Attach_Handler applies.
8724 -- Note: this record is passed to the subprograms created by the expansion
8725 -- of protected subprograms and entries. It is an in parameter to protected
8726 -- functions and an in out parameter to procedures and entry bodies. The
8727 -- Entity_Id for this created record type is placed in the
8728 -- Corresponding_Record_Type field of the associated protected type entity.
8730 -- Next we create a procedure specifications for protected subprograms and
8731 -- entry bodies. For each protected subprograms two subprograms are
8732 -- created, an unprotected and a protected version. The unprotected version
8733 -- is called from within other operations of the same protected object.
8735 -- We also build the call to register the procedure if a pragma
8736 -- Interrupt_Handler applies.
8738 -- A single subprogram is created to service all entry bodies; it has an
8739 -- additional boolean out parameter indicating that the previous entry call
8740 -- made by the current task was serviced immediately, i.e. not by proxy.
8741 -- The O parameter contains a pointer to a record object of the type
8742 -- described above. An untyped interface is used here to allow this
8743 -- procedure to be called in places where the type of the object to be
8744 -- serviced is not known. This must be done, for example, when a call that
8745 -- may have been requeued is cancelled; the corresponding object must be
8746 -- serviced, but which object that is not known till runtime.
8748 -- procedure ptypeS
8749 -- (O : System.Address; P : out Boolean);
8750 -- procedure pprocN (_object : in out poV);
8751 -- procedure pproc (_object : in out poV);
8752 -- function pfuncN (_object : poV);
8753 -- function pfunc (_object : poV);
8754 -- ...
8756 -- Note that this must come after the record type declaration, since
8757 -- the specs refer to this type.
8759 procedure Expand_N_Protected_Type_Declaration (N : Node_Id) is
8760 Discr_Map : constant Elist_Id := New_Elmt_List;
8761 Loc : constant Source_Ptr := Sloc (N);
8762 Prot_Typ : constant Entity_Id := Defining_Identifier (N);
8764 Lock_Free_Active : constant Boolean := Uses_Lock_Free (Prot_Typ);
8765 -- This flag indicates whether the lock free implementation is active
8767 Pdef : constant Node_Id := Protected_Definition (N);
8768 -- This contains two lists; one for visible and one for private decls
8770 Current_Node : Node_Id := N;
8771 E_Count : Int;
8772 Entries_Aggr : Node_Id;
8773 Rec_Decl : Node_Id;
8774 Rec_Id : Entity_Id;
8776 procedure Check_Inlining (Subp : Entity_Id);
8777 -- If the original operation has a pragma Inline, propagate the flag
8778 -- to the internal body, for possible inlining later on. The source
8779 -- operation is invisible to the back-end and is never actually called.
8781 procedure Expand_Entry_Declaration (Decl : Node_Id);
8782 -- Create the entry barrier and the procedure body for entry declaration
8783 -- Decl. All generated subprograms are added to Entry_Bodies_Array.
8785 function Static_Component_Size (Comp : Entity_Id) return Boolean;
8786 -- When compiling under the Ravenscar profile, private components must
8787 -- have a static size, or else a protected object will require heap
8788 -- allocation, violating the corresponding restriction. It is preferable
8789 -- to make this check here, because it provides a better error message
8790 -- than the back-end, which refers to the object as a whole.
8792 procedure Register_Handler;
8793 -- For a protected operation that is an interrupt handler, add the
8794 -- freeze action that will register it as such.
8796 procedure Replace_Access_Definition (Comp : Node_Id);
8797 -- If a private component of the type is an access to itself, this
8798 -- is not a reference to the current instance, but an access type out
8799 -- of which one might construct a list. If such a component exists, we
8800 -- create an incomplete type for the equivalent record type, and
8801 -- a named access type for it, that replaces the access definition
8802 -- of the original component. This is similar to what is done for
8803 -- records in Check_Anonymous_Access_Components, but simpler, because
8804 -- the corresponding record type has no previous declaration.
8805 -- This needs to be done only once, even if there are several such
8806 -- access components. The following entity stores the constructed
8807 -- access type.
8809 Acc_T : Entity_Id := Empty;
8811 --------------------
8812 -- Check_Inlining --
8813 --------------------
8815 procedure Check_Inlining (Subp : Entity_Id) is
8816 begin
8817 if Is_Inlined (Subp) then
8818 Set_Is_Inlined (Protected_Body_Subprogram (Subp));
8819 Set_Is_Inlined (Subp, False);
8820 end if;
8822 if Has_Pragma_No_Inline (Subp) then
8823 Set_Has_Pragma_No_Inline (Protected_Body_Subprogram (Subp));
8824 end if;
8825 end Check_Inlining;
8827 ---------------------------
8828 -- Static_Component_Size --
8829 ---------------------------
8831 function Static_Component_Size (Comp : Entity_Id) return Boolean is
8832 Typ : constant Entity_Id := Etype (Comp);
8833 C : Entity_Id;
8835 begin
8836 if Is_Scalar_Type (Typ) then
8837 return True;
8839 elsif Is_Array_Type (Typ) then
8840 return Compile_Time_Known_Bounds (Typ);
8842 elsif Is_Record_Type (Typ) then
8843 C := First_Component (Typ);
8844 while Present (C) loop
8845 if not Static_Component_Size (C) then
8846 return False;
8847 end if;
8849 Next_Component (C);
8850 end loop;
8852 return True;
8854 -- Any other type will be checked by the back-end
8856 else
8857 return True;
8858 end if;
8859 end Static_Component_Size;
8861 ------------------------------
8862 -- Expand_Entry_Declaration --
8863 ------------------------------
8865 procedure Expand_Entry_Declaration (Decl : Node_Id) is
8866 Ent_Id : constant Entity_Id := Defining_Entity (Decl);
8867 Bar_Id : Entity_Id;
8868 Bod_Id : Entity_Id;
8869 Subp : Node_Id;
8871 begin
8872 E_Count := E_Count + 1;
8874 -- Create the protected body subprogram
8876 Bod_Id :=
8877 Make_Defining_Identifier (Loc,
8878 Chars => Build_Selected_Name (Prot_Typ, Ent_Id, 'E'));
8879 Set_Protected_Body_Subprogram (Ent_Id, Bod_Id);
8881 Subp :=
8882 Make_Subprogram_Declaration (Loc,
8883 Specification =>
8884 Build_Protected_Entry_Specification (Loc, Bod_Id, Ent_Id));
8886 Insert_After (Current_Node, Subp);
8887 Current_Node := Subp;
8889 Analyze (Subp);
8891 -- Build a wrapper procedure to handle contract cases, preconditions,
8892 -- and postconditions.
8894 Build_Entry_Contract_Wrapper (Ent_Id, N);
8896 -- Create the barrier function
8898 Bar_Id :=
8899 Make_Defining_Identifier (Loc,
8900 Chars => Build_Selected_Name (Prot_Typ, Ent_Id, 'B'));
8901 Set_Barrier_Function (Ent_Id, Bar_Id);
8903 Subp :=
8904 Make_Subprogram_Declaration (Loc,
8905 Specification =>
8906 Build_Barrier_Function_Specification (Loc, Bar_Id));
8907 Set_Is_Entry_Barrier_Function (Subp);
8909 Insert_After (Current_Node, Subp);
8910 Current_Node := Subp;
8912 Analyze (Subp);
8914 Set_Protected_Body_Subprogram (Bar_Id, Bar_Id);
8915 Set_Scope (Bar_Id, Scope (Ent_Id));
8917 -- Collect pointers to the protected subprogram and the barrier
8918 -- of the current entry, for insertion into Entry_Bodies_Array.
8920 Append_To (Expressions (Entries_Aggr),
8921 Make_Aggregate (Loc,
8922 Expressions => New_List (
8923 Make_Attribute_Reference (Loc,
8924 Prefix => New_Occurrence_Of (Bar_Id, Loc),
8925 Attribute_Name => Name_Unrestricted_Access),
8926 Make_Attribute_Reference (Loc,
8927 Prefix => New_Occurrence_Of (Bod_Id, Loc),
8928 Attribute_Name => Name_Unrestricted_Access))));
8929 end Expand_Entry_Declaration;
8931 ----------------------
8932 -- Register_Handler --
8933 ----------------------
8935 procedure Register_Handler is
8937 -- All semantic checks already done in Sem_Prag
8939 Prot_Proc : constant Entity_Id :=
8940 Defining_Unit_Name (Specification (Current_Node));
8942 Proc_Address : constant Node_Id :=
8943 Make_Attribute_Reference (Loc,
8944 Prefix =>
8945 New_Occurrence_Of (Prot_Proc, Loc),
8946 Attribute_Name => Name_Address);
8948 RTS_Call : constant Entity_Id :=
8949 Make_Procedure_Call_Statement (Loc,
8950 Name =>
8951 New_Occurrence_Of
8952 (RTE (RE_Register_Interrupt_Handler), Loc),
8953 Parameter_Associations => New_List (Proc_Address));
8954 begin
8955 Append_Freeze_Action (Prot_Proc, RTS_Call);
8956 end Register_Handler;
8958 -------------------------------
8959 -- Replace_Access_Definition --
8960 -------------------------------
8962 procedure Replace_Access_Definition (Comp : Node_Id) is
8963 Loc : constant Source_Ptr := Sloc (Comp);
8964 Inc_T : Node_Id;
8965 Inc_D : Node_Id;
8966 Acc_Def : Node_Id;
8967 Acc_D : Node_Id;
8969 begin
8970 if No (Acc_T) then
8971 Inc_T := Make_Defining_Identifier (Loc, Chars (Rec_Id));
8972 Inc_D := Make_Incomplete_Type_Declaration (Loc, Inc_T);
8973 Acc_T := Make_Temporary (Loc, 'S');
8974 Acc_Def :=
8975 Make_Access_To_Object_Definition (Loc,
8976 Subtype_Indication => New_Occurrence_Of (Inc_T, Loc));
8977 Acc_D :=
8978 Make_Full_Type_Declaration (Loc,
8979 Defining_Identifier => Acc_T,
8980 Type_Definition => Acc_Def);
8982 Insert_Before (Rec_Decl, Inc_D);
8983 Analyze (Inc_D);
8985 Insert_Before (Rec_Decl, Acc_D);
8986 Analyze (Acc_D);
8987 end if;
8989 Set_Access_Definition (Comp, Empty);
8990 Set_Subtype_Indication (Comp, New_Occurrence_Of (Acc_T, Loc));
8991 end Replace_Access_Definition;
8993 -- Local variables
8995 Body_Arr : Node_Id;
8996 Body_Id : Entity_Id;
8997 Cdecls : List_Id;
8998 Comp : Node_Id;
8999 Expr : Node_Id;
9000 New_Priv : Node_Id;
9001 Obj_Def : Node_Id;
9002 Object_Comp : Node_Id;
9003 Priv : Node_Id;
9004 Sub : Node_Id;
9006 -- Start of processing for Expand_N_Protected_Type_Declaration
9008 begin
9009 if Present (Corresponding_Record_Type (Prot_Typ)) then
9010 return;
9011 else
9012 Rec_Decl := Build_Corresponding_Record (N, Prot_Typ, Loc);
9013 Rec_Id := Defining_Identifier (Rec_Decl);
9014 end if;
9016 Cdecls := Component_Items (Component_List (Type_Definition (Rec_Decl)));
9018 Qualify_Entity_Names (N);
9020 -- If the type has discriminants, their occurrences in the declaration
9021 -- have been replaced by the corresponding discriminals. For components
9022 -- that are constrained by discriminants, their homologues in the
9023 -- corresponding record type must refer to the discriminants of that
9024 -- record, so we must apply a new renaming to subtypes_indications:
9026 -- protected discriminant => discriminal => record discriminant
9028 -- This replacement is not applied to default expressions, for which
9029 -- the discriminal is correct.
9031 if Has_Discriminants (Prot_Typ) then
9032 declare
9033 Disc : Entity_Id;
9034 Decl : Node_Id;
9036 begin
9037 Disc := First_Discriminant (Prot_Typ);
9038 Decl := First (Discriminant_Specifications (Rec_Decl));
9039 while Present (Disc) loop
9040 Append_Elmt (Discriminal (Disc), Discr_Map);
9041 Append_Elmt (Defining_Identifier (Decl), Discr_Map);
9042 Next_Discriminant (Disc);
9043 Next (Decl);
9044 end loop;
9045 end;
9046 end if;
9048 -- Fill in the component declarations
9050 -- Add components for entry families. For each entry family, create an
9051 -- anonymous type declaration with the same size, and analyze the type.
9053 Collect_Entry_Families (Loc, Cdecls, Current_Node, Prot_Typ);
9055 pragma Assert (Present (Pdef));
9057 Insert_After (Current_Node, Rec_Decl);
9058 Current_Node := Rec_Decl;
9060 -- Add private field components
9062 Priv := First (Private_Declarations (Pdef));
9063 while Present (Priv) loop
9064 if Nkind (Priv) = N_Component_Declaration then
9065 if not Static_Component_Size (Defining_Identifier (Priv)) then
9067 -- When compiling for a restricted profile, the private
9068 -- components must have a static size. If not, this is an error
9069 -- for a single protected declaration, and rates a warning on a
9070 -- protected type declaration.
9072 if not Comes_From_Source (Prot_Typ) then
9074 -- It's ok to be checking this restriction at expansion
9075 -- time, because this is only for the restricted profile,
9076 -- which is not subject to strict RM conformance, so it
9077 -- is OK to miss this check in -gnatc mode.
9079 Check_Restriction (No_Implicit_Heap_Allocations, Priv);
9080 Check_Restriction
9081 (No_Implicit_Protected_Object_Allocations, Priv);
9083 elsif Restriction_Active (No_Implicit_Heap_Allocations) then
9084 if not Discriminated_Size (Defining_Identifier (Priv))
9085 then
9086 -- Any object of the type will be non-static
9088 Error_Msg_N ("component has non-static size??", Priv);
9089 Error_Msg_NE
9090 ("\creation of protected object of type& will "
9091 & "violate restriction "
9092 & "No_Implicit_Heap_Allocations??", Priv, Prot_Typ);
9093 else
9094 -- Object will be non-static if discriminants are
9096 Error_Msg_NE
9097 ("creation of protected object of type& with "
9098 & "non-static discriminants will violate "
9099 & "restriction No_Implicit_Heap_Allocations??",
9100 Priv, Prot_Typ);
9101 end if;
9103 -- Likewise for No_Implicit_Protected_Object_Allocations
9105 elsif Restriction_Active
9106 (No_Implicit_Protected_Object_Allocations)
9107 then
9108 if not Discriminated_Size (Defining_Identifier (Priv)) then
9109 -- Any object of the type will be non-static
9111 Error_Msg_N ("component has non-static size??", Priv);
9112 Error_Msg_NE
9113 ("\creation of protected object of type& will violate "
9114 & "restriction "
9115 & "No_Implicit_Protected_Object_Allocations??",
9116 Priv, Prot_Typ);
9117 else
9118 -- Object will be non-static if discriminants are
9120 Error_Msg_NE
9121 ("creation of protected object of type& with "
9122 & "non-static discriminants will violate restriction "
9123 & "No_Implicit_Protected_Object_Allocations??",
9124 Priv, Prot_Typ);
9125 end if;
9126 end if;
9127 end if;
9129 -- The component definition consists of a subtype indication, or
9130 -- (in Ada 2005) an access definition. Make a copy of the proper
9131 -- definition.
9133 declare
9134 Old_Comp : constant Node_Id := Component_Definition (Priv);
9135 Oent : constant Entity_Id := Defining_Identifier (Priv);
9136 Nent : constant Entity_Id :=
9137 Make_Defining_Identifier (Sloc (Oent),
9138 Chars => Chars (Oent));
9139 New_Comp : Node_Id;
9141 begin
9142 if Present (Subtype_Indication (Old_Comp)) then
9143 New_Comp :=
9144 Make_Component_Definition (Sloc (Oent),
9145 Aliased_Present => False,
9146 Subtype_Indication =>
9147 New_Copy_Tree
9148 (Subtype_Indication (Old_Comp), Discr_Map));
9149 else
9150 New_Comp :=
9151 Make_Component_Definition (Sloc (Oent),
9152 Aliased_Present => False,
9153 Access_Definition =>
9154 New_Copy_Tree
9155 (Access_Definition (Old_Comp), Discr_Map));
9157 -- A self-reference in the private part becomes a
9158 -- self-reference to the corresponding record.
9160 if Entity (Subtype_Mark (Access_Definition (New_Comp)))
9161 = Prot_Typ
9162 then
9163 Replace_Access_Definition (New_Comp);
9164 end if;
9165 end if;
9167 New_Priv :=
9168 Make_Component_Declaration (Loc,
9169 Defining_Identifier => Nent,
9170 Component_Definition => New_Comp,
9171 Expression => Expression (Priv));
9173 Set_Has_Per_Object_Constraint (Nent,
9174 Has_Per_Object_Constraint (Oent));
9176 Append_To (Cdecls, New_Priv);
9177 end;
9179 elsif Nkind (Priv) = N_Subprogram_Declaration then
9181 -- Make the unprotected version of the subprogram available for
9182 -- expansion of intra object calls. There is need for a protected
9183 -- version only if the subprogram is an interrupt handler,
9184 -- otherwise this operation can only be called from within the
9185 -- body.
9187 Sub :=
9188 Make_Subprogram_Declaration (Loc,
9189 Specification =>
9190 Build_Protected_Sub_Specification
9191 (Priv, Prot_Typ, Unprotected_Mode));
9193 Insert_After (Current_Node, Sub);
9194 Analyze (Sub);
9196 Set_Protected_Body_Subprogram
9197 (Defining_Unit_Name (Specification (Priv)),
9198 Defining_Unit_Name (Specification (Sub)));
9199 Check_Inlining (Defining_Unit_Name (Specification (Priv)));
9200 Current_Node := Sub;
9202 Sub :=
9203 Make_Subprogram_Declaration (Loc,
9204 Specification =>
9205 Build_Protected_Sub_Specification
9206 (Priv, Prot_Typ, Protected_Mode));
9208 Insert_After (Current_Node, Sub);
9209 Analyze (Sub);
9210 Current_Node := Sub;
9212 if Is_Interrupt_Handler
9213 (Defining_Unit_Name (Specification (Priv)))
9214 then
9215 if not Restricted_Profile then
9216 Register_Handler;
9217 end if;
9218 end if;
9219 end if;
9221 Next (Priv);
9222 end loop;
9224 -- Except for the lock-free implementation, append the _Object field
9225 -- with the right type to the component list. We need to compute the
9226 -- number of entries, and in some cases the number of Attach_Handler
9227 -- pragmas.
9229 if not Lock_Free_Active then
9230 declare
9231 Entry_Count_Expr : constant Node_Id :=
9232 Build_Entry_Count_Expression
9233 (Prot_Typ, Loc);
9234 Num_Attach_Handler : Nat := 0;
9235 Protection_Subtype : Node_Id;
9236 Ritem : Node_Id;
9238 begin
9239 if Has_Attach_Handler (Prot_Typ) then
9240 Ritem := First_Rep_Item (Prot_Typ);
9241 while Present (Ritem) loop
9242 if Nkind (Ritem) = N_Pragma
9243 and then Pragma_Name (Ritem) = Name_Attach_Handler
9244 then
9245 Num_Attach_Handler := Num_Attach_Handler + 1;
9246 end if;
9248 Next_Rep_Item (Ritem);
9249 end loop;
9250 end if;
9252 -- Determine the proper protection type. There are two special
9253 -- cases: 1) when the protected type has dynamic interrupt
9254 -- handlers, and 2) when it has static handlers and we use a
9255 -- restricted profile.
9257 if Has_Attach_Handler (Prot_Typ)
9258 and then not Restricted_Profile
9259 then
9260 Protection_Subtype :=
9261 Make_Subtype_Indication (Loc,
9262 Subtype_Mark =>
9263 New_Occurrence_Of
9264 (RTE (RE_Static_Interrupt_Protection), Loc),
9265 Constraint =>
9266 Make_Index_Or_Discriminant_Constraint (Loc,
9267 Constraints => New_List (
9268 Entry_Count_Expr,
9269 Make_Integer_Literal (Loc, Num_Attach_Handler))));
9271 elsif Has_Interrupt_Handler (Prot_Typ)
9272 and then not Restriction_Active (No_Dynamic_Attachment)
9273 then
9274 Protection_Subtype :=
9275 Make_Subtype_Indication (Loc,
9276 Subtype_Mark =>
9277 New_Occurrence_Of
9278 (RTE (RE_Dynamic_Interrupt_Protection), Loc),
9279 Constraint =>
9280 Make_Index_Or_Discriminant_Constraint (Loc,
9281 Constraints => New_List (Entry_Count_Expr)));
9283 else
9284 case Corresponding_Runtime_Package (Prot_Typ) is
9285 when System_Tasking_Protected_Objects_Entries =>
9286 Protection_Subtype :=
9287 Make_Subtype_Indication (Loc,
9288 Subtype_Mark =>
9289 New_Occurrence_Of
9290 (RTE (RE_Protection_Entries), Loc),
9291 Constraint =>
9292 Make_Index_Or_Discriminant_Constraint (Loc,
9293 Constraints => New_List (Entry_Count_Expr)));
9295 when System_Tasking_Protected_Objects_Single_Entry =>
9296 Protection_Subtype :=
9297 New_Occurrence_Of (RTE (RE_Protection_Entry), Loc);
9299 when System_Tasking_Protected_Objects =>
9300 Protection_Subtype :=
9301 New_Occurrence_Of (RTE (RE_Protection), Loc);
9303 when others =>
9304 raise Program_Error;
9305 end case;
9306 end if;
9308 Object_Comp :=
9309 Make_Component_Declaration (Loc,
9310 Defining_Identifier =>
9311 Make_Defining_Identifier (Loc, Name_uObject),
9312 Component_Definition =>
9313 Make_Component_Definition (Loc,
9314 Aliased_Present => True,
9315 Subtype_Indication => Protection_Subtype));
9316 end;
9318 -- Put the _Object component after the private component so that it
9319 -- be finalized early as required by 9.4 (20)
9321 Append_To (Cdecls, Object_Comp);
9322 end if;
9324 -- Analyze the record declaration immediately after construction,
9325 -- because the initialization procedure is needed for single object
9326 -- declarations before the next entity is analyzed (the freeze call
9327 -- that generates this initialization procedure is found below).
9329 Analyze (Rec_Decl, Suppress => All_Checks);
9331 -- Ada 2005 (AI-345): Construct the primitive entry wrappers before
9332 -- the corresponding record is frozen. If any wrappers are generated,
9333 -- Current_Node is updated accordingly.
9335 if Ada_Version >= Ada_2005 then
9336 Build_Wrapper_Specs (Loc, Prot_Typ, Current_Node);
9337 end if;
9339 -- Collect pointers to entry bodies and their barriers, to be placed
9340 -- in the Entry_Bodies_Array for the type. For each entry/family we
9341 -- add an expression to the aggregate which is the initial value of
9342 -- this array. The array is declared after all protected subprograms.
9344 if Has_Entries (Prot_Typ) then
9345 Entries_Aggr := Make_Aggregate (Loc, Expressions => New_List);
9346 else
9347 Entries_Aggr := Empty;
9348 end if;
9350 -- Build two new procedure specifications for each protected subprogram;
9351 -- one to call from outside the object and one to call from inside.
9352 -- Build a barrier function and an entry body action procedure
9353 -- specification for each protected entry. Initialize the entry body
9354 -- array. If subprogram is flagged as eliminated, do not generate any
9355 -- internal operations.
9357 E_Count := 0;
9358 Comp := First (Visible_Declarations (Pdef));
9359 while Present (Comp) loop
9360 if Nkind (Comp) = N_Subprogram_Declaration then
9361 Sub :=
9362 Make_Subprogram_Declaration (Loc,
9363 Specification =>
9364 Build_Protected_Sub_Specification
9365 (Comp, Prot_Typ, Unprotected_Mode));
9367 Insert_After (Current_Node, Sub);
9368 Analyze (Sub);
9370 Set_Protected_Body_Subprogram
9371 (Defining_Unit_Name (Specification (Comp)),
9372 Defining_Unit_Name (Specification (Sub)));
9373 Check_Inlining (Defining_Unit_Name (Specification (Comp)));
9375 -- Make the protected version of the subprogram available for
9376 -- expansion of external calls.
9378 Current_Node := Sub;
9380 Sub :=
9381 Make_Subprogram_Declaration (Loc,
9382 Specification =>
9383 Build_Protected_Sub_Specification
9384 (Comp, Prot_Typ, Protected_Mode));
9386 Insert_After (Current_Node, Sub);
9387 Analyze (Sub);
9389 Current_Node := Sub;
9391 -- Generate an overriding primitive operation specification for
9392 -- this subprogram if the protected type implements an interface
9393 -- and Build_Wrapper_Spec did not generate its wrapper.
9395 if Ada_Version >= Ada_2005
9396 and then
9397 Present (Interfaces (Corresponding_Record_Type (Prot_Typ)))
9398 then
9399 declare
9400 Found : Boolean := False;
9401 Prim_Elmt : Elmt_Id;
9402 Prim_Op : Node_Id;
9404 begin
9405 Prim_Elmt :=
9406 First_Elmt
9407 (Primitive_Operations
9408 (Corresponding_Record_Type (Prot_Typ)));
9410 while Present (Prim_Elmt) loop
9411 Prim_Op := Node (Prim_Elmt);
9413 if Is_Primitive_Wrapper (Prim_Op)
9414 and then Wrapped_Entity (Prim_Op) =
9415 Defining_Entity (Specification (Comp))
9416 then
9417 Found := True;
9418 exit;
9419 end if;
9421 Next_Elmt (Prim_Elmt);
9422 end loop;
9424 if not Found then
9425 Sub :=
9426 Make_Subprogram_Declaration (Loc,
9427 Specification =>
9428 Build_Protected_Sub_Specification
9429 (Comp, Prot_Typ, Dispatching_Mode));
9431 Insert_After (Current_Node, Sub);
9432 Analyze (Sub);
9434 Current_Node := Sub;
9435 end if;
9436 end;
9437 end if;
9439 -- If a pragma Interrupt_Handler applies, build and add a call to
9440 -- Register_Interrupt_Handler to the freezing actions of the
9441 -- protected version (Current_Node) of the subprogram:
9443 -- system.interrupts.register_interrupt_handler
9444 -- (prot_procP'address);
9446 if not Restricted_Profile
9447 and then Is_Interrupt_Handler
9448 (Defining_Unit_Name (Specification (Comp)))
9449 then
9450 Register_Handler;
9451 end if;
9453 elsif Nkind (Comp) = N_Entry_Declaration then
9454 Expand_Entry_Declaration (Comp);
9455 end if;
9457 Next (Comp);
9458 end loop;
9460 -- If there are some private entry declarations, expand it as if they
9461 -- were visible entries.
9463 Comp := First (Private_Declarations (Pdef));
9464 while Present (Comp) loop
9465 if Nkind (Comp) = N_Entry_Declaration then
9466 Expand_Entry_Declaration (Comp);
9467 end if;
9469 Next (Comp);
9470 end loop;
9472 -- Create the declaration of an array object which contains the values
9473 -- of aspect/pragma Max_Queue_Length for all entries of the protected
9474 -- type. This object is later passed to the appropriate protected object
9475 -- initialization routine.
9477 if Has_Entries (Prot_Typ)
9478 and then Corresponding_Runtime_Package (Prot_Typ) =
9479 System_Tasking_Protected_Objects_Entries
9480 then
9481 declare
9482 Count : Int;
9483 Item : Entity_Id;
9484 Max_Vals : Node_Id;
9485 Maxes : List_Id;
9486 Maxes_Id : Entity_Id;
9487 Need_Array : Boolean := False;
9489 begin
9490 -- First check if there is any Max_Queue_Length pragma
9492 Item := First_Entity (Prot_Typ);
9493 while Present (Item) loop
9494 if Is_Entry (Item) and then Has_Max_Queue_Length (Item) then
9495 Need_Array := True;
9496 exit;
9497 end if;
9499 Next_Entity (Item);
9500 end loop;
9502 -- Gather the Max_Queue_Length values of all entries in a list. A
9503 -- value of zero indicates that the entry has no limitation on its
9504 -- queue length.
9506 if Need_Array then
9507 Count := 0;
9508 Item := First_Entity (Prot_Typ);
9509 Maxes := New_List;
9510 while Present (Item) loop
9511 if Is_Entry (Item) then
9512 Count := Count + 1;
9513 Append_To (Maxes,
9514 Make_Integer_Literal
9515 (Loc, Get_Max_Queue_Length (Item)));
9516 end if;
9518 Next_Entity (Item);
9519 end loop;
9521 -- Create the declaration of the array object. Generate:
9523 -- Maxes_Id : aliased constant
9524 -- Protected_Entry_Queue_Max_Array
9525 -- (1 .. Count) := (..., ...);
9527 Maxes_Id :=
9528 Make_Defining_Identifier (Loc,
9529 Chars => New_External_Name (Chars (Prot_Typ), 'B'));
9531 Max_Vals :=
9532 Make_Object_Declaration (Loc,
9533 Defining_Identifier => Maxes_Id,
9534 Aliased_Present => True,
9535 Constant_Present => True,
9536 Object_Definition =>
9537 Make_Subtype_Indication (Loc,
9538 Subtype_Mark =>
9539 New_Occurrence_Of
9540 (RTE (RE_Protected_Entry_Queue_Max_Array), Loc),
9541 Constraint =>
9542 Make_Index_Or_Discriminant_Constraint (Loc,
9543 Constraints => New_List (
9544 Make_Range (Loc,
9545 Make_Integer_Literal (Loc, 1),
9546 Make_Integer_Literal (Loc, Count))))),
9547 Expression => Make_Aggregate (Loc, Maxes));
9549 -- A pointer to this array will be placed in the corresponding
9550 -- record by its initialization procedure so this needs to be
9551 -- analyzed here.
9553 Insert_After (Current_Node, Max_Vals);
9554 Current_Node := Max_Vals;
9555 Analyze (Max_Vals);
9557 Set_Entry_Max_Queue_Lengths_Array (Prot_Typ, Maxes_Id);
9558 end if;
9559 end;
9560 end if;
9562 -- Emit declaration for Entry_Bodies_Array, now that the addresses of
9563 -- all protected subprograms have been collected.
9565 if Has_Entries (Prot_Typ) then
9566 Body_Id :=
9567 Make_Defining_Identifier (Sloc (Prot_Typ),
9568 Chars => New_External_Name (Chars (Prot_Typ), 'A'));
9570 case Corresponding_Runtime_Package (Prot_Typ) is
9571 when System_Tasking_Protected_Objects_Entries =>
9572 Expr := Entries_Aggr;
9573 Obj_Def :=
9574 Make_Subtype_Indication (Loc,
9575 Subtype_Mark =>
9576 New_Occurrence_Of
9577 (RTE (RE_Protected_Entry_Body_Array), Loc),
9578 Constraint =>
9579 Make_Index_Or_Discriminant_Constraint (Loc,
9580 Constraints => New_List (
9581 Make_Range (Loc,
9582 Make_Integer_Literal (Loc, 1),
9583 Make_Integer_Literal (Loc, E_Count)))));
9585 when System_Tasking_Protected_Objects_Single_Entry =>
9586 Expr := Remove_Head (Expressions (Entries_Aggr));
9587 Obj_Def := New_Occurrence_Of (RTE (RE_Entry_Body), Loc);
9589 when others =>
9590 raise Program_Error;
9591 end case;
9593 Body_Arr :=
9594 Make_Object_Declaration (Loc,
9595 Defining_Identifier => Body_Id,
9596 Aliased_Present => True,
9597 Constant_Present => True,
9598 Object_Definition => Obj_Def,
9599 Expression => Expr);
9601 -- A pointer to this array will be placed in the corresponding record
9602 -- by its initialization procedure so this needs to be analyzed here.
9604 Insert_After (Current_Node, Body_Arr);
9605 Current_Node := Body_Arr;
9606 Analyze (Body_Arr);
9608 Set_Entry_Bodies_Array (Prot_Typ, Body_Id);
9610 -- Finally, build the function that maps an entry index into the
9611 -- corresponding body. A pointer to this function is placed in each
9612 -- object of the type. Except for a ravenscar-like profile (no abort,
9613 -- no entry queue, 1 entry)
9615 if Corresponding_Runtime_Package (Prot_Typ) =
9616 System_Tasking_Protected_Objects_Entries
9617 then
9618 Sub :=
9619 Make_Subprogram_Declaration (Loc,
9620 Specification => Build_Find_Body_Index_Spec (Prot_Typ));
9622 Insert_After (Current_Node, Sub);
9623 Analyze (Sub);
9624 end if;
9625 end if;
9626 end Expand_N_Protected_Type_Declaration;
9628 --------------------------------
9629 -- Expand_N_Requeue_Statement --
9630 --------------------------------
9632 -- A nondispatching requeue statement is expanded into one of four GNARLI
9633 -- operations, depending on the source and destination (task or protected
9634 -- object). A dispatching requeue statement is expanded into a call to the
9635 -- predefined primitive _Disp_Requeue. In addition, code is generated to
9636 -- jump around the remainder of processing for the original entry and, if
9637 -- the destination is (different) protected object, to attempt to service
9638 -- it. The following illustrates the various cases:
9640 -- procedure entE
9641 -- (O : System.Address;
9642 -- P : System.Address;
9643 -- E : Protected_Entry_Index)
9644 -- is
9645 -- <discriminant renamings>
9646 -- <private object renamings>
9647 -- type poVP is access poV;
9648 -- _object : ptVP := ptVP!(O);
9650 -- begin
9651 -- begin
9652 -- <start of statement sequence for entry>
9654 -- -- Requeue from one protected entry body to another protected
9655 -- -- entry.
9657 -- Requeue_Protected_Entry (
9658 -- _object._object'Access,
9659 -- new._object'Access,
9660 -- E,
9661 -- Abort_Present);
9662 -- return;
9664 -- <some more of the statement sequence for entry>
9666 -- -- Requeue from an entry body to a task entry
9668 -- Requeue_Protected_To_Task_Entry (
9669 -- New._task_id,
9670 -- E,
9671 -- Abort_Present);
9672 -- return;
9674 -- <rest of statement sequence for entry>
9675 -- Complete_Entry_Body (_object._object);
9677 -- exception
9678 -- when all others =>
9679 -- Exceptional_Complete_Entry_Body (
9680 -- _object._object, Get_GNAT_Exception);
9681 -- end;
9682 -- end entE;
9684 -- Requeue of a task entry call to a task entry
9686 -- Accept_Call (E, Ann);
9687 -- <start of statement sequence for accept statement>
9688 -- Requeue_Task_Entry (New._task_id, E, Abort_Present);
9689 -- goto Lnn;
9690 -- <rest of statement sequence for accept statement>
9691 -- <<Lnn>>
9692 -- Complete_Rendezvous;
9694 -- exception
9695 -- when all others =>
9696 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
9698 -- Requeue of a task entry call to a protected entry
9700 -- Accept_Call (E, Ann);
9701 -- <start of statement sequence for accept statement>
9702 -- Requeue_Task_To_Protected_Entry (
9703 -- new._object'Access,
9704 -- E,
9705 -- Abort_Present);
9706 -- newS (new, Pnn);
9707 -- goto Lnn;
9708 -- <rest of statement sequence for accept statement>
9709 -- <<Lnn>>
9710 -- Complete_Rendezvous;
9712 -- exception
9713 -- when all others =>
9714 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
9716 -- Ada 2012 (AI05-0030): Dispatching requeue to an interface primitive
9717 -- marked by pragma Implemented (XXX, By_Entry).
9719 -- The requeue is inside a protected entry:
9721 -- procedure entE
9722 -- (O : System.Address;
9723 -- P : System.Address;
9724 -- E : Protected_Entry_Index)
9725 -- is
9726 -- <discriminant renamings>
9727 -- <private object renamings>
9728 -- type poVP is access poV;
9729 -- _object : ptVP := ptVP!(O);
9731 -- begin
9732 -- begin
9733 -- <start of statement sequence for entry>
9735 -- _Disp_Requeue
9736 -- (<interface class-wide object>,
9737 -- True,
9738 -- _object'Address,
9739 -- Ada.Tags.Get_Offset_Index
9740 -- (Tag (_object),
9741 -- <interface dispatch table index of target entry>),
9742 -- Abort_Present);
9743 -- return;
9745 -- <rest of statement sequence for entry>
9746 -- Complete_Entry_Body (_object._object);
9748 -- exception
9749 -- when all others =>
9750 -- Exceptional_Complete_Entry_Body (
9751 -- _object._object, Get_GNAT_Exception);
9752 -- end;
9753 -- end entE;
9755 -- The requeue is inside a task entry:
9757 -- Accept_Call (E, Ann);
9758 -- <start of statement sequence for accept statement>
9759 -- _Disp_Requeue
9760 -- (<interface class-wide object>,
9761 -- False,
9762 -- null,
9763 -- Ada.Tags.Get_Offset_Index
9764 -- (Tag (_object),
9765 -- <interface dispatch table index of target entrt>),
9766 -- Abort_Present);
9767 -- newS (new, Pnn);
9768 -- goto Lnn;
9769 -- <rest of statement sequence for accept statement>
9770 -- <<Lnn>>
9771 -- Complete_Rendezvous;
9773 -- exception
9774 -- when all others =>
9775 -- Exceptional_Complete_Rendezvous (Get_GNAT_Exception);
9777 -- Ada 2012 (AI05-0030): Dispatching requeue to an interface primitive
9778 -- marked by pragma Implemented (XXX, By_Protected_Procedure). The requeue
9779 -- statement is replaced by a dispatching call with actual parameters taken
9780 -- from the inner-most accept statement or entry body.
9782 -- Target.Primitive (Param1, ..., ParamN);
9784 -- Ada 2012 (AI05-0030): Dispatching requeue to an interface primitive
9785 -- marked by pragma Implemented (XXX, By_Any | Optional) or not marked
9786 -- at all.
9788 -- declare
9789 -- S : constant Offset_Index :=
9790 -- Get_Offset_Index (Tag (Concval), DT_Position (Ename));
9791 -- C : constant Prim_Op_Kind := Get_Prim_Op_Kind (Tag (Concval), S);
9793 -- begin
9794 -- if C = POK_Protected_Entry
9795 -- or else C = POK_Task_Entry
9796 -- then
9797 -- <statements for dispatching requeue>
9799 -- elsif C = POK_Protected_Procedure then
9800 -- <dispatching call equivalent>
9802 -- else
9803 -- raise Program_Error;
9804 -- end if;
9805 -- end;
9807 procedure Expand_N_Requeue_Statement (N : Node_Id) is
9808 Loc : constant Source_Ptr := Sloc (N);
9809 Conc_Typ : Entity_Id;
9810 Concval : Node_Id;
9811 Ename : Node_Id;
9812 Enc_Subp : Entity_Id;
9813 Index : Node_Id;
9814 Old_Typ : Entity_Id;
9816 function Build_Dispatching_Call_Equivalent return Node_Id;
9817 -- Ada 2012 (AI05-0030): N denotes a dispatching requeue statement of
9818 -- the form Concval.Ename. It is statically known that Ename is allowed
9819 -- to be implemented by a protected procedure. Create a dispatching call
9820 -- equivalent of Concval.Ename taking the actual parameters from the
9821 -- inner-most accept statement or entry body.
9823 function Build_Dispatching_Requeue return Node_Id;
9824 -- Ada 2012 (AI05-0030): N denotes a dispatching requeue statement of
9825 -- the form Concval.Ename. It is statically known that Ename is allowed
9826 -- to be implemented by a protected or a task entry. Create a call to
9827 -- primitive _Disp_Requeue which handles the low-level actions.
9829 function Build_Dispatching_Requeue_To_Any return Node_Id;
9830 -- Ada 2012 (AI05-0030): N denotes a dispatching requeue statement of
9831 -- the form Concval.Ename. Ename is either marked by pragma Implemented
9832 -- (XXX, By_Any | Optional) or not marked at all. Create a block which
9833 -- determines at runtime whether Ename denotes an entry or a procedure
9834 -- and perform the appropriate kind of dispatching select.
9836 function Build_Normal_Requeue return Node_Id;
9837 -- N denotes a nondispatching requeue statement to either a task or a
9838 -- protected entry. Build the appropriate runtime call to perform the
9839 -- action.
9841 function Build_Skip_Statement (Search : Node_Id) return Node_Id;
9842 -- For a protected entry, create a return statement to skip the rest of
9843 -- the entry body. Otherwise, create a goto statement to skip the rest
9844 -- of a task accept statement. The lookup for the enclosing entry body
9845 -- or accept statement starts from Search.
9847 ---------------------------------------
9848 -- Build_Dispatching_Call_Equivalent --
9849 ---------------------------------------
9851 function Build_Dispatching_Call_Equivalent return Node_Id is
9852 Call_Ent : constant Entity_Id := Entity (Ename);
9853 Obj : constant Node_Id := Original_Node (Concval);
9854 Acc_Ent : Node_Id;
9855 Actuals : List_Id;
9856 Formal : Node_Id;
9857 Formals : List_Id;
9859 begin
9860 -- Climb the parent chain looking for the inner-most entry body or
9861 -- accept statement.
9863 Acc_Ent := N;
9864 while Present (Acc_Ent)
9865 and then Nkind (Acc_Ent) not in N_Accept_Statement | N_Entry_Body
9866 loop
9867 Acc_Ent := Parent (Acc_Ent);
9868 end loop;
9870 -- A requeue statement should be housed inside an entry body or an
9871 -- accept statement at some level. If this is not the case, then the
9872 -- tree is malformed.
9874 pragma Assert (Present (Acc_Ent));
9876 -- Recover the list of formal parameters
9878 if Nkind (Acc_Ent) = N_Entry_Body then
9879 Acc_Ent := Entry_Body_Formal_Part (Acc_Ent);
9880 end if;
9882 Formals := Parameter_Specifications (Acc_Ent);
9884 -- Create the actual parameters for the dispatching call. These are
9885 -- simply copies of the entry body or accept statement formals in the
9886 -- same order as they appear.
9888 Actuals := No_List;
9890 if Present (Formals) then
9891 Actuals := New_List;
9892 Formal := First (Formals);
9893 while Present (Formal) loop
9894 Append_To (Actuals,
9895 Make_Identifier (Loc, Chars (Defining_Identifier (Formal))));
9896 Next (Formal);
9897 end loop;
9898 end if;
9900 -- Generate:
9901 -- Obj.Call_Ent (Actuals);
9903 return
9904 Make_Procedure_Call_Statement (Loc,
9905 Name =>
9906 Make_Selected_Component (Loc,
9907 Prefix => Make_Identifier (Loc, Chars (Obj)),
9908 Selector_Name => Make_Identifier (Loc, Chars (Call_Ent))),
9910 Parameter_Associations => Actuals);
9911 end Build_Dispatching_Call_Equivalent;
9913 -------------------------------
9914 -- Build_Dispatching_Requeue --
9915 -------------------------------
9917 function Build_Dispatching_Requeue return Node_Id is
9918 Params : constant List_Id := New_List;
9920 begin
9921 -- Process the "with abort" parameter
9923 Prepend_To (Params,
9924 New_Occurrence_Of (Boolean_Literals (Abort_Present (N)), Loc));
9926 -- Process the entry wrapper's position in the primary dispatch
9927 -- table parameter. Generate:
9929 -- Ada.Tags.Get_Entry_Index
9930 -- (T => To_Tag_Ptr (Obj'Address).all,
9931 -- Position =>
9932 -- Ada.Tags.Get_Offset_Index
9933 -- (Ada.Tags.Tag (Concval),
9934 -- <interface dispatch table position of Ename>));
9936 -- Note that Obj'Address is recursively expanded into a call to
9937 -- Base_Address (Obj).
9939 if Tagged_Type_Expansion then
9940 Prepend_To (Params,
9941 Make_Function_Call (Loc,
9942 Name => New_Occurrence_Of (RTE (RE_Get_Entry_Index), Loc),
9943 Parameter_Associations => New_List (
9945 Make_Explicit_Dereference (Loc,
9946 Unchecked_Convert_To (RTE (RE_Tag_Ptr),
9947 Make_Attribute_Reference (Loc,
9948 Prefix => New_Copy_Tree (Concval),
9949 Attribute_Name => Name_Address))),
9951 Make_Function_Call (Loc,
9952 Name => New_Occurrence_Of (RTE (RE_Get_Offset_Index), Loc),
9953 Parameter_Associations => New_List (
9954 Unchecked_Convert_To (RTE (RE_Tag), Concval),
9955 Make_Integer_Literal (Loc,
9956 DT_Position (Entity (Ename))))))));
9958 -- VM targets
9960 else
9961 Prepend_To (Params,
9962 Make_Function_Call (Loc,
9963 Name => New_Occurrence_Of (RTE (RE_Get_Entry_Index), Loc),
9964 Parameter_Associations => New_List (
9966 Make_Attribute_Reference (Loc,
9967 Prefix => Concval,
9968 Attribute_Name => Name_Tag),
9970 Make_Function_Call (Loc,
9971 Name => New_Occurrence_Of (RTE (RE_Get_Offset_Index), Loc),
9973 Parameter_Associations => New_List (
9975 -- Obj_Tag
9977 Make_Attribute_Reference (Loc,
9978 Prefix => Concval,
9979 Attribute_Name => Name_Tag),
9981 -- Tag_Typ
9983 Make_Attribute_Reference (Loc,
9984 Prefix => New_Occurrence_Of (Etype (Concval), Loc),
9985 Attribute_Name => Name_Tag),
9987 -- Position
9989 Make_Integer_Literal (Loc,
9990 DT_Position (Entity (Ename))))))));
9991 end if;
9993 -- Specific actuals for protected to XXX requeue
9995 if Is_Protected_Type (Old_Typ) then
9996 Prepend_To (Params,
9997 Make_Attribute_Reference (Loc, -- _object'Address
9998 Prefix =>
9999 Concurrent_Ref (New_Occurrence_Of (Old_Typ, Loc)),
10000 Attribute_Name => Name_Address));
10002 Prepend_To (Params, -- True
10003 New_Occurrence_Of (Standard_True, Loc));
10005 -- Specific actuals for task to XXX requeue
10007 else
10008 pragma Assert (Is_Task_Type (Old_Typ));
10010 Prepend_To (Params, -- null
10011 New_Occurrence_Of (RTE (RE_Null_Address), Loc));
10013 Prepend_To (Params, -- False
10014 New_Occurrence_Of (Standard_False, Loc));
10015 end if;
10017 -- Add the object parameter
10019 Prepend_To (Params, New_Copy_Tree (Concval));
10021 -- Generate:
10022 -- _Disp_Requeue (<Params>);
10024 -- Find entity for Disp_Requeue operation, which belongs to
10025 -- the type and may not be directly visible.
10027 declare
10028 Elmt : Elmt_Id;
10029 Op : Entity_Id := Empty;
10031 begin
10032 Elmt := First_Elmt (Primitive_Operations (Etype (Conc_Typ)));
10033 while Present (Elmt) loop
10034 Op := Node (Elmt);
10035 exit when Chars (Op) = Name_uDisp_Requeue;
10036 Next_Elmt (Elmt);
10037 end loop;
10039 pragma Assert (Present (Op));
10041 return
10042 Make_Procedure_Call_Statement (Loc,
10043 Name => New_Occurrence_Of (Op, Loc),
10044 Parameter_Associations => Params);
10045 end;
10046 end Build_Dispatching_Requeue;
10048 --------------------------------------
10049 -- Build_Dispatching_Requeue_To_Any --
10050 --------------------------------------
10052 function Build_Dispatching_Requeue_To_Any return Node_Id is
10053 Call_Ent : constant Entity_Id := Entity (Ename);
10054 Obj : constant Node_Id := Original_Node (Concval);
10055 Skip : constant Node_Id := Build_Skip_Statement (N);
10056 C : Entity_Id;
10057 Decls : List_Id;
10058 S : Entity_Id;
10059 Stmts : List_Id;
10061 begin
10062 Decls := New_List;
10063 Stmts := New_List;
10065 -- Dispatch table slot processing, generate:
10066 -- S : Integer;
10068 S := Build_S (Loc, Decls);
10070 -- Call kind processing, generate:
10071 -- C : Ada.Tags.Prim_Op_Kind;
10073 C := Build_C (Loc, Decls);
10075 -- Generate:
10076 -- S := Ada.Tags.Get_Offset_Index
10077 -- (Ada.Tags.Tag (Obj), DT_Position (Call_Ent));
10079 Append_To (Stmts, Build_S_Assignment (Loc, S, Obj, Call_Ent));
10081 -- Generate:
10082 -- _Disp_Get_Prim_Op_Kind (Obj, S, C);
10084 Append_To (Stmts,
10085 Make_Procedure_Call_Statement (Loc,
10086 Name =>
10087 New_Occurrence_Of (
10088 Find_Prim_Op (Etype (Etype (Obj)),
10089 Name_uDisp_Get_Prim_Op_Kind),
10090 Loc),
10091 Parameter_Associations => New_List (
10092 New_Copy_Tree (Obj),
10093 New_Occurrence_Of (S, Loc),
10094 New_Occurrence_Of (C, Loc))));
10096 Append_To (Stmts,
10098 -- if C = POK_Protected_Entry
10099 -- or else C = POK_Task_Entry
10100 -- then
10102 Make_Implicit_If_Statement (N,
10103 Condition =>
10104 Make_Op_Or (Loc,
10105 Left_Opnd =>
10106 Make_Op_Eq (Loc,
10107 Left_Opnd =>
10108 New_Occurrence_Of (C, Loc),
10109 Right_Opnd =>
10110 New_Occurrence_Of (RTE (RE_POK_Protected_Entry), Loc)),
10112 Right_Opnd =>
10113 Make_Op_Eq (Loc,
10114 Left_Opnd =>
10115 New_Occurrence_Of (C, Loc),
10116 Right_Opnd =>
10117 New_Occurrence_Of (RTE (RE_POK_Task_Entry), Loc))),
10119 -- Dispatching requeue equivalent
10121 Then_Statements => New_List (
10122 Build_Dispatching_Requeue,
10123 Skip),
10125 -- elsif C = POK_Protected_Procedure then
10127 Elsif_Parts => New_List (
10128 Make_Elsif_Part (Loc,
10129 Condition =>
10130 Make_Op_Eq (Loc,
10131 Left_Opnd =>
10132 New_Occurrence_Of (C, Loc),
10133 Right_Opnd =>
10134 New_Occurrence_Of (
10135 RTE (RE_POK_Protected_Procedure), Loc)),
10137 -- Dispatching call equivalent
10139 Then_Statements => New_List (
10140 Build_Dispatching_Call_Equivalent))),
10142 -- else
10143 -- raise Program_Error;
10144 -- end if;
10146 Else_Statements => New_List (
10147 Make_Raise_Program_Error (Loc,
10148 Reason => PE_Explicit_Raise))));
10150 -- Wrap everything into a block
10152 return
10153 Make_Block_Statement (Loc,
10154 Declarations => Decls,
10155 Handled_Statement_Sequence =>
10156 Make_Handled_Sequence_Of_Statements (Loc,
10157 Statements => Stmts));
10158 end Build_Dispatching_Requeue_To_Any;
10160 --------------------------
10161 -- Build_Normal_Requeue --
10162 --------------------------
10164 function Build_Normal_Requeue return Node_Id is
10165 Params : constant List_Id := New_List;
10166 Param : Node_Id;
10167 RT_Call : Node_Id;
10169 begin
10170 -- Process the "with abort" parameter
10172 Prepend_To (Params,
10173 New_Occurrence_Of (Boolean_Literals (Abort_Present (N)), Loc));
10175 -- Add the index expression to the parameters. It is common among all
10176 -- four cases.
10178 Prepend_To (Params,
10179 Entry_Index_Expression (Loc, Entity (Ename), Index, Conc_Typ));
10181 if Is_Protected_Type (Old_Typ) then
10182 declare
10183 Self_Param : Node_Id;
10185 begin
10186 Self_Param :=
10187 Make_Attribute_Reference (Loc,
10188 Prefix =>
10189 Concurrent_Ref (New_Occurrence_Of (Old_Typ, Loc)),
10190 Attribute_Name =>
10191 Name_Unchecked_Access);
10193 -- Protected to protected requeue
10195 if Is_Protected_Type (Conc_Typ) then
10196 RT_Call :=
10197 New_Occurrence_Of (
10198 RTE (RE_Requeue_Protected_Entry), Loc);
10200 Param :=
10201 Make_Attribute_Reference (Loc,
10202 Prefix =>
10203 Concurrent_Ref (Concval),
10204 Attribute_Name =>
10205 Name_Unchecked_Access);
10207 -- Protected to task requeue
10209 else pragma Assert (Is_Task_Type (Conc_Typ));
10210 RT_Call :=
10211 New_Occurrence_Of (
10212 RTE (RE_Requeue_Protected_To_Task_Entry), Loc);
10214 Param := Concurrent_Ref (Concval);
10215 end if;
10217 Prepend_To (Params, Param);
10218 Prepend_To (Params, Self_Param);
10219 end;
10221 else pragma Assert (Is_Task_Type (Old_Typ));
10223 -- Task to protected requeue
10225 if Is_Protected_Type (Conc_Typ) then
10226 RT_Call :=
10227 New_Occurrence_Of (
10228 RTE (RE_Requeue_Task_To_Protected_Entry), Loc);
10230 Param :=
10231 Make_Attribute_Reference (Loc,
10232 Prefix =>
10233 Concurrent_Ref (Concval),
10234 Attribute_Name =>
10235 Name_Unchecked_Access);
10237 -- Task to task requeue
10239 else pragma Assert (Is_Task_Type (Conc_Typ));
10240 RT_Call :=
10241 New_Occurrence_Of (RTE (RE_Requeue_Task_Entry), Loc);
10243 Param := Concurrent_Ref (Concval);
10244 end if;
10246 Prepend_To (Params, Param);
10247 end if;
10249 return
10250 Make_Procedure_Call_Statement (Loc,
10251 Name => RT_Call,
10252 Parameter_Associations => Params);
10253 end Build_Normal_Requeue;
10255 --------------------------
10256 -- Build_Skip_Statement --
10257 --------------------------
10259 function Build_Skip_Statement (Search : Node_Id) return Node_Id is
10260 Skip_Stmt : Node_Id;
10262 begin
10263 -- Build a return statement to skip the rest of the entire body
10265 if Is_Protected_Type (Old_Typ) then
10266 Skip_Stmt := Make_Simple_Return_Statement (Loc);
10268 -- If the requeue is within a task, find the end label of the
10269 -- enclosing accept statement and create a goto statement to it.
10271 else
10272 declare
10273 Acc : Node_Id;
10274 Label : Node_Id;
10276 begin
10277 -- Climb the parent chain looking for the enclosing accept
10278 -- statement.
10280 Acc := Parent (Search);
10281 while Present (Acc)
10282 and then Nkind (Acc) /= N_Accept_Statement
10283 loop
10284 Acc := Parent (Acc);
10285 end loop;
10287 -- The last statement is the second label used for completing
10288 -- the rendezvous the usual way. The label we are looking for
10289 -- is right before it.
10291 Label :=
10292 Prev (Last (Statements (Handled_Statement_Sequence (Acc))));
10294 pragma Assert (Nkind (Label) = N_Label);
10296 -- Generate a goto statement to skip the rest of the accept
10298 Skip_Stmt :=
10299 Make_Goto_Statement (Loc,
10300 Name =>
10301 New_Occurrence_Of (Entity (Identifier (Label)), Loc));
10302 end;
10303 end if;
10305 Set_Analyzed (Skip_Stmt);
10307 return Skip_Stmt;
10308 end Build_Skip_Statement;
10310 -- Start of processing for Expand_N_Requeue_Statement
10312 begin
10313 -- Extract the components of the entry call
10315 Extract_Entry (N, Concval, Ename, Index);
10316 Conc_Typ := Etype (Concval);
10318 -- Examine the scope stack in order to find nearest enclosing concurrent
10319 -- type. This will constitute our invocation source.
10321 Old_Typ := Current_Scope;
10322 while Present (Old_Typ)
10323 and then not Is_Concurrent_Type (Old_Typ)
10324 loop
10325 Old_Typ := Scope (Old_Typ);
10326 end loop;
10328 -- Obtain the innermost enclosing callable construct for use in
10329 -- generating a dynamic accessibility check.
10331 Enc_Subp := Current_Scope;
10333 if Ekind (Enc_Subp) not in Entry_Kind | Subprogram_Kind then
10334 Enc_Subp := Enclosing_Subprogram (Enc_Subp);
10335 end if;
10337 -- Generate a dynamic accessibility check on the target object
10339 Insert_Before_And_Analyze (N,
10340 Make_Raise_Program_Error (Loc,
10341 Condition =>
10342 Make_Op_Gt (Loc,
10343 Left_Opnd => Accessibility_Level (Name (N), Dynamic_Level),
10344 Right_Opnd => Make_Integer_Literal (Loc,
10345 Scope_Depth (Enc_Subp))),
10346 Reason => PE_Accessibility_Check_Failed));
10348 -- Ada 2012 (AI05-0030): We have a dispatching requeue of the form
10349 -- Concval.Ename where the type of Concval is class-wide concurrent
10350 -- interface.
10352 if Ada_Version >= Ada_2012
10353 and then Present (Concval)
10354 and then Is_Class_Wide_Type (Conc_Typ)
10355 and then Is_Concurrent_Interface (Conc_Typ)
10356 then
10357 declare
10358 Has_Impl : Boolean := False;
10359 Impl_Kind : Name_Id := No_Name;
10361 begin
10362 -- Check whether the Ename is flagged by pragma Implemented
10364 if Has_Rep_Pragma (Entity (Ename), Name_Implemented) then
10365 Has_Impl := True;
10366 Impl_Kind := Implementation_Kind (Entity (Ename));
10367 end if;
10369 -- The procedure_or_entry_NAME is guaranteed to be overridden by
10370 -- an entry. Create a call to predefined primitive _Disp_Requeue.
10372 if Has_Impl and then Impl_Kind = Name_By_Entry then
10373 Rewrite (N, Build_Dispatching_Requeue);
10374 Analyze (N);
10375 Insert_After (N, Build_Skip_Statement (N));
10377 -- The procedure_or_entry_NAME is guaranteed to be overridden by
10378 -- a protected procedure. In this case the requeue is transformed
10379 -- into a dispatching call.
10381 elsif Has_Impl
10382 and then Impl_Kind = Name_By_Protected_Procedure
10383 then
10384 Rewrite (N, Build_Dispatching_Call_Equivalent);
10385 Analyze (N);
10387 -- The procedure_or_entry_NAME's implementation kind is either
10388 -- By_Any, Optional, or pragma Implemented was not applied at all.
10389 -- In this case a runtime test determines whether Ename denotes an
10390 -- entry or a protected procedure and performs the appropriate
10391 -- call.
10393 else
10394 Rewrite (N, Build_Dispatching_Requeue_To_Any);
10395 Analyze (N);
10396 end if;
10397 end;
10399 -- Processing for regular (nondispatching) requeues
10401 else
10402 Rewrite (N, Build_Normal_Requeue);
10403 Analyze (N);
10404 Insert_After (N, Build_Skip_Statement (N));
10405 end if;
10406 end Expand_N_Requeue_Statement;
10408 -------------------------------
10409 -- Expand_N_Selective_Accept --
10410 -------------------------------
10412 procedure Expand_N_Selective_Accept (N : Node_Id) is
10413 Loc : constant Source_Ptr := Sloc (N);
10414 Alts : constant List_Id := Select_Alternatives (N);
10416 -- Note: in the below declarations a lot of new lists are allocated
10417 -- unconditionally which may well not end up being used. That's not
10418 -- a good idea since it wastes space gratuitously ???
10420 Accept_Case : List_Id;
10421 Accept_List : constant List_Id := New_List;
10423 Alt : Node_Id;
10424 Alt_List : constant List_Id := New_List;
10425 Alt_Stats : List_Id;
10426 Ann : Entity_Id := Empty;
10428 Check_Guard : Boolean := True;
10430 Decls : constant List_Id := New_List;
10431 Stats : constant List_Id := New_List;
10432 Body_List : constant List_Id := New_List;
10433 Trailing_List : constant List_Id := New_List;
10435 Choices : List_Id;
10436 Else_Present : Boolean := False;
10437 Terminate_Alt : Node_Id := Empty;
10438 Select_Mode : Node_Id;
10440 Delay_Case : List_Id;
10441 Delay_Count : Integer := 0;
10442 Delay_Val : Entity_Id;
10443 Delay_Index : Entity_Id;
10444 Delay_Min : Entity_Id;
10445 Delay_Num : Pos := 1;
10446 Delay_Alt_List : List_Id := New_List;
10447 Delay_List : constant List_Id := New_List;
10448 D : Entity_Id;
10449 M : Entity_Id;
10451 First_Delay : Boolean := True;
10452 Guard_Open : Entity_Id;
10454 End_Lab : Node_Id;
10455 Index : Pos := 1;
10456 Lab : Node_Id;
10457 Num_Alts : Nat;
10458 Num_Accept : Nat := 0;
10459 Proc : Node_Id;
10460 Time_Type : Entity_Id := Empty;
10461 Select_Call : Node_Id;
10463 Qnam : constant Entity_Id :=
10464 Make_Defining_Identifier (Loc, New_External_Name ('S', 0));
10466 Xnam : constant Entity_Id :=
10467 Make_Defining_Identifier (Loc, New_External_Name ('J', 1));
10469 -----------------------
10470 -- Local subprograms --
10471 -----------------------
10473 function Accept_Or_Raise return List_Id;
10474 -- For the rare case where delay alternatives all have guards, and
10475 -- all of them are closed, it is still possible that there were open
10476 -- accept alternatives with no callers. We must reexamine the
10477 -- Accept_List, and execute a selective wait with no else if some
10478 -- accept is open. If none, we raise program_error.
10480 procedure Add_Accept (Alt : Node_Id);
10481 -- Process a single accept statement in a select alternative. Build
10482 -- procedure for body of accept, and add entry to dispatch table with
10483 -- expression for guard, in preparation for call to run time select.
10485 function Make_And_Declare_Label (Num : Int) return Node_Id;
10486 -- Manufacture a label using Num as a serial number and declare it.
10487 -- The declaration is appended to Decls. The label marks the trailing
10488 -- statements of an accept or delay alternative.
10490 function Make_Select_Call (Select_Mode : Entity_Id) return Node_Id;
10491 -- Build call to Selective_Wait runtime routine
10493 procedure Process_Delay_Alternative (Alt : Node_Id; Index : Int);
10494 -- Add code to compare value of delay with previous values, and
10495 -- generate case entry for trailing statements.
10497 procedure Process_Accept_Alternative
10498 (Alt : Node_Id;
10499 Index : Int;
10500 Proc : Node_Id);
10501 -- Add code to call corresponding procedure, and branch to
10502 -- trailing statements, if any.
10504 ---------------------
10505 -- Accept_Or_Raise --
10506 ---------------------
10508 function Accept_Or_Raise return List_Id is
10509 Cond : Node_Id;
10510 Stats : List_Id;
10511 J : constant Entity_Id := Make_Temporary (Loc, 'J');
10513 begin
10514 -- We generate the following:
10516 -- for J in q'range loop
10517 -- if q(J).S /=null_task_entry then
10518 -- selective_wait (simple_mode,...);
10519 -- done := True;
10520 -- exit;
10521 -- end if;
10522 -- end loop;
10524 -- if no rendez_vous then
10525 -- raise program_error;
10526 -- end if;
10528 -- Note that the code needs to know that the selector name
10529 -- in an Accept_Alternative is named S.
10531 Cond := Make_Op_Ne (Loc,
10532 Left_Opnd =>
10533 Make_Selected_Component (Loc,
10534 Prefix =>
10535 Make_Indexed_Component (Loc,
10536 Prefix => New_Occurrence_Of (Qnam, Loc),
10537 Expressions => New_List (New_Occurrence_Of (J, Loc))),
10538 Selector_Name => Make_Identifier (Loc, Name_S)),
10539 Right_Opnd =>
10540 New_Occurrence_Of (RTE (RE_Null_Task_Entry), Loc));
10542 Stats := New_List (
10543 Make_Implicit_Loop_Statement (N,
10544 Iteration_Scheme =>
10545 Make_Iteration_Scheme (Loc,
10546 Loop_Parameter_Specification =>
10547 Make_Loop_Parameter_Specification (Loc,
10548 Defining_Identifier => J,
10549 Discrete_Subtype_Definition =>
10550 Make_Attribute_Reference (Loc,
10551 Prefix => New_Occurrence_Of (Qnam, Loc),
10552 Attribute_Name => Name_Range,
10553 Expressions => New_List (
10554 Make_Integer_Literal (Loc, 1))))),
10556 Statements => New_List (
10557 Make_Implicit_If_Statement (N,
10558 Condition => Cond,
10559 Then_Statements => New_List (
10560 Make_Select_Call (
10561 New_Occurrence_Of (RTE (RE_Simple_Mode), Loc)),
10562 Make_Exit_Statement (Loc))))));
10564 Append_To (Stats,
10565 Make_Raise_Program_Error (Loc,
10566 Condition => Make_Op_Eq (Loc,
10567 Left_Opnd => New_Occurrence_Of (Xnam, Loc),
10568 Right_Opnd =>
10569 New_Occurrence_Of (RTE (RE_No_Rendezvous), Loc)),
10570 Reason => PE_All_Guards_Closed));
10572 return Stats;
10573 end Accept_Or_Raise;
10575 ----------------
10576 -- Add_Accept --
10577 ----------------
10579 procedure Add_Accept (Alt : Node_Id) is
10580 Acc_Stm : constant Node_Id := Accept_Statement (Alt);
10581 Ename : constant Node_Id := Entry_Direct_Name (Acc_Stm);
10582 Eloc : constant Source_Ptr := Sloc (Ename);
10583 Eent : constant Entity_Id := Entity (Ename);
10584 Index : constant Node_Id := Entry_Index (Acc_Stm);
10586 Call : Node_Id;
10587 Expr : Node_Id;
10588 Null_Body : Node_Id;
10589 PB_Ent : Entity_Id;
10590 Proc_Body : Node_Id;
10592 -- Start of processing for Add_Accept
10594 begin
10595 if No (Ann) then
10596 Ann := Node (Last_Elmt (Accept_Address (Eent)));
10597 end if;
10599 if Present (Condition (Alt)) then
10600 Expr :=
10601 Make_If_Expression (Eloc, New_List (
10602 Condition (Alt),
10603 Entry_Index_Expression (Eloc, Eent, Index, Scope (Eent)),
10604 New_Occurrence_Of (RTE (RE_Null_Task_Entry), Eloc)));
10605 else
10606 Expr := Entry_Index_Expression (Eloc, Eent, Index, Scope (Eent));
10607 end if;
10609 if Present (Handled_Statement_Sequence (Accept_Statement (Alt))) then
10610 Null_Body := New_Occurrence_Of (Standard_False, Eloc);
10612 -- Always add call to Abort_Undefer when generating code, since
10613 -- this is what the runtime expects (abort deferred in
10614 -- Selective_Wait). In CodePeer mode this only confuses the
10615 -- analysis with unknown calls, so don't do it.
10617 if not CodePeer_Mode then
10618 Call := Build_Runtime_Call (Loc, RE_Abort_Undefer);
10619 Insert_Before
10620 (First (Statements (Handled_Statement_Sequence
10621 (Accept_Statement (Alt)))),
10622 Call);
10623 Analyze (Call);
10624 end if;
10626 PB_Ent :=
10627 Make_Defining_Identifier (Eloc,
10628 New_External_Name (Chars (Ename), 'A', Num_Accept));
10630 -- Link the acceptor to the original receiving entry
10632 Mutate_Ekind (PB_Ent, E_Procedure);
10633 Set_Receiving_Entry (PB_Ent, Eent);
10635 if Comes_From_Source (Alt) then
10636 Set_Debug_Info_Needed (PB_Ent);
10637 end if;
10639 Proc_Body :=
10640 Make_Subprogram_Body (Eloc,
10641 Specification =>
10642 Make_Procedure_Specification (Eloc,
10643 Defining_Unit_Name => PB_Ent),
10644 Declarations => Declarations (Acc_Stm),
10645 Handled_Statement_Sequence =>
10646 Build_Accept_Body (Accept_Statement (Alt)));
10648 Reset_Scopes_To (Proc_Body, PB_Ent);
10650 -- During the analysis of the body of the accept statement, any
10651 -- zero cost exception handler records were collected in the
10652 -- Accept_Handler_Records field of the N_Accept_Alternative node.
10653 -- This is where we move them to where they belong, namely the
10654 -- newly created procedure.
10656 Set_Handler_Records (PB_Ent, Accept_Handler_Records (Alt));
10657 Append (Proc_Body, Body_List);
10659 else
10660 Null_Body := New_Occurrence_Of (Standard_True, Eloc);
10662 -- if accept statement has declarations, insert above, given that
10663 -- we are not creating a body for the accept.
10665 if Present (Declarations (Acc_Stm)) then
10666 Insert_Actions (N, Declarations (Acc_Stm));
10667 end if;
10668 end if;
10670 Append_To (Accept_List,
10671 Make_Aggregate (Eloc, Expressions => New_List (Null_Body, Expr)));
10673 Num_Accept := Num_Accept + 1;
10674 end Add_Accept;
10676 ----------------------------
10677 -- Make_And_Declare_Label --
10678 ----------------------------
10680 function Make_And_Declare_Label (Num : Int) return Node_Id is
10681 Lab_Id : Node_Id;
10683 begin
10684 Lab_Id := Make_Identifier (Loc, New_External_Name ('L', Num));
10685 Lab :=
10686 Make_Label (Loc, Lab_Id);
10688 Append_To (Decls,
10689 Make_Implicit_Label_Declaration (Loc,
10690 Defining_Identifier =>
10691 Make_Defining_Identifier (Loc, Chars (Lab_Id)),
10692 Label_Construct => Lab));
10694 return Lab;
10695 end Make_And_Declare_Label;
10697 ----------------------
10698 -- Make_Select_Call --
10699 ----------------------
10701 function Make_Select_Call (Select_Mode : Entity_Id) return Node_Id is
10702 Params : constant List_Id := New_List;
10704 begin
10705 Append_To (Params,
10706 Make_Attribute_Reference (Loc,
10707 Prefix => New_Occurrence_Of (Qnam, Loc),
10708 Attribute_Name => Name_Unchecked_Access));
10709 Append_To (Params, Select_Mode);
10710 Append_To (Params, New_Occurrence_Of (Ann, Loc));
10711 Append_To (Params, New_Occurrence_Of (Xnam, Loc));
10713 return
10714 Make_Procedure_Call_Statement (Loc,
10715 Name => New_Occurrence_Of (RTE (RE_Selective_Wait), Loc),
10716 Parameter_Associations => Params);
10717 end Make_Select_Call;
10719 --------------------------------
10720 -- Process_Accept_Alternative --
10721 --------------------------------
10723 procedure Process_Accept_Alternative
10724 (Alt : Node_Id;
10725 Index : Int;
10726 Proc : Node_Id)
10728 Astmt : constant Node_Id := Accept_Statement (Alt);
10729 Alt_Stats : List_Id;
10731 begin
10732 Adjust_Condition (Condition (Alt));
10734 -- Accept with body
10736 if Present (Handled_Statement_Sequence (Astmt)) then
10737 Alt_Stats :=
10738 New_List (
10739 Make_Procedure_Call_Statement (Sloc (Proc),
10740 Name =>
10741 New_Occurrence_Of
10742 (Defining_Unit_Name (Specification (Proc)),
10743 Sloc (Proc))));
10745 -- Accept with no body (followed by trailing statements)
10747 else
10748 declare
10749 Entry_Id : constant Entity_Id :=
10750 Entity (Entry_Direct_Name (Accept_Statement (Alt)));
10751 begin
10752 -- Ada 2022 (AI12-0279)
10754 if Has_Yield_Aspect (Entry_Id)
10755 and then RTE_Available (RE_Yield)
10756 then
10757 Alt_Stats :=
10758 New_List (
10759 Make_Procedure_Call_Statement (Sloc (Proc),
10760 New_Occurrence_Of (RTE (RE_Yield), Sloc (Proc))));
10761 else
10762 Alt_Stats := Empty_List;
10763 end if;
10764 end;
10765 end if;
10767 Ensure_Statement_Present (Sloc (Astmt), Alt);
10769 -- After the call, if any, branch to trailing statements, if any.
10770 -- We create a label for each, as well as the corresponding label
10771 -- declaration.
10773 if not Is_Empty_List (Statements (Alt)) then
10774 Lab := Make_And_Declare_Label (Index);
10775 Append (Lab, Trailing_List);
10776 Append_List (Statements (Alt), Trailing_List);
10777 Append_To (Trailing_List,
10778 Make_Goto_Statement (Loc,
10779 Name => New_Copy (Identifier (End_Lab))));
10781 else
10782 Lab := End_Lab;
10783 end if;
10785 Append_To (Alt_Stats,
10786 Make_Goto_Statement (Loc, Name => New_Copy (Identifier (Lab))));
10788 Append_To (Alt_List,
10789 Make_Case_Statement_Alternative (Loc,
10790 Discrete_Choices => New_List (Make_Integer_Literal (Loc, Index)),
10791 Statements => Alt_Stats));
10792 end Process_Accept_Alternative;
10794 -------------------------------
10795 -- Process_Delay_Alternative --
10796 -------------------------------
10798 procedure Process_Delay_Alternative (Alt : Node_Id; Index : Int) is
10799 Dloc : constant Source_Ptr := Sloc (Delay_Statement (Alt));
10800 Cond : Node_Id;
10801 Delay_Alt : List_Id;
10803 begin
10804 -- Deal with C/Fortran boolean as delay condition
10806 Adjust_Condition (Condition (Alt));
10808 -- Determine the smallest specified delay
10810 -- for each delay alternative generate:
10812 -- if guard-expression then
10813 -- Delay_Val := delay-expression;
10814 -- Guard_Open := True;
10815 -- if Delay_Val < Delay_Min then
10816 -- Delay_Min := Delay_Val;
10817 -- Delay_Index := Index;
10818 -- end if;
10819 -- end if;
10821 -- The enclosing if-statement is omitted if there is no guard
10823 if Delay_Count = 1 or else First_Delay then
10824 First_Delay := False;
10826 Delay_Alt := New_List (
10827 Make_Assignment_Statement (Loc,
10828 Name => New_Occurrence_Of (Delay_Min, Loc),
10829 Expression => Expression (Delay_Statement (Alt))));
10831 if Delay_Count > 1 then
10832 Append_To (Delay_Alt,
10833 Make_Assignment_Statement (Loc,
10834 Name => New_Occurrence_Of (Delay_Index, Loc),
10835 Expression => Make_Integer_Literal (Loc, Index)));
10836 end if;
10838 else
10839 Delay_Alt := New_List (
10840 Make_Assignment_Statement (Loc,
10841 Name => New_Occurrence_Of (Delay_Val, Loc),
10842 Expression => Expression (Delay_Statement (Alt))));
10844 if Time_Type = Standard_Duration then
10845 Cond :=
10846 Make_Op_Lt (Loc,
10847 Left_Opnd => New_Occurrence_Of (Delay_Val, Loc),
10848 Right_Opnd => New_Occurrence_Of (Delay_Min, Loc));
10850 else
10851 -- The scope of the time type must define a comparison
10852 -- operator. The scope itself may not be visible, so we
10853 -- construct a node with entity information to insure that
10854 -- semantic analysis can find the proper operator.
10856 Cond :=
10857 Make_Function_Call (Loc,
10858 Name => Make_Selected_Component (Loc,
10859 Prefix =>
10860 New_Occurrence_Of (Scope (Time_Type), Loc),
10861 Selector_Name =>
10862 Make_Operator_Symbol (Loc,
10863 Chars => Name_Op_Lt,
10864 Strval => No_String)),
10865 Parameter_Associations =>
10866 New_List (
10867 New_Occurrence_Of (Delay_Val, Loc),
10868 New_Occurrence_Of (Delay_Min, Loc)));
10870 Set_Entity (Prefix (Name (Cond)), Scope (Time_Type));
10871 end if;
10873 Append_To (Delay_Alt,
10874 Make_Implicit_If_Statement (N,
10875 Condition => Cond,
10876 Then_Statements => New_List (
10877 Make_Assignment_Statement (Loc,
10878 Name => New_Occurrence_Of (Delay_Min, Loc),
10879 Expression => New_Occurrence_Of (Delay_Val, Loc)),
10881 Make_Assignment_Statement (Loc,
10882 Name => New_Occurrence_Of (Delay_Index, Loc),
10883 Expression => Make_Integer_Literal (Loc, Index)))));
10884 end if;
10886 if Check_Guard then
10887 Append_To (Delay_Alt,
10888 Make_Assignment_Statement (Loc,
10889 Name => New_Occurrence_Of (Guard_Open, Loc),
10890 Expression => New_Occurrence_Of (Standard_True, Loc)));
10891 end if;
10893 if Present (Condition (Alt)) then
10894 Delay_Alt := New_List (
10895 Make_Implicit_If_Statement (N,
10896 Condition => Condition (Alt),
10897 Then_Statements => Delay_Alt));
10898 end if;
10900 Append_List (Delay_Alt, Delay_List);
10902 Ensure_Statement_Present (Dloc, Alt);
10904 -- If the delay alternative has a statement part, add choice to the
10905 -- case statements for delays.
10907 if not Is_Empty_List (Statements (Alt)) then
10909 if Delay_Count = 1 then
10910 Append_List (Statements (Alt), Delay_Alt_List);
10912 else
10913 Append_To (Delay_Alt_List,
10914 Make_Case_Statement_Alternative (Loc,
10915 Discrete_Choices => New_List (
10916 Make_Integer_Literal (Loc, Index)),
10917 Statements => Statements (Alt)));
10918 end if;
10920 elsif Delay_Count = 1 then
10922 -- If the single delay has no trailing statements, add a branch
10923 -- to the exit label to the selective wait.
10925 Delay_Alt_List := New_List (
10926 Make_Goto_Statement (Loc,
10927 Name => New_Copy (Identifier (End_Lab))));
10929 end if;
10930 end Process_Delay_Alternative;
10932 -- Start of processing for Expand_N_Selective_Accept
10934 begin
10935 Process_Statements_For_Controlled_Objects (N);
10937 -- First insert some declarations before the select. The first is:
10939 -- Ann : Address
10941 -- This variable holds the parameters passed to the accept body. This
10942 -- declaration has already been inserted by the time we get here by
10943 -- a call to Expand_Accept_Declarations made from the semantics when
10944 -- processing the first accept statement contained in the select. We
10945 -- can find this entity as Accept_Address (E), where E is any of the
10946 -- entries references by contained accept statements.
10948 -- The first step is to scan the list of Selective_Accept_Statements
10949 -- to find this entity, and also count the number of accepts, and
10950 -- determine if terminated, delay or else is present:
10952 Num_Alts := 0;
10954 Alt := First (Alts);
10955 while Present (Alt) loop
10956 Process_Statements_For_Controlled_Objects (Alt);
10958 if Nkind (Alt) = N_Accept_Alternative then
10959 Add_Accept (Alt);
10961 elsif Nkind (Alt) = N_Delay_Alternative then
10962 Delay_Count := Delay_Count + 1;
10964 -- If the delays are relative delays, the delay expressions have
10965 -- type Standard_Duration. Otherwise they must have some time type
10966 -- recognized by GNAT.
10968 if Nkind (Delay_Statement (Alt)) = N_Delay_Relative_Statement then
10969 Time_Type := Standard_Duration;
10970 else
10971 Time_Type := Etype (Expression (Delay_Statement (Alt)));
10973 if Is_RTE (Base_Type (Etype (Time_Type)), RO_CA_Time)
10974 or else Is_RTE (Base_Type (Etype (Time_Type)), RO_RT_Time)
10975 then
10976 null;
10977 else
10978 -- Move this check to sem???
10979 Error_Msg_NE (
10980 "& is not a time type (RM 9.6(6))",
10981 Expression (Delay_Statement (Alt)), Time_Type);
10982 Time_Type := Standard_Duration;
10983 Set_Etype (Expression (Delay_Statement (Alt)), Any_Type);
10984 end if;
10985 end if;
10987 if No (Condition (Alt)) then
10989 -- This guard will always be open
10991 Check_Guard := False;
10992 end if;
10994 elsif Nkind (Alt) = N_Terminate_Alternative then
10995 Adjust_Condition (Condition (Alt));
10996 Terminate_Alt := Alt;
10997 end if;
10999 Num_Alts := Num_Alts + 1;
11000 Next (Alt);
11001 end loop;
11003 Else_Present := Present (Else_Statements (N));
11005 -- At the same time (see procedure Add_Accept) we build the accept list:
11007 -- Qnn : Accept_List (1 .. num-select) := (
11008 -- (null-body, entry-index),
11009 -- (null-body, entry-index),
11010 -- ..
11011 -- (null_body, entry-index));
11013 -- In the above declaration, null-body is True if the corresponding
11014 -- accept has no body, and false otherwise. The entry is either the
11015 -- entry index expression if there is no guard, or if a guard is
11016 -- present, then an if expression of the form:
11018 -- (if guard then entry-index else Null_Task_Entry)
11020 -- If a guard is statically known to be false, the entry can simply
11021 -- be omitted from the accept list.
11023 Append_To (Decls,
11024 Make_Object_Declaration (Loc,
11025 Defining_Identifier => Qnam,
11026 Object_Definition => New_Occurrence_Of (RTE (RE_Accept_List), Loc),
11027 Aliased_Present => True,
11028 Expression =>
11029 Make_Qualified_Expression (Loc,
11030 Subtype_Mark =>
11031 New_Occurrence_Of (RTE (RE_Accept_List), Loc),
11032 Expression =>
11033 Make_Aggregate (Loc, Expressions => Accept_List))));
11035 -- Then we declare the variable that holds the index for the accept
11036 -- that will be selected for service:
11038 -- Xnn : Select_Index;
11040 Append_To (Decls,
11041 Make_Object_Declaration (Loc,
11042 Defining_Identifier => Xnam,
11043 Object_Definition =>
11044 New_Occurrence_Of (RTE (RE_Select_Index), Loc),
11045 Expression =>
11046 New_Occurrence_Of (RTE (RE_No_Rendezvous), Loc)));
11048 -- After this follow procedure declarations for each accept body
11050 -- procedure Pnn is
11051 -- begin
11052 -- ...
11053 -- end;
11055 -- where the ... are statements from the corresponding procedure body.
11056 -- No parameters are involved, since the parameters are passed via Ann
11057 -- and the parameter references have already been expanded to be direct
11058 -- references to Ann (see Exp_Ch2.Expand_Entry_Parameter). Furthermore,
11059 -- any embedded tasking statements (which would normally be illegal in
11060 -- procedures), have been converted to calls to the tasking runtime so
11061 -- there is no problem in putting them into procedures.
11063 -- The original accept statement has been expanded into a block in
11064 -- the same fashion as for simple accepts (see Build_Accept_Body).
11066 -- Note: we don't really need to build these procedures for the case
11067 -- where no delay statement is present, but it is just as easy to
11068 -- build them unconditionally, and not significantly inefficient,
11069 -- since if they are short they will be inlined anyway.
11071 -- The procedure declarations have been assembled in Body_List
11073 -- If delays are present, we must compute the required delay.
11074 -- We first generate the declarations:
11076 -- Delay_Index : Boolean := 0;
11077 -- Delay_Min : Some_Time_Type.Time;
11078 -- Delay_Val : Some_Time_Type.Time;
11080 -- Delay_Index will be set to the index of the minimum delay, i.e. the
11081 -- active delay that is actually chosen as the basis for the possible
11082 -- delay if an immediate rendez-vous is not possible.
11084 -- In the most common case there is a single delay statement, and this
11085 -- is handled specially.
11087 if Delay_Count > 0 then
11089 -- Generate the required declarations
11091 Delay_Val :=
11092 Make_Defining_Identifier (Loc, New_External_Name ('D', 1));
11093 Delay_Index :=
11094 Make_Defining_Identifier (Loc, New_External_Name ('D', 2));
11095 Delay_Min :=
11096 Make_Defining_Identifier (Loc, New_External_Name ('D', 3));
11098 pragma Assert (Present (Time_Type));
11100 Append_To (Decls,
11101 Make_Object_Declaration (Loc,
11102 Defining_Identifier => Delay_Val,
11103 Object_Definition => New_Occurrence_Of (Time_Type, Loc)));
11105 Append_To (Decls,
11106 Make_Object_Declaration (Loc,
11107 Defining_Identifier => Delay_Index,
11108 Object_Definition => New_Occurrence_Of (Standard_Integer, Loc),
11109 Expression => Make_Integer_Literal (Loc, 0)));
11111 Append_To (Decls,
11112 Make_Object_Declaration (Loc,
11113 Defining_Identifier => Delay_Min,
11114 Object_Definition => New_Occurrence_Of (Time_Type, Loc),
11115 Expression =>
11116 Unchecked_Convert_To (Time_Type,
11117 Make_Attribute_Reference (Loc,
11118 Prefix =>
11119 New_Occurrence_Of (Underlying_Type (Time_Type), Loc),
11120 Attribute_Name => Name_Last))));
11122 -- Create Duration and Delay_Mode objects used for passing a delay
11123 -- value to RTS
11125 D := Make_Temporary (Loc, 'D');
11126 M := Make_Temporary (Loc, 'M');
11128 declare
11129 Discr : Entity_Id;
11131 begin
11132 -- Note that these values are defined in s-osprim.ads and must
11133 -- be kept in sync:
11135 -- Relative : constant := 0;
11136 -- Absolute_Calendar : constant := 1;
11137 -- Absolute_RT : constant := 2;
11139 if Time_Type = Standard_Duration then
11140 Discr := Make_Integer_Literal (Loc, 0);
11142 elsif Is_RTE (Base_Type (Etype (Time_Type)), RO_CA_Time) then
11143 Discr := Make_Integer_Literal (Loc, 1);
11145 else
11146 pragma Assert
11147 (Is_RTE (Base_Type (Etype (Time_Type)), RO_RT_Time));
11148 Discr := Make_Integer_Literal (Loc, 2);
11149 end if;
11151 Append_To (Decls,
11152 Make_Object_Declaration (Loc,
11153 Defining_Identifier => D,
11154 Object_Definition =>
11155 New_Occurrence_Of (Standard_Duration, Loc)));
11157 Append_To (Decls,
11158 Make_Object_Declaration (Loc,
11159 Defining_Identifier => M,
11160 Object_Definition =>
11161 New_Occurrence_Of (Standard_Integer, Loc),
11162 Expression => Discr));
11163 end;
11165 if Check_Guard then
11166 Guard_Open :=
11167 Make_Defining_Identifier (Loc, New_External_Name ('G', 1));
11169 Append_To (Decls,
11170 Make_Object_Declaration (Loc,
11171 Defining_Identifier => Guard_Open,
11172 Object_Definition =>
11173 New_Occurrence_Of (Standard_Boolean, Loc),
11174 Expression =>
11175 New_Occurrence_Of (Standard_False, Loc)));
11176 end if;
11178 -- Delay_Count is zero, don't need M and D set (suppress warning)
11180 else
11181 M := Empty;
11182 D := Empty;
11183 end if;
11185 if Present (Terminate_Alt) then
11187 -- If the terminate alternative guard is False, use
11188 -- Simple_Mode; otherwise use Terminate_Mode.
11190 if Present (Condition (Terminate_Alt)) then
11191 Select_Mode := Make_If_Expression (Loc,
11192 New_List (Condition (Terminate_Alt),
11193 New_Occurrence_Of (RTE (RE_Terminate_Mode), Loc),
11194 New_Occurrence_Of (RTE (RE_Simple_Mode), Loc)));
11195 else
11196 Select_Mode := New_Occurrence_Of (RTE (RE_Terminate_Mode), Loc);
11197 end if;
11199 elsif Else_Present or Delay_Count > 0 then
11200 Select_Mode := New_Occurrence_Of (RTE (RE_Else_Mode), Loc);
11202 else
11203 Select_Mode := New_Occurrence_Of (RTE (RE_Simple_Mode), Loc);
11204 end if;
11206 Select_Call := Make_Select_Call (Select_Mode);
11207 Append (Select_Call, Stats);
11209 -- Now generate code to act on the result. There is an entry
11210 -- in this case for each accept statement with a non-null body,
11211 -- followed by a branch to the statements that follow the Accept.
11212 -- In the absence of delay alternatives, we generate:
11214 -- case X is
11215 -- when No_Rendezvous => -- omitted if simple mode
11216 -- goto Lab0;
11218 -- when 1 =>
11219 -- P1n;
11220 -- goto Lab1;
11222 -- when 2 =>
11223 -- P2n;
11224 -- goto Lab2;
11226 -- when others =>
11227 -- goto Exit;
11228 -- end case;
11230 -- Lab0: Else_Statements;
11231 -- goto exit;
11233 -- Lab1: Trailing_Statements1;
11234 -- goto Exit;
11236 -- Lab2: Trailing_Statements2;
11237 -- goto Exit;
11238 -- ...
11239 -- Exit:
11241 -- Generate label for common exit
11243 End_Lab := Make_And_Declare_Label (Num_Alts + 1);
11245 -- First entry is the default case, when no rendezvous is possible
11247 Choices := New_List (New_Occurrence_Of (RTE (RE_No_Rendezvous), Loc));
11249 if Else_Present then
11251 -- If no rendezvous is possible, the else part is executed
11253 Lab := Make_And_Declare_Label (0);
11254 Alt_Stats := New_List (
11255 Make_Goto_Statement (Loc,
11256 Name => New_Copy (Identifier (Lab))));
11258 Append (Lab, Trailing_List);
11259 Append_List (Else_Statements (N), Trailing_List);
11260 Append_To (Trailing_List,
11261 Make_Goto_Statement (Loc,
11262 Name => New_Copy (Identifier (End_Lab))));
11263 else
11264 Alt_Stats := New_List (
11265 Make_Goto_Statement (Loc,
11266 Name => New_Copy (Identifier (End_Lab))));
11267 end if;
11269 Append_To (Alt_List,
11270 Make_Case_Statement_Alternative (Loc,
11271 Discrete_Choices => Choices,
11272 Statements => Alt_Stats));
11274 -- We make use of the fact that Accept_Index is an integer type, and
11275 -- generate successive literals for entries for each accept. Only those
11276 -- for which there is a body or trailing statements get a case entry.
11278 Alt := First (Select_Alternatives (N));
11279 Proc := First (Body_List);
11280 while Present (Alt) loop
11282 if Nkind (Alt) = N_Accept_Alternative then
11283 Process_Accept_Alternative (Alt, Index, Proc);
11284 Index := Index + 1;
11286 if Present
11287 (Handled_Statement_Sequence (Accept_Statement (Alt)))
11288 then
11289 Next (Proc);
11290 end if;
11292 elsif Nkind (Alt) = N_Delay_Alternative then
11293 Process_Delay_Alternative (Alt, Delay_Num);
11294 Delay_Num := Delay_Num + 1;
11295 end if;
11297 Next (Alt);
11298 end loop;
11300 -- An others choice is always added to the main case, as well
11301 -- as the delay case (to satisfy the compiler).
11303 Append_To (Alt_List,
11304 Make_Case_Statement_Alternative (Loc,
11305 Discrete_Choices =>
11306 New_List (Make_Others_Choice (Loc)),
11307 Statements =>
11308 New_List (Make_Goto_Statement (Loc,
11309 Name => New_Copy (Identifier (End_Lab))))));
11311 Accept_Case := New_List (
11312 Make_Case_Statement (Loc,
11313 Expression => New_Occurrence_Of (Xnam, Loc),
11314 Alternatives => Alt_List));
11316 Append_List (Trailing_List, Accept_Case);
11317 Append_List (Body_List, Decls);
11319 -- Construct case statement for trailing statements of delay
11320 -- alternatives, if there are several of them.
11322 if Delay_Count > 1 then
11323 Append_To (Delay_Alt_List,
11324 Make_Case_Statement_Alternative (Loc,
11325 Discrete_Choices =>
11326 New_List (Make_Others_Choice (Loc)),
11327 Statements =>
11328 New_List (Make_Null_Statement (Loc))));
11330 Delay_Case := New_List (
11331 Make_Case_Statement (Loc,
11332 Expression => New_Occurrence_Of (Delay_Index, Loc),
11333 Alternatives => Delay_Alt_List));
11334 else
11335 Delay_Case := Delay_Alt_List;
11336 end if;
11338 -- If there are no delay alternatives, we append the case statement
11339 -- to the statement list.
11341 if Delay_Count = 0 then
11342 Append_List (Accept_Case, Stats);
11344 -- Delay alternatives present
11346 else
11347 -- If delay alternatives are present we generate:
11349 -- find minimum delay.
11350 -- DX := minimum delay;
11351 -- M := <delay mode>;
11352 -- Timed_Selective_Wait (Q'Unchecked_Access, Delay_Mode, P,
11353 -- DX, MX, X);
11355 -- if X = No_Rendezvous then
11356 -- case statement for delay statements.
11357 -- else
11358 -- case statement for accept alternatives.
11359 -- end if;
11361 declare
11362 Cases : Node_Id;
11363 Stmt : Node_Id;
11364 Parms : List_Id;
11365 Parm : Node_Id;
11366 Conv : Node_Id;
11368 begin
11369 -- The type of the delay expression is known to be legal
11371 if Time_Type = Standard_Duration then
11372 Conv := New_Occurrence_Of (Delay_Min, Loc);
11374 elsif Is_RTE (Base_Type (Etype (Time_Type)), RO_CA_Time) then
11375 Conv := Make_Function_Call (Loc,
11376 New_Occurrence_Of (RTE (RO_CA_To_Duration), Loc),
11377 New_List (New_Occurrence_Of (Delay_Min, Loc)));
11379 else
11380 pragma Assert
11381 (Is_RTE (Base_Type (Etype (Time_Type)), RO_RT_Time));
11383 Conv := Make_Function_Call (Loc,
11384 New_Occurrence_Of (RTE (RO_RT_To_Duration), Loc),
11385 New_List (New_Occurrence_Of (Delay_Min, Loc)));
11386 end if;
11388 Stmt := Make_Assignment_Statement (Loc,
11389 Name => New_Occurrence_Of (D, Loc),
11390 Expression => Conv);
11392 -- Change the value for Accept_Modes. (Else_Mode -> Delay_Mode)
11394 Parms := Parameter_Associations (Select_Call);
11396 Parm := First (Parms);
11397 while Present (Parm) and then Parm /= Select_Mode loop
11398 Next (Parm);
11399 end loop;
11401 pragma Assert (Present (Parm));
11402 Rewrite (Parm, New_Occurrence_Of (RTE (RE_Delay_Mode), Loc));
11403 Analyze (Parm);
11405 -- Prepare two new parameters of Duration and Delay_Mode type
11406 -- which represent the value and the mode of the minimum delay.
11408 Next (Parm);
11409 Insert_After (Parm, New_Occurrence_Of (M, Loc));
11410 Insert_After (Parm, New_Occurrence_Of (D, Loc));
11412 -- Create a call to RTS
11414 Rewrite (Select_Call,
11415 Make_Procedure_Call_Statement (Loc,
11416 Name => New_Occurrence_Of (RTE (RE_Timed_Selective_Wait), Loc),
11417 Parameter_Associations => Parms));
11419 -- This new call should follow the calculation of the minimum
11420 -- delay.
11422 Insert_List_Before (Select_Call, Delay_List);
11424 if Check_Guard then
11425 Stmt :=
11426 Make_Implicit_If_Statement (N,
11427 Condition => New_Occurrence_Of (Guard_Open, Loc),
11428 Then_Statements => New_List (
11429 New_Copy_Tree (Stmt),
11430 New_Copy_Tree (Select_Call)),
11431 Else_Statements => Accept_Or_Raise);
11432 Rewrite (Select_Call, Stmt);
11433 else
11434 Insert_Before (Select_Call, Stmt);
11435 end if;
11437 Cases :=
11438 Make_Implicit_If_Statement (N,
11439 Condition => Make_Op_Eq (Loc,
11440 Left_Opnd => New_Occurrence_Of (Xnam, Loc),
11441 Right_Opnd =>
11442 New_Occurrence_Of (RTE (RE_No_Rendezvous), Loc)),
11444 Then_Statements => Delay_Case,
11445 Else_Statements => Accept_Case);
11447 Append (Cases, Stats);
11448 end;
11449 end if;
11451 Append (End_Lab, Stats);
11453 -- Replace accept statement with appropriate block
11455 Rewrite (N,
11456 Make_Block_Statement (Loc,
11457 Declarations => Decls,
11458 Handled_Statement_Sequence =>
11459 Make_Handled_Sequence_Of_Statements (Loc, Statements => Stats)));
11460 Analyze (N);
11462 -- Note: have to worry more about abort deferral in above code ???
11464 -- Final step is to unstack the Accept_Address entries for all accept
11465 -- statements appearing in accept alternatives in the select statement
11467 Alt := First (Alts);
11468 while Present (Alt) loop
11469 if Nkind (Alt) = N_Accept_Alternative then
11470 Remove_Last_Elmt (Accept_Address
11471 (Entity (Entry_Direct_Name (Accept_Statement (Alt)))));
11472 end if;
11474 Next (Alt);
11475 end loop;
11476 end Expand_N_Selective_Accept;
11478 -------------------------------------------
11479 -- Expand_N_Single_Protected_Declaration --
11480 -------------------------------------------
11482 -- A single protected declaration should never be present after semantic
11483 -- analysis because it is transformed into a protected type declaration
11484 -- and an accompanying anonymous object. This routine ensures that the
11485 -- transformation takes place.
11487 procedure Expand_N_Single_Protected_Declaration (N : Node_Id) is
11488 begin
11489 raise Program_Error;
11490 end Expand_N_Single_Protected_Declaration;
11492 --------------------------------------
11493 -- Expand_N_Single_Task_Declaration --
11494 --------------------------------------
11496 -- A single task declaration should never be present after semantic
11497 -- analysis because it is transformed into a task type declaration and
11498 -- an accompanying anonymous object. This routine ensures that the
11499 -- transformation takes place.
11501 procedure Expand_N_Single_Task_Declaration (N : Node_Id) is
11502 begin
11503 raise Program_Error;
11504 end Expand_N_Single_Task_Declaration;
11506 ------------------------
11507 -- Expand_N_Task_Body --
11508 ------------------------
11510 -- Given a task body
11512 -- task body tname is
11513 -- <declarations>
11514 -- begin
11515 -- <statements>
11516 -- end x;
11518 -- This expansion routine converts it into a procedure and sets the
11519 -- elaboration flag for the procedure to true, to represent the fact
11520 -- that the task body is now elaborated:
11522 -- procedure tnameB (_Task : access tnameV) is
11523 -- discriminal : dtype renames _Task.discriminant;
11525 -- procedure _clean is
11526 -- begin
11527 -- Abort_Defer.all;
11528 -- Complete_Task;
11529 -- Abort_Undefer.all;
11530 -- return;
11531 -- end _clean;
11533 -- begin
11534 -- Abort_Undefer.all;
11535 -- <declarations>
11536 -- System.Task_Stages.Complete_Activation;
11537 -- <statements>
11538 -- at end
11539 -- _clean;
11540 -- end tnameB;
11542 -- tnameE := True;
11544 -- In addition, if the task body is an activator, then a call to activate
11545 -- tasks is added at the start of the statements, before the call to
11546 -- Complete_Activation, and if in addition the task is a master then it
11547 -- must be established as a master. These calls are inserted and analyzed
11548 -- in Expand_Cleanup_Actions, when the Handled_Sequence_Of_Statements is
11549 -- expanded.
11551 -- There is one discriminal declaration line generated for each
11552 -- discriminant that is present to provide an easy reference point for
11553 -- discriminant references inside the body (see Exp_Ch2.Expand_Name).
11555 -- Note on relationship to GNARLI definition. In the GNARLI definition,
11556 -- task body procedures have a profile (Arg : System.Address). That is
11557 -- needed because GNARLI has to use the same access-to-subprogram type
11558 -- for all task types. We depend here on knowing that in GNAT, passing
11559 -- an address argument by value is identical to passing a record value
11560 -- by access (in either case a single pointer is passed), so even though
11561 -- this procedure has the wrong profile. In fact it's all OK, since the
11562 -- callings sequence is identical.
11564 procedure Expand_N_Task_Body (N : Node_Id) is
11565 Loc : constant Source_Ptr := Sloc (N);
11566 Ttyp : constant Entity_Id := Corresponding_Spec (N);
11567 Call : Node_Id;
11568 New_N : Node_Id;
11570 Insert_Nod : Node_Id;
11571 -- Used to determine the proper location of wrapper body insertions
11573 begin
11574 -- if no task body procedure, means we had an error in configurable
11575 -- run-time mode, and there is no point in proceeding further.
11577 if No (Task_Body_Procedure (Ttyp)) then
11578 return;
11579 end if;
11581 -- Add renaming declarations for discriminals and a declaration for the
11582 -- entry family index (if applicable).
11584 Install_Private_Data_Declarations
11585 (Loc, Task_Body_Procedure (Ttyp), Ttyp, N, Declarations (N));
11587 -- Add a call to Abort_Undefer at the very beginning of the task
11588 -- body since this body is called with abort still deferred.
11590 if Abort_Allowed then
11591 Call := Build_Runtime_Call (Loc, RE_Abort_Undefer);
11592 Prepend (Call, Declarations (N));
11593 Analyze (Call);
11594 end if;
11596 -- Place call to Complete_Activation at the head of the statement list.
11598 if Restricted_Profile then
11599 Call := Build_Runtime_Call (Loc, RE_Complete_Restricted_Activation);
11600 else
11601 Call := Build_Runtime_Call (Loc, RE_Complete_Activation);
11602 end if;
11604 Insert_Before
11605 (First (Statements (Handled_Statement_Sequence (N))), Call);
11606 Analyze (Call);
11608 New_N :=
11609 Make_Subprogram_Body (Loc,
11610 Specification => Build_Task_Proc_Specification (Ttyp),
11611 Declarations => Declarations (N),
11612 Handled_Statement_Sequence => Handled_Statement_Sequence (N));
11613 Set_Is_Task_Body_Procedure (New_N);
11614 Set_At_End_Proc (New_N, At_End_Proc (N));
11616 -- If the task contains generic instantiations, cleanup actions are
11617 -- delayed until after instantiation. Transfer the activation chain to
11618 -- the subprogram, to insure that the activation call is properly
11619 -- generated. It the task body contains inner tasks, indicate that the
11620 -- subprogram is a task master.
11622 if Delay_Cleanups (Ttyp) then
11623 Set_Activation_Chain_Entity (New_N, Activation_Chain_Entity (N));
11624 Set_Is_Task_Master (New_N, Is_Task_Master (N));
11625 end if;
11627 Rewrite (N, New_N);
11628 Analyze (N);
11630 -- Set elaboration flag immediately after task body. If the body is a
11631 -- subunit, the flag is set in the declarative part containing the stub.
11633 if Nkind (Parent (N)) /= N_Subunit then
11634 Insert_After (N,
11635 Make_Assignment_Statement (Loc,
11636 Name =>
11637 Make_Identifier (Loc, New_External_Name (Chars (Ttyp), 'E')),
11638 Expression => New_Occurrence_Of (Standard_True, Loc)));
11639 end if;
11641 -- Ada 2005 (AI-345): Construct the primitive entry wrapper bodies after
11642 -- the task body. At this point all wrapper specs have been created,
11643 -- frozen and included in the dispatch table for the task type.
11645 if Ada_Version >= Ada_2005 then
11646 if Nkind (Parent (N)) = N_Subunit then
11647 Insert_Nod := Corresponding_Stub (Parent (N));
11648 else
11649 Insert_Nod := N;
11650 end if;
11652 Build_Wrapper_Bodies (Loc, Ttyp, Insert_Nod);
11653 end if;
11654 end Expand_N_Task_Body;
11656 ------------------------------------
11657 -- Expand_N_Task_Type_Declaration --
11658 ------------------------------------
11660 -- We have several things to do. First we must create a Boolean flag used
11661 -- to mark if the body is elaborated yet. This variable gets set to True
11662 -- when the body of the task is elaborated (we can't rely on the normal
11663 -- ABE mechanism for the task body, since we need to pass an access to
11664 -- this elaboration boolean to the runtime routines).
11666 -- taskE : aliased Boolean := False;
11668 -- Next a variable is declared to hold the task stack size (either the
11669 -- default : Unspecified_Size, or a value that is set by a pragma
11670 -- Storage_Size). If the value of the pragma Storage_Size is static, then
11671 -- the variable is initialized with this value:
11673 -- taskZ : Size_Type := Unspecified_Size;
11674 -- or
11675 -- taskZ : Size_Type := Size_Type (size_expression);
11677 -- Note: No variable is needed to hold the task relative deadline since
11678 -- its value would never be static because the parameter is of a private
11679 -- type (Ada.Real_Time.Time_Span).
11681 -- Next we create a corresponding record type declaration used to represent
11682 -- values of this task. The general form of this type declaration is
11684 -- type taskV (discriminants) is record
11685 -- _Task_Id : Task_Id;
11686 -- entry_family : array (bounds) of Void;
11687 -- _Priority : Integer := priority_expression;
11688 -- _Size : Size_Type := size_expression;
11689 -- _Secondary_Stack_Size : Size_Type := size_expression;
11690 -- _Task_Info : Task_Info_Type := task_info_expression;
11691 -- _CPU : Integer := cpu_range_expression;
11692 -- _Relative_Deadline : Time_Span := time_span_expression;
11693 -- _Domain : Dispatching_Domain := dd_expression;
11694 -- end record;
11696 -- The discriminants are present only if the corresponding task type has
11697 -- discriminants, and they exactly mirror the task type discriminants.
11699 -- The Id field is always present. It contains the Task_Id value, as set by
11700 -- the call to Create_Task. Note that although the task is limited, the
11701 -- task value record type is not limited, so there is no problem in passing
11702 -- this field as an out parameter to Create_Task.
11704 -- One entry_family component is present for each entry family in the task
11705 -- definition. The bounds correspond to the bounds of the entry family
11706 -- (which may depend on discriminants). The element type is void, since we
11707 -- only need the bounds information for determining the entry index. Note
11708 -- that the use of an anonymous array would normally be illegal in this
11709 -- context, but this is a parser check, and the semantics is quite prepared
11710 -- to handle such a case.
11712 -- The _Size field is present only if a Storage_Size pragma appears in the
11713 -- task definition. The expression captures the argument that was present
11714 -- in the pragma, and is used to override the task stack size otherwise
11715 -- associated with the task type.
11717 -- The _Secondary_Stack_Size field is present only the task entity has a
11718 -- Secondary_Stack_Size rep item. It will be filled at the freeze point,
11719 -- when the record init proc is built, to capture the expression of the
11720 -- rep item (see Build_Record_Init_Proc in Exp_Ch3). Note that it cannot
11721 -- be filled here since aspect evaluations are delayed till the freeze
11722 -- point.
11724 -- The _Priority field is present only if the task entity has a Priority or
11725 -- Interrupt_Priority rep item (pragma, aspect specification or attribute
11726 -- definition clause). It will be filled at the freeze point, when the
11727 -- record init proc is built, to capture the expression of the rep item
11728 -- (see Build_Record_Init_Proc in Exp_Ch3). Note that it cannot be filled
11729 -- here since aspect evaluations are delayed till the freeze point.
11731 -- The _Task_Info field is present only if a Task_Info pragma appears in
11732 -- the task definition. The expression captures the argument that was
11733 -- present in the pragma, and is used to provide the Task_Image parameter
11734 -- to the call to Create_Task.
11736 -- The _CPU field is present only if the task entity has a CPU rep item
11737 -- (pragma, aspect specification or attribute definition clause). It will
11738 -- be filled at the freeze point, when the record init proc is built, to
11739 -- capture the expression of the rep item (see Build_Record_Init_Proc in
11740 -- Exp_Ch3). Note that it cannot be filled here since aspect evaluations
11741 -- are delayed till the freeze point.
11743 -- The _Relative_Deadline field is present only if a Relative_Deadline
11744 -- pragma appears in the task definition. The expression captures the
11745 -- argument that was present in the pragma, and is used to provide the
11746 -- Relative_Deadline parameter to the call to Create_Task.
11748 -- The _Domain field is present only if the task entity has a
11749 -- Dispatching_Domain rep item (pragma, aspect specification or attribute
11750 -- definition clause). It will be filled at the freeze point, when the
11751 -- record init proc is built, to capture the expression of the rep item
11752 -- (see Build_Record_Init_Proc in Exp_Ch3). Note that it cannot be filled
11753 -- here since aspect evaluations are delayed till the freeze point.
11755 -- When a task is declared, an instance of the task value record is
11756 -- created. The elaboration of this declaration creates the correct bounds
11757 -- for the entry families, and also evaluates the size, priority, and
11758 -- task_Info expressions if needed. The initialization routine for the task
11759 -- type itself then calls Create_Task with appropriate parameters to
11760 -- initialize the value of the Task_Id field.
11762 -- Note: the address of this record is passed as the "Discriminants"
11763 -- parameter for Create_Task. Since Create_Task merely passes this onto the
11764 -- body procedure, it does not matter that it does not quite match the
11765 -- GNARLI model of what is being passed (the record contains more than just
11766 -- the discriminants, but the discriminants can be found from the record
11767 -- value).
11769 -- The Entity_Id for this created record type is placed in the
11770 -- Corresponding_Record_Type field of the associated task type entity.
11772 -- Next we create a procedure specification for the task body procedure:
11774 -- procedure taskB (_Task : access taskV);
11776 -- Note that this must come after the record type declaration, since
11777 -- the spec refers to this type. It turns out that the initialization
11778 -- procedure for the value type references the task body spec, but that's
11779 -- fine, since it won't be generated till the freeze point for the type,
11780 -- which is certainly after the task body spec declaration.
11782 -- Finally, we set the task index value field of the entry attribute in
11783 -- the case of a simple entry.
11785 procedure Expand_N_Task_Type_Declaration (N : Node_Id) is
11786 Loc : constant Source_Ptr := Sloc (N);
11787 TaskId : constant Entity_Id := Defining_Identifier (N);
11788 Tasktyp : constant Entity_Id := Etype (Defining_Identifier (N));
11789 Tasknm : constant Name_Id := Chars (Tasktyp);
11790 Taskdef : constant Node_Id := Task_Definition (N);
11792 Body_Decl : Node_Id;
11793 Cdecls : List_Id;
11794 Decl_Stack : Node_Id;
11795 Decl_SS : Node_Id;
11796 Elab_Decl : Node_Id;
11797 Ent_Stack : Entity_Id;
11798 Proc_Spec : Node_Id;
11799 Rec_Decl : Node_Id;
11800 Rec_Ent : Entity_Id;
11801 Size_Decl : Entity_Id;
11802 Task_Size : Node_Id;
11804 function Get_Relative_Deadline_Pragma (T : Node_Id) return Node_Id;
11805 -- Searches the task definition T for the first occurrence of the pragma
11806 -- Relative Deadline. The caller has ensured that the pragma is present
11807 -- in the task definition. Note that this routine cannot be implemented
11808 -- with the Rep Item chain mechanism since Relative_Deadline pragmas are
11809 -- not chained because their expansion into a procedure call statement
11810 -- would cause a break in the chain.
11812 ----------------------------------
11813 -- Get_Relative_Deadline_Pragma --
11814 ----------------------------------
11816 function Get_Relative_Deadline_Pragma (T : Node_Id) return Node_Id is
11817 N : Node_Id;
11819 begin
11820 N := First (Visible_Declarations (T));
11821 while Present (N) loop
11822 if Nkind (N) = N_Pragma
11823 and then Pragma_Name (N) = Name_Relative_Deadline
11824 then
11825 return N;
11826 end if;
11828 Next (N);
11829 end loop;
11831 N := First (Private_Declarations (T));
11832 while Present (N) loop
11833 if Nkind (N) = N_Pragma
11834 and then Pragma_Name (N) = Name_Relative_Deadline
11835 then
11836 return N;
11837 end if;
11839 Next (N);
11840 end loop;
11842 raise Program_Error;
11843 end Get_Relative_Deadline_Pragma;
11845 -- Start of processing for Expand_N_Task_Type_Declaration
11847 begin
11848 -- If already expanded, nothing to do
11850 if Present (Corresponding_Record_Type (Tasktyp)) then
11851 return;
11852 end if;
11854 -- Here we will do the expansion
11856 Rec_Decl := Build_Corresponding_Record (N, Tasktyp, Loc);
11858 Rec_Ent := Defining_Identifier (Rec_Decl);
11859 Cdecls := Component_Items (Component_List
11860 (Type_Definition (Rec_Decl)));
11862 Qualify_Entity_Names (N);
11864 -- First create the elaboration variable
11866 Elab_Decl :=
11867 Make_Object_Declaration (Loc,
11868 Defining_Identifier =>
11869 Make_Defining_Identifier (Sloc (Tasktyp),
11870 Chars => New_External_Name (Tasknm, 'E')),
11871 Aliased_Present => True,
11872 Object_Definition => New_Occurrence_Of (Standard_Boolean, Loc),
11873 Expression => New_Occurrence_Of (Standard_False, Loc));
11875 Insert_After (N, Elab_Decl);
11877 -- Next create the declaration of the size variable (tasknmZ)
11879 Set_Storage_Size_Variable (Tasktyp,
11880 Make_Defining_Identifier (Sloc (Tasktyp),
11881 Chars => New_External_Name (Tasknm, 'Z')));
11883 if Present (Taskdef)
11884 and then Has_Storage_Size_Pragma (Taskdef)
11885 and then
11886 Is_OK_Static_Expression
11887 (Expression
11888 (First (Pragma_Argument_Associations
11889 (Get_Rep_Pragma (TaskId, Name_Storage_Size)))))
11890 then
11891 Size_Decl :=
11892 Make_Object_Declaration (Loc,
11893 Defining_Identifier => Storage_Size_Variable (Tasktyp),
11894 Object_Definition =>
11895 New_Occurrence_Of (RTE (RE_Size_Type), Loc),
11896 Expression =>
11897 Convert_To (RTE (RE_Size_Type),
11898 Relocate_Node
11899 (Expression (First (Pragma_Argument_Associations
11900 (Get_Rep_Pragma
11901 (TaskId, Name_Storage_Size)))))));
11903 else
11904 Size_Decl :=
11905 Make_Object_Declaration (Loc,
11906 Defining_Identifier => Storage_Size_Variable (Tasktyp),
11907 Object_Definition =>
11908 New_Occurrence_Of (RTE (RE_Size_Type), Loc),
11909 Expression =>
11910 New_Occurrence_Of (RTE (RE_Unspecified_Size), Loc));
11911 end if;
11913 Insert_After (Elab_Decl, Size_Decl);
11915 -- Next build the rest of the corresponding record declaration. This is
11916 -- done last, since the corresponding record initialization procedure
11917 -- will reference the previously created entities.
11919 -- Fill in the component declarations -- first the _Task_Id field
11921 Append_To (Cdecls,
11922 Make_Component_Declaration (Loc,
11923 Defining_Identifier =>
11924 Make_Defining_Identifier (Loc, Name_uTask_Id),
11925 Component_Definition =>
11926 Make_Component_Definition (Loc,
11927 Aliased_Present => False,
11928 Subtype_Indication => New_Occurrence_Of (RTE (RO_ST_Task_Id),
11929 Loc))));
11931 -- Declare static ATCB (that is, created by the expander) if we are
11932 -- using the Restricted run time.
11934 if Restricted_Profile then
11935 Append_To (Cdecls,
11936 Make_Component_Declaration (Loc,
11937 Defining_Identifier =>
11938 Make_Defining_Identifier (Loc, Name_uATCB),
11940 Component_Definition =>
11941 Make_Component_Definition (Loc,
11942 Aliased_Present => True,
11943 Subtype_Indication => Make_Subtype_Indication (Loc,
11944 Subtype_Mark =>
11945 New_Occurrence_Of (RTE (RE_Ada_Task_Control_Block), Loc),
11947 Constraint =>
11948 Make_Index_Or_Discriminant_Constraint (Loc,
11949 Constraints =>
11950 New_List (Make_Integer_Literal (Loc, 0)))))));
11952 end if;
11954 -- Declare static stack (that is, created by the expander) if we are
11955 -- using the Restricted run time on a bare board configuration.
11957 if Restricted_Profile and then Preallocated_Stacks_On_Target then
11959 -- First we need to extract the appropriate stack size
11961 Ent_Stack := Make_Defining_Identifier (Loc, Name_uStack);
11963 if Present (Taskdef) and then Has_Storage_Size_Pragma (Taskdef) then
11964 declare
11965 Expr_N : constant Node_Id :=
11966 Expression (First (
11967 Pragma_Argument_Associations (
11968 Get_Rep_Pragma (TaskId, Name_Storage_Size))));
11969 Etyp : constant Entity_Id := Etype (Expr_N);
11970 P : constant Node_Id := Parent (Expr_N);
11972 begin
11973 -- The stack is defined inside the corresponding record.
11974 -- Therefore if the size of the stack is set by means of
11975 -- a discriminant, we must reference the discriminant of the
11976 -- corresponding record type.
11978 if Nkind (Expr_N) in N_Has_Entity
11979 and then Present (Discriminal_Link (Entity (Expr_N)))
11980 then
11981 Task_Size :=
11982 New_Occurrence_Of
11983 (CR_Discriminant (Discriminal_Link (Entity (Expr_N))),
11984 Loc);
11985 Set_Parent (Task_Size, P);
11986 Set_Etype (Task_Size, Etyp);
11987 Set_Analyzed (Task_Size);
11989 else
11990 Task_Size := New_Copy_Tree (Expr_N);
11991 end if;
11992 end;
11994 else
11995 Task_Size :=
11996 New_Occurrence_Of (RTE (RE_Default_Stack_Size), Loc);
11997 end if;
11999 Decl_Stack := Make_Component_Declaration (Loc,
12000 Defining_Identifier => Ent_Stack,
12002 Component_Definition =>
12003 Make_Component_Definition (Loc,
12004 Aliased_Present => True,
12005 Subtype_Indication => Make_Subtype_Indication (Loc,
12006 Subtype_Mark =>
12007 New_Occurrence_Of (RTE (RE_Storage_Array), Loc),
12009 Constraint =>
12010 Make_Index_Or_Discriminant_Constraint (Loc,
12011 Constraints => New_List (Make_Range (Loc,
12012 Low_Bound => Make_Integer_Literal (Loc, 1),
12013 High_Bound => Convert_To (RTE (RE_Storage_Offset),
12014 Task_Size)))))));
12016 Append_To (Cdecls, Decl_Stack);
12018 -- The appropriate alignment for the stack is ensured by the run-time
12019 -- code in charge of task creation.
12021 end if;
12023 -- Declare a static secondary stack if the conditions for a statically
12024 -- generated stack are met.
12026 if Create_Secondary_Stack_For_Task (TaskId) then
12027 declare
12028 Size_Expr : constant Node_Id :=
12029 Expression (First (
12030 Pragma_Argument_Associations (
12031 Get_Rep_Pragma (TaskId,
12032 Name_Secondary_Stack_Size))));
12034 Stack_Size : Node_Id;
12036 begin
12037 -- The secondary stack is defined inside the corresponding
12038 -- record. Therefore if the size of the stack is set by means
12039 -- of a discriminant, we must reference the discriminant of the
12040 -- corresponding record type.
12042 if Nkind (Size_Expr) in N_Has_Entity
12043 and then Present (Discriminal_Link (Entity (Size_Expr)))
12044 then
12045 Stack_Size :=
12046 New_Occurrence_Of
12047 (CR_Discriminant (Discriminal_Link (Entity (Size_Expr))),
12048 Loc);
12049 Set_Parent (Stack_Size, Parent (Size_Expr));
12050 Set_Etype (Stack_Size, Etype (Size_Expr));
12051 Set_Analyzed (Stack_Size);
12053 else
12054 Stack_Size := New_Copy_Tree (Size_Expr);
12055 end if;
12057 -- Create the secondary stack for the task
12059 Decl_SS :=
12060 Make_Component_Declaration (Loc,
12061 Defining_Identifier =>
12062 Make_Defining_Identifier (Loc, Name_uSecondary_Stack),
12063 Component_Definition =>
12064 Make_Component_Definition (Loc,
12065 Aliased_Present => True,
12066 Subtype_Indication =>
12067 Make_Subtype_Indication (Loc,
12068 Subtype_Mark =>
12069 New_Occurrence_Of (RTE (RE_SS_Stack), Loc),
12070 Constraint =>
12071 Make_Index_Or_Discriminant_Constraint (Loc,
12072 Constraints => New_List (
12073 Convert_To (RTE (RE_Size_Type),
12074 Stack_Size))))));
12076 Append_To (Cdecls, Decl_SS);
12077 end;
12078 end if;
12080 -- Add components for entry families
12082 Collect_Entry_Families (Loc, Cdecls, Size_Decl, Tasktyp);
12084 -- Add the _Priority component if a Interrupt_Priority or Priority rep
12085 -- item is present.
12087 if Has_Rep_Item (TaskId, Name_Priority, Check_Parents => False) then
12088 Append_To (Cdecls,
12089 Make_Component_Declaration (Loc,
12090 Defining_Identifier =>
12091 Make_Defining_Identifier (Loc, Name_uPriority),
12092 Component_Definition =>
12093 Make_Component_Definition (Loc,
12094 Aliased_Present => False,
12095 Subtype_Indication =>
12096 New_Occurrence_Of (Standard_Integer, Loc))));
12097 end if;
12099 -- Add the _Size component if a Storage_Size pragma is present
12101 if Present (Taskdef) and then Has_Storage_Size_Pragma (Taskdef) then
12102 Append_To (Cdecls,
12103 Make_Component_Declaration (Loc,
12104 Defining_Identifier =>
12105 Make_Defining_Identifier (Loc, Name_uSize),
12107 Component_Definition =>
12108 Make_Component_Definition (Loc,
12109 Aliased_Present => False,
12110 Subtype_Indication =>
12111 New_Occurrence_Of (RTE (RE_Size_Type), Loc)),
12113 Expression =>
12114 Convert_To (RTE (RE_Size_Type),
12115 New_Copy_Tree (
12116 Expression (First (
12117 Pragma_Argument_Associations (
12118 Get_Rep_Pragma (TaskId, Name_Storage_Size))))))));
12119 end if;
12121 -- Add the _Secondary_Stack_Size component if a Secondary_Stack_Size
12122 -- pragma is present.
12124 if Has_Rep_Pragma
12125 (TaskId, Name_Secondary_Stack_Size, Check_Parents => False)
12126 then
12127 Append_To (Cdecls,
12128 Make_Component_Declaration (Loc,
12129 Defining_Identifier =>
12130 Make_Defining_Identifier (Loc, Name_uSecondary_Stack_Size),
12132 Component_Definition =>
12133 Make_Component_Definition (Loc,
12134 Aliased_Present => False,
12135 Subtype_Indication =>
12136 New_Occurrence_Of (RTE (RE_Size_Type), Loc))));
12137 end if;
12139 -- Add the _Task_Info component if a Task_Info pragma is present
12141 if Has_Rep_Pragma (TaskId, Name_Task_Info, Check_Parents => False) then
12142 Append_To (Cdecls,
12143 Make_Component_Declaration (Loc,
12144 Defining_Identifier =>
12145 Make_Defining_Identifier (Loc, Name_uTask_Info),
12147 Component_Definition =>
12148 Make_Component_Definition (Loc,
12149 Aliased_Present => False,
12150 Subtype_Indication =>
12151 New_Occurrence_Of (RTE (RE_Task_Info_Type), Loc)),
12153 Expression => New_Copy (
12154 Expression (First (
12155 Pragma_Argument_Associations (
12156 Get_Rep_Pragma
12157 (TaskId, Name_Task_Info, Check_Parents => False)))))));
12158 end if;
12160 -- Add the _CPU component if a CPU rep item is present
12162 if Has_Rep_Item (TaskId, Name_CPU, Check_Parents => False) then
12163 Append_To (Cdecls,
12164 Make_Component_Declaration (Loc,
12165 Defining_Identifier =>
12166 Make_Defining_Identifier (Loc, Name_uCPU),
12168 Component_Definition =>
12169 Make_Component_Definition (Loc,
12170 Aliased_Present => False,
12171 Subtype_Indication =>
12172 New_Occurrence_Of (RTE (RE_CPU_Range), Loc))));
12173 end if;
12175 -- Add the _Relative_Deadline component if a Relative_Deadline pragma is
12176 -- present. If we are using a restricted run time this component will
12177 -- not be added (deadlines are not allowed by the Ravenscar profile),
12178 -- unless the task dispatching policy is EDF (for GNAT_Ravenscar_EDF
12179 -- profile).
12181 if (not Restricted_Profile or else Task_Dispatching_Policy = 'E')
12182 and then Present (Taskdef)
12183 and then Has_Relative_Deadline_Pragma (Taskdef)
12184 then
12185 Append_To (Cdecls,
12186 Make_Component_Declaration (Loc,
12187 Defining_Identifier =>
12188 Make_Defining_Identifier (Loc, Name_uRelative_Deadline),
12190 Component_Definition =>
12191 Make_Component_Definition (Loc,
12192 Aliased_Present => False,
12193 Subtype_Indication =>
12194 New_Occurrence_Of (RTE (RE_Time_Span), Loc)),
12196 Expression =>
12197 Convert_To (RTE (RE_Time_Span),
12198 New_Copy_Tree (
12199 Expression (First (
12200 Pragma_Argument_Associations (
12201 Get_Relative_Deadline_Pragma (Taskdef))))))));
12202 end if;
12204 -- Add the _Dispatching_Domain component if a Dispatching_Domain rep
12205 -- item is present. If we are using a restricted run time this component
12206 -- will not be added (dispatching domains are not allowed by the
12207 -- Ravenscar profile).
12209 if not Restricted_Profile
12210 and then
12211 Has_Rep_Item
12212 (TaskId, Name_Dispatching_Domain, Check_Parents => False)
12213 then
12214 Append_To (Cdecls,
12215 Make_Component_Declaration (Loc,
12216 Defining_Identifier =>
12217 Make_Defining_Identifier (Loc, Name_uDispatching_Domain),
12219 Component_Definition =>
12220 Make_Component_Definition (Loc,
12221 Aliased_Present => False,
12222 Subtype_Indication =>
12223 New_Occurrence_Of
12224 (RTE (RE_Dispatching_Domain_Access), Loc))));
12225 end if;
12227 Insert_After (Size_Decl, Rec_Decl);
12229 -- Analyze the record declaration immediately after construction,
12230 -- because the initialization procedure is needed for single task
12231 -- declarations before the next entity is analyzed.
12233 Analyze (Rec_Decl);
12235 -- Create the declaration of the task body procedure
12237 Proc_Spec := Build_Task_Proc_Specification (Tasktyp);
12238 Body_Decl :=
12239 Make_Subprogram_Declaration (Loc,
12240 Specification => Proc_Spec);
12241 Set_Is_Task_Body_Procedure (Body_Decl);
12243 Insert_After (Rec_Decl, Body_Decl);
12245 -- The subprogram does not comes from source, so we have to indicate the
12246 -- need for debugging information explicitly.
12248 if Comes_From_Source (Original_Node (N)) then
12249 Set_Debug_Info_Needed (Defining_Entity (Proc_Spec));
12250 end if;
12252 -- Ada 2005 (AI-345): Construct the primitive entry wrapper specs before
12253 -- the corresponding record has been frozen.
12255 if Ada_Version >= Ada_2005 then
12256 Build_Wrapper_Specs (Loc, Tasktyp, Rec_Decl);
12257 end if;
12259 -- Ada 2005 (AI-345): We must defer freezing to allow further
12260 -- declaration of primitive subprograms covering task interfaces
12262 if Ada_Version <= Ada_95 then
12264 -- Now we can freeze the corresponding record. This needs manually
12265 -- freezing, since it is really part of the task type, and the task
12266 -- type is frozen at this stage. We of course need the initialization
12267 -- procedure for this corresponding record type and we won't get it
12268 -- in time if we don't freeze now.
12270 Insert_List_After (Body_Decl, List => Freeze_Entity (Rec_Ent, N));
12271 end if;
12273 -- Complete the expansion of access types to the current task type, if
12274 -- any were declared.
12276 Expand_Previous_Access_Type (Tasktyp);
12278 -- Create wrappers for entries that have contract cases, preconditions
12279 -- and postconditions.
12281 declare
12282 Ent : Entity_Id;
12284 begin
12285 Ent := First_Entity (Tasktyp);
12286 while Present (Ent) loop
12287 if Ekind (Ent) in E_Entry | E_Entry_Family then
12288 Build_Entry_Contract_Wrapper (Ent, N);
12289 end if;
12291 Next_Entity (Ent);
12292 end loop;
12293 end;
12294 end Expand_N_Task_Type_Declaration;
12296 -------------------------------
12297 -- Expand_N_Timed_Entry_Call --
12298 -------------------------------
12300 -- A timed entry call in normal case is not implemented using ATC mechanism
12301 -- anymore for efficiency reason.
12303 -- select
12304 -- T.E;
12305 -- S1;
12306 -- or
12307 -- delay D;
12308 -- S2;
12309 -- end select;
12311 -- is expanded as follows:
12313 -- 1) When T.E is a task entry_call;
12315 -- declare
12316 -- B : Boolean;
12317 -- X : Task_Entry_Index := <entry index>;
12318 -- DX : Duration := To_Duration (D);
12319 -- M : Delay_Mode := <discriminant>;
12320 -- P : parms := (parm, parm, parm);
12322 -- begin
12323 -- Timed_Protected_Entry_Call
12324 -- (<acceptor-task>, X, P'Address, DX, M, B);
12325 -- if B then
12326 -- S1;
12327 -- else
12328 -- S2;
12329 -- end if;
12330 -- end;
12332 -- 2) When T.E is a protected entry_call;
12334 -- declare
12335 -- B : Boolean;
12336 -- X : Protected_Entry_Index := <entry index>;
12337 -- DX : Duration := To_Duration (D);
12338 -- M : Delay_Mode := <discriminant>;
12339 -- P : parms := (parm, parm, parm);
12341 -- begin
12342 -- Timed_Protected_Entry_Call
12343 -- (<object>'unchecked_access, X, P'Address, DX, M, B);
12344 -- if B then
12345 -- S1;
12346 -- else
12347 -- S2;
12348 -- end if;
12349 -- end;
12351 -- 3) Ada 2005 (AI-345): When T.E is a dispatching procedure call, there
12352 -- is no delay and the triggering statements are executed. We first
12353 -- determine the kind of the triggering call and then execute a
12354 -- synchronized operation or a direct call.
12356 -- declare
12357 -- B : Boolean := False;
12358 -- C : Ada.Tags.Prim_Op_Kind;
12359 -- DX : Duration := To_Duration (D)
12360 -- K : Ada.Tags.Tagged_Kind :=
12361 -- Ada.Tags.Get_Tagged_Kind (Ada.Tags.Tag (<object>));
12362 -- M : Integer :=...;
12363 -- P : Parameters := (Param1 .. ParamN);
12364 -- S : Integer;
12366 -- begin
12367 -- if K = Ada.Tags.TK_Limited_Tagged
12368 -- or else K = Ada.Tags.TK_Tagged
12369 -- then
12370 -- <dispatching-call>;
12371 -- B := True;
12373 -- else
12374 -- S :=
12375 -- Ada.Tags.Get_Offset_Index
12376 -- (Ada.Tags.Tag (<object>), DT_Position (<dispatching-call>));
12378 -- _Disp_Timed_Select (<object>, S, P'Address, DX, M, C, B);
12380 -- if C = POK_Protected_Entry
12381 -- or else C = POK_Task_Entry
12382 -- then
12383 -- Param1 := P.Param1;
12384 -- ...
12385 -- ParamN := P.ParamN;
12386 -- end if;
12388 -- if B then
12389 -- if C = POK_Procedure
12390 -- or else C = POK_Protected_Procedure
12391 -- or else C = POK_Task_Procedure
12392 -- then
12393 -- <dispatching-call>;
12394 -- end if;
12395 -- end if;
12396 -- end if;
12398 -- if B then
12399 -- <triggering-statements>
12400 -- else
12401 -- <timed-statements>
12402 -- end if;
12403 -- end;
12405 -- The triggering statement and the sequence of timed statements have not
12406 -- been analyzed yet (see Analyzed_Timed_Entry_Call), but they may contain
12407 -- global references if within an instantiation.
12409 procedure Expand_N_Timed_Entry_Call (N : Node_Id) is
12410 Actuals : List_Id;
12411 Blk_Typ : Entity_Id;
12412 Call : Node_Id;
12413 Call_Ent : Entity_Id;
12414 Conc_Typ_Stmts : List_Id;
12415 Concval : Node_Id := Empty; -- init to avoid warning
12416 D_Alt : constant Node_Id := Delay_Alternative (N);
12417 D_Conv : Node_Id;
12418 D_Disc : Node_Id;
12419 D_Stat : Node_Id := Delay_Statement (D_Alt);
12420 D_Stats : List_Id;
12421 D_Type : Entity_Id;
12422 Decls : List_Id;
12423 Dummy : Node_Id;
12424 E_Alt : constant Node_Id := Entry_Call_Alternative (N);
12425 E_Call : Node_Id := Entry_Call_Statement (E_Alt);
12426 E_Stats : List_Id;
12427 Ename : Node_Id;
12428 Formals : List_Id;
12429 Index : Node_Id;
12430 Is_Disp_Select : Boolean;
12431 Lim_Typ_Stmts : List_Id;
12432 Loc : constant Source_Ptr := Sloc (D_Stat);
12433 N_Stats : List_Id;
12434 Obj : Entity_Id;
12435 Param : Node_Id;
12436 Params : List_Id;
12437 Stmt : Node_Id;
12438 Stmts : List_Id;
12439 Unpack : List_Id;
12441 B : Entity_Id; -- Call status flag
12442 C : Entity_Id; -- Call kind
12443 D : Entity_Id; -- Delay
12444 K : Entity_Id; -- Tagged kind
12445 M : Entity_Id; -- Delay mode
12446 P : Entity_Id; -- Parameter block
12447 S : Entity_Id; -- Primitive operation slot
12449 -- Start of processing for Expand_N_Timed_Entry_Call
12451 begin
12452 -- Under the Ravenscar profile, timed entry calls are excluded. An error
12453 -- was already reported on spec, so do not attempt to expand the call.
12455 if Restriction_Active (No_Select_Statements) then
12456 return;
12457 end if;
12459 Process_Statements_For_Controlled_Objects (E_Alt);
12460 Process_Statements_For_Controlled_Objects (D_Alt);
12462 Ensure_Statement_Present (Sloc (D_Stat), D_Alt);
12464 -- Retrieve E_Stats and D_Stats now because the finalization machinery
12465 -- may wrap them in blocks.
12467 E_Stats := Statements (E_Alt);
12468 D_Stats := Statements (D_Alt);
12470 -- The arguments in the call may require dynamic allocation, and the
12471 -- call statement may have been transformed into a block. The block
12472 -- may contain additional declarations for internal entities, and the
12473 -- original call is found by sequential search.
12475 if Nkind (E_Call) = N_Block_Statement then
12476 E_Call := First (Statements (Handled_Statement_Sequence (E_Call)));
12477 while Nkind (E_Call) not in
12478 N_Procedure_Call_Statement | N_Entry_Call_Statement
12479 loop
12480 Next (E_Call);
12481 end loop;
12482 end if;
12484 Is_Disp_Select :=
12485 Ada_Version >= Ada_2005
12486 and then Nkind (E_Call) = N_Procedure_Call_Statement;
12488 if Is_Disp_Select then
12489 Extract_Dispatching_Call (E_Call, Call_Ent, Obj, Actuals, Formals);
12490 Decls := New_List;
12492 Stmts := New_List;
12494 -- Generate:
12495 -- B : Boolean := False;
12497 B := Build_B (Loc, Decls);
12499 -- Generate:
12500 -- C : Ada.Tags.Prim_Op_Kind;
12502 C := Build_C (Loc, Decls);
12504 -- Because the analysis of all statements was disabled, manually
12505 -- analyze the delay statement.
12507 Analyze (D_Stat);
12508 D_Stat := Original_Node (D_Stat);
12510 else
12511 -- Build an entry call using Simple_Entry_Call
12513 Extract_Entry (E_Call, Concval, Ename, Index);
12514 Build_Simple_Entry_Call (E_Call, Concval, Ename, Index);
12516 Decls := Declarations (E_Call);
12517 Stmts := Statements (Handled_Statement_Sequence (E_Call));
12519 if No (Decls) then
12520 Decls := New_List;
12521 end if;
12523 -- Generate:
12524 -- B : Boolean;
12526 B := Make_Defining_Identifier (Loc, Name_uB);
12528 Prepend_To (Decls,
12529 Make_Object_Declaration (Loc,
12530 Defining_Identifier => B,
12531 Object_Definition =>
12532 New_Occurrence_Of (Standard_Boolean, Loc)));
12533 end if;
12535 -- Duration and mode processing
12537 D_Type := Base_Type (Etype (Expression (D_Stat)));
12539 -- Use the type of the delay expression (Calendar or Real_Time) to
12540 -- generate the appropriate conversion.
12542 if Nkind (D_Stat) = N_Delay_Relative_Statement then
12543 D_Disc := Make_Integer_Literal (Loc, 0);
12544 D_Conv := Relocate_Node (Expression (D_Stat));
12546 elsif Is_RTE (D_Type, RO_CA_Time) then
12547 D_Disc := Make_Integer_Literal (Loc, 1);
12548 D_Conv :=
12549 Make_Function_Call (Loc,
12550 Name => New_Occurrence_Of (RTE (RO_CA_To_Duration), Loc),
12551 Parameter_Associations =>
12552 New_List (New_Copy (Expression (D_Stat))));
12554 else pragma Assert (Is_RTE (D_Type, RO_RT_Time));
12555 D_Disc := Make_Integer_Literal (Loc, 2);
12556 D_Conv :=
12557 Make_Function_Call (Loc,
12558 Name => New_Occurrence_Of (RTE (RO_RT_To_Duration), Loc),
12559 Parameter_Associations =>
12560 New_List (New_Copy (Expression (D_Stat))));
12561 end if;
12563 D := Make_Temporary (Loc, 'D');
12565 -- Generate:
12566 -- D : Duration;
12568 Append_To (Decls,
12569 Make_Object_Declaration (Loc,
12570 Defining_Identifier => D,
12571 Object_Definition => New_Occurrence_Of (Standard_Duration, Loc)));
12573 M := Make_Temporary (Loc, 'M');
12575 -- Generate:
12576 -- M : Integer := (0 | 1 | 2);
12578 Append_To (Decls,
12579 Make_Object_Declaration (Loc,
12580 Defining_Identifier => M,
12581 Object_Definition => New_Occurrence_Of (Standard_Integer, Loc),
12582 Expression => D_Disc));
12584 -- Parameter block processing
12586 -- Manually create the parameter block for dispatching calls. In the
12587 -- case of entries, the block has already been created during the call
12588 -- to Build_Simple_Entry_Call.
12590 if Is_Disp_Select then
12592 -- Compute the delay at this stage because the evaluation of its
12593 -- expression must not occur earlier (see ACVC C97302A).
12595 Append_To (Stmts,
12596 Make_Assignment_Statement (Loc,
12597 Name => New_Occurrence_Of (D, Loc),
12598 Expression => D_Conv));
12600 -- Tagged kind processing, generate:
12601 -- K : Ada.Tags.Tagged_Kind :=
12602 -- Ada.Tags.Get_Tagged_Kind (Ada.Tags.Tag <object>));
12604 K := Build_K (Loc, Decls, Obj);
12606 Blk_Typ := Build_Parameter_Block (Loc, Actuals, Formals, Decls);
12607 P :=
12608 Parameter_Block_Pack (Loc, Blk_Typ, Actuals, Formals, Decls, Stmts);
12610 -- Dispatch table slot processing, generate:
12611 -- S : Integer;
12613 S := Build_S (Loc, Decls);
12615 -- Generate:
12616 -- S := Ada.Tags.Get_Offset_Index
12617 -- (Ada.Tags.Tag (<object>), DT_Position (Call_Ent));
12619 Conc_Typ_Stmts :=
12620 New_List (Build_S_Assignment (Loc, S, Obj, Call_Ent));
12622 -- Generate:
12623 -- _Disp_Timed_Select (<object>, S, P'Address, D, M, C, B);
12625 -- where Obj is the controlling formal parameter, S is the dispatch
12626 -- table slot number of the dispatching operation, P is the wrapped
12627 -- parameter block, D is the duration, M is the duration mode, C is
12628 -- the call kind and B is the call status.
12630 Params := New_List;
12632 Append_To (Params, New_Copy_Tree (Obj));
12633 Append_To (Params, New_Occurrence_Of (S, Loc));
12634 Append_To (Params,
12635 Make_Attribute_Reference (Loc,
12636 Prefix => New_Occurrence_Of (P, Loc),
12637 Attribute_Name => Name_Address));
12638 Append_To (Params, New_Occurrence_Of (D, Loc));
12639 Append_To (Params, New_Occurrence_Of (M, Loc));
12640 Append_To (Params, New_Occurrence_Of (C, Loc));
12641 Append_To (Params, New_Occurrence_Of (B, Loc));
12643 Append_To (Conc_Typ_Stmts,
12644 Make_Procedure_Call_Statement (Loc,
12645 Name =>
12646 New_Occurrence_Of
12647 (Find_Prim_Op
12648 (Etype (Etype (Obj)), Name_uDisp_Timed_Select), Loc),
12649 Parameter_Associations => Params));
12651 -- Generate:
12652 -- if C = POK_Protected_Entry
12653 -- or else C = POK_Task_Entry
12654 -- then
12655 -- Param1 := P.Param1;
12656 -- ...
12657 -- ParamN := P.ParamN;
12658 -- end if;
12660 Unpack := Parameter_Block_Unpack (Loc, P, Actuals, Formals);
12662 -- Generate the if statement only when the packed parameters need
12663 -- explicit assignments to their corresponding actuals.
12665 if Present (Unpack) then
12666 Append_To (Conc_Typ_Stmts,
12667 Make_Implicit_If_Statement (N,
12669 Condition =>
12670 Make_Or_Else (Loc,
12671 Left_Opnd =>
12672 Make_Op_Eq (Loc,
12673 Left_Opnd => New_Occurrence_Of (C, Loc),
12674 Right_Opnd =>
12675 New_Occurrence_Of
12676 (RTE (RE_POK_Protected_Entry), Loc)),
12678 Right_Opnd =>
12679 Make_Op_Eq (Loc,
12680 Left_Opnd => New_Occurrence_Of (C, Loc),
12681 Right_Opnd =>
12682 New_Occurrence_Of (RTE (RE_POK_Task_Entry), Loc))),
12684 Then_Statements => Unpack));
12685 end if;
12687 -- Generate:
12689 -- if B then
12690 -- if C = POK_Procedure
12691 -- or else C = POK_Protected_Procedure
12692 -- or else C = POK_Task_Procedure
12693 -- then
12694 -- <dispatching-call>
12695 -- end if;
12696 -- end if;
12698 N_Stats := New_List (
12699 Make_Implicit_If_Statement (N,
12700 Condition =>
12701 Make_Or_Else (Loc,
12702 Left_Opnd =>
12703 Make_Op_Eq (Loc,
12704 Left_Opnd => New_Occurrence_Of (C, Loc),
12705 Right_Opnd =>
12706 New_Occurrence_Of (RTE (RE_POK_Procedure), Loc)),
12708 Right_Opnd =>
12709 Make_Or_Else (Loc,
12710 Left_Opnd =>
12711 Make_Op_Eq (Loc,
12712 Left_Opnd => New_Occurrence_Of (C, Loc),
12713 Right_Opnd =>
12714 New_Occurrence_Of (RTE (
12715 RE_POK_Protected_Procedure), Loc)),
12716 Right_Opnd =>
12717 Make_Op_Eq (Loc,
12718 Left_Opnd => New_Occurrence_Of (C, Loc),
12719 Right_Opnd =>
12720 New_Occurrence_Of
12721 (RTE (RE_POK_Task_Procedure), Loc)))),
12723 Then_Statements => New_List (E_Call)));
12725 Append_To (Conc_Typ_Stmts,
12726 Make_Implicit_If_Statement (N,
12727 Condition => New_Occurrence_Of (B, Loc),
12728 Then_Statements => N_Stats));
12730 -- Generate:
12731 -- <dispatching-call>;
12732 -- B := True;
12734 Lim_Typ_Stmts :=
12735 New_List (New_Copy_Tree (E_Call),
12736 Make_Assignment_Statement (Loc,
12737 Name => New_Occurrence_Of (B, Loc),
12738 Expression => New_Occurrence_Of (Standard_True, Loc)));
12740 -- Generate:
12741 -- if K = Ada.Tags.TK_Limited_Tagged
12742 -- or else K = Ada.Tags.TK_Tagged
12743 -- then
12744 -- Lim_Typ_Stmts
12745 -- else
12746 -- Conc_Typ_Stmts
12747 -- end if;
12749 Append_To (Stmts,
12750 Make_Implicit_If_Statement (N,
12751 Condition => Build_Dispatching_Tag_Check (K, N),
12752 Then_Statements => Lim_Typ_Stmts,
12753 Else_Statements => Conc_Typ_Stmts));
12755 -- Generate:
12757 -- if B then
12758 -- <triggering-statements>
12759 -- else
12760 -- <timed-statements>
12761 -- end if;
12763 Append_To (Stmts,
12764 Make_Implicit_If_Statement (N,
12765 Condition => New_Occurrence_Of (B, Loc),
12766 Then_Statements => E_Stats,
12767 Else_Statements => D_Stats));
12769 else
12770 -- Simple case of a nondispatching trigger. Skip assignments to
12771 -- temporaries created for in-out parameters.
12773 -- This makes unwarranted assumptions about the shape of the expanded
12774 -- tree for the call, and should be cleaned up ???
12776 Stmt := First (Stmts);
12777 while Nkind (Stmt) /= N_Procedure_Call_Statement loop
12778 Next (Stmt);
12779 end loop;
12781 -- Compute the delay at this stage because the evaluation of
12782 -- its expression must not occur earlier (see ACVC C97302A).
12784 Insert_Before (Stmt,
12785 Make_Assignment_Statement (Loc,
12786 Name => New_Occurrence_Of (D, Loc),
12787 Expression => D_Conv));
12789 Call := Stmt;
12790 Params := Parameter_Associations (Call);
12792 -- For a protected type, we build a Timed_Protected_Entry_Call
12794 if Is_Protected_Type (Etype (Concval)) then
12796 -- Create a new call statement
12798 Param := First (Params);
12799 while Present (Param)
12800 and then not Is_RTE (Etype (Param), RE_Call_Modes)
12801 loop
12802 Next (Param);
12803 end loop;
12805 Dummy := Remove_Next (Next (Param));
12807 -- Remove garbage is following the Cancel_Param if present
12809 Dummy := Next (Param);
12811 -- Remove the mode of the Protected_Entry_Call call, then remove
12812 -- the Communication_Block of the Protected_Entry_Call call, and
12813 -- finally add Duration and a Delay_Mode parameter
12815 pragma Assert (Present (Param));
12816 Rewrite (Param, New_Occurrence_Of (D, Loc));
12818 Rewrite (Dummy, New_Occurrence_Of (M, Loc));
12820 -- Add a Boolean flag for successful entry call
12822 Append_To (Params, New_Occurrence_Of (B, Loc));
12824 case Corresponding_Runtime_Package (Etype (Concval)) is
12825 when System_Tasking_Protected_Objects_Entries =>
12826 Rewrite (Call,
12827 Make_Procedure_Call_Statement (Loc,
12828 Name =>
12829 New_Occurrence_Of
12830 (RTE (RE_Timed_Protected_Entry_Call), Loc),
12831 Parameter_Associations => Params));
12833 when others =>
12834 raise Program_Error;
12835 end case;
12837 -- For the task case, build a Timed_Task_Entry_Call
12839 else
12840 -- Create a new call statement
12842 Append_To (Params, New_Occurrence_Of (D, Loc));
12843 Append_To (Params, New_Occurrence_Of (M, Loc));
12844 Append_To (Params, New_Occurrence_Of (B, Loc));
12846 Rewrite (Call,
12847 Make_Procedure_Call_Statement (Loc,
12848 Name =>
12849 New_Occurrence_Of (RTE (RE_Timed_Task_Entry_Call), Loc),
12850 Parameter_Associations => Params));
12851 end if;
12853 Append_To (Stmts,
12854 Make_Implicit_If_Statement (N,
12855 Condition => New_Occurrence_Of (B, Loc),
12856 Then_Statements => E_Stats,
12857 Else_Statements => D_Stats));
12858 end if;
12860 Rewrite (N,
12861 Make_Block_Statement (Loc,
12862 Declarations => Decls,
12863 Handled_Statement_Sequence =>
12864 Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
12866 Analyze (N);
12868 -- Some items in Decls used to be in the N_Block in E_Call that is
12869 -- constructed in Expand_Entry_Call, and are now in the new Block
12870 -- into which N has been rewritten. Adjust their scopes to reflect that.
12872 if Nkind (E_Call) = N_Block_Statement then
12873 Obj := First_Entity (Entity (Identifier (E_Call)));
12874 while Present (Obj) loop
12875 Set_Scope (Obj, Entity (Identifier (N)));
12876 Next_Entity (Obj);
12877 end loop;
12878 end if;
12880 Reset_Scopes_To (N, Entity (Identifier (N)));
12881 end Expand_N_Timed_Entry_Call;
12883 ----------------------------------------
12884 -- Expand_Protected_Body_Declarations --
12885 ----------------------------------------
12887 procedure Expand_Protected_Body_Declarations
12888 (N : Node_Id;
12889 Spec_Id : Entity_Id)
12891 begin
12892 if No_Run_Time_Mode then
12893 Error_Msg_CRT ("protected body", N);
12894 return;
12896 elsif Expander_Active then
12898 -- Associate discriminals with the first subprogram or entry body to
12899 -- be expanded.
12901 if Present (First_Protected_Operation (Declarations (N))) then
12902 Set_Discriminals (Parent (Spec_Id));
12903 end if;
12904 end if;
12905 end Expand_Protected_Body_Declarations;
12907 -------------------------
12908 -- External_Subprogram --
12909 -------------------------
12911 function External_Subprogram (E : Entity_Id) return Entity_Id is
12912 Subp : constant Entity_Id := Protected_Body_Subprogram (E);
12914 begin
12915 -- The internal and external subprograms follow each other on the entity
12916 -- chain. Note that previously private operations had no separate
12917 -- external subprogram. We now create one in all cases, because a
12918 -- private operation may actually appear in an external call, through
12919 -- a 'Access reference used for a callback.
12921 -- If the operation is a function that returns an anonymous access type,
12922 -- the corresponding itype appears before the operation, and must be
12923 -- skipped.
12925 -- This mechanism is fragile, there should be a real link between the
12926 -- two versions of the operation, but there is no place to put it ???
12928 if Is_Access_Type (Next_Entity (Subp)) then
12929 return Next_Entity (Next_Entity (Subp));
12930 else
12931 return Next_Entity (Subp);
12932 end if;
12933 end External_Subprogram;
12935 ------------------------------
12936 -- Extract_Dispatching_Call --
12937 ------------------------------
12939 procedure Extract_Dispatching_Call
12940 (N : Node_Id;
12941 Call_Ent : out Entity_Id;
12942 Object : out Entity_Id;
12943 Actuals : out List_Id;
12944 Formals : out List_Id)
12946 Call_Nam : Node_Id;
12948 begin
12949 pragma Assert (Nkind (N) = N_Procedure_Call_Statement);
12951 if Present (Original_Node (N)) then
12952 Call_Nam := Name (Original_Node (N));
12953 else
12954 Call_Nam := Name (N);
12955 end if;
12957 -- Retrieve the name of the dispatching procedure. It contains the
12958 -- dispatch table slot number.
12960 loop
12961 case Nkind (Call_Nam) is
12962 when N_Identifier =>
12963 exit;
12965 when N_Selected_Component =>
12966 Call_Nam := Selector_Name (Call_Nam);
12968 when others =>
12969 raise Program_Error;
12970 end case;
12971 end loop;
12973 Actuals := Parameter_Associations (N);
12974 Call_Ent := Entity (Call_Nam);
12975 Formals := Parameter_Specifications (Parent (Call_Ent));
12976 Object := First (Actuals);
12978 if Present (Original_Node (Object)) then
12979 Object := Original_Node (Object);
12980 end if;
12982 -- If the type of the dispatching object is an access type then return
12983 -- an explicit dereference of a copy of the object, and note that this
12984 -- is the controlling actual of the call.
12986 if Is_Access_Type (Etype (Object)) then
12987 Object :=
12988 Make_Explicit_Dereference (Sloc (N), New_Copy_Tree (Object));
12989 Analyze (Object);
12990 Set_Is_Controlling_Actual (Object);
12991 end if;
12992 end Extract_Dispatching_Call;
12994 -------------------
12995 -- Extract_Entry --
12996 -------------------
12998 procedure Extract_Entry
12999 (N : Node_Id;
13000 Concval : out Node_Id;
13001 Ename : out Node_Id;
13002 Index : out Node_Id)
13004 Nam : constant Node_Id := Name (N);
13006 begin
13007 -- For a simple entry, the name is a selected component, with the
13008 -- prefix being the task value, and the selector being the entry.
13010 if Nkind (Nam) = N_Selected_Component then
13011 Concval := Prefix (Nam);
13012 Ename := Selector_Name (Nam);
13013 Index := Empty;
13015 -- For a member of an entry family, the name is an indexed component
13016 -- where the prefix is a selected component, whose prefix in turn is
13017 -- the task value, and whose selector is the entry family. The single
13018 -- expression in the expressions list of the indexed component is the
13019 -- subscript for the family.
13021 else pragma Assert (Nkind (Nam) = N_Indexed_Component);
13022 Concval := Prefix (Prefix (Nam));
13023 Ename := Selector_Name (Prefix (Nam));
13024 Index := First (Expressions (Nam));
13025 end if;
13027 -- Through indirection, the type may actually be a limited view of a
13028 -- concurrent type. When compiling a call, the non-limited view of the
13029 -- type is visible.
13031 if From_Limited_With (Etype (Concval)) then
13032 Set_Etype (Concval, Non_Limited_View (Etype (Concval)));
13033 end if;
13034 end Extract_Entry;
13036 -------------------
13037 -- Family_Offset --
13038 -------------------
13040 function Family_Offset
13041 (Loc : Source_Ptr;
13042 Hi : Node_Id;
13043 Lo : Node_Id;
13044 Ttyp : Entity_Id;
13045 Cap : Boolean) return Node_Id
13047 Ityp : Entity_Id;
13048 Real_Hi : Node_Id;
13049 Real_Lo : Node_Id;
13051 function Convert_Discriminant_Ref (Bound : Node_Id) return Node_Id;
13052 -- If one of the bounds is a reference to a discriminant, replace with
13053 -- corresponding discriminal of type. Within the body of a task retrieve
13054 -- the renamed discriminant by simple visibility, using its generated
13055 -- name. Within a protected object, find the original discriminant and
13056 -- replace it with the discriminal of the current protected operation.
13058 ------------------------------
13059 -- Convert_Discriminant_Ref --
13060 ------------------------------
13062 function Convert_Discriminant_Ref (Bound : Node_Id) return Node_Id is
13063 Loc : constant Source_Ptr := Sloc (Bound);
13064 B : Node_Id;
13065 D : Entity_Id;
13067 begin
13068 if Is_Entity_Name (Bound)
13069 and then Ekind (Entity (Bound)) = E_Discriminant
13070 then
13071 if Is_Task_Type (Ttyp) and then Has_Completion (Ttyp) then
13072 B := Make_Identifier (Loc, Chars (Entity (Bound)));
13073 Find_Direct_Name (B);
13075 elsif Is_Protected_Type (Ttyp) then
13076 D := First_Discriminant (Ttyp);
13077 while Chars (D) /= Chars (Entity (Bound)) loop
13078 Next_Discriminant (D);
13079 end loop;
13081 B := New_Occurrence_Of (Discriminal (D), Loc);
13083 else
13084 B := New_Occurrence_Of (Discriminal (Entity (Bound)), Loc);
13085 end if;
13087 elsif Nkind (Bound) = N_Attribute_Reference then
13088 return Bound;
13090 else
13091 B := New_Copy_Tree (Bound);
13092 end if;
13094 return
13095 Make_Attribute_Reference (Loc,
13096 Attribute_Name => Name_Pos,
13097 Prefix => New_Occurrence_Of (Etype (Bound), Loc),
13098 Expressions => New_List (B));
13099 end Convert_Discriminant_Ref;
13101 -- Start of processing for Family_Offset
13103 begin
13104 Real_Hi := Convert_Discriminant_Ref (Hi);
13105 Real_Lo := Convert_Discriminant_Ref (Lo);
13107 if Cap then
13108 if Is_Task_Type (Ttyp) then
13109 Ityp := RTE (RE_Task_Entry_Index);
13110 else
13111 Ityp := RTE (RE_Protected_Entry_Index);
13112 end if;
13114 Real_Hi :=
13115 Make_Attribute_Reference (Loc,
13116 Prefix => New_Occurrence_Of (Ityp, Loc),
13117 Attribute_Name => Name_Min,
13118 Expressions => New_List (
13119 Real_Hi,
13120 Make_Integer_Literal (Loc, Entry_Family_Bound - 1)));
13122 Real_Lo :=
13123 Make_Attribute_Reference (Loc,
13124 Prefix => New_Occurrence_Of (Ityp, Loc),
13125 Attribute_Name => Name_Max,
13126 Expressions => New_List (
13127 Real_Lo,
13128 Make_Integer_Literal (Loc, -Entry_Family_Bound)));
13129 end if;
13131 return Make_Op_Subtract (Loc, Real_Hi, Real_Lo);
13132 end Family_Offset;
13134 -----------------
13135 -- Family_Size --
13136 -----------------
13138 function Family_Size
13139 (Loc : Source_Ptr;
13140 Hi : Node_Id;
13141 Lo : Node_Id;
13142 Ttyp : Entity_Id;
13143 Cap : Boolean) return Node_Id
13145 Ityp : Entity_Id;
13147 begin
13148 if Is_Task_Type (Ttyp) then
13149 Ityp := RTE (RE_Task_Entry_Index);
13150 else
13151 Ityp := RTE (RE_Protected_Entry_Index);
13152 end if;
13154 return
13155 Make_Attribute_Reference (Loc,
13156 Prefix => New_Occurrence_Of (Ityp, Loc),
13157 Attribute_Name => Name_Max,
13158 Expressions => New_List (
13159 Make_Op_Add (Loc,
13160 Left_Opnd => Family_Offset (Loc, Hi, Lo, Ttyp, Cap),
13161 Right_Opnd => Make_Integer_Literal (Loc, 1)),
13162 Make_Integer_Literal (Loc, 0)));
13163 end Family_Size;
13165 ----------------------------
13166 -- Find_Enclosing_Context --
13167 ----------------------------
13169 procedure Find_Enclosing_Context
13170 (N : Node_Id;
13171 Context : out Node_Id;
13172 Context_Id : out Entity_Id;
13173 Context_Decls : out List_Id)
13175 begin
13176 -- Traverse the parent chain looking for an enclosing body, block,
13177 -- package or return statement.
13179 Context := Parent (N);
13180 while Present (Context) loop
13181 if Nkind (Context) in N_Entry_Body
13182 | N_Extended_Return_Statement
13183 | N_Package_Body
13184 | N_Package_Declaration
13185 | N_Subprogram_Body
13186 | N_Task_Body
13187 then
13188 exit;
13190 -- Do not consider block created to protect a list of statements with
13191 -- an Abort_Defer / Abort_Undefer_Direct pair.
13193 elsif Nkind (Context) = N_Block_Statement
13194 and then not Is_Abort_Block (Context)
13195 then
13196 exit;
13197 end if;
13199 Context := Parent (Context);
13200 end loop;
13202 pragma Assert (Present (Context));
13204 -- Extract the constituents of the context
13206 if Nkind (Context) = N_Extended_Return_Statement then
13207 Context_Decls := Return_Object_Declarations (Context);
13208 Context_Id := Return_Statement_Entity (Context);
13210 -- Package declarations and bodies use a common library-level activation
13211 -- chain or task master, therefore return the package declaration as the
13212 -- proper carrier for the appropriate flag.
13214 elsif Nkind (Context) = N_Package_Body then
13215 Context_Decls := Declarations (Context);
13216 Context_Id := Corresponding_Spec (Context);
13217 Context := Parent (Context_Id);
13219 if Nkind (Context) = N_Defining_Program_Unit_Name then
13220 Context := Parent (Parent (Context));
13221 else
13222 Context := Parent (Context);
13223 end if;
13225 elsif Nkind (Context) = N_Package_Declaration then
13226 Context_Decls := Visible_Declarations (Specification (Context));
13227 Context_Id := Defining_Unit_Name (Specification (Context));
13229 if Nkind (Context_Id) = N_Defining_Program_Unit_Name then
13230 Context_Id := Defining_Identifier (Context_Id);
13231 end if;
13233 else
13234 if Nkind (Context) = N_Block_Statement then
13235 Context_Id := Entity (Identifier (Context));
13237 if No (Declarations (Context)) then
13238 Set_Declarations (Context, New_List);
13239 end if;
13241 elsif Nkind (Context) = N_Entry_Body then
13242 Context_Id := Defining_Identifier (Context);
13244 elsif Nkind (Context) = N_Subprogram_Body then
13245 if Present (Corresponding_Spec (Context)) then
13246 Context_Id := Corresponding_Spec (Context);
13247 else
13248 Context_Id := Defining_Unit_Name (Specification (Context));
13250 if Nkind (Context_Id) = N_Defining_Program_Unit_Name then
13251 Context_Id := Defining_Identifier (Context_Id);
13252 end if;
13253 end if;
13255 elsif Nkind (Context) = N_Task_Body then
13256 Context_Id := Corresponding_Spec (Context);
13258 else
13259 raise Program_Error;
13260 end if;
13262 Context_Decls := Declarations (Context);
13263 end if;
13265 pragma Assert (Present (Context_Id));
13266 pragma Assert (Present (Context_Decls));
13267 end Find_Enclosing_Context;
13269 -----------------------
13270 -- Find_Master_Scope --
13271 -----------------------
13273 function Find_Master_Scope (E : Entity_Id) return Entity_Id is
13274 S : Entity_Id;
13276 begin
13277 -- In Ada 2005, the master is the innermost enclosing scope that is not
13278 -- transient. If the enclosing block is the rewriting of a call or the
13279 -- scope is an extended return statement this is valid master. The
13280 -- master in an extended return is only used within the return, and is
13281 -- subsequently overwritten in Move_Activation_Chain, but it must exist
13282 -- now before that overwriting occurs.
13284 S := Scope (E);
13286 if Ada_Version >= Ada_2005 then
13287 while Is_Internal (S) loop
13288 if Nkind (Parent (S)) = N_Block_Statement
13289 and then Has_Master_Entity (S)
13290 then
13291 exit;
13293 elsif Ekind (S) = E_Return_Statement then
13294 exit;
13296 else
13297 S := Scope (S);
13298 end if;
13299 end loop;
13300 end if;
13302 return S;
13303 end Find_Master_Scope;
13305 -------------------------------
13306 -- First_Protected_Operation --
13307 -------------------------------
13309 function First_Protected_Operation (D : List_Id) return Node_Id is
13310 First_Op : Node_Id;
13312 begin
13313 First_Op := First (D);
13314 while Present (First_Op)
13315 and then Nkind (First_Op) not in N_Subprogram_Body | N_Entry_Body
13316 loop
13317 Next (First_Op);
13318 end loop;
13320 return First_Op;
13321 end First_Protected_Operation;
13323 ---------------------------------------
13324 -- Install_Private_Data_Declarations --
13325 ---------------------------------------
13327 procedure Install_Private_Data_Declarations
13328 (Loc : Source_Ptr;
13329 Spec_Id : Entity_Id;
13330 Conc_Typ : Entity_Id;
13331 Body_Nod : Node_Id;
13332 Decls : List_Id;
13333 Barrier : Boolean := False;
13334 Family : Boolean := False)
13336 Is_Protected : constant Boolean := Is_Protected_Type (Conc_Typ);
13337 Decl : Node_Id;
13338 Def : Node_Id;
13339 Insert_Node : Node_Id := Empty;
13340 Obj_Ent : Entity_Id;
13342 procedure Add (Decl : Node_Id);
13343 -- Add a single declaration after Insert_Node. If this is the first
13344 -- addition, Decl is added to the front of Decls and it becomes the
13345 -- insertion node.
13347 function Replace_Bound (Bound : Node_Id) return Node_Id;
13348 -- The bounds of an entry index may depend on discriminants, create a
13349 -- reference to the corresponding prival. Otherwise return a duplicate
13350 -- of the original bound.
13352 ---------
13353 -- Add --
13354 ---------
13356 procedure Add (Decl : Node_Id) is
13357 begin
13358 if No (Insert_Node) then
13359 Prepend_To (Decls, Decl);
13360 else
13361 Insert_After (Insert_Node, Decl);
13362 end if;
13364 Insert_Node := Decl;
13365 end Add;
13367 -------------------
13368 -- Replace_Bound --
13369 -------------------
13371 function Replace_Bound (Bound : Node_Id) return Node_Id is
13372 begin
13373 if Nkind (Bound) = N_Identifier
13374 and then Is_Discriminal (Entity (Bound))
13375 then
13376 return Make_Identifier (Loc, Chars (Entity (Bound)));
13377 else
13378 return Duplicate_Subexpr (Bound);
13379 end if;
13380 end Replace_Bound;
13382 -- Start of processing for Install_Private_Data_Declarations
13384 begin
13385 -- Step 1: Retrieve the concurrent object entity. Obj_Ent can denote
13386 -- formal parameter _O, _object or _task depending on the context.
13388 Obj_Ent := Concurrent_Object (Spec_Id, Conc_Typ);
13390 -- Special processing of _O for barrier functions, protected entries
13391 -- and families.
13393 if Barrier
13394 or else
13395 (Is_Protected
13396 and then
13397 (Ekind (Spec_Id) = E_Entry
13398 or else Ekind (Spec_Id) = E_Entry_Family))
13399 then
13400 declare
13401 Conc_Rec : constant Entity_Id :=
13402 Corresponding_Record_Type (Conc_Typ);
13403 Typ_Id : constant Entity_Id :=
13404 Make_Defining_Identifier (Loc,
13405 New_External_Name (Chars (Conc_Rec), 'P'));
13406 begin
13407 -- Generate:
13408 -- type prot_typVP is access prot_typV;
13410 Decl :=
13411 Make_Full_Type_Declaration (Loc,
13412 Defining_Identifier => Typ_Id,
13413 Type_Definition =>
13414 Make_Access_To_Object_Definition (Loc,
13415 Subtype_Indication =>
13416 New_Occurrence_Of (Conc_Rec, Loc)));
13417 Add (Decl);
13419 -- Generate:
13420 -- _object : prot_typVP := prot_typV (_O);
13422 Decl :=
13423 Make_Object_Declaration (Loc,
13424 Defining_Identifier =>
13425 Make_Defining_Identifier (Loc, Name_uObject),
13426 Object_Definition => New_Occurrence_Of (Typ_Id, Loc),
13427 Expression =>
13428 Unchecked_Convert_To (Typ_Id,
13429 New_Occurrence_Of (Obj_Ent, Loc)));
13430 Add (Decl);
13432 -- Set the reference to the concurrent object
13434 Obj_Ent := Defining_Identifier (Decl);
13435 end;
13436 end if;
13438 -- Step 2: Create the Protection object and build its declaration for
13439 -- any protected entry (family) of subprogram. Note for the lock-free
13440 -- implementation, the Protection object is not needed anymore.
13442 if Is_Protected and then not Uses_Lock_Free (Conc_Typ) then
13443 declare
13444 Prot_Ent : constant Entity_Id := Make_Temporary (Loc, 'R');
13445 Prot_Typ : RE_Id;
13447 begin
13448 Set_Protection_Object (Spec_Id, Prot_Ent);
13450 -- Determine the proper protection type
13452 if Has_Attach_Handler (Conc_Typ)
13453 and then not Restricted_Profile
13454 then
13455 Prot_Typ := RE_Static_Interrupt_Protection;
13457 elsif Has_Interrupt_Handler (Conc_Typ)
13458 and then not Restriction_Active (No_Dynamic_Attachment)
13459 then
13460 Prot_Typ := RE_Dynamic_Interrupt_Protection;
13462 else
13463 case Corresponding_Runtime_Package (Conc_Typ) is
13464 when System_Tasking_Protected_Objects_Entries =>
13465 Prot_Typ := RE_Protection_Entries;
13467 when System_Tasking_Protected_Objects_Single_Entry =>
13468 Prot_Typ := RE_Protection_Entry;
13470 when System_Tasking_Protected_Objects =>
13471 Prot_Typ := RE_Protection;
13473 when others =>
13474 raise Program_Error;
13475 end case;
13476 end if;
13478 -- Generate:
13479 -- conc_typR : protection_typ renames _object._object;
13481 Decl :=
13482 Make_Object_Renaming_Declaration (Loc,
13483 Defining_Identifier => Prot_Ent,
13484 Subtype_Mark =>
13485 New_Occurrence_Of (RTE (Prot_Typ), Loc),
13486 Name =>
13487 Make_Selected_Component (Loc,
13488 Prefix => New_Occurrence_Of (Obj_Ent, Loc),
13489 Selector_Name => Make_Identifier (Loc, Name_uObject)));
13491 Add (Decl);
13492 end;
13493 end if;
13495 -- Step 3: Add discriminant renamings (if any)
13497 if Has_Discriminants (Conc_Typ) then
13498 declare
13499 D : Entity_Id;
13501 begin
13502 D := First_Discriminant (Conc_Typ);
13503 while Present (D) loop
13505 -- Adjust the source location
13507 Set_Sloc (Discriminal (D), Loc);
13509 -- Generate:
13510 -- discr_name : discr_typ renames _object.discr_name;
13511 -- or
13512 -- discr_name : discr_typ renames _task.discr_name;
13514 Decl :=
13515 Make_Object_Renaming_Declaration (Loc,
13516 Defining_Identifier => Discriminal (D),
13517 Subtype_Mark => New_Occurrence_Of (Etype (D), Loc),
13518 Name =>
13519 Make_Selected_Component (Loc,
13520 Prefix => New_Occurrence_Of (Obj_Ent, Loc),
13521 Selector_Name => Make_Identifier (Loc, Chars (D))));
13523 Add (Decl);
13525 -- Set debug info needed on this renaming declaration even
13526 -- though it does not come from source, so that the debugger
13527 -- will get the right information for these generated names.
13529 Set_Debug_Info_Needed (Discriminal (D));
13531 Next_Discriminant (D);
13532 end loop;
13533 end;
13534 end if;
13536 -- Step 4: Add private component renamings (if any)
13538 if Is_Protected then
13539 Def := Protected_Definition (Parent (Conc_Typ));
13541 if Present (Private_Declarations (Def)) then
13542 declare
13543 Comp : Node_Id;
13544 Comp_Id : Entity_Id;
13545 Decl_Id : Entity_Id;
13546 Nam : Name_Id;
13548 begin
13549 Comp := First (Private_Declarations (Def));
13550 while Present (Comp) loop
13551 if Nkind (Comp) = N_Component_Declaration then
13552 Comp_Id := Defining_Identifier (Comp);
13553 Nam := Chars (Comp_Id);
13554 Decl_Id := Make_Defining_Identifier (Sloc (Comp_Id), Nam);
13556 -- Minimal decoration
13558 if Ekind (Spec_Id) = E_Function then
13559 Mutate_Ekind (Decl_Id, E_Constant);
13560 else
13561 Mutate_Ekind (Decl_Id, E_Variable);
13562 end if;
13564 Set_Prival (Comp_Id, Decl_Id);
13565 Set_Prival_Link (Decl_Id, Comp_Id);
13566 Set_Is_Aliased (Decl_Id, Is_Aliased (Comp_Id));
13567 Set_Is_Independent (Decl_Id, Is_Independent (Comp_Id));
13569 -- Copy the Comes_From_Source flag of the component, as
13570 -- the renaming may be the only entity directly seen by
13571 -- the user in the context, but do not warn for it.
13573 Set_Comes_From_Source
13574 (Decl_Id, Comes_From_Source (Comp_Id));
13575 Set_Warnings_Off (Decl_Id);
13577 -- Generate:
13578 -- comp_name : comp_typ renames _object.comp_name;
13580 Decl :=
13581 Make_Object_Renaming_Declaration (Loc,
13582 Defining_Identifier => Decl_Id,
13583 Subtype_Mark =>
13584 New_Occurrence_Of (Etype (Comp_Id), Loc),
13585 Name =>
13586 Make_Selected_Component (Loc,
13587 Prefix => New_Occurrence_Of (Obj_Ent, Loc),
13588 Selector_Name => Make_Identifier (Loc, Nam)));
13590 Add (Decl);
13591 end if;
13593 Next (Comp);
13594 end loop;
13595 end;
13596 end if;
13597 end if;
13599 -- Step 5: Add the declaration of the entry index and the associated
13600 -- type for barrier functions and entry families.
13602 if (Barrier and Family) or else Ekind (Spec_Id) = E_Entry_Family then
13603 declare
13604 E : constant Entity_Id := Index_Object (Spec_Id);
13605 Index : constant Entity_Id :=
13606 Defining_Identifier
13607 (Entry_Index_Specification
13608 (Entry_Body_Formal_Part (Body_Nod)));
13609 Index_Con : constant Entity_Id :=
13610 Make_Defining_Identifier (Loc, Chars (Index));
13611 High : Node_Id;
13612 Index_Typ : Entity_Id;
13613 Low : Node_Id;
13615 begin
13616 -- Minimal decoration
13618 Mutate_Ekind (Index_Con, E_Constant);
13619 Set_Entry_Index_Constant (Index, Index_Con);
13620 Set_Discriminal_Link (Index_Con, Index);
13622 -- Retrieve the bounds of the entry family
13624 High := Type_High_Bound (Etype (Index));
13625 Low := Type_Low_Bound (Etype (Index));
13627 -- In the simple case the entry family is given by a subtype mark
13628 -- and the index constant has the same type.
13630 if Is_Entity_Name (Original_Node (
13631 Discrete_Subtype_Definition (Parent (Index))))
13632 then
13633 Index_Typ := Etype (Index);
13635 -- Otherwise a new subtype declaration is required
13637 else
13638 High := Replace_Bound (High);
13639 Low := Replace_Bound (Low);
13641 Index_Typ := Make_Temporary (Loc, 'J');
13643 -- Generate:
13644 -- subtype Jnn is <Etype of Index> range Low .. High;
13646 Decl :=
13647 Make_Subtype_Declaration (Loc,
13648 Defining_Identifier => Index_Typ,
13649 Subtype_Indication =>
13650 Make_Subtype_Indication (Loc,
13651 Subtype_Mark =>
13652 New_Occurrence_Of (Base_Type (Etype (Index)), Loc),
13653 Constraint =>
13654 Make_Range_Constraint (Loc,
13655 Range_Expression =>
13656 Make_Range (Loc, Low, High))));
13657 Add (Decl);
13658 end if;
13660 Set_Etype (Index_Con, Index_Typ);
13662 -- Create the object which designates the index:
13663 -- J : constant Jnn :=
13664 -- Jnn'Val (_E - <index expr> + Jnn'Pos (Jnn'First));
13666 -- where Jnn is the subtype created above or the original type of
13667 -- the index, _E is a formal of the protected body subprogram and
13668 -- <index expr> is the index of the first family member.
13670 Decl :=
13671 Make_Object_Declaration (Loc,
13672 Defining_Identifier => Index_Con,
13673 Constant_Present => True,
13674 Object_Definition =>
13675 New_Occurrence_Of (Index_Typ, Loc),
13677 Expression =>
13678 Make_Attribute_Reference (Loc,
13679 Prefix =>
13680 New_Occurrence_Of (Index_Typ, Loc),
13681 Attribute_Name => Name_Val,
13683 Expressions => New_List (
13685 Make_Op_Add (Loc,
13686 Left_Opnd =>
13687 Make_Op_Subtract (Loc,
13688 Left_Opnd => New_Occurrence_Of (E, Loc),
13689 Right_Opnd =>
13690 Entry_Index_Expression (Loc,
13691 Defining_Identifier (Body_Nod),
13692 Empty, Conc_Typ)),
13694 Right_Opnd =>
13695 Make_Attribute_Reference (Loc,
13696 Prefix =>
13697 New_Occurrence_Of (Index_Typ, Loc),
13698 Attribute_Name => Name_Pos,
13699 Expressions => New_List (
13700 Make_Attribute_Reference (Loc,
13701 Prefix =>
13702 New_Occurrence_Of (Index_Typ, Loc),
13703 Attribute_Name => Name_First)))))));
13704 Add (Decl);
13705 end;
13706 end if;
13707 end Install_Private_Data_Declarations;
13709 ---------------------------------
13710 -- Is_Potentially_Large_Family --
13711 ---------------------------------
13713 function Is_Potentially_Large_Family
13714 (Base_Index : Entity_Id;
13715 Conctyp : Entity_Id;
13716 Lo : Node_Id;
13717 Hi : Node_Id) return Boolean
13719 begin
13720 return Scope (Base_Index) = Standard_Standard
13721 and then Base_Index = Base_Type (Standard_Integer)
13722 and then Has_Defaulted_Discriminants (Conctyp)
13723 and then
13724 (Denotes_Discriminant (Lo, True)
13725 or else
13726 Denotes_Discriminant (Hi, True));
13727 end Is_Potentially_Large_Family;
13729 -------------------------------------
13730 -- Is_Private_Primitive_Subprogram --
13731 -------------------------------------
13733 function Is_Private_Primitive_Subprogram (Id : Entity_Id) return Boolean is
13734 begin
13735 return
13736 (Ekind (Id) = E_Function or else Ekind (Id) = E_Procedure)
13737 and then Is_Private_Primitive (Id);
13738 end Is_Private_Primitive_Subprogram;
13740 ------------------
13741 -- Index_Object --
13742 ------------------
13744 function Index_Object (Spec_Id : Entity_Id) return Entity_Id is
13745 Bod_Subp : constant Entity_Id := Protected_Body_Subprogram (Spec_Id);
13746 Formal : Entity_Id;
13748 begin
13749 Formal := First_Formal (Bod_Subp);
13750 while Present (Formal) loop
13752 -- Look for formal parameter _E
13754 if Chars (Formal) = Name_uE then
13755 return Formal;
13756 end if;
13758 Next_Formal (Formal);
13759 end loop;
13761 -- A protected body subprogram should always have the parameter in
13762 -- question.
13764 raise Program_Error;
13765 end Index_Object;
13767 --------------------------------
13768 -- Make_Initialize_Protection --
13769 --------------------------------
13771 function Make_Initialize_Protection
13772 (Protect_Rec : Entity_Id) return List_Id
13774 Loc : constant Source_Ptr := Sloc (Protect_Rec);
13775 P_Arr : Entity_Id;
13776 Pdec : Node_Id;
13777 Ptyp : constant Node_Id :=
13778 Corresponding_Concurrent_Type (Protect_Rec);
13779 Args : List_Id;
13780 L : constant List_Id := New_List;
13781 Has_Entry : constant Boolean := Has_Entries (Ptyp);
13782 Prio_Type : Entity_Id;
13783 Prio_Var : Entity_Id := Empty;
13784 Restricted : constant Boolean := Restricted_Profile;
13786 begin
13787 -- We may need two calls to properly initialize the object, one to
13788 -- Initialize_Protection, and possibly one to Install_Handlers if we
13789 -- have a pragma Attach_Handler.
13791 -- Get protected declaration. In the case of a task type declaration,
13792 -- this is simply the parent of the protected type entity. In the single
13793 -- protected object declaration, this parent will be the implicit type,
13794 -- and we can find the corresponding single protected object declaration
13795 -- by searching forward in the declaration list in the tree.
13797 -- Is the test for N_Single_Protected_Declaration needed here??? Nodes
13798 -- of this type should have been removed during semantic analysis.
13800 Pdec := Parent (Ptyp);
13801 while Nkind (Pdec) not in
13802 N_Protected_Type_Declaration | N_Single_Protected_Declaration
13803 loop
13804 Next (Pdec);
13805 end loop;
13807 -- Build the parameter list for the call. Note that _Init is the name
13808 -- of the formal for the object to be initialized, which is the task
13809 -- value record itself.
13811 Args := New_List;
13813 -- For lock-free implementation, skip initializations of the Protection
13814 -- object.
13816 if not Uses_Lock_Free (Defining_Identifier (Pdec)) then
13818 -- Object parameter. This is a pointer to the object of type
13819 -- Protection used by the GNARL to control the protected object.
13821 Append_To (Args,
13822 Make_Attribute_Reference (Loc,
13823 Prefix =>
13824 Make_Selected_Component (Loc,
13825 Prefix => Make_Identifier (Loc, Name_uInit),
13826 Selector_Name => Make_Identifier (Loc, Name_uObject)),
13827 Attribute_Name => Name_Unchecked_Access));
13829 -- Priority parameter. Set to Unspecified_Priority unless there is a
13830 -- Priority rep item, in which case we take the value from the pragma
13831 -- or attribute definition clause, or there is an Interrupt_Priority
13832 -- rep item and no Priority rep item, and we set the ceiling to
13833 -- Interrupt_Priority'Last, an implementation-defined value, see
13834 -- (RM D.3(10)).
13836 if Has_Rep_Item (Ptyp, Name_Priority, Check_Parents => False) then
13837 declare
13838 Prio_Clause : constant Node_Id :=
13839 Get_Rep_Item
13840 (Ptyp, Name_Priority, Check_Parents => False);
13842 Prio : Node_Id;
13844 begin
13845 -- Pragma Priority
13847 if Nkind (Prio_Clause) = N_Pragma then
13848 Prio :=
13849 Expression
13850 (First (Pragma_Argument_Associations (Prio_Clause)));
13852 -- Get_Rep_Item returns either priority pragma
13854 if Pragma_Name (Prio_Clause) = Name_Priority then
13855 Prio_Type := RTE (RE_Any_Priority);
13856 else
13857 Prio_Type := RTE (RE_Interrupt_Priority);
13858 end if;
13860 -- Attribute definition clause Priority
13862 else
13863 if Chars (Prio_Clause) = Name_Priority then
13864 Prio_Type := RTE (RE_Any_Priority);
13865 else
13866 Prio_Type := RTE (RE_Interrupt_Priority);
13867 end if;
13869 Prio := Expression (Prio_Clause);
13870 end if;
13872 -- Always create a locale variable to capture the priority.
13873 -- The priority is also passed to Install_Restriced_Handlers.
13874 -- Note that it is really necessary to create this variable
13875 -- explicitly. It might be thought that removing side effects
13876 -- would the appropriate approach, but that could generate
13877 -- declarations improperly placed in the enclosing scope.
13879 Prio_Var := Make_Temporary (Loc, 'R', Prio);
13880 Append_To (L,
13881 Make_Object_Declaration (Loc,
13882 Defining_Identifier => Prio_Var,
13883 Object_Definition => New_Occurrence_Of (Prio_Type, Loc),
13884 Expression => Relocate_Node (Prio)));
13886 Append_To (Args, New_Occurrence_Of (Prio_Var, Loc));
13887 end;
13889 -- When no priority is specified but an xx_Handler pragma is, we
13890 -- default to System.Interrupts.Default_Interrupt_Priority, see
13891 -- D.3(10).
13893 elsif Has_Attach_Handler (Ptyp)
13894 or else Has_Interrupt_Handler (Ptyp)
13895 then
13896 Append_To (Args,
13897 New_Occurrence_Of (RTE (RE_Default_Interrupt_Priority), Loc));
13899 -- Normal case, no priority or xx_Handler specified, default priority
13901 else
13902 Append_To (Args,
13903 New_Occurrence_Of (RTE (RE_Unspecified_Priority), Loc));
13904 end if;
13906 -- Deadline_Floor parameter for GNAT_Ravenscar_EDF runtimes
13908 if Restricted_Profile and Task_Dispatching_Policy = 'E' then
13909 Deadline_Floor : declare
13910 Item : constant Node_Id :=
13911 Get_Rep_Item
13912 (Ptyp, Name_Deadline_Floor, Check_Parents => False);
13914 Deadline : Node_Id;
13916 begin
13917 if Present (Item) then
13919 -- Pragma Deadline_Floor
13921 if Nkind (Item) = N_Pragma then
13922 Deadline :=
13923 Expression
13924 (First (Pragma_Argument_Associations (Item)));
13926 -- Attribute definition clause Deadline_Floor
13928 else
13929 pragma Assert
13930 (Nkind (Item) = N_Attribute_Definition_Clause);
13932 Deadline := Expression (Item);
13933 end if;
13935 Append_To (Args, Deadline);
13937 -- Unusual case: default deadline
13939 else
13940 Append_To (Args,
13941 New_Occurrence_Of (RTE (RE_Time_Span_Zero), Loc));
13942 end if;
13943 end Deadline_Floor;
13944 end if;
13946 -- Test for Compiler_Info parameter. This parameter allows entry body
13947 -- procedures and barrier functions to be called from the runtime. It
13948 -- is a pointer to the record generated by the compiler to represent
13949 -- the protected object.
13951 -- A protected type without entries that covers an interface and
13952 -- overrides the abstract routines with protected procedures is
13953 -- considered equivalent to a protected type with entries in the
13954 -- context of dispatching select statements.
13956 -- Protected types with interrupt handlers (when not using a
13957 -- restricted profile) are also considered equivalent to protected
13958 -- types with entries.
13960 -- The types which are used (Static_Interrupt_Protection and
13961 -- Dynamic_Interrupt_Protection) are derived from Protection_Entries.
13963 declare
13964 Pkg_Id : constant RTU_Id := Corresponding_Runtime_Package (Ptyp);
13966 Called_Subp : RE_Id;
13968 begin
13969 case Pkg_Id is
13970 when System_Tasking_Protected_Objects_Entries =>
13971 Called_Subp := RE_Initialize_Protection_Entries;
13973 -- Argument Compiler_Info
13975 Append_To (Args,
13976 Make_Attribute_Reference (Loc,
13977 Prefix => Make_Identifier (Loc, Name_uInit),
13978 Attribute_Name => Name_Address));
13980 when System_Tasking_Protected_Objects_Single_Entry =>
13981 Called_Subp := RE_Initialize_Protection_Entry;
13983 -- Argument Compiler_Info
13985 Append_To (Args,
13986 Make_Attribute_Reference (Loc,
13987 Prefix => Make_Identifier (Loc, Name_uInit),
13988 Attribute_Name => Name_Address));
13990 when System_Tasking_Protected_Objects =>
13991 Called_Subp := RE_Initialize_Protection;
13993 when others =>
13994 raise Program_Error;
13995 end case;
13997 -- Entry_Queue_Maxes parameter. This is an access to an array of
13998 -- naturals representing the entry queue maximums for each entry
13999 -- in the protected type. Zero represents no max. The access is
14000 -- null if there is no limit for all entries (usual case).
14002 if Has_Entry
14003 and then Pkg_Id = System_Tasking_Protected_Objects_Entries
14004 then
14005 if Present (Entry_Max_Queue_Lengths_Array (Ptyp)) then
14006 Append_To (Args,
14007 Make_Attribute_Reference (Loc,
14008 Prefix =>
14009 New_Occurrence_Of
14010 (Entry_Max_Queue_Lengths_Array (Ptyp), Loc),
14011 Attribute_Name => Name_Unrestricted_Access));
14012 else
14013 Append_To (Args, Make_Null (Loc));
14014 end if;
14016 -- Edge cases exist where entry initialization functions are
14017 -- called, but no entries exist, so null is appended.
14019 elsif Pkg_Id = System_Tasking_Protected_Objects_Entries then
14020 Append_To (Args, Make_Null (Loc));
14021 end if;
14023 -- Entry_Bodies parameter. This is a pointer to an array of
14024 -- pointers to the entry body procedures and barrier functions of
14025 -- the object. If the protected type has no entries this object
14026 -- will not exist, in this case, pass a null (it can happen when
14027 -- there are protected interrupt handlers or interfaces).
14029 if Has_Entry then
14030 P_Arr := Entry_Bodies_Array (Ptyp);
14032 -- Argument Entry_Body (for single entry) or Entry_Bodies (for
14033 -- multiple entries).
14035 Append_To (Args,
14036 Make_Attribute_Reference (Loc,
14037 Prefix => New_Occurrence_Of (P_Arr, Loc),
14038 Attribute_Name => Name_Unrestricted_Access));
14040 if Pkg_Id = System_Tasking_Protected_Objects_Entries then
14042 -- Find index mapping function (clumsy but ok for now)
14044 while Ekind (P_Arr) /= E_Function loop
14045 Next_Entity (P_Arr);
14046 end loop;
14048 Append_To (Args,
14049 Make_Attribute_Reference (Loc,
14050 Prefix => New_Occurrence_Of (P_Arr, Loc),
14051 Attribute_Name => Name_Unrestricted_Access));
14052 end if;
14054 elsif Pkg_Id = System_Tasking_Protected_Objects_Single_Entry then
14056 -- This is the case where we have a protected object with
14057 -- interfaces and no entries, and the single entry restriction
14058 -- is in effect. We pass a null pointer for the entry
14059 -- parameter because there is no actual entry.
14061 Append_To (Args, Make_Null (Loc));
14063 elsif Pkg_Id = System_Tasking_Protected_Objects_Entries then
14065 -- This is the case where we have a protected object with no
14066 -- entries and:
14067 -- - either interrupt handlers with non restricted profile,
14068 -- - or interfaces
14069 -- Note that the types which are used for interrupt handlers
14070 -- (Static/Dynamic_Interrupt_Protection) are derived from
14071 -- Protection_Entries. We pass two null pointers because there
14072 -- is no actual entry, and the initialization procedure needs
14073 -- both Entry_Bodies and Find_Body_Index.
14075 Append_To (Args, Make_Null (Loc));
14076 Append_To (Args, Make_Null (Loc));
14077 end if;
14079 Append_To (L,
14080 Make_Procedure_Call_Statement (Loc,
14081 Name =>
14082 New_Occurrence_Of (RTE (Called_Subp), Loc),
14083 Parameter_Associations => Args));
14084 end;
14085 end if;
14087 if Has_Attach_Handler (Ptyp) then
14089 -- We have a list of N Attach_Handler (ProcI, ExprI), and we have to
14090 -- make the following call:
14092 -- Install_Handlers (_object,
14093 -- ((Expr1, Proc1'access), ...., (ExprN, ProcN'access));
14095 -- or, in the case of Ravenscar:
14097 -- Install_Restricted_Handlers
14098 -- (Prio, ((Expr1, Proc1'access), ...., (ExprN, ProcN'access)));
14100 declare
14101 Args : constant List_Id := New_List;
14102 Table : constant List_Id := New_List;
14103 Ritem : Node_Id := First_Rep_Item (Ptyp);
14105 begin
14106 -- Build the Priority parameter (only for ravenscar)
14108 if Restricted then
14110 -- Priority comes from a pragma
14112 if Present (Prio_Var) then
14113 Append_To (Args, New_Occurrence_Of (Prio_Var, Loc));
14115 -- Priority is the default one
14117 else
14118 Append_To (Args,
14119 New_Occurrence_Of
14120 (RTE (RE_Default_Interrupt_Priority), Loc));
14121 end if;
14122 end if;
14124 -- Build the Attach_Handler table argument
14126 while Present (Ritem) loop
14127 if Nkind (Ritem) = N_Pragma
14128 and then Pragma_Name (Ritem) = Name_Attach_Handler
14129 then
14130 declare
14131 Handler : constant Node_Id :=
14132 First (Pragma_Argument_Associations (Ritem));
14134 Interrupt : constant Node_Id := Next (Handler);
14135 Expr : constant Node_Id := Expression (Interrupt);
14137 begin
14138 Append_To (Table,
14139 Make_Aggregate (Loc, Expressions => New_List (
14140 Unchecked_Convert_To
14141 (RTE (RE_System_Interrupt_Id), Expr),
14142 Make_Attribute_Reference (Loc,
14143 Prefix =>
14144 Make_Selected_Component (Loc,
14145 Prefix =>
14146 Make_Identifier (Loc, Name_uInit),
14147 Selector_Name =>
14148 Duplicate_Subexpr_No_Checks
14149 (Expression (Handler))),
14150 Attribute_Name => Name_Access))));
14151 end;
14152 end if;
14154 Next_Rep_Item (Ritem);
14155 end loop;
14157 -- Append the table argument we just built
14159 Append_To (Args, Make_Aggregate (Loc, Table));
14161 -- Append the Install_Handlers (or Install_Restricted_Handlers)
14162 -- call to the statements.
14164 if Restricted then
14165 -- Call a simplified version of Install_Handlers to be used
14166 -- when the Ravenscar restrictions are in effect
14167 -- (Install_Restricted_Handlers).
14169 Append_To (L,
14170 Make_Procedure_Call_Statement (Loc,
14171 Name =>
14172 New_Occurrence_Of
14173 (RTE (RE_Install_Restricted_Handlers), Loc),
14174 Parameter_Associations => Args));
14176 else
14177 if not Uses_Lock_Free (Defining_Identifier (Pdec)) then
14179 -- First, prepends the _object argument
14181 Prepend_To (Args,
14182 Make_Attribute_Reference (Loc,
14183 Prefix =>
14184 Make_Selected_Component (Loc,
14185 Prefix => Make_Identifier (Loc, Name_uInit),
14186 Selector_Name =>
14187 Make_Identifier (Loc, Name_uObject)),
14188 Attribute_Name => Name_Unchecked_Access));
14189 end if;
14191 -- Then, insert call to Install_Handlers
14193 Append_To (L,
14194 Make_Procedure_Call_Statement (Loc,
14195 Name =>
14196 New_Occurrence_Of (RTE (RE_Install_Handlers), Loc),
14197 Parameter_Associations => Args));
14198 end if;
14199 end;
14200 end if;
14202 return L;
14203 end Make_Initialize_Protection;
14205 ---------------------------
14206 -- Make_Task_Create_Call --
14207 ---------------------------
14209 function Make_Task_Create_Call (Task_Rec : Entity_Id) return Node_Id is
14210 Loc : constant Source_Ptr := Sloc (Task_Rec);
14211 Args : List_Id;
14212 Ecount : Node_Id;
14213 Name : Node_Id;
14214 Tdec : Node_Id;
14215 Tdef : Node_Id;
14216 Tnam : Name_Id;
14217 Ttyp : Entity_Id;
14219 begin
14220 Ttyp := Corresponding_Concurrent_Type (Task_Rec);
14221 Tnam := Chars (Ttyp);
14223 -- Get task declaration. In the case of a task type declaration, this is
14224 -- simply the parent of the task type entity. In the single task
14225 -- declaration, this parent will be the implicit type, and we can find
14226 -- the corresponding single task declaration by searching forward in the
14227 -- declaration list in the tree.
14229 -- Is the test for N_Single_Task_Declaration needed here??? Nodes of
14230 -- this type should have been removed during semantic analysis.
14232 Tdec := Parent (Ttyp);
14233 while Nkind (Tdec) not in
14234 N_Task_Type_Declaration | N_Single_Task_Declaration
14235 loop
14236 Next (Tdec);
14237 end loop;
14239 -- Now we can find the task definition from this declaration
14241 Tdef := Task_Definition (Tdec);
14243 -- Build the parameter list for the call. Note that _Init is the name
14244 -- of the formal for the object to be initialized, which is the task
14245 -- value record itself.
14247 Args := New_List;
14249 -- Priority parameter. Set to Unspecified_Priority unless there is a
14250 -- Priority rep item, in which case we take the value from the rep item.
14251 -- Not used on Ravenscar_EDF profile.
14253 if not (Restricted_Profile and then Task_Dispatching_Policy = 'E') then
14254 if Has_Rep_Item (Ttyp, Name_Priority, Check_Parents => False) then
14255 Append_To (Args,
14256 Make_Selected_Component (Loc,
14257 Prefix => Make_Identifier (Loc, Name_uInit),
14258 Selector_Name => Make_Identifier (Loc, Name_uPriority)));
14259 else
14260 Append_To (Args,
14261 New_Occurrence_Of (RTE (RE_Unspecified_Priority), Loc));
14262 end if;
14263 end if;
14265 -- Optional Stack parameter
14267 if Restricted_Profile then
14269 -- If the stack has been preallocated by the expander then
14270 -- pass its address. Otherwise, pass a null address.
14272 if Preallocated_Stacks_On_Target then
14273 Append_To (Args,
14274 Make_Attribute_Reference (Loc,
14275 Prefix =>
14276 Make_Selected_Component (Loc,
14277 Prefix => Make_Identifier (Loc, Name_uInit),
14278 Selector_Name => Make_Identifier (Loc, Name_uStack)),
14279 Attribute_Name => Name_Address));
14281 else
14282 Append_To (Args,
14283 New_Occurrence_Of (RTE (RE_Null_Address), Loc));
14284 end if;
14285 end if;
14287 -- Size parameter. If no Storage_Size pragma is present, then
14288 -- the size is taken from the taskZ variable for the type, which
14289 -- is either Unspecified_Size, or has been reset by the use of
14290 -- a Storage_Size attribute definition clause. If a pragma is
14291 -- present, then the size is taken from the _Size field of the
14292 -- task value record, which was set from the pragma value.
14294 if Present (Tdef) and then Has_Storage_Size_Pragma (Tdef) then
14295 Append_To (Args,
14296 Make_Selected_Component (Loc,
14297 Prefix => Make_Identifier (Loc, Name_uInit),
14298 Selector_Name => Make_Identifier (Loc, Name_uSize)));
14300 else
14301 Append_To (Args,
14302 New_Occurrence_Of (Storage_Size_Variable (Ttyp), Loc));
14303 end if;
14305 -- Secondary_Stack parameter used for restricted profiles
14307 if Restricted_Profile then
14309 -- If the secondary stack has been allocated by the expander then
14310 -- pass its access pointer. Otherwise, pass null.
14312 if Create_Secondary_Stack_For_Task (Ttyp) then
14313 Append_To (Args,
14314 Make_Attribute_Reference (Loc,
14315 Prefix =>
14316 Make_Selected_Component (Loc,
14317 Prefix => Make_Identifier (Loc, Name_uInit),
14318 Selector_Name =>
14319 Make_Identifier (Loc, Name_uSecondary_Stack)),
14320 Attribute_Name => Name_Unrestricted_Access));
14322 else
14323 Append_To (Args, Make_Null (Loc));
14324 end if;
14325 end if;
14327 -- Secondary_Stack_Size parameter. Set RE_Unspecified_Size unless there
14328 -- is a Secondary_Stack_Size pragma, in which case take the value from
14329 -- the pragma. If the restriction No_Secondary_Stack is active then a
14330 -- size of 0 is passed regardless to prevent the allocation of the
14331 -- unused stack.
14333 if Restriction_Active (No_Secondary_Stack) then
14334 Append_To (Args, Make_Integer_Literal (Loc, 0));
14336 elsif Has_Rep_Pragma
14337 (Ttyp, Name_Secondary_Stack_Size, Check_Parents => False)
14338 then
14339 Append_To (Args,
14340 Make_Selected_Component (Loc,
14341 Prefix => Make_Identifier (Loc, Name_uInit),
14342 Selector_Name =>
14343 Make_Identifier (Loc, Name_uSecondary_Stack_Size)));
14345 else
14346 Append_To (Args,
14347 New_Occurrence_Of (RTE (RE_Unspecified_Size), Loc));
14348 end if;
14350 -- Task_Info parameter. Set to Unspecified_Task_Info unless there is a
14351 -- Task_Info pragma, in which case we take the value from the pragma.
14353 if Has_Rep_Pragma (Ttyp, Name_Task_Info, Check_Parents => False) then
14354 Append_To (Args,
14355 Make_Selected_Component (Loc,
14356 Prefix => Make_Identifier (Loc, Name_uInit),
14357 Selector_Name => Make_Identifier (Loc, Name_uTask_Info)));
14359 else
14360 Append_To (Args,
14361 New_Occurrence_Of (RTE (RE_Unspecified_Task_Info), Loc));
14362 end if;
14364 -- CPU parameter. Set to Unspecified_CPU unless there is a CPU rep item,
14365 -- in which case we take the value from the rep item. The parameter is
14366 -- passed as an Integer because in the case of unspecified CPU the
14367 -- value is not in the range of CPU_Range.
14369 if Has_Rep_Item (Ttyp, Name_CPU, Check_Parents => False) then
14370 Append_To (Args,
14371 Convert_To (Standard_Integer,
14372 Make_Selected_Component (Loc,
14373 Prefix => Make_Identifier (Loc, Name_uInit),
14374 Selector_Name => Make_Identifier (Loc, Name_uCPU))));
14375 else
14376 Append_To (Args,
14377 New_Occurrence_Of (RTE (RE_Unspecified_CPU), Loc));
14378 end if;
14380 if not Restricted_Profile or else Task_Dispatching_Policy = 'E' then
14382 -- Deadline parameter. If no Relative_Deadline pragma is present,
14383 -- then the deadline is Time_Span_Zero. If a pragma is present, then
14384 -- the deadline is taken from the _Relative_Deadline field of the
14385 -- task value record, which was set from the pragma value. Note that
14386 -- this parameter must not be generated for the restricted profiles
14387 -- since Ravenscar does not allow deadlines.
14389 -- Case where pragma Relative_Deadline applies: use given value
14391 if Present (Tdef) and then Has_Relative_Deadline_Pragma (Tdef) then
14392 Append_To (Args,
14393 Make_Selected_Component (Loc,
14394 Prefix => Make_Identifier (Loc, Name_uInit),
14395 Selector_Name =>
14396 Make_Identifier (Loc, Name_uRelative_Deadline)));
14398 -- No pragma Relative_Deadline apply to the task
14400 else
14401 Append_To (Args,
14402 New_Occurrence_Of (RTE (RE_Time_Span_Zero), Loc));
14403 end if;
14404 end if;
14406 if not Restricted_Profile then
14408 -- Dispatching_Domain parameter. If no Dispatching_Domain rep item is
14409 -- present, then the dispatching domain is null. If a rep item is
14410 -- present, then the dispatching domain is taken from the
14411 -- _Dispatching_Domain field of the task value record, which was set
14412 -- from the rep item value.
14414 -- Case where Dispatching_Domain rep item applies: use given value
14416 if Has_Rep_Item
14417 (Ttyp, Name_Dispatching_Domain, Check_Parents => False)
14418 then
14419 Append_To (Args,
14420 Make_Selected_Component (Loc,
14421 Prefix =>
14422 Make_Identifier (Loc, Name_uInit),
14423 Selector_Name =>
14424 Make_Identifier (Loc, Name_uDispatching_Domain)));
14426 -- No pragma or aspect Dispatching_Domain applies to the task
14428 else
14429 Append_To (Args, Make_Null (Loc));
14430 end if;
14432 -- Number of entries. This is an expression of the form:
14434 -- n + _Init.a'Length + _Init.a'B'Length + ...
14436 -- where a,b... are the entry family names for the task definition
14438 Ecount := Build_Entry_Count_Expression (Ttyp, Loc);
14439 Append_To (Args, Ecount);
14441 -- Master parameter. This is a reference to the _Master parameter of
14442 -- the initialization procedure, except in the case of the pragma
14443 -- Restrictions (No_Task_Hierarchy) where the value is fixed to
14444 -- System.Tasking.Library_Task_Level.
14446 if Restriction_Active (No_Task_Hierarchy) = False then
14447 Append_To (Args, Make_Identifier (Loc, Name_uMaster));
14448 else
14449 Append_To (Args, Make_Integer_Literal (Loc, Library_Task_Level));
14450 end if;
14451 end if;
14453 -- State parameter. This is a pointer to the task body procedure. The
14454 -- required value is obtained by taking 'Unrestricted_Access of the task
14455 -- body procedure and converting it (with an unchecked conversion) to
14456 -- the type required by the task kernel. For further details, see the
14457 -- description of Expand_N_Task_Body. We use 'Unrestricted_Access rather
14458 -- than 'Address in order to avoid creating trampolines.
14460 declare
14461 Body_Proc : constant Node_Id := Get_Task_Body_Procedure (Ttyp);
14462 Subp_Ptr_Typ : constant Node_Id :=
14463 Create_Itype (E_Access_Subprogram_Type, Tdec);
14464 Ref : constant Node_Id := Make_Itype_Reference (Loc);
14466 begin
14467 Set_Directly_Designated_Type (Subp_Ptr_Typ, Body_Proc);
14468 Set_Etype (Subp_Ptr_Typ, Subp_Ptr_Typ);
14470 -- Be sure to freeze a reference to the access-to-subprogram type,
14471 -- otherwise gigi will complain that it's in the wrong scope, because
14472 -- it's actually inside the init procedure for the record type that
14473 -- corresponds to the task type.
14475 Set_Itype (Ref, Subp_Ptr_Typ);
14476 Append_Freeze_Action (Task_Rec, Ref);
14478 Append_To (Args,
14479 Unchecked_Convert_To (RTE (RE_Task_Procedure_Access),
14480 Make_Qualified_Expression (Loc,
14481 Subtype_Mark => New_Occurrence_Of (Subp_Ptr_Typ, Loc),
14482 Expression =>
14483 Make_Attribute_Reference (Loc,
14484 Prefix => New_Occurrence_Of (Body_Proc, Loc),
14485 Attribute_Name => Name_Unrestricted_Access))));
14486 end;
14488 -- Discriminants parameter. This is just the address of the task
14489 -- value record itself (which contains the discriminant values
14491 Append_To (Args,
14492 Make_Attribute_Reference (Loc,
14493 Prefix => Make_Identifier (Loc, Name_uInit),
14494 Attribute_Name => Name_Address));
14496 -- Elaborated parameter. This is an access to the elaboration Boolean
14498 Append_To (Args,
14499 Make_Attribute_Reference (Loc,
14500 Prefix => Make_Identifier (Loc, New_External_Name (Tnam, 'E')),
14501 Attribute_Name => Name_Unchecked_Access));
14503 -- Add Chain parameter (not done for sequential elaboration policy, see
14504 -- comment for Create_Restricted_Task_Sequential in s-tarest.ads).
14506 if Partition_Elaboration_Policy /= 'S' then
14507 Append_To (Args, Make_Identifier (Loc, Name_uChain));
14508 end if;
14510 -- Task name parameter. Take this from the _Task_Id parameter to the
14511 -- init call unless there is a Task_Name pragma, in which case we take
14512 -- the value from the pragma.
14514 if Has_Rep_Pragma (Ttyp, Name_Task_Name, Check_Parents => False) then
14515 -- Copy expression in full, because it may be dynamic and have
14516 -- side effects.
14518 Append_To (Args,
14519 New_Copy_Tree
14520 (Expression
14521 (First
14522 (Pragma_Argument_Associations
14523 (Get_Rep_Pragma
14524 (Ttyp, Name_Task_Name, Check_Parents => False))))));
14526 else
14527 Append_To (Args, Make_Identifier (Loc, Name_uTask_Name));
14528 end if;
14530 -- Created_Task parameter. This is the _Task_Id field of the task
14531 -- record value
14533 Append_To (Args,
14534 Make_Selected_Component (Loc,
14535 Prefix => Make_Identifier (Loc, Name_uInit),
14536 Selector_Name => Make_Identifier (Loc, Name_uTask_Id)));
14538 declare
14539 Create_RE : RE_Id;
14541 begin
14542 if Restricted_Profile then
14543 if Partition_Elaboration_Policy = 'S' then
14544 Create_RE := RE_Create_Restricted_Task_Sequential;
14545 else
14546 Create_RE := RE_Create_Restricted_Task;
14547 end if;
14548 else
14549 Create_RE := RE_Create_Task;
14550 end if;
14552 Name := New_Occurrence_Of (RTE (Create_RE), Loc);
14553 end;
14555 return
14556 Make_Procedure_Call_Statement (Loc,
14557 Name => Name,
14558 Parameter_Associations => Args);
14559 end Make_Task_Create_Call;
14561 ------------------------------
14562 -- Next_Protected_Operation --
14563 ------------------------------
14565 function Next_Protected_Operation (N : Node_Id) return Node_Id is
14566 Next_Op : Node_Id;
14568 begin
14569 -- Check whether there is a subsequent body for a protected operation
14570 -- in the current protected body. In Ada2012 that includes expression
14571 -- functions that are completions.
14573 Next_Op := Next (N);
14574 while Present (Next_Op)
14575 and then Nkind (Next_Op) not in
14576 N_Subprogram_Body | N_Entry_Body | N_Expression_Function
14577 loop
14578 Next (Next_Op);
14579 end loop;
14581 return Next_Op;
14582 end Next_Protected_Operation;
14584 ---------------------
14585 -- Null_Statements --
14586 ---------------------
14588 function Null_Statements (Stats : List_Id) return Boolean is
14589 Stmt : Node_Id;
14591 begin
14592 Stmt := First (Stats);
14593 while Nkind (Stmt) /= N_Empty
14594 and then (Nkind (Stmt) in N_Null_Statement | N_Label
14595 or else
14596 (Nkind (Stmt) = N_Pragma
14597 and then
14598 Pragma_Name_Unmapped (Stmt) in Name_Unreferenced
14599 | Name_Unmodified
14600 | Name_Warnings))
14601 loop
14602 Next (Stmt);
14603 end loop;
14605 return Nkind (Stmt) = N_Empty;
14606 end Null_Statements;
14608 --------------------------
14609 -- Parameter_Block_Pack --
14610 --------------------------
14612 function Parameter_Block_Pack
14613 (Loc : Source_Ptr;
14614 Blk_Typ : Entity_Id;
14615 Actuals : List_Id;
14616 Formals : List_Id;
14617 Decls : List_Id;
14618 Stmts : List_Id) return Entity_Id
14620 Actual : Entity_Id;
14621 Expr : Node_Id := Empty;
14622 Formal : Entity_Id;
14623 Has_Param : Boolean := False;
14624 P : Entity_Id;
14625 Params : List_Id;
14626 Temp_Asn : Node_Id;
14627 Temp_Nam : Node_Id;
14629 begin
14630 Actual := First (Actuals);
14631 Formal := Defining_Identifier (First (Formals));
14632 Params := New_List;
14633 while Present (Actual) loop
14634 if Is_By_Copy_Type (Etype (Actual)) then
14635 -- Generate:
14636 -- Jnn : aliased <formal-type>
14638 Temp_Nam := Make_Temporary (Loc, 'J');
14640 Append_To (Decls,
14641 Make_Object_Declaration (Loc,
14642 Aliased_Present => True,
14643 Defining_Identifier => Temp_Nam,
14644 Object_Definition =>
14645 New_Occurrence_Of (Etype (Formal), Loc)));
14647 -- The object is initialized with an explicit assignment
14648 -- later. Indicate that it does not need an initialization
14649 -- to prevent spurious warnings if the type excludes null.
14651 Set_No_Initialization (Last (Decls));
14653 if Ekind (Formal) /= E_Out_Parameter then
14655 -- Generate:
14656 -- Jnn := <actual>
14658 Temp_Asn :=
14659 New_Occurrence_Of (Temp_Nam, Loc);
14661 Set_Assignment_OK (Temp_Asn);
14663 Append_To (Stmts,
14664 Make_Assignment_Statement (Loc,
14665 Name => Temp_Asn,
14666 Expression => New_Copy_Tree (Actual)));
14667 end if;
14669 -- If the actual is not controlling, generate:
14671 -- Jnn'unchecked_access
14673 -- and add it to aggegate for access to formals. Note that the
14674 -- actual may be by-copy but still be a controlling actual if it
14675 -- is an access to class-wide interface.
14677 if not Is_Controlling_Actual (Actual) then
14678 Append_To (Params,
14679 Make_Attribute_Reference (Loc,
14680 Attribute_Name => Name_Unchecked_Access,
14681 Prefix => New_Occurrence_Of (Temp_Nam, Loc)));
14683 Has_Param := True;
14684 end if;
14686 -- The controlling parameter is omitted
14688 else
14689 if not Is_Controlling_Actual (Actual) then
14690 Append_To (Params,
14691 Make_Reference (Loc, New_Copy_Tree (Actual)));
14693 Has_Param := True;
14694 end if;
14695 end if;
14697 Next_Actual (Actual);
14698 Next_Formal_With_Extras (Formal);
14699 end loop;
14701 if Has_Param then
14702 Expr := Make_Aggregate (Loc, Params);
14703 end if;
14705 -- Generate:
14706 -- P : Ann := (
14707 -- J1'unchecked_access;
14708 -- <actual2>'reference;
14709 -- ...);
14711 P := Make_Temporary (Loc, 'P');
14713 Append_To (Decls,
14714 Make_Object_Declaration (Loc,
14715 Defining_Identifier => P,
14716 Object_Definition => New_Occurrence_Of (Blk_Typ, Loc),
14717 Expression => Expr));
14719 return P;
14720 end Parameter_Block_Pack;
14722 ----------------------------
14723 -- Parameter_Block_Unpack --
14724 ----------------------------
14726 function Parameter_Block_Unpack
14727 (Loc : Source_Ptr;
14728 P : Entity_Id;
14729 Actuals : List_Id;
14730 Formals : List_Id) return List_Id
14732 Actual : Entity_Id;
14733 Asnmt : Node_Id;
14734 Formal : Entity_Id;
14735 Has_Asnmt : Boolean := False;
14736 Result : constant List_Id := New_List;
14738 begin
14739 Actual := First (Actuals);
14740 Formal := Defining_Identifier (First (Formals));
14741 while Present (Actual) loop
14742 if Is_By_Copy_Type (Etype (Actual))
14743 and then Ekind (Formal) /= E_In_Parameter
14744 then
14745 -- Generate:
14746 -- <actual> := P.<formal>;
14748 Asnmt :=
14749 Make_Assignment_Statement (Loc,
14750 Name =>
14751 New_Copy (Actual),
14752 Expression =>
14753 Make_Explicit_Dereference (Loc,
14754 Make_Selected_Component (Loc,
14755 Prefix =>
14756 New_Occurrence_Of (P, Loc),
14757 Selector_Name =>
14758 Make_Identifier (Loc, Chars (Formal)))));
14760 Set_Assignment_OK (Name (Asnmt));
14761 Append_To (Result, Asnmt);
14763 Has_Asnmt := True;
14764 end if;
14766 Next_Actual (Actual);
14767 Next_Formal_With_Extras (Formal);
14768 end loop;
14770 if Has_Asnmt then
14771 return Result;
14772 else
14773 return New_List (Make_Null_Statement (Loc));
14774 end if;
14775 end Parameter_Block_Unpack;
14777 ---------------------
14778 -- Reset_Scopes_To --
14779 ---------------------
14781 procedure Reset_Scopes_To (Bod : Node_Id; E : Entity_Id) is
14782 function Reset_Scope (N : Node_Id) return Traverse_Result;
14783 -- Temporaries may have been declared during expansion of the procedure
14784 -- created for an entry body or an accept alternative. Indicate that
14785 -- their scope is the new body, to ensure proper generation of uplevel
14786 -- references where needed during unnesting.
14788 procedure Reset_Scopes is new Traverse_Proc (Reset_Scope);
14790 -----------------
14791 -- Reset_Scope --
14792 -----------------
14794 function Reset_Scope (N : Node_Id) return Traverse_Result is
14795 Decl : Node_Id;
14797 begin
14798 -- If this is a block statement with an Identifier, it forms a scope,
14799 -- so we want to reset its scope but not look inside.
14801 if N /= Bod
14802 and then Nkind (N) = N_Block_Statement
14803 and then Present (Identifier (N))
14804 then
14805 Set_Scope (Entity (Identifier (N)), E);
14806 return Skip;
14808 -- Ditto for a package declaration or a full type declaration, etc.
14810 elsif (Nkind (N) = N_Package_Declaration
14811 and then N /= Specification (N))
14812 or else Nkind (N) in N_Declaration
14813 or else Nkind (N) in N_Renaming_Declaration
14814 then
14815 Set_Scope (Defining_Entity (N), E);
14816 return Skip;
14818 elsif N = Bod then
14820 -- Scan declarations in new body. Declarations in the statement
14821 -- part will be handled during later traversal.
14823 Decl := First (Declarations (N));
14824 while Present (Decl) loop
14825 Reset_Scopes (Decl);
14826 Next (Decl);
14827 end loop;
14829 elsif Nkind (N) = N_Freeze_Entity then
14831 -- Scan the actions associated with a freeze node, which may
14832 -- actually be declarations with entities that need to have
14833 -- their scopes reset.
14835 Decl := First (Actions (N));
14836 while Present (Decl) loop
14837 Reset_Scopes (Decl);
14838 Next (Decl);
14839 end loop;
14841 elsif N /= Bod and then Nkind (N) in N_Proper_Body then
14843 -- A subprogram without a separate declaration may be encountered,
14844 -- and we need to reset the subprogram's entity's scope.
14846 if Nkind (N) = N_Subprogram_Body then
14847 Set_Scope (Defining_Entity (Specification (N)), E);
14848 end if;
14850 return Skip;
14851 end if;
14853 return OK;
14854 end Reset_Scope;
14856 -- Start of processing for Reset_Scopes_To
14858 begin
14859 Reset_Scopes (Bod);
14860 end Reset_Scopes_To;
14862 ----------------------
14863 -- Set_Discriminals --
14864 ----------------------
14866 procedure Set_Discriminals (Dec : Node_Id) is
14867 D : Entity_Id;
14868 Pdef : Entity_Id;
14869 D_Minal : Entity_Id;
14871 begin
14872 pragma Assert (Nkind (Dec) = N_Protected_Type_Declaration);
14873 Pdef := Defining_Identifier (Dec);
14875 if Has_Discriminants (Pdef) then
14876 D := First_Discriminant (Pdef);
14877 while Present (D) loop
14878 D_Minal :=
14879 Make_Defining_Identifier (Sloc (D),
14880 Chars => New_External_Name (Chars (D), 'D'));
14882 Mutate_Ekind (D_Minal, E_Constant);
14883 Set_Etype (D_Minal, Etype (D));
14884 Set_Scope (D_Minal, Pdef);
14885 Set_Discriminal (D, D_Minal);
14886 Set_Discriminal_Link (D_Minal, D);
14888 Next_Discriminant (D);
14889 end loop;
14890 end if;
14891 end Set_Discriminals;
14893 -----------------------
14894 -- Trivial_Accept_OK --
14895 -----------------------
14897 function Trivial_Accept_OK return Boolean is
14898 begin
14899 case Opt.Task_Dispatching_Policy is
14901 -- If we have the default task dispatching policy in effect, we can
14902 -- definitely do the optimization (one way of looking at this is to
14903 -- think of the formal definition of the default policy being allowed
14904 -- to run any task it likes after a rendezvous, so even if notionally
14905 -- a full rescheduling occurs, we can say that our dispatching policy
14906 -- (i.e. the default dispatching policy) reorders the queue to be the
14907 -- same as just before the call.
14909 when ' ' =>
14910 return True;
14912 -- FIFO_Within_Priorities certainly does not permit this
14913 -- optimization since the Rendezvous is a scheduling action that may
14914 -- require some other task to be run.
14916 when 'F' =>
14917 return False;
14919 -- For now, disallow the optimization for all other policies. This
14920 -- may be over-conservative, but it is certainly not incorrect.
14922 when others =>
14923 return False;
14924 end case;
14925 end Trivial_Accept_OK;
14927 end Exp_Ch9;