PR libstdc++/87308 adjust regex used in std::any pretty printer
[official-gcc.git] / gcc / ada / exp_prag.adb
blob485f066f7023bf88fb38827e6ba9a96b81bcc022
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- E X P _ P R A G --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2018, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
20 -- --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
23 -- --
24 ------------------------------------------------------------------------------
26 with Atree; use Atree;
27 with Casing; use Casing;
28 with Checks; use Checks;
29 with Debug; use Debug;
30 with Einfo; use Einfo;
31 with Errout; use Errout;
32 with Exp_Ch11; use Exp_Ch11;
33 with Exp_Util; use Exp_Util;
34 with Expander; use Expander;
35 with Inline; use Inline;
36 with Lib; use Lib;
37 with Namet; use Namet;
38 with Nlists; use Nlists;
39 with Nmake; use Nmake;
40 with Opt; use Opt;
41 with Restrict; use Restrict;
42 with Rident; use Rident;
43 with Rtsfind; use Rtsfind;
44 with Sem; use Sem;
45 with Sem_Aux; use Sem_Aux;
46 with Sem_Ch8; use Sem_Ch8;
47 with Sem_Prag; use Sem_Prag;
48 with Sem_Util; use Sem_Util;
49 with Sinfo; use Sinfo;
50 with Sinput; use Sinput;
51 with Snames; use Snames;
52 with Stringt; use Stringt;
53 with Stand; use Stand;
54 with Tbuild; use Tbuild;
55 with Uintp; use Uintp;
56 with Validsw; use Validsw;
58 package body Exp_Prag is
60 -----------------------
61 -- Local Subprograms --
62 -----------------------
64 function Arg1 (N : Node_Id) return Node_Id;
65 function Arg2 (N : Node_Id) return Node_Id;
66 function Arg3 (N : Node_Id) return Node_Id;
67 -- Obtain specified pragma argument expression
69 procedure Expand_Pragma_Abort_Defer (N : Node_Id);
70 procedure Expand_Pragma_Check (N : Node_Id);
71 procedure Expand_Pragma_Common_Object (N : Node_Id);
72 procedure Expand_Pragma_Import_Or_Interface (N : Node_Id);
73 procedure Expand_Pragma_Inspection_Point (N : Node_Id);
74 procedure Expand_Pragma_Interrupt_Priority (N : Node_Id);
75 procedure Expand_Pragma_Loop_Variant (N : Node_Id);
76 procedure Expand_Pragma_Psect_Object (N : Node_Id);
77 procedure Expand_Pragma_Relative_Deadline (N : Node_Id);
78 procedure Expand_Pragma_Suppress_Initialization (N : Node_Id);
80 procedure Undo_Initialization (Def_Id : Entity_Id; N : Node_Id);
81 -- This procedure is used to undo initialization already done for Def_Id,
82 -- which is always an E_Variable, in response to the occurrence of the
83 -- pragma N, a pragma Interface, Import, or Suppress_Initialization. In all
84 -- these cases we want no initialization to occur, but we have already done
85 -- the initialization by the time we see the pragma, so we have to undo it.
87 ----------
88 -- Arg1 --
89 ----------
91 function Arg1 (N : Node_Id) return Node_Id is
92 Arg : constant Node_Id := First (Pragma_Argument_Associations (N));
93 begin
94 if Present (Arg)
95 and then Nkind (Arg) = N_Pragma_Argument_Association
96 then
97 return Expression (Arg);
98 else
99 return Arg;
100 end if;
101 end Arg1;
103 ----------
104 -- Arg2 --
105 ----------
107 function Arg2 (N : Node_Id) return Node_Id is
108 Arg1 : constant Node_Id := First (Pragma_Argument_Associations (N));
110 begin
111 if No (Arg1) then
112 return Empty;
114 else
115 declare
116 Arg : constant Node_Id := Next (Arg1);
117 begin
118 if Present (Arg)
119 and then Nkind (Arg) = N_Pragma_Argument_Association
120 then
121 return Expression (Arg);
122 else
123 return Arg;
124 end if;
125 end;
126 end if;
127 end Arg2;
129 ----------
130 -- Arg3 --
131 ----------
133 function Arg3 (N : Node_Id) return Node_Id is
134 Arg1 : constant Node_Id := First (Pragma_Argument_Associations (N));
136 begin
137 if No (Arg1) then
138 return Empty;
140 else
141 declare
142 Arg : Node_Id := Next (Arg1);
143 begin
144 if No (Arg) then
145 return Empty;
147 else
148 Next (Arg);
150 if Present (Arg)
151 and then Nkind (Arg) = N_Pragma_Argument_Association
152 then
153 return Expression (Arg);
154 else
155 return Arg;
156 end if;
157 end if;
158 end;
159 end if;
160 end Arg3;
162 ---------------------
163 -- Expand_N_Pragma --
164 ---------------------
166 procedure Expand_N_Pragma (N : Node_Id) is
167 Pname : constant Name_Id := Pragma_Name (N);
168 Prag_Id : constant Pragma_Id := Get_Pragma_Id (Pname);
170 begin
171 -- Suppress the expansion of an ignored assertion pragma. Such a pragma
172 -- should not be transformed into a null statment because:
174 -- * The pragma may be part of the rep item chain of a type, in which
175 -- case rewriting it will destroy the chain.
177 -- * The analysis of the pragma may involve two parts (see routines
178 -- Analyze_xxx_In_Decl_Part). The second part of the analysis will
179 -- not happen if the pragma is rewritten.
181 if Assertion_Expression_Pragma (Prag_Id) and then Is_Ignored (N) then
182 return;
184 -- Rewrite the pragma into a null statement when it is ignored using
185 -- pragma Ignore_Pragma, or denotes Default_Scalar_Storage_Order and
186 -- compilation switch -gnatI is in effect.
188 elsif Should_Ignore_Pragma_Sem (N)
189 or else (Prag_Id = Pragma_Default_Scalar_Storage_Order
190 and then Ignore_Rep_Clauses)
191 then
192 Rewrite (N, Make_Null_Statement (Sloc (N)));
193 return;
194 end if;
196 case Prag_Id is
198 -- Pragmas requiring special expander action
200 when Pragma_Abort_Defer =>
201 Expand_Pragma_Abort_Defer (N);
203 when Pragma_Check =>
204 Expand_Pragma_Check (N);
206 when Pragma_Common_Object =>
207 Expand_Pragma_Common_Object (N);
209 when Pragma_Import =>
210 Expand_Pragma_Import_Or_Interface (N);
212 when Pragma_Inspection_Point =>
213 Expand_Pragma_Inspection_Point (N);
215 when Pragma_Interface =>
216 Expand_Pragma_Import_Or_Interface (N);
218 when Pragma_Interrupt_Priority =>
219 Expand_Pragma_Interrupt_Priority (N);
221 when Pragma_Loop_Variant =>
222 Expand_Pragma_Loop_Variant (N);
224 when Pragma_Psect_Object =>
225 Expand_Pragma_Psect_Object (N);
227 when Pragma_Relative_Deadline =>
228 Expand_Pragma_Relative_Deadline (N);
230 when Pragma_Suppress_Initialization =>
231 Expand_Pragma_Suppress_Initialization (N);
233 -- All other pragmas need no expander action (includes
234 -- Unknown_Pragma).
236 when others => null;
237 end case;
238 end Expand_N_Pragma;
240 -------------------------------
241 -- Expand_Pragma_Abort_Defer --
242 -------------------------------
244 -- An Abort_Defer pragma appears as the first statement in a handled
245 -- statement sequence (right after the begin). It defers aborts for
246 -- the entire statement sequence, but not for any declarations or
247 -- handlers (if any) associated with this statement sequence.
249 -- The transformation is to transform
251 -- pragma Abort_Defer;
252 -- statements;
254 -- into
256 -- begin
257 -- Abort_Defer.all;
258 -- statements
259 -- exception
260 -- when all others =>
261 -- Abort_Undefer.all;
262 -- raise;
263 -- at end
264 -- Abort_Undefer_Direct;
265 -- end;
267 procedure Expand_Pragma_Abort_Defer (N : Node_Id) is
268 begin
269 -- Abort_Defer has no useful effect if Abort's are not allowed
271 if not Abort_Allowed then
272 return;
273 end if;
275 -- Normal case where abort is possible
277 declare
278 Loc : constant Source_Ptr := Sloc (N);
279 Stm : Node_Id;
280 Stms : List_Id;
281 HSS : Node_Id;
282 Blk : constant Entity_Id :=
283 New_Internal_Entity (E_Block, Current_Scope, Sloc (N), 'B');
284 AUD : constant Entity_Id := RTE (RE_Abort_Undefer_Direct);
286 begin
287 Stms := New_List (Build_Runtime_Call (Loc, RE_Abort_Defer));
288 loop
289 Stm := Remove_Next (N);
290 exit when No (Stm);
291 Append (Stm, Stms);
292 end loop;
294 HSS :=
295 Make_Handled_Sequence_Of_Statements (Loc,
296 Statements => Stms,
297 At_End_Proc => New_Occurrence_Of (AUD, Loc));
299 -- Present the Abort_Undefer_Direct function to the backend so that
300 -- it can inline the call to the function.
302 Add_Inlined_Body (AUD, N);
304 Rewrite (N,
305 Make_Block_Statement (Loc, Handled_Statement_Sequence => HSS));
307 Set_Scope (Blk, Current_Scope);
308 Set_Etype (Blk, Standard_Void_Type);
309 Set_Identifier (N, New_Occurrence_Of (Blk, Sloc (N)));
310 Expand_At_End_Handler (HSS, Blk);
311 Analyze (N);
312 end;
313 end Expand_Pragma_Abort_Defer;
315 --------------------------
316 -- Expand_Pragma_Check --
317 --------------------------
319 procedure Expand_Pragma_Check (N : Node_Id) is
320 Cond : constant Node_Id := Arg2 (N);
321 Nam : constant Name_Id := Chars (Arg1 (N));
322 Msg : Node_Id;
324 Loc : constant Source_Ptr := Sloc (First_Node (Cond));
325 -- Source location used in the case of a failed assertion: point to the
326 -- failing condition, not Loc. Note that the source location of the
327 -- expression is not usually the best choice here, because it points to
328 -- the location of the topmost tree node, which may be an operator in
329 -- the middle of the source text of the expression. For example, it gets
330 -- located on the last AND keyword in a chain of boolean expressiond
331 -- AND'ed together. It is best to put the message on the first character
332 -- of the condition, which is the effect of the First_Node call here.
333 -- This source location is used to build the default exception message,
334 -- and also as the sloc of the call to the runtime subprogram raising
335 -- Assert_Failure, so that coverage analysis tools can relate the
336 -- call to the failed check.
338 procedure Replace_Discriminals_Of_Protected_Op (Expr : Node_Id);
339 -- Discriminants of the enclosing protected object may be referenced
340 -- in the expression of a precondition of a protected operation.
341 -- In the body of the operation these references must be replaced by
342 -- the discriminal created for them, which are renamings of the
343 -- discriminants of the object that is the target of the operation.
344 -- This replacement is done by visibility when the references appear
345 -- in the subprogram body, but in the case of a condition which appears
346 -- on the specification of the subprogram it has be done separately
347 -- because the condition has been replaced by a Check pragma and
348 -- analyzed earlier, before the creation of the discriminal renaming
349 -- declarations that are added to the subprogram body.
351 ------------------------------------------
352 -- Replace_Discriminals_Of_Protected_Op --
353 ------------------------------------------
355 procedure Replace_Discriminals_Of_Protected_Op (Expr : Node_Id) is
356 function Find_Corresponding_Discriminal
357 (E : Entity_Id) return Entity_Id;
358 -- Find the local entity that renames a discriminant of the enclosing
359 -- protected type, and has a matching name.
361 function Replace_Discr_Ref (N : Node_Id) return Traverse_Result;
362 -- Replace a reference to a discriminant of the original protected
363 -- type by the local renaming declaration of the discriminant of
364 -- the target object.
366 ------------------------------------
367 -- Find_Corresponding_Discriminal --
368 ------------------------------------
370 function Find_Corresponding_Discriminal
371 (E : Entity_Id) return Entity_Id
373 R : Entity_Id;
375 begin
376 R := First_Entity (Current_Scope);
378 while Present (R) loop
379 if Nkind (Parent (R)) = N_Object_Renaming_Declaration
380 and then Present (Discriminal_Link (R))
381 and then Chars (Discriminal_Link (R)) = Chars (E)
382 then
383 return R;
384 end if;
386 Next_Entity (R);
387 end loop;
389 return Empty;
390 end Find_Corresponding_Discriminal;
392 -----------------------
393 -- Replace_Discr_Ref --
394 -----------------------
396 function Replace_Discr_Ref (N : Node_Id) return Traverse_Result is
397 R : Entity_Id;
399 begin
400 if Is_Entity_Name (N)
401 and then Present (Discriminal_Link (Entity (N)))
402 then
403 R := Find_Corresponding_Discriminal (Entity (N));
404 Rewrite (N, New_Occurrence_Of (R, Sloc (N)));
405 end if;
407 return OK;
408 end Replace_Discr_Ref;
410 procedure Replace_Discriminant_References is
411 new Traverse_Proc (Replace_Discr_Ref);
413 -- Start of processing for Replace_Discriminals_Of_Protected_Op
415 begin
416 Replace_Discriminant_References (Expr);
417 end Replace_Discriminals_Of_Protected_Op;
419 -- Start of processing for Expand_Pragma_Check
421 begin
422 -- Nothing to do if pragma is ignored
424 if Is_Ignored (N) then
425 return;
426 end if;
428 -- Since this check is active, rewrite the pragma into a corresponding
429 -- if statement, and then analyze the statement.
431 -- The normal case expansion transforms:
433 -- pragma Check (name, condition [,message]);
435 -- into
437 -- if not condition then
438 -- System.Assertions.Raise_Assert_Failure (Str);
439 -- end if;
441 -- where Str is the message if one is present, or the default of
442 -- name failed at file:line if no message is given (the "name failed
443 -- at" is omitted for name = Assertion, since it is redundant, given
444 -- that the name of the exception is Assert_Failure.)
446 -- Also, instead of "XXX failed at", we generate slightly
447 -- different messages for some of the contract assertions (see
448 -- code below for details).
450 -- An alternative expansion is used when the No_Exception_Propagation
451 -- restriction is active and there is a local Assert_Failure handler.
452 -- This is not a common combination of circumstances, but it occurs in
453 -- the context of Aunit and the zero footprint profile. In this case we
454 -- generate:
456 -- if not condition then
457 -- raise Assert_Failure;
458 -- end if;
460 -- This will then be transformed into a goto, and the local handler will
461 -- be able to handle the assert error (which would not be the case if a
462 -- call is made to the Raise_Assert_Failure procedure).
464 -- We also generate the direct raise if the Suppress_Exception_Locations
465 -- is active, since we don't want to generate messages in this case.
467 -- Note that the reason we do not always generate a direct raise is that
468 -- the form in which the procedure is called allows for more efficient
469 -- breakpointing of assertion errors.
471 -- Generate the appropriate if statement. Note that we consider this to
472 -- be an explicit conditional in the source, not an implicit if, so we
473 -- do not call Make_Implicit_If_Statement.
475 -- Case where we generate a direct raise
477 if ((Debug_Flag_Dot_G
478 or else Restriction_Active (No_Exception_Propagation))
479 and then Present (Find_Local_Handler (RTE (RE_Assert_Failure), N)))
480 or else (Opt.Exception_Locations_Suppressed and then No (Arg3 (N)))
481 then
482 Rewrite (N,
483 Make_If_Statement (Loc,
484 Condition => Make_Op_Not (Loc, Right_Opnd => Cond),
485 Then_Statements => New_List (
486 Make_Raise_Statement (Loc,
487 Name => New_Occurrence_Of (RTE (RE_Assert_Failure), Loc)))));
489 -- Case where we call the procedure
491 else
492 -- If we have a message given, use it
494 if Present (Arg3 (N)) then
495 Msg := Get_Pragma_Arg (Arg3 (N));
497 -- Here we have no string, so prepare one
499 else
500 declare
501 Loc_Str : constant String := Build_Location_String (Loc);
503 begin
504 Name_Len := 0;
506 -- For Assert, we just use the location
508 if Nam = Name_Assert then
509 null;
511 -- For predicate, we generate the string "predicate failed at
512 -- yyy". We prefer all lower case for predicate.
514 elsif Nam = Name_Predicate then
515 Add_Str_To_Name_Buffer ("predicate failed at ");
517 -- For special case of Precondition/Postcondition the string is
518 -- "failed xx from yy" where xx is precondition/postcondition
519 -- in all lower case. The reason for this different wording is
520 -- that the failure is not at the point of occurrence of the
521 -- pragma, unlike the other Check cases.
523 elsif Nam_In (Nam, Name_Precondition, Name_Postcondition) then
524 Get_Name_String (Nam);
525 Insert_Str_In_Name_Buffer ("failed ", 1);
526 Add_Str_To_Name_Buffer (" from ");
528 -- For special case of Invariant, the string is "failed
529 -- invariant from yy", to be consistent with the string that is
530 -- generated for the aspect case (the code later on checks for
531 -- this specific string to modify it in some cases, so this is
532 -- functionally important).
534 elsif Nam = Name_Invariant then
535 Add_Str_To_Name_Buffer ("failed invariant from ");
537 -- For all other checks, the string is "xxx failed at yyy"
538 -- where xxx is the check name with appropriate casing.
540 else
541 Get_Name_String (Nam);
542 Set_Casing
543 (Identifier_Casing (Source_Index (Current_Sem_Unit)));
544 Add_Str_To_Name_Buffer (" failed at ");
545 end if;
547 -- In all cases, add location string
549 Add_Str_To_Name_Buffer (Loc_Str);
551 -- Build the message
553 Msg := Make_String_Literal (Loc, Name_Buffer (1 .. Name_Len));
554 end;
555 end if;
557 -- For a precondition, replace references to discriminants of a
558 -- protected type with the local discriminals.
560 if Is_Protected_Type (Scope (Current_Scope))
561 and then Has_Discriminants (Scope (Current_Scope))
562 and then From_Aspect_Specification (N)
563 then
564 Replace_Discriminals_Of_Protected_Op (Cond);
565 end if;
567 -- Now rewrite as an if statement
569 Rewrite (N,
570 Make_If_Statement (Loc,
571 Condition => Make_Op_Not (Loc, Right_Opnd => Cond),
572 Then_Statements => New_List (
573 Make_Procedure_Call_Statement (Loc,
574 Name =>
575 New_Occurrence_Of (RTE (RE_Raise_Assert_Failure), Loc),
576 Parameter_Associations => New_List (Relocate_Node (Msg))))));
577 end if;
579 Analyze (N);
581 -- If new condition is always false, give a warning
583 if Warn_On_Assertion_Failure
584 and then Nkind (N) = N_Procedure_Call_Statement
585 and then Is_RTE (Entity (Name (N)), RE_Raise_Assert_Failure)
586 then
587 -- If original condition was a Standard.False, we assume that this is
588 -- indeed intended to raise assert error and no warning is required.
590 if Is_Entity_Name (Original_Node (Cond))
591 and then Entity (Original_Node (Cond)) = Standard_False
592 then
593 null;
595 elsif Nam = Name_Assert then
596 Error_Msg_N ("?A?assertion will fail at run time", N);
597 else
598 Error_Msg_N ("?A?check will fail at run time", N);
599 end if;
600 end if;
601 end Expand_Pragma_Check;
603 ---------------------------------
604 -- Expand_Pragma_Common_Object --
605 ---------------------------------
607 -- Use a machine attribute to replicate semantic effect in DEC Ada
609 -- pragma Machine_Attribute (intern_name, "common_object", extern_name);
611 -- For now we do nothing with the size attribute ???
613 -- Note: Psect_Object shares this processing
615 procedure Expand_Pragma_Common_Object (N : Node_Id) is
616 Loc : constant Source_Ptr := Sloc (N);
618 Internal : constant Node_Id := Arg1 (N);
619 External : constant Node_Id := Arg2 (N);
621 Psect : Node_Id;
622 -- Psect value upper cased as string literal
624 Iloc : constant Source_Ptr := Sloc (Internal);
625 Eloc : constant Source_Ptr := Sloc (External);
626 Ploc : Source_Ptr;
628 begin
629 -- Acquire Psect value and fold to upper case
631 if Present (External) then
632 if Nkind (External) = N_String_Literal then
633 String_To_Name_Buffer (Strval (External));
634 else
635 Get_Name_String (Chars (External));
636 end if;
638 Set_All_Upper_Case;
640 Psect :=
641 Make_String_Literal (Eloc, Strval => String_From_Name_Buffer);
643 else
644 Get_Name_String (Chars (Internal));
645 Set_All_Upper_Case;
646 Psect :=
647 Make_String_Literal (Iloc, Strval => String_From_Name_Buffer);
648 end if;
650 Ploc := Sloc (Psect);
652 -- Insert the pragma
654 Insert_After_And_Analyze (N,
655 Make_Pragma (Loc,
656 Chars => Name_Machine_Attribute,
657 Pragma_Argument_Associations => New_List (
658 Make_Pragma_Argument_Association (Iloc,
659 Expression => New_Copy_Tree (Internal)),
660 Make_Pragma_Argument_Association (Eloc,
661 Expression =>
662 Make_String_Literal (Sloc => Ploc, Strval => "common_object")),
663 Make_Pragma_Argument_Association (Ploc,
664 Expression => New_Copy_Tree (Psect)))));
665 end Expand_Pragma_Common_Object;
667 ----------------------------------
668 -- Expand_Pragma_Contract_Cases --
669 ----------------------------------
671 -- Pragma Contract_Cases is expanded in the following manner:
673 -- subprogram S is
674 -- Count : Natural := 0;
675 -- Flag_1 : Boolean := False;
676 -- . . .
677 -- Flag_N : Boolean := False;
678 -- Flag_N+1 : Boolean := False; -- when "others" present
679 -- Pref_1 : ...;
680 -- . . .
681 -- Pref_M : ...;
683 -- <preconditions (if any)>
685 -- -- Evaluate all case guards
687 -- if Case_Guard_1 then
688 -- Flag_1 := True;
689 -- Count := Count + 1;
690 -- end if;
691 -- . . .
692 -- if Case_Guard_N then
693 -- Flag_N := True;
694 -- Count := Count + 1;
695 -- end if;
697 -- -- Emit errors depending on the number of case guards that
698 -- -- evaluated to True.
700 -- if Count = 0 then
701 -- raise Assertion_Error with "xxx contract cases incomplete";
702 -- <or>
703 -- Flag_N+1 := True; -- when "others" present
705 -- elsif Count > 1 then
706 -- declare
707 -- Str0 : constant String :=
708 -- "contract cases overlap for subprogram ABC";
709 -- Str1 : constant String :=
710 -- (if Flag_1 then
711 -- Str0 & "case guard at xxx evaluates to True"
712 -- else Str0);
713 -- StrN : constant String :=
714 -- (if Flag_N then
715 -- StrN-1 & "case guard at xxx evaluates to True"
716 -- else StrN-1);
717 -- begin
718 -- raise Assertion_Error with StrN;
719 -- end;
720 -- end if;
722 -- -- Evaluate all attribute 'Old prefixes found in the selected
723 -- -- consequence.
725 -- if Flag_1 then
726 -- Pref_1 := <prefix of 'Old found in Consequence_1>
727 -- . . .
728 -- elsif Flag_N then
729 -- Pref_M := <prefix of 'Old found in Consequence_N>
730 -- end if;
732 -- procedure _Postconditions is
733 -- begin
734 -- <postconditions (if any)>
736 -- if Flag_1 and then not Consequence_1 then
737 -- raise Assertion_Error with "failed contract case at xxx";
738 -- end if;
739 -- . . .
740 -- if Flag_N[+1] and then not Consequence_N[+1] then
741 -- raise Assertion_Error with "failed contract case at xxx";
742 -- end if;
743 -- end _Postconditions;
744 -- begin
745 -- . . .
746 -- end S;
748 procedure Expand_Pragma_Contract_Cases
749 (CCs : Node_Id;
750 Subp_Id : Entity_Id;
751 Decls : List_Id;
752 Stmts : in out List_Id)
754 Loc : constant Source_Ptr := Sloc (CCs);
756 procedure Case_Guard_Error
757 (Decls : List_Id;
758 Flag : Entity_Id;
759 Error_Loc : Source_Ptr;
760 Msg : in out Entity_Id);
761 -- Given a declarative list Decls, status flag Flag, the location of the
762 -- error and a string Msg, construct the following check:
763 -- Msg : constant String :=
764 -- (if Flag then
765 -- Msg & "case guard at Error_Loc evaluates to True"
766 -- else Msg);
767 -- The resulting code is added to Decls
769 procedure Consequence_Error
770 (Checks : in out Node_Id;
771 Flag : Entity_Id;
772 Conseq : Node_Id);
773 -- Given an if statement Checks, status flag Flag and a consequence
774 -- Conseq, construct the following check:
775 -- [els]if Flag and then not Conseq then
776 -- raise Assertion_Error
777 -- with "failed contract case at Sloc (Conseq)";
778 -- [end if;]
779 -- The resulting code is added to Checks
781 function Declaration_Of (Id : Entity_Id) return Node_Id;
782 -- Given the entity Id of a boolean flag, generate:
783 -- Id : Boolean := False;
785 procedure Expand_Attributes_In_Consequence
786 (Decls : List_Id;
787 Evals : in out Node_Id;
788 Flag : Entity_Id;
789 Conseq : Node_Id);
790 -- Perform specialized expansion of all attribute 'Old references found
791 -- in consequence Conseq such that at runtime only prefixes coming from
792 -- the selected consequence are evaluated. Similarly expand attribute
793 -- 'Result references by replacing them with identifier _result which
794 -- resolves to the sole formal parameter of procedure _Postconditions.
795 -- Any temporaries generated in the process are added to declarations
796 -- Decls. Evals is a complex if statement tasked with the evaluation of
797 -- all prefixes coming from a single selected consequence. Flag is the
798 -- corresponding case guard flag. Conseq is the consequence expression.
800 function Increment (Id : Entity_Id) return Node_Id;
801 -- Given the entity Id of a numerical variable, generate:
802 -- Id := Id + 1;
804 function Set (Id : Entity_Id) return Node_Id;
805 -- Given the entity Id of a boolean variable, generate:
806 -- Id := True;
808 ----------------------
809 -- Case_Guard_Error --
810 ----------------------
812 procedure Case_Guard_Error
813 (Decls : List_Id;
814 Flag : Entity_Id;
815 Error_Loc : Source_Ptr;
816 Msg : in out Entity_Id)
818 New_Line : constant Character := Character'Val (10);
819 New_Msg : constant Entity_Id := Make_Temporary (Loc, 'S');
821 begin
822 Start_String;
823 Store_String_Char (New_Line);
824 Store_String_Chars (" case guard at ");
825 Store_String_Chars (Build_Location_String (Error_Loc));
826 Store_String_Chars (" evaluates to True");
828 -- Generate:
829 -- New_Msg : constant String :=
830 -- (if Flag then
831 -- Msg & "case guard at Error_Loc evaluates to True"
832 -- else Msg);
834 Append_To (Decls,
835 Make_Object_Declaration (Loc,
836 Defining_Identifier => New_Msg,
837 Constant_Present => True,
838 Object_Definition => New_Occurrence_Of (Standard_String, Loc),
839 Expression =>
840 Make_If_Expression (Loc,
841 Expressions => New_List (
842 New_Occurrence_Of (Flag, Loc),
844 Make_Op_Concat (Loc,
845 Left_Opnd => New_Occurrence_Of (Msg, Loc),
846 Right_Opnd => Make_String_Literal (Loc, End_String)),
848 New_Occurrence_Of (Msg, Loc)))));
850 Msg := New_Msg;
851 end Case_Guard_Error;
853 -----------------------
854 -- Consequence_Error --
855 -----------------------
857 procedure Consequence_Error
858 (Checks : in out Node_Id;
859 Flag : Entity_Id;
860 Conseq : Node_Id)
862 Cond : Node_Id;
863 Error : Node_Id;
865 begin
866 -- Generate:
867 -- Flag and then not Conseq
869 Cond :=
870 Make_And_Then (Loc,
871 Left_Opnd => New_Occurrence_Of (Flag, Loc),
872 Right_Opnd =>
873 Make_Op_Not (Loc,
874 Right_Opnd => Relocate_Node (Conseq)));
876 -- Generate:
877 -- raise Assertion_Error
878 -- with "failed contract case at Sloc (Conseq)";
880 Start_String;
881 Store_String_Chars ("failed contract case at ");
882 Store_String_Chars (Build_Location_String (Sloc (Conseq)));
884 Error :=
885 Make_Procedure_Call_Statement (Loc,
886 Name =>
887 New_Occurrence_Of (RTE (RE_Raise_Assert_Failure), Loc),
888 Parameter_Associations => New_List (
889 Make_String_Literal (Loc, End_String)));
891 if No (Checks) then
892 Checks :=
893 Make_Implicit_If_Statement (CCs,
894 Condition => Cond,
895 Then_Statements => New_List (Error));
897 else
898 if No (Elsif_Parts (Checks)) then
899 Set_Elsif_Parts (Checks, New_List);
900 end if;
902 Append_To (Elsif_Parts (Checks),
903 Make_Elsif_Part (Loc,
904 Condition => Cond,
905 Then_Statements => New_List (Error)));
906 end if;
907 end Consequence_Error;
909 --------------------
910 -- Declaration_Of --
911 --------------------
913 function Declaration_Of (Id : Entity_Id) return Node_Id is
914 begin
915 return
916 Make_Object_Declaration (Loc,
917 Defining_Identifier => Id,
918 Object_Definition => New_Occurrence_Of (Standard_Boolean, Loc),
919 Expression => New_Occurrence_Of (Standard_False, Loc));
920 end Declaration_Of;
922 --------------------------------------
923 -- Expand_Attributes_In_Consequence --
924 --------------------------------------
926 procedure Expand_Attributes_In_Consequence
927 (Decls : List_Id;
928 Evals : in out Node_Id;
929 Flag : Entity_Id;
930 Conseq : Node_Id)
932 Eval_Stmts : List_Id := No_List;
933 -- The evaluation sequence expressed as assignment statements of all
934 -- prefixes of attribute 'Old found in the current consequence.
936 function Expand_Attributes (N : Node_Id) return Traverse_Result;
937 -- Determine whether an arbitrary node denotes attribute 'Old or
938 -- 'Result and if it does, perform all expansion-related actions.
940 -----------------------
941 -- Expand_Attributes --
942 -----------------------
944 function Expand_Attributes (N : Node_Id) return Traverse_Result is
945 Decl : Node_Id;
946 Pref : Node_Id;
947 Temp : Entity_Id;
949 begin
950 -- Attribute 'Old
952 if Nkind (N) = N_Attribute_Reference
953 and then Attribute_Name (N) = Name_Old
954 then
955 Pref := Prefix (N);
956 Temp := Make_Temporary (Loc, 'T', Pref);
957 Set_Etype (Temp, Etype (Pref));
959 -- Generate a temporary to capture the value of the prefix:
960 -- Temp : <Pref type>;
962 Decl :=
963 Make_Object_Declaration (Loc,
964 Defining_Identifier => Temp,
965 Object_Definition =>
966 New_Occurrence_Of (Etype (Pref), Loc));
968 -- Place that temporary at the beginning of declarations, to
969 -- prevent anomalies in the GNATprove flow-analysis pass in
970 -- the precondition procedure that follows.
972 Prepend_To (Decls, Decl);
974 -- If the type is unconstrained, the prefix provides its
975 -- value and constraint, so add it to declaration.
977 if not Is_Constrained (Etype (Pref))
978 and then Is_Entity_Name (Pref)
979 then
980 Set_Expression (Decl, Pref);
981 Analyze (Decl);
983 -- Otherwise add an assignment statement to temporary using
984 -- prefix as RHS.
986 else
987 Analyze (Decl);
989 if No (Eval_Stmts) then
990 Eval_Stmts := New_List;
991 end if;
993 Append_To (Eval_Stmts,
994 Make_Assignment_Statement (Loc,
995 Name => New_Occurrence_Of (Temp, Loc),
996 Expression => Pref));
998 end if;
1000 -- Ensure that the prefix is valid
1002 if Validity_Checks_On and then Validity_Check_Operands then
1003 Ensure_Valid (Pref);
1004 end if;
1006 -- Replace the original attribute 'Old by a reference to the
1007 -- generated temporary.
1009 Rewrite (N, New_Occurrence_Of (Temp, Loc));
1011 -- Attribute 'Result
1013 elsif Is_Attribute_Result (N) then
1014 Rewrite (N, Make_Identifier (Loc, Name_uResult));
1015 end if;
1017 return OK;
1018 end Expand_Attributes;
1020 procedure Expand_Attributes_In is
1021 new Traverse_Proc (Expand_Attributes);
1023 -- Start of processing for Expand_Attributes_In_Consequence
1025 begin
1026 -- Inspect the consequence and expand any attribute 'Old and 'Result
1027 -- references found within.
1029 Expand_Attributes_In (Conseq);
1031 -- The consequence does not contain any attribute 'Old references
1033 if No (Eval_Stmts) then
1034 return;
1035 end if;
1037 -- Augment the machinery to trigger the evaluation of all prefixes
1038 -- found in the step above. If Eval is empty, then this is the first
1039 -- consequence to yield expansion of 'Old. Generate:
1041 -- if Flag then
1042 -- <evaluation statements>
1043 -- end if;
1045 if No (Evals) then
1046 Evals :=
1047 Make_Implicit_If_Statement (CCs,
1048 Condition => New_Occurrence_Of (Flag, Loc),
1049 Then_Statements => Eval_Stmts);
1051 -- Otherwise generate:
1052 -- elsif Flag then
1053 -- <evaluation statements>
1054 -- end if;
1056 else
1057 if No (Elsif_Parts (Evals)) then
1058 Set_Elsif_Parts (Evals, New_List);
1059 end if;
1061 Append_To (Elsif_Parts (Evals),
1062 Make_Elsif_Part (Loc,
1063 Condition => New_Occurrence_Of (Flag, Loc),
1064 Then_Statements => Eval_Stmts));
1065 end if;
1066 end Expand_Attributes_In_Consequence;
1068 ---------------
1069 -- Increment --
1070 ---------------
1072 function Increment (Id : Entity_Id) return Node_Id is
1073 begin
1074 return
1075 Make_Assignment_Statement (Loc,
1076 Name => New_Occurrence_Of (Id, Loc),
1077 Expression =>
1078 Make_Op_Add (Loc,
1079 Left_Opnd => New_Occurrence_Of (Id, Loc),
1080 Right_Opnd => Make_Integer_Literal (Loc, 1)));
1081 end Increment;
1083 ---------
1084 -- Set --
1085 ---------
1087 function Set (Id : Entity_Id) return Node_Id is
1088 begin
1089 return
1090 Make_Assignment_Statement (Loc,
1091 Name => New_Occurrence_Of (Id, Loc),
1092 Expression => New_Occurrence_Of (Standard_True, Loc));
1093 end Set;
1095 -- Local variables
1097 Aggr : constant Node_Id :=
1098 Expression (First (Pragma_Argument_Associations (CCs)));
1100 Case_Guard : Node_Id;
1101 CG_Checks : Node_Id;
1102 CG_Stmts : List_Id;
1103 Conseq : Node_Id;
1104 Conseq_Checks : Node_Id := Empty;
1105 Count : Entity_Id;
1106 Count_Decl : Node_Id;
1107 Error_Decls : List_Id := No_List; -- init to avoid warning
1108 Flag : Entity_Id;
1109 Flag_Decl : Node_Id;
1110 If_Stmt : Node_Id;
1111 Msg_Str : Entity_Id := Empty;
1112 Multiple_PCs : Boolean;
1113 Old_Evals : Node_Id := Empty;
1114 Others_Decl : Node_Id;
1115 Others_Flag : Entity_Id := Empty;
1116 Post_Case : Node_Id;
1118 -- Start of processing for Expand_Pragma_Contract_Cases
1120 begin
1121 -- Do nothing if pragma is not enabled. If pragma is disabled, it has
1122 -- already been rewritten as a Null statement.
1124 if Is_Ignored (CCs) then
1125 return;
1127 -- Guard against malformed contract cases
1129 elsif Nkind (Aggr) /= N_Aggregate then
1130 return;
1131 end if;
1133 -- The expansion of contract cases is quite distributed as it produces
1134 -- various statements to evaluate the case guards and consequences. To
1135 -- preserve the original context, set the Is_Assertion_Expr flag. This
1136 -- aids the Ghost legality checks when verifying the placement of a
1137 -- reference to a Ghost entity.
1139 In_Assertion_Expr := In_Assertion_Expr + 1;
1141 Multiple_PCs := List_Length (Component_Associations (Aggr)) > 1;
1143 -- Create the counter which tracks the number of case guards that
1144 -- evaluate to True.
1146 -- Count : Natural := 0;
1148 Count := Make_Temporary (Loc, 'C');
1149 Count_Decl :=
1150 Make_Object_Declaration (Loc,
1151 Defining_Identifier => Count,
1152 Object_Definition => New_Occurrence_Of (Standard_Natural, Loc),
1153 Expression => Make_Integer_Literal (Loc, 0));
1155 Prepend_To (Decls, Count_Decl);
1156 Analyze (Count_Decl);
1158 -- Create the base error message for multiple overlapping case guards
1160 -- Msg_Str : constant String :=
1161 -- "contract cases overlap for subprogram Subp_Id";
1163 if Multiple_PCs then
1164 Msg_Str := Make_Temporary (Loc, 'S');
1166 Start_String;
1167 Store_String_Chars ("contract cases overlap for subprogram ");
1168 Store_String_Chars (Get_Name_String (Chars (Subp_Id)));
1170 Error_Decls := New_List (
1171 Make_Object_Declaration (Loc,
1172 Defining_Identifier => Msg_Str,
1173 Constant_Present => True,
1174 Object_Definition => New_Occurrence_Of (Standard_String, Loc),
1175 Expression => Make_String_Literal (Loc, End_String)));
1176 end if;
1178 -- Process individual post cases
1180 Post_Case := First (Component_Associations (Aggr));
1181 while Present (Post_Case) loop
1182 Case_Guard := First (Choices (Post_Case));
1183 Conseq := Expression (Post_Case);
1185 -- The "others" choice requires special processing
1187 if Nkind (Case_Guard) = N_Others_Choice then
1188 Others_Flag := Make_Temporary (Loc, 'F');
1189 Others_Decl := Declaration_Of (Others_Flag);
1191 Prepend_To (Decls, Others_Decl);
1192 Analyze (Others_Decl);
1194 -- Check possible overlap between a case guard and "others"
1196 if Multiple_PCs and Exception_Extra_Info then
1197 Case_Guard_Error
1198 (Decls => Error_Decls,
1199 Flag => Others_Flag,
1200 Error_Loc => Sloc (Case_Guard),
1201 Msg => Msg_Str);
1202 end if;
1204 -- Inspect the consequence and perform special expansion of any
1205 -- attribute 'Old and 'Result references found within.
1207 Expand_Attributes_In_Consequence
1208 (Decls => Decls,
1209 Evals => Old_Evals,
1210 Flag => Others_Flag,
1211 Conseq => Conseq);
1213 -- Check the corresponding consequence of "others"
1215 Consequence_Error
1216 (Checks => Conseq_Checks,
1217 Flag => Others_Flag,
1218 Conseq => Conseq);
1220 -- Regular post case
1222 else
1223 -- Create the flag which tracks the state of its associated case
1224 -- guard.
1226 Flag := Make_Temporary (Loc, 'F');
1227 Flag_Decl := Declaration_Of (Flag);
1229 Prepend_To (Decls, Flag_Decl);
1230 Analyze (Flag_Decl);
1232 -- The flag is set when the case guard is evaluated to True
1233 -- if Case_Guard then
1234 -- Flag := True;
1235 -- Count := Count + 1;
1236 -- end if;
1238 If_Stmt :=
1239 Make_Implicit_If_Statement (CCs,
1240 Condition => Relocate_Node (Case_Guard),
1241 Then_Statements => New_List (
1242 Set (Flag),
1243 Increment (Count)));
1245 Append_To (Decls, If_Stmt);
1246 Analyze (If_Stmt);
1248 -- Check whether this case guard overlaps with another one
1250 if Multiple_PCs and Exception_Extra_Info then
1251 Case_Guard_Error
1252 (Decls => Error_Decls,
1253 Flag => Flag,
1254 Error_Loc => Sloc (Case_Guard),
1255 Msg => Msg_Str);
1256 end if;
1258 -- Inspect the consequence and perform special expansion of any
1259 -- attribute 'Old and 'Result references found within.
1261 Expand_Attributes_In_Consequence
1262 (Decls => Decls,
1263 Evals => Old_Evals,
1264 Flag => Flag,
1265 Conseq => Conseq);
1267 -- The corresponding consequence of the case guard which evaluated
1268 -- to True must hold on exit from the subprogram.
1270 Consequence_Error
1271 (Checks => Conseq_Checks,
1272 Flag => Flag,
1273 Conseq => Conseq);
1274 end if;
1276 Next (Post_Case);
1277 end loop;
1279 -- Raise Assertion_Error when none of the case guards evaluate to True.
1280 -- The only exception is when we have "others", in which case there is
1281 -- no error because "others" acts as a default True.
1283 -- Generate:
1284 -- Flag := True;
1286 if Present (Others_Flag) then
1287 CG_Stmts := New_List (Set (Others_Flag));
1289 -- Generate:
1290 -- raise Assertion_Error with "xxx contract cases incomplete";
1292 else
1293 Start_String;
1294 Store_String_Chars (Build_Location_String (Loc));
1295 Store_String_Chars (" contract cases incomplete");
1297 CG_Stmts := New_List (
1298 Make_Procedure_Call_Statement (Loc,
1299 Name =>
1300 New_Occurrence_Of (RTE (RE_Raise_Assert_Failure), Loc),
1301 Parameter_Associations => New_List (
1302 Make_String_Literal (Loc, End_String))));
1303 end if;
1305 CG_Checks :=
1306 Make_Implicit_If_Statement (CCs,
1307 Condition =>
1308 Make_Op_Eq (Loc,
1309 Left_Opnd => New_Occurrence_Of (Count, Loc),
1310 Right_Opnd => Make_Integer_Literal (Loc, 0)),
1311 Then_Statements => CG_Stmts);
1313 -- Detect a possible failure due to several case guards evaluating to
1314 -- True.
1316 -- Generate:
1317 -- elsif Count > 0 then
1318 -- declare
1319 -- <Error_Decls>
1320 -- begin
1321 -- raise Assertion_Error with <Msg_Str>;
1322 -- end if;
1324 if Multiple_PCs then
1325 Set_Elsif_Parts (CG_Checks, New_List (
1326 Make_Elsif_Part (Loc,
1327 Condition =>
1328 Make_Op_Gt (Loc,
1329 Left_Opnd => New_Occurrence_Of (Count, Loc),
1330 Right_Opnd => Make_Integer_Literal (Loc, 1)),
1332 Then_Statements => New_List (
1333 Make_Block_Statement (Loc,
1334 Declarations => Error_Decls,
1335 Handled_Statement_Sequence =>
1336 Make_Handled_Sequence_Of_Statements (Loc,
1337 Statements => New_List (
1338 Make_Procedure_Call_Statement (Loc,
1339 Name =>
1340 New_Occurrence_Of
1341 (RTE (RE_Raise_Assert_Failure), Loc),
1342 Parameter_Associations => New_List (
1343 New_Occurrence_Of (Msg_Str, Loc))))))))));
1344 end if;
1346 Append_To (Decls, CG_Checks);
1347 Analyze (CG_Checks);
1349 -- Once all case guards are evaluated and checked, evaluate any prefixes
1350 -- of attribute 'Old founds in the selected consequence.
1352 if Present (Old_Evals) then
1353 Append_To (Decls, Old_Evals);
1354 Analyze (Old_Evals);
1355 end if;
1357 -- Raise Assertion_Error when the corresponding consequence of a case
1358 -- guard that evaluated to True fails.
1360 if No (Stmts) then
1361 Stmts := New_List;
1362 end if;
1364 Append_To (Stmts, Conseq_Checks);
1366 In_Assertion_Expr := In_Assertion_Expr - 1;
1367 end Expand_Pragma_Contract_Cases;
1369 ---------------------------------------
1370 -- Expand_Pragma_Import_Or_Interface --
1371 ---------------------------------------
1373 procedure Expand_Pragma_Import_Or_Interface (N : Node_Id) is
1374 Def_Id : Entity_Id;
1376 begin
1377 -- In Relaxed_RM_Semantics, support old Ada 83 style:
1378 -- pragma Import (Entity, "external name");
1380 if Relaxed_RM_Semantics
1381 and then List_Length (Pragma_Argument_Associations (N)) = 2
1382 and then Pragma_Name (N) = Name_Import
1383 and then Nkind (Arg2 (N)) = N_String_Literal
1384 then
1385 Def_Id := Entity (Arg1 (N));
1386 else
1387 Def_Id := Entity (Arg2 (N));
1388 end if;
1390 -- Variable case (we have to undo any initialization already done)
1392 if Ekind (Def_Id) = E_Variable then
1393 Undo_Initialization (Def_Id, N);
1395 -- Case of exception with convention C++
1397 elsif Ekind (Def_Id) = E_Exception
1398 and then Convention (Def_Id) = Convention_CPP
1399 then
1400 -- Import a C++ convention
1402 declare
1403 Loc : constant Source_Ptr := Sloc (N);
1404 Rtti_Name : constant Node_Id := Arg3 (N);
1405 Dum : constant Entity_Id := Make_Temporary (Loc, 'D');
1406 Exdata : List_Id;
1407 Lang_Char : Node_Id;
1408 Foreign_Data : Node_Id;
1410 begin
1411 Exdata := Component_Associations (Expression (Parent (Def_Id)));
1413 Lang_Char := Next (First (Exdata));
1415 -- Change the one-character language designator to 'C'
1417 Rewrite (Expression (Lang_Char),
1418 Make_Character_Literal (Loc,
1419 Chars => Name_uC,
1420 Char_Literal_Value => UI_From_Int (Character'Pos ('C'))));
1421 Analyze (Expression (Lang_Char));
1423 -- Change the value of Foreign_Data
1425 Foreign_Data := Next (Next (Next (Next (Lang_Char))));
1427 Insert_Actions (Def_Id, New_List (
1428 Make_Object_Declaration (Loc,
1429 Defining_Identifier => Dum,
1430 Object_Definition =>
1431 New_Occurrence_Of (Standard_Character, Loc)),
1433 Make_Pragma (Loc,
1434 Chars => Name_Import,
1435 Pragma_Argument_Associations => New_List (
1436 Make_Pragma_Argument_Association (Loc,
1437 Expression => Make_Identifier (Loc, Name_Ada)),
1439 Make_Pragma_Argument_Association (Loc,
1440 Expression => Make_Identifier (Loc, Chars (Dum))),
1442 Make_Pragma_Argument_Association (Loc,
1443 Chars => Name_External_Name,
1444 Expression => Relocate_Node (Rtti_Name))))));
1446 Rewrite (Expression (Foreign_Data),
1447 Unchecked_Convert_To (Standard_A_Char,
1448 Make_Attribute_Reference (Loc,
1449 Prefix => Make_Identifier (Loc, Chars (Dum)),
1450 Attribute_Name => Name_Address)));
1451 Analyze (Expression (Foreign_Data));
1452 end;
1454 -- No special expansion required for any other case
1456 else
1457 null;
1458 end if;
1459 end Expand_Pragma_Import_Or_Interface;
1461 -------------------------------------
1462 -- Expand_Pragma_Initial_Condition --
1463 -------------------------------------
1465 procedure Expand_Pragma_Initial_Condition
1466 (Pack_Id : Entity_Id;
1467 N : Node_Id)
1469 procedure Extract_Package_Body_Lists
1470 (Pack_Body : Node_Id;
1471 Body_List : out List_Id;
1472 Call_List : out List_Id;
1473 Spec_List : out List_Id);
1474 -- Obtain the various declarative and statement lists of package body
1475 -- Pack_Body needed to insert the initial condition procedure and the
1476 -- call to it. The lists are as follows:
1478 -- * Body_List - used to insert the initial condition procedure body
1480 -- * Call_List - used to insert the call to the initial condition
1481 -- procedure.
1483 -- * Spec_List - used to insert the initial condition procedure spec
1485 procedure Extract_Package_Declaration_Lists
1486 (Pack_Decl : Node_Id;
1487 Body_List : out List_Id;
1488 Call_List : out List_Id;
1489 Spec_List : out List_Id);
1490 -- Obtain the various declarative lists of package declaration Pack_Decl
1491 -- needed to insert the initial condition procedure and the call to it.
1492 -- The lists are as follows:
1494 -- * Body_List - used to insert the initial condition procedure body
1496 -- * Call_List - used to insert the call to the initial condition
1497 -- procedure.
1499 -- * Spec_List - used to insert the initial condition procedure spec
1501 --------------------------------
1502 -- Extract_Package_Body_Lists --
1503 --------------------------------
1505 procedure Extract_Package_Body_Lists
1506 (Pack_Body : Node_Id;
1507 Body_List : out List_Id;
1508 Call_List : out List_Id;
1509 Spec_List : out List_Id)
1511 Pack_Spec : constant Entity_Id := Corresponding_Spec (Pack_Body);
1513 Dummy_1 : List_Id;
1514 Dummy_2 : List_Id;
1515 HSS : Node_Id;
1517 begin
1518 pragma Assert (Present (Pack_Spec));
1520 -- The different parts of the invariant procedure are inserted as
1521 -- follows:
1523 -- package Pack is package body Pack is
1524 -- <IC spec> <IC body>
1525 -- private begin
1526 -- ... <IC call>
1527 -- end Pack; end Pack;
1529 -- The initial condition procedure spec is inserted in the visible
1530 -- declaration of the corresponding package spec.
1532 Extract_Package_Declaration_Lists
1533 (Pack_Decl => Unit_Declaration_Node (Pack_Spec),
1534 Body_List => Dummy_1,
1535 Call_List => Dummy_2,
1536 Spec_List => Spec_List);
1538 -- The initial condition procedure body is added to the declarations
1539 -- of the package body.
1541 Body_List := Declarations (Pack_Body);
1543 if No (Body_List) then
1544 Body_List := New_List;
1545 Set_Declarations (Pack_Body, Body_List);
1546 end if;
1548 -- The call to the initial condition procedure is inserted in the
1549 -- statements of the package body.
1551 HSS := Handled_Statement_Sequence (Pack_Body);
1553 if No (HSS) then
1554 HSS :=
1555 Make_Handled_Sequence_Of_Statements (Sloc (Pack_Body),
1556 Statements => New_List);
1557 Set_Handled_Statement_Sequence (Pack_Body, HSS);
1558 end if;
1560 Call_List := Statements (HSS);
1561 end Extract_Package_Body_Lists;
1563 ---------------------------------------
1564 -- Extract_Package_Declaration_Lists --
1565 ---------------------------------------
1567 procedure Extract_Package_Declaration_Lists
1568 (Pack_Decl : Node_Id;
1569 Body_List : out List_Id;
1570 Call_List : out List_Id;
1571 Spec_List : out List_Id)
1573 Pack_Spec : constant Node_Id := Specification (Pack_Decl);
1575 begin
1576 -- The different parts of the invariant procedure are inserted as
1577 -- follows:
1579 -- package Pack is
1580 -- <IC spec>
1581 -- <IC body>
1582 -- private
1583 -- <IC call>
1584 -- end Pack;
1586 -- The initial condition procedure spec and body are inserted in the
1587 -- visible declarations of the package spec.
1589 Body_List := Visible_Declarations (Pack_Spec);
1591 if No (Body_List) then
1592 Body_List := New_List;
1593 Set_Visible_Declarations (Pack_Spec, Body_List);
1594 end if;
1596 Spec_List := Body_List;
1598 -- The call to the initial procedure is inserted in the private
1599 -- declarations of the package spec.
1601 Call_List := Private_Declarations (Pack_Spec);
1603 if No (Call_List) then
1604 Call_List := New_List;
1605 Set_Private_Declarations (Pack_Spec, Call_List);
1606 end if;
1607 end Extract_Package_Declaration_Lists;
1609 -- Local variables
1611 IC_Prag : constant Node_Id :=
1612 Get_Pragma (Pack_Id, Pragma_Initial_Condition);
1614 Body_List : List_Id;
1615 Call : Node_Id;
1616 Call_List : List_Id;
1617 Call_Loc : Source_Ptr;
1618 Expr : Node_Id;
1619 Loc : Source_Ptr;
1620 Proc_Body : Node_Id;
1621 Proc_Body_Id : Entity_Id;
1622 Proc_Decl : Node_Id;
1623 Proc_Id : Entity_Id;
1624 Spec_List : List_Id;
1626 -- Start of processing for Expand_Pragma_Initial_Condition
1628 begin
1629 -- Nothing to do when the package is not subject to an Initial_Condition
1630 -- pragma.
1632 if No (IC_Prag) then
1633 return;
1634 end if;
1636 Expr := Get_Pragma_Arg (First (Pragma_Argument_Associations (IC_Prag)));
1637 Loc := Sloc (IC_Prag);
1639 -- Nothing to do when the pragma or its argument are illegal because
1640 -- there is no valid expression to check.
1642 if Error_Posted (IC_Prag) or else Error_Posted (Expr) then
1643 return;
1644 end if;
1646 -- Obtain the various lists of the context where the individual pieces
1647 -- of the initial condition procedure are to be inserted.
1649 if Nkind (N) = N_Package_Body then
1650 Extract_Package_Body_Lists
1651 (Pack_Body => N,
1652 Body_List => Body_List,
1653 Call_List => Call_List,
1654 Spec_List => Spec_List);
1656 elsif Nkind (N) = N_Package_Declaration then
1657 Extract_Package_Declaration_Lists
1658 (Pack_Decl => N,
1659 Body_List => Body_List,
1660 Call_List => Call_List,
1661 Spec_List => Spec_List);
1663 -- This routine should not be used on anything other than packages
1665 else
1666 pragma Assert (False);
1667 return;
1668 end if;
1670 Proc_Id :=
1671 Make_Defining_Identifier (Loc,
1672 Chars => New_External_Name (Chars (Pack_Id), "Initial_Condition"));
1674 Set_Ekind (Proc_Id, E_Procedure);
1675 Set_Is_Initial_Condition_Procedure (Proc_Id);
1677 -- Generate:
1678 -- procedure <Pack_Id>Initial_Condition;
1680 Proc_Decl :=
1681 Make_Subprogram_Declaration (Loc,
1682 Make_Procedure_Specification (Loc,
1683 Defining_Unit_Name => Proc_Id));
1685 Append_To (Spec_List, Proc_Decl);
1687 -- The initial condition procedure requires debug info when initial
1688 -- condition is subject to Source Coverage Obligations.
1690 if Generate_SCO then
1691 Set_Debug_Info_Needed (Proc_Id);
1692 end if;
1694 -- Generate:
1695 -- procedure <Pack_Id>Initial_Condition is
1696 -- begin
1697 -- pragma Check (Initial_Condition, <Expr>);
1698 -- end <Pack_Id>Initial_Condition;
1700 Proc_Body :=
1701 Make_Subprogram_Body (Loc,
1702 Specification =>
1703 Copy_Subprogram_Spec (Specification (Proc_Decl)),
1704 Declarations => Empty_List,
1705 Handled_Statement_Sequence =>
1706 Make_Handled_Sequence_Of_Statements (Loc,
1707 Statements => New_List (
1708 Make_Pragma (Loc,
1709 Chars => Name_Check,
1710 Pragma_Argument_Associations => New_List (
1711 Make_Pragma_Argument_Association (Loc,
1712 Expression =>
1713 Make_Identifier (Loc, Name_Initial_Condition)),
1714 Make_Pragma_Argument_Association (Loc,
1715 Expression => New_Copy_Tree (Expr)))))));
1717 Append_To (Body_List, Proc_Body);
1719 -- The initial condition procedure requires debug info when initial
1720 -- condition is subject to Source Coverage Obligations.
1722 Proc_Body_Id := Defining_Entity (Proc_Body);
1724 if Generate_SCO then
1725 Set_Debug_Info_Needed (Proc_Body_Id);
1726 end if;
1728 -- The location of the initial condition procedure call must be as close
1729 -- as possible to the intended semantic location of the check because
1730 -- the ABE mechanism relies heavily on accurate locations.
1732 Call_Loc := End_Keyword_Location (N);
1734 -- Generate:
1735 -- <Pack_Id>Initial_Condition;
1737 Call :=
1738 Make_Procedure_Call_Statement (Call_Loc,
1739 Name => New_Occurrence_Of (Proc_Id, Call_Loc));
1741 Append_To (Call_List, Call);
1743 Analyze (Proc_Decl);
1744 Analyze (Proc_Body);
1745 Analyze (Call);
1746 end Expand_Pragma_Initial_Condition;
1748 ------------------------------------
1749 -- Expand_Pragma_Inspection_Point --
1750 ------------------------------------
1752 -- If no argument is given, then we supply a default argument list that
1753 -- includes all objects declared at the source level in all subprograms
1754 -- that enclose the inspection point pragma.
1756 procedure Expand_Pragma_Inspection_Point (N : Node_Id) is
1757 Loc : constant Source_Ptr := Sloc (N);
1758 A : List_Id;
1759 Assoc : Node_Id;
1760 S : Entity_Id;
1761 E : Entity_Id;
1763 begin
1764 if No (Pragma_Argument_Associations (N)) then
1765 A := New_List;
1766 S := Current_Scope;
1768 while S /= Standard_Standard loop
1769 E := First_Entity (S);
1770 while Present (E) loop
1771 if Comes_From_Source (E)
1772 and then Is_Object (E)
1773 and then not Is_Entry_Formal (E)
1774 and then Ekind (E) /= E_Component
1775 and then Ekind (E) /= E_Discriminant
1776 and then Ekind (E) /= E_Generic_In_Parameter
1777 and then Ekind (E) /= E_Generic_In_Out_Parameter
1778 then
1779 Append_To (A,
1780 Make_Pragma_Argument_Association (Loc,
1781 Expression => New_Occurrence_Of (E, Loc)));
1782 end if;
1784 Next_Entity (E);
1785 end loop;
1787 S := Scope (S);
1788 end loop;
1790 Set_Pragma_Argument_Associations (N, A);
1791 end if;
1793 -- Expand the arguments of the pragma. Expanding an entity reference
1794 -- is a noop, except in a protected operation, where a reference may
1795 -- have to be transformed into a reference to the corresponding prival.
1796 -- Are there other pragmas that may require this ???
1798 Assoc := First (Pragma_Argument_Associations (N));
1799 while Present (Assoc) loop
1800 Expand (Expression (Assoc));
1801 Next (Assoc);
1802 end loop;
1803 end Expand_Pragma_Inspection_Point;
1805 --------------------------------------
1806 -- Expand_Pragma_Interrupt_Priority --
1807 --------------------------------------
1809 -- Supply default argument if none exists (System.Interrupt_Priority'Last)
1811 procedure Expand_Pragma_Interrupt_Priority (N : Node_Id) is
1812 Loc : constant Source_Ptr := Sloc (N);
1813 begin
1814 if No (Pragma_Argument_Associations (N)) then
1815 Set_Pragma_Argument_Associations (N, New_List (
1816 Make_Pragma_Argument_Association (Loc,
1817 Expression =>
1818 Make_Attribute_Reference (Loc,
1819 Prefix =>
1820 New_Occurrence_Of (RTE (RE_Interrupt_Priority), Loc),
1821 Attribute_Name => Name_Last))));
1822 end if;
1823 end Expand_Pragma_Interrupt_Priority;
1825 --------------------------------
1826 -- Expand_Pragma_Loop_Variant --
1827 --------------------------------
1829 -- Pragma Loop_Variant is expanded in the following manner:
1831 -- Original code
1833 -- for | while ... loop
1834 -- <preceding source statements>
1835 -- pragma Loop_Variant
1836 -- (Increases => Incr_Expr,
1837 -- Decreases => Decr_Expr);
1838 -- <succeeding source statements>
1839 -- end loop;
1841 -- Expanded code
1843 -- Curr_1 : <type of Incr_Expr>;
1844 -- Curr_2 : <type of Decr_Expr>;
1845 -- Old_1 : <type of Incr_Expr>;
1846 -- Old_2 : <type of Decr_Expr>;
1847 -- Flag : Boolean := False;
1849 -- for | while ... loop
1850 -- <preceding source statements>
1852 -- if Flag then
1853 -- Old_1 := Curr_1;
1854 -- Old_2 := Curr_2;
1855 -- end if;
1857 -- Curr_1 := <Incr_Expr>;
1858 -- Curr_2 := <Decr_Expr>;
1860 -- if Flag then
1861 -- if Curr_1 /= Old_1 then
1862 -- pragma Check (Loop_Variant, Curr_1 > Old_1);
1863 -- else
1864 -- pragma Check (Loop_Variant, Curr_2 < Old_2);
1865 -- end if;
1866 -- else
1867 -- Flag := True;
1868 -- end if;
1870 -- <succeeding source statements>
1871 -- end loop;
1873 procedure Expand_Pragma_Loop_Variant (N : Node_Id) is
1874 Loc : constant Source_Ptr := Sloc (N);
1875 Last_Var : constant Node_Id :=
1876 Last (Pragma_Argument_Associations (N));
1878 Curr_Assign : List_Id := No_List;
1879 Flag_Id : Entity_Id := Empty;
1880 If_Stmt : Node_Id := Empty;
1881 Old_Assign : List_Id := No_List;
1882 Loop_Scop : Entity_Id;
1883 Loop_Stmt : Node_Id;
1884 Variant : Node_Id;
1886 procedure Process_Variant (Variant : Node_Id; Is_Last : Boolean);
1887 -- Process a single increasing / decreasing termination variant. Flag
1888 -- Is_Last should be set when processing the last variant.
1890 ---------------------
1891 -- Process_Variant --
1892 ---------------------
1894 procedure Process_Variant (Variant : Node_Id; Is_Last : Boolean) is
1895 function Make_Op
1896 (Loc : Source_Ptr;
1897 Curr_Val : Node_Id;
1898 Old_Val : Node_Id) return Node_Id;
1899 -- Generate a comparison between Curr_Val and Old_Val depending on
1900 -- the change mode (Increases / Decreases) of the variant.
1902 -------------
1903 -- Make_Op --
1904 -------------
1906 function Make_Op
1907 (Loc : Source_Ptr;
1908 Curr_Val : Node_Id;
1909 Old_Val : Node_Id) return Node_Id
1911 begin
1912 if Chars (Variant) = Name_Increases then
1913 return Make_Op_Gt (Loc, Curr_Val, Old_Val);
1914 else pragma Assert (Chars (Variant) = Name_Decreases);
1915 return Make_Op_Lt (Loc, Curr_Val, Old_Val);
1916 end if;
1917 end Make_Op;
1919 -- Local variables
1921 Expr : constant Node_Id := Expression (Variant);
1922 Expr_Typ : constant Entity_Id := Etype (Expr);
1923 Loc : constant Source_Ptr := Sloc (Expr);
1924 Loop_Loc : constant Source_Ptr := Sloc (Loop_Stmt);
1925 Curr_Id : Entity_Id;
1926 Old_Id : Entity_Id;
1927 Prag : Node_Id;
1929 -- Start of processing for Process_Variant
1931 begin
1932 -- All temporaries generated in this routine must be inserted before
1933 -- the related loop statement. Ensure that the proper scope is on the
1934 -- stack when analyzing the temporaries. Note that we also use the
1935 -- Sloc of the related loop.
1937 Push_Scope (Scope (Loop_Scop));
1939 -- Step 1: Create the declaration of the flag which controls the
1940 -- behavior of the assertion on the first iteration of the loop.
1942 if No (Flag_Id) then
1944 -- Generate:
1945 -- Flag : Boolean := False;
1947 Flag_Id := Make_Temporary (Loop_Loc, 'F');
1949 Insert_Action (Loop_Stmt,
1950 Make_Object_Declaration (Loop_Loc,
1951 Defining_Identifier => Flag_Id,
1952 Object_Definition =>
1953 New_Occurrence_Of (Standard_Boolean, Loop_Loc),
1954 Expression =>
1955 New_Occurrence_Of (Standard_False, Loop_Loc)));
1957 -- Prevent an unwanted optimization where the Current_Value of
1958 -- the flag eliminates the if statement which stores the variant
1959 -- values coming from the previous iteration.
1961 -- Flag : Boolean := False;
1962 -- loop
1963 -- if Flag then -- condition rewritten to False
1964 -- Old_N := Curr_N; -- and if statement eliminated
1965 -- end if;
1966 -- . . .
1967 -- Flag := True;
1968 -- end loop;
1970 Set_Current_Value (Flag_Id, Empty);
1971 end if;
1973 -- Step 2: Create the temporaries which store the old and current
1974 -- values of the associated expression.
1976 -- Generate:
1977 -- Curr : <type of Expr>;
1979 Curr_Id := Make_Temporary (Loc, 'C');
1981 Insert_Action (Loop_Stmt,
1982 Make_Object_Declaration (Loop_Loc,
1983 Defining_Identifier => Curr_Id,
1984 Object_Definition => New_Occurrence_Of (Expr_Typ, Loop_Loc)));
1986 -- Generate:
1987 -- Old : <type of Expr>;
1989 Old_Id := Make_Temporary (Loc, 'P');
1991 Insert_Action (Loop_Stmt,
1992 Make_Object_Declaration (Loop_Loc,
1993 Defining_Identifier => Old_Id,
1994 Object_Definition => New_Occurrence_Of (Expr_Typ, Loop_Loc)));
1996 -- Restore original scope after all temporaries have been analyzed
1998 Pop_Scope;
2000 -- Step 3: Store value of the expression from the previous iteration
2002 if No (Old_Assign) then
2003 Old_Assign := New_List;
2004 end if;
2006 -- Generate:
2007 -- Old := Curr;
2009 Append_To (Old_Assign,
2010 Make_Assignment_Statement (Loc,
2011 Name => New_Occurrence_Of (Old_Id, Loc),
2012 Expression => New_Occurrence_Of (Curr_Id, Loc)));
2014 -- Step 4: Store the current value of the expression
2016 if No (Curr_Assign) then
2017 Curr_Assign := New_List;
2018 end if;
2020 -- Generate:
2021 -- Curr := <Expr>;
2023 Append_To (Curr_Assign,
2024 Make_Assignment_Statement (Loc,
2025 Name => New_Occurrence_Of (Curr_Id, Loc),
2026 Expression => Relocate_Node (Expr)));
2028 -- Step 5: Create corresponding assertion to verify change of value
2030 -- Generate:
2031 -- pragma Check (Loop_Variant, Curr <|> Old);
2033 Prag :=
2034 Make_Pragma (Loc,
2035 Chars => Name_Check,
2036 Pragma_Argument_Associations => New_List (
2037 Make_Pragma_Argument_Association (Loc,
2038 Expression => Make_Identifier (Loc, Name_Loop_Variant)),
2039 Make_Pragma_Argument_Association (Loc,
2040 Expression =>
2041 Make_Op (Loc,
2042 Curr_Val => New_Occurrence_Of (Curr_Id, Loc),
2043 Old_Val => New_Occurrence_Of (Old_Id, Loc)))));
2045 -- Generate:
2046 -- if Curr /= Old then
2047 -- <Prag>;
2049 if No (If_Stmt) then
2051 -- When there is just one termination variant, do not compare the
2052 -- old and current value for equality, just check the pragma.
2054 if Is_Last then
2055 If_Stmt := Prag;
2056 else
2057 If_Stmt :=
2058 Make_If_Statement (Loc,
2059 Condition =>
2060 Make_Op_Ne (Loc,
2061 Left_Opnd => New_Occurrence_Of (Curr_Id, Loc),
2062 Right_Opnd => New_Occurrence_Of (Old_Id, Loc)),
2063 Then_Statements => New_List (Prag));
2064 end if;
2066 -- Generate:
2067 -- else
2068 -- <Prag>;
2069 -- end if;
2071 elsif Is_Last then
2072 Set_Else_Statements (If_Stmt, New_List (Prag));
2074 -- Generate:
2075 -- elsif Curr /= Old then
2076 -- <Prag>;
2078 else
2079 if Elsif_Parts (If_Stmt) = No_List then
2080 Set_Elsif_Parts (If_Stmt, New_List);
2081 end if;
2083 Append_To (Elsif_Parts (If_Stmt),
2084 Make_Elsif_Part (Loc,
2085 Condition =>
2086 Make_Op_Ne (Loc,
2087 Left_Opnd => New_Occurrence_Of (Curr_Id, Loc),
2088 Right_Opnd => New_Occurrence_Of (Old_Id, Loc)),
2089 Then_Statements => New_List (Prag)));
2090 end if;
2091 end Process_Variant;
2093 -- Start of processing for Expand_Pragma_Loop_Variant
2095 begin
2096 -- If pragma is not enabled, rewrite as Null statement. If pragma is
2097 -- disabled, it has already been rewritten as a Null statement.
2099 if Is_Ignored (N) then
2100 Rewrite (N, Make_Null_Statement (Loc));
2101 Analyze (N);
2102 return;
2103 end if;
2105 -- The expansion of Loop_Variant is quite distributed as it produces
2106 -- various statements to capture and compare the arguments. To preserve
2107 -- the original context, set the Is_Assertion_Expr flag. This aids the
2108 -- Ghost legality checks when verifying the placement of a reference to
2109 -- a Ghost entity.
2111 In_Assertion_Expr := In_Assertion_Expr + 1;
2113 -- Locate the enclosing loop for which this assertion applies. In the
2114 -- case of Ada 2012 array iteration, we might be dealing with nested
2115 -- loops. Only the outermost loop has an identifier.
2117 Loop_Stmt := N;
2118 while Present (Loop_Stmt) loop
2119 if Nkind (Loop_Stmt) = N_Loop_Statement
2120 and then Present (Identifier (Loop_Stmt))
2121 then
2122 exit;
2123 end if;
2125 Loop_Stmt := Parent (Loop_Stmt);
2126 end loop;
2128 Loop_Scop := Entity (Identifier (Loop_Stmt));
2130 -- Create the circuitry which verifies individual variants
2132 Variant := First (Pragma_Argument_Associations (N));
2133 while Present (Variant) loop
2134 Process_Variant (Variant, Is_Last => Variant = Last_Var);
2135 Next (Variant);
2136 end loop;
2138 -- Construct the segment which stores the old values of all expressions.
2139 -- Generate:
2140 -- if Flag then
2141 -- <Old_Assign>
2142 -- end if;
2144 Insert_Action (N,
2145 Make_If_Statement (Loc,
2146 Condition => New_Occurrence_Of (Flag_Id, Loc),
2147 Then_Statements => Old_Assign));
2149 -- Update the values of all expressions
2151 Insert_Actions (N, Curr_Assign);
2153 -- Add the assertion circuitry to test all changes in expressions.
2154 -- Generate:
2155 -- if Flag then
2156 -- <If_Stmt>
2157 -- else
2158 -- Flag := True;
2159 -- end if;
2161 Insert_Action (N,
2162 Make_If_Statement (Loc,
2163 Condition => New_Occurrence_Of (Flag_Id, Loc),
2164 Then_Statements => New_List (If_Stmt),
2165 Else_Statements => New_List (
2166 Make_Assignment_Statement (Loc,
2167 Name => New_Occurrence_Of (Flag_Id, Loc),
2168 Expression => New_Occurrence_Of (Standard_True, Loc)))));
2170 -- Note: the pragma has been completely transformed into a sequence of
2171 -- corresponding declarations and statements. We leave it in the tree
2172 -- for documentation purposes. It will be ignored by the backend.
2174 In_Assertion_Expr := In_Assertion_Expr - 1;
2175 end Expand_Pragma_Loop_Variant;
2177 --------------------------------
2178 -- Expand_Pragma_Psect_Object --
2179 --------------------------------
2181 -- Convert to Common_Object, and expand the resulting pragma
2183 procedure Expand_Pragma_Psect_Object (N : Node_Id)
2184 renames Expand_Pragma_Common_Object;
2186 -------------------------------------
2187 -- Expand_Pragma_Relative_Deadline --
2188 -------------------------------------
2190 procedure Expand_Pragma_Relative_Deadline (N : Node_Id) is
2191 P : constant Node_Id := Parent (N);
2192 Loc : constant Source_Ptr := Sloc (N);
2194 begin
2195 -- Expand the pragma only in the case of the main subprogram. For tasks
2196 -- the expansion is done in exp_ch9. Generate a call to Set_Deadline
2197 -- at Clock plus the relative deadline specified in the pragma. Time
2198 -- values are translated into Duration to allow for non-private
2199 -- addition operation.
2201 if Nkind (P) = N_Subprogram_Body then
2202 Rewrite
2204 Make_Procedure_Call_Statement (Loc,
2205 Name => New_Occurrence_Of (RTE (RE_Set_Deadline), Loc),
2206 Parameter_Associations => New_List (
2207 Unchecked_Convert_To (RTE (RO_RT_Time),
2208 Make_Op_Add (Loc,
2209 Left_Opnd =>
2210 Make_Function_Call (Loc,
2211 New_Occurrence_Of (RTE (RO_RT_To_Duration), Loc),
2212 New_List
2213 (Make_Function_Call
2214 (Loc, New_Occurrence_Of (RTE (RE_Clock), Loc)))),
2215 Right_Opnd =>
2216 Unchecked_Convert_To (Standard_Duration, Arg1 (N)))))));
2218 Analyze (N);
2219 end if;
2220 end Expand_Pragma_Relative_Deadline;
2222 -------------------------------------------
2223 -- Expand_Pragma_Suppress_Initialization --
2224 -------------------------------------------
2226 procedure Expand_Pragma_Suppress_Initialization (N : Node_Id) is
2227 Def_Id : constant Entity_Id := Entity (Arg1 (N));
2229 begin
2230 -- Variable case (we have to undo any initialization already done)
2232 if Ekind (Def_Id) = E_Variable then
2233 Undo_Initialization (Def_Id, N);
2234 end if;
2235 end Expand_Pragma_Suppress_Initialization;
2237 -------------------------
2238 -- Undo_Initialization --
2239 -------------------------
2241 procedure Undo_Initialization (Def_Id : Entity_Id; N : Node_Id) is
2242 Init_Call : Node_Id;
2244 begin
2245 -- When applied to a variable, the default initialization must not be
2246 -- done. As it is already done when the pragma is found, we just get rid
2247 -- of the call the initialization procedure which followed the object
2248 -- declaration. The call is inserted after the declaration, but validity
2249 -- checks may also have been inserted and thus the initialization call
2250 -- does not necessarily appear immediately after the object declaration.
2252 -- We can't use the freezing mechanism for this purpose, since we have
2253 -- to elaborate the initialization expression when it is first seen (so
2254 -- this elaboration cannot be deferred to the freeze point).
2256 -- Find and remove generated initialization call for object, if any
2258 Init_Call := Remove_Init_Call (Def_Id, Rep_Clause => N);
2260 -- Any default initialization expression should be removed (e.g.
2261 -- null defaults for access objects, zero initialization of packed
2262 -- bit arrays). Imported objects aren't allowed to have explicit
2263 -- initialization, so the expression must have been generated by
2264 -- the compiler.
2266 if No (Init_Call) and then Present (Expression (Parent (Def_Id))) then
2267 Set_Expression (Parent (Def_Id), Empty);
2268 end if;
2270 -- The object may not have any initialization, but in the presence of
2271 -- Initialize_Scalars code is inserted after then declaration, which
2272 -- must now be removed as well. The code carries the same source
2273 -- location as the declaration itself.
2275 if Initialize_Scalars and then Is_Array_Type (Etype (Def_Id)) then
2276 declare
2277 Init : Node_Id;
2278 Nxt : Node_Id;
2279 begin
2280 Init := Next (Parent (Def_Id));
2281 while not Comes_From_Source (Init)
2282 and then Sloc (Init) = Sloc (Def_Id)
2283 loop
2284 Nxt := Next (Init);
2285 Remove (Init);
2286 Init := Nxt;
2287 end loop;
2288 end;
2289 end if;
2290 end Undo_Initialization;
2292 end Exp_Prag;